Pyyan / Agentic engineering

The discipline, not the directory

Agentic engineering

Building an agent is not choosing a framework. It is nine decisions about control, state, context, tools, safety, measurement and cost, most of which are made badly, early, and only discovered in production. This page is what the people actually shipping these systems have published about each one.

9 phases5 orchestration patterns4 kinds of memory1 unresolved argument

Before anything else

Five composable patterns

A → B → CPrompt chainingThe task decomposes cleanly into fixed subtasks.Trades latency for accuracy by making each call simpler.
→ ◇ → A | B | CRoutingDistinct input categories are better handled separately.Buys separation of concerns and lets each branch be specialised.
→ ⋔ → ⋀ParallelisationSubtasks are independent, or you want several opinions on one thing.Sectioning for speed; voting for confidence.
◉ ⇉ ○ ○ ○Orchestrator–workersYou cannot predict the subtasks in advance.The orchestrator decides the decomposition at runtime, not you.
A ⇄ ✓Evaluator–optimiserClear evaluation criteria exist and iteration measurably helps.Only works if a critic can articulate what is wrong.
01

Problem scoping & boundary definition

Should this be an agent at all?

Most failed agent projects were decided here, before a line of code. The question is not whether an agent could do the job. It is whether anything cheaper could.

Anthropic draws the line at who controls the path. A workflow is LLMs and tools orchestrated through predefined code paths. An agent is a system where the model dynamically directs its own process and tool usage. The distinction is not about sophistication; it is about who decides what happens next.

Agents buy you the ability to handle problems whose steps you cannot enumerate in advance. You pay for that in cost, latency, and compounding error. One wrong step at 95% reliability becomes a 60% success rate over ten steps. If you can enumerate the steps, enumerate them.

Scope is also a safety boundary. An agent that can only read is a different risk class from one that can write, and one that can spend money is different again. Draw that boundary before architecture, because everything downstream inherits it.

You should consider adding complexity only when it demonstrably improves outcomes.
Anthropic, Building effective agents

In practice

  1. Enumerate the steps firstIf you can write the flow as a diagram with no diamonds you cannot resolve, build a workflow. Reach for an agent only where the branching genuinely cannot be known ahead of time.
  2. Set the blast radius before the architectureDecide what the agent may read, write, spend and send at scoping time. These constraints shape tool design, guardrails and the human-approval surface, and retrofitting them is far more expensive.
  3. Define doneAn agent with no terminal condition is a bill, not a product. Specify what success looks like, what the maximum step budget is, and what happens when it is exhausted.
Common failureThe mega-prompt

One prompt, fifty tools, and a hope. Tool selection accuracy collapses as the tool count rises, the context fills with descriptions the model never uses, and every failure is unattributable. This is the single most common shape of a broken agent.

RESOLVABLE · YOU KNOW THE RULEGet invoicetotal > 1000?if (total > 1000)yesSend to approvernoAuto-approveYou know the rule, so youcan encode it.→ BUILD A WORKFLOWUNRESOLVABLE · NOBODY KNOWS YETTest is failingwhat now?read the stack tracecheck a recent commitrun it again in isolation…something not listedThe next step depends on whatthe last one found.→ THIS IS WHERE AN AGENT EARNS ITS COST
Sketch the process as a flowchart, then interrogate every diamond: can I write this condition down in advance? Every diamond you can resolve is a branch you should encode. Only the ones you genuinely cannot draw justify an agent.
Worked example

The trap: “needs an LLM” is not “needs an agent”

A support inbox. You want angry emails escalated to a human and neutral ones auto-acknowledged.

  1. The instinctNo regex can tell angry from neutral, so this must need an agent.
  2. What is actually trueIt needs a model. That is a different claim.
  3. The shape of the flowOne classification call, then a fixed branch. You know exactly where the decision sits and what the possible outcomes are.
  4. SoIt is a resolvable diamond. That is the routing pattern: a workflow with a model inside one step, not an agent.

So: The line is not whether a model is involved. It is whether you know the shape of the path. If you know it, encode it. It will be cheaper, faster, testable, and it cannot wander.

02

Architecture & state modelling

What does the system remember, and where does it live?

This is where most teams conflate two different things. State and memory are not synonyms. Memory is one kind of state, and treating them as the same produces systems that cannot be resumed, replayed or debugged.

State is everything the system needs to continue. It splits in two. Execution state is where the agent is in its own process: the step counter, the pending tool call, the retry count, the current plan. Business state is what the agent has actually done to the world: the row written, the payment sent, the ticket opened.

The twelve-factor agents formulation is to unify execution state and business state, keeping them in one place, in your own data model, rather than letting a framework hide the execution half in memory it will lose on restart. If those two diverge, an agent that crashes mid-run will either forget it sent the email or send it twice.

