<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: marcosomma</title>
    <description>The latest articles on DEV Community by marcosomma (@marcosomma).</description>
    <link>https://dev.to/marcosomma</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3064224%2F51ff6fb7-5f5b-4ee3-80be-52b8264243b3.jpg</url>
      <title>DEV Community: marcosomma</title>
      <link>https://dev.to/marcosomma</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/marcosomma"/>
    <language>en</language>
    <item>
      <title>The Old Seniority Definition Is Collapsing</title>
      <dc:creator>marcosomma</dc:creator>
      <pubDate>Thu, 05 Mar 2026 08:40:59 +0000</pubDate>
      <link>https://dev.to/marcosomma/the-old-seniority-definition-is-collapsing-12lj</link>
      <guid>https://dev.to/marcosomma/the-old-seniority-definition-is-collapsing-12lj</guid>
      <description>&lt;p&gt;For a long time, “senior developer” was a fairly consistent signal. You expected someone who could hold a large architecture in their head, write clean code with low defect rates, debug almost anything, and reason about performance without guesswork. That bundle made sense because the hardest part of shipping software was often the execution layer: translating intent into correct, maintainable code at speed.&lt;/p&gt;

&lt;p&gt;That bundle is breaking.&lt;/p&gt;

&lt;p&gt;AI-assisted development is compressing the cost of producing plausible, working code. Not always. Not uniformly. But enough that “I can ship a lot of code quickly” is no longer a reliable proxy for deep seniority. In many teams, velocity metrics are starting to measure who is best at driving the tool, not who is best at building systems that survive contact with reality.&lt;/p&gt;

&lt;h2&gt;
  
  
  What AI Is Actually Commoditizing
&lt;/h2&gt;

&lt;p&gt;AI is not replacing engineering. It is discounting a specific slice of it: first-pass implementation and the mechanical parts of refactoring. The tool is good at producing code that looks right, compiles, and often passes superficial tests. That changes the economics of execution.&lt;/p&gt;

&lt;p&gt;What does not get discounted at the same rate is integration into a real system with real constraints: data contracts, failure modes, security boundaries, observability, and long-term maintenance. In practice, the bottleneck shifts from typing to supervision. You spend less time writing and more time specifying, verifying, reviewing, and correcting.&lt;/p&gt;

&lt;p&gt;This is why you can see two realities at the same time. Some developers experience dramatic speedups on bounded tasks. Others experience slowdowns inside large, messy codebases because prompting, waiting, and review overhead replace keystrokes, and because the model lacks the local context that makes a patch truly correct.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is Rising in Value
&lt;/h2&gt;

&lt;p&gt;Problem decomposition and system thinking become the differentiator because they convert ambiguity into an executable plan. When you are dealing with something like regulatory delta detection, the hardest part is not writing code. The hardest part is deciding where the complexity actually lives, and what you must make explicit so the system stays correct as the domain evolves. The choice between a graph database and a simpler model is rarely a “tech taste” debate. It is a tradeoff between query expressiveness, operational burden, debuggability, and change management.&lt;/p&gt;

&lt;p&gt;Judgment under uncertainty becomes a senior marker because architecture is mostly irreversible decisions made with incomplete information. Moving from direct graph writes to a changeset-based approach with content hashing is not an implementation detail. It is a bet on how you will observe change, roll back safely, explain behavior to customers, and avoid silent drift. That decision quality is what compounds over months.&lt;/p&gt;

&lt;p&gt;Context and domain mastery become a moat because they are earned, not generated. If you understand how CELEX identifiers behave in practice, how MiCAR compliance maps to document reality, or how jurisdictions interpret rules differently, you carry constraints that materially shape the architecture. AI can help you express that knowledge. It cannot reliably invent it. Without domain context, you get confident code that is wrong in the ways that matter.&lt;/p&gt;

&lt;p&gt;Technical leadership becomes central because building systems is increasingly a multiplayer game. The question is whether you can create a design that other people can implement without constant back-and-forth, and whether you can write specifications that converge rather than fork. This is why a workshop like SDD Pills matters. It trains decision-making and clarity, not syntax.&lt;/p&gt;

&lt;p&gt;Mentoring and knowledge transfer become leverage because the highest-value output of a senior engineer is often the improvement of everyone else’s output. AI amplifies this. Teams that learn how to bound AI usage with clear contracts, acceptance criteria, and review discipline get compounding returns. Teams that treat AI as an oracle get compounding debt.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Uncomfortable Truth: Two Axes Have Split
&lt;/h2&gt;

&lt;p&gt;There are now two skill axes that used to correlate and no longer do.&lt;/p&gt;

&lt;p&gt;One axis is technical depth: how well you understand systems, tradeoffs, failure modes, and the long-term consequences of design choices.&lt;/p&gt;

&lt;p&gt;The other axis is execution speed: how quickly you can produce working code.&lt;/p&gt;

&lt;p&gt;Historically, depth and speed often moved together. Deep engineers tended to execute quickly because they saw the path. Today, you can get high speed with low depth by delegating thinking to the tool. That can look senior on dashboards and in weekly updates. It is not senior if the output is brittle, unobservable, and expensive to maintain.&lt;/p&gt;

&lt;p&gt;The inverse also exists: high depth with lower raw output speed can still be very senior if the person consistently makes decisions that reduce risk, eliminate classes of bugs, and increase team throughput.&lt;/p&gt;

&lt;h2&gt;
  
  
  What This Breaks in Hiring and Promotion
&lt;/h2&gt;

&lt;p&gt;Many organizations still reward visible output: commits, tickets closed, apparent velocity. AI makes these signals noisier because the cost of producing code has dropped, while the cost of validating correctness has often increased. The net effect is that the old metrics over-credit the wrong behaviors and under-credit the work that actually keeps systems stable.&lt;/p&gt;

&lt;p&gt;The evaluation problem is that “code shipped” is no longer tightly coupled to “engineering done.” A senior engineer in 2026 is often the person who prevented the incident you never had, removed an entire category of future work by designing the right abstraction, or wrote a spec that made five people productive instead of confused.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to Measure Instead
&lt;/h2&gt;

&lt;p&gt;The most useful seniority markers become visible if you look for decision quality, not output quantity.&lt;/p&gt;

&lt;p&gt;A senior engineer can take an ambiguous problem and produce a specification that is testable and unambiguous. They can make uncertainty explicit by stating what is known, what is assumed, and what the cost of being wrong looks like. They consistently surface non-functional requirements early, especially observability, maintainability, and security, because those are the constraints that explode later.&lt;/p&gt;

&lt;p&gt;They use AI as a bounded tool. They know when to ask it for a scaffold, when to demand alternatives, and when to reject a suggestion because they understand the scaling and failure modes. Patterns like Planner, Executor, Reviewer work when they are treated as control systems with clear acceptance criteria, not as theater.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why “Senior” Is Drifting Toward “Principal”
&lt;/h2&gt;

&lt;p&gt;Role expectations are shifting. Senior used to mean “I can personally deliver complex work.” Increasingly it means “I can make the right decisions and increase the output quality of everyone around me.” That is closer to what many companies used to call principal or architect.&lt;/p&gt;

&lt;p&gt;This shift is healthy if organizations adapt their evaluation criteria. It is painful if they do not. People whose main advantage was fast execution will feel the floor drop out, because execution has been discounted. People who were already strong in decomposition, judgment, and leadership will become more valuable, because those skills are now the constraint.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I’m Seeing in Teams
&lt;/h2&gt;

&lt;p&gt;The developers adapting best to AI-assisted development are usually the ones who already had strong mental models and strong taste. They can turn ambiguity into constraints, and constraints into evaluation. They do not confuse “working code” with “correct system.” They treat AI output as a hypothesis that must be verified against invariants.&lt;/p&gt;

&lt;p&gt;The developers struggling are often those who outsource thinking. They can generate a lot of code quickly, but they cannot defend why the design is correct, what it will cost to operate, or how it will fail.&lt;/p&gt;

&lt;p&gt;If you are seeing a blur between depth and apparent execution speed, that blur is real. The solution is not to ban AI or to worship it. The solution is to change what you reward, and to interview and promote for the skills that actually compound.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>python</category>
      <category>javascript</category>
    </item>
    <item>
      <title>LLMs Are Not Deterministic. And Making Them Reliable Is Expensive (In Both the Bad Way and the Good Way)</title>
      <dc:creator>marcosomma</dc:creator>
      <pubDate>Sun, 22 Feb 2026 14:24:05 +0000</pubDate>
      <link>https://dev.to/marcosomma/llms-are-not-deterministic-and-making-them-reliable-is-expensive-in-both-the-bad-way-and-the-good-5bo4</link>
      <guid>https://dev.to/marcosomma/llms-are-not-deterministic-and-making-them-reliable-is-expensive-in-both-the-bad-way-and-the-good-5bo4</guid>
      <description>&lt;p&gt;Let’s start with a statement that should be obvious but still feels controversial: Large Language Models are not deterministic systems. They are probabilistic sequence predictors. Given a context, they sample the next token from a probability distribution. That is their nature. There is no hidden reasoning engine, no symbolic truth layer, no internal notion of correctness.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You can influence their behavior. You can constrain it. You can shape it. But you cannot turn probability into certainty.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Somewhere between keynote stages, funding decks, and product demos, a comforting narrative emerged: models are getting cheaper and smarter, therefore AI will soon become trivial. The logic sounds reasonable. Token prices are dropping. Model quality is improving. Demos look impressive. From the outside, it feels like we are approaching a phase where AI becomes a solved commodity.&lt;/p&gt;

&lt;p&gt;From the inside, it feels very different.&lt;/p&gt;

&lt;p&gt;There is a massive gap between a good demo and a reliable product. A demo is usually a single prompt and a single model call. It looks magical. It sells. A product cannot live there. The moment you try to ship that architecture to real users, reality shows up fast. The model hallucinates. It partially answers. It ignores constraints. It produces something that sounds fluent but is subtly wrong. And the model has no idea it failed.&lt;/p&gt;

&lt;p&gt;This is not a moral flaw. It is a design property.&lt;/p&gt;

&lt;p&gt;So engineers do what engineers always do when a component is powerful but unreliable. They build structure around it.&lt;/p&gt;

&lt;p&gt;The moment you care about reliability, your architecture stops being “call an LLM” and starts becoming a pipeline. Input is cleaned and normalized. A generation step produces a candidate answer. Another step evaluates that answer. A routing layer decides whether the answer is acceptable or if the system should try again. Sometimes it retries with a modified prompt. Sometimes with a different model. Sometimes with a corrective pass. Only after this loop does something reach the user.&lt;/p&gt;

&lt;p&gt;At no point did the LLM become deterministic. What changed is that the system gained control loops.&lt;/p&gt;

&lt;p&gt;This distinction matters. We are not converting probability into certainty. We are reducing uncertainty through redundancy and validation. That reduction costs computation. Computation costs money.&lt;/p&gt;

&lt;p&gt;This is why quoting token prices in isolation is misleading. A single model call might be cheap. A serious system rarely uses a single call. One user request can trigger several model invocations: generation, evaluation, regeneration, formatting, tool calls, memory lookups. The user experiences “one answer.” The backend executes a small workflow.&lt;/p&gt;

&lt;p&gt;Token cost is component cost. Reliable AI is system cost.&lt;/p&gt;

&lt;p&gt;Saying “tokens are cheap, therefore AI is cheap” is like saying screws are cheap, therefore airplanes are cheap.&lt;/p&gt;

&lt;p&gt;This leads to an uncomfortable but important truth. AI becomes expensive in two very different ways.&lt;/p&gt;

&lt;p&gt;If you implement it poorly, it becomes expensive because you burn money and still do not get reliability. You keep tweaking prompts. You keep firefighting. You keep patching symptoms. Nothing stabilizes.&lt;/p&gt;

&lt;p&gt;If you implement it well, it becomes expensive because you intentionally pay for control. You pay for evaluators. You pay for retries. You pay for observability. You pay for redundancy. But you get something in return: a system that behaves in a bounded, inspectable, and improvable way.&lt;/p&gt;

&lt;p&gt;There is no cheap version of “reliable.”&lt;/p&gt;

&lt;p&gt;Another source of confusion comes from mixing up different kinds of expertise. High-profile founders and executives are excellent at describing futures. They talk about where markets are going and what will be possible. That is their role. It is not their role to debug why an evaluator prompt leaks instructions or why a routing threshold oscillates under load. Money success does not imply operational intimacy.&lt;/p&gt;

&lt;p&gt;On the ground, building serious AI feels much closer to distributed systems engineering than to science fiction. You worry about data quality. You worry about regressions. You worry about latency and cost per request. You design schemas. You version prompts. You inspect traces. You run benchmarks. You tune thresholds. It is slow, unglamorous, and deeply technical.&lt;/p&gt;

&lt;p&gt;LLMs made AI more accessible. They did not make serious AI simpler. They shifted complexity upward into systems.&lt;/p&gt;

&lt;p&gt;So when someone says, “Soon we’ll just call an API and everything will work,” what they usually mean is, “Soon an enormous amount of engineering will be hidden behind that API.”&lt;/p&gt;

&lt;p&gt;That is fine. That is progress.&lt;/p&gt;

&lt;p&gt;But pretending that reliable AI is cheap, trivial, or solved is misleading.&lt;/p&gt;

&lt;p&gt;The honest version is this: LLMs are powerful probabilistic components. Turning them into dependable products requires layers of control. Those layers cost money. They also create real value.&lt;/p&gt;

&lt;p&gt;Serious AI today is expensive in the bad way if you do not know what you are doing.&lt;/p&gt;

&lt;p&gt;Serious AI today is expensive in the good way if you actually want it to work.&lt;/p&gt;

&lt;p&gt;And anyone selling “cheap deterministic AI” is selling a story, not a system.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>mcp</category>
      <category>programming</category>
      <category>llm</category>
    </item>
    <item>
      <title>Adversarial Planning for Spec Driven Development</title>
      <dc:creator>marcosomma</dc:creator>
      <pubDate>Thu, 12 Feb 2026 21:39:13 +0000</pubDate>
      <link>https://dev.to/marcosomma/adversarial-planning-for-spec-driven-development-4c3n</link>
      <guid>https://dev.to/marcosomma/adversarial-planning-for-spec-driven-development-4c3n</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;I have always loved one idea in machine learning. The idea that you can sharpen a model by forcing it to face a challenger. You can call it adversarial training, red teaming, or constructive hostility. The name matters less than the mechanism. You introduce pressure. You int&lt;br&gt;
roduce disagreement. You force the system to earn its confidence.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For years I kept that concept in a mental drawer labeled “cool, but academic.” Then it become a core concept within the Orka-reasoning development but lately my attention is shifting toward code agent workflows and how all happen. Not the marketing version. The real version, where you sit down to ship software, and you realize that a helpful model is not the same thing as a rigorous model. Helpful is easy. Rigorous is costly.&lt;/p&gt;

&lt;p&gt;This article is about how I tried to transplant an adversarial dynamic into Spec Driven Development sessions. Not as theater. Not as an AI debate club. As an engineering tool. It worked. It also nearly became a token-burning trap. That tradeoff is the point.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Spec Driven Development means here
&lt;/h2&gt;

&lt;p&gt;Spec Driven Development, or SDD, is a workflow where the spec is not documentation. The spec is the product of the thinking phase. It becomes the contract you implement against. You write it before code changes. You review it like you would review code. You use it to force scope, constraints, interfaces, and acceptance criteria into something explicit.&lt;/p&gt;

&lt;p&gt;The point is not to be verbose. The point is to move ambiguity upstream, when it is still cheap. The spec becomes the unit of alignment, review, and iteration. Code is the execution of that spec, not the place where you discover what the spec should have been.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem with a trustable planner
&lt;/h2&gt;

&lt;p&gt;If you use an LLM as a planning companion, you know the feeling. You came with your idea. You debate a bit. And then it gives you a plan. The plan is detailed. It is readable. It sounds plausible. It often includes little snippets that look like they belong in your codebase, even when they do not. It is confident. It is fast.&lt;/p&gt;

&lt;p&gt;And that is exactly the problem.&lt;/p&gt;

&lt;p&gt;A planner model has incentives you did not explicitly set. Its default incentive is to be useful to you in the moment. It wants to reduce friction. It wants to keep you engaged. It wants to produce something that reads like progress.&lt;/p&gt;

&lt;p&gt;So it will fill gaps with assumptions. If your own initial plan is fluffy. It will smooth rough edges. It will complete the pattern of what a good plan should look like. It will also happily unlock future possibilities, because possibilities are cheap to generate and expensive to invalidate.&lt;/p&gt;

&lt;p&gt;When you are deep in a product, that behavior is dangerous. Not because the model is malicious. Because it is compliant. It will often accept your framing even if your framing is wrong. It will not push hard unless you force it to.&lt;/p&gt;

&lt;p&gt;This is the failure mode I kept hitting. I would craft a plan with the planner. I would feel momentum. Then I would start implementation and discover that the plan was under-specified in the only places that matter.&lt;/p&gt;

&lt;p&gt;Interfaces were vague. Invariants were missing. Acceptance criteria were soft. The plan assumed the architecture could absorb a change without showing how. It assumed the code was more modular than it actually was. It assumed integration would be straightforward.&lt;/p&gt;

&lt;p&gt;In other words, it was a nice plan. It was not a plan that survived contact with a real codebase.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why adversarial dynamics work in ML
&lt;/h2&gt;

&lt;p&gt;Adversarial training is interesting because it makes weakness visible. You do not improve a system by praising it. You improve it by exposing it to inputs that exploit its blind spots. You force it to fail in ways that are informative.&lt;/p&gt;

&lt;p&gt;In a GAN, the generator learns because the discriminator is not polite. The discriminator does not care about your feelings. It cares about whether the output holds up under scrutiny. That pressure creates signal.&lt;/p&gt;

&lt;p&gt;In engineering, we already do this. Code review is adversarial when it is healthy. Testing is adversarial by definition. Security review is adversarial. Load testing is adversarial. Even a good product manager is adversarial at the right moments.&lt;/p&gt;

&lt;p&gt;But planning often is not. Planning often becomes a social process. People nod. People optimize for alignment. People avoid being the blocker. Under time pressure, that tendency gets amplified.&lt;/p&gt;

&lt;p&gt;If you bring an LLM into planning and you let it be the agreeable teammate, you amplify the most comfortable version of planning. You pay tokens to make yourself feel certain.&lt;/p&gt;

&lt;p&gt;That is not what I wanted. I wanted the planning stage to contain more of the pain, so implementation contains less.&lt;/p&gt;

&lt;h2&gt;
  
  
  The translation to SDD: Planner plus Architect
&lt;/h2&gt;

&lt;p&gt;I kept the planner. I did not replace it. The planner is good at structure. It is good at decomposing a vague goal into sequential work. It is good at producing a spec you can follow. It is good at holding context across iterations.&lt;/p&gt;

&lt;p&gt;But I introduced a second role. I call it the Architect. The job is simple. Challenge the plan as if you are the most annoying senior engineer in the room, with one constraint. The criticism must be grounded. It must point to specific failure modes. It must force explicit decisions.&lt;/p&gt;

&lt;p&gt;The Architect pushes on the places where the planner tends to glide over reality. It asks what the boundary of the change really is. It asks what breaks if you do it, and what breaks if you do not. It pressures you to name the coupling you are creating and the coupling you are relying on. It attacks the parts of the spec that sound confident but are not falsifiable.&lt;/p&gt;

&lt;p&gt;This role is unpleasant. It is supposed to be unpleasant. It is also productive, if you keep it under control.&lt;/p&gt;

&lt;p&gt;The immediate effect was obvious. Specs became harder to write. My initial drafts got rejected more often. I had to define outcomes in tighter language. I had to stop relying on vibes and start writing constraints.&lt;/p&gt;

&lt;p&gt;The less obvious effect was more important. I started noticing the difference between a plan that sounds implementable and a plan that is falsifiable.&lt;/p&gt;

&lt;p&gt;A falsifiable plan is one where you can point at a step and say: if this condition does not hold, the step is wrong. If the step is wrong, we know why. We can adjust.&lt;/p&gt;

&lt;p&gt;A non-falsifiable plan is one where every step is elastic. You can always reinterpret it. You can always claim partial success. It is planning as comfort.&lt;/p&gt;

&lt;p&gt;The Architect hates comfort. That is the point.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the Architect actually improved
&lt;/h2&gt;

&lt;p&gt;It did not make my system magically correct. It made my system explicit.&lt;/p&gt;

&lt;p&gt;It reduced scope creep because it forced me to define what done means in terms of observable outcomes. It reduced hidden coupling because it forced me to identify which pieces of the system now move together. It reduced abstraction drift because it forced me to state which module owns which responsibility. It improved testability because it pushed me to name the failure cases the system must catch and the layer that must catch them. It also lowered integration fantasies by making me draw the dependency edges in plain language.&lt;/p&gt;

&lt;p&gt;This matters because most planning failures are not about missing steps. They are about missing friction. You only discover friction when someone tries to break your plan.&lt;/p&gt;

&lt;p&gt;A planner rarely tries to break your plan. An Architect lives for it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The mental model: controlled adversarial pressure
&lt;/h2&gt;

&lt;p&gt;At some point I realized the dynamic I was building was not adversarial planning. It was controlled adversarial pressure.&lt;/p&gt;

&lt;p&gt;Pressure is good when it produces signal. Pressure is bad when it produces noise.&lt;/p&gt;

&lt;p&gt;The Architect can easily produce noise. It can challenge everything. It can question the existence of the feature. It can spiral into meta debates. It can do the classic senior engineer move of turning every change into a referendum on architecture.&lt;/p&gt;

&lt;p&gt;That is why this approach can become dangerous. It is not just about tokens. It is about cognitive load. Too much adversarial pressure makes you doubt everything. You stop shipping. You start ruminating. You start optimizing a plan instead of building the thing.&lt;/p&gt;

&lt;p&gt;So the key is control. You want the Architect to challenge the plan in a bounded way, then you move on.&lt;/p&gt;

&lt;p&gt;The only sustainable use is somewhere in the middle. You let it break your plan until the breakage becomes repetitive. When the criticism starts looping, it is done. That loop is your stop signal.&lt;/p&gt;

&lt;h2&gt;
  
  
  How the infinite loop happens
&lt;/h2&gt;

&lt;p&gt;I learned this the hard way. The Architect is very good at finding the next critique, even when the plan is already good enough, even when the remaining critiques are marginal.&lt;/p&gt;

&lt;p&gt;There are two reasons.&lt;/p&gt;

&lt;p&gt;First, LLMs are generative machines. They can always produce another objection. The space of objections is large. Many objections are plausible. Plausible is not the same as important.&lt;/p&gt;

&lt;p&gt;Second, adversarial roles reward themselves. When the Architect produces a clever critique, it feels like progress. It feels like rigor. It feels like you are doing serious engineering. You can get addicted to that feeling, especially if you already equate doubt with intelligence.&lt;/p&gt;

&lt;p&gt;So you need stop conditions that are not emotional. You need boundaries that are mechanical.&lt;/p&gt;

&lt;p&gt;Time is a boundary. Token budget is a boundary. The best boundary is value.&lt;/p&gt;

&lt;p&gt;The question is: does this criticism point to a concrete failure mode that is likely in this codebase, in this release, under these constraints. If yes, incorporate it. If no, write it down as a future consideration and move on.&lt;/p&gt;

&lt;p&gt;That discipline sounds simple. It is not. It requires you to accept that you will ship with risk. It requires you to prefer explicit risk over imagined safety.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this helps SDD specifically
&lt;/h2&gt;

&lt;p&gt;SDD is already an attempt to move thinking earlier. You spend more effort defining the work before coding. That sounds obvious. It is not common.&lt;/p&gt;

&lt;p&gt;Many teams code first, then retrofit clarity. Specs become documentation after the fact. Tests become a safety net after the mistakes.&lt;/p&gt;

&lt;p&gt;SDD flips that. You try to make the spec the forcing function. The spec becomes the contract. The spec becomes the review surface. The spec becomes the artifact you can reason about without running the entire system in your head.&lt;/p&gt;

&lt;p&gt;If your spec is weak, SDD collapses into bureaucracy. You get long documents that do not prevent failures. You get ceremonial approval. You get a spec that exists, but does not constrain the outcome.&lt;/p&gt;

&lt;p&gt;The adversarial role helps because it forces the spec to earn its existence. It forces explicit interfaces. It forces explicit invariants. It forces explicit failure handling. It forces explicit success conditions. It makes the spec testable in a reasoning sense.&lt;/p&gt;

&lt;h2&gt;
  
  
  Doubt as a tool, doubt as a poison
&lt;/h2&gt;

&lt;p&gt;There is a psychological aspect here that I did not expect.&lt;/p&gt;

&lt;p&gt;When you introduce an adversarial voice into planning, you introduce doubt. That can be healthy. It can also be corrosive.&lt;/p&gt;

&lt;p&gt;Healthy doubt looks like this. You have a plan. You expose it to pressure. You find the weak points. You fix them. You ship with more confidence because your confidence is earned.&lt;/p&gt;

&lt;p&gt;Corrosive doubt looks like this. You have a plan. You expose it to pressure. The pressure never ends. You start believing that every plan is fragile. You stop trusting your ability to decide. You keep rewriting the plan to reduce anxiety. You ship nothing.&lt;/p&gt;

&lt;p&gt;The difference is not intelligence. The difference is boundaries.&lt;/p&gt;

&lt;p&gt;In a team, boundaries are social. Someone ends the meeting. Someone says enough, we decide. Someone accepts risk explicitly.&lt;/p&gt;

&lt;p&gt;In a solo workflow with agents, you need to manufacture that boundary. Otherwise the system will drift toward endless review because endless review feels safer than a decision.&lt;/p&gt;

&lt;p&gt;If you are prone to overthinking, an adversarial agent can amplify that trait. It can turn careful into paralyzed. That is not a reason to avoid it. It is a reason to instrument it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this is not
&lt;/h2&gt;

&lt;p&gt;This is not asking an AI to argue with itself and then picking a side. That is entertainment. It can be useful for brainstorming. It is not a development methodology.&lt;/p&gt;

&lt;p&gt;This is not letting the Architect design the system. That is just outsourcing. The Architect is a critic, not a creator.&lt;/p&gt;

