P2 · Trust Engineering · Productive Architecture & Deterministic Routing
The wrong tool is not a acceptable approach
285 tools, 30 queries, a critical mission banking domain. As a pre-execution barrier of four layers led 7 incorrect executions to zero — and how the solution evolved from a proof of concept (PoC) to a High performance productive architecture blueprint with Cold/Hot Path decoupling and SLAs sub-2ms.
Measured in the MVP benchmark · 30 queries · 53 training examples · molded tools · offline
Deterministic output of python -m candidate_starter.run_case Measured in the MVP benchmark —
is not the system's accuracy in production or total financial economy. The ability is to choose the right tool;
Trust is knowing when not to execute any.
- In a sentence
- A bank agent router that chooses 2 tools between 285 and blocks execution when the decision is unreliable enough. The ability is to choose the right tool; trust is to know when not to execute any.
- Format
- Technical Case
- Depth
- In-depth reading · ~3 min for central idea · ~31 min complete
You prefer the essentials first? Read synthesis (~1 min)
Video summary
The case in a video
"The Machine of Trust: Case Study in Banking Genetic Development" — general view before technical deepening: the problem, the Silent Crash, the barrier of Four guards and what the numbers prove -- and what they don't prove.
01 · The Enunciate
The project: what was asked in a banking agent brain
Build routing brain from a digital bank service agent. Before any expensive LLM call, the system decides the cheapest and safest way to answer each message.
The three pillars of architecture
| Pillar | Engineering Problem | Code Component |
|---|---|---|
| 1 · Router | Sort Query in FAST_PATH (Cheers/FAQ) or AGENT (needs tool + reasoning). |
candidate_starter/router.py |
| 2 · Retrieval Tool | Select 2 more relevant tools between 285 before mounting the LLM prompt. | candidate_starter/retrieval.py |
| 3 · Evaluation Harness | Measure quality, cost, latency and security in a deterministic way offline. | candidate_starter/harness.py |
The non-negotiable restriction of the domain
"This is a banking domain. An incorrect tool is not an acceptable approach.
Never execute a tool if the decision is below safety thresholds.
Never remove quality gates just to increase recall or economy.
Do not use expected_tool the dataset within the production logic.
This field can only be used by the harness to evaluate offline."
The Border: production does not see the template
What separates adjustment engineering from template is one line: expected_tool
lives in evaluation layer and never in production logic.
Decide with signs available at the time of application: confidence of the router, score of the retriever, relative margin and the verb of the query. Nothing more.
expected_tool Do eval_dataset.json only read
Here.offline to score Hit Rate after the decision has already been made.
grep -n "expected_tool" candidate_starter/retrieval.py candidate_starter/router.py candidate_starter/taxonomy.py
# Saída: zero resultados.
02 · Lifecycle & Engineering Decision
Two Strategies, One Domain: Prototyping Agility vs Robustez Enterprise
In senior software engineering, a technical solution does not exist in the vacuum. The official repository
case-agents implements and documents two active architectural approaches in parallel branches,
demonstrating the deliberate transition of an exploratory Concept Proof (PoC) to a mission-critical governance system.
Approach 1: Lean PoC
Branch:feature/solucao-enxuta
Strict focus on minimum testing speed and footprint. Implement router
and the retriever in direct Python: Platt calibration, capacity collapse and steering guard exist, but embedded in router.py and retrieval.py, no taxonomy module and no ADRs.
Ideal for quick validation of product viability and starting benchmark.
Pros & Trade-offs:
- Pro: Clean code (~560 lines in four modules and a script), easy to audit and deliver in a few days.
- Pro: Low cognitive friction for early-stage teams.
- Against: Branch Harness Prints 26.3% of Precision@2, because it compares the name of the variant with the canonical name; recounted by capacity, are 20/20 in the top-2 (see Statistics in Code).
- Against: 16.7% abstentions (5 out of 30), and the steering guard only covers reading→written in the tools that the prefix of the name reveals (167 out of 285 tools).
Approach 2: SDD Enterprise & Trust
Branch:main (old solucao-sdd-vibe)
Focus on banking reliability, compliance and industrial life cycle. Adopt Spec-Driven Development (SDD), 9 formal ADRs, canonical capacity taxonomy, Platt Scaling calibration, 4-layer barrier (including Steering Guard) and the blueprint for high performance compiled inference.
Pros & Trade-offs:
- Pro: 100% Hit Rate@2 and zero incorrect executions formally guaranteed.
- Pro: Proven protection against damage to the client's bank record (G4).
- Pro: Ready for industrial scale: manifesto
APM.ymland ADR-009 (Rust/Go). - Against: Requires continuous discipline of catalog governance and parity tests.
The lesson of duality: In the validation phase (PoC), the Shiny Solution is tempting by speed.
However, in finance or health, the cost of incorrect execution in production exceeds the cost of governance infinitely.
A branch main there is to demonstrate how to overcome this barrier with engineering rigor.
03 · The Measure Failure
Silent Crash: the failure that 54 tests did not catch
In an intermediate iteration (commit c8f30d2), the project showed:
54 tests on green, 100% router, 100% Hit Rate@2, zero incorrect executions and status approved with praise.
An external review, however, requested a collision test between reading and writing vocabulary.
Customer Query: "What's the email registered to my account?" — a READING.
Margin (0.4795 − 0.2554) / 0.4795 = 0.467 >> 0.25 → the margin guard it won't catch. High trust, high score, loose margin: IMPLEMENTATION — The officer alters the record of those who only asked.
The Query is for reading; the writing ability is discarded before the ranking. Margin (0.3891 − 0.1792) / 0.3891 = 0.539 > 0.25 → runs the consultation, dry cut, no transition.
None of the three old guards took it: the mistake It's not a tie. — is a decision confident and wrong. This illustrates the central thesis of the pillar Trust Engineering: the most dangerous error in AI does not generate code exception. He passes the green and makes a ruinous decision with loose margins.
04 · Structural Diagnosis
Why no vectorization weight solves the problem
When the problem appeared, the first attempt was to adjust the combination of weights between lexical search and intent search (score = (1−α)·lexical + α·intent). The mathematical demonstration below proves why this is impossible:
Query: "Quero mudar o e-mail vinculado a minha conta" (ESCRITA)
consultar_email_vinculado_conta -> lexical = 0.8457 | intent = 0.4400
atualizar_email -> lexical = 0.1983 | intent = 0.3200
Para a escrita vencer por ajuste de α:
(1 - α)·0.1983 + α·0.3200 > (1 - α)·0.8457 + α·0.4400
α·(0.3200 - 0.4400 - 0.1983 + 0.8457) > 0.8457 - 0.1983
0.5274·α > 0.6474 => α > 1.227 (IMPOSSÍVEL, pois α ∈ [0, 1])
The structural lesson: Reading and writing on the same object share all nouns (e-mail, conta, cadastro).
The difference between consultation and change is one word: the verb. In a bag of words with TF-IDF, this verb is diluted between ten tokens. The direction of the operation is not recoverable by textual similarity — it needs to be a semantic restriction declared.
05 · The Rigid Solution
The 4 Layers Pre-Execution Barrier
Four deterministic guards chained up. The Query only advances to the LLM and to the execution of tools if it passes through all four locks. If any guard fails, the system diverts to abstinence or human care.
The deliberate asymmetry of Guard 4
- WRITTEN READ CHERY + WRITTEN Tool: Total disposal of tool. Changing the record of those who just asked is irreversible damage to the customer.
- Written Query + READING Tool: Score down, don't rule it out. Refer to those who requested change is unfulfilled task — recoverable in the following message.
06 · MVP Pipeline
Architecture in 4 Layers (Mathematics Validation in Python)
the complete flow of the application until the execution authorisation on the validation engine:
- Query user
-
Router — TF-IDF + LogisticRegression + Platt scaling
FAST_PATH→ local response, zero cost of LLMAGENTbelow - Taxonomy — catalogue governance: capacity
- Retriever —
top-kdifferent capacities - Barrier — 4 guards in order: G1 · G2 · G3 · G4 Failure in any guard → Abstention or human care
- LLM — called only after the barrier authorized
- Tool execution
TfidfVectorizer(ngram_range=(1,2)) + LogisticRegression calibrated via CalibratedClassifierCV(method="sigmoid") Platt scaling.
Solves the problem of underconfidence by regularization L2 in small dataset without artificially inflating probabilities.
Declaration of 14 canonical capabilities and 45 variants with operation mode (read or write).
Map the user vocabulary (aliases) for intentions and solve semantic duplicates of the catalog.
BM25F score combination: score = 0.5·lexical + 0.5·intent.
The alias glossary is indexed in a separate field to prevent L2 normalization from diluting the original terms. It performs capacity collapse by returning different canonical top-k.
Quality Gate tri-state (APROVADO, REPROVADO, INDETERMINADO).
Validate the four guards before the execution mock. If there is no transactional query in the benchmark, the result is marked as UNDETERMINED by security.
07 · Statistics in the Code
The five statistical techniques of the case and Python implementing them
Whoever decides on this pipeline is not a language model. There are five classic statistical and statistical techniques information retrieval, each responding to a concrete problem of banking service. Each technique below has two layers: the concept, in simple language, and the Python excerpt that implements it.
The snippets are from the branch feature/solucao-enxuta (commit)
e2dcd7f),
the simplified version: four modules and an execution script, about 560 lines, without
taxonomy.py And no ADRs. Where the main does different, a note warns.
The numbers come from the output of python -m candidate_starter.run_case in this branch and
offline recounts on the same report. It's not the numbers of main quoted in the rest
from the page.
| Technique | Operational problem | Where in code |
|---|---|---|
| 1 · TF-IDF + logistic regression | Decide, cheap and in milliseconds, if the message needs an agent. | router.py · QueryRouter |
| 2 · Platt scaling + cross-validation stratified | Doing the number "0.75" means a probability of right. | router.py · fit() |
| 3 · Multi-field cosine + capacity collapse | Find two tools between 285 without returning two duplicates. | retrieval.py · ToolRetriever.search |
| 4 · Thresholds, relative margin and steering guard | Know when no execute. | harness.py · run_harness; retrieval.py |
| 5 · Evaluation and economics metrics | Prove it works without counting how I get what's just abstention. | harness.py · compute_* |
1 · Supervised classification: TF-IDF and logistic regression
Operational problem. Greetings and FAQ questions ("What time is it?") do not require
LLM or tool. Answer this locally has zero cost of LLM. The router needs to separate
FAST_PATH of AGENT in milliseconds, before any man calls.
Concept. Supervised rating is to teach with examples already labeled: here, 53 messages marked
FAST_PATH (25) or AGENT (28) The model learns what separates the two
classes and applies this to new messages, in two steps: turn text into numbers and learn a boundary between classes.
O TF-IDF gives each term a weight that grows with its frequency in the message (TF) and decreases with the number of messages from the set containing it (IDF). "De" appears in almost everything and weighs little; "block" appears in few and weighs much. With n-grams from 1 to 2 terms, pairs like "second way" also saw terms. Each message becomes a sparse vector (almost everything zero) length 1.
A logistic regression transforms a weighted sum of the terms into a probability, between 0 and 1, of a
message be AGENT. A regularisation L2 penalty large weights, for model not
decorate 53 examples; C control force (1.0 is the scikit-learn pattern and is the value used).
It is a linear and light classifier, and each term has a coefficient that you can read, which matters in an audit.
tf-idf(t, d) = tf(t, d) × idf(t) idf(t) = ln((1 + n) / (1 + df(t))) + 1
vetor(d) = tf-idf(d) / ‖tf-idf(d)‖₂ (norma L2 = 1)
P(AGENT | x) = σ(w·x + b) = 1 / (1 + e^−(w·x + b))
o treino minimiza: ½‖w‖² + C · Σ log-loss(yᵢ, P(xᵢ)) (C = 1,0)
self._vectorizer = TfidfVectorizer(
ngram_range=(1, 2),
min_df=1,
preprocessor=normalize,
)
self._base_clf = LogisticRegression(C=1.0, max_iter=1000, random_state=42)
def normalize(text: str) -> str:
if not text:
return ""
# 1. Lowercase
text = text.lower()
# 2. Remover acentos
text = remove_accents(text)
# 3. Variantes ortográficas do domínio (antes de remover pontuação se houver hífens)
for pattern, replacement in DOMAIN_VARIANTS:
text = re.sub(pattern, replacement, text)
# 4. Remover caracteres especiais (manter apenas letras, números e espaços)
text = re.sub(r"[^a-z0-9\s]", " ", text)
# 5. Colapsar múltiplos espaços
text = re.sub(r"\s+", " ", text).strip()
return text
normalize() is the preprocessor vectorizer, then the same treatment
(low, without accent, domain variants as "second way" → segundavia, no score)
in practice and consultation. If the two were normalized differently, the vocabulary learned would not marry the
Real question.
Measured in this branch:
- Vocabulary of 378 terms (unigrams and bigrams) on the 53 training examples.
- Router 30/30 in benchmark; confusion matrix FAST_PATH 10 · 0 / AGENT 0 · 20.
predict(), already with the calibration of technique 2: median of 2,2 ms and p95 of 4,4 ms in 200 local calls (Windows, scikit-learn 1.9).
2 · Probability calibration: Platt scaling and cross-validation stratified
Operational problem. Guard G1 threshold of 0.75 (section The Barrier) is only a policy
risk if "0.75" means "the model fits in about 75% of cases". Regular logistic regression, with 53 examples and
378 terms, shrink the weights and return shy odds, close to 0.5, even when the class is right. No calibration,
in this branch, 20 of the 20 messages AGENT Benchmark is below 0.75 (the highest confidence is 0.713),
Although the router hits them all. The threshold would no longer separate a good decision from a bad decision and only rule out coverage.
Concept. Calibrate is to correct the number scale without changing what the model decides. O Platt schedule trains a second logistic regression of a single variable on the gross score f The model. Parameters A and B are estimated by maximum likelihood in forecasts made on examples that the template no saw in practice (out-of-fold: predictions about the part of the data left out in each round). To estimate them in the very examples of training would measure the model memory, not the ability to generalize.
A cross-validation stratified divides the 53 examples into 3 folds that preserve the proportion of classes; each
fold serves once as an unseen set. No shuffle (shuffle=False), the folds are the same in
Any machine, and the tests are reproducible. Code does not call StratifiedKFold directly: pass
cv=3 to a classifier makes the scikit-learn use this divider (checked in version 1.9). The number of
folds come from the smallest class: 3 if it has at least 3 examples, 2 if it has 2, and without calibration below that, for the
fit() do not break into tiny test sets.
Why sigmoid and not isotonic. Isotonic calibration is nonparametric: with few data it overfits and
saturates confidence around 1, the opposite problem. The sigmoid has two parameters and is stable. A main
measured this comparison in the
ADR-007.
Platt: p(AGENT | f) = 1 / (1 + exp(A·f + B)) A, B por máxima verossimilhança, em dados fora da dobra
Dobras: StratifiedKFold(n_splits=3, shuffle=False) → 3 modelos calibrados; a probabilidade final é a média
# Contar menor número de amostras por classe
unique_labels, counts = np.unique(labels, return_counts=True)
min_class_count = int(np.min(counts))
if min_class_count >= 3:
cv = 3
elif min_class_count >= 2:
cv = 2
else:
cv = None
if cv is not None:
self._clf = CalibratedClassifierCV(estimator=self._base_clf, method="sigmoid", cv=cv)
else:
self._clf = self._base_clf
self._clf.fit(X, labels)
X_q = self._vectorizer.transform([query])
probs = self._clf.predict_proba(X_q)[0]
best_idx = np.argmax(probs)
route = str(self.classes_[best_idx])
confidence = float(probs[best_idx])
Measured in this branch:
- No calibration, 20 of 20 messages
AGENTare below 0.75. With calibration, 1 of 20 (0,732). -
In the entire benchmark, G1 barred 2 messages: "I changed number, I need to update the registered phone"
(
AGENT, 0.732) and "What documents do I need to open an account?" (FAST_PATH, 0.718). In this branch, G1 is for both routes. - The least confidence accepted is 0,753: 0.003 slack on the threshold. Calibration corrected the scale, but the margin remains narrow.
-
The repository does not measure the calibration itself (Brier score, expected calibration error, reliability curve), only its effect on the threshold.
With 20 queries
AGENT, a reliability curve would have few points per range.
3 · Vector recovery: Cosine similarity, multi-field score and capacity collapse
Operational problem. The catalog has 285 tools. Putting all in the prompt of an LLM bursts the context, confuses the model and cost expensive, so the retriever chooses the 2 most relevant before any call. And the catalogue has duplicates: 8 different tools make "get the invoice".
Concept. A Cosine similarity measures the angle between two vectors: 1 when they have the same weighted vocabulary, 0 when they do not share any term. As TF-IDF already delivers vectors of length 1, cosine is only the scalar product, that is, a multiplication of sparse matrix between the query and the 285 tools.
The score combines two fields with equal weight. The tool document is nome + descrição + categoria;
Intention field is nome + descrição. Keep fields separate, instead of concatenating everything, exists for
that L2 normalization does not dilute the original terms when adding synonyms to the same text
(the ADR-006
ed main document this problem). A list of functional words (a,
de, para, quero...) comes out of vocabulary first, for a
Query short not only score by prepositions.
A limit on this branch. The two fields come out of the same text: they differ only by category. Measured, the correlation between
two similarities is at least 0.97, and the top-1 of the combined score is identical to that of the single field in the 30 queries. Here, α = 0,5
It hardly changes the result. A second field only helps when it brings new information, like the handwritten glossary of
main.
O capacity collapse groups duplicates with an embedded dictionary (CANONICAL_TOOL_MAP:
49 tools in 12 capacities) and holds the highest score per group (max-pooling, a maximum aggregation). Like this.
k=2 returns two distinct capacities, not two variants of it. Then the code orders by score
decreasing and cuts into k. Candidates with score 0 are discarded: a query without any common word with
the catalog returns empty list. Empates follow the order of the catalogue, because the sorted Python is stable.
This is deterministic for the same file, but it is not an explicit tiebreaker (a main Untie by the name of
capacity).
cos(q, d) = (q · d) / (‖q‖ · ‖d‖) = q · d (vetores TF-IDF com ‖v‖₂ = 1)
score(ferramenta) = (1 − α) · cos(q, documento) + α · cos(q, intenção) α = 0,5
score(capacidade) = max { score(t) : t pertence à capacidade } (colapso por máximo)
doc_texts = []
intent_texts = []
for tool in tools:
# Document text: name + description + category
doc_text = f"{tool.name} {tool.description} {tool.category}"
doc_texts.append(doc_text)
# Intent text: name.replace("_", " ") + description
intent_text = f"{tool.name.replace('_', ' ')} {tool.description}"
intent_texts.append(intent_text)
self._doc_matrix = self._doc_vectorizer.fit_transform(doc_texts)
self._intent_matrix = self._intent_vectorizer.fit_transform(intent_texts)
doc_sims = cosine_similarity(q_doc_vec, self._doc_matrix)[0]
intent_sims = cosine_similarity(q_intent_vec, self._intent_matrix)[0]
combined_scores = (1 - self.alpha) * doc_sims + self.alpha * intent_sims
# Apply direction guard & canonical collapsing
canonical_best: Dict[str, Tuple[str, float]] = {}
for idx, tool in enumerate(self._tools):
score = float(combined_scores[idx])
# … (guarda de direção: técnica 4)
if score <= 0:
continue
canon_group = get_canonical_name(tool.name)
if canon_group not in canonical_best or score > canonical_best[canon_group][1]:
canonical_best[canon_group] = (tool.name, score)
# Sort matches by score descending
sorted_matches = sorted(canonical_best.values(), key=lambda item: item[1], reverse=True)
top_k_matches = [ToolMatch(name=name, score=score) for name, score in sorted_matches[:k]]
Measured in this branch: recounting by capacity (get_canonical_name on the result),
expected capacity is in the top-1 in 19 of 20 transactional and top-2 in 20 of 20. The report
Print shows another number. The explanation is in technique 5.
4 · Decision under uncertainty: thresholds, relative margin and steering guard
Operational problem. Choosing the best tool is not enough: the system needs to know when no execute. A mistake that passes in silence (see The Silent Crash) costs more than a confirmation question.
Concept. Instead of always acting on the best candidate, the pipeline tests three statistical signals, in order, and only
Execute if everyone passes. None of them read the expected_tool the gauge.
- G1 · confidence: the calibrated probability of the router is ≥ 0.75.
- G2 · minimum relevance: the top-1 score is ≥ 0.10, a floor against weddings by chance.
-
G3 · relative margin:
(s₁ − s₂) / s₁ ≥ 0,25. Measure how much the first candidate wins the second in proportion of the score itself. It is relative not to depend on the scale: a difference of 0.03 weighs different when the Top-1 is 0.18 and when it's 0.80.
# Guard Rail 1: Router confidence >= 0.75
confidence = route_result.confidence if route_result.confidence is not None else 1.0
if confidence < 0.75:
row["final_status"] = "HUMAN_FALLBACK_LOW_CONFIDENCE"
abstentions += 1
elif route_result.route == "FAST_PATH":
fast_path_answer(query)
else:
retrieval_result = retriever.search(query, k=k)
# …
# Guard Rail 2: Top-1 score >= 0.10
top1_score = top_k_matches[0].score if top_k_matches else 0.0
if top1_score < 0.10:
row["final_status"] = "ABSTAIN_LOW_SCORE"
abstentions += 1
else:
# Guard Rail 3: Margin relative >= 0.25
top2_score = top_k_matches[1].score if len(top_k_matches) > 1 else 0.0
margin = (top1_score - top2_score) / top1_score if top1_score > 0 else 0.0
if margin < 0.25:
row["final_status"] = "AMBIGUOUS_CONFIRMATION"
abstentions += 1
else:
# Executa a tool top-1
mock_tool_execution(top_k_names[0], query)
The margin in three real issues, all diverted by G3 in the benchmark:
| Query | Top-1 and top-2 (score) | Margin | Result |
|---|---|---|---|
| "I lost my card on the street, I need to block it now" | bloquear_cartao 0,180 · bloquear_cartao_temporariamente 0,177 |
0,017 | AMBIGUOUS_CONFIRMATION |
| "I changed addresses, how do I update my delivery?" | alterar_endereco 0,474 · consultar_endereco_cadastrado 0,434 |
0,084 | AMBIGUOUS_CONFIRMATION |
| "Did my new card arrive, how do I unlock?" | instrucoes_desbloqueio_cartao_novo 0,546 · confirmar_recebimento_cartao_novo 0,420 |
0,231 | AMBIGUOUS_CONFIRMATION |
The third failure by 0.019: 0.25 is a policy, not a constant of nature. In this branch the three thresholds are literal in
code; main are named constants, and the margin is harness parameter.
G4 · steering guard. It is not a measure of similarity, and the reason is statistical: reading and writing about the
even given divide almost all the terms (the section Why no weight solves shows the
arithmetic). Then the direction enters as a declared sign: Query verbs and keywords say whether it is reading or writing, and the
tool name prefix (consultar_, atualizar_...) says what kind she is.
Reading Query with writing tool: zeroed score.
def infer_query_direction(query_norm: str) -> str:
"""Inferir direção da query: 'read', 'write', ou 'unknown'."""
has_read = any(re.search(rf"\b{kw}\b", query_norm) for kw in READ_QUERY_KEYWORDS)
has_write = any(re.search(rf"\b{kw}\b", query_norm) for kw in WRITE_QUERY_KEYWORDS)
if has_read and not has_write:
return "read"
if has_write and not has_read:
return "write"
return "unknown"
def infer_tool_direction(tool_name: str) -> str:
"""Inferir direção da ferramenta pelo prefixo."""
if tool_name.startswith(READ_TOOL_PREFIXES):
return "read"
if tool_name.startswith(WRITE_TOOL_PREFIXES):
return "write"
return "unknown"
# …
# Direction guard rule: read query + write tool -> score = 0
if query_direction == "read" and tool_direction == "write":
score = 0.0
Measured and limited in this branch:
-
Protected reading. "What's the email registered to my account?"
confirmar_email_cadastrado(reading) first.atualizar_emaildoesn't appear among the first three. -
Writing→reading is not treated. The lean specification expected to lower the reading tool, but the code does nothing in this
Meaning. "I want to change the email linked to my account" executes
consultar_email_vinculado_conta(score 0.664): It doesn't change anything, but it doesn't comply. - You only see what the name reveals. By prefix, 82 of the 285 tools are read, 85 are write and 118 tools (41%) they do not reveal direction by name and pass without restriction.
-
Reading grouped under writing. The collapse dictionary puts
consultar_email_vinculado_contaandconfirmar_email_cadastrado, reading tools, underatualizar_emailThat's writing. Amainprohibits this by invariant: reading and writing do not group.
5 · Evaluation and economics metrics
Operational problem. Without measurement, "works" is opinion. And a misread metric is worse than none: cost savings It goes up when the system abstains further, even if it answers less.
Concept. A accuracy is the proportion of correct answers: correct answers divided by the total. A confusion matrix 2×2 separates the two errors
possible, which cost different things: send an FAQ to the agent spends LLM for nothing; send a transactional request to
FAST_PATH gives the customer a generic response in place of the operation. The code initializes all cells with zero,
then the structure is complete even without cross errors.
O hit rate@k is the fraction of the queries in which the expected tool appears among the first k. Not Precision@K
classic (relevant between k, divided by k): with one relevant tool and k = 2, maximum precision@2 would be 0.5. The function if
flame compute_precision_at_kBut what she calculates is hit rate.
A economy is the percentage reduction against baseline (send all message to the LLM, with all the tools in the prompt), with guard to baseline zero. In MVP, costs and latencies come from mock constants (US$ 0.03 per baseline call, US$ 0.01 per called the agent), so the percentage measures the pipeline structure, not a real price.
acurácia = acertos / total
hit rate@k = (queries com a ferramenta esperada no top-k) / (queries avaliadas)
economia % = (baseline − pipeline) / baseline × 100 (0 se baseline = 0)
correct = sum(1 for yt, yp in zip(y_true, y_pred) if yt == yp)
accuracy = correct / len(y_true)
matrix = {l1: {l2: 0 for l2 in labels} for l1 in labels}
for yt, yp in zip(y_true, y_pred):
if yt in matrix and yp in matrix[yt]:
matrix[yt][yp] += 1
# …
def compute_precision_at_k(hits: List[int]) -> float:
"""Calcula Precision@K a partir de uma lista de 0/1 (acertou ou não a tool)."""
if not hits:
return 0.0
return float(sum(hits) / len(hits))
# …
cost_savings = 0.0
if baseline_cost_usd > 0:
cost_savings = ((baseline_cost_usd - smart_cost_usd) / baseline_cost_usd) * 100.0
Output of python -m candidate_starter.run_case in lean branch, 30 queries:
| Metric | Value | Origin |
|---|---|---|
| Router accuracy | 100% (30/30) · matrix 10 · 0 / 0 · 20 | printed |
precision_at_k (k = 2) |
26,3% (5/19) | printed |
| Expected capacity per capacity | top-1 19/20 · top-2 20/20 | offline recount |
| Abstentions | 5 (16.7%): 2 per G1.0 per G2, 3 per G3 | printed; division by guard, recount |
| Executions | 16, of which 15 in expected capacity | offline recount |
| Cost: pipeline/baseline | US$ 0.16003 / US$ 0.90000 → savings of 82.2% | printed |
Because 26.3% is not the quality of recovery. O ToolMatch.name which the retriever returns is the name of
variant that married (e.g. verificar_saldo_conta_corrente), and expected_tool
the dataset is the name canonical (consultar_saldo). The string comparison fails even with the right ability.
Recounting for capacity, the result is 19/20 and 20/20. The denominator is also 19, not 20: the Query barred by G1 never reached the retriever and
It's out of line.
Because 82.2% is larger than 77.8% of the rest of the page. Five messages were diverted by abstention and did not call LLM. It's the
the same effect as described in Economy without success rate is disguised risk: the economy rises when the system does
Less. The execution that comes out of the expected capacity is "Send the pdf of my current invoice" → reenviar_fatura_email, that the
dictionary does not group into consultar_fatura. And the right 15 include the email query, whose reading tool
dictionary groups under atualizar_email. The lean branch does not calculate incorrect executions or the balance point of the
human service cost: these two accounts only exist in the main.
lean branch × main, technique by technique
| Point | lean Branch | main |
|---|---|---|
| Calibration folds | cv = 3 (less class ≥ 3) |
until 5: min(5, menor classe) |
| Second score field | derived from name and description: almost redundant | Handwritten glossary by capacity, indexed in separate field |
| Capacity collapse | built-in dictionary: 49 variants, 12 capacities | taxonomy.py: 14 capacities, 45 variants, with tested invariants |
| Untie | stable order of the catalog | direction, then −score, then capacity name |
| Score floor (G2) | in harness; the retriever only discards score ≤ 0 | min_score in the retriever, with 0,10 passed by those who mount it |
| Direction (G4) | name prefix; read-only→write zera | mode declared (59 of 285); reading→discard writing, writing→low reading |
| Metrics | precision_at_k by exact name |
hit rate@1 and @k, correct and incorrect executions, balance point, quality gate tri-state |
The five techniques are simple and cheap in both branches. What separates the lean from main is not a technique anymore
sophisticated, but what surrounds each: a field with new information, declared direction, a metric contract that compares capacity with
ability and an explicit tiebreaker.
08 · From proof of concept to production
High Performance Multi-Language Architecture (ADR-009 & RFC)
MVP Python pipeline proved the mathematical solidity of the engine: 100% accuracy and zero incorrect executions.
However, transfer Python pods directly to critical banking production path (attending tens of thousands
requests per second with SLA p99 < 1-3 ms) runs into unavoidable limitations:
o Global Interpreter Lock (GIL), the Garbage Collection (GC) unpredictable jitter
and the cost of dynamic dismatch.
The formalized engineering response in ADR-009 and RFC Architecture is the strict decoupling between Cold Path and Hot Path:
Cold Path: Search & MLOps
Python 3.12 · Offline / CI
Keeps the Python ecosystem where it is unbeatable: feature engineering, training with scikit-learn,
calibration via CalibratedClassifierCV (Platt Scaling), SHAP and generation of deterministic artifacts.
- ONNX Export: Compiled linear inference graph (
modelo_router.onnx). - CSR Sparsa Matrix: The 285 documents in the catalogue are pre-computed and serialized in
doc_matrix.csr. - Deterministic Vocabulary: IDF-indexed TF-IDF Dictionary (
vocab_tfidf.json). - Banking immutability: Object Storage versioned artifacts signed with hash SHA-256.
- Hard Insulation: The production runtime never matters Python, numpy or scikit-learn.
Hot Path: OmniRoute Gateway
Rust / Go · Online StatelessSingle stateless input point via gRPC or HTTP/2. Built-in inference motor (in-process), eliminating network jumps, intermediate serialization or IPC calls.
- Zero Garbage Collection: Rust operates without garbage collector, eliminating jitter and ensuring deterministic latency p99 (< 1-3 ms).
- Zero-allocation on Hot Path: Static pools and pre-allocated buffers via
tokioand memory arenas. - Guard of 4 Layers in RAM: Router, Retriever (multiplication of parallel sparse matrix) and Guard Rails executed in < 10 μs.
- Distroless Container: Single static torque (~20 MB) with minimal attack surface and memory safety proven by the compiler.
- Slot-Filling Rinse: The LLM is only invoked when the tool has already been isolated and authorized.
Technology Decision Matrix: Rust vs Go
The architecture document thoroughly compares engineering options for OmniRoute Gateway:
| Assessment Criteria | Rust (Primary Recommended) | Go (secondary alternative) |
|---|---|---|
| Memory Management | Zero GC (Ownership & Borrow Checker). No unpredictable breaks. | Garbage Collector with sub-millissecond pauses, but with jitter risk under high string volume. |
| Latency p99 | Sub-milissecond (< 1 ms) deterministic and predictable. | 2 ms to 5 ms (small oscillations during GC collections). |
| Competition | tokio (I/O non-blocking) + rayon (data parallelism). |
Native Goroutines and canals. Excellent I/O competition. |
| Linear algebra & ONNX | Crate ort (official ONNX Runtime zero-overhead bindings) + sprs (CSR). |
onnxruntime-go via CGo (context exchange cost Go ↔ C). |
| Compliance and Security | Formal prevention of data races and buffer overflows in compilation time. | Memory safe, but at risk of excessive allocations in the heap. |
| Artifact of Delivery | Static torque (~15-25 MB), container distroless. |
Static torque (~20-30 MB), container distroless. |
The Architecture Decision Ecosystem (9 ADRs)
Each structural choice was recorded according to the Architecture Decision Record (ADR), ensuring that any new team member understands the context, discarded alternatives and consequences:
Multi-Language architecture & Cold/Hot Path Decoupling
Offline Python pipeline segregation for inference compiled in Rust/Go with latency p99 < 1-3 ms.
Steering Guard (Read vs Writing)
Silent Crash Final Containment: Reading Queries never perform writing tools.
Platt Scaling & Margin Guard Calibration
Platt Scaling in logistic estimator, eliminating 45% of false negatives by underconfidence.
Ability Taxonomy and Canon Collapse
Collapse of redundant operational duplicates, raising Hit Rate@2 from 35% to 100%.
Alignment APM & OmniRoute Gateway
Corporate packaging manifesto in accordance with LGPD, PCI-DSS v4.0 and BACEN 4893.
Grounds: Normalization, Router, Ranking and Harness
Unicode NFKD canonical normalization, lexical separation and deterministic harmony of metrics.
09 · Catalog Governance
The catalog is the problem, not the vectorization
The initial diagnosis of low recall (35% Hit Rate@2) seemed a failure of the model. The tool register examination revealed the real cause: semantic duplications accumulated by different teams over years.
consultar_fatura -> "Gera o PDF ou linha digitável da fatura do mês atual."
gerar_linha_digitavel_fatura -> "Gera a linha digitável da fatura ... para pagamentos."
enviar_pdf_fatura_atual -> "Envia o PDF da fatura atual ... para o cliente."
consultar_valor_fatura_mes_atual -> "Consulta o valor da fatura ... do mês atual."
For a simple lexical retriever, the hyperspecific variant always wins the canonical because it repeats word for word of the query.
The solution was to introduce the concept of Canon Capacity with Collapse: the retriever groups the variants under the same capacity and returns in k=2 two capacities different.
The specific variant that married is preserved in matched_variant as an audit trail for runtime.
10 · Measured Evolution
Economy without success rate is disguised risk
As Goodhart's Law ("when a metric becomes a goal, it ceases to be a good metric"), blindly optimizing cost savings led the initial pipeline to abstain from almost half of calls, artificially inflating the percentage of savings.
| Metric / Iteration | Initial commit (fc830dc) |
Crash Iteration (c8f30d2) |
Published version (1f780c0) |
|---|---|---|---|
| Automated Tests | 35 | 54 | 72 passed, 0 skipped |
| Hit Rate@2 | 35% | 100% | 100% |
| Correct Top-1 Execution | 20% (4/20) | 95% (19/20) | 100% (20/20) |
| Incorrect Executions | 7 incorrect | 0 (but vulnerable) | 0 incorrect |
| Reading Solving Writing | Not measured | Yes (margin 0.47) | Impossible (G4) |
| Fallback for Low Trust | 9 abstentions | 0 | 0 |
| Economy of LLM measured (benchmark) | 87.8% (inflated) | 78,9% | 77.8% (real net) |
| Harness Status | REPROVED | APPROVED | APPROVED IN BENCHMARK |
Why did the economy fall from 87.8% to 77.8%? In the first version, 9 improper abstentions avoided LLM calls, inflating the economy while delivering only 20% success. The final version solves 20 out of 20 transactional issues with 100% hit and paid LLM for all of them.
What 77.8% measures — and what does not measure. It is the reduction of cost of LLM calls
between the smart pipeline and the "everything for LLM" baseline on the offline benchmark. It's not a financial economy
Total system: the cost of human fallback, for example, is premise and not measurement — so report
public cost_savings_pct_on_resolved, deferred_to_human and
human_fallback_breakeven_cost_usd side by side.
11 · The Case
How was developed: the agentic method with embedded criticism
Development didn't follow a straight line. Two rounds were driven by external adverse review, where each note generated a diagnostic cycle, ADR measurement (Architecture Decision Record) and extended testing suite. The third had no reviewer: appeared because the steady state has been tested instead of green.
Commit Review fc830dc
35% recall diagnosis, 7 incorrect executions and inflated economy. It produced ADRs 0006 and 0007, raising the suite from 35 to 54 tests.
Adverse Review of the Committee c8f30d2
Mapping of 8 remaining risks. The recommended reading/writing collision test exposed the Silent Crash. It generated the ADR-0008 and added the collision tests to the suite.
The saga of the origin of the report — commits 0d2c9ae … 1f780c0
Regenerate candidate_report.json And running the suite again revealed the count with a 1 skipped Too much. O skip was not benign conditional — it was a silent test giving up. Corrected, the suite closes in 72 passed, 0 skipped.
The origin that contaminated the measurement itself
The metric report is versioned — and a versioned JSON ages silently: the code changes, the file stays, and those who read believe in numbers that the current commit no longer produces. The project has a test that rewards decisions against the current code. This test had three defects of the same family, all with the report soiling the measurement that should audit it:
-
Unsatisfactory assertion. Requirement
snapshot.git_commit == HEAD. How to commit the report creates a new commit,snapshotalways points to the previous one — the assertion could never pass. The real auditable property is another: between the commit which generated the report and the HEAD, nothing outside ofreports/changed — and the failure becomes name files Late. -
git_dirtyself-sucking.build_snapshot()countedreports/on the dirty tree check. As the report is written by the function itself, from the second execution onward it was declared irreproductive because of the file that it had just generated. -
_git().strip()ate the status prefix space. The filter slicedline[3:]Do--porcelain, but.strip()at the exit removes the initial space from the first line: the path exited displaced (eports/...), the filter never married and the test He would jump again in silence. Solved by delegating the filter to git itself (pathspec':(exclude)reports'), without parsing.
A green suite with 1 skipped He looked healthy. It wasn't — the skip It was a test giving up silently, and it only appeared because the stationary state was tested (regenerate the report, rotate the suite again) instead of accepting the green. It is the third instance of the thesis of this page: Green metrics are not coverage.
Principles governing decisions
- Measure before editing: No changes were made without registering the metric table before/after ADR.
- Never move the beam: Easy solutions (such as climbing probability parameters to mask errors) were summarily rejected.
- No Effect Tests: Tests that ensure that
mock_tool_executionis never called If any guard fails. - Test steady state: It is not enough for the suite to pass once — it must continue passing after the system writes its own artifacts.
12 · Executable Specification
The Suite of 72 Tests as System Specification
Eight test files divided by security and integrity invariants. The part more valuable does not check a returned value; check that Nothing happened.:
def test_a_read_request_can_never_resolve_to_a_write_capability(retriever):
"""Antes da guarda de direcao, "Qual e o email cadastrado na minha conta?"
devolvia atualizar_email (ESCRITA) em 1o lugar com margem relativa de 0.47 —
acima do limiar de 0.25: a guarda de margem NAO pegava."""
for query in read_requests: # 5 consultas puras
for m in retriever.search(query, k=3).matches:
assert CAPABILITY_MODE.get(m.name) != "write"
Test Suite Categories
- No effect:
mock_tool_executionis never called when any guard fails (executed.assert_not_called()). - Taxonomy Integrity: 7 authorship invariants (existence in the catalogue, absence of collision, reading, writing, declared and inherited direction).
- Generalization without Adjustment to Gabarite: 12 paraphrases written with totally absent vocabulary from the official dataset (9/12 on top-1, 11/12 on top-2).
- Stability and Origin: Shuffle the order in the catalogue does not change any decision; the JSON report corresponds exactly to the commit and current code — and this check Can't jump (it was the fault of round 3).
13 · Technical Transparency
Real Project Limitations (What Benchmark Does Not Cover)
Publishing limitations is what separates advertising engineering. The 7 restrictions below are registered in the README of the official repository:
- Approved in this benchmark, not for live banking production: 30 queries, 53 training examples and molded tools. Real traffic with opponents requires layers of MFA, authorization and idempotence outside this scope.
- The steering guard only protects what is stated: 59 of the 285 tools have
mode(14 canonical capacities + 45 variants). The others 226 They pass without driving restrictions. The right architectural place formodeis the register itself — is metadatad from the endpoint, not taxonomy. - Paraphrased lexical recovery ceiling: The recall of pure paraphrases without keywords reaches 9/12 in the top-1. The next step requires dense/reranker embeddings.
- Manually maintained taxonomy: 14 capabilities and 45 variants configured in Python code over 285 tools.
- Guards 2 and 3 are no longer exercised by the official benchmark: With 20/20 and zero abstentions, they are proven only by tests of no effect. A benchmark that never triggers the security network doesn't show it works.
- Router calibration break is narrow: A Query
AGENTless confident registers 0.7674 against the threshold of 0.75 — 0.017 Off duty, registered as a liability. (On the other hand the margins of the right decisions lie between 0.592 and 0.741 against the threshold of 0.25: this, yes, loose.) - Human fallback cost is premise, not measurement: The reliable number is the equilibrium point, which is derived from measurements.
14 · Ecosystem & Links
Conceptual References of the Site
Trust Engineering
- Trust Engineering — The ISM model and silent Crash containment.
- AI Agent Engineering — The Five Pillars and the Spectrum of Autonomy.
- Agent Ready — The surface of the website readable by agents.
Foundation & Method
- Problem Formulation — Recast the retrieval problem for catalog governance.
- Knowledge OS Enterprise — Context Lakes and explicit knowledge.
- The Invisible Artificer — Making the engineering work behind 100% visible.