Memory is different. State is what the agent needs to finish this task. Memory is what it should carry into tasks it has not started yet. Persistent state also includes things that are not memory at all: task ledgers, permissions, commitments, provenance and audit trails.

Getting this wrong is subtle. If you store 'the user prefers metric units' in execution state, it vanishes when the run completes. If you store 'currently retrying step 4' in long-term memory, the agent will resume a task that finished last week.

Execution stateWhere the agent is in its own process.Step index, pending tool call, retry count, current plan, paused-awaiting-human flag. Must be checkpointed to durable storage after every tool invocation.
Business stateWhat the agent has done to the world.Rows written, emails sent, payments made. Owned by your application's real data model, not by the agent framework.
MemoryWhat the agent carries between tasks.A kind of state, but scoped to the user or the domain rather than the run. Four types, below.
Stateless reducerThe agent as a pure function of state.`(state, event) → state`. Makes every run replayable and every bug reproducible. The single highest-leverage architectural choice for debuggability.
Unify execution state and business state. Make your agent a stateless reducer.
12-Factor Agents, factors 5 and 12

In practice

  1. Checkpoint after every tool callPersist graph state to durable storage such as Postgres or Redis after each tool invocation, not at the end of the run. This is what makes a network failure survivable and a paused workflow resumable.
  2. Make actions idempotentReplay is the recovery mechanism, so every side effect must tolerate being attempted twice. Idempotency keys on writes, payments and sends. Without this, checkpointing turns one outage into duplicate charges.
  3. Separate the two clocksApplication-level failure (bad reasoning, wrong branch, human approval pending) and infrastructure-level failure (container crash, network partition) need different machinery. LangGraph checkpointers handle the first; Temporal and its peers handle the second. Production systems usually need both.
Common failureThe framework ate my state

The agent works until the process restarts, then resumes from nothing or from the wrong place. Almost always because execution state lived in a framework's in-memory object rather than in a table you own.

Execution stateWhere the agent is in its own processstep: 4 of 9pending: send_emailretries: 1awaiting_human: falseDIES WHEN THE TASK FINISHESBusiness stateWhat it has done to the worldinvoice_1042.status = sentpayment_88.captured = trueaudit_log += 3 rowsOUTLIVES THE AGENT ENTIRELYMemoryWhat it carries to the next taskprefers metric unitsbilling contact = Anuapproves under ₹5,000SCOPED TO A USER, NOT A RUNPut a preference in execution state and it vanishes when the run ends.Put a retry counter in memory and the agent resumes a task that finished last week.
One agent chasing an unpaid invoice, its state pulled apart. Memory is a kind of state, but it is the only column scoped to the person rather than the run.
Worked example

What a crash costs when state is in the wrong place

An agent chasing an unpaid invoice. Step 4 of 9 is send_email. The container is preempted mid-step.

