Skip to main content

Cambium

Cost discipline and bounded agency for LLM call sites — the deterministic spine decides what to ask, the model only answers.

PyPI Python License: Apache-2.0

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 a CostLedger.
  • 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.

Metadata

Release files for cambium-ai 0.4.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for cambium-ai 0.4.0
File Size Uploaded
cambium_ai-0.4.0.tar.gz 158.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for cambium-ai 0.4.0
File Interpreter ABI Platform
cambium_ai-0.4.0-py3-none-any.whl Python 3 none any Details

Total release size: 305.8 kB

Release files / cambium_ai-0.4.0.tar.gz

Download URL cambium_ai-0.4.0.tar.gz
Size 158.4 kB
Tags Source
SHA-256 checksum
How to use checksums
6b3c64ff1d0d22c6491d80239803afde3ddee9d330aa71265f9779070e50b42c
BLAKE2b-256 checksum
How to use checksums
31eed560ffd7acf625b150045666a0f009365ee9863ecb5fc39a743dd70415d8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/2.0.1 CPython/3.13.15 Linux/6.17.0-1022-azure

Release files / cambium_ai-0.4.0-py3-none-any.whl

Download URL cambium_ai-0.4.0-py3-none-any.whl
Size 147.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
1297e64c65f6bb86d758e8933e79825d50c5a5c47c77a8c96db822df5ee61734
BLAKE2b-256 checksum
How to use checksums
ebe97ee265e922aebc25e251c664d033f0d7bd1b2bce62e39a4c0c0eceb3b23e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/2.0.1 CPython/3.13.15 Linux/6.17.0-1022-azure

Release history Release notifications | RSS feed

This release

0.4.0 This release

2 release files

0.3.0

2 release files

0.2.7

2 release files

0.2.6

2 release files

0.2.5

2 release files

0.2.4

2 release files

0.2.3

2 release files

0.2.2

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page