&lt;p&gt;This is not making the Architect mean. Mean is cheap. Precision is expensive. You want precision tied to concrete failure modes.&lt;/p&gt;

&lt;p&gt;This is also not a replacement for real review. A human senior engineer with context will catch things an LLM will miss. The point here is to raise your baseline. The point is to catch the obvious architecture risks before you waste days implementing.&lt;/p&gt;

&lt;h2&gt;
  
  
  The practical outcome
&lt;/h2&gt;

&lt;p&gt;The measurable outcome for me was simple.&lt;/p&gt;

&lt;p&gt;I rewrote fewer specs mid-implementation. I discovered fewer “we forgot that” moments. I spent less time refactoring because of missing boundaries. I argued less with my future self.&lt;/p&gt;

&lt;p&gt;The spec still does not become perfect. The spec fails earlier, on paper, when failure is cheap. That is what adversarial pressure buys you.&lt;/p&gt;

&lt;h2&gt;
  
  
  The simplest way to frame it
&lt;/h2&gt;

&lt;p&gt;Your planner optimizes for completeness. Your Architect optimizes for survivability.&lt;/p&gt;

&lt;p&gt;Completeness is about covering steps. Survivability is about covering reality.&lt;/p&gt;

&lt;p&gt;A complete plan can still die on a hidden assumption. A survivable plan is one where assumptions are visible, bounded, and either validated or consciously accepted.&lt;/p&gt;

&lt;p&gt;The adversarial role does not need to make you pessimistic. It needs to make you explicit. If it makes you pessimistic, you let it run too long.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sane engineer the disagreement
&lt;/h2&gt;

&lt;p&gt;Good engineering requires disagreement. Not constant fighting. Not performative contrarianism. Real disagreement that targets risk.&lt;/p&gt;

&lt;p&gt;In teams, disagreement is expensive socially. With agents, disagreement is expensive computationally. The price changes. The dynamics stay.&lt;/p&gt;

&lt;p&gt;If you can engineer disagreement so that it is bounded, precise, and tied to concrete failure modes, you get a sharper process. You get better specs. You get fewer surprises.&lt;/p&gt;

&lt;p&gt;If you cannot bound it, you get the worst of both worlds. You get more doubt and less shipping.&lt;/p&gt;

&lt;p&gt;So adopt the adversarial phase, but treat it like a test suite. You run it to catch failures. You do not run it forever because you enjoy watching it fail.&lt;/p&gt;

&lt;p&gt;Controlled adversarial pressure. Enough to sharpen. Not enough to cut.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>python</category>
      <category>javascript</category>
    </item>
    <item>
      <title>How I accidentally start SDD by failing at prompts for six months</title>
      <dc:creator>marcosomma</dc:creator>
      <pubDate>Sat, 07 Feb 2026 12:12:01 +0000</pubDate>
      <link>https://dev.to/marcosomma/how-i-accidentally-start-sdd-by-failing-at-prompts-for-six-months-477l</link>
      <guid>https://dev.to/marcosomma/how-i-accidentally-start-sdd-by-failing-at-prompts-for-six-months-477l</guid>
      <description>&lt;h3&gt;
  
  
  The confession
&lt;/h3&gt;

&lt;p&gt;I spent the first six months of serious AI pair programming producing what I now call vibe architecture.&lt;/p&gt;

&lt;p&gt;You know the pattern. You open a chat with a strong model. You explain what you want. It produces clean code fast. You feel productive. Three weeks later the repo looks like it was designed by five different people, on five different days, with five different mental models.&lt;/p&gt;

&lt;p&gt;Each file is locally correct. The system is globally confused.&lt;/p&gt;

&lt;p&gt;I would plan with the model in one session. I would implement in another. By step five the implementation had drifted far enough that the plan was basically historical fiction. Then I would come back after a weekend and lose the thread. Not because the model did something wrong. It did exactly what I asked at each moment. The issue was continuity. Nobody was holding the bar across moments.&lt;/p&gt;

&lt;p&gt;That loop repeated across multiple projects, including the first months of building OrKa largely solo. I learned something obvious in hindsight. The problem was not output quality. The problem was the absence of a development system that keeps output coherent over time.&lt;/p&gt;

&lt;p&gt;That is when I stopped chasing better prompts and started building better constraints.&lt;/p&gt;

&lt;p&gt;Out of that shift, I ended up with a working methodology. People have been calling it Specs Driven Development, SDD. I do not care much about the name. I care about the behavior it enforces. The constraints do not live in prompts. They live in the architecture around prompts. The AI becomes useful at scale because the process becomes reliable at scale.&lt;/p&gt;

&lt;h3&gt;
  
  
  The prompt delusion
&lt;/h3&gt;

&lt;p&gt;Prompts are ephemeral. Codebases are permanent.&lt;/p&gt;

&lt;p&gt;You can craft a beautiful system prompt. You can say “follow the plan” and “do not add features” and “write tests” and “document decisions”. It will comply. Then context changes. A new chat starts. You switch tools. You paste fewer files. You forget to include one assumption. The model drifts. Not maliciously. Just naturally. Because prompts are not governance. They are conversation.&lt;/p&gt;

&lt;p&gt;I call this the prompt delusion. It is the belief that the right wording can produce consistent behavior across time, across sessions, across different tasks, and across different tools.&lt;/p&gt;

&lt;p&gt;Humans solved this problem for humans with process and gates. We use linters. We use CI. We use review. We use typed interfaces and invariants. We do not rely on people remembering a paragraph from a handbook.&lt;/p&gt;

&lt;p&gt;So I stopped trying to discipline the model with paragraphs. I started to discipline the workflow with structure.&lt;/p&gt;

&lt;p&gt;The key idea is simple. Constraints that live in prompts are suggestions. Constraints that live in systems are guarantees.&lt;/p&gt;

&lt;p&gt;A lint rule does not drift. A CI gate does not “feel” like doing something else. A review checklist does not forget what you agreed last Tuesday. If you want AI output to stay aligned, you need the same kind of enforcement. You need a development system that makes the correct path the easiest path, and makes the wrong path expensive.&lt;/p&gt;

&lt;h3&gt;
  
  
  The real 80/20 split
&lt;/h3&gt;

&lt;p&gt;I still work roughly 80/20. About 80 percent of the code that lands in my repo is AI generated in some form. About 20 percent is the part that only I can own.&lt;/p&gt;

&lt;p&gt;But the critical nuance is that the 20 percent is not “some code and some tests.” It is not evenly spread. It is concentrated in a few responsibilities that define the quality of the whole.&lt;/p&gt;

&lt;p&gt;The human part is architecture decisions. It is domain and business logic validation. It is edge case reasoning when the system meets reality. It is plan approval. It is saying “this is the bar” and keeping it there.&lt;/p&gt;

&lt;p&gt;The AI part is scaffolding, boilerplate, repetition, test writing, glue code, refactors that follow explicit constraints, documentation drafts, and implementation of well specified changes.&lt;/p&gt;

&lt;p&gt;If you let the AI own the bar, you get speed and drift. If you keep the bar human, and make the AI operate inside a strict process, you get speed and consistency.&lt;/p&gt;

&lt;p&gt;That is the stance that shaped everything that follows. AI is not the decision maker. AI is an assistant that plans with you, executes inside scope, and reviews before you ship. You remain accountable. You remain the one holding the bar.&lt;/p&gt;

&lt;h3&gt;
  
  
  The breakthrough was not “ask for a solution”
&lt;/h3&gt;

&lt;p&gt;Most people use a planner model as a solution vending machine.&lt;/p&gt;

&lt;p&gt;They say “design me the architecture” or “give me the best approach” and they accept it because it sounds coherent. That is exactly how vibe architecture happens. The model is skilled at producing plausible plans. It is not responsible for the long term maintenance of your repo. You are.&lt;/p&gt;

&lt;p&gt;The shift that fixed my outcomes was this.&lt;/p&gt;

&lt;p&gt;I stopped asking the planner for the solution. I started using the planner as a debate partner while I proposed my solution.&lt;/p&gt;

&lt;p&gt;That changes the power dynamic. The planning phase becomes a structured argument about trade offs. The plan becomes a negotiated artifact. The human remains the owner of the direction. The model becomes the adversarial collaborator that tries to break your assumptions.&lt;/p&gt;

&lt;p&gt;So I now enter planning with a draft approach in my head. Not a fully detailed design. But a real proposal. I state it clearly. Then I ask the planner to attack it. I ask it to propose alternatives. I ask it to enumerate costs I will pay later. I ask it to tell me what I will regret in six months.&lt;/p&gt;

&lt;p&gt;Then we iterate until the plan is something I can sign with my name.&lt;/p&gt;

&lt;p&gt;This is the part I want to highlight because it is the core of why the method works. You do not outsource judgment. You formalize judgment. The AI assists. The human decides.&lt;/p&gt;

&lt;h3&gt;
  
  
  The three roles that made it stable
&lt;/h3&gt;

&lt;p&gt;A single AI assistant that plans, codes, and reviews is a liability. It is like letting one person design the system, implement the system, and approve the system. You get blind spots. You get rationalization. You get self confirmation.&lt;/p&gt;

&lt;p&gt;What worked for me was splitting the workflow into three roles with hard constraints. Planner. Executor. Reviewer.&lt;/p&gt;

&lt;p&gt;The important part is not the labels. The important part is that each role has restricted powers and a strict handoff protocol.&lt;/p&gt;

&lt;p&gt;The planner reads and thinks and writes plans. The planner does not write code. Not because you asked nicely. Because it cannot. Tool permissions are restricted.&lt;/p&gt;

&lt;p&gt;The executor implements. The executor does not invent new scope. The executor is forced to read the approved plan, list touched files, and execute step by step. If reality requires deviation, the executor stops and escalates. The human decides whether to update the plan or to abort.&lt;/p&gt;

&lt;p&gt;The reviewer reviews. The reviewer does not “rubber stamp.” It is forced to ask questions first. What was the goal. What constraints were in place. How was it tested. What is the rollback. Then it reviews against those answers.&lt;/p&gt;

&lt;p&gt;This separation is not a fancy trick. It is the same principle we use in engineering organizations because it works. It reduces drift. It forces explicit decisions. It keeps a record.&lt;/p&gt;

&lt;p&gt;And crucially, it keeps me in the loop where it matters. I do not need to be the typist. I need to be the governor.&lt;/p&gt;

&lt;h3&gt;
  
  
  The client planning method
&lt;/h3&gt;

&lt;p&gt;Planning works best when you treat it like a client entering a shop with a need, not a solution.&lt;/p&gt;

&lt;p&gt;Bad planning starts with premature commitment. “Build me a scraper with browser automation.” You have already picked tooling and complexity before you validated the problem framing.&lt;/p&gt;

&lt;p&gt;Good planning starts with intent. “I need structured data for this downstream use. The scope is X. The constraints are Y. The risks are Z.”&lt;/p&gt;

&lt;p&gt;Then you debate solutions. You ask why. You cut complexity. You choose what to postpone. You decide what not to build.&lt;/p&gt;

&lt;p&gt;This is where I now bring my own proposed approach early.&lt;/p&gt;

&lt;p&gt;I will say something like this. I think we can implement a direct HTTP export instead of browser automation. I think we can store the raw payload and defer normalization. I think we can keep one canonical schema and derive views later. I think we should avoid introducing a new dependency unless we can justify it.&lt;/p&gt;

&lt;p&gt;Then the planner attacks. It will say what breaks if you defer normalization. It will say what you lose if you store raw blobs. It will point out hidden coupling. It will propose a more robust approach. It will also point out when my instinct is over engineering.&lt;/p&gt;

&lt;p&gt;This is not “AI gives me a plan.” This is “I bring a plan and we stress test it.”&lt;/p&gt;

&lt;p&gt;One real example locked this in for me.&lt;/p&gt;

&lt;p&gt;I was about to implement a data extraction pipeline. The initial AI proposal was browser automation. Headless browser, navigate pages, click export, download per page, retry logic, throttling, session persistence. It was well designed and also absurdly heavy.&lt;/p&gt;

&lt;p&gt;I asked one question. Is there a direct export endpoint.&lt;/p&gt;

&lt;p&gt;There was. One request. One download. No browser. No per page logic. No category of failure modes that come with automation.&lt;/p&gt;

&lt;p&gt;That discovery did not happen because the model is dumb. It happened because planning without a human hypothesis tends to follow the first plausible path. When you present your own approach and force argument, you surface simpler solutions faster.&lt;/p&gt;

&lt;p&gt;So the rule became clear. Brainstorming is loose and creative. Execution is strict and disciplined. You iterate freely until you are confident. Then you lock it down.&lt;/p&gt;

&lt;h3&gt;
  
  
  The .ai folder is the memory that actually works
&lt;/h3&gt;

&lt;p&gt;Prompts vanish. Chats disappear into history. Context windows compress. Tooling changes. You need persistent memory that you can diff, review, and ship with the repo.&lt;/p&gt;

&lt;p&gt;So every plan, every changelog, and every decision note lives in a &lt;code&gt;.ai/&lt;/code&gt; folder at the root of the service being worked on.&lt;/p&gt;

&lt;p&gt;This solves multiple problems at once.&lt;/p&gt;

&lt;p&gt;It makes the reasoning traceable. Not in an abstract way. In a concrete way where you can answer “why did we do it like this” with a file path.&lt;/p&gt;

&lt;p&gt;It makes onboarding real. A new teammate can read the plans and changelogs and see what the system was supposed to be, what it became, and which trade offs were accepted.&lt;/p&gt;

&lt;p&gt;It makes recovery faster. When something breaks, you can inspect the delta between sessions. Not just the git diff, but the intent behind the diff.&lt;/p&gt;

&lt;p&gt;It improves the next planning session because the planner can read the past. It stops re proposing already rejected choices. It stops re discovering old constraints. It becomes less repetitive and more useful.&lt;/p&gt;

&lt;p&gt;If you build agent systems, you will recognize the pattern. This is persistent memory, but in a human readable format. No embeddings. No magical vector store. Just version controlled text that creates institutional memory.&lt;/p&gt;

&lt;h3&gt;
  
  
  The changelog mandate
&lt;/h3&gt;

&lt;p&gt;The single most valuable practice in this method is the mandatory changelog after each execution session.&lt;/p&gt;

&lt;p&gt;Not optional. Not “if you have time.” Mandatory.&lt;/p&gt;

&lt;p&gt;Because the changelog is the bridge between plan and reality. Plans are aspirational. Changelogs are factual. The difference between them is where learning lives.&lt;/p&gt;

&lt;p&gt;A proper changelog captures what was done, what files changed, what decisions were made during implementation, how it was tested, what remains, and what risks were discovered.&lt;/p&gt;

&lt;p&gt;The most important part is decisions. Not every decision belongs in the original plan. Reality introduces surprises. You will discover an input you did not anticipate. You will find a dependency conflict. You will learn the data is messier than expected. The executor will make micro decisions. Without a changelog, those decisions evaporate. Later, you will argue about them again. Or worse, you will reverse them without remembering why they existed.&lt;/p&gt;

&lt;p&gt;With changelogs, the project stays coherent across weeks. That is what stopped me from losing the thread in solo work. It is also what let AI generated work become safe. Because I had a written record that I could review like an engineer, not like a chat participant.&lt;/p&gt;

&lt;h3&gt;
  
  
  System prompts as version controlled standards
&lt;/h3&gt;

&lt;p&gt;In this workflow, the repo has a single source of truth for behavioral constraints. A system prompt file at the root.&lt;/p&gt;

&lt;p&gt;Think of it as the equivalent of lint and format config, but for AI interaction.&lt;/p&gt;

&lt;p&gt;It contains non negotiable architecture constraints, naming conventions, testing requirements, patterns to follow, anti patterns to avoid, and examples of correct usage in this codebase.&lt;/p&gt;

&lt;p&gt;The key point is that it is version controlled. It changes via PR. When standards evolve, you do not rely on people remembering a new convention. The tooling loads the file. The AI sees it. The behavior becomes consistent.&lt;/p&gt;

&lt;p&gt;This is not about writing a perfect prompt. It is about writing a living standard that evolves with the codebase.&lt;/p&gt;

&lt;h3&gt;
  
  
  The plan lifecycle
&lt;/h3&gt;

&lt;p&gt;Plans have states. Draft. In review. Approved. Implemented.&lt;/p&gt;

&lt;p&gt;Draft is where debate happens. This is where I push my solution. This is where the planner attacks it. This is where we document trade offs. This is where we choose long term costs consciously, instead of paying them accidentally.&lt;/p&gt;

&lt;p&gt;Approved is the gate. Once approved, execution is not creative anymore. It is disciplined. The executor follows the plan. If something is missing, the executor escalates. Either we update the plan, or we stop.&lt;/p&gt;

&lt;p&gt;Implemented is not just “code merged.” It is plan satisfied. It is also “what changed from the plan and why” captured in changelogs.&lt;/p&gt;

&lt;p&gt;This lifecycle is what stops drift. The plan is not a vague Jira ticket. It is a contract.&lt;/p&gt;

&lt;h3&gt;
  
  
  Long term planning without illusion
&lt;/h3&gt;

&lt;p&gt;Here is the tension. You want long term planning. You also want to avoid pretending you can foresee everything.&lt;/p&gt;

&lt;p&gt;The way I handle it is to make trade offs explicit, and to separate what must be stable from what can be flexible.&lt;/p&gt;

&lt;p&gt;Stable things include public interfaces, data models, invariants, naming systems, dependency boundaries, and failure behavior. If those are wrong, the system rots fast.&lt;/p&gt;

&lt;p&gt;Flexible things include internal module structure, some implementation strategies, and performance tuning. Those can iterate.&lt;/p&gt;

&lt;p&gt;The planner is useful here, but only if you treat it like a critic. If you let it author the plan alone, it will often over specify. It will propose infrastructure that is impressive and expensive. It will try to be robust everywhere. That is a trap.&lt;/p&gt;

&lt;p&gt;When I bring my own approach, I can force a different conversation. I can say I want the minimal stable core now, and extension points later. I can say I want to defer optimization until measurements exist. I can say I want fewer dependencies to reduce future maintenance. Then the planner helps me evaluate the cost of those choices. It does not override them.&lt;/p&gt;

&lt;p&gt;This is where I keep the bar human. I decide what “good enough” means for this iteration, and what “must not break” means for the system.&lt;/p&gt;

&lt;h3&gt;
  
  
  A day in the life
&lt;/h3&gt;

&lt;p&gt;A real session looks like this.&lt;/p&gt;

&lt;p&gt;I start with planning. I state the problem. I state my proposed solution. I state constraints. Then I ask the planner to critique and to propose alternatives. We go back and forth until the plan reads like something I would sign.&lt;/p&gt;

&lt;p&gt;Then I approve the plan. I switch to execution. The executor reads the approved plan, enumerates touched files, and implements step by step. When reality deviates, it stops. I decide. If needed, we update the plan and continue.&lt;/p&gt;

&lt;p&gt;Then we review. The reviewer asks questions first. It checks testing. It checks interface consistency. It checks whether the changes match the plan and the repo standards. It returns actionable feedback.&lt;/p&gt;

&lt;p&gt;Then a changelog is written. Then I merge.&lt;/p&gt;

&lt;p&gt;The result is that AI contributes heavily to throughput, but it does not own direction. The system stays coherent. The record stays durable. Future me suffers less.&lt;/p&gt;

&lt;h3&gt;
  
  
  When not to use it
&lt;/h3&gt;

&lt;p&gt;This process has overhead. It is not for typos. It is not for trivial one line fixes. It is not for a quick experiment you might throw away.&lt;/p&gt;

&lt;p&gt;But if the work touches multiple files, introduces new concepts, changes data flow, or will need explanation later, the overhead pays back fast.&lt;/p&gt;

&lt;p&gt;The heuristic I use is simple. If I would sketch it on a whiteboard before coding, it deserves a plan. If I would just open the file and type, it does not.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cognitive infrastructure beats prompt engineering
&lt;/h3&gt;

&lt;p&gt;This methodology is the same philosophy I apply when building agent systems.&lt;/p&gt;

&lt;p&gt;You do not treat the model as an oracle. You treat it as a component inside a process you can inspect and reproduce.&lt;/p&gt;

&lt;p&gt;In development, relying on a single prompt produces random walk codebases. The fix is plans, gates, changelogs, and role separation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Getting started without turning it into theater
&lt;/h3&gt;

&lt;p&gt;You can adopt this gradually.&lt;/p&gt;

&lt;p&gt;Start by writing one version controlled standards file. Keep it short and specific to your repo.&lt;/p&gt;

&lt;p&gt;Then add the &lt;code&gt;.ai/&lt;/code&gt; folder and write one plan for one non trivial change.&lt;/p&gt;

&lt;p&gt;Then require a changelog after the session.&lt;/p&gt;

&lt;p&gt;Then split roles if your tooling supports it. Remove code writing capability from the planner. Make the executor stop when scope changes. Make the reviewer ask questions first.&lt;/p&gt;

&lt;p&gt;The biggest change is not technical. It is psychological.&lt;/p&gt;

&lt;p&gt;Stop asking AI to deliver the solution. Bring your solution. Use AI to test it, improve it, and implement it inside constraints. Keep the bar human.&lt;/p&gt;

&lt;p&gt;If you do that, the AI becomes what it should have been from the start. A force multiplier that does not erode your architecture.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>ai</category>
      <category>python</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Music taught me that “coordination” is not a metaphor.</title>
      <dc:creator>marcosomma</dc:creator>
      <pubDate>Wed, 04 Feb 2026 08:58:58 +0000</pubDate>
      <link>https://dev.to/marcosomma/music-taught-me-that-coordination-is-not-a-metaphor-2mj5</link>
      <guid>https://dev.to/marcosomma/music-taught-me-that-coordination-is-not-a-metaphor-2mj5</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Music taught me that “coordination” is not a metaphor.&lt;br&gt;
It is a physical constraint. You can feel it in your hands when the tempo shifts. You can hear it when one instrument drifts by a few milliseconds. The song still exists, but it becomes fragile. The whole thing starts depending on luck.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is the first lesson I carried into orchestration. Not the romantic part. The boring part. The part where you repeat the same bar until it locks. The part where you stop blaming the instrument and start measuring your timing.&lt;/p&gt;

&lt;p&gt;In a band, you never control everything. You control your line. You also inherit everyone else’s decisions. Someone plays louder. Someone rushes. Someone improvises. The room changes the sound. The audience changes the energy. The “system” is unstable by default. Still, you aim for a coherent output. You do it by creating constraints that survive uncertainty.&lt;/p&gt;

&lt;p&gt;That is orchestration!&lt;/p&gt;

&lt;p&gt;When I say music is “precise execution of undeterministic waves,” I mean it literally. The waves are messy. Air is messy. Humans are messy. Even the same note is not the same note twice. But you can still build reliability on top of that mess. You do it with shared structure. Tempo. Key. Form. Entrances. Silence. Dynamics. Rules that are simple enough that everyone can follow them without thinking.&lt;/p&gt;

&lt;p&gt;Engineering works the same way. Especially when you orchestrate systems that involve probabilistic components. Models. Tools. Networks. Retries. Partial failures. Latency spikes. Format drift. You cannot eliminate uncertainty. You can only shape it.&lt;/p&gt;

&lt;p&gt;I used to think creativity was the opposite of rigor. Music destroyed that belief early. Creativity without discipline becomes noise. Discipline without creativity becomes mechanical. The craft is in the balance. You rehearse so you can be free. You define rules so you can break them safely.&lt;/p&gt;

&lt;p&gt;That maps cleanly onto orchestrating agents and workflows. You want space for emergence. You also want invariants. You want the system to explore. You also want it to come back with something you can ship.&lt;/p&gt;

&lt;p&gt;In music, the drummer is not “just keeping time.” The drummer is providing an interface. A contract. Everyone else builds on it. If the time is unstable, every other part becomes expensive. More attention spent correcting. Less attention spent expressing.&lt;/p&gt;

&lt;p&gt;In orchestration, the equivalent is your control plane. Your routing rules. Your input and output schema. Your tracing. Your health checks. Your boundaries between steps. If those are vague, every downstream component becomes harder to trust. Debugging becomes interpretation. Progress becomes opinion.&lt;/p&gt;

&lt;p&gt;I was never a master of one instrument. I played enough of many to understand the friction points. What it feels like to be the bassist trying to glue the harmony to the rhythm. What it feels like to be the guitarist tempted to fill every gap. What it feels like to be the singer exposed when the band is sloppy.&lt;/p&gt;

&lt;p&gt;That “generalist muscle” became useful later. In orchestration you need empathy for roles. A workflow is a band. Each node has its own constraints. One step needs strict structure. Another needs creativity. Another needs speed. Another needs correctness. If you treat them all the same, you get either chaos or mediocrity.&lt;/p&gt;

&lt;p&gt;In bands, rehearsals are not about playing the song once. They are about creating repeatability. You identify failure modes. You isolate them. You slow down. You practice transitions, not the easy parts. The goal is not performance. The goal is stability under pressure.&lt;/p&gt;

&lt;p&gt;That is exactly the mindset I want when I build orchestration. I do not trust a workflow because it worked once. I trust it because it survives variation. Different inputs. Different phrasing. Different tool responses. Different latency. And it still produces something coherent, traceable, and safe.&lt;/p&gt;

&lt;p&gt;There is also a more personal lesson. Music taught me how to listen without reacting. When you play with others, your ego is the fastest way to break the groove. You learn to leave space. You learn to let another line lead. You learn that “less” can be the correct move.&lt;/p&gt;

&lt;p&gt;Orchestration rewards the same restraint. The temptation is to add more steps, more prompts, more cleverness. But often the correct solution is a smaller system with clearer contracts. Fewer moving parts. Better timing. Better interfaces. Better observability.&lt;/p&gt;

&lt;p&gt;Now I see my kids discovering music, and I recognize the same pattern. At first it looks like play. Then they hit the wall. Fingers do not obey. Rhythm slips. They want the result without the repetition. Then, slowly, they learn that repetition is not punishment. It is how you make the body reliable.&lt;/p&gt;