State in the framework's memory
1. send_email(#1042) → delivered ✓
2. container dies before anything is written
3. restart → step counter is gone, run restarts at 1
4. send_email(#1042) → delivered again
→ the customer gets two emails, and you cannot prove why
State checkpointed after every tool call
1. write { step: 4, pending: send_email, key: inv-1042-r1 }
2. send_email(#1042, idempotency_key: inv-1042-r1) → delivered ✓
3. write { step: 5, pending: null }
4. container dies → restart reads step 5 and carries on
→ and if it died between 2 and 3, the key makes the resend a no-op

So: Checkpointing alone is not enough. Replay is the recovery mechanism, so every side effect has to tolerate being attempted twice. The idempotency key is what turns a crash into a resume instead of a duplicate charge.

03

Memory

What should survive this conversation, and in what form?

Memory is not a database you bolt on. It is a decision about what is worth remembering, made repeatedly, under a budget, and the hard part is not storage but consolidation and forgetting.

The useful taxonomy is borrowed from cognitive science and has held up well in practice: working, episodic, semantic and procedural. They differ in what they hold, how long they live, and, critically, how they are written.

Working memory is written by the agent loop and thrown away. Episodic memory is written by logging what happened. Semantic memory is not written directly at all. It is produced by consolidation, where the agent processes its episodes, finds repeated patterns, extracts entities and relationships, and distils them into reusable facts.

The failure everyone hits is temporal. Facts change. 'The customer is on the enterprise plan' was true in March and false in June, and a vector store that returns both with equal confidence has made the agent worse, not better. This is why the strongest systems model when a fact was true, not just that it was.

The benchmark that separates these is LongMemEval, which tests recall of facts that change over time. Zep's Graphiti backend scores 63.8% against Mem0's 49.0%, a fifteen-point gap on exactly the capability most production agents actually need.

ConsolidationTurning episodes into facts.The agent reads its own history, finds patterns, and writes distilled semantic memory. Without it, memory grows without becoming more useful.
Temporal validityWhen a fact was true.A bi-temporal model records both when something happened and when the system learned it, which is the difference between a memory store and a knowledge graph.
ForgettingA feature, not a leak.Staleness policies and decay. An agent that remembers everything eventually retrieves noise, and retrieval quality falls as the store grows.
Structured note-takingMemory the agent writes itself.Anthropic's term for an agent persisting notes outside the context window and reading them back: persistent memory with minimal machinery.
The agent maintains precise tallies across thousands of game steps… after context resets, reading its own notes enables continuation of multi-hour sequences.
Anthropic, on structured note-taking

In practice

  1. Decide the write policy before the storeWhat earns a memory? Every turn is too much; explicit user instruction only is too little. Most working systems write on task completion and on explicitly stated preferences, then consolidate on a schedule.
  2. Scope memory to an ownerUser, org, or agent. Memory without an owner leaks between tenants, which is a security incident rather than a quality problem.
  3. Test retrieval, not storageIt is easy to build a memory system that stores everything and retrieves the wrong thing. Evaluate on questions whose answers changed over time. That is where naive vector recall fails.
Common failureThe memory landfill

Every turn written to a vector store, nothing consolidated, nothing expired. Retrieval quality degrades as the corpus grows, so the agent gets measurably worse the longer a customer uses it, the opposite of the intended effect.

ONE AGENT, CHASING ONE UNPAID INVOICEWorkingGone at session end, correctly.“The invoice I am looking at right now is #1042.”EpisodicA thing that happened, with a date.“On 3 June I emailed Anu about #1042 and she asked for a PO number.”SemanticDistilled from many episodes.“This customer always requires a PO number before paying.”ProceduralA learned way of working.“For this customer: get the PO first, then invoice, then chase on day 14.”consolidation
Semantic memory is the one you cannot write directly. It is produced by consolidation: the agent reading its own episodes and distilling the pattern. Skip that step and you have a log, not a memory.
Worked example

The fact that changed

In March the customer was on the Pro plan. In June they upgraded to Enterprise. In August the agent is asked what support tier they get.

Naive vector recall
query → “what plan is this customer on?”
0.91  “Customer is on the Pro plan.”      (March)
0.89  “Customer upgraded to Enterprise.”  (June)
→ both are similar, both come back, neither is dated
→ the agent picks the higher score and answers Pro
Temporal knowledge graph
plan(customer_88) = Pro          valid Mar 02 → Jun 14
plan(customer_88) = Enterprise   valid Jun 14 → now
→ query at t = today returns exactly one fact
→ and the March answer is still there if you ask about March

So: This is why LongMemEval exists and why the gap on it is fifteen points. Most production memory questions are not “what do you know” but “what is true now”, and similarity search has no opinion about time.

The four kinds, and how they differ

KindHorizonWhat it holdsWhen it should dieExample
WorkingThis turnThe current task, recent turns, the scratchpad.When the session ends, and that is correct behaviour, not a bug.The file the agent is currently editing.
EpisodicSpecific past eventsSequences of what the agent actually did, and what happened.Never, but it must be consolidated or it becomes a landfill.“Last Tuesday approach X failed on client Y because of Z.”
SemanticTimeless factsFacts about the world and the user, distilled from episodes.When superseded, which is why temporal validity matters.“This customer is on the enterprise plan.”
ProceduralLearned skillHow to do a thing: the agent's repertoire of effective actions.When the underlying system changes and the skill goes stale.“The optimal sequence for booking travel in this system.”

Working memory is written by the loop. Episodic is written by logging. Semantic is not written directly at all. It is produced by consolidation from episodes. Procedural is the one almost nobody implements, and the one that makes an agent get better at a job rather than merely remember it.

04

Context engineering

What goes into the window on this call, and what comes out?

Context engineering superseded prompt engineering for anything long-horizon. Prompt engineering is discrete: you write instructions once. Context engineering is a loop that owns the entire token lifecycle, from the first system prompt token to the last compacted summary.

The premise is that context is a finite resource with diminishing marginal returns. Anthropic frames it as an attention budget: every token spends from a limited pool. The architecture explains why. A transformer computes n² pairwise relationships for n tokens, and models have seen far fewer long sequences in training than short ones.

The observable consequence is context rot: as the window grows, recall of what is inside it falls. Not a cliff at the limit, a gradient from the beginning, with a well-documented 'lost in the middle' effect. A million-token window is a budget, not a promise.

So the goal is the smallest set of high-signal tokens that produces the outcome. Three techniques carry long-horizon work, and they are chosen by task shape rather than ranked.

Compaction summarises the trajectory and restarts the window with the summary. Tune it by first maximising recall, then trimming for precision. Structured note-taking writes state outside the window entirely. Sub-agents give each subtask a clean window and return 1,000–2,000 token summaries to a lead agent.

Attention budgetTokens are spent, not stored.Every token in the window competes for the same finite attention. Adding context has a cost even when the context is correct.
Context rotRecall degrades as the window fills.Measurable from early in the window, not at the limit. Information in the middle suffers most.
CompactionSummarise and restart.Preserve architectural decisions, unresolved bugs and implementation details; discard redundant tool output. Clearing old tool results is the cheapest version.
System prompt altitudeNeither brittle nor vague.Hardcoded if/else logic in prose is fragile; high-level platitudes give no signal. Aim for specific enough to guide, flexible enough to generalise.
Find the smallest possible set of high-signal tokens that maximize the likelihood of some desired outcome.
Anthropic, Effective context engineering

In practice

  1. Cache before you compressPrompt caching gives the best effort-to-result ratio available and changes nothing about output quality. Exhaust it before reaching for lossy compression.
  2. Structure the prompt in sectionsDistinct blocks for background, instructions and tool guidance, delimited with XML tags or Markdown headings. Then cut to the minimal set that fully specifies the behaviour.
  3. Use examples as pictures, not an edge-case listA few diverse canonical examples outperform an exhaustive catalogue of special cases, which mostly spends budget.
Common failureThe million-token dump

The whole repository, the whole conversation, every tool result retained forever, on the theory that a large window makes curation unnecessary. Accuracy falls while the bill rises, and because nothing errors, the degradation is invisible without evals.

Turn 112%
System prompt, tools, the task.
Turn 4055%
Forty tool results, most now dead weight.
Turn 9094%
Recall is already falling. Nothing has errored.
Compacted22%
Decisions kept, raw output discarded.
LIMIT
Nothing throws an error at 94%. The model simply gets worse at recalling what is already in front of it, which is why context rot is usually found by an eval, or by a user, and almost never by a log.
Worked example

What compaction keeps, and what it throws away

A coding agent, ninety turns into a refactor, about to hit the window. It has to be reduced to a summary it can keep working from.

Keep: decisions and open state
we chose Postgres over Redis for the queue, because ordering matters
auth middleware moved to lib/auth.ts, 3 imports still to update
the flaky test is a real race in the pool, not a test bug
the user asked for British spelling throughout
Discard: recoverable or spent
the full text of 40 files we read and did not change
12 successful test runs that told us nothing new
the directory listing, four times
our own intermediate reasoning that led nowhere

So: The test for keeping a line is not “was this important?” but “would losing it change what happens next?” Tune the prompt for recall first, missing nothing, then trim for precision. A file can be re-read; a decision cannot be recovered.

05

Tool & schema engineering

What can the agent actually do, and how well is it described?

Tools are the agent's entire causal surface on the world. Anthropic calls this the agent–computer interface and argues it deserves as much design effort as a human-computer interface. Most teams give it almost none.

The first rule is that tools are not an API wrapper. Wrapping every endpoint one-to-one produces a large, flat, ambiguous surface. Consolidate instead: replace list_users, list_events and create_event with a single schedule_event; collapse get_customer_by_id, list_transactions and list_notes into get_customer_context. More tools do not lead to better outcomes.

The second is that tools should return meaning, not data. Prioritise contextual relevance over completeness, and prefer name and file_type to uuid and mime_type, because models handle natural-language identifiers markedly better than cryptic ones. A tool that returns a raw 40-field JSON row has pushed its work into the context window.

The third is token discipline at the boundary. Pagination, filtering, range selection and truncation with sensible defaults. Claude Code caps tool responses at 25,000 tokens by default; when you truncate, say so in the response and tell the agent how to get the rest.

And descriptions are prompt engineering, among the highest-leverage work available. Write them as you would brief a new hire: state the query format, define the terminology, explain how resources relate. Small refinements here produce disproportionate gains.

Agent–computer interfaceThe tool surface as a design artefact.The ACI is to an agent what a UI is to a person. It deserves iteration, user testing and evaluation.
NamespacingPrefixes that draw boundaries.`asana_search` vs `jira_search`. Anthropic reports that prefix-versus-suffix choice alone has non-trivial effects on tool-use evals.
Structured outputA tool call is just JSON.Not magic, but a schema the model fills and deterministic code executes. Treating it that way makes validation and testing ordinary.
Error as instructionFailures should teach.Return what to do differently, not an opaque code. The error message is a prompt the agent will act on.
If a human engineer can't definitively say which tool should be used in a given situation, an AI agent can't be expected to do better.
Anthropic, Effective context engineering

In practice

  1. Two to five tools per agentSpecialised sub-agents with a small focused tool set, coordinated by a router, beat one agent holding everything. This is the direct antidote to the mega-prompt.
  2. Evaluate tools like codeGenerate realistic multi-tool tasks, then measure accuracy, runtime, tool-call count, token consumption and error rate. Read the transcripts for what the agent failed to do, not only what it said.
  3. Name parameters unambiguously`user_id`, not `user`. Ambiguity in a parameter name is resolved by guessing, and the guess is silent.
Common failureThe overlapping pair

Two tools whose descriptions do not clearly separate them. The agent picks inconsistently, evals look noisy rather than broken, and the cause is invisible until someone reads the descriptions side by side.

WRAPPING THE API · 10 TOOLSlist_usersget_user_by_idlist_calendarslist_eventsget_eventcreate_eventupdate_eventcheck_availabilitylist_roomsbook_roomWhich one books a meeting?Four of them, in the right order.SELECTION ACCURACY FALLS AS THE LIST GROWSSHAPED LIKE THE TASK · 2 TOOLSschedule_eventfinds people, checks free time, books the roomget_customer_contextprofile, recent orders and open tickets in one callOne call, one obvious choice, andthe orchestration lives in your code.THE TOOL IS THE INTERFACE, NOT THE ENDPOINT
A tool is not an API wrapper. If a human engineer cannot say with certainty which of your tools to reach for, the model has no chance either.
Worked example

Two words that changed the eval score

A search tool the agent kept misusing, calling it with natural-language questions and getting nothing back.

Before
search(query: string)
"""Search for documents."""
→ agent calls search("what did Anu say about the Q3 budget")
→ 0 results. The index only matches keywords.
After
search(query: string, author?: string, after?: date)
"""Keyword search over documents. Not semantic.
  pass 2–4 keywords, not a question. To narrow by
  person use `author`, not the query string.
  Example: search("Q3 budget", author="Anu")"""
→ agent calls it correctly on the first try

So: Nothing about the implementation changed. Writing the description the way you would brief a new hire, saying what it is not, naming the format and showing one example, is among the highest-leverage work available, and almost nobody does it.

06

Guardrails & runtime safety

What stops it, and who has to say yes?

Guardrails are not a content filter bolted on at the end. They are the runtime expression of the blast radius you drew during scoping, and the most effective one is not a model at all.

The highest-value rule is determinism first, model second. Use ordinary code for anything with a static control flow, meaning routing, validation and permission checks, and spend model calls only on genuinely non-deterministic judgement and natural-language understanding. Every decision moved out of the model is a decision that cannot hallucinate.

The second is the human-in-the-loop gateway: an approval breakpoint before any state-mutating action. Database writes, payments, outbound email. Twelve-factor agents makes the elegant point that this should be a tool call like any other. The agent requests a human the same way it requests a search, which keeps one control flow rather than two.

Then the layered defences. Input classifiers for prompt injection, output rails for what got through, and identity controls treating each agent as a non-human identity with scoped, time-bound, least-privilege credentials rather than standing access.

One caution about the pattern people reach for first. Having a model check a model is weaker than it sounds: LLMs do not reliably self-correct reasoning without external feedback, and self-correction can degrade results. Multi-agent debate barely outperforms plain self-consistency at equal token cost. What does work is grading steps rather than outcomes: process reward models, where an agentic verifier at 4B parameters beat state-of-the-art outcome models by 25%.

HITL gatewayApproval before mutation.A breakpoint before writes, payments and sends. Implemented as a tool call so pause and resume use the same machinery as everything else.
Least-privilege agent identityThe agent is a principal.Scoped, time-bound credentials granted for the task window, replacing standing access. An agent is a non-human identity and should be governed as one.
Input & output railsTwo checkpoints, not one.Classifiers screen incoming injection attempts; output rails catch the cases where an injection succeeded.
Process vs outcome rewardGrade the steps, not the answer.Outcome models say the answer was wrong; process models say which step went wrong. The difference is worth roughly 25% in reported verifier accuracy.
LLMs cannot self-correct reasoning yet. Without external feedback, self-correction can degrade performance.
Huang et al., ICLR

In practice

  1. Move every static decision into codeIf the branch condition can be expressed as a boolean over known fields, it does not belong in a prompt. This is the cheapest reliability win available and it compounds.
  2. Gate on mutation, not on risk scoreApproval triggers should key off whether an action changes the world, which is a property you can check statically, rather than a model's estimate of how dangerous it is.
  3. Budget the latency of judgesA model-as-judge in the request path adds hundreds of milliseconds. Use cheap classifiers inline and reserve model judgement for asynchronous evaluation.
Common failureThe self-grading agent

An agent asked to check its own work, reporting high confidence in wrong answers. Self-assessment without external signal mostly measures fluency. Anything that matters needs an independent check: a test suite, a deterministic validator, or a human.

A REFUND AGENT · WHERE EACH DECISION BELONGSIs the refund under ₹2,000?CODEA number and a threshold.Has this order already been refunded?CODEA database lookup.Is the customer within the 30-day window?CODETwo dates.Is this complaint about damage or delay?MODELLanguage, not logic.Does this photo show the damage described?MODELGenuine judgement.Should we refund this?HUMANIt mutates money.Three of six never reach the model. Each one is a decision that cannot hallucinate.
Determinism first, model second. Move every decision you can express as a boolean into code. It is the cheapest reliability you will ever buy, and it compounds.
Worked example

The approval gate as a tool call

The refund agent has decided a refund is warranted. It must not issue one unsupervised.

Two control flows
if (action.mutates) { pauseAgent(); notifyHuman(); /* … */ }
→ a second code path for pause, resume, timeout and rejection
→ which is separately tested, separately broken
One control flow
tools = [search_orders, issue_refund, ask_human]
ask_human({ question: "Refund ₹4,200 on #8812, damaged in transit?",
           options: ["approve", "reject"], evidence: [photo_url] })
→ the agent already knows how to wait for a tool result
→ pause, resume and timeout are the machinery you already have

So: Contact humans with tool calls. The agent asking a person is not a special case in the runtime. It is a tool that happens to be slow, and modelling it that way removes an entire parallel code path.

07

Evals & systematic benchmarking

How do you know a change made it better?

Without evals you are not engineering, you are redecorating. Agents fail probabilistically and silently. The same prompt passes on Monday and fails on Thursday, so intuition about whether a change helped is worthless at this error rate.

Build the eval set from real traces, not imagined ones. The failures that matter are the ones your users already hit, and production traces are the cheapest source of hard cases you will ever have. This is why observability and evaluation converged into the same products.

Measure more than accuracy. A change that improves task success while tripling tool calls and doubling tokens may be a regression once it meets a bill. Track accuracy, runtime, tool-call count, token consumption and error frequency together.

Then wire it into CI. Braintrust's GitHub Action runs evals on every commit and can block a merge on a quality threshold, treating prompts and tool descriptions as code that can regress, because they are.

Public benchmarks are for calibration, not for your product. SWE-bench Verified for real bug fixes, τ²-bench for tool-agent-user interaction and policy adherence, Terminal-Bench for command-line work, OSWorld for computer use, GAIA for general assistance. As of April 2026, state of the art ran from the high 30s on OSWorld to the mid 70s on SWE-bench Verified, worth knowing before you promise reliability.

Trace-derived evalTest cases mined from production.The failures that already happened, frozen into regression tests. Higher value per case than anything synthesised.
LLM-as-judgeA model grades an output.Useful offline and at scale; unreliable as the only signal, and expensive in the request path.
Held-out setCases the prompt never saw.Prompt optimisation overfits to its eval set exactly as training overfits to training data.
Regression gateQuality thresholds in CI.A prompt change is a code change. If it can regress the product, it should be able to fail the build.

In practice

  1. Start the eval set on day oneTwenty real cases beat two hundred invented ones. Grow it from every production failure. A bug that was never turned into a test case will happen again.
  2. Evaluate the agent, not the modelYour system is a prompt, a tool surface, a context policy and a model. Swapping the model without re-running evals tells you nothing about the system you actually ship.
  3. Watch cost as a first-class metricToken consumption and tool-call count belong on the same dashboard as accuracy. Most quality regressions in production are actually cost regressions nobody was measuring.
Common failureVibes-based iteration

A prompt tweaked until a handful of hand-tested examples look good, shipped, then quietly worse in aggregate. Without a held-out set there is no way to distinguish improvement from overfitting to the three cases you kept trying.

Worked example

A bug becomes a test

A user reports the agent refunded the wrong order. You have the trace. Most teams fix the prompt and move on. This is the step they skip.

  1. 1 · Freeze the inputPull the exact user message and the account state at that moment out of the trace. Not a paraphrase. The real one, including the typo.
  2. 2 · Assert on the action, not the wordsThe test is not “mentions order 8815”. It is `issue_refund` called with `order_id == 8815`, or not called at all. Text assertions on model output are how eval suites become flaky.
  3. 3 · Add the near-missThe same query where two orders genuinely match. The fix must handle ambiguity, not just this one case.
  4. 4 · Gate the mergeWire it into CI. A prompt change is a code change, and if it can regress the product it should be able to fail the build.

So: Twenty cases mined from real failures beat two hundred invented ones. A bug that was never turned into a test case is a bug you have agreed to ship again.

08

Observability & production monitoring

When it fails at 3am, can you tell why?

An agent failure is not a stack trace. It is a decision that looked reasonable at every individual step and was wrong in aggregate, so the unit of debugging is the trace, not the log line.

The trace is the primary object: nested spans across the agent loop, every model call, every tool invocation, every retrieval, with inputs, outputs, latency and token counts attached. Anything less and you are guessing which of forty steps went wrong.

The layer standardised faster than most people expect. OpenTelemetry GenAI semantic conventions mean instrumenting once and switching backends later, a genuinely unusual property in a market this young, and worth exploiting rather than betting on a vendor.

Cost monitoring is not a separate discipline. Token spend per route, per model, per tenant belongs on the same trace as latency and quality, because in agent systems those three trade against each other continuously and a win in one is often a loss in another.

Close the loop deliberately: production traces become eval cases, eval failures become regression tests, regression tests gate deploys. Observability that only produces dashboards is a cost centre; observability that feeds the eval set is how the system improves.

SpanOne step, nested in its parent.A model call, a tool invocation, a retrieval. Nesting is what makes a forty-step run legible.
OTel GenAI conventionsA portable trace format.Standard attribute names for model calls and tool use, so instrumentation outlives your vendor choice.
Online evalScoring live traffic.Evaluation scores attached to production traces, not only to an offline suite. It is the only way to catch drift.
Cost attributionSpend per tenant, route and model.Agent cost is emergent, not designed. A retry loop can multiply a bill without any code change.

In practice

  1. Instrument to OpenTelemetry, not to a vendor SDKThe GenAI conventions are stable enough to build on, and this layer is consolidating fast. Four notable vendors were acquired or shut in the last eighteen months.
  2. Trace before you scaleRetrofitting tracing onto a running agent is far harder than starting with it, because the interesting failures are the rare ones and you cannot reconstruct a trace you did not record.
  3. Alert on cost derivatives, not totalsA daily total tells you after the fact. A spike in tokens per successful task tells you an agent has started looping while the bill is still small.
Common failureLogs without traces

Every model call logged, no parent-child relationship between them. You can see that step 31 returned nonsense but not which planning decision twelve steps earlier caused it, and reconstructing that by hand is where the night goes.

ONE TRACE · THE FAILURE IS NOT WHERE THE ERROR ISrun refund_agent18.4splan1.2stool search_orders("jacket")returned 200 rows, truncated at 500.4stool get_order(#8812)wrong order, the right one was row 910.3s…28 further steps14.1stool issue_refund(#8812)refunded the wrong purchase0.9sThe refund at step 31 was caused by a silent truncation at step 3.
No step threw. Every individual decision looked reasonable. Without the parent-child structure of a trace you would be reading thirty-one correct-looking log lines.
Worked example

The bill that tripled with no deploy

Monday's spend is ₹4,100. Thursday's is ₹12,800. Nothing shipped in between.

  1. What the daily total saysCosts are up 3×. It tells you this on Friday, after the money is gone.
  2. What tokens-per-successful-task says18k on Monday, 61k on Thursday. Same number of users, same success rate.
  3. What the trace saysOne tool started returning a 400 with an empty body. The agent could not tell it had failed, so it retried, and the retry loop is inside the agent, invisible to any request counter.
  4. The fix, and the lessonReturn an actionable error. But the reason it was caught on Thursday and not Friday is that the alert watched the derivative, not the total.

So: Agent cost is emergent, not designed. No code changed; a dependency did. Alert on tokens per successful task and you find it while the bill is still small.

09

Optimisation & self-improvement

Can the system get better without you rewriting it?

The newest phase, and the least settled. The premise is that prompts, tool descriptions and context policies are parameters, and parameters can be optimised rather than hand-tuned.

DSPy started this by treating a prompt as a compiled artefact: declare the signature, supply examples and a metric, and let an optimiser such as MIPROv2 search the prompt space. You stop writing prompts and start specifying objectives.

GEPA sharpened it considerably. Rather than optimising against a scalar score, it reads the full execution trace, diagnoses failures in natural language, assigns credit, and evolves the prompt from that reflection. It reports beating reinforcement-learning methods such as GRPO and prompt optimisers such as MIPROv2 by 10–20% accuracy with up to 35× fewer rollouts, which matters because rollouts are the expensive part.

Agentic Context Engineering (ACE) applies the same reflective idea to the context itself, making localised updates rather than repeated full rewrites, and reports ReAct + ACE outperforming baselines by an average of 10.6%.

Below that sits reinforcement fine-tuning, where the bottleneck has moved. With GRPO and RLOO now standard for reasoning models, wall-clock training time is governed by how fast your environment produces verified rollouts, not by GPU count. Prime Intellect's Environments Hub exists for exactly this reason and carries 2,500+ community environments.

Prompt as parameterSearch, don't hand-tune.Declare the objective and let an optimiser find the wording. Requires a metric, which is why this phase depends entirely on the previous one.
Reflective evolutionLearn from traces, not scores.GEPA's move: read why it failed in natural language, then propose a targeted change. Far more sample-efficient than scalar reward.
Verifiable environmentA task with a checkable answer.The unit of agent RL. Environment throughput, not GPU count, now sets training wall-clock.
Up to 10–20% higher accuracy than GRPO, with as much as 35× fewer rollouts.
GEPA, reflective prompt evolution

In practice

  1. Do not optimise before you can measureEvery optimiser here needs a metric and a held-out set. Applied without them it will confidently overfit to noise. This phase is strictly downstream of evals.
  2. Optimise the cheap parameters firstPrompt and context policy are free to change and instantly reversible. Fine-tuning is neither. Exhaust the reversible options before touching weights.
Common failureOptimising the wrong objective

An optimiser will maximise exactly what you measured. If the metric rewards answer length or judge agreeability, that is what improves, and the system gets measurably better at the benchmark while getting worse for users.

Worked example

What an optimiser reads that a score cannot

An extraction agent scores 71%. You want it higher. The two ways of getting there are not equally efficient.

Optimising against a number
reward = 0.71 → try a variation → 0.69 → try another → 0.73
→ the signal is one number per rollout
→ it says nothing about which of nine steps was wrong
→ so it needs thousands of rollouts to find out
Optimising against the trace
read the full execution trace, then reflect in words:
"29 of 31 failures had a date in DD/MM. The prompt
  never states a format, so the model assumed MM/DD."
→ propose one targeted edit, re-run, keep if better
→ reported: 10–20% better than GRPO, up to 35× fewer rollouts

So: A scalar tells you that you failed. A trace tells you why. Reflective optimisers are sample-efficient for the same reason a good code review is: they read the work, not just the grade.

Should you build multi-agent systems?

This is not settled, and anyone who tells you it is has picked a side. Two of the most credible engineering teams in the field published opposite conclusions within months of each other, and both were reasoning from production experience.

AnthropicYes: isolate context in sub-agents
  • Each sub-agent explores with a clean context window and returns a condensed 1,000–2,000 token summary.
  • Clear separation of concerns: detailed search context stays inside the sub-agent; the lead agent synthesises.
  • Best fit for complex research and analysis that benefits from parallel exploration.
Read it ↗
CognitionNo: keep it single-threaded
  • Share context, and share full agent traces, not just individual messages.
  • Actions carry implicit decisions, and conflicting decisions carry bad results.
  • Sub-agents working in parallel cannot see each other's assumptions, and the coordinator cannot repair a fundamental miscommunication after the fact.
Read it ↗
Where that leaves you

The reconciliation is task shape. Parallel sub-agents work when subtasks are genuinely independent and the output is a synthesis: research, search, review. They fail when subtasks share implicit design decisions, which is most of software engineering. Cognition builds a coding agent; Anthropic described a research system. Both are right about their own problem, and the mistake is generalising either answer to yours.

Production checklist

Ten things that separate an agent demo from an agent system. None of them are about which model you picked.

  1. 01
    Single-responsibility agents

    No mega-prompts with fifty tools. Specialised sub-agents with two to five focused tools each, coordinated by a router.

  2. 02
    Determinism first, model second

    Deterministic code for static control flow: routing, validation, permissions. Reserve model calls for genuine judgement and language understanding.

  3. 03
    Human-in-the-loop gateways

    Approval breakpoints before any state-mutating action: database writes, payments, outbound email. Implemented as a tool call so pause and resume share one control flow.

  4. 04
    State persistence after every tool call

    Checkpoint to durable storage such as Postgres or Redis after each tool invocation, not at the end of the run. This is what survives a network failure and resumes a paused workflow.

  5. 05
    Idempotent side effects

    Replay is the recovery mechanism, so every external action must tolerate a second attempt. Idempotency keys on every write, payment and send.

  6. 06
    Own your context window

    Decide explicitly what enters it and what is dropped. Do not delegate that to a framework default you have not read.

  7. 07
    Compact errors into context

    Represent failures concisely. A stack trace pasted whole spends the budget that the recovery attempt needs.

  8. 08
    Trace everything, from the first commit

    Nested spans over the whole loop. You cannot reconstruct a trace you did not record, and the interesting failures are rare.

  9. 09
    Evals before optimisation

    A held-out set built from real production failures. Every optimiser and every prompt change is meaningless without one.

  10. 10
    Cost on the same dashboard as quality

    Tokens per successful task, tool calls per run. Agent cost is emergent, and a looping retry can multiply a bill with no code change.

SourcesEvery claim on this page traces to one of these, mostly the engineering teams themselves rather than commentary

This layer moves faster than the rest of the index. Four notable tools in it were acquired or shut down in the eighteen months to August 2026. Where a tool is named here it is because it solves a problem described above, not because it is the largest.