01 · Hello, Jev: your first System One call¶
Jev is TypeSafe AI's System One model. The name comes from Kahneman's Thinking, Fast and Slow:
| Fast brain: Jev (System 1) | Slow brain: LLM (System 2) | |
|---|---|---|
| Input | a state (text or JSON) + typed questions | a chat transcript |
| Output | typed answers with calibrated probabilities | free text (and tool calls) |
| Speed | ~70-500 ms | seconds |
| Price | $0.042 per million input tokens, output free | $0.10-$10 per million input tokens, plus output |
| Hallucination | impossible by construction: answers come from the options you define | possible |
| Can it write an email? | no | yes |
Jev answers three kinds of question, and every notebook in this course is built from them:
Noul: a yes/no question, answered with P(yes)Choice: one of up to 255 named options, answered with a probability for eachScore: a position on an ordered scale of 2-10 levels, answered with a fractional score
One key, both brains. Your OpenRouter key drives the LLM (via the OpenAI SDK) and Jev (via the TypeSafe SDK). Run uv run python scripts/doctor.py first to check it.
# --- Provider config: ONE OpenRouter key drives both brains ------------------------------
# slow brain (LLM) -> OpenAI SDK -> https://openrouter.ai/api/v1 (chat completions + tools)
# fast brain (Jev) -> TypeSafe SDK -> https://openrouter.ai/api (POST /v1/systemone)
import os, json, time
# Load settings from a .env file if present (falls back to existing env vars).
try:
from dotenv import load_dotenv, find_dotenv
load_dotenv(find_dotenv(usecwd=True))
except Exception:
if os.path.exists(".env"):
for _line in open(".env"):
_line = _line.strip()
if _line and not _line.startswith("#") and "=" in _line:
_k, _v = _line.split("=", 1)
os.environ.setdefault(_k.strip(), _v.strip())
BASE_URL = os.environ.get("OPENAI_BASE_URL", "https://openrouter.ai/api/v1")
API_KEY = os.environ.get("OPENAI_API_KEY", "set-me")
MODEL = os.environ.get("MODEL", "openai/gpt-6-luna") # slow brain: any tool-capable chat model
JEV_BACKEND = os.environ.get("JEV_BACKEND", "typesafe").strip().lower() # typesafe | adapter
JEV_MODEL = os.environ.get("JEV_MODEL", "~typesafe/jev-latest")
JEV_BASE_URL = os.environ.get("TYPESAFE_BASE_URL", "https://openrouter.ai/api")
JEV_API_KEY = os.environ.get("TYPESAFE_API_KEY") or API_KEY # one key for both brains
# Behind a TLS-intercepting firewall/proxy, set VERIFY_SSL=false in .env (trusted networks only).
import httpx, httpx2
VERIFY_SSL = os.environ.get("VERIFY_SSL", "true").strip().lower() not in ("false", "0", "no")
if not VERIFY_SSL:
import warnings
warnings.filterwarnings("ignore")
print("\u26a0\ufe0f SSL verification DISABLED (VERIFY_SSL=false) \u2014 use only on a trusted network")
from openai import OpenAI
client = OpenAI(base_url=BASE_URL, api_key=API_KEY, http_client=httpx.Client(verify=VERIFY_SSL))
if JEV_BACKEND == "adapter":
# No Jev access yet? Same System One API, answered by your LLM (slower, pricier, but it runs).
from system_one_adapter import SystemOneAdapterClient, Noul, Choice, Score
from system_one_adapter.providers.openai import OpenAIProvider
jev = SystemOneAdapterClient(
structured_outputs=True, llm_answer_mode="probabilities", normalize_probabilities=True,
n_retry_malformed_structure=2,
model=OpenAIProvider(MODEL, base_url=BASE_URL, api_key=API_KEY, api="chat_completions"))
else:
from typesafe_sdk import TypeSafeClient, Noul, Choice, Score
jev = TypeSafeClient(api_key=JEV_API_KEY, base_url=JEV_BASE_URL, model=JEV_MODEL,
http_client=httpx2.Client(verify=VERIFY_SSL))
print(f"slow brain (LLM): {MODEL} @ {BASE_URL}")
print(f"fast brain (Jev): {JEV_MODEL if JEV_BACKEND != 'adapter' else MODEL + ' via adapter'} @ {JEV_BASE_URL if JEV_BACKEND != 'adapter' else BASE_URL}")
slow brain (LLM): openai/gpt-6-luna @ https://openrouter.ai/api/v1 fast brain (Jev): ~typesafe/jev-latest @ https://openrouter.ai/api
# --- Helpers used in every notebook: ask the fast brain, ask the slow brain, track spend ---
class Spend:
"""Running tally of what OpenRouter charged, per brain (it reports exact USD per call)."""
def __init__(self):
self.usd, self.calls = {"jev": 0.0, "llm": 0.0}, {"jev": 0, "llm": 0}
def add(self, brain, resp):
self.calls[brain] += 1
try: cost = resp.raw_http_response.json()["usage"].get("cost") # Jev response
except Exception: cost = getattr(getattr(resp, "usage", None), "cost", None) # LLM response
self.usd[brain] += cost or 0.0
def __repr__(self):
return (f"Jev: {self.calls['jev']} calls ${self.usd['jev']:.5f} | "
f"LLM: {self.calls['llm']} calls ${self.usd['llm']:.5f}")
SPEND = Spend()
def ask_jev(state, questions):
"""Fast brain. state (text or JSON) + typed questions -> typed, calibrated answers."""
r = jev.system_one(state, questions)
SPEND.add("jev", r)
return r
def chat(prompt, system="Be concise.", model=None):
"""Slow brain, single shot (no tools). Returns the reply text."""
resp = client.chat.completions.create(model=model or MODEL, messages=[
{"role": "system", "content": system}, {"role": "user", "content": prompt}])
SPEND.add("llm", resp)
return resp.choices[0].message.content
def show(r):
"""Print every answer in a Jev response on one line each."""
for k, a in r.answers.items():
if a.type == "noul":
print(f" {k:<18} noul P(yes)={a.noul:.2f}")
elif a.type == "choice":
top = sorted(a.probabilities.items(), key=lambda kv: -kv[1])[:3]
print(f" {k:<18} choice {a.choice!r:<22} conf={a.confidence:.2f} top={top}")
else:
level = {int(i): v for i, v in (a.legend or {}).items()}.get(round(a.score), "")
print(f" {k:<18} score {a.score:.2f} -> {level!r:<18} conf={a.confidence:.2f}")
1. Noul: a yes/no question, answered with a probability¶
The state is the thing being judged. The question is typed. You get a number back, not a paragraph.
r = ask_jev(
"The delivery arrived two weeks late and the box was crushed. Not ordering again.",
{"complaint": Noul(instructions="Is the customer complaining?")},
)
print("P(complaint) =", r.nouls["complaint"].noul)
print("model:", r.model)
P(complaint) = 0.99 model: typesafe/jev-1.13-20260917
2. Choice: pick one of N named options¶
You define the options, so Jev cannot invent a new one. You get the winner, a probability for every option, and a confidence.
r = ask_jev(
"I was charged twice for my subscription this month and nobody answers the phone.",
{"team": Choice(
instructions="Which team should handle this message?",
criteria={
"billing": "payments, invoices, refunds, charges",
"technical": "bugs, outages, errors, integrations",
"sales": "pricing questions, upgrades, new contracts",
"other": "anything else",
})},
)
a = r.choices["team"]
print("choice:", a.choice, "| confidence:", a.confidence)
print("probabilities:", a.probabilities)
choice: billing | confidence: 1.0
probabilities: {'sales': 0.0, 'other': 0.0, 'technical': 0.0, 'billing': 1.0}
3. Score: a position on an ordered scale¶
The levels are ordered, so the score is fractional: a score of 1.6 sits between level 1 and level 2. That tells you more than a single label would.
r = ask_jev(
"Production checkout has been down for 20 minutes and customers are tweeting about it.",
{"urgency": Score(
instructions="How urgent is this for the on-call engineer?",
criteria=["can wait until next week", "today", "within the hour", "drop everything now"])},
)
a = r.scores["urgency"]
print("score:", round(a.score, 2), "| legend:", a.legend, "| confidence:", a.confidence)
score: 2.96 | legend: {0: 'can wait until next week', 1: 'today', 2: 'within the hour', 3: 'drop everything now'} | confidence: 0.96
4. Fan-out: many questions, one call¶
Jev answers every question about the same state in a single request, in parallel. It does not generate them one after another the way an LLM generates tokens.
msg = "Help! Payouts have failed for 3 days and my team can't get paid. This is unacceptable."
t0 = time.perf_counter()
r = ask_jev(msg, {
"is_urgent": Noul(instructions="Does the message convey urgency?"),
"department": Choice(instructions="Which team handles this?",
criteria={"billing": "payments, payouts, invoices", "technical": "bugs, outages",
"account": "login, profile, permissions"}),
"frustration": Score(instructions="How frustrated is the customer?",
criteria=["calm", "annoyed", "frustrated", "furious"]),
"wants_refund": Noul(instructions="Is the customer explicitly asking for money back?"),
})
print(f"4 questions, 1 call, {1000 * (time.perf_counter() - t0):.0f} ms")
show(r)
4 questions, 1 call, 364 ms
is_urgent noul P(yes)=0.98
department choice 'billing' conf=0.98 top=[('billing', 0.99), ('technical', 0.01), ('account', 0.0)]
frustration score 2.80 -> 'furious' conf=0.80
wants_refund noul P(yes)=0.11
5. State can be JSON¶
Real systems have structured records such as tickets, rows and events. Pass them as they are. Jev reads keys and values.
ticket = {
"customer": {"plan": "enterprise", "seats": 1200, "tenure_years": 4},
"subject": "SSO broken after your update",
"body": "Since this morning nobody in our org can sign in through Okta. 1,200 people are locked out.",
}
r = ask_jev(ticket, {
"severity": Score(instructions="How severe is the business impact?",
criteria=["minor", "moderate", "major", "critical"]),
"churn_risk": Noul(instructions="Is this customer at risk of leaving if this is not fixed fast?"),
})
show(r)
severity score 2.99 -> 'critical' conf=0.99 churn_risk noul P(yes)=0.83
6. criteria sharpen the question (Jev reads literally)¶
Jev takes your wording literally. Ask a vague "is this urgent?" about a sale email that says URGENT and you get a fence-sitting answer. State the exact condition you mean and the answer becomes decisive. For a Noul, criteria defines what true and false mean.
text = "URGENT!!! Our 50% OFF flash sale ends TONIGHT. Don't miss out!!!"
loose = ask_jev(text, {"q": Noul(instructions="Is this urgent?")})
strict = ask_jev(text, {"q": Noul(
instructions="Will the recipient suffer real harm (outage, data loss, money lost, blocked work) "
"if they do not act within the next hour?",
criteria={"true": "a real deadline with real consequences", "false": "marketing pressure or no consequence"})})
print("loose P(yes) =", loose.nouls["q"].noul)
print("strict P(yes) =", strict.nouls["q"].noul)
loose P(yes) = 0.44 strict P(yes) = 0.04
7. Fast brain vs slow brain, head to head¶
The same yes/no question goes to Jev and to the LLM. Watch the latency. Then remember that Jev gave you a probability, while the LLM gave you a string you would still have to parse.
text = "URGENT: your bank account is locked. Verify now at http://secure-bank-login.test/verify"
t0 = time.perf_counter()
r = ask_jev(text, {"scam": Noul(instructions="Is this SMS a phishing scam?")})
jev_ms = 1000 * (time.perf_counter() - t0)
t0 = time.perf_counter()
reply = chat(f"Is this SMS a phishing scam? Answer yes or no.\n\n{text}")
llm_ms = 1000 * (time.perf_counter() - t0)
print(f"Jev : P(scam)={r.nouls['scam'].noul:.2f} {jev_ms:5.0f} ms")
print(f"LLM : {reply.strip()!r:<12} {llm_ms:5.0f} ms")
Jev : P(scam)=0.97 400 ms LLM : 'Yes.' 2598 ms
8. What did this notebook cost?¶
SPEND is filled in by ask_jev and chat. OpenRouter reports the exact USD cost of every call.
print(SPEND)
print(f"average Jev call: ${SPEND.usd['jev'] / max(SPEND.calls['jev'], 1):.7f} -> "
f"${1000 * SPEND.usd['jev'] / max(SPEND.calls['jev'], 1):.4f} per 1,000 decisions")
Jev: 8 calls $0.00012 | LLM: 1 calls $0.00002 average Jev call: $0.0000144 -> $0.0144 per 1,000 decisions
Recap¶
- A Jev call is
state+ typed questions -> typed, calibrated answers. You design the questions, so there is nothing for it to hallucinate. Noulgives P(yes),Choicegives one of N with probabilities, andScoregives a position on a scale. Asking several questions at once costs one call.- Jev is not a chat model. It cannot write, count or do date arithmetic. Keep math and dates in code (notebook 02 shows why).
The idea behind this whole course: Jev makes the thousands of small, fast decisions, and the LLM does the few expensive things that need language.
Next: 02_jev_vs_llm.ipynb benchmarks Jev against the LLM on 40 labeled SMS: accuracy, latency, cost and calibration.