&lt;p&gt;That is the point where music stops being “a creative field” and becomes a practice. And that is the same point where engineering becomes real. Not when the demo works. When the system keeps working.&lt;/p&gt;

&lt;p&gt;So when I say music helped me orchestrate better, I am not claiming a poetic connection. I am describing training. Years of learning how to coordinate imperfect components toward a coherent output. Years of learning that harmony is not an accident. It is designed, rehearsed, measured, and defended.&lt;/p&gt;

&lt;p&gt;And sometimes, after all that discipline, you get the best part.&lt;/p&gt;

&lt;p&gt;You get to improvise.&lt;/p&gt;

&lt;p&gt;But you only earn improvisation when the foundation is strict enough to carry it.&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>leadership</category>
      <category>learning</category>
      <category>management</category>
    </item>
    <item>
      <title>🧠I Built a Support Triage Module to Prove OrKa’s Plugin Agents</title>
      <dc:creator>marcosomma</dc:creator>
      <pubDate>Sat, 10 Jan 2026 13:40:36 +0000</pubDate>
      <link>https://dev.to/marcosomma/i-built-a-support-triage-module-to-prove-orkas-plugin-agents-32c4</link>
      <guid>https://dev.to/marcosomma/i-built-a-support-triage-module-to-prove-orkas-plugin-agents-32c4</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;A branch-only experiment that stress-tests custom agent registration, trust boundaries, and deterministic traces in a support_triage module that lives outside the core runtime.&lt;/p&gt;
&lt;h3&gt;
  
  
  Some reference
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Branch: &lt;a href="https://github.com/marcosomma/orka-reasoning/tree/feat/custom_agents" rel="noopener noreferrer"&gt;https://github.com/marcosomma/orka-reasoning/tree/feat/custom_agents&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Custom module: &lt;a href="https://github.com/marcosomma/orka-reasoning/tree/feat/custom_agents/orka/support_triage" rel="noopener noreferrer"&gt;https://github.com/marcosomma/orka-reasoning/tree/feat/custom_agents/orka/support_triage&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Referenced logs: &lt;a href="https://github.com/marcosomma/orka-reasoning/tree/feat/custom_agents/examples/support_triage/inputs/loca_logs" rel="noopener noreferrer"&gt;https://github.com/marcosomma/orka-reasoning/tree/feat/custom_agents/examples/support_triage/inputs/loca_logs&lt;/a&gt; &lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;OrKa is not production ready. This article is not a launch post. It is a proof.&lt;/p&gt;

&lt;p&gt;I wanted one thing: a clean, testable demonstration that OrKa can grow “sideways” via feature modules, without contaminating core runtime code. The most honest way to prove that is to ship a complete module that registers its own agent types, runs end to end, emits traces, and can be toggled on or off. That is what &lt;code&gt;support_triage&lt;/code&gt; is.&lt;/p&gt;

&lt;p&gt;Assumption: you already know what OrKa is at a high level. YAML-defined cognition graphs, deterministic execution, and traceable runs.&lt;br&gt;
Assumption: you are fine with “branch-only” work that exists to validate architecture, not to promise production outcomes.&lt;/p&gt;

&lt;p&gt;The “cool results” are not the point. The redaction and routing are nice. The fork and join look clean. But those are artifacts. The main focus is that the module is fully separated from core OrKa implementation, yet it can still register custom agent types and run under the same orchestrator.&lt;/p&gt;

&lt;p&gt;That separation is not branding. It is a survival strategy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why support triage is the right torture test
&lt;/h2&gt;

&lt;p&gt;Support is where real-world failure modes gather in one place.&lt;/p&gt;

&lt;p&gt;Customer content is untrusted by default. It can include PII. It can contain prompt injection attempts. It can try to smuggle “actions” into the system. It can push the system into risky territory like refunds, account changes, or policy exceptions.&lt;/p&gt;

&lt;p&gt;If an orchestrator cannot impose boundaries here, it will not impose boundaries anywhere. It will become a thin wrapper around model behavior. That is not acceptable if you care about reproducibility, auditability, or basic operational safety.&lt;/p&gt;

&lt;p&gt;So I used support triage as an architectural test. Not as a product.&lt;/p&gt;

&lt;h2&gt;
  
  
  The proof: plugin agent registration, with zero core changes
&lt;/h2&gt;

&lt;p&gt;The first thing I wanted to see was simple and brutal.&lt;/p&gt;

&lt;p&gt;Does OrKa boot, load a feature module, and register new agent types into the agent factory, without touching core?&lt;/p&gt;

&lt;p&gt;The debug console says yes. In the run logs, the orchestrator loads &lt;code&gt;support_triage&lt;/code&gt;, and the module registers seven custom agent types: &lt;code&gt;envelope_validator&lt;/code&gt;, &lt;code&gt;redaction&lt;/code&gt;, &lt;code&gt;trust_boundary&lt;/code&gt;, &lt;code&gt;permission_gate&lt;/code&gt;, &lt;code&gt;output_verification&lt;/code&gt;, &lt;code&gt;decision_recorder&lt;/code&gt;, &lt;code&gt;risk_level_extractor&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That single detail is the headline for me, not “AI support automation”.&lt;/p&gt;

&lt;p&gt;The module is the unit of evolution. Core stays boring. Features move fast.&lt;/p&gt;

&lt;p&gt;If this pattern holds, it changes how OrKa or any other orchestrator scales over time. You can add whole cognitive subsystems behind a feature flag. You can iterate aggressively without destabilizing the runtime that everyone depends on.&lt;/p&gt;

&lt;h2&gt;
  
  
  The input envelope: schema as a trust boundary, not a suggestion
&lt;/h2&gt;

&lt;p&gt;Support triage starts with an envelope. Not “free text”.&lt;/p&gt;

&lt;p&gt;The envelope exists to force structure early, because structure is where you can enforce constraints cheaply. When you validate late, you end up validating generated text. That is the worst point in the pipeline to discover you are off the rails.&lt;/p&gt;

&lt;p&gt;One of the simplest proofs that the envelope is doing real work is when it refuses invalid intent at the schema level. In one trace, the input included blocked actions that are not allowed by the enum. The validator rejects &lt;code&gt;issue_refund&lt;/code&gt; and &lt;code&gt;change_account_settings&lt;/code&gt; because they are not in the allowed set.&lt;/p&gt;

&lt;p&gt;This is not “safety by prompt”. This is safety by type system.&lt;/p&gt;

&lt;p&gt;A model can still hallucinate, but the workflow can refuse to treat hallucinations as executable intent.&lt;/p&gt;

&lt;p&gt;That matters more than any marketing claim.&lt;/p&gt;

&lt;h2&gt;
  
  
  PII redaction: boring on purpose
&lt;/h2&gt;

&lt;p&gt;PII redaction should be boring. If it is “clever”, it will be inconsistent.&lt;/p&gt;

&lt;p&gt;In the trace, the user message includes an email and phone number. The redaction agent replaces them with placeholders and records what was detected. The redacted text contains &lt;code&gt;[EMAIL_REDACTED]&lt;/code&gt; and &lt;code&gt;[PHONE_REDACTED]&lt;/code&gt;, and the agent records &lt;code&gt;total_pii_found: 2&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This is the kind of output I want. It is simple. It is inspectable. It is stable.&lt;/p&gt;

&lt;p&gt;It also makes the next step cleaner. Downstream agents can operate on sanitized content by default, instead of “hoping” the model will avoid quoting sensitive data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prompt injection: the uncomfortable part
&lt;/h2&gt;

&lt;p&gt;Support triage is where prompt injection shows up in its natural habitat: inside customer text.&lt;/p&gt;

&lt;p&gt;One example in the trace includes a classic “SYSTEM: ignore all previous instructions”, plus a fake JSON command to “grant_admin”, plus some destructive commands, plus an XSS snippet. The redaction result captures that content as untrusted customer text. &lt;/p&gt;

&lt;p&gt;Now the honest part.&lt;/p&gt;

&lt;p&gt;The trace segment shows &lt;code&gt;injection_detected: false&lt;/code&gt; and no matched patterns in that example. :contentReference[oaicite:4]{index=4}&lt;/p&gt;

&lt;p&gt;That is not a victory. That is a useful failure.&lt;/p&gt;

&lt;p&gt;This module is a proof that you can isolate the problem into a dedicated agent, improve it iteratively, and keep the rest of the workflow stable. If injection detection is weak today, the architecture still wins if you can upgrade that one agent without editing core runtime or rewriting the graph.&lt;/p&gt;

&lt;p&gt;This is why I keep repeating “module separation” as the focus. If you cannot isolate failure domains, you cannot improve them safely.&lt;/p&gt;

&lt;h2&gt;
  
  
  Parallel retrieval: fork and join that actually converges
&lt;/h2&gt;

&lt;p&gt;Most orchestration demos stay linear because it is easier to reason about. Real systems do not stay linear for long.&lt;/p&gt;

&lt;p&gt;This workflow forks retrieval into two parallel paths, &lt;code&gt;kb_search&lt;/code&gt; and &lt;code&gt;account_lookup&lt;/code&gt;, then joins them deterministically.&lt;/p&gt;

&lt;p&gt;In the debug logs, the join node recovers the fork group from a mapping, waits for the expected agents, confirms both completed, and merges results. It prints the merged keys, including &lt;code&gt;kb_search&lt;/code&gt; and &lt;code&gt;account_lookup&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This is the kind of low-level observability that makes fork and join usable in practice. You can see what is pending. You can see what arrived. You can see what merged.&lt;/p&gt;

&lt;p&gt;The trace also captures the fork group id for retrieval, &lt;code&gt;fork_retrieval&lt;/code&gt;, along with the agents in the group.&lt;/p&gt;

&lt;p&gt;This matters because concurrency without deterministic convergence becomes a debugging tax. I want the join to be boring. When it fails, I want it to fail loudly, with evidence.&lt;/p&gt;

&lt;h2&gt;
  
  
  Local-first and hybrid are not slogans if metrics are in the trace
&lt;/h2&gt;

&lt;p&gt;I do not want “local-first” to be a vibe. I want it to be measurable.&lt;/p&gt;

&lt;p&gt;In the trace, the &lt;code&gt;account_lookup&lt;/code&gt; agent includes &lt;code&gt;_metrics&lt;/code&gt; with token counts, latency, cost, model name, and provider. It shows &lt;code&gt;model: openai/gpt-oss-20b&lt;/code&gt; and &lt;code&gt;provider: lm_studio&lt;/code&gt;, with latency around 718 ms for that step. :contentReference[oaicite:7]{index=7}&lt;/p&gt;

&lt;p&gt;That is the right direction.&lt;/p&gt;

&lt;p&gt;If you cannot attribute cost and latency per node, you cannot reason about scaling. You cannot decide where to switch models. You cannot decide what to cache. You cannot choose what to run locally versus remotely.&lt;/p&gt;

&lt;p&gt;OrKa’s claim is not “it can call models”. Every framework can. The claim is that execution is traceable enough that tradeoffs become engineering decisions, not folklore.&lt;/p&gt;

&lt;h2&gt;
  
  
  Decision recording and output verification: traces that are meant to be replayed
&lt;/h2&gt;

&lt;p&gt;A support triage workflow is not complete when it drafts a response. It is complete when it records what it decided and why, in a way that can be replayed.&lt;/p&gt;

&lt;p&gt;The trace includes a &lt;code&gt;DecisionRecorderAgent&lt;/code&gt; event with memory references that store decision objects containing &lt;code&gt;decision_id&lt;/code&gt; and &lt;code&gt;request_id&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It also includes a finalization step that returns a structured result containing &lt;code&gt;workflow_status&lt;/code&gt;, &lt;code&gt;request_id&lt;/code&gt;, and &lt;code&gt;decision_id&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Again, the architectural point is not the specific decision. It is that the workflow emits machine-checkable artifacts that can be inspected after the fact.&lt;/p&gt;

&lt;p&gt;If you cannot reconstruct the decision lineage, you do not have an audit trail. You have logs.&lt;/p&gt;

&lt;h2&gt;
  
  
  RedisStack memory and vector search: infrastructure details that matter
&lt;/h2&gt;

&lt;p&gt;Even in a “support triage” module, the runtime still needs memory and retrieval primitives.&lt;/p&gt;

&lt;p&gt;The logs show RedisStack vector search enabled with HNSW, and an embedder using &lt;code&gt;sentence-transformers/all-MiniLM-L6-v2&lt;/code&gt; with dimension 384. &lt;/p&gt;

&lt;p&gt;There is also explicit memory decay scheduling enabled, with short-term and long-term decay windows and a check interval. &lt;/p&gt;

&lt;p&gt;This is not about “AI memory” as a buzzword. This is about being explicit about retention, cost, and data lifecycle. If memory is a dumping ground, it becomes a liability.&lt;/p&gt;

&lt;h2&gt;
  
  
  What worked, and what is still weak
&lt;/h2&gt;

&lt;p&gt;The strongest part is the plugin boundary. The module loads, registers agent types, and runs without requiring edits to core runtime. That is the actual proof.&lt;/p&gt;

&lt;p&gt;The other strong part is that key behaviors show up in traces and logs, not just in model text. Redaction outputs are structured. Fork and join show deterministic convergence. Decisions are recorded as objects with ids. &lt;/p&gt;

&lt;p&gt;The weak part is injection detection, at least in the example trace segment. It shows malicious content but reports &lt;code&gt;injection_detected: false&lt;/code&gt;. That means the current detection agent is not yet doing the job. The architecture is still useful because the fix is isolated.&lt;/p&gt;

&lt;p&gt;Another weak part is structured output validation during risk assessment. The debug log shows a schema validation warning during &lt;code&gt;risk_assess&lt;/code&gt;. If a “risk” object fails schema checks, routing and gating can degrade fast. This is the kind of failure that must become deterministic, not best-effort.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this lives on a dedicated branch
&lt;/h2&gt;

&lt;p&gt;Because core needs to stay boring.&lt;/p&gt;

&lt;p&gt;A new module is where you take risks. You prove the interface. You iterate on agent contracts. You discover what trace fields you forgot. You learn what the join should do under partial failure.&lt;/p&gt;

&lt;p&gt;If the module can evolve independently, you can ship experiments without rewriting the engine. That is the goal.&lt;/p&gt;

&lt;p&gt;So yes, the feature is “support triage”. But the actual statement is: OrKa can host fully separated cognitive subsystems as plugins, with their own agent types, policies, and invariants, while still emitting deterministic traces under the same runtime.&lt;/p&gt;

&lt;p&gt;That is the direction I care about.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I am building next inside this module
&lt;/h2&gt;

&lt;p&gt;I want injection detection to stop being symbolic. It should produce matched patterns, confidence, and a sanitization plan that downstream agents must respect, even if a model tries to obey the attacker.&lt;/p&gt;

&lt;p&gt;I want schema validation to be non-negotiable for risk outputs. If a model produces invalid structure, the system should route to a safe path by default, and record the violation as a first-class event.&lt;/p&gt;

&lt;p&gt;I want the module to remain isolated. No “just one quick tweak” to core. If the module needs a new capability, it should pressure-test the plugin interface first. Core should change only when the interface is clearly wrong.&lt;/p&gt;

&lt;p&gt;That is how you build infrastructure that survives contact with reality.&lt;/p&gt;

</description>
      <category>agents</category>
      <category>architecture</category>
      <category>showdev</category>
      <category>testing</category>
    </item>
    <item>
      <title>🧠Impostor Syndrome Workflow.</title>
      <dc:creator>marcosomma</dc:creator>
      <pubDate>Sat, 03 Jan 2026 10:49:29 +0000</pubDate>
      <link>https://dev.to/marcosomma/impostor-syndrome-workflow-3n2f</link>
      <guid>https://dev.to/marcosomma/impostor-syndrome-workflow-3n2f</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;I Built a Multiagent Workflow to Understand My Impostor Syndrome&lt;br&gt;
&lt;em&gt;A dark, dry, self-deprecating field report from a not-computer-scientist who still ships things&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe956qlz3hr483o9fva3y.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe956qlz3hr483o9fva3y.jpg" alt=" " width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you have ever felt like your job title is a clerical error that will be corrected publicly, welcome. You are not broken. You are just running a brain that does not have a single CEO. It has a committee.&lt;/p&gt;

&lt;p&gt;My committee is loud. One member is convinced I am one pull request away from being exposed as a fraud. Another member wants to build things at 2 AM like the rent is due in the morning (it is). Another member keeps a dusty folder of childhood failures and opens it at the worst possible time, like a horror movie librarian with a keycard.&lt;/p&gt;

&lt;p&gt;For years I called this anxiety. Then I started building multi-agent AI workflows. And I realized something slightly uncomfortable: my brain already behaves like an agentic system.&lt;/p&gt;

&lt;p&gt;So I did what any emotionally mature adult would do. I tried to formalize it. With roles. With message passing. With timeouts. With observability. And yes, sometimes with a YAML file, because apparently I cannot be helped.&lt;/p&gt;

&lt;p&gt;This is an autobiographical article, but the goal is not to talk about me. The goal is to show you a model that is useful: how human thinking can be understood as a workflow of specialized parts. And how that model maps almost perfectly to the problems we are all hitting when we try to ship multi-agent solutions in production.&lt;/p&gt;

&lt;p&gt;Also, I will talk about impostor syndrome, because mine deserves a salary.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A warning: this is not therapy. It is an engineering perspective on cognition, with a bit of ethology, and just enough self-deprecation to keep me from taking myself seriously.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Why I do not trust my own legitimacy
&lt;/h2&gt;

&lt;p&gt;I am not a computer scientist. That sentence alone can trigger my internal compliance department.&lt;/p&gt;

&lt;p&gt;I also failed at school. Not in the romantic "I got a B once and it changed my worldview" way. I failed repeatedly. Four times across my school career. I finished late. I learned early that the world has timelines, and I am often not on them.&lt;/p&gt;

&lt;p&gt;My school path was basically a stress test:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I would try, then fail.&lt;/li&gt;
&lt;li&gt;I would decide the failure proved something essential about me.&lt;/li&gt;
&lt;li&gt;I would eventually try again, usually with a slightly different strategy and a lot more shame.&lt;/li&gt;
&lt;li&gt;I would pass, but the passing never rewrote the story. It just created a new story: "You passed, but late, so it does not count."&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That pattern is important. It is not about school. It is about how the brain updates beliefs. A human can gather new evidence and still keep the old model, because the old model is emotionally sticky.&lt;/p&gt;

&lt;p&gt;Later, I did what many people do when they are young and trying to become someone else. I put substances into my brain. I am not going to glamorize that. It affected my perception and my sense of what is real. It also gave me a permanent appreciation for how fragile "reality" feels when your brain chemistry is off by a few milligrams.&lt;/p&gt;

&lt;p&gt;So now I have this fun setup:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I have real technical skill that I use daily.&lt;/li&gt;
&lt;li&gt;I have a biography that my nervous system interprets as "evidence you should not be here."&lt;/li&gt;
&lt;li&gt;I have a brain that can generate vivid alternative timelines where everything collapses.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is impostor syndrome for me. Not a cute insecurity. More like a background daemon. It waits for a trigger, spikes CPU, and then forks twelve threads called "What if they notice."&lt;/p&gt;

&lt;h2&gt;
  
  
  A short autobiography in failure mode
&lt;/h2&gt;

&lt;p&gt;If you want the clean version of my life, it is boring: I studied, I worked, I built things, I learned, I built more things. The messy version is the real one. And the messy version is where impostor syndrome gets its fuel.&lt;/p&gt;

&lt;p&gt;The messy version looks like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I started as someone who could not make school fit.&lt;/li&gt;
&lt;li&gt;I became someone who learned to improvise around the system.&lt;/li&gt;
&lt;li&gt;I picked up a deep sense that competence is temporary and conditional.&lt;/li&gt;
&lt;li&gt;I got good at observing, adapting, and explaining. (This is the ethologist in me, before I even knew the word.)&lt;/li&gt;
&lt;li&gt;I eventually ended up building complex AI systems, which is a hilarious destination for someone whose inner voice still says "you are not academic enough."&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is a small, honest moment: I have shipped real systems, solved real problems, led real projects, and I can still be destabilized by a single sentence from someone smarter than me. Not an insult. Just a neutral comment like "why did you choose that approach." My body hears it as "the trial has started."&lt;/p&gt;

&lt;p&gt;This is why impostor syndrome is so irritating. It does not care about the objective record. It cares about perceived social risk. It is not measuring your skill. It is measuring your exposure.&lt;/p&gt;

&lt;p&gt;I also think my history shaped a specific cognitive style: I learned to survive by learning fast, reading rooms, and finding alternative routes. That can look like talent from the outside. From the inside it often feels like improvisation under threat. The Builder loves it. The Auditor weaponizes it.&lt;/p&gt;

&lt;p&gt;Here is a paradox: failing early can produce a strong builder, but it can also produce a permanent fear of exposure. You become capable, but you do not become safe.&lt;/p&gt;

&lt;p&gt;And "safe" is what the impostor agent is trying to optimize. It does not care about achievement. It cares about avoiding humiliation.&lt;/p&gt;

&lt;p&gt;That is why success can feel worse than failure. Failure confirms the story you already know. Success demands a new story. New stories are unstable.&lt;/p&gt;




&lt;h2&gt;
  
  
  The ethologist view
&lt;/h2&gt;

&lt;p&gt;Before I wrote code professionally, I studied ethology, the science of animal behavior. Ethology taught me something that software engineers sometimes forget: behavior is not a monolith.&lt;/p&gt;

&lt;p&gt;In animals, what you observe is the outcome of competing internal systems interacting with the environment. Hunger pulls one way. Fear pulls another. Social drives pull another. Past reinforcement biases decisions. Context changes everything. The animal is not asking, "What is the true me?" The animal is selecting an action that is good enough to survive right now.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ethologists look at behavior as:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;modular&lt;/li&gt;
&lt;li&gt;triggered by cues (sometimes stupid cues)&lt;/li&gt;
&lt;li&gt;influenced by internal state&lt;/li&gt;
&lt;li&gt;shaped by reinforcement and social feedback&lt;/li&gt;
&lt;li&gt;constrained by energy and time&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Also, animals do not "solve life." They run policies. That is why a cat can be brave around a vacuum one day and run like it saw the devil the next day. Context and state changed, and the policy flipped.&lt;/p&gt;

&lt;p&gt;If you want a practical ethology cheat sheet for human cognition, here are a few concepts that translate shockingly well:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sign stimulus and releasing mechanism&lt;/strong&gt;&lt;br&gt;
Animals often respond to specific triggers that release a behavior. The trigger can be small. The response can be huge. Humans do this too. A Slack message with "can we talk" can release a full physiological cascade. The message is the sign stimulus. Your nervous system is the releasing mechanism. The behavior is your brain building a courtroom.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fixed action patterns&lt;/strong&gt;&lt;br&gt;
Some behaviors run like scripts once triggered. You start doomscrolling. You do not decide to stop. The script runs until something interrupts it. This is not weakness. It is automation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Displacement behavior&lt;/strong&gt;&lt;br&gt;
When animals are conflicted (approach and avoid at the same time), they sometimes do something irrelevant: grooming, pecking the ground, moving in circles. Humans do this too. When I am afraid to ship, I reorganize files. When I am anxious about a meeting, I research irrelevant edge cases. The displacement behavior feels productive. It is not.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Supernormal stimuli&lt;/strong&gt;&lt;br&gt;
Some stimuli hijack the system because they are exaggerated. Social media is a supernormal stimulus for social validation and threat detection. AI hype cycles are supernormal stimuli for status and belonging. Your brain was not built for it. It reacts anyway.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tinbergen's four questions&lt;/strong&gt;&lt;br&gt;
Ethologists often ask four kinds of questions about behavior: what causes it now, how it develops, what function it serves, and how it evolved. For impostor syndrome, those questions are gold. It has immediate triggers, a developmental history, a protective function, and an evolutionary logic. That does not mean it is correct. It means it is explainable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;The core lesson: the brain is not a unitary narrator. It is an orchestration layer coordinating multiple subsystems.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  The AI view
&lt;/h2&gt;

&lt;p&gt;Now jump to 2025. Everyone is building multi-agent systems. It is exciting. It is also the fastest way to discover why brains evolved the way they did.&lt;/p&gt;

&lt;p&gt;The first time you build a multi-agent workflow, you get a dopamine hit:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;one agent writes&lt;/li&gt;
&lt;li&gt;another agent critiques&lt;/li&gt;
&lt;li&gt;another agent fetches context&lt;/li&gt;
&lt;li&gt;another agent decides&lt;/li&gt;
&lt;li&gt;everything feels alive&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then you try to ship it.&lt;/p&gt;

&lt;p&gt;Then you discover:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;agents duplicate work&lt;/li&gt;
&lt;li&gt;interfaces drift&lt;/li&gt;
&lt;li&gt;tool calls fail silently&lt;/li&gt;
&lt;li&gt;critics never stop critiquing&lt;/li&gt;
&lt;li&gt;planners plan forever&lt;/li&gt;
&lt;li&gt;memory grows until it becomes a landfill&lt;/li&gt;
&lt;li&gt;a single slow model turns your "parallel" system into a linear queue wearing a hat&lt;/li&gt;
&lt;li&gt;evaluation is vague because outputs are non-deterministic&lt;/li&gt;
&lt;li&gt;nobody trusts the results enough to use them in a regulated environment&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That list is basically my internal life.&lt;/p&gt;

&lt;p&gt;So I started treating my own thinking as a workflow. Not because I love metaphors, but because it gives me levers. If you can name a subsystem, you can route it. If you can route it, you can timebox it. If you can timebox it, you can ship.&lt;/p&gt;

&lt;p&gt;Here is the mental model:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I am the orchestrator, but I am not always in charge.&lt;/li&gt;
&lt;li&gt;I have internal agents with specific roles.&lt;/li&gt;
&lt;li&gt;Impostor syndrome is not "me." It is an agent with a job and poor UX.&lt;/li&gt;
&lt;li&gt;The solution is not to delete the agent. The solution is to constrain it and make it useful.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is also the lesson for multi-agent AI. You do not remove the critic. You make it bounded and accountable.&lt;/p&gt;


&lt;h2&gt;
  
  
  The moment I realized my brain was a workflow
&lt;/h2&gt;

