Bring the decision-model approach to existing LLMs.
Inspired by Jev's System One approach: unstructured input in, explicit choices with scores out, and the application controls what happens next.
DecisionBridge is an adapter that lets you use an existing LLM as a decision function. Define a question and its allowed answers, get scores for the options, optionally calibrate on your labeled examples, and set a threshold for human review. No model fine-tuning required.
Input: “Save loses my changes.”
Question: What kind of request is this?
Choices: bug / feature / howto / other
↓
LLM scores → optional calibration → your threshold
↓
Output: selected label + scores, or abstention
Your app: route the request, or ask a human to review it
Use this pattern for issue triage, document classification, and request routing. OpenAI, Anthropic, OpenRouter, and local MLX share the same choice interface. Each call answers one question; your code can compose separate calls into a workflow. Model support and score sources differ by backend.
Python 3.11+. Install from source (no PyPI release yet):
git clone https://github.com/grishahq/decisionbridge.git
cd decisionbridge
uv venv --python 3.12
uv pip install --python .venv/bin/python -e '.[api]'Set OPENAI_API_KEY and OPENAI_MODEL in your environment, then:
import os
from decisionbridge import Choice
from decisionbridge.backends.api import APIDecisionModel
model = APIDecisionModel("openai", os.environ["OPENAI_MODEL"], mode="json")
choice = Choice("What is the main intent?", {
"bug": "An existing feature is broken.",
"feature": "A request for a new capability.",
"howto": "A question about using an existing feature.",
"other": "None of those, or insufficient information.",
})
decision = model.choose("Save loses my changes.", choice, threshold=0.8)
print(dict(decision.scores)) # One score per category
print(decision.score_source) # Here: verbalized_json
if decision.abstained:
print("Request human review")
else:
print("Route to:", decision.selected_winner)This quickstart uses model-generated JSON estimates, with an illustrative raw threshold. Fit calibration and evaluate the threshold on your task before using it for automatic routing. Model IDs are explicit; select one supporting the mode.
| Provider | Connection | Score modes |
|---|---|---|
| OpenAI | APIDecisionModel("openai", model_id, mode=...) |
logprobs (default), json |
| Anthropic | APIDecisionModel("anthropic", model_id) |
json (default) |
| OpenRouter | APIDecisionModel("openrouter", model_id, mode=...) |
logprobs (default), json |
| Local MLX | MLXDecisionModel() |
Full-vocabulary logits, no answer generation |
- Token scores: local MLX reads logits directly. API
logprobsreads the first output position's token probabilities on compatible models. All exact option tokens must be returned; missing scores raise an error. - JSON estimates: the model generates a structured object of scores. These
are labeled
verbalized_json; they are not internal token probabilities.
There is no silent switch between modes. API requests generate output tokens and send text to the selected provider. Local MLX processes text on your Mac.
API modes support 2–20 labels for logprobs and 2–26 for json. MLX supports
2–26. Provider and model capabilities vary. API integrations are covered by
mock HTTP tests; live calls have not yet been verified. Existing benchmark
results cover only the local backend. See provider setup and limits.
.venv/bin/decisionbridge decide --provider openai --model "$OPENAI_MODEL" --mode json \
--question 'What is the main intent?' --text 'Please add a dark theme.' \
--option 'feature=A request for a new capability' --option 'other=Anything else'Replace the provider and model with anthropic / $ANTHROPIC_MODEL or
openrouter / $OPENROUTER_MODEL; set that provider's API key. The
runnable API example also reports token usage and model identity.
For local inference on Apple Silicon:
uv pip install --python .venv/bin/python -e '.[mlx]'from decisionbridge.backends.mlx import MLXDecisionModel
model = MLXDecisionModel() # Use the same Choice and choose() callThe default is pinned Qwen3-4B-Instruct-2507, 4-bit MLX. First use downloads about
2.26 GB of weights plus tokenizer files. Then MLXDecisionModel(offline=True)
uses the cached checkpoint. No API key is needed for this backend.
- A common result: label, scores, score source, timing, and calibration status.
- Temperature calibration on separate labeled examples, bound to model identity, prompt, score mode, and labels. No changes to model weights.
- An optional review threshold:
selected_winner=Nonewhen abstaining. Your application decides what happens next. - A local evaluation harness comparing direct scores, a one-token answer, and prompted JSON, with every prediction in an offline report.
A score of 0.9 does not guarantee 90% correctness. Calibration preserves the winning label and may not transfer to new data. A one-token answer is already a competitive baseline if you only need a label. This library does not promise universal speed or accuracy gains. Token scoring and temperature scaling are established techniques.
The shared idea is bounded decisions that software can use directly: provide the state, define the allowed choices, inspect the scores, and keep the branching rules in application code. DecisionBridge brings a small version of that interface to existing LLMs.
It does not reproduce Jev's architecture, RLCD training, or parallel sampler. Multiple questions require separate calls. Temperature calibration fits a scalar on your examples; it does not retrain the LLM or establish Jev-level performance. The recorded benchmark compares output methods on a local LLM, not against Jev.
The following benchmark command uses the local MLX backend:
.venv/bin/decisionbridge benchmark \
--dataset examples/issue_triage.json --output reports/my-run.json
.venv/bin/decisionbridge report reports/my-run.json --output reports/my-run.html
open reports/my-run.htmlThe bundled evaluation is a small, English-only, AI-authored synthetic pilot. Recorded results and methodology include failures, timing, and probability metrics. They make no claims about the API providers.
See usage and calibration and calibrating API scores.
uv pip install --python .venv/bin/python -e '.[dev]'
.venv/bin/python -m pytest -qTests require no model downloads or credentials. API tests use mock HTTP responses. See CONTRIBUTING.md.
Code: MIT. Local inference: MLX LM. Default weights: Qwen3-4B-Instruct-2507, whose model card lists Apache-2.0, through the MLX community quantization. Weights are downloaded separately and retain their own license.