Cambium
Cost discipline and bounded agency for LLM call sites — the deterministic spine decides what to ask, the model only answers.
What it is
Cambium is the cost-discipline / bounded-agent layer that sits in front of your model calls. Instead of handing an LLM every decision, it routes work through the cheapest path that can answer it and only pays for the model when nothing cheaper will do. Three deterministic, pure-Python capabilities anchor the public surface:
cambium.distill— pre-call payload minimization. Decide whether a payload even needs the model (assemble/pass/condense/summarize), shrink oversized payloads deterministically, and record what every call cost via aCostLedger.cambium.resolve— a cost-tiered resolution ladder. Try resolvers in cost order (deterministic → statistical → generative) and stop at the first one confident enough; the expensive generative tier is a budget-gated last resort.cambium.adapt— the feedback substrate for outcome-driven learning: record predictions, observe real outcomes, score them, and attribute credit/blame across the features and strategies that produced them.
Three further deterministic capabilities carry accountability — not "what did we decide" but "at what epistemic strength, and what could we not decide":
cambium.epistemics— every claim is typed at construction (theorem/identification/estimate/debt) and a per-profile debt ledger records, machine-readably, what the engine does not know and the evidence that would resolve it.cambium.anchoring— models a conversation as progressive anchoring of a distribution over user intents, with a monotone commitment fraction and a regime read (exploring / deliberating / drifting). Pure, replayable, shadow-safe.cambium.conjunction— eval discipline: score how many independent, zero-tuned predictions one shared config satisfies at once, and flag per-segment parameters that are fitted on too little data to be falsifiable.
Every one of these is deterministic, dependency-light, and replayable — no model call, no RNG, no wall clock — so each result is exactly reproducible from its inputs. See The science for the grounding.
The package import name is cambium; the PyPI distribution is cambium-ai.
Install
pip install cambium-ai
The core (distill / resolve / adapt) has no LLM dependency. Live
generative clients are optional extras:
pip install "cambium-ai[claude]" # live Anthropic client
pip install "cambium-ai[gemini]" # live Gemini generator
cambium.distill — pre-call payload minimization + cost ledger
prepare runs the full routing pipeline and hands back a ready-to-send payload
plus the accounting the ledger needs. Route.ASSEMBLE means no model call at
all.
from cambium.distill import prepare, Route, CostLedger
prepared = prepare(task_output, budget_tokens=2000)
ledger = CostLedger(job_id="research-run")
if prepared.route is Route.ASSEMBLE:
answer = format_table(task_output) # deterministic, no model
ledger.record_avoided(label="summary", route="assemble",
tokens_saved=prepared.tokens_saved)
else:
response = claude.call(prompt_with(prepared.content)) # your model call
ledger.record(label="summary", model="claude-3-5-haiku",
input_tokens=response.input_tokens,
output_tokens=response.output_tokens,
tier="generative", tokens_saved=prepared.tokens_saved)
report = ledger.report
report.within_budget(max_cost_usd=0.05) # cost-regression gate
estimate_tokens(content) and condense(content, max_tokens=...) are also
public if you want the pieces directly.
cambium.resolve — cost-tiered resolution ladder
Implement a Resolver per tier and let resolve climb only as far as it must.
The generative tier is skipped once the ledger is over budget.
from cambium.resolve import Tier, Resolution, resolve
from cambium.distill import CostLedger
class ExactMatch:
tier = Tier.DETERMINISTIC
name = "exact_match"
def resolve(self, request):
hit = lookup(request)
if hit is None:
return None
return Resolution(value=hit, confidence=1.0, tier=self.tier)
ledger = CostLedger()
result = resolve(
request,
[ExactMatch(), embedding_resolver, llm_resolver],
ledger=ledger,
threshold=0.8,
max_cost_usd=0.05, # gates the generative tier
)
resolve returns the first resolution at/above threshold, else the best
below-threshold one, else None. ResolverRegistry is available for grouping
resolvers by decision type.
cambium.adapt — outcome-driven feedback substrate
Record predictions, feed back real outcomes, and mature them into scored attributions that a reweighting layer can consume.
from cambium.adapt import (
PredictionRecord, OutcomeRecord, InMemoryPredictionLedger, mature,
)
led = InMemoryPredictionLedger()
led.record_prediction(PredictionRecord(
id="p1", subject="AAPL", strategy="momentum",
features={"rsi": 0.7, "trend": 0.3}, predicted=1.0, baseline=0.0,
))
led.record_outcome(OutcomeRecord(prediction_id="p1", actual=1.0))
scores = mature(led) # [PredictionScore(accuracy=1.0, attributions={...})]
Weights / update / aggregate and predict_from_attributes /
blend_strategies / best_strategy close the loop for the reweighting phase.
cambium.epistemics — typed claims + a debt ledger
Provenance stops being "here is what we decided" and becomes "here is what we decided, at what epistemic strength, and here is the itemized list of what we could not decide and why." Every claim carries a mandatory epistemic type — an untyped claim cannot be constructed — and open questions are registered as resolvable debts.
from cambium.epistemics import (
EpistemicType, TypedClaim, InMemoryEpistemicLedger, evidence_debts,
)
ledger = InMemoryEpistemicLedger()
# Typed at construction: a bounded numeric claim with stated uncertainty.
ledger.record_claim(TypedClaim.build(
epistemic_type=EpistemicType.ESTIMATE,
user_id_hash="u1", domain="finance",
subject="risk_tolerance", value=0.4, uncertainty=0.25,
))
# Register what the engine does NOT know: asserted dimensions the evidence
# does not actually support become debts, each naming its blocker.
evidence_debts(identity, scores, at=window_end, min_events=3, store=ledger)
for debt in ledger.open_debts():
print(debt.subject, "→", debt.blocker) # ... "only 1 of 3 events cite it"
Debts are append-only and immutable — resolved only by a new ResolutionEvent
that references them, so the full lineage (opened → evidence arrived → resolved)
is always queryable. claims_from_score / claims_from_insight type existing
spine outputs without mutating them.
cambium.anchoring — progressive-anchoring conversation model
A conversation is modeled as a live distribution over user intents that contracts as the user commits. Each event is classified by anchoring power (a hedge anchors almost nothing; an executed trade anchors hard), and the tracker emits a monotone commitment fraction plus a provisional regime label.
from cambium.anchoring import (
IntentDistribution, AnchoringEvent, AnchoringKind, AnchoringTracker,
)
tracker = AnchoringTracker(IntentDistribution.uniform(("save", "invest", "spend")))
for i, kind in enumerate((AnchoringKind.HEDGE,
AnchoringKind.STATEMENT,
AnchoringKind.EXECUTED_ACTION)):
snap = tracker.record(
AnchoringEvent(event_id=f"e{i}", kind=kind, target_intent="invest")
)
print(snap.commitment_fraction, snap.top_intent, snap.regime.regime.value)
# commitment_fraction is monotone non-decreasing across the run, by construction
The regime classifier ships provisional (estimate-typed, dormant) until an
eval harness validates its thresholds; the state tracker is safe to run in shadow
with zero behavior change. claims_from_snapshot feeds the anchoring signal into
the epistemic ledger at its honest strength (estimate, never fact).
cambium.conjunction — conjunction eval discipline
Report not one averaged metric but how many independent, zero-tuned predictions the single shared config gets right simultaneously — and refuse per-segment parameters that overfit their own calibration data.
from cambium.conjunction import (
Prediction, score_conjunction, conjunction_regression_gate,
SegmentFit, lint_segment_fits,
)
report = score_conjunction([
Prediction(name="calibration_ece", passed=True),
Prediction(name="direction_agreement", passed=True),
Prediction(name="judge_min", passed=False),
])
report.conjunction_score # 0.667 — two of three, one config, zero tuning
# CI gate: fail a change that regresses any conjunct the baseline got right.
conjunction_regression_gate(baseline_report, report)
# Linter: 3 parameters fitted on 3 examples is a restatement, not a fit.
lint_segment_fits([SegmentFit(segment="cohort_a", num_parameters=3,
num_calibration_examples=3,
beats_shared_on_holdout=True)]) # → flagged circular
The science
These capabilities emerged from translating an interpretive framework into platform mechanics, but each stands on established, checkable ground — not metaphor. What follows is the actual math the code runs.
Epistemic typing. Claims are partitioned by how they are known, forming a
strength ordering: theorem (deductively recomputable from config + inputs) →
identification (a model-asserted mapping) → estimate (a bounded numeric claim
with explicit uncertainty) → debt (a known-unknown with a named blocker and a
declared resolution condition). The debt ledger is an explicit, machine-readable
representation of the system's known-unknowns — the epistemic complement to its
outputs. The type is required at construction, so the boundary between what was
derived and what was asserted can never silently blur.
Anchoring as entropy contraction. The unanchored state is a distribution
p over intents; its uncertainty is the Shannon entropy H(p) = -Σ pᵢ ln pᵢ.
An anchoring event applies an exponential tilt — a tempered pseudo-observation:
targeted event → pᵢ ∝ pᵢ · exp(w·κ·[i = target])
untargeted → pᵢ ∝ pᵢ^(1 + w·κ) (tempering toward the current mode)
where w ∈ [0,1] is the event's anchoring weight and κ a single shared
sharpness constant. This is standard exponential-family / tempered-Bayesian
updating; the "superposition → definite outcome" language is the interpretive
metaphor, but the operator is closed-form and deterministic.
Commitment fraction — monotone by construction. Separately from where the
intent mass sits, we track how much has been committed. Each event commits a
wₙ fraction of the remaining unanchored mass:
Uₙ = Uₙ₋₁ · (1 − wₙ), U₀ = 1 (unanchored mass)
Cₙ = 1 − Uₙ (commitment fraction)
Because every wₙ ∈ [0,1], each factor is in [0,1], so Uₙ is non-increasing
and Cₙ is monotone non-decreasing — a guarantee that holds for any event
sequence, proven by construction rather than clamped after the fact.
Conjunction over parsimony. A single averaged score hides compensating
errors. The conjunction score instead counts how many independent, zero-tuned
predictions hold at once — jointly passing N independent checks is a
multiplicatively stronger claim than any one metric average, so regression gates
key off it. The circularity linter enforces the parsimony discipline behind it:
a per-segment parameter set fitted on comparably-sized calibration data (k
parameters to k data points) can only restate its inputs — it is unfalsifiable.
The linter requires a minimum data-per-parameter ratio and a held-out
improvement over the shared default before per-segment tuning is admitted (an
Occam / model-selection constraint applied to config).
Every formula above is exercised by the test suite and computed with no model call, so the numbers are exactly reproducible from their inputs.
License
Apache-2.0. See LICENSE.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file cambium_ai-0.3.0.tar.gz.
File metadata
- Download URL: cambium_ai-0.3.0.tar.gz
- Upload date:
- Size: 143.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/2.0.1 CPython/3.13.14 Linux/6.17.0-1020-azure
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4dc64180ca54e12b99ed26f927c2a3a7bc98a171ce31102a530d79eaa0d70706
|
|
| MD5 |
a35a8b5f55bfbe05ac391074671257c0
|
|
| BLAKE2b-256 |
5fb2833546ce79abfb29ae65662fbfa0d111ff25b015faa430e8e6fb29b3a060
|
File details
Details for the file cambium_ai-0.3.0-py3-none-any.whl.
File metadata
- Download URL: cambium_ai-0.3.0-py3-none-any.whl
- Upload date:
- Size: 144.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/2.0.1 CPython/3.13.14 Linux/6.17.0-1020-azure
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7df05573c7e23521e671d6596f8c975cc53522f0a8752426fd0f43a47fba8973
|
|
| MD5 |
58f399fa55a480e146b6bd3596ce2905
|
|
| BLAKE2b-256 |
1b06bdc08ac49d04384ac6f4304f3ad5b6ae3fb803b6b3ec33e145a640ccda44
|