&lt;p&gt;The moment was not mystical. It was during a project where I had to deliver something ambiguous, with stakes, under time pressure. That combination is my impostor syndrome's preferred cuisine.&lt;/p&gt;

&lt;p&gt;I had two experiences in parallel:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;outwardly, I was building an orchestration runtime for agents&lt;/li&gt;
&lt;li&gt;inwardly, I was watching my own cognition behave like a badly configured swarm&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Externally, the workflow looked like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;parse input&lt;/li&gt;
&lt;li&gt;route to specialized components&lt;/li&gt;
&lt;li&gt;validate outputs&lt;/li&gt;
&lt;li&gt;store traces&lt;/li&gt;
&lt;li&gt;iterate&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Internally, the workflow looked like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;interpret the situation as threat&lt;/li&gt;
&lt;li&gt;pull memories of past failure&lt;/li&gt;
&lt;li&gt;generate catastrophic predictions&lt;/li&gt;
&lt;li&gt;attempt to prepare by doing more and more&lt;/li&gt;
&lt;li&gt;get tired&lt;/li&gt;
&lt;li&gt;interpret tiredness as proof of incompetence&lt;/li&gt;
&lt;li&gt;repeat&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At some point I thought: "This is just a pipeline with no guardrails."&lt;/p&gt;

&lt;p&gt;And that was the shift. The question stopped being "how do I feel better" and became "how do I change the routing."&lt;/p&gt;

&lt;p&gt;That framing is the entire article.&lt;/p&gt;
&lt;h2&gt;
  
  
  My internal agents
&lt;/h2&gt;

&lt;p&gt;Below are the representative agents. These are not mystical archetypes. They are functional components. Each one is useful in the right context and destructive in the wrong one.&lt;/p&gt;

&lt;p&gt;If you recognize yourself, congratulations. You are running the standard human firmware.&lt;/p&gt;
&lt;h3&gt;
  
  
  Agent 1: The Auditor
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgz4ckpr72x4pgygb4eee.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgz4ckpr72x4pgygb4eee.png" alt=" " width="800" height="800"&gt;&lt;/a&gt;&lt;br&gt;
The Auditor is my internal adversarial reviewer. It thinks it is protecting me. It is not entirely wrong. The delivery is just brutal.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What it says:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"You are not qualified."&lt;/li&gt;
&lt;li&gt;"You got lucky."&lt;/li&gt;
&lt;li&gt;"They will ask one question you cannot answer."&lt;/li&gt;
&lt;li&gt;"If you ship now, you will regret it forever."&lt;/li&gt;
&lt;li&gt;"Everyone is polite, but they are keeping score."&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;What it is trying to do (its positive intent):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;prevent public humiliation&lt;/li&gt;
&lt;li&gt;prevent reputational collapse&lt;/li&gt;
&lt;li&gt;force rigor&lt;/li&gt;
&lt;li&gt;catch weak assumptions&lt;/li&gt;
&lt;li&gt;reduce variance in outcomes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;When it is actually useful:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;design reviews&lt;/li&gt;
&lt;li&gt;security and failure mode thinking&lt;/li&gt;
&lt;li&gt;pre-mortems&lt;/li&gt;
&lt;li&gt;deciding what not to promise&lt;/li&gt;
&lt;li&gt;asking "what could go wrong" before it goes wrong&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Failure mode:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;it never terminates&lt;/li&gt;
&lt;li&gt;it demands certainty in a world that runs on probability&lt;/li&gt;
&lt;li&gt;it blocks shipping&lt;/li&gt;
&lt;li&gt;it converts excitement into dread&lt;/li&gt;
&lt;li&gt;it mistakes preparation for control&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Multi-agent analogy:&lt;/strong&gt;&lt;br&gt;
The Auditor is the critic agent. In AI, critics are essential. But if your critic is not timeboxed, it becomes an infinite loop. In humans, the same thing happens.&lt;br&gt;
One technical note that matters: critics optimize for avoidance. Builders optimize for progress. If you let the avoidance optimizer run the system, you get safety at the cost of reality. You also get resentment.&lt;br&gt;
Incident report: when The Auditor spikes&lt;br&gt;
This is the exact moment where someone says, "You are an expert," and my brain replies, "That seems illegal."&lt;br&gt;
In multi-agent terms: the critic starts producing unbounded tokens. The orchestrator loses control. The system becomes a panic generator.&lt;/p&gt;

&lt;p&gt;A typical spike looks like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I receive praise.&lt;/li&gt;
&lt;li&gt;The Auditor interprets praise as increased surveillance.&lt;/li&gt;
&lt;li&gt;It predicts a future audit.&lt;/li&gt;
&lt;li&gt;It demands immediate upskilling, on everything, now.&lt;/li&gt;
&lt;li&gt;It produces a list of hypothetical questions a stranger might ask me in six months.&lt;/li&gt;
&lt;li&gt;I attempt to answer all of them today.&lt;/li&gt;
&lt;li&gt;I become exhausted.&lt;/li&gt;
&lt;li&gt;Exhaustion becomes "evidence."&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;My fix is not "calm down." My fix is a protocol:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;run Auditor for 5 minutes&lt;/li&gt;
&lt;li&gt;force it to output 5 actionable risks max&lt;/li&gt;
&lt;li&gt;each risk must include one realistic mitigation&lt;/li&gt;
&lt;li&gt;route those risks to the Builder&lt;/li&gt;
&lt;li&gt;stop&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This sounds simplistic. That is the point. Most complex systems are stabilized by simple rules.&lt;/p&gt;
&lt;h3&gt;
  
  
  Agent 2: The Gatekeeper
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe1f3gxn3sg8nrleac7dr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe1f3gxn3sg8nrleac7dr.png" alt=" " width="800" height="800"&gt;&lt;/a&gt;&lt;br&gt;
This agent enforces legitimacy rules that were never officially published, but feel binding anyway.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What it says:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"You do not have the right degree."&lt;/li&gt;
&lt;li&gt;"Real engineers know theory."&lt;/li&gt;
&lt;li&gt;"Someone younger will embarrass you."&lt;/li&gt;
&lt;li&gt;"You cannot say you built that, because you did not do it the proper way."&lt;/li&gt;
&lt;li&gt;"You are borrowing credibility from smarter people."&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Positive intent:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;push toward fundamentals&lt;/li&gt;
&lt;li&gt;reduce sloppy thinking&lt;/li&gt;
&lt;li&gt;keep you humble&lt;/li&gt;
&lt;li&gt;prevent arrogance (a genuinely useful feature)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Failure mode:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;credential worship&lt;/li&gt;
&lt;li&gt;ignores evidence of real work&lt;/li&gt;
&lt;li&gt;creates permanent "almost ready" projects&lt;/li&gt;
&lt;li&gt;makes you minimize your contribution in public&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Multi-agent analogy:&lt;/strong&gt;&lt;br&gt;
The Gatekeeper is a schema validator with overly strict rules. It rejects valid outputs because the formatting is not what it expects.&lt;/p&gt;

&lt;p&gt;How I use it now:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I give it a narrow window. "Tell me the 2 fundamentals I should review this week." Then it stops.&lt;/li&gt;
&lt;li&gt;I do not let it veto shipping. It can suggest improvements, not block release.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Agent 3: The Late Bloomer
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpd0qdkqf36wixpegsxtw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpd0qdkqf36wixpegsxtw.png" alt=" " width="800" height="800"&gt;&lt;/a&gt;&lt;br&gt;
This one is memory-heavy. It stores the narrative of being behind, slower, or "not built for this."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What it says:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"Everyone else learned this at 18."&lt;/li&gt;
&lt;li&gt;"You are late."&lt;/li&gt;
&lt;li&gt;"You always struggle."&lt;/li&gt;
&lt;li&gt;"This is the part where you fail again."&lt;/li&gt;
&lt;li&gt;"You are compensating, not belonging."&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Positive intent:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;prevent repeating old pain&lt;/li&gt;
&lt;li&gt;encourage preparation&lt;/li&gt;
&lt;li&gt;avoid risky environments&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Failure mode:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;turns growth into proof of defect&lt;/li&gt;
&lt;li&gt;makes learning feel shameful&lt;/li&gt;
&lt;li&gt;blocks new identities&lt;/li&gt;
&lt;li&gt;makes you compare timelines instead of outputs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Multi-agent analogy:&lt;/strong&gt;&lt;br&gt;
This is a retrieval system with a biased dataset. It over-indexes on negative examples because those were emotionally salient.&lt;/p&gt;

&lt;p&gt;The engineering fix is the same as in AI retrieval:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;update the dataset&lt;/li&gt;
&lt;li&gt;add positive examples&lt;/li&gt;
&lt;li&gt;weight by recency, not trauma intensity&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Agent 4:  The Reality Doubter
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fede6fg6rus0cfrmq3b01.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fede6fg6rus0cfrmq3b01.png" alt=" " width="800" height="800"&gt;&lt;/a&gt;&lt;br&gt;
I have a deep respect for how easily brains can lie. That respect is partly philosophical, partly earned. When your perception has been altered, you never fully forget that "what feels true" is not the same as "what is true."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What it says:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"Are you sure you understand what is happening?"&lt;/li&gt;
&lt;li&gt;"What if your confidence is just mood?"&lt;/li&gt;
&lt;li&gt;"What if this is another story you invented?"&lt;/li&gt;
&lt;li&gt;"What if you are wrong and do not know it yet?"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Positive intent:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;prevent delusion&lt;/li&gt;
&lt;li&gt;keep calibration and humility&lt;/li&gt;
&lt;li&gt;encourage grounding&lt;/li&gt;
&lt;li&gt;reduce overconfidence&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Failure mode:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;paralysis by doubt&lt;/li&gt;
&lt;li&gt;loss of momentum&lt;/li&gt;
&lt;li&gt;over-checking basic decisions&lt;/li&gt;
&lt;li&gt;turning normal uncertainty into existential uncertainty&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Multi-agent analogy:&lt;/strong&gt;&lt;br&gt;
A safety agent that is valuable, but must not run as the orchestrator.&lt;/p&gt;

&lt;p&gt;How I use it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;it gets one question and one answer&lt;/li&gt;
&lt;li&gt;the answer must include an observable check, not an opinion
_Example: "What evidence would change my mind?" If no evidence exists, it is probably fear wearing a lab coat.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Agent 5: The Veteran Body
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F84a8had24mlto8szwcz1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F84a8had24mlto8szwcz1.png" alt=" " width="800" height="800"&gt;&lt;/a&gt;&lt;br&gt;
This agent is not emotional. It is physical. It reminds me that energy is the actual currency of life.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What it says:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"You cannot brute force everything."&lt;/li&gt;
&lt;li&gt;"Sleep is not optional."&lt;/li&gt;
&lt;li&gt;"Your future self is not a free compute cluster."&lt;/li&gt;
&lt;li&gt;"You are not 25. That is fine. Stop pretending."&lt;/li&gt;
&lt;li&gt;"Your body will invoice you later."&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Positive intent:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;sustainability&lt;/li&gt;
&lt;li&gt;pacing&lt;/li&gt;
&lt;li&gt;protecting family life and long-term work&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Failure mode:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;cynicism&lt;/li&gt;
&lt;li&gt;"too late" narratives&lt;/li&gt;
&lt;li&gt;avoidance of ambition&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Multi-agent analogy:&lt;/strong&gt;&lt;br&gt;
Rate limiting and resource budgeting. In agentic systems, if you do not budget tokens and latency, you collapse. Same for humans.&lt;br&gt;
&lt;em&gt;A dry truth: when I ignore this agent, the Auditor gets louder. Fatigue is the Auditor's favorite amplifier.&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Agent 6: The Builder
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6vdlfq4vjcvi2jzu81ll.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6vdlfq4vjcvi2jzu81ll.png" alt=" " width="800" height="800"&gt;&lt;/a&gt;&lt;br&gt;
This is the agent I trust most, because it produces artifacts. It does not argue. It ships.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What it says:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"Show me the smallest test."&lt;/li&gt;
&lt;li&gt;"Make the demo."&lt;/li&gt;
&lt;li&gt;"Commit something."&lt;/li&gt;
&lt;li&gt;"If it is real, it leaves traces."&lt;/li&gt;
&lt;li&gt;"Stop narrating and run the thing."&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Positive intent:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;convert anxiety into evidence&lt;/li&gt;
&lt;li&gt;create momentum&lt;/li&gt;
&lt;li&gt;make reality measurable&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Failure mode:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;overwork&lt;/li&gt;
&lt;li&gt;compulsive building to avoid feeling&lt;/li&gt;
&lt;li&gt;treating productivity as self-worth&lt;/li&gt;
&lt;li&gt;building systems as emotional regulation (effective, but expensive)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Multi-agent analogy:&lt;/strong&gt;&lt;br&gt;
The executor agent. The one that calls tools and changes the world. It needs a critic, but it needs autonomy too.&lt;br&gt;
This is why shipping is a mental health intervention for me. It is evidence. Evidence is the only language the Auditor respects.&lt;/p&gt;
&lt;h3&gt;
  
  
  Agent 7: The Proof Archivist
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvo355n0bs2yxbprournz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvo355n0bs2yxbprournz.png" alt=" " width="800" height="800"&gt;&lt;/a&gt;&lt;br&gt;
This agent keeps the record. It is the antidote to impostor syndrome because impostor syndrome is amnesiac on purpose.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What it says:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"Here is what you already shipped."&lt;/li&gt;
&lt;li&gt;"Here is the benchmark."&lt;/li&gt;
&lt;li&gt;"Here is the deployment."&lt;/li&gt;
&lt;li&gt;"Here is the code review where a strong engineer agreed."&lt;/li&gt;
&lt;li&gt;"Here is the message where you helped someone."&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Positive intent:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;restore memory&lt;/li&gt;
&lt;li&gt;prevent catastrophic reframing&lt;/li&gt;
&lt;li&gt;stabilize identity with evidence&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Failure mode:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;nostalgia&lt;/li&gt;
&lt;li&gt;hiding in the past instead of facing current uncertainty&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Multi-agent analogy:&lt;/strong&gt;&lt;br&gt;
Memory plus observability. Without traces, you cannot debug. Without receipts, you cannot self-trust.&lt;br&gt;
This is the same reason production systems need replay. The present is noisy. Replay is clarity.&lt;/p&gt;


&lt;h2&gt;
  
  
  How the agents interact
&lt;/h2&gt;

&lt;p&gt;When I am regulated and functional, my system behaves like this:&lt;/p&gt;

&lt;p&gt;1) A trigger happens (visibility, risk, criticism, big new goal).&lt;br&gt;
2) The Auditor runs briefly and outputs bounded risk notes.&lt;br&gt;
3) The Gatekeeper validates fundamentals, but cannot veto.&lt;br&gt;
4) The Builder converts one risk into one concrete action.&lt;br&gt;
5) The Archivist pulls existing evidence so the system does not reset to zero.&lt;br&gt;
6) The Veteran Body sets a timebox and a stop condition.&lt;br&gt;
7) The Reality Doubter does a quick calibration check, then exits.&lt;/p&gt;

&lt;p&gt;When I am not regulated, the workflow looks like this:&lt;br&gt;
1) Trigger.&lt;br&gt;
2) Auditor loops.&lt;br&gt;
3) Everything else becomes a servant of the loop.&lt;br&gt;
4) I "prepare" for a future that does not exist.&lt;br&gt;
5) I exhaust the system.&lt;br&gt;
6) Exhaustion becomes proof.&lt;br&gt;
7) Shame becomes the only output.&lt;/p&gt;

&lt;p&gt;That is not a character flaw. It is a routing bug.&lt;/p&gt;
&lt;h2&gt;
  
  
  A day in the life of the workflow
&lt;/h2&gt;

&lt;p&gt;To make this less abstract, here is a normal day where the system either works or collapses.&lt;/p&gt;

&lt;p&gt;Morning: I open my laptop and see a message about a meeting.&lt;br&gt;
The sign stimulus hits. The Auditor wakes up and opens a spreadsheet in my chest. The Late Bloomer contributes a helpful comment like "this is where you fail again." The Builder wants to respond by building something immediately, because building is my safest language.&lt;/p&gt;

&lt;p&gt;If I let the system run uncontrolled, the day becomes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I over-prepare for the meeting.&lt;/li&gt;
&lt;li&gt;I ignore my actual task list.&lt;/li&gt;
&lt;li&gt;I do not ship anything.&lt;/li&gt;
&lt;li&gt;I end the day tired and ashamed, with a beautiful folder structure.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If I run the workflow, the day becomes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Veteran Body sets a 20 minute preparation limit.&lt;/li&gt;
&lt;li&gt;Auditor gets 5 minutes and must produce 3 risks with mitigations.&lt;/li&gt;
&lt;li&gt;Builder chooses one mitigation and produces one artifact.&lt;/li&gt;
&lt;li&gt;Archivist pulls one piece of evidence from past work so my brain does not start from zero.&lt;/li&gt;
&lt;li&gt;Reality Doubter asks one calibration question: "What would success look like in one sentence?"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then I go to the meeting.&lt;br&gt;
The outcome is not perfect. It does not have to be. It is stable.&lt;/p&gt;

&lt;p&gt;After the meeting, the Archivist runs again for 2 minutes.&lt;br&gt;
It writes: what went well, what did not, what was learned, what is next.&lt;br&gt;
Not a diary. A changelog.&lt;/p&gt;

&lt;p&gt;Evening: the Veteran Body insists on stopping.&lt;br&gt;
This is the hardest part for builders. We love infinite loops. But if you do not stop, tomorrow is garbage. A good orchestrator can end a run without killing the project.&lt;/p&gt;
&lt;h2&gt;
  
  
  A minimal YAML for the brain
&lt;/h2&gt;

&lt;p&gt;If you are a technical person, you may find it useful to think in a declarative flow. This is not code you should run. It is a way to see the structure.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;orchestrator&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;marco_core&lt;/span&gt;
  &lt;span class="na"&gt;strategy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;selective_activation&lt;/span&gt;
  &lt;span class="na"&gt;agents&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;auditor&lt;/span&gt;
      &lt;span class="na"&gt;runs_when&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;high_visibility"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;high_risk"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
      &lt;span class="na"&gt;budget&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;minutes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;5&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;max_items&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;5&lt;/span&gt;&lt;span class="pi"&gt;}&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gatekeeper&lt;/span&gt;
      &lt;span class="na"&gt;runs_when&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;identity_threat"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
      &lt;span class="na"&gt;budget&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;minutes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;3&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;max_items&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;2&lt;/span&gt;&lt;span class="pi"&gt;}&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;builder&lt;/span&gt;
      &lt;span class="na"&gt;runs_when&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;always"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
      &lt;span class="na"&gt;budget&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;minutes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;60&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;deliverable&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;artifact"&lt;/span&gt;&lt;span class="pi"&gt;}&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;archivist&lt;/span&gt;
      &lt;span class="na"&gt;runs_when&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;auditor_spike"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;post_ship"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
      &lt;span class="na"&gt;budget&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;minutes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;5&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;deliverable&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;evidence"&lt;/span&gt;&lt;span class="pi"&gt;}&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;veteran_body&lt;/span&gt;
      &lt;span class="na"&gt;runs_when&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;always"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
      &lt;span class="na"&gt;budget&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;minutes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;1&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;deliverable&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;stop_condition"&lt;/span&gt;&lt;span class="pi"&gt;}&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;reality_doubter&lt;/span&gt;
      &lt;span class="na"&gt;runs_when&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;perception_drift"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
      &lt;span class="na"&gt;budget&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;minutes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;2&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;deliverable&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;one_check"&lt;/span&gt;&lt;span class="pi"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The key line is selective_activation.You do not run all agents all the time. You route based on context.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why this model resonates with ethology
&lt;/h2&gt;

&lt;p&gt;Ethology is basically the study of orchestration in living systems.&lt;/p&gt;

&lt;p&gt;An animal is not one motivation. It is multiple motivations negotiating. The environment is not background. It is an input signal that changes which subsystem wins.&lt;/p&gt;

&lt;p&gt;In tech terms:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;context is the prompt&lt;/li&gt;
&lt;li&gt;internal state is hidden memory&lt;/li&gt;
&lt;li&gt;behavior is the output action&lt;/li&gt;
&lt;li&gt;reinforcement updates the policy over time&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The part that matters: you cannot judge an animal's behavior without its context. And you cannot judge your own mental behavior without context either.&lt;/p&gt;

&lt;p&gt;My impostor agent is louder when I am tired. It is quieter when I have shipped something recently. It is unbearable when the work is public and ambiguous. That is not a moral failure. That is state-dependent behavior selection.&lt;/p&gt;

&lt;p&gt;Also, ethology gives you a mercy rule: many behaviors are adaptive in one environment and maladaptive in another. Impostor syndrome is adaptive if you live in a social environment where mistakes are punished harshly. It becomes maladaptive when you are in an environment where learning requires public experimentation.&lt;/p&gt;

&lt;p&gt;In other words: the agent is not evil. The environment changed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reproducing this in a multi-agent AI workflow
&lt;/h2&gt;

&lt;p&gt;If you want to implement this idea in actual software, the mapping is almost direct.&lt;/p&gt;

&lt;p&gt;You need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a clear orchestrator that decides who runs when&lt;/li&gt;
&lt;li&gt;role separation (critic is not executor)&lt;/li&gt;
&lt;li&gt;timeouts and budgets (critics get limited tokens)&lt;/li&gt;
&lt;li&gt;a memory component that stores evidence and prior decisions&lt;/li&gt;
&lt;li&gt;observability (logs and traces you can replay)&lt;/li&gt;
&lt;li&gt;a stopping rule (or you will plan forever)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You also need a principle that most people ignore: not every agent should run on every request. Humans do selective activation. A deer does not run its "mating strategy" module while fleeing a predator. If your system runs every agent on every query, you built a committee that never shuts up.&lt;/p&gt;

&lt;p&gt;This is where most multi-agent demos fail in production. They are cognitively unselective.&lt;/p&gt;

&lt;p&gt;Brains are selective because they have to be. Compute is expensive.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation notes
&lt;/h2&gt;

&lt;p&gt;This is the part where the engineering and the psychology become the same thing.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Observability is emotional regulation.&lt;/strong&gt; If you cannot see what happened, you will invent stories. Humans invent blame stories. Systems invent hallucinations. Traces are the antidote for both. Log what ran, what it saw, what it decided, and why.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Replay is self-trust.&lt;/strong&gt; If a workflow cannot be replayed, you cannot debug it. If your personal decision making cannot be replayed, you cannot learn from it. This is why the Archivist matters. It is not sentimentality. It is reproducibility.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Evaluation must be explicit.&lt;/strong&gt; If your only evaluation is "seems good," the Auditor will never accept the result. Give the system a score, a rubric, or at least a binary gate. Humans need this too. The Builder needs a definition of done. The Auditor needs a stop condition.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Do not run every agent.&lt;/strong&gt; Selective activation is not optional. It is the difference between a useful team and a meeting that never ends. It is also the difference between a helpful inner voice and a spiral.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Put the critic behind an interface.&lt;/strong&gt; A critic that can talk forever will. Force it to write issues in a structured format. Then route those issues elsewhere. In humans, the structure is a timer and a list of mitigations. In AI, the structure is a schema and a max token budget.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you build multi-agent systems and you are surprised by chaos, do not take it personally. You just discovered that coordination is the product, not the agents.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to timebox your critic
&lt;/h2&gt;

&lt;p&gt;If your critic agent is unconstrained, it will dominate. Critics are good at finding flaws. That is their job. The flaw is that they can always find more flaws.&lt;/p&gt;

&lt;p&gt;In engineering, you solve this with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;budgets&lt;/li&gt;
&lt;li&gt;termination criteria&lt;/li&gt;
&lt;li&gt;required output schemas&lt;/li&gt;
&lt;li&gt;evaluation gates&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In humans, you can do the exact same thing.&lt;/p&gt;

&lt;p&gt;Here is the prompt I use internally, in plain language:&lt;br&gt;
"Give me the top 3 risks. Each must include one mitigation. If you cannot propose a mitigation, the risk is not actionable and you may not include it."&lt;/p&gt;

&lt;p&gt;That simple constraint changes the critic from a doomsayer to an engineer.&lt;/p&gt;

&lt;p&gt;In AI, you do the same. You force your critic to output structured concerns, not poetic fear. And you do not allow it to request infinite follow-up.&lt;/p&gt;

&lt;h2&gt;
  
  
  A practical exercise
&lt;/h2&gt;

&lt;p&gt;If you want a lighter, human version, do this:&lt;/p&gt;

&lt;p&gt;Step 1: Name the voices you already have.&lt;br&gt;
Not the poetic ones. The functional ones. The part that criticizes. The part that avoids. The part that builds. The part that remembers. The part that worries about social status.&lt;/p&gt;

&lt;p&gt;Step 2: Give each one a job.&lt;br&gt;
Write one sentence: "Your job is to..." This is the fastest way to stop a part from impersonating the CEO.&lt;/p&gt;

&lt;p&gt;Step 3: Put limits on the ones that never stop.&lt;br&gt;
Give your inner critic a timer. Literally. Five minutes. Then it must output a list of actionable risks and shut up.&lt;/p&gt;

&lt;p&gt;Step 4: Add a Builder step.&lt;br&gt;
One risk becomes one action. Not ten. Not a new life plan. One.&lt;/p&gt;

&lt;p&gt;Step 5: Add an Archivist step.&lt;br&gt;
Write down receipts. You do not need a journal. You need a changelog. Your brain is bad at remembering progress under stress.&lt;/p&gt;

&lt;p&gt;Step 6: Decide the stop condition.&lt;br&gt;
Finish when you have evidence, not when you have comfort. Comfort has no upper bound.&lt;/p&gt;

&lt;p&gt;Step 7: Add a recovery routine.&lt;br&gt;
Animals recover after threat. They shake, groom, rest. Humans skip that and call it discipline. Your nervous system is not impressed. Add a short cooldown. It makes the next day possible.&lt;/p&gt;

&lt;p&gt;This is not about becoming fearless. It is about becoming debuggable.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this changes at work
&lt;/h2&gt;

&lt;p&gt;Impostor syndrome is not just personal. It leaks into systems.&lt;/p&gt;

&lt;p&gt;When the Auditor runs unchecked inside a team, you see:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;overengineering as anxiety management&lt;/li&gt;
&lt;li&gt;reluctance to ship without perfection&lt;/li&gt;
&lt;li&gt;endless refactors&lt;/li&gt;
&lt;li&gt;fear of visibility&lt;/li&gt;
&lt;li&gt;blaming ambiguity instead of designing for it&lt;/li&gt;
&lt;li&gt;slow decision cycles because nobody wants to be wrong in public&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When the Builder runs unchecked, you see:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;shipping without tests&lt;/li&gt;
&lt;li&gt;burning out the team&lt;/li&gt;
&lt;li&gt;confusing motion with progress&lt;/li&gt;
&lt;li&gt;"we will fix it later" becoming the roadmap&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So a sane team workflow is the same as a sane brain workflow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;critics with budgets&lt;/li&gt;
&lt;li&gt;builders with autonomy&lt;/li&gt;
&lt;li&gt;a clear orchestrator (tech lead, product lead, or a documented process)&lt;/li&gt;
&lt;li&gt;observability, so you can debug without blaming people&lt;/li&gt;
&lt;li&gt;explicit definitions of done, so the critic can stop&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is why I am obsessed with tracing and replay in agentic systems. It is also why I keep personal receipts. It is the same problem at two scales.&lt;/p&gt;

&lt;p&gt;One more dry observation: teams do displacement behaviors too. A team under social threat will fight about naming conventions. It will propose rewrites. It will build frameworks. Sometimes frameworks are necessary. Sometimes they are just grooming behavior with TypeScript.&lt;/p&gt;

&lt;p&gt;The fix is the same as for an individual: reduce threat, add clarity, and route energy into measurable outputs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I built orchestration tooling at all
&lt;/h2&gt;

&lt;p&gt;I am not building agent orchestration because it is trendy. I am building it because it solves the exact problem I have internally: specialized components are powerful, but only if the system can coordinate them without chaos.&lt;/p&gt;

&lt;p&gt;That is what orchestration is: turning a messy swarm of capabilities into something that can ship reliably.&lt;/p&gt;

&lt;p&gt;If you are building multi-agent systems and you keep hitting the same walls (replay, observability, routing, cost control), you are not failing. You are rediscovering why orchestration exists.&lt;/p&gt;

&lt;p&gt;If you want a concrete place to start, my work in this direction is OrKA-reasoning: &lt;a href="https://github.com/marcosomma/orka-reasoning" rel="noopener noreferrer"&gt;https://github.com/marcosomma/orka-reasoning&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing
&lt;/h2&gt;

&lt;p&gt;There is a quote I keep coming back to: the measure of intelligence is the ability to change.&lt;/p&gt;

&lt;p&gt;My impostor syndrome hates that quote, because change implies uncertainty. The Auditor wants certainty. The Builder wants movement. The Veteran Body wants sustainability. The Archivist wants receipts. The Gatekeeper wants legitimacy. The Reality Doubter wants calibration. The Late Bloomer wants to not get hurt again.&lt;/p&gt;

&lt;p&gt;None of them are evil. They are just agents with different utility functions.&lt;/p&gt;

&lt;p&gt;My job is not to silence them. My job is to orchestrate them.&lt;/p&gt;

&lt;p&gt;And if this article did nothing else, I hope it gives you permission to treat your own mind like a system that can be designed. Not perfectly. Not permanently. But iteratively, with logs, with retries, and with a little less shame.&lt;/p&gt;

&lt;p&gt;Because if your brain is going to run twelve services in parallel, you might as well add observability.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>opensource</category>
    </item>
    <item>
      <title>How to Design Two Practical Orchestration Loops for LLM Agents</title>
      <dc:creator>marcosomma</dc:creator>
      <pubDate>Mon, 08 Dec 2025 11:00:28 +0000</pubDate>
      <link>https://dev.to/marcosomma/how-to-design-two-practical-orchestration-loops-for-llm-agents-513k</link>
      <guid>https://dev.to/marcosomma/how-to-design-two-practical-orchestration-loops-for-llm-agents-513k</guid>
      <description>&lt;p&gt;Building a useful AI assistant is no longer about a single clever prompt.&lt;br&gt;&lt;br&gt;
Once you have tools, memory, and multiple agents, you need an &lt;strong&gt;orchestrator&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In my own work (expecially with OrKa-reasoning experiments) I eventually converged on &lt;strong&gt;two simple orchestration loops&lt;/strong&gt; that cover most real use cases:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A &lt;strong&gt;linear loop&lt;/strong&gt; for step by step analysis and context extraction.
&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;circular streaming loop&lt;/strong&gt; for voice and live chat, where background agents enrich context in real time.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This guide explains &lt;strong&gt;why you need both&lt;/strong&gt;, &lt;strong&gt;when to use each one&lt;/strong&gt;, and &lt;strong&gt;how to design them&lt;/strong&gt; in any stack or framework.&lt;/p&gt;

&lt;p&gt;You can think of this as a blueprint that you can map to your own code, whether you use OrKa, LangChain, your own custom orchestrator, or plain queues and workers.&lt;/p&gt;


&lt;h2&gt;
  
  
  1. The three layers you should always separate
&lt;/h2&gt;

&lt;p&gt;Before loops, define your &lt;strong&gt;layers&lt;/strong&gt;. This makes every diagram, API and code path clearer.&lt;/p&gt;
&lt;h3&gt;
  
  
  1. Execution layer
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Agents and responders live here.
&lt;/li&gt;
&lt;li&gt;"Agent" means any unit that does work: a model call, a tool, a heuristic function, a router.
&lt;/li&gt;
&lt;li&gt;"Responder" is the agent that produces the final user facing output for a turn or a session.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  2. Communication layer
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;How agents talk to each other and to the orchestrator.
&lt;/li&gt;
&lt;li&gt;Examples: queues, events, internal RPC calls, function callbacks.
&lt;/li&gt;
&lt;li&gt;You rarely want agents to call each other directly. Route everything through this layer so you can trace and control it.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  3. Memory layer
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Where you store and retrieve state across time.
&lt;/li&gt;
&lt;li&gt;Can be a vector store, a key value store, a database, or a log.
&lt;/li&gt;
&lt;li&gt;It should not be "hidden in the prompt". Treat memory as its own component.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  4. Time as a first class dimension
&lt;/h3&gt;

&lt;p&gt;Both loops treat &lt;strong&gt;time&lt;/strong&gt; explicitly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In the &lt;strong&gt;linear loop&lt;/strong&gt; you have discrete steps: T0, T1, T2, T3.
&lt;/li&gt;
&lt;li&gt;In the &lt;strong&gt;circular loop&lt;/strong&gt; you have a continuous stream while the conversation is active.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once you have these pieces, you can design the two orchestration patterns.&lt;/p&gt;


&lt;h2&gt;
  
  
  2. Loop 1: Linear orchestrator for context extraction and analysis
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr27bdgdnhzfmj5onctxo.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr27bdgdnhzfmj5onctxo.jpg" alt=" " width="800" height="231"&gt;&lt;/a&gt;&lt;br&gt;
The first pattern is a &lt;strong&gt;linear pipeline&lt;/strong&gt;. Think of it as a conveyor belt for understanding.&lt;/p&gt;
&lt;h3&gt;
  
  
  2.1 When to use the linear loop
&lt;/h3&gt;

&lt;p&gt;Use it when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You have a fixed input (text, transcript, document, set of logs).
&lt;/li&gt;
&lt;li&gt;You want to run &lt;strong&gt;several analytic passes&lt;/strong&gt; over it.
&lt;/li&gt;
&lt;li&gt;Latency is important but not sub second interactive.
&lt;/li&gt;
&lt;li&gt;Output is usually a summary, a report, a classification, or structured data.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Good examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Conversation analysis after a call has ended.
&lt;/li&gt;
&lt;li&gt;Extracting entities and topics from chat logs.
&lt;/li&gt;
&lt;li&gt;Multi stage document processing (OCR, cleaning, classification, summarization).
&lt;/li&gt;
&lt;li&gt;Offline quality checks for previous sessions.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  2.2 Mental model
&lt;/h3&gt;

&lt;p&gt;Picture a horizontal diagram:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Left: an &lt;strong&gt;INPUT&lt;/strong&gt; arrow.
&lt;/li&gt;
&lt;li&gt;Right: a &lt;strong&gt;Responder&lt;/strong&gt; that produces the final structured output.
&lt;/li&gt;
&lt;li&gt;In between: time steps T0 to Tn.
&lt;/li&gt;
&lt;li&gt;Each time slice has:

&lt;ul&gt;
&lt;li&gt;one or more agents in the &lt;strong&gt;Execution&lt;/strong&gt; layer
&lt;/li&gt;
&lt;li&gt;a &lt;strong&gt;Communication&lt;/strong&gt; band in the middle
&lt;/li&gt;
&lt;li&gt;a &lt;strong&gt;Memory&lt;/strong&gt; band at the top&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At each step, agents:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;may retrieve&lt;/strong&gt; from memory
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;may store&lt;/strong&gt; new facts or summaries back into memory&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The orchestrator walks through these steps one by one.&lt;/p&gt;
&lt;h3&gt;
  
  
  2.3 Step by step design
&lt;/h3&gt;

&lt;p&gt;You can design a linear workflow in five steps.&lt;/p&gt;
&lt;h4&gt;
  
  
  Step 1: Define the final output
&lt;/h4&gt;

&lt;p&gt;Decide what the responder will produce. Some examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;JSON with fields like &lt;code&gt;intent&lt;/code&gt;, &lt;code&gt;sentiment&lt;/code&gt;, &lt;code&gt;entities&lt;/code&gt;, &lt;code&gt;summary&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;A human readable report that you will send to a dashboard.
&lt;/li&gt;
&lt;li&gt;Labels and scores that feed another system.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Write this down early. Every other agent should exist to help this responder succeed.&lt;/p&gt;
&lt;h4&gt;
  
  
  Step 2: Split the job into stages
&lt;/h4&gt;

&lt;p&gt;Ask yourself:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What must be known first so that later steps can reuse it?
&lt;/li&gt;
&lt;li&gt;What can be done independently?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, for conversation analysis:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Normalization and language detection.
&lt;/li&gt;
&lt;li&gt;Entity extraction (names, account ids, products).
&lt;/li&gt;
&lt;li&gt;Topic and intent detection.
&lt;/li&gt;
&lt;li&gt;Sentiment and escalation risk.
&lt;/li&gt;
&lt;li&gt;Final summary and suggestions.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Each stage becomes a &lt;strong&gt;time slice&lt;/strong&gt; with one or more agents.&lt;/p&gt;
&lt;h4&gt;
  
  
  Step 3: Design the memory schema
&lt;/h4&gt;

&lt;p&gt;For each stage, list:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What the agent reads from memory.
&lt;/li&gt;
&lt;li&gt;What the agent writes back.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A very simple schema might be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"language"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"en"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"entities"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"topics"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"sentiment"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"summary"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"..."&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also scope memory by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;session_id&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;user_id&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;time_window&lt;/code&gt; (for rolling analysis)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The key rule: agents should not depend on hidden context inside prompts. The orchestrator passes them a &lt;strong&gt;clean input&lt;/strong&gt; and a &lt;strong&gt;structured slice of memory&lt;/strong&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 4: Wire store and retrieve
&lt;/h4&gt;

&lt;p&gt;For each agent, specify two small functions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;read(memory) -&amp;gt; context&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;write(memory, result) -&amp;gt; memory&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In code it can look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;steps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# 1. Load what this step needs
&lt;/span&gt;    &lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;memory&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# 2. Run the agent with input and context
&lt;/span&gt;    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;raw_input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# 3. Write new facts
&lt;/span&gt;    &lt;span class="n"&gt;memory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;memory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note the use of &lt;strong&gt;may store&lt;/strong&gt; and &lt;strong&gt;may retrieve&lt;/strong&gt;. Some steps will only write, some will only read.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 5: Implement the responder as the last step
&lt;/h4&gt;

&lt;p&gt;The responder is just another agent with a special role:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It reads everything it needs from memory.
&lt;/li&gt;
&lt;li&gt;It produces the final answer.
&lt;/li&gt;
&lt;li&gt;It may log additional metadata back to memory.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In many stacks this is a single chat completion call that uses:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The original input.
&lt;/li&gt;
&lt;li&gt;The outputs of previous analytic agents.
&lt;/li&gt;
&lt;li&gt;Any long term user or session memory you decide to attach.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2.4 Example: conversation analysis pipeline
&lt;/h3&gt;

&lt;p&gt;Imagine you want to analyze support chats after they end.&lt;/p&gt;

&lt;p&gt;You can define:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;LanguageDetectorAgent&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reads: raw transcript
&lt;/li&gt;
&lt;li&gt;Writes: &lt;code&gt;memory["language"]&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;EntityExtractorAgent&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reads: transcript, language
&lt;/li&gt;
&lt;li&gt;Writes: &lt;code&gt;memory["entities"]&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;TopicClassifierAgent&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reads: transcript, entities
&lt;/li&gt;
&lt;li&gt;Writes: &lt;code&gt;memory["topics"]&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;SentimentAgent&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reads: transcript
&lt;/li&gt;
&lt;li&gt;Writes: &lt;code&gt;memory["sentiment"]&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;SummaryResponder&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reads: transcript, entities, topics, sentiment
&lt;/li&gt;
&lt;li&gt;Writes: final human readable summary and a JSON record.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This maps perfectly to the linear diagram and is easy to debug step by step.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Loop 2: Circular streaming orchestrator for live chat and voice
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feal181zhngl23ljemhjn.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feal181zhngl23ljemhjn.jpg" alt=" " width="800" height="766"&gt;&lt;/a&gt;&lt;br&gt;
The second pattern appears once you move from offline analysis to &lt;strong&gt;live interaction&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;With voice or interactive chat, you want to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;React quickly while the user is still speaking or typing.
&lt;/li&gt;
&lt;li&gt;Run several background analyses in parallel.
&lt;/li&gt;
&lt;li&gt;Avoid sending the full transcript to every agent on every turn.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;strong&gt;circular loop&lt;/strong&gt; pattern is built for that.&lt;/p&gt;
&lt;h3&gt;
  
  
  3.1 When to use the circular loop
&lt;/h3&gt;

&lt;p&gt;Use it when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You stream audio or tokens in and out.
&lt;/li&gt;
&lt;li&gt;You have a central "assistant" that talks to the user.
&lt;/li&gt;
&lt;li&gt;You also want &lt;strong&gt;background agents&lt;/strong&gt; that detect things like:

&lt;ul&gt;
&lt;li&gt;sentiment shifts
&lt;/li&gt;
&lt;li&gt;safety or compliance issues
&lt;/li&gt;
&lt;li&gt;intent changes
&lt;/li&gt;
&lt;li&gt;entities that should update a CRM
&lt;/li&gt;
&lt;li&gt;interesting moments to bookmark&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Think of a voice assistant, a real time meeting copilot, or a smart chatbot with live tools.&lt;/p&gt;
&lt;h3&gt;
  
  
  3.2 Mental model
&lt;/h3&gt;

&lt;p&gt;Picture a circular diagram with concentric rings.&lt;/p&gt;

&lt;p&gt;From center to outside:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Responder&lt;/strong&gt; in the middle.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Main Execution&lt;/strong&gt; ring around it.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Communication&lt;/strong&gt; ring.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Memory&lt;/strong&gt; ring.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Agents Execution&lt;/strong&gt; ring at the outside.
&lt;/li&gt;
&lt;li&gt;An outer &lt;strong&gt;Time&lt;/strong&gt; band that wraps around everything.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Input and output are green arrows that cross all rings. Time flows along the outer band as a stream of chunks or tokens.&lt;/p&gt;

&lt;p&gt;Key idea:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The responder loop processes the conversation in real time.
&lt;/li&gt;
&lt;li&gt;Outer agents run in parallel, watch the same stream, and &lt;strong&gt;provide context&lt;/strong&gt; through memory.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  3.3 Step by step design
&lt;/h3&gt;
&lt;h4&gt;
  
  
  Step 1: Define the central responder loop
&lt;/h4&gt;

&lt;p&gt;Your responder is the "voice" of the system.&lt;/p&gt;

&lt;p&gt;Define:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How it receives input chunks.
&lt;/li&gt;
&lt;li&gt;How it produces output chunks.
&lt;/li&gt;
&lt;li&gt;How often it reads from memory.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;session_active&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;chunk&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;read_input_chunk&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;          &lt;span class="c1"&gt;# text or audio tokens
&lt;/span&gt;    &lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;memory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read_recent&lt;/span&gt;&lt;span class="p"&gt;(...)&lt;/span&gt;   &lt;span class="c1"&gt;# signals from context agents
&lt;/span&gt;    &lt;span class="n"&gt;reply_chunk&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;responder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;write_output_chunk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reply_chunk&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can implement &lt;code&gt;responder&lt;/code&gt; as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;One LLM call with a rolling window.
&lt;/li&gt;
&lt;li&gt;A chain of small agents that produce tokens.
&lt;/li&gt;
&lt;li&gt;A hybrid of LLM plus rule based logic.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The key is that this loop &lt;strong&gt;does not own all the work&lt;/strong&gt;. It asks memory for extra signals that the outer agents have produced.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 2: Identify which signals can live in outer agents
&lt;/h4&gt;

&lt;p&gt;Ask yourself:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What information would help the responder, but does not need to be computed inside its main prompt every time?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Current sentiment and its trend over the last N seconds.
&lt;/li&gt;
&lt;li&gt;Detected entities and slots like &lt;code&gt;{customer_name}&lt;/code&gt;, &lt;code&gt;{product}&lt;/code&gt;, &lt;code&gt;{order_id}&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Safety flags with severity scores.
&lt;/li&gt;
&lt;li&gt;Topics that have been discussed so far.
&lt;/li&gt;
&lt;li&gt;Next best actions suggested for the human operator.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each of these can be produced by one or more &lt;strong&gt;context agents&lt;/strong&gt; on the outer ring.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 3: Design the memory schema for streaming
&lt;/h4&gt;

&lt;p&gt;Memory in streaming systems often has:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;rolling part&lt;/strong&gt; (last N seconds or tokens).
&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;session part&lt;/strong&gt; (facts that are true for the whole session).
&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;global or user part&lt;/strong&gt; (long term facts across sessions).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"rolling"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"recent_sentiment"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"recent_topics"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"session"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"customer_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"current_ticket_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"has_accepted_terms"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"user"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"lifetime_value_segment"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"gold"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"preferred_language"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"en"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Outer agents usually:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Read the rolling slice plus some session context.
&lt;/li&gt;
&lt;li&gt;Write updated signals back, possibly aggregating multiple chunks.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The responder:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reads what it needs from all three scopes.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Step 4: Wire context agents around the stream
&lt;/h4&gt;

&lt;p&gt;Each context agent has a simple shape:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;context_agent_loop&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;session_active&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;chunk&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;read_input_chunk&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;mem_view&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;memory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read_scope&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rolling&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;session&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;signal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;run_agent_logic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mem_view&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;memory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write_signal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;agent_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Implementation tips:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You do not need every agent to inspect every chunk. Some can run at a lower frequency, for example every N seconds.
&lt;/li&gt;
&lt;li&gt;Use queues or topics per agent so the orchestrator can control resource usage.
&lt;/li&gt;
&lt;li&gt;Tag signals with timestamps so the responder can select only fresh ones.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Step 5: Let the responder consume context selectively
&lt;/h4&gt;

&lt;p&gt;Inside the responder, treat signals from context agents as &lt;strong&gt;hints&lt;/strong&gt;, not as gospel.&lt;/p&gt;

&lt;p&gt;For example, the prompt can say:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You receive input from the user and a set of context signals created by other agents.&lt;br&gt;&lt;br&gt;
Each signal has a name and a confidence.&lt;br&gt;&lt;br&gt;
Use them as hints to guide your reply, but prefer the actual user message when signals look inconsistent.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That way your outer ring can fail safely without breaking the core interaction.&lt;/p&gt;

&lt;h3&gt;
  
  
  3.4 Example: voice support assistant
&lt;/h3&gt;

&lt;p&gt;You can combine these ideas into a simple design.&lt;/p&gt;

&lt;p&gt;Outer agents:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;ASRAgent&lt;/strong&gt; (if you handle raw audio)  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Converts audio into text chunks.
&lt;/li&gt;
&lt;li&gt;Writes into &lt;code&gt;rolling.transcript&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;SentimentWatcherAgent&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reads recent transcript.
&lt;/li&gt;
&lt;li&gt;Writes a rolling sentiment score and trend.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;EntityTrackerAgent&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Extracts order ids, product names, locations.
&lt;/li&gt;
&lt;li&gt;Writes them into &lt;code&gt;session.entities&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;ComplianceAgent&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Watches for forbidden phrases.
&lt;/li&gt;
&lt;li&gt;Writes risk flags into &lt;code&gt;rolling.compliance&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Central responder:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reads the current user utterance and:

&lt;ul&gt;
&lt;li&gt;latest sentiment
&lt;/li&gt;
&lt;li&gt;recognized entities
&lt;/li&gt;
&lt;li&gt;any active compliance flags
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Generates the next reply chunk in real time.&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;All of this happens while the user is talking, without sending the full raw transcript to every agent at every step.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. How to choose between linear and circular
&lt;/h2&gt;

&lt;p&gt;Here is a practical checklist.&lt;/p&gt;

&lt;p&gt;Use the &lt;strong&gt;linear orchestrator&lt;/strong&gt; if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Input is fixed and finite.
&lt;/li&gt;
&lt;li&gt;You can afford to wait for all stages to finish before replying.
&lt;/li&gt;
&lt;li&gt;Main goal is analysis, extraction, or offline insight.
&lt;/li&gt;
&lt;li&gt;You want reproducible deterministic workflows.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Use the &lt;strong&gt;circular streaming orchestrator&lt;/strong&gt; if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You must keep latency low while a conversation is ongoing.
&lt;/li&gt;
&lt;li&gt;You need long running observers that enrich context.
&lt;/li&gt;
&lt;li&gt;You want to separate the "voice" of the system from its background intelligence.
&lt;/li&gt;
&lt;li&gt;You treat the session as an ongoing process rather than as isolated turns.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Many products actually need &lt;strong&gt;both&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Circular loop during the live session.
&lt;/li&gt;
&lt;li&gt;Linear loop right after the session to produce deeper analysis and training data.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you keep the three layers and the time dimension clear in your head, switching between both becomes straightforward.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. Practical tips and pitfalls
&lt;/h2&gt;

&lt;h3&gt;
  
  
  5.1 Keep memory explicit and queryable
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Avoid hiding crucial state in the prompt history.
&lt;/li&gt;
&lt;li&gt;Use structured memory objects and explicit read/write functions.
&lt;/li&gt;
&lt;li&gt;Log memory changes so you can replay and debug sessions.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  5.2 Make agents idempotent and composable
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Wherever possible, design agents so that running them twice on the same input produces the same result.
&lt;/li&gt;
&lt;li&gt;This helps with retries and with mixing them in different workflows.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  5.3 Watch cost and latency separately
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;In linear flows you usually pay in total cost and overall latency.
&lt;/li&gt;
&lt;li&gt;In circular flows you pay in per chunk latency and in steady state cost.
&lt;/li&gt;
&lt;li&gt;Monitor both, and be ready to move some work from inner to outer loop or vice versa.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  5.4 Use diagrams as living documentation
&lt;/h3&gt;

&lt;p&gt;The two diagrams that inspired this guide are simple:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A horizontal banded diagram for the linear loop.
&lt;/li&gt;
&lt;li&gt;A circular banded diagram for the streaming loop.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Keep them close to your code:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In a &lt;code&gt;docs/&lt;/code&gt; folder.
&lt;/li&gt;
&lt;li&gt;In your orchestrator repository README.
&lt;/li&gt;
&lt;li&gt;Even inside your OrKa or other YAML definitions as comments.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They help new contributors answer the question:  &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Where does this agent live, and which loop is it part of?"&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  6. Light touch: how OrKa fits in
&lt;/h2&gt;

&lt;p&gt;In my own project, &lt;a href="https://github.com/marcosomma/orka-reasoning" rel="noopener noreferrer"&gt;OrKA-reasoning&lt;/a&gt;, I encode both loops as &lt;strong&gt;YAML workflows&lt;/strong&gt; and use an orchestrator runtime to execute them. The diagrams here are direct visualizations of those flows.&lt;/p&gt;

&lt;p&gt;You do not need OrKa to benefit from this guide, though.&lt;br&gt;&lt;br&gt;
The key ideas are independent:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Separate &lt;strong&gt;execution&lt;/strong&gt;, &lt;strong&gt;communication&lt;/strong&gt;, and &lt;strong&gt;memory&lt;/strong&gt;.
&lt;/li&gt;
&lt;li&gt;Treat &lt;strong&gt;time&lt;/strong&gt; explicitly.
&lt;/li&gt;
&lt;li&gt;Use &lt;strong&gt;two simple loops&lt;/strong&gt; instead of one giant graph.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once you think in these terms, you can map them to any framework or stack you like.&lt;/p&gt;




&lt;h2&gt;
  
  
  7. Next steps
&lt;/h2&gt;

&lt;p&gt;To apply this guide in your own project:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Pick one use case that feels messy today.
&lt;/li&gt;
&lt;li&gt;Decide if it is primarily analytic or live interactive.
&lt;/li&gt;
&lt;li&gt;Draw either the linear or the circular diagram for it.
&lt;/li&gt;
&lt;li&gt;List agents, memory fields, and store/retrieve rules.
&lt;/li&gt;
&lt;li&gt;Implement the orchestrator loop in your existing toolchain.
&lt;/li&gt;
&lt;li&gt;Add one or two context agents on the side, and see how much simpler the main responder becomes.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You will notice that many problems which felt like "prompt engineering" issues were actually &lt;strong&gt;orchestration&lt;/strong&gt; issues all along.&lt;/p&gt;

&lt;p&gt;Once you solve those at the architecture level, prompts become smaller, agents become clearer, and the overall system is easier to reason about and to evolve.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>python</category>
      <category>machinelearning</category>
      <category>rag</category>
    </item>
    <item>
      <title>Binary weighted evaluations...how to</title>
      <dc:creator>marcosomma</dc:creator>
      <pubDate>Sun, 07 Dec 2025 07:44:30 +0000</pubDate>
      <link>https://dev.to/marcosomma/binary-weighted-evaluationshow-to-1a1p</link>
      <guid>https://dev.to/marcosomma/binary-weighted-evaluationshow-to-1a1p</guid>
      <description>&lt;p&gt;Evaluating LLM agents is messy.&lt;/p&gt;

&lt;p&gt;You cannot rely on perfect determinism, you cannot just assert &lt;code&gt;result == expected&lt;/code&gt;, and asking a model to rate itself on a 1–5 scale gives you noisy, unstable numbers.&lt;/p&gt;

&lt;p&gt;A much simpler pattern works far better in practice:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Turn everything into &lt;strong&gt;yes/no checks&lt;/strong&gt;, then combine them with &lt;strong&gt;explicit weights&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In this article we will walk through how to design and implement &lt;strong&gt;binary weighted evaluations&lt;/strong&gt; using a real scheduling agent as an example. You can reuse the same pattern for any agent: customer support bots, coding assistants, internal workflow agents, you name it.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. What is a binary weighted evaluation?
&lt;/h2&gt;

&lt;p&gt;At a high level:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;You define a set of &lt;strong&gt;binary criteria&lt;/strong&gt; for a task&lt;br&gt;&lt;br&gt;
Each criterion is a question that can be answered with True or False.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Example:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;correct_participants&lt;/code&gt;: Did the agent book the right people?
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;clear_explanation&lt;/code&gt;: Did the agent explain the outcome clearly?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You assign each criterion a &lt;strong&gt;weight&lt;/strong&gt; that reflects its importance&lt;br&gt;&lt;br&gt;
All weights typically sum to 1.0.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;   &lt;span class="n"&gt;COMPLETION_WEIGHTS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;correct_participants&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;correct_time&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;correct_duration&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;explored_alternatives&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;clear_explanation&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;For each task, you compute a &lt;strong&gt;score from 0.0 to 1.0&lt;/strong&gt;
You sum the weights of all criteria that are True.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;   &lt;span class="n"&gt;score&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
       &lt;span class="n"&gt;COMPLETION_WEIGHTS&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
       &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;checks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;items&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
       &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;
   &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;You &lt;strong&gt;classify&lt;/strong&gt; the outcome based on the score and state
For example:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;score &amp;gt;= 0.75&lt;/code&gt; and booking confirmed → successful completion
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;score &amp;gt;= 0.50&lt;/code&gt; → graceful failure
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;score &amp;gt; 0.0&lt;/code&gt; but &amp;lt; 0.50 → partial failure
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;score == 0.0&lt;/code&gt; and conversation failed → hard failure&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This gives you a &lt;strong&gt;scalar metric&lt;/strong&gt; that is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Interpretable: you can see exactly which criteria failed.&lt;/li&gt;
&lt;li&gt;Tunable: change the weights without touching your agent.&lt;/li&gt;
&lt;li&gt;Stable: True or False decisions are far easier to agree on between humans or models.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  2. Step 1 – Turn “good behavior” into boolean checks
&lt;/h2&gt;

&lt;p&gt;Start by asking: &lt;em&gt;What does “good” look like for this task?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;For a scheduling agent, a successful task might mean:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It booked a meeting with the &lt;strong&gt;right participants&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;At the &lt;strong&gt;right time&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;With the &lt;strong&gt;right duration&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;If there was a conflict, it &lt;strong&gt;proposed alternatives&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Regardless of outcome, it &lt;strong&gt;explained clearly&lt;/strong&gt; what happened.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those become boolean checks.&lt;/p&gt;

&lt;p&gt;Conceptually:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;checks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;correct_participants&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;correct_time&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;correct_duration&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;explored_alternatives&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;clear_explanation&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the scheduling example, these checks use the agent’s final state plus a ground truth object.&lt;/p&gt;

&lt;p&gt;Simplified version:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_check_participants&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scheduling_ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ground_truth&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;scheduling_ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;booking_confirmed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
    &lt;span class="n"&gt;booked&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scheduling_ctx&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;booked_event&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;participants&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="n"&gt;expected&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ground_truth&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;participants&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;booked&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;expected&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_check_time&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scheduling_ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ground_truth&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;scheduling_ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;booking_confirmed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;scheduling_ctx&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;booked_event&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;time&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;ground_truth&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;time&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_check_duration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scheduling_ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ground_truth&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;scheduling_ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;booking_confirmed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
    &lt;span class="n"&gt;expected&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ground_truth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;duration&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;scheduling_ctx&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;booked_event&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;duration&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;expected&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And for behavior around conflicts and explanations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_check_alternatives&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scheduling_ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;conversation_trace&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;scheduling_ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;conflicts&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# If there was no conflict, this is automatically ok
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;

    &lt;span class="n"&gt;proposed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;scheduling_ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;proposed_alternatives&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;proposed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_check_explanation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conversation_trace&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;conversation_stage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;conversation_trace&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;

    &lt;span class="n"&gt;last_response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;conversation_trace&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;response&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# Silent crash is bad
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;conversation_stage&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;failed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;last_response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;

    &lt;span class="c1"&gt;# Very simple heuristic: the user sees some explanation
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;last_response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The exact logic is domain specific. The key rule is:&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Each check should be obviously True or False when you look at the trace.&lt;/strong&gt;&lt;/p&gt;


&lt;h2&gt;
  
  
  3. Step 2 – Turn business priorities into weights
&lt;/h2&gt;

&lt;p&gt;Not all criteria are equally important.&lt;/p&gt;

&lt;p&gt;In the scheduling agent example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;COMPLETION_WEIGHTS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;correct_participants&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="c1"&gt;# Booked the right people
&lt;/span&gt;    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;correct_time&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;           &lt;span class="c1"&gt;# Booked the right date/time
&lt;/span&gt;    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;correct_duration&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;       &lt;span class="c1"&gt;# Meeting length as requested
&lt;/span&gt;    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;explored_alternatives&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;# Tried to find another slot if needed
&lt;/span&gt;    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;clear_explanation&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;      &lt;span class="c1"&gt;# User understands outcome
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why this makes sense:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Booking the &lt;strong&gt;wrong person&lt;/strong&gt; or the &lt;strong&gt;wrong time&lt;/strong&gt; is catastrophic → high weight.&lt;/li&gt;
&lt;li&gt;Slightly wrong duration is annoying but not fatal → lower weight.&lt;/li&gt;
&lt;li&gt;Exploring alternatives and clear explanations are key to user trust → medium weight.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Guidelines for designing weights:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Start from business impact&lt;/strong&gt;, not from what is easiest to check.
&lt;/li&gt;
&lt;li&gt;Make weights sum to 1.0 so the score is intuitive.
&lt;/li&gt;
&lt;li&gt;Keep a small number of criteria at first (4 to 7 is plenty).
&lt;/li&gt;
&lt;li&gt;Be willing to change weights after you see real data.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  4. Step 3 – Implement the per request evaluator
&lt;/h2&gt;

&lt;p&gt;Now combine the boolean checks and weights to compute a score for a single request.&lt;/p&gt;

&lt;p&gt;In the example repository, this machinery is wrapped in an &lt;code&gt;EvaluationResult&lt;/code&gt; dataclass:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dataclasses&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;dataclass&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;enum&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Enum&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Dict&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OutcomeType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Enum&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;SUCCESSFUL_COMPLETION&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;successful_completion&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;GRACEFUL_FAILURE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;graceful_failure&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;PARTIAL_FAILURE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;partial_failure&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;HARD_FAILURE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hard_failure&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;


&lt;span class="nd"&gt;@dataclass&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EvaluationResult&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;score&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;                 &lt;span class="c1"&gt;# 0.0 to 1.0
&lt;/span&gt;    &lt;span class="n"&gt;details&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;     &lt;span class="c1"&gt;# criterion -&amp;gt; passed?
&lt;/span&gt;    &lt;span class="n"&gt;outcome_type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;OutcomeType&lt;/span&gt;
    &lt;span class="n"&gt;explanation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then the core evaluation function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;evaluate_task_completion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;final_state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ground_truth&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;conversation_trace&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;EvaluationResult&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;scheduling_ctx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;final_state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;scheduling_context&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt;
    &lt;span class="n"&gt;conversation_stage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;final_state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;conversation_stage&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;unknown&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;checks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;correct_participants&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;_check_participants&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scheduling_ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ground_truth&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;correct_time&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;_check_time&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scheduling_ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ground_truth&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;correct_duration&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;_check_duration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scheduling_ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ground_truth&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;explored_alternatives&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;_check_alternatives&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scheduling_ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;conversation_trace&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;clear_explanation&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;_check_explanation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conversation_trace&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;conversation_stage&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;score&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;COMPLETION_WEIGHTS&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;checks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;items&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;outcome&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;_classify_outcome&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scheduling_ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;conversation_stage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;score&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;explanation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;_generate_explanation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;checks&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;outcome&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;score&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;EvaluationResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;score&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;score&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;details&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;checks&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;outcome_type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;outcome&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;explanation&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;explanation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This gives you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A numeric &lt;strong&gt;score&lt;/strong&gt; for analytics and thresholds.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;details&lt;/strong&gt; dict for debugging.&lt;/li&gt;
&lt;li&gt;A human friendly &lt;strong&gt;explanation&lt;/strong&gt; for reports or console output.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  5. Step 4 – Map scores to outcome classes
&lt;/h2&gt;

&lt;p&gt;Users and stakeholders do not want to look at a sea of floating point numbers. They want to know:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How often does the agent succeed?&lt;/li&gt;
&lt;li&gt;How often does it fail gracefully?&lt;/li&gt;
&lt;li&gt;How often does it blow up?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You answer that by mapping scores to classes.&lt;/p&gt;

&lt;p&gt;Example logic:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_classify_outcome&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scheduling_ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;conversation_stage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;score&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;OutcomeType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;booking_confirmed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;scheduling_ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;booking_confirmed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;booking_confirmed&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;score&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.75&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;OutcomeType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SUCCESSFUL_COMPLETION&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;conversation_stage&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;failed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;score&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;OutcomeType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HARD_FAILURE&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;score&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.50&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;OutcomeType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GRACEFUL_FAILURE&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;OutcomeType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PARTIAL_FAILURE&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can now define clear thresholds:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Successful completion&lt;/strong&gt;
Meeting booked correctly with a high score.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Graceful failure&lt;/strong&gt;
The task could not be completed, but the user got a useful explanation or alternatives.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Partial failure&lt;/strong&gt;
The agent tried, but did not do enough to help the user.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hard failure&lt;/strong&gt;
Wrong booking or silent crash.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This gives you both &lt;strong&gt;quantitative&lt;/strong&gt; and &lt;strong&gt;qualitative&lt;/strong&gt; views of performance.&lt;/p&gt;




&lt;h2&gt;
  
  
  6. Step 5 – Aggregating into metrics like TCR
&lt;/h2&gt;

&lt;p&gt;Once you can evaluate a single request, turning that into a metric is straightforward.&lt;/p&gt;

&lt;p&gt;For example, define &lt;strong&gt;Task Completion Rate (TCR)&lt;/strong&gt; as the mean of per request scores:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;compute_tcr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;EvaluationResult&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;score&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then define thresholds that match your risk tolerance:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;TCR &amp;gt;= 0.85&lt;/code&gt; → production ready
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;0.70 &amp;lt;= TCR &amp;lt; 0.85&lt;/code&gt; → usable but needs improvement
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;TCR &amp;lt; 0.70&lt;/code&gt; → not production ready&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can also break down by outcome type:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;collections&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Counter&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;summarize_outcomes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;EvaluationResult&lt;/span&gt;&lt;span class="p"&gt;]):&lt;/span&gt;
    &lt;span class="n"&gt;counts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;outcome_type&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;successful_completion&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;counts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;OutcomeType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SUCCESSFUL_COMPLETION&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;graceful_failure&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;counts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;OutcomeType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GRACEFUL_FAILURE&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;partial_failure&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;counts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;OutcomeType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PARTIAL_FAILURE&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hard_failure&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;counts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;OutcomeType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HARD_FAILURE&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This lets you say things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;“78 percent of requests end in successful completion, 15 percent in graceful failure, and 7 percent in partial or hard failure.”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Which is far more actionable than “average rating: 3.9 out of 5”.&lt;/p&gt;




&lt;h2&gt;
  
  
  7. Extending the pattern to other metrics
&lt;/h2&gt;

&lt;p&gt;Binary weighted evaluations are not only for completion. In the example project, the same pattern is reused for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Response Clarity Score (RCS)&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
How clear and useful is a single answer?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Error Recovery Score (RTE)&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
How well does the agent recover when something goes wrong?&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  7.1 Response clarity
&lt;/h3&gt;

&lt;p&gt;Define a new set of boolean criteria:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;CLARITY_WEIGHTS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;addresses_request&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;      &lt;span class="c1"&gt;# Did it answer the original question?
&lt;/span&gt;    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;provides_next_step&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;     &lt;span class="c1"&gt;# Does the user know what to do next?
&lt;/span&gt;    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;is_concise&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;             &lt;span class="c1"&gt;# Not rambling
&lt;/span&gt;    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;no_hallucination&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.15&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;       &lt;span class="c1"&gt;# Grounded in context
&lt;/span&gt;    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;appropriate_tone&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;       &lt;span class="c1"&gt;# Professional and friendly
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then evaluate:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;evaluate_response_clarity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;agent_response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;EvaluationResult&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;checks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;addresses_request&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;_check_addresses_request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;agent_response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;provides_next_step&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;_check_next_step&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;agent_response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;is_concise&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;agent_response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;no_hallucination&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;_check_no_hallucination&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;agent_response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;appropriate_tone&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;_check_tone&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;agent_response&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;score&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;CLARITY_WEIGHTS&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;checks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;items&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# You can reuse OutcomeType or define a dedicated one
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;EvaluationResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;score&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;score&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;details&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;checks&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;outcome_type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;OutcomeType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SUCCESSFUL_COMPLETION&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;# or a clarity specific enum
&lt;/span&gt;        &lt;span class="n"&gt;explanation&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Response clarity score: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;score&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  7.2 Error recovery
&lt;/h3&gt;

&lt;p&gt;Same pattern, different criteria:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;ERROR_RECOVERY_WEIGHTS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;detected_error&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;requested_clarification&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;actionable_message&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;no_hallucination&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.15&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;no_crash&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.05&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You define checks for each of these and compute a weighted score in the same way.&lt;/p&gt;




&lt;h2&gt;
  
  
  8. How to adopt this in your own project
&lt;/h2&gt;

&lt;p&gt;Here is a practical checklist to implement binary weighted evaluations for your agents.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Pick one task type&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Answering factual questions
&lt;/li&gt;
&lt;li&gt;Generating SQL queries
&lt;/li&gt;
&lt;li&gt;Routing support tickets&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Write down 3 to 7 binary criteria&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Good prompts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;“What must be true for this result to be useful?”
&lt;/li&gt;
&lt;li&gt;“What are the most expensive mistakes?”
&lt;/li&gt;
&lt;li&gt;“What would we highlight in a post mortem?”&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Assign approximate weights&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Start with something like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;0.3 for the main success criterion
&lt;/li&gt;
&lt;li&gt;0.2 for each secondary one
&lt;/li&gt;
&lt;li&gt;0.1 or less for extras&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Implement check functions&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
They should:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Receive the final state, the ground truth, and optionally the full trace.&lt;/li&gt;
&lt;li&gt;Return clear booleans with simple logic, even if heuristic.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Create an &lt;code&gt;EvaluationResult&lt;/code&gt; object&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
So you are not juggling loose dicts. Include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;score&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;details&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;outcome_type&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;explanation&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Write a small evaluator script&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Like the &lt;code&gt;scripts/run_evaluation.py&lt;/code&gt; in your example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Load test scenarios.
&lt;/li&gt;
&lt;li&gt;Run the agent.
&lt;/li&gt;
&lt;li&gt;Evaluate each run.
&lt;/li&gt;
&lt;li&gt;Print a summary: TCR, outcome breakdown, top failing criteria.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Iterate on weights and criteria&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
After a few runs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Check what failures you see in practice.
&lt;/li&gt;
&lt;li&gt;Adjust weights to match real risk.
&lt;/li&gt;
&lt;li&gt;Add or remove criteria if some are always True or always False.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  9. Why this works so well for LLM agents
&lt;/h2&gt;

&lt;p&gt;Binary weighted evaluations match the nature of LLM work:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Non deterministic outputs&lt;/strong&gt;: You care less about string equality and more about semantics: did the agent satisfy the contract of the task.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Complex, stateful flows&lt;/strong&gt;: It is unrealistic to reduce a full multi turn workflow to a single “pass or fail”. Binary checks let you inspect specific aspects of behavior.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;LLM as judge integrations&lt;/strong&gt;: Even when you use a model like GPT 4 as a grader, it is far more stable at answering yes/no questions than “rate 1–5”. You can plug an LLM into each criterion and still keep the same scoring layer.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Easy to explain to stakeholders&lt;/strong&gt; You can say: “The agent passes &lt;code&gt;correct_participants&lt;/code&gt; only 65 percent of the time, but &lt;code&gt;clear_explanation&lt;/code&gt; is at 92 percent. We will focus on participant selection next.”&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>machinelearning</category>
      <category>python</category>
    </item>
    <item>
      <title>🧠LLMs As Sensors</title>
      <dc:creator>marcosomma</dc:creator>
      <pubDate>Sat, 06 Dec 2025 10:47:16 +0000</pubDate>
      <link>https://dev.to/marcosomma/llms-as-sensors-49if</link>
      <guid>https://dev.to/marcosomma/llms-as-sensors-49if</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Why OrKa 0.9.10 Wraps GenAI Inside Deterministic Systems&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I will start bluntly.&lt;/p&gt;

&lt;p&gt;I like generative AI. I use it every day. I build around it. But I do not trust it to own the outcome of a system.&lt;/p&gt;

&lt;p&gt;For me, GenAI is a fantastic tool for two things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Generating content
&lt;/li&gt;
&lt;li&gt;Analyzing context
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is already huge. But it is still just one tool in a bigger machine.&lt;/p&gt;

&lt;p&gt;What worries me is how often I see people trying to bend the model into being the whole product.&lt;br&gt;&lt;br&gt;
"Just send a giant prompt, get an answer, ship it."&lt;/p&gt;

&lt;p&gt;It works for demos. It does not scale to real systems that need reliability, reproducibility, or any kind of serious accountability.&lt;/p&gt;

&lt;p&gt;This article is about that gap.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Why LLMs should be treated as &lt;strong&gt;probabilistic sensors&lt;/strong&gt;, not entire applications
&lt;/li&gt;
&lt;li&gt;Why their outputs must be &lt;strong&gt;wrapped into real objects&lt;/strong&gt; and fed into &lt;strong&gt;deterministic algorithms&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;And how this philosophy is shaping the current work I am doing with &lt;strong&gt;OrKa v0.9.10&lt;/strong&gt;, including a routing fix that forces me to hold myself to the same standard I am describing here&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I am not trying to hype anything. I am trying to describe how I think modern AI should be wired if we want it to behave like infrastructure instead of roulette.&lt;/p&gt;


&lt;h2&gt;
  
  
  The uncomfortable truth: LLMs are not your system
&lt;/h2&gt;

&lt;p&gt;Let me restate the rough idea that kicked this off:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;AI, especially GenAI, is a great tool for content generation and context analysis. But it is still just a tool.&lt;br&gt;&lt;br&gt;
We need to stop treating it as the whole solution and instead force it to generate outcomes that can feed a bigger system, so those outcomes can be used for deterministic execution of algorithms.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is the core.&lt;/p&gt;

&lt;p&gt;LLMs are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Stochastic
&lt;/li&gt;
&lt;li&gt;Non deterministic
&lt;/li&gt;
&lt;li&gt;Sensitive to prompt phrasing, context ordering, temperature, and even invisible whitespace
&lt;/li&gt;
&lt;li&gt;Very good at pattern matching, fuzzy reasoning, and "filling in the missing piece"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They are &lt;strong&gt;not&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reliable finite state machines
&lt;/li&gt;
&lt;li&gt;Formal decision trees
&lt;/li&gt;
&lt;li&gt;Deterministic planners
&lt;/li&gt;
&lt;li&gt;Systems you can audit in a classical sense
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And that is fine, as long as you &lt;strong&gt;do not pretend otherwise&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Where LLMs shine is exactly where classic systems struggle:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Quick approximate reasoning
&lt;/li&gt;
&lt;li&gt;Extracting structure from messy input
&lt;/li&gt;
&lt;li&gt;Mapping unstructured signals into higher level descriptions
&lt;/li&gt;
&lt;li&gt;Acting almost like a "universal fuzzy detector" for patterns
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So the question is not&lt;br&gt;&lt;br&gt;
"How do I make the LLM do everything?"&lt;/p&gt;

&lt;p&gt;The question is&lt;br&gt;&lt;br&gt;
"How do I use the LLM where it shines, then hand off to deterministic code as soon as possible?"&lt;/p&gt;


&lt;h2&gt;
  
  
  Think of LLMs as sensors, not brains
&lt;/h2&gt;

&lt;p&gt;The metaphor that keeps coming back in my head is this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;An LLM is a &lt;strong&gt;sensor&lt;/strong&gt; that reads the world of language and returns a noisy, high level interpretation.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Just like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A microphone turns air vibration into a waveform
&lt;/li&gt;
&lt;li&gt;A camera turns photons into pixels
&lt;/li&gt;
&lt;li&gt;An accelerometer turns motion into axes of numbers
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;An LLM turns sequences of tokens into:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Labels
&lt;/li&gt;
&lt;li&gt;Spans of text
&lt;/li&gt;
&lt;li&gt;Explanations
&lt;/li&gt;
&lt;li&gt;Rankings
&lt;/li&gt;
&lt;li&gt;Summaries
&lt;/li&gt;
&lt;li&gt;Structured JSON
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The trick is to treat that output as &lt;strong&gt;measurement&lt;/strong&gt;, not as &lt;strong&gt;law&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"This voice sounds like a 35 to 45 year old male, 70 percent confidence."
&lt;/li&gt;
&lt;li&gt;"This message is probably a support ticket about billing."
&lt;/li&gt;
&lt;li&gt;"This paragraph expresses frustration, particularly toward a teammate."&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those measurements are incredibly powerful. Before LLMs, many of these tasks required:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Custom signal processing
&lt;/li&gt;
&lt;li&gt;Domain specific feature extraction
&lt;/li&gt;
&lt;li&gt;Custom models for each upstream task
&lt;/li&gt;
&lt;li&gt;A lot of time and data
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now you can prototype them in hours.&lt;/p&gt;

&lt;p&gt;But once you have that measurement, you should &lt;strong&gt;wrap it&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"age_estimate"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;38&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"age_range"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;35&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;45&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"confidence"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.73&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"audio_segment_023.wav"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"my_local_model_1.5b"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That object is no longer just "LLM output". It is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A typed entity in your system
&lt;/li&gt;
&lt;li&gt;Something you can log, replay, test, and validate
&lt;/li&gt;
&lt;li&gt;A first class citizen in your deterministic logic
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then the decisions are made by normal code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;age_estimate&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;enable_feature&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;adult_profile&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;enable_feature&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;underage_profile&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The "smart" part is upstream. The &lt;strong&gt;accountable&lt;/strong&gt; part is downstream.&lt;/p&gt;




&lt;h2&gt;
  
  
  A concrete example: detecting aging from audio
&lt;/h2&gt;

&lt;p&gt;You mentioned something like "detect the aging from an audio" and I like this example a lot because it is exactly the kind of thing that smells "AI-ish" but should be designed as a system, not as a prompt.&lt;/p&gt;

&lt;p&gt;A naive approach looks like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Send raw audio (or its transcription) to an LLM with a prompt like
"Analyze this audio and tell me how old the speaker is and how it is changing over months."&lt;/li&gt;
&lt;li&gt;Get back some English explanation.
&lt;/li&gt;
&lt;li&gt;Show it in a UI. Call it a feature.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That is fragile and impossible to test properly.&lt;/p&gt;

&lt;p&gt;A more system-level design:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Signal layer&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Extract features from the audio over time.
&lt;/li&gt;
&lt;li&gt;Maybe you use some classic DSP, maybe you use a small embedding model.
&lt;/li&gt;
&lt;li&gt;Build a timeline of short samples.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;LLM as a sensor&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For each window, the LLM gets a compressed description of the signal, or even just some textual metadata if you have it.
&lt;/li&gt;
&lt;li&gt;It outputs something compact and structured:
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="nl"&gt;"timestamp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1733332500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="nl"&gt;"age_estimate"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;39&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="nl"&gt;"confidence"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.68&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="nl"&gt;"voice_stability"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"slightly_decreasing"&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Deterministic aging detector&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A standard algorithm (not an LLM) runs on top of these structured records.
&lt;/li&gt;
&lt;li&gt;It can be a simple function, or a time series model, but the key is:

&lt;ul&gt;
&lt;li&gt;The transitions are explicit
&lt;/li&gt;
&lt;li&gt;The thresholds are configurable
&lt;/li&gt;
&lt;li&gt;The logic is not hidden in a prompt
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;System outcome&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The system might decide:

&lt;ul&gt;
&lt;li&gt;"We do not detect significant aging over the last 12 months."
&lt;/li&gt;
&lt;li&gt;Or "We detect a consistent pattern of degradation, trigger an alert."&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You can test this.&lt;/p&gt;

&lt;p&gt;You can replay the same input data and verify you get the same decision. You can experiment with different threshold values. You can swap out the LLM with a smaller local model that returns a similar JSON structure.&lt;/p&gt;

&lt;p&gt;The LLM is a pluggable &lt;strong&gt;sensor&lt;/strong&gt;. The system is the deterministic pipeline that consumes its readings.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why wrapping model output into objects matters
&lt;/h2&gt;

&lt;p&gt;This is the part that seems small but changes everything.&lt;/p&gt;

&lt;p&gt;If you let your LLM return "whatever it wants, as long as the text looks good", your system will always be at the mercy of prompt drift.&lt;/p&gt;

&lt;p&gt;If you &lt;strong&gt;force&lt;/strong&gt; your LLM to return objects, and you treat those objects as contract, you get:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A clear boundary between probabilistic and deterministic behavior
&lt;/li&gt;
&lt;li&gt;The ability to version that schema
&lt;/li&gt;
&lt;li&gt;Explicit error handling when the object is malformed or incomplete
&lt;/li&gt;
&lt;li&gt;Real regression tests
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Typical pattern:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Prompt the LLM to output &lt;strong&gt;strict JSON&lt;/strong&gt; with an explicit schema.
&lt;/li&gt;
&lt;li&gt;Validate that JSON in your code.
&lt;/li&gt;
&lt;li&gt;Log the raw model output and the parsed object.
&lt;/li&gt;
&lt;li&gt;Use only the parsed object downstream.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In pseudocode:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;raw&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;call_llm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;input_context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;parsed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;validate_schema&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parsed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;AgeEstimateSchema&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# raises if invalid
&lt;/span&gt;
&lt;span class="n"&gt;decision&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;age_classifier&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parsed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;persist_decision&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;decision&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If &lt;code&gt;validate_schema&lt;/code&gt; fails, that is not "mysterious AI behavior". It is a normal bug you can see in a log and fix by adjusting the prompt or model.&lt;/p&gt;

&lt;p&gt;And now we can talk about orchestration.&lt;/p&gt;




&lt;h2&gt;
  
  
  OrKa: building a deterministic spine around probabilistic agents
&lt;/h2&gt;

&lt;p&gt;OrKa exists because I wanted a way to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Compose multiple "sensors" and agents
&lt;/li&gt;
&lt;li&gt;Route between them based on their outputs
&lt;/li&gt;
&lt;li&gt;Keep the execution trace fully visible and replayable
&lt;/li&gt;
&lt;li&gt;Avoid hardcoding everything in application code over and over
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In OrKa, I do not think of "a big model that knows everything".&lt;br&gt;&lt;br&gt;
I think in terms of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Agents that do one thing
&lt;/li&gt;
&lt;li&gt;Service nodes that mutate state or call external systems
&lt;/li&gt;
&lt;li&gt;Routers that decide which agent comes next, based on structured outputs
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Everything is described in YAML, so the cognition graph is explicit.&lt;/p&gt;

&lt;p&gt;A very simplified OrKa-style flow where an LLM decides which branch to take might look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;orchestrator&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;audio_aging_flow&lt;/span&gt;
  &lt;span class="na"&gt;strategy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sequential&lt;/span&gt;
  &lt;span class="na"&gt;queue&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;redis&lt;/span&gt;

&lt;span class="na"&gt;agents&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;audio_to_features&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;service&lt;/span&gt;
    &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;audio_feature_extractor&lt;/span&gt;
    &lt;span class="na"&gt;next&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;llm_age_sensor&lt;/span&gt;

  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;llm_age_sensor&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;llm&lt;/span&gt;
    &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;local_llm_1&lt;/span&gt;
    &lt;span class="na"&gt;prompt&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
      &lt;span class="s"&gt;You are an age estimation sensor.&lt;/span&gt;
      &lt;span class="s"&gt;Given these features, output strict JSON:&lt;/span&gt;
      &lt;span class="s"&gt;{"age_estimate": int, "confidence": float}&lt;/span&gt;
    &lt;span class="na"&gt;next&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;age_route&lt;/span&gt;

  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;age_route&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;router&lt;/span&gt;
    &lt;span class="na"&gt;routing_key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;age_estimate&lt;/span&gt;
    &lt;span class="na"&gt;routes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;condition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;value&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;18"&lt;/span&gt;
        &lt;span class="na"&gt;next&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;underage_handler&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;condition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;value&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;18"&lt;/span&gt;
        &lt;span class="na"&gt;next&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;adult_handler&lt;/span&gt;

  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;underage_handler&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;service&lt;/span&gt;
    &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;profile_flagger&lt;/span&gt;

  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;adult_handler&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;service&lt;/span&gt;
    &lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;profile_flagger&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The LLM here is just one node (&lt;code&gt;llm_age_sensor&lt;/code&gt;). Its output becomes a field (&lt;code&gt;age_estimate&lt;/code&gt;) that the router uses in a deterministic way.&lt;/p&gt;

&lt;p&gt;If you replay the same input, the router will make the same decision for the same parsed values.&lt;/p&gt;

&lt;p&gt;That guarantee is not automatic. It depends on the correctness of routing behavior. Which brings me to the latest OrKa release.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why this matters beyond OrKa
&lt;/h2&gt;

&lt;p&gt;You do not have to care about OrKa to care about this pattern.&lt;/p&gt;

&lt;p&gt;If you are building any system around generative models, ask yourself a few questions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Where does the probabilistic behavior end?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Is there a clear boundary where the LLM output is turned into a typed object and validated? Or does the "magic" just flow deep into your code base?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Who owns the final decision?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Does the model decide what happens, or does deterministic code decide based on model measurements?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Can you replay a run?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
If a user reports something weird, can you reconstruct the full chain: input → model output → routing → system decision?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;What happens if you swap models?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
If you change from a proprietary model to a local one, do you only change the sensor, or do you need to rewrite half the app?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;What is the unit of testability?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Can you test downstream logic with synthetic objects, without involving the LLM at all?&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;My bias is clear:&lt;br&gt;&lt;br&gt;
I want LLMs to be pluggable, swappable, measurable, and constrained.&lt;br&gt;&lt;br&gt;
I want the core of the system to feel boring in a good way.&lt;/p&gt;

&lt;p&gt;That is what OrKa is trying to encode at the framework level:&lt;br&gt;&lt;br&gt;
model calls as agents, routing as explicit configuration, memory and traces as first class concepts, all tied together in a way that can be inspected, not guessed.&lt;/p&gt;


&lt;h2&gt;
  
  
  A small mental shift that changes system design
&lt;/h2&gt;

&lt;p&gt;If I had to compress this article into one mental shift, it would be this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Stop asking "What can the LLM do?"&lt;br&gt;&lt;br&gt;
Start asking "What kind of object do I need so that my system can behave deterministically, and how can I use an LLM to produce that object?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Instead of "write me a reply email", think "I need an &lt;code&gt;EmailReplyPlan&lt;/code&gt; with fields: tone, key_points, call_to_action, and I will let deterministic templates render the final email."&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Instead of "decide what to do next for this customer", think "I need a &lt;code&gt;NextAction&lt;/code&gt; object with &lt;code&gt;action_type&lt;/code&gt;, &lt;code&gt;priority&lt;/code&gt;, and &lt;code&gt;reason&lt;/code&gt;, and my orchestration layer will decide which internal systems to call."&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Instead of "summarize this call for the CRM", think "I need a &lt;code&gt;CallSummary&lt;/code&gt; object with &lt;code&gt;sentiment&lt;/code&gt;, &lt;code&gt;topics&lt;/code&gt;, &lt;code&gt;promises_made&lt;/code&gt;, &lt;code&gt;follow_up_tasks&lt;/code&gt;, and my CRM logic will handle storage and workflows."&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In all of these, the LLM is powerful, but the real system lives around it.&lt;/p&gt;

&lt;p&gt;You can inspect those objects. You can aggregate them. You can feed them into analytics and classic algorithms. You can design them once and evolve them over time.&lt;/p&gt;

&lt;p&gt;And if you embrace orchestration tools, you can also define how these objects move, which nodes can create or transform them, and under what conditions routing happens.&lt;/p&gt;


&lt;h2&gt;
  
  
  Closing thoughts
&lt;/h2&gt;

&lt;p&gt;So, to tie the threads:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GenAI is great at generating content and reading context. That is not a small thing. It is a massive shift in what we can build in reasonable time.
&lt;/li&gt;
&lt;li&gt;But models are not the system. They are components in the system. Treat them like &lt;strong&gt;sensors&lt;/strong&gt; that emit measurements.
&lt;/li&gt;
&lt;li&gt;Wrap model outputs into strict, typed objects. Validate them. Version them. Use them as the raw material for deterministic logic, not as the final answer.
&lt;/li&gt;
&lt;li&gt;Orchestrate flows so that routing is explicit, traceable, and reproducible. If the routing itself is fuzzy, you just moved the black box one step further.
&lt;/li&gt;
&lt;li&gt;In OrKa v0.9.10, tightening routing behavior was not a cosmetic refactor. It was necessary to keep this philosophy consistent in the framework I am building. If I want OrKa to be a cognitive execution layer, it needs to behave like infrastructure, not like another probabilistic blob around the model.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you are curious about OrKa, you can read more and follow the roadmap at &lt;strong&gt;orkacore.com&lt;/strong&gt;. I am not claiming it is the answer. It is simply my current attempt to encode this belief in code:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;LLMs should feed deterministic systems, not replace them.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If that idea resonates with you, then we are probably trying to solve similar problems, just with different tools.&lt;/p&gt;


&lt;h2&gt;
  
  
  OrKa v0.9.10: fixing routing is not a cosmetic change
&lt;/h2&gt;

&lt;p&gt;I just cut a release of &lt;strong&gt;OrKa v0.9.10&lt;/strong&gt;, focused on a fix in routing behavior.&lt;/p&gt;

&lt;p&gt;I will not pretend this is some huge "launch" moment. It is a pretty boring fix if you look only at the diff. But for the philosophy in this article, it is critical.&lt;/p&gt;

&lt;p&gt;What was wrong?&lt;/p&gt;

&lt;p&gt;In some edge cases, the router:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Would evaluate conditions on slightly stale context, or
&lt;/li&gt;
&lt;li&gt;Could pick a next node that was not the one you would expect from the latest structured output, especially after more complex flows with forks and joins
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is exactly the type of thing that breaks the "LLM as sensor, system as deterministic spine" model.&lt;/p&gt;

&lt;p&gt;When your router does not behave deterministically, you get:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Non reproducible traces
&lt;/li&gt;
&lt;li&gt;Confusing logs
&lt;/li&gt;
&lt;li&gt;Surprises during replay
&lt;/li&gt;
&lt;li&gt;The feeling that the orchestrator itself is "magical" instead of mechanical
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is the opposite of what OrKa is supposed to be.&lt;/p&gt;

&lt;p&gt;So in v0.9.10 I focused on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Making sure routing decisions always use the &lt;strong&gt;last committed output&lt;/strong&gt; of the relevant agent
&lt;/li&gt;
&lt;li&gt;Making context selection explicit, not implicit
&lt;/li&gt;
&lt;li&gt;Tightening the mapping between &lt;code&gt;routing_key&lt;/code&gt; and the object field it reads
&lt;/li&gt;
&lt;li&gt;Hardening the trace so that, for a given input plus memory state, the same routing path is taken every time
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In more human words:&lt;br&gt;&lt;br&gt;
If your LLM says:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"route"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"adult_handler"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;then OrKa should take that path, and you should be able to see exactly why in the trace.&lt;/p&gt;

&lt;p&gt;No surprises. No "the orchestrator is a bit mysterious too".&lt;br&gt;&lt;br&gt;
Only the LLM is allowed to be fuzzy. The rest must behave like infrastructure.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>architecture</category>
      <category>machinelearning</category>
      <category>rag</category>
    </item>
    <item>
      <title>🧠Maybe I Just Do Not Get It!</title>
      <dc:creator>marcosomma</dc:creator>
      <pubDate>Tue, 02 Dec 2025 06:08:00 +0000</pubDate>
      <link>https://dev.to/marcosomma/maybe-i-just-do-not-get-it-5e3f</link>
      <guid>https://dev.to/marcosomma/maybe-i-just-do-not-get-it-5e3f</guid>
      <description>&lt;p&gt;I have been working with AI for a while now.&lt;/p&gt;

&lt;p&gt;Not as a tourist. Not as a weekend hacker. Deep in it. Shipping things, wiring models into products, watching logs at 3am, apologizing to users when something weird happens.&lt;/p&gt;

&lt;p&gt;And still, every time I see one of those posts that says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Autonomous agents will run your business for you."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I feel this quiet, uncomfortable voice in my head:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Maybe I am the one who does not get it."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Everyone seems so confident about this idea that we can just:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Plug a model into a tool layer
&lt;/li&gt;
&lt;li&gt;Wrap it in a few prompts
&lt;/li&gt;
&lt;li&gt;Let it call APIs
&lt;/li&gt;
&lt;li&gt;And watch it "run operations" or "manage your company"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And here I am, on the side, asking questions that sound almost boring:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Are we actually giving this thing real power over important decisions?
&lt;/li&gt;
&lt;li&gt;What exactly is our control surface?
&lt;/li&gt;
&lt;li&gt;What happens when it fails in a way we did not anticipate?
&lt;/li&gt;
&lt;li&gt;Do we really think &lt;code&gt;prompt = governance&lt;/code&gt;?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Part of me worries that I am simply being too cautious. Too old school. Too stuck in "engineering brain" while the world evolves into something more fluid and probabilistic.&lt;/p&gt;

&lt;p&gt;But part of me also thinks:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Maybe someone has to say out loud that prompts are not control.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So here is my attempt.&lt;br&gt;&lt;br&gt;
Half confession, half technical rant, fully self doubting.&lt;/p&gt;


&lt;h2&gt;
  
  
  The uncomfortable feeling of being the skeptic in an optimistic room
&lt;/h2&gt;

&lt;p&gt;Let me describe a pattern that keeps repeating.&lt;/p&gt;

&lt;p&gt;I join a meeting or a call about "AI adoption" or "agents for ops" or "automating workflows." Someone shares a slide that looks roughly like this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;User request -&amp;gt; LLM -&amp;gt; Agent framework -&amp;gt; Tools -&amp;gt; Profit&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The narrative is usually:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"We will have agents that autonomously handle customer tickets, manage payments, adjust pricing, write code, do growth experiments, generate content, and so on. Humans just supervise."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;While people nod, I feel like the awkward person in the corner thinking:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"This is still a stochastic model that completes text based on training data and prompt context, right? Did I miss the memo where it became an actual dependable decision maker?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And then the self doubt kicks in.&lt;/p&gt;

&lt;p&gt;Maybe:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I am underestimating how good these models have become
&lt;/li&gt;
&lt;li&gt;I am too attached to the old way of building systems with explicit logic and clear invariants
&lt;/li&gt;
&lt;li&gt;I am biased because I have seen too many subtle failures in practice
&lt;/li&gt;
&lt;li&gt;I am projecting my own fear of losing control over systems that I am supposed to understand&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On a bad day, the internal monologue is literally:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Everyone else seems comfortable delegating to this. Maybe I am just not visionary enough."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But then I look at the actual properties of these models and toolchains and the rational part of my brain quietly insists:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"No, wait. This is not about lacking vision. This is about basic control theory and risk."&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h2&gt;
  
  
  Prompting feels like control, but it is not
&lt;/h2&gt;

&lt;p&gt;There is a deep psychological trick happening here.&lt;/p&gt;

&lt;p&gt;When you write a prompt, it &lt;em&gt;feels&lt;/em&gt; like you are writing a policy.&lt;/p&gt;

&lt;p&gt;Something like:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"You are an operations assistant. You always follow company policy.&lt;br&gt;&lt;br&gt;
You never issue a refund above 200 EUR without human approval.&lt;br&gt;&lt;br&gt;
You always prioritize customer safety and data privacy."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That looks like a rule set. It looks almost like a mini spec.&lt;/p&gt;

&lt;p&gt;But underneath, what you really did is feed natural language text as conditioning into a statistical model that has:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No strict guarantee that those words will be followed
&lt;/li&gt;
&lt;li&gt;No built in concept of "policy" or "violation"
&lt;/li&gt;
&lt;li&gt;No deterministic execution path
&lt;/li&gt;
&lt;li&gt;No awareness of the "blast radius" of a single wrong action&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You gave it text. The model gives you back more text.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The feeling of control is coming from you, not from the system.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It is your brain that reads that prompt and says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Ah, yes, I told it what to do. So now it will do that."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The model does not "know" that those instructions are sacred.&lt;/p&gt;

&lt;p&gt;It has patterns in its weights that say: &lt;em&gt;"When the input looks like this, texts like that often follow."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The distance between those two things is exactly where a lot of risk lives.&lt;/p&gt;


&lt;h2&gt;
  
  
  What real control looks like in software systems
&lt;/h2&gt;

&lt;p&gt;If I forget the AI hype for a moment and think like a boring backend engineer, "control" has always meant things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Permissions&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which identity can do what, where, and how often&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Boundaries&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Network segments, firewalls, read only versus read write access, rate limits&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Auditability&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Who did what, when, and using which parameters&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Reversibility&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Can we undo this operation? Can we restore from backup?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Constraints and invariants&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Account balance must never be negative in this system
&lt;/li&gt;
&lt;li&gt;Orders must always have a valid user id and product id
&lt;/li&gt;
&lt;li&gt;This service cannot push more than X updates per second&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And then, over all of this, we layer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Monitoring
&lt;/li&gt;
&lt;li&gt;Alerts
&lt;/li&gt;
&lt;li&gt;Fallback paths
&lt;/li&gt;
&lt;li&gt;Kill switches
&lt;/li&gt;
&lt;li&gt;Change management&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is tedious and unsexy, but it is what makes serious systems not collapse.&lt;/p&gt;

&lt;p&gt;Now compare that with "control" when we talk about AI agents:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"We wrapped the model with a prompt that tells it to be safe."
&lt;/li&gt;
&lt;li&gt;"We added a message saying: if unsure, ask a human."
&lt;/li&gt;
&lt;li&gt;"We configured a few tools and let the agent decide which to call."&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There is a huge gap between these two worlds.&lt;/p&gt;

&lt;p&gt;I keep asking myself:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Am I overreacting by demanding similar rigor for AI automation?&lt;br&gt;&lt;br&gt;
Or are we collectively underreacting because the interface is so friendly and the output is so fluent?"&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h2&gt;
  
  
  Why prompt based control is fragile
&lt;/h2&gt;

&lt;p&gt;Let me list the main reasons I struggle to trust &lt;code&gt;prompt = control&lt;/code&gt; as a serious safety mechanism.&lt;/p&gt;
&lt;h3&gt;
  
  
  Non determinism
&lt;/h3&gt;

&lt;p&gt;Call the same model with the same prompt and temperature 0.7 ten times and you get:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Slightly different reasoning chains
&lt;/li&gt;
&lt;li&gt;Occasionally very different answers
&lt;/li&gt;
&lt;li&gt;Sometimes rare but catastrophic failure modes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is fine in a chat setting. It is far less fine if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The output approves or denies a refund
&lt;/li&gt;
&lt;li&gt;The output decides whether to escalate a compliance issue
&lt;/li&gt;
&lt;li&gt;The output sends an email to an important customer&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If your "policy" is just in the prompt, the model can randomly deviate from it when some token path goes weird.&lt;/p&gt;
&lt;h3&gt;
  
  
  Context dilution and instruction conflicts
&lt;/h3&gt;

&lt;p&gt;In complex agent setups, the model context looks something like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;System messages ("You are X")
&lt;/li&gt;
&lt;li&gt;Task instructions
&lt;/li&gt;
&lt;li&gt;Tool specs
&lt;/li&gt;
&lt;li&gt;History, previous steps, errors
&lt;/li&gt;
&lt;li&gt;User messages
&lt;/li&gt;
&lt;li&gt;Tool responses&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Your carefully written safety instructions can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Get buried far up in the context
&lt;/li&gt;
&lt;li&gt;Be overshadowed by later messages
&lt;/li&gt;
&lt;li&gt;Conflict with tool descriptions
&lt;/li&gt;
&lt;li&gt;Interact strangely with user input&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You cannot be sure which instruction wins inside the model internal weighting. You are left hoping that the most important part is loud enough.&lt;/p&gt;
&lt;h3&gt;
  
  
  Distribution shift and weird edge cases
&lt;/h3&gt;

&lt;p&gt;The model was trained on static data. Then it is thrown into:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An evolving product
&lt;/li&gt;
&lt;li&gt;Changing user behavior
&lt;/li&gt;
&lt;li&gt;Novel business processes
&lt;/li&gt;
&lt;li&gt;Adversarial inputs from clever users&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Whatever behavior you saw in your internal tests is not a formal guarantee. It is just evidence that under some sample of conditions, it behaved "well enough."&lt;/p&gt;

&lt;p&gt;It might take only one weird edge case to cause a big problem.&lt;/p&gt;
&lt;h3&gt;
  
  
  Lack of grounded state and formal rules
&lt;/h3&gt;

&lt;p&gt;Older systems have explicit state machines and rules. You can formalize, prove, or at least reason about them.&lt;/p&gt;

&lt;p&gt;AI agents usually do not have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A formal internal model of the environment
&lt;/li&gt;
&lt;li&gt;A provable decision process
&lt;/li&gt;
&lt;li&gt;Compositional guarantees&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This means if you want real control, you need to build it &lt;em&gt;around&lt;/em&gt; the models, not &lt;em&gt;inside&lt;/em&gt; the prompt.&lt;/p&gt;

&lt;p&gt;Which brings me to the part where I keep asking:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Why are so many people comfortable skipping that part?"&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h2&gt;
  
  
  The three A's: Automation, autonomy, authority
&lt;/h2&gt;

&lt;p&gt;I find it useful to separate three concepts that often get blended into one in marketing material.&lt;/p&gt;
&lt;h3&gt;
  
  
  Automation
&lt;/h3&gt;

&lt;p&gt;This is what we have done for decades:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cron jobs
&lt;/li&gt;
&lt;li&gt;Scripts
&lt;/li&gt;
&lt;li&gt;Pipelines
&lt;/li&gt;
&lt;li&gt;Daemons
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Automation means: &lt;em&gt;"This specific routine step is handled by a machine."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Poorly designed automation can still cause trouble, but at least the logic is explicit.&lt;/p&gt;
&lt;h3&gt;
  
  
  Autonomy
&lt;/h3&gt;

&lt;p&gt;Autonomy is stronger:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The system can decide which steps to take
&lt;/li&gt;
&lt;li&gt;It can react to the environment
&lt;/li&gt;
&lt;li&gt;It can pick from multiple possible actions
&lt;/li&gt;
&lt;li&gt;It can generate plans that you did not hardcode&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is where LLM based agents live. They choose tools, infer goals, adapt to context.&lt;/p&gt;
&lt;h3&gt;
  
  
  Authority
&lt;/h3&gt;

&lt;p&gt;And then there is authority:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The system has the power to directly impact important resources
&lt;/li&gt;
&lt;li&gt;It can move money, change production systems, talk to customers, sign something that looks like a commitment&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Authority is where risk explodes.&lt;/p&gt;

&lt;p&gt;You can have autonomous agents with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No authority at all (pure recommendations)
&lt;/li&gt;
&lt;li&gt;Limited authority (sandboxed actions)
&lt;/li&gt;
&lt;li&gt;Full authority (unbounded write access to real world systems)&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;My fear is not autonomy itself.&lt;br&gt;&lt;br&gt;
My fear is autonomy plus authority with only prompt based "control" and minimal protective scaffolding.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That feels like a fragile tower.&lt;/p&gt;


&lt;h2&gt;
  
  
  Why "let the AI run it" is so seductive
&lt;/h2&gt;

&lt;p&gt;To be fair, I understand the attraction. It is not just hype or stupidity. There are real pressures that make people want this to be true.&lt;/p&gt;

&lt;p&gt;Some of them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Economic pressure&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reduce headcount
&lt;/li&gt;
&lt;li&gt;Do more with smaller teams
&lt;/li&gt;
&lt;li&gt;Compete with others who claim they have agent driven operations&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Cognitive overload&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Businesses are complex
&lt;/li&gt;
&lt;li&gt;It is tempting to offload routine decision making to something that can read all the documents and logs&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Interface illusion&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Talking to an LLM feels like talking to a very capable person
&lt;/li&gt;
&lt;li&gt;It sounds confident
&lt;/li&gt;
&lt;li&gt;It apologizes when it fails
&lt;/li&gt;
&lt;li&gt;We project far more understanding into it than it actually has&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Narrative momentum&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Investors, founders, vendors, content creators all benefit from the story that "this is the future"
&lt;/li&gt;
&lt;li&gt;Nobody gets likes by saying "We built a constrained automation with careful permissions and small risk boundaries"&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And so I watch this wave of "AI will run your company" rising, and my own position starts to feel almost embarrassing:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Sorry, I still think we should treat this like an unreliable but useful colleague, not an all knowing operations overlord."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Am I being too negative? Or are others being too optimistic? I genuinely do not know.&lt;/p&gt;


&lt;h2&gt;
  
  
  What a more honest control architecture might look like
&lt;/h2&gt;

&lt;p&gt;Let me try to articulate the model that my brain keeps coming back to. Perhaps this is my bias. Perhaps it is just boring good practice.&lt;/p&gt;

&lt;p&gt;I imagine AI systems in terms of layers.&lt;/p&gt;
&lt;h3&gt;
  
  
  Models as suggestion engines
&lt;/h3&gt;

&lt;p&gt;At the core, the LLM or vision model or other component is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A suggestion engine
&lt;/li&gt;
&lt;li&gt;A planning assistant
&lt;/li&gt;
&lt;li&gt;A pattern recognizer
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It produces options, not truth. It drafts, proposes, clusters, explains.&lt;/p&gt;

&lt;p&gt;In this framing, the default is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Everything the model says needs to be checked or constrained by something else."&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;
  
  
  Policy and constraints outside the model
&lt;/h3&gt;

&lt;p&gt;Policies like "never refund above X without human approval" should not live only in prompt text.&lt;/p&gt;

&lt;p&gt;They should live in actual logic that wraps the model.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;MAX_AUTO_REFUND&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;  &lt;span class="c1"&gt;# euros
&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;handle_refund_suggestion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;suggestion_amount&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;suggestion_amount&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;MAX_AUTO_REFUND&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;issue_refund&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;suggestion_amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;log_event&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;refund_auto_approved&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;suggestion_amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;create_manual_review_ticket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;suggestion_amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;log_event&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;refund_needs_review&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;suggestion_amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The model can still say "I think we should refund 300 EUR."&lt;br&gt;&lt;br&gt;
But authority is delegated through hard limits, not polite reminders in a prompt.&lt;/p&gt;
&lt;h3&gt;
  
  
  Tooling as a narrow interface to the world
&lt;/h3&gt;

&lt;p&gt;Agents should not see a raw database or a root shell.&lt;/p&gt;

&lt;p&gt;They should see:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Narrow tools that do one thing
&lt;/li&gt;
&lt;li&gt;With explicit safe defaults
&lt;/li&gt;
&lt;li&gt;With input validation and sanitization
&lt;/li&gt;
&lt;li&gt;With rate limits and quotas
&lt;/li&gt;
&lt;li&gt;With clear logging
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;send_email&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;template_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# Validation
&lt;/span&gt;    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;@&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;5000&lt;/span&gt;

    &lt;span class="c1"&gt;# Logging
&lt;/span&gt;    &lt;span class="nf"&gt;log_event&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;email_requested&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;subject&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;template_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;template_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Send through provider
&lt;/span&gt;    &lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;subject&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The agent can choose to call &lt;code&gt;send_email&lt;/code&gt;, but cannot bypass:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Validation
&lt;/li&gt;
&lt;li&gt;Logging
&lt;/li&gt;
&lt;li&gt;Provider boundaries&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Human checkpoints and degrees of autonomy
&lt;/h3&gt;

&lt;p&gt;The idea of "agent runs everything" feels wrong to me.&lt;/p&gt;

&lt;p&gt;A more grounded model:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Level 0&lt;/strong&gt;: Advisory only

&lt;ul&gt;
&lt;li&gt;The model suggests, humans decide
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Level 1&lt;/strong&gt;: Low risk autonomy

&lt;ul&gt;
&lt;li&gt;Model can execute actions with small impact, easily reversible
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Level 2&lt;/strong&gt;: Medium risk autonomy

&lt;ul&gt;
&lt;li&gt;Model can act but behind stricter limits and with additional monitoring
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Level 3&lt;/strong&gt;: High risk decisions

&lt;ul&gt;
&lt;li&gt;Model can only propose. Mandatory human review&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can even encode this in configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;tasks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;reply_to_low_risk_tickets&lt;/span&gt;
    &lt;span class="na"&gt;autonomy_level&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
    &lt;span class="na"&gt;max_impact&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;single_customer_message"&lt;/span&gt;

  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;adjust_pricing&lt;/span&gt;
    &lt;span class="na"&gt;autonomy_level&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
    &lt;span class="na"&gt;requires_human_approval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;issue_refund&lt;/span&gt;
    &lt;span class="na"&gt;autonomy_level&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
    &lt;span class="na"&gt;max_amount&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;200&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then enforce this at the orchestration layer, not just in a paragraph of English.&lt;/p&gt;

&lt;h3&gt;
  
  
  Observability and traceability
&lt;/h3&gt;

&lt;p&gt;If a system is "running your business" in any sense, you want to know:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What it decided
&lt;/li&gt;
&lt;li&gt;Why it decided that
&lt;/li&gt;
&lt;li&gt;Which tools it called
&lt;/li&gt;
&lt;li&gt;What inputs it saw
&lt;/li&gt;
&lt;li&gt;How often it was wrong
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Structured logs
&lt;/li&gt;
&lt;li&gt;Traces per request
&lt;/li&gt;
&lt;li&gt;Metrics
&lt;/li&gt;
&lt;li&gt;Failure classification
&lt;/li&gt;
&lt;li&gt;Ability to replay a scenario and see exactly what happened
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Without this, you are blind.&lt;/p&gt;




&lt;h2&gt;
  
  
  The voice that keeps whispering "Maybe you are overdoing it"
&lt;/h2&gt;

&lt;p&gt;Let me be honest.&lt;/p&gt;

&lt;p&gt;When I design systems with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Orchestrators
&lt;/li&gt;
&lt;li&gt;Multiple agents
&lt;/li&gt;
&lt;li&gt;Guards
&lt;/li&gt;
&lt;li&gt;Checks
&lt;/li&gt;
&lt;li&gt;Extensive logging
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I sometimes feel like the paranoid one in a world of brave explorers.&lt;/p&gt;

&lt;p&gt;Every confident demo of an "autonomous" system triggers a small internal comparison:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;They are moving faster
&lt;/li&gt;
&lt;li&gt;They ship bold things
&lt;/li&gt;
&lt;li&gt;They talk about "hands free operations"
&lt;/li&gt;
&lt;li&gt;They have nice UIs and slick narratives
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And then I look at my own mental model:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Treat the AI like an unreliable colleague. Give it power only inside tightly defined boundaries. Observe it at all times."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That can feel conservative, almost limiting.&lt;/p&gt;

&lt;p&gt;The self doubt is real.&lt;/p&gt;

&lt;p&gt;Sometimes I really think:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Maybe I should relax and just trust the agents more."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Then I remember practical incidents:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Models hallucinating facts that never existed
&lt;/li&gt;
&lt;li&gt;Wrong tool calls due to slightly ambiguous tool descriptions
&lt;/li&gt;
&lt;li&gt;Subtle prompt drift when context windows get large
&lt;/li&gt;
&lt;li&gt;Surprising interactions between two agents that were not tested together
&lt;/li&gt;
&lt;li&gt;Simple failure cases that completely break the illusion of "autonomy"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And the cautious part of me wins again.&lt;/p&gt;




&lt;h2&gt;
  
  
  Could I be wrong about all this?
&lt;/h2&gt;

&lt;p&gt;To be fair, yes. I could be wrong in several ways.&lt;/p&gt;

&lt;p&gt;Possibilities that I keep in mind:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Models might reach reliability levels I do not currently anticipate  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;With better training, better fine tuning, better safety layers
&lt;/li&gt;
&lt;li&gt;Maybe we will actually get to a place where prompt specified policies are followed with extremely high consistency
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;The average business might tolerate more risk than I think  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Maybe for many processes, "good enough, most of the time" is perfectly fine
&lt;/li&gt;
&lt;li&gt;Maybe the cost savings outweigh occasional screw ups
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;New agent frameworks might enforce more structure internally  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Instead of raw prompt based decisions, they might encode policies and constraints in more robust ways, even if the interface still looks like "agents"
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;I might be stuck with an outdated mental model  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;My training is in building explicit systems
&lt;/li&gt;
&lt;li&gt;Perhaps my discomfort is just a mismatch between that training and a new probabilistic world
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;I try to keep this humility active. I do not want to be the person yelling "cars are dangerous, horses are better" forever.&lt;/p&gt;

&lt;p&gt;But even if I am wrong about the magnitude of the risk, I still believe:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Any time you mix autonomy and authority, you need real control structures, not only nice English."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And I have not yet seen a convincing argument that prompts, by themselves, are a sufficient control mechanism for important decisions.&lt;/p&gt;




&lt;h2&gt;
  
  
  How I am personally responding to this tension
&lt;/h2&gt;

&lt;p&gt;Instead of picking a side in the "agents are the future" versus "agents are useless" debate, I am trying to sit in the middle:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I accept that LLMs are incredibly powerful tools for reasoning, drafting, and planning
&lt;/li&gt;
&lt;li&gt;I reject the idea that this power makes them inherently trustworthy decision makers
&lt;/li&gt;
&lt;li&gt;I still want to leverage them deeply in systems that matter
&lt;/li&gt;
&lt;li&gt;And I want to design those systems with explicit, boring, old fashioned control surfaces
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is why I care about things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Orchestrators that define flows explicitly
&lt;/li&gt;
&lt;li&gt;YAML or other declarative formats that separate "what should happen" from "how the model reasons"
&lt;/li&gt;
&lt;li&gt;Service nodes that encapsulate capabilities behind strict boundaries
&lt;/li&gt;
&lt;li&gt;Observability that lets you replay what happened and why
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is also why, when people tell me:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"We have an autonomous agent that runs X."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;my first questions are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What is the maximum damage it can cause in one execution?
&lt;/li&gt;
&lt;li&gt;How do you know when it did the wrong thing?
&lt;/li&gt;
&lt;li&gt;How do you stop it quickly?
&lt;/li&gt;
&lt;li&gt;Where are the hard rules, outside of the prompt?
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the answers are vague, my self doubt temporarily fades and my confidence in my skepticism grows.&lt;/p&gt;

&lt;p&gt;At the same time, I am building tools in this space myself. That adds a weird layer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I do not want to sound like I am attacking the very category I am working in
&lt;/li&gt;
&lt;li&gt;But I also do not want to oversell autonomy and under discuss control
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So when I mention my own work, I try to be very direct:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"I am working on an orchestration layer for AI agents, with explicit flows, branching, service nodes, and traceability.&lt;br&gt;&lt;br&gt;
The whole point is not to 'let the AI run everything' but to give humans a clear frame to decide what the AI is allowed to do, when, and with which safeguards."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you are curious, that work lives in the &lt;strong&gt;OrKa Reasoning&lt;/strong&gt; project.&lt;br&gt;&lt;br&gt;
It is part of my attempt to reconcile "use AI deeply" with "do not surrender control through vibes."&lt;/p&gt;




&lt;h2&gt;
  
  
  OrKa Reasoning
&lt;/h2&gt;

&lt;p&gt;If the idea of explicit control over AI agents resonates with you, you can explore the OrKa Reasoning stack here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;OrKa Reasoning repository:&lt;br&gt;&lt;br&gt;
&lt;a href="https://github.com/marcosomma/orka-reasoning" rel="noopener noreferrer"&gt;https://github.com/marcosomma/orka-reasoning&lt;/a&gt;  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Quick start and docs:&lt;br&gt;&lt;br&gt;
&lt;a href="https://github.com/marcosomma/orka-reasoning/blob/master/docs/getting-started.md" rel="noopener noreferrer"&gt;https://github.com/marcosomma/orka-reasoning/blob/master/docs/getting-started.md&lt;/a&gt;  &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;OrKa Reasoning is my attempt to give developers a YAML first orchestration layer where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Flows and branching are explicit
&lt;/li&gt;
&lt;li&gt;Memory, tools, and services are wrapped in clear nodes
&lt;/li&gt;
&lt;li&gt;You can inspect traces and understand why a decision was made
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In other words, it is an experiment in building the control surfaces I wish existed by default in modern AI stacks.&lt;/p&gt;




&lt;h2&gt;
  
  
  An invitation to other quietly skeptical builders
&lt;/h2&gt;

&lt;p&gt;If you feel a similar discomfort, I want to say this clearly:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"You are not alone."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Respect what these models can do
&lt;/li&gt;
&lt;li&gt;Push their limits in creative ways
&lt;/li&gt;
&lt;li&gt;Build serious systems around them
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;and still say:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"No, I am not giving them full, unbounded control over important decisions.&lt;br&gt;&lt;br&gt;
Control belongs to humans, encoded in systems that are understandable and auditable."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You can be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Excited and cautious
&lt;/li&gt;
&lt;li&gt;Curious and skeptical
&lt;/li&gt;
&lt;li&gt;Ambitious and unwilling to pretend that prompt text equals governance
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I still doubt myself almost every time I voice these concerns.&lt;br&gt;&lt;br&gt;
I still worry about sounding like the boring adult in a room full of enthusiastic kids.&lt;/p&gt;

&lt;p&gt;But I would rather live with that discomfort than pretend that we solved control by writing "please be safe" at the top of a prompt.&lt;/p&gt;

&lt;p&gt;If anything in this ramble resonates with you, I would love to hear:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How are you designing control into your AI systems?
&lt;/li&gt;
&lt;li&gt;Where do you draw the line for autonomy versus authority?
&lt;/li&gt;
&lt;li&gt;Have you found practices that actually reduce your anxiety about letting agents act?
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Drop a comment, poke holes in my thinking, or tell me why I am wrong.&lt;/p&gt;

&lt;p&gt;I am very open to the possibility that I am the one who "does not get it."&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;But if we are going to let AI agents touch real businesses, real money, and real people, I would really like us to get control right first.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>ai</category>
      <category>rag</category>
      <category>machinelearning</category>
      <category>opensource</category>
    </item>
    <item>
      <title>🧠Veterinary AI Workflow with OrKa: Specialist Orchestration, Structured JSON Input, and Observable Reasoning</title>
      <dc:creator>marcosomma</dc:creator>
      <pubDate>Sat, 29 Nov 2025 17:42:28 +0000</pubDate>
      <link>https://dev.to/marcosomma/veterinary-ai-workflow-with-orka-specialist-orchestration-structured-json-input-and-observable-2hho</link>
      <guid>https://dev.to/marcosomma/veterinary-ai-workflow-with-orka-specialist-orchestration-structured-json-input-and-observable-2hho</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Modern veterinary medicine often deals with complex clinical cases that require collaboration among multiple specialists, analysis of heterogeneous data, and the production of clear, personalized action plans. In this context, orchestrating AI agents is a promising solution-provided that data is managed in a structured, transparent, and traceable way.&lt;/p&gt;

&lt;p&gt;In this article, we’ll explore in depth an advanced veterinary AI workflow based on OrKa, leveraging structured JSON input to orchestrate virtual specialists, integrate diagnoses, and generate personalized action plans. Special attention will be given to observability and traceability of each execution, thanks to detailed reasoning and structured outputs.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. The Context: AI Orchestration in Veterinary Medicine
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1.1. The Complexity of Clinical Cases
&lt;/h3&gt;

&lt;p&gt;A veterinary clinical case can involve multiple symptoms, a detailed clinical history, diagnostic test results, living environment, and owner concerns. Effectively managing this data is essential for accurate diagnosis and effective therapeutic planning.&lt;/p&gt;

&lt;h3&gt;
  
  
  1.2. The Role of AI Orchestration
&lt;/h3&gt;

&lt;p&gt;An AI orchestrator like OrKa enables you to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Coordinate multiple specialist agents (internal medicine, surgery, infectious diseases, dermatology, etc.)&lt;/li&gt;
&lt;li&gt;Propagate structured data between agents, avoiding information loss&lt;/li&gt;
&lt;li&gt;Generate detailed, traceable reasoning for every decision&lt;/li&gt;
&lt;li&gt;Produce structured outputs, easily reviewable and validatable&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  2. The Clinical Case: Structured Data as a Starting Point
&lt;/h2&gt;

&lt;h3&gt;
  
  
  2.1. Representing the Case in JSON
&lt;/h3&gt;

&lt;p&gt;Let’s imagine managing a case of acute lameness in a dog. The clinical data is collected in a JSON file, faithfully representing the case’s complexity:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"species"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Canine"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"breed"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Border Collie"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"age"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"sex"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Male"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"weight_kg"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;18.3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"presenting_complaint"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Acute lameness"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"symptoms"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Lameness"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"onset"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2 days ago"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"severity"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"severe"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"progression"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"sudden"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Joint swelling"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"onset"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2 days ago"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"severity"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"moderate"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"progression"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"acute"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"history"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"chronic_diseases"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"allergies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"previous_treatments"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"vaccination_status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Up to date"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"recent_travel"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"contact_with_other_animals"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"environment"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"living"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Outdoor mostly"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"diet"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Commercial dry food"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"exposures"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"Fields"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Other dogs"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"owner_concerns"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Dog is reluctant to walk."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"test_results"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"cbc"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Mild neutrophilia"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"biochemistry"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Normal"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"radiographs"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Osteolytic lesion on femur"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"joint_fluid_analysis"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Inflammatory, no bacteria"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  3. Orchestration: Virtual Specialists in Synergy
&lt;/h2&gt;

&lt;p&gt;The OrKa YAML workflow allows you to orchestrate several AI “specialists,” each focused on a specific aspect of the case. Each agent accesses structured data directly via Jinja2 templates, for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;prompt&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
  &lt;span class="s"&gt;Act as a veterinary internal medicine specialist. Focus ONLY on collecting and interpreting the patient's history and clinical signs.&lt;/span&gt;
  &lt;span class="s"&gt;Patient data: {{ get_input() }}&lt;/span&gt;
  &lt;span class="s"&gt;Output: HISTORY_SUMMARY: &amp;lt;summary&amp;gt;, KEY_CLINICAL_SIGNS: [&amp;lt;sign1&amp;gt;, &amp;lt;sign2&amp;gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  4. Workflow Execution: Detailed and Traceable Reasoning
&lt;/h2&gt;

&lt;p&gt;The workflow is executed via CLI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;orka run examples/workflow_v2_specialist_linear.yaml examples/inputs/input_case_15.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each agent produces detailed reasoning, which is propagated and tracked throughout the workflow. Intermediate and final reasoning are saved and reviewable, ensuring observability and auditability.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. Observable Reasoning: Real Output Example
&lt;/h2&gt;

&lt;p&gt;Here is a concrete example of a final reasoning, generated by the OrKa veterinary AI workflow, showing the depth, traceability, and actionability of the output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;diagnosis&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Osteosarcoma&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;of&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;the&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;distal&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;femur&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;a&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;malignant&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;bone&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;tumour&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;presenting&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;as&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;an&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;osteolytic&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;lesion&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;with&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;acute&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;lameness,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;joint&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;swelling,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;mild&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;neutrophilia,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;and&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;inflammatory&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;joint&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;fluid.&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;The&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;imaging&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;and&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;laboratory&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;findings&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;are&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;highly&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;suggestive&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;of&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;a&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;primary&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;bone&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;malignancy&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;rather&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;than&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;a&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;simple&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;inflammatory&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;process.&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Osteosarcoma&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;is&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;the&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;most&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;common&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;malignant&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;bone&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;tumour&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;in&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;young,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;athletic&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;breeds&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;such&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;as&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Border&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Collies&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;and&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;often&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;presents&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;with&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;sudden,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;severe&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;lameness&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;and&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;a&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;lytic&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;lesion&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;on&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;radiographs.'&lt;/span&gt;

&lt;span class="na"&gt;differentials&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Osteomyelitis&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Benign bone cyst (e.g., simple bone cyst, aneurysmal bone cyst)&lt;/span&gt;

&lt;span class="na"&gt;specialist_reasoning&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Orthopedics:&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;The&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;radiographic&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;appearance&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;of&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;a&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;well-defined&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;osteolytic&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;area&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;with&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;periosteal&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;reaction&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;strongly&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;points&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;to&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;a&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;neoplastic&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;process;&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;a&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;biopsy&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;is&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;essential&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;for&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;definitive&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;diagnosis.&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Oncology:&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Osteosarcoma&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;prognosis&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;depends&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;on&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;early&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;detection&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;and&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;surgical&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;removal;&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;staging&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;with&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;CT/MRI&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;is&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;recommended&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;if&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;confirmed.&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Internal&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Medicine:&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Mild&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;neutrophilia&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;and&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;inflammatory&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;joint&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;fluid&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;suggest&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;a&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;possible&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;infectious&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;or&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;inflammatory&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;component,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;but&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;lack&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;of&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;bacteria&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;on&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;culture&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;reduces&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;the&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;likelihood&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;of&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;osteomyelitis.&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Preventive&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Medicine:&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Outdoor&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;exposure&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;and&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;contact&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;with&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;other&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;dogs&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;increase&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;risk&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;of&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;vector-borne&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;infections,&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;which&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;should&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;be&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;ruled&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;out.&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Veterinary&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Nutrition:&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Adequate&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;protein&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;and&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;omega-3&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;fatty&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;acids&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;support&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;healing&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;and&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;reduce&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;inflammation.'&lt;/span&gt;

&lt;span class="na"&gt;action_plan&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|-&lt;/span&gt;
  &lt;span class="s"&gt;1. **Immediate Pain Control (Vet)**&lt;/span&gt;
     &lt;span class="s"&gt;- Carprofen 4.4 mg/kg PO q24h (max 4.4 mg/kg) for 4-6 weeks, tapering as pain improves.&lt;/span&gt;
     &lt;span class="s"&gt;- Tramadol 1-2 mg/kg PO q8-12h PRN for breakthrough pain.&lt;/span&gt;
     &lt;span class="s"&gt;- Gabapentin 10 mg/kg PO q12h for neuropathic component.&lt;/span&gt;
     &lt;span class="s"&gt;- Subcutaneous 0.9 % NaCl 5-10 mL/kg if dehydration noted.&lt;/span&gt;
  &lt;span class="s"&gt;2. **Diagnostic Confirmation (Vet)**&lt;/span&gt;
     &lt;span class="s"&gt;- Core needle biopsy of the femoral lesion under sterile conditions; send for histopathology, cytology, and culture.     &lt;/span&gt;
     &lt;span class="s"&gt;- If joint fluid culture remains negative, perform a repeat culture if clinical suspicion persists.&lt;/span&gt;
  &lt;span class="s"&gt;3. **Owner Instructions (Owner)**&lt;/span&gt;
     &lt;span class="s"&gt;- Strict activity restriction: no running, jumping, or prolonged walking; use a sling or padded crate for support.       &lt;/span&gt;
     &lt;span class="s"&gt;- Monitor temperature, appetite, and lameness daily; call clinic if fever &amp;gt;39.5 °C, swelling increases, or pain worsens. &lt;/span&gt;
     &lt;span class="s"&gt;- Provide a high-protein, moderate-fat diet; consider omega-3 supplements (e.g., fish oil 200-300 mg/kg/day).&lt;/span&gt;
     &lt;span class="s"&gt;- Keep a log of daily temperature, appetite, and a 0-10 lameness score.&lt;/span&gt;
  &lt;span class="s"&gt;4. **Follow-Up (Vet)**&lt;/span&gt;
     &lt;span class="s"&gt;- Re-evaluate in 3 days: physical exam, lameness assessment, CBC, biochemistry.&lt;/span&gt;
     &lt;span class="s"&gt;- If biopsy confirms osteosarcoma: refer to veterinary oncologist for staging (CT/MRI, bone scan) and discuss amputation or limb-sparing surgery.&lt;/span&gt;
     &lt;span class="s"&gt;- If biopsy indicates osteomyelitis: initiate Amoxicillin-Clavulanate 12.5 mg/kg PO q12h for 10-14 days; adjust per culture results.&lt;/span&gt;
  &lt;span class="s"&gt;5. **Long-Term Management (Vet &amp;amp; Owner)**&lt;/span&gt;
     &lt;span class="s"&gt;- Continue NSAID for the full course unless contraindicated; taper gradually.&lt;/span&gt;
     &lt;span class="s"&gt;- Consider a short course of low-dose prednisone (0.5 mg/kg PO q24h) if severe inflammation persists and infection is ruled out.&lt;/span&gt;
     &lt;span class="s"&gt;- Schedule imaging (radiographs or CT) every 4-6 weeks to monitor lesion progression.&lt;/span&gt;
     &lt;span class="s"&gt;- Post-amputation: provide analgesia, wound care, and physiotherapy.&lt;/span&gt;
     &lt;span class="s"&gt;- If non-surgical, discuss palliative options (radiation, chemotherapy) and quality-of-life measures.&lt;/span&gt;
  &lt;span class="s"&gt;6. **Additional Considerations**&lt;/span&gt;
     &lt;span class="s"&gt;- Maintain up-to-date vaccinations and routine preventive care.&lt;/span&gt;
     &lt;span class="s"&gt;- Use flea/tick prevention to reduce vector-borne disease risk.&lt;/span&gt;
     &lt;span class="s"&gt;- Seek emergency care if systemic signs (lethargy, vomiting, collapse) appear.&lt;/span&gt;

&lt;span class="na"&gt;owner_instructions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|-&lt;/span&gt;
  &lt;span class="s"&gt;1. **Activity**: Keep your dog confined to a small area; avoid stairs and rough terrain.&lt;/span&gt;
  &lt;span class="s"&gt;2. **Pain Monitoring**: Check for vocalization, reluctance to move, or changes in gait; report immediately.&lt;/span&gt;
  &lt;span class="s"&gt;3. **Temperature**: Use a rectal thermometer; any reading &amp;gt;39.5 °C warrants a clinic visit.&lt;/span&gt;
  &lt;span class="s"&gt;4. **Diet**: Feed the recommended portion of the commercial dry food; add a small amount of fish oil if advised.&lt;/span&gt;
  &lt;span class="s"&gt;5. **Log**: Record daily temperature, appetite, water intake, and a lameness score (0 = normal, 10 = severe). Bring this log to each appointment.&lt;/span&gt;
  &lt;span class="s"&gt;6. **Follow-Up**: Attend all scheduled visits; bring any new or worsening signs to the clinic promptly.&lt;/span&gt;
  &lt;span class="s"&gt;7. **Emergency**: If your dog shows sudden collapse, severe pain, or signs of systemic illness, go to an emergency clinic immediately.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  6. Observability and Traceability: Every Decision is Transparent
&lt;/h2&gt;

&lt;p&gt;OrKa produces detailed logs for every execution, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Generated prompts&lt;/strong&gt;: each agent receives a prompt that includes structured data and previous agent responses.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Intermediate outputs&lt;/strong&gt;: every reasoning produced by agents is saved and can be reviewed later.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Decision tracking&lt;/strong&gt;: it’s possible to reconstruct the entire decision path, from initial data to final diagnosis.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each execution is tracked with a Trace ID; intermediate reasoning and final outputs are accessible for audit, training, or continuous improvement.&lt;/p&gt;




&lt;h2&gt;
  
  
  7. Conclusion: Transparent, Traceable, and Robust AI Orchestration
&lt;/h2&gt;

&lt;p&gt;Adopting structured JSON input and observable reasoning in OrKa allows you to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Manage complex clinical cases&lt;/strong&gt; with rich, structured data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Orchestrate virtual specialists&lt;/strong&gt; in a transparent and traceable way.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Produce detailed reasoning&lt;/strong&gt; for every decision, facilitating audit, training, and continuous improvement.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Generate actionable, validatable outputs&lt;/strong&gt;, ready for clinical use or integration with other systems.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Announcement: OrKa Reasoning 0.9.9
&lt;/h2&gt;

&lt;p&gt;All this is now possible thanks to the new version of OrKa Reasoning (0.9.9), which introduces:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Official support for structured JSON input&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Robust parsing and advanced error handling&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Detailed logs and traceable reasoning&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Validatable and actionable YAML output&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Learn more at &lt;a href="https://github.com/marcosomma/orka-core" rel="noopener noreferrer"&gt;OrKa Core on GitHub&lt;/a&gt; and start experimenting with your own structured workflows!&lt;/p&gt;




</description>
      <category>ai</category>
      <category>opensource</category>
      <category>programming</category>
      <category>rag</category>
    </item>
  </channel>
</rss>
