<?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: Tech Trails</title>
    <description>The latest articles on DEV Community by Tech Trails (techtrails).</description>
    <link>https://dev.to/techtrails</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.us-east-2.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F14068%2F3873cc41-dad9-4c1d-94cf-04bf8f4413f3.jpg</url>
      <title>DEV Community: Tech Trails</title>
      <link>https://dev.to/techtrails</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/techtrails"/>
    <language>en</language>
    <item>
      <title>Protocols in Agentic Systems</title>
      <dc:creator>Deepak Patil</dc:creator>
      <pubDate>Tue, 11 Aug 2026 19:12:32 +0000</pubDate>
      <link>https://dev.to/techtrails/protocols-in-agentic-systems-2adm</link>
      <guid>https://dev.to/techtrails/protocols-in-agentic-systems-2adm</guid>
      <description>&lt;p&gt;Picture an office where every employee speaks a different language, uses a different filing system, and refuses to fill out the same form twice. That's most multi-agent AI systems before someone introduces a protocol. Agents are brilliant in isolation and chaotic in groups, and the only thing standing between "chaotic" and "coordinated" is a shared set of rules about who says what, when, and in what format.&lt;/p&gt;

&lt;p&gt;This is the unglamorous half of agentic AI. Nobody writes a viral demo about a well-designed message schema. But spend a week debugging an agent swarm that silently corrupts its own state, and you'll start treating protocols with the reverence usually reserved for database transactions.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a Protocol Actually is
&lt;/h2&gt;

&lt;p&gt;A protocol, in the agentic context, is an agreed-upon contract for communication. It answers four questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Who&lt;/strong&gt; can talk to whom?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What&lt;/strong&gt; shape does a message take?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;When&lt;/strong&gt; does a turn end and the next one begin?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What happens&lt;/strong&gt; when something goes wrong?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's it. It's not a model architecture, not a prompting trick, not a clever chain-of-thought technique. It's plumbing. And like plumbing, you only think about it when it leaks.&lt;/p&gt;

&lt;p&gt;A useful mental model: if a single LLM call is a sentence and a ReAct loop is a conversation with yourself, a protocol is etiquette for a conversation with strangers. The moment more than one autonomous component is involved - another agent, a tool, a human, or a database - etiquette stops being optional.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Agents Need Protocols More Than Humans Do
&lt;/h2&gt;

&lt;p&gt;Humans get away with sloppy communication because we're extraordinary at inferring intent. Say "Can you grab that?" while pointing vaguely at a table, and another person fills in the gaps using context, tone, and shared history.&lt;/p&gt;

&lt;p&gt;Agents don't do this gracefully. An LLM agent calling a tool with a malformed argument doesn't pause and think, "They probably meant the CSV, not the JSON." It either fails loudly, fails silently, or - worse - succeeds in a way nobody intended. Without a protocol, here's a fairly typical failure mode in a two-agent setup:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Agent A:&lt;/strong&gt; "Here's the summary you asked for: [wall of unstructured text]."&lt;br&gt;
&lt;strong&gt;Agent B:&lt;/strong&gt; &lt;em&gt;(expecting a JSON object with a &lt;code&gt;summary&lt;/code&gt; key, gets a string instead, crashes trying to parse it)&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Nobody did anything "wrong" exactly. Agent A produced a perfectly reasonable summary. Agent B had a perfectly reasonable expectation. The system failed because nobody agreed in advance on the shape of the handoff. This is the agentic equivalent of two people agreeing to meet "later" without specifying a time — technically an agreement but practically useless.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tool-Calling Protocols
&lt;/h2&gt;

&lt;p&gt;The most common protocol any agent encounters: a structured schema (usually JSON) describing what a tool accepts and returns. This is the seatbelt of agentic systems - unglamorous, occasionally annoying, and the reason you don't go through the windshield when a model decides to get creative with its output format.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt; OpenAI's function calling, Anthropic's tool-use API, and Google's function declarations all do the same fundamental thing - they force the model to emit a structured payload (&lt;code&gt;{"name": "get_weather", "arguments": {"city": "Pune"}}&lt;/code&gt;) instead of a free-text guess at what a tool call should look like. The protocol isn't the tool. It's the agreed format for &lt;em&gt;requesting&lt;/em&gt; the tool.&lt;/p&gt;

&lt;h2&gt;
  
  
  Agent-to-Agent (A2A) Communication Protocols
&lt;/h2&gt;

&lt;p&gt;This is the layer that gets the least attention and causes the most pain. Tool-calling protocols govern how an agent talks to a &lt;em&gt;function&lt;/em&gt;. A2A protocols govern how an agent talks to &lt;em&gt;another agent&lt;/em&gt; - a fundamentally messier problem, because the other party isn't a deterministic API. It's another model with its own context, its own interpretation of the task, and its own way of going off-script.&lt;/p&gt;

&lt;p&gt;A workable A2A protocol typically needs to define:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Identity&lt;/strong&gt; — Which agent is speaking and what role it's speaking from (researcher, critic, planner, or executor).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Message envelope&lt;/strong&gt; — a consistent structure wrapping the actual content, e.g. &lt;code&gt;{"from": "researcher", "to": "writer", "type": "handoff", "payload": {...}}&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Conversation state&lt;/strong&gt; — whether this message is a new task, a follow-up, a correction, or a final answer, so the receiving agent doesn't have to guess.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Termination signal&lt;/strong&gt; — an explicit way to say "I'm done, here's the result" versus "I'm still working," so the system doesn't poll forever or cut an agent off mid-thought.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Industry example:&lt;/strong&gt; Google's &lt;strong&gt;Agent2Agent (A2A) protocol&lt;/strong&gt; is a direct attempt to standardise exactly this - giving agents built on different frameworks (say, one built with LangGraph and another with CrewAI) a common envelope for discovering each other's capabilities and exchanging tasks, regardless of which vendor or framework built them. Without something like this, every pair of agent frameworks needs a custom translator, which scales about as well as you'd expect - that is, badly.&lt;/p&gt;

&lt;p&gt;Frameworks like AutoGen and CrewAI bake a version of A2A messaging into their internals already - when a "manager" agent delegates to a "worker" agent, there's a defined message format underneath, even if it's framework-specific rather than a true open standard. The trend industry-wide is towards pulling that logic out of individual frameworks and into shared, framework-agnostic protocols.&lt;/p&gt;

&lt;h2&gt;
  
  
  Context and Tool-Sharing Protocols (MCP)
&lt;/h2&gt;

&lt;p&gt;How does an agent know what tools and data exist without every integration being hand-wired? This is where the &lt;strong&gt;Model Context Protocol (MCP)&lt;/strong&gt; comes in - an open standard for connecting AI applications to external tools, data sources, and systems through a single, consistent interface.&lt;/p&gt;

&lt;p&gt;Think of it as the difference between every appliance in your house needing its own proprietary charger versus everything just using USB-C. Mildly annoying to standardise, wildly convenient once it's done.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Concrete example:&lt;/strong&gt; Without MCP, an agent that needs to read files from Google Drive, query a Postgres database, and check GitHub issues needs three separate, custom-built integrations - each with its own auth handling, its own response format, and its own edge cases to maintain. With MCP, each of those becomes an &lt;strong&gt;MCP server&lt;/strong&gt; that exposes its capabilities (e.g., &lt;code&gt;list_files&lt;/code&gt;, &lt;code&gt;run_query&lt;/code&gt;, &lt;code&gt;get_issue&lt;/code&gt;) in a standard format. Any MCP-compatible agent can then talk to any of them the same way, without bespoke glue code per integration. Anthropic's Claude Desktop, for instance, can connect to a local filesystem MCP server or a Slack MCP server using the same underlying protocol - the agent doesn't need a different communication style for each one.&lt;/p&gt;

&lt;p&gt;This is also why MCP gets compared to the &lt;strong&gt;Language Server Protocol (LSP)&lt;/strong&gt; in developer tooling. Before LSP, every code editor needed a custom integration for every programming language's autocomplete and linting. LSP lets editors and language tooling agree on one interface, so any editor could support any language without N×M custom integrations. MCP is making the same bet for agents and tools.&lt;/p&gt;

&lt;h2&gt;
  
  
  Coordination and Turn-Taking Protocols
&lt;/h2&gt;

&lt;p&gt;In a multi-agent workflow, somebody has to decide whose turn it is to act, or you get the digital equivalent of a conference call where four people start talking at once and two never get a word in.&lt;/p&gt;

&lt;p&gt;This is a real protocol layer, not just a scheduling detail, because it defines a contract: only one agent (or a defined subset) may act at a time, and there's an explicit rule for handing control back. A few concrete patterns in current use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Supervisor/orchestrator pattern (LangGraph):&lt;/strong&gt; A central orchestrator node decides which agent runs next based on the current state and routes control explicitly via a graph of edges. No agent decides on its own that it's "next" - the orchestrator decides for it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Round-robin and group chat (AutoGen):&lt;/strong&gt; AutoGen's &lt;code&gt;GroupChat&lt;/code&gt; manager cycles through agents in turn or selects the next speaker based on the conversation so far, with an explicit manager component responsible for the decision, rather than leaving it to the agents to sort out among themselves.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Role-based sequential handoff (CrewAI):&lt;/strong&gt; Agents are assigned roles in a defined sequence (researcher → writer → editor), and a task is only "live" for one role at a time, with output passed forward once that role completes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In each case, the underlying agreement is the same: turn-taking can't be implicit. Someone - a manager process, a graph,or a queue - has to own the decision of who acts next, or the system devolves into agents talking over each other or, just as commonly, everyone waiting for someone else to go first.&lt;/p&gt;

&lt;h2&gt;
  
  
  Error and Fallback Protocols
&lt;/h2&gt;

&lt;p&gt;What happens when a tool call fails, a response times out, or an agent returns something nonsensical? This counts as a protocol because it's a contract too - just one for the unhappy path instead of the happy one. A system without this contract doesn't fail gracefully; it fails &lt;em&gt;wherever it happens to fail&lt;/em&gt;, which in production is usually somewhere inconvenient.&lt;/p&gt;

&lt;p&gt;Concrete patterns worth knowing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Retry with backoff:&lt;/strong&gt; if a tool call times out, retry a fixed number of times before escalating, rather than retrying forever or giving up immediately.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Typed error responses:&lt;/strong&gt; instead of throwing a raw exception, a tool returns a structured error (&lt;code&gt;{"status": "error", "reason": "rate_limited"}&lt;/code&gt;) that the calling agent can actually reason about and act on.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Escalation to a human-in-the-loop:&lt;/strong&gt; when an agent's confidence is low or a tool repeatedly fails, the protocol defines a handoff to a human reviewer instead of letting the agent guess indefinitely — a pattern increasingly built into orchestration frameworks as a first-class node, not an afterthought.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Circuit breakers:&lt;/strong&gt; If a downstream tool fails repeatedly, the protocol stops calling it for a cooldown period instead of hammering a dead service — borrowed directly from distributed systems design.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A Worked Example
&lt;/h2&gt;

&lt;p&gt;Consider a simple two-agent system: a &lt;strong&gt;Researcher&lt;/strong&gt; agent that searches the web and a &lt;strong&gt;Writer&lt;/strong&gt; agent that drafts a summary from the research.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Without a protocol&lt;/strong&gt;, the Researcher might return:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Found some interesting stuff about quantum computing, here's what I think...&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The Writer agent, expecting structured findings, has to guess what's a fact, what's the Researcher's opinion, and what's even usable. It's working from vibes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;With a protocol&lt;/strong&gt;, the contract might look like this:&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;"from"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"researcher"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"to"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"writer"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"handoff"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"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;"complete"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"findings"&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;"claim"&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;"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;"..."&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="s2"&gt;"high"&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="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now the Writer knows exactly what it's receiving, can validate it before using it, and - crucially - can fail predictably if the Researcher sends something malformed, rather than failing mysteriously. The difference between these two systems isn't model quality. It's whether anyone bothered to define the interface.&lt;/p&gt;

&lt;h2&gt;
  
  
  Designing Your Own Protocol: A Short Checklist
&lt;/h2&gt;

&lt;p&gt;If you're building a multi-agent system and rolling your own protocol — which, early on, you often will - a few things tend to matter more than they first appear:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Make failure a first-class message, not an exception.&lt;/strong&gt; Agents should be able to say "I don't know" or "this failed" in the same structured format they use for success - not as a stack trace that breaks the contract.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Version your message schema.&lt;/strong&gt; The moment you have two agents and a schema change, you have a compatibility problem. Future you will be grateful for a &lt;code&gt;"version": "1.2"&lt;/code&gt; field.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep payloads minimal but explicit.&lt;/strong&gt; Don't make the receiving agent infer anything; it could have just been told&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Log everything that crosses the boundary.&lt;/strong&gt; Inter-agent communication is the first place to look when debugging emergent weirdness, so make it inspectable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Assume the other agent is a stranger, not a collaborator.&lt;/strong&gt; Defensive parsing isn't paranoia in agentic systems - it's the default posture.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Protocols don't make agentic systems smarter. They make them legible to each other and to the humans trying to debug them at midnight. The flashy parts of agentic AI (reasoning loops, tool use, autonomous planning) get the conference talks. Protocols get the postmortems.&lt;/p&gt;

&lt;p&gt;But every durable multi-agent system, from A2A and orchestrator frameworks to standards like MCP, is ultimately betting on the same unsexy truth: agents that agree on how to talk to each other will always outlast agents that are merely good at talking.&lt;/p&gt;

</description>
      <category>agents</category>
      <category>techtrails</category>
      <category>genai</category>
      <category>ai</category>
    </item>
    <item>
      <title>The Orchestrator in Agentic Systems</title>
      <dc:creator>Deepak Patil</dc:creator>
      <pubDate>Sat, 08 Aug 2026 09:20:28 +0000</pubDate>
      <link>https://dev.to/techtrails/the-orchestrator-in-agentic-systems-4oap</link>
      <guid>https://dev.to/techtrails/the-orchestrator-in-agentic-systems-4oap</guid>
      <description>&lt;p&gt;A multi-agent system without an orchestrator is just a collection of agents. Each one is capable, but none of them coordinated. They might all be excellent at their individual jobs - searching the web, writing code, calling APIs - but without something deciding what gets done, in what order, by whom, and what to do when a result comes back wrong, the system does not behave like a system. It behaves like a group project with no project manager.&lt;/p&gt;

&lt;p&gt;The orchestrator is the project manager. Its job is not to do the work. Its job is to make sure the work gets done - and that is a harder, more subtle problem than it sounds.&lt;/p&gt;




&lt;h2&gt;
  
  
  What an orchestrator is responsible for
&lt;/h2&gt;

&lt;p&gt;An orchestrator does four things, and only these four things:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Decompose the goal.&lt;/strong&gt; Turn a high-level objective into a concrete set of subtasks. This is a planning problem, not an execution problem. The orchestrator decides &lt;em&gt;what&lt;/em&gt; needs to happen, not &lt;em&gt;how&lt;/em&gt; to do it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Route tasks to the right workers.&lt;/strong&gt; Match each subtask to an agent capable of doing it. This requires knowing what tools and capabilities each worker has - not in detail, but well enough to delegate correctly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Manage state across the workflow.&lt;/strong&gt; As workers return results, the orchestrator decides what those results mean for the remaining plan. Sometimes a result changes the plan entirely. Sometimes it confirms the next step. The orchestrator holds the full picture.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Synthesise the final output.&lt;/strong&gt; Worker outputs are partial. The orchestrator assembles them into a coherent response and decides when the goal has been met.&lt;/p&gt;

&lt;p&gt;Notice what is absent: the orchestrator does not call APIs, does not run code, does not search the web. It reasons about work and routes it. The moment an orchestrator starts executing, it loses the focus that makes it good at coordination.&lt;/p&gt;




&lt;h2&gt;
  
  
  Building one from scratch
&lt;/h2&gt;

&lt;p&gt;Here is a minimal orchestrator in Python. It plans upfront, delegates to type workers, and synthesizes results:&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;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;orchestrator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;goal&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;workers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&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;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# Step 1: plan
&lt;/span&gt;    &lt;span class="n"&gt;plan_prompt&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;
    Goal: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;goal&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;
    Available workers: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;workers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;

    Return a JSON array of steps: [{{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;task&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="s"&gt;...&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="s"&gt;worker&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="s"&gt;...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;}}]
    Return JSON only, no explanation.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;plan&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="nf"&gt;llm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;plan_prompt&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="c1"&gt;# Step 2: execute each step, collect results
&lt;/span&gt;    &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&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;step&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;plan&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;worker&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;workers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;worker&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]]&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;worker&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="n"&gt;step&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;task&lt;/span&gt;&lt;span class="sh"&gt;"&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="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;task&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;task&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;result&lt;/span&gt;&lt;span class="sh"&gt;"&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;span class="c1"&gt;# Step 3: synthesise
&lt;/span&gt;    &lt;span class="n"&gt;synthesis_prompt&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;
    Original goal: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;goal&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;
    Worker results: &lt;/span&gt;&lt;span class="si"&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;dumps&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="n"&gt;indent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;

    Synthesise a final answer from these results.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;llm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;synthesis_prompt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three things in this snippet are worth pulling apart.&lt;/p&gt;

&lt;p&gt;The orchestrator calls &lt;code&gt;llm()&lt;/code&gt; twice - once to plan, once to synthesize - but never once to execute. Execution is entirely delegated. If you find yourself adding a tool call directly inside the orchestrator loop, stop and ask whether a worker should own that instead.&lt;/p&gt;

&lt;p&gt;The plan is a first-class object - a list of typed steps, not an implicit chain of thought. This means you can inspect it, log it, replay it, and re-plan from any point when something goes wrong.&lt;/p&gt;

&lt;p&gt;Results are kept verbatim before synthesis. The orchestrator does not summarise early. It gives the synthesis step the full picture, letting the model decide what is relevant. Premature summarization is where context gets lost.&lt;/p&gt;




&lt;h2&gt;
  
  
  Re-planning when reality diverges
&lt;/h2&gt;

&lt;p&gt;A fixed plan fails the moment a worker returns an unexpected result. A real orchestrator needs to decide: Does this change the remaining plan?&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;orchestrator_with_replan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;goal&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;workers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&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;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;plan&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;initial_plan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;goal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;workers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;completed&lt;/span&gt; &lt;span class="o"&gt;=&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;plan&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;step&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;plan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&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;workers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;worker&lt;/span&gt;&lt;span class="sh"&gt;"&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="n"&gt;step&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;task&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="n"&gt;completed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;task&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;task&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;result&lt;/span&gt;&lt;span class="sh"&gt;"&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;span class="c1"&gt;# check if the result warrants re-planning
&lt;/span&gt;        &lt;span class="n"&gt;replan_prompt&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;
        Remaining plan: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;plan&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;
        Latest result: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;

        Does this result change what should happen next?
        If yes, return a revised plan as JSON. If no, return null.
        &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
        &lt;span class="n"&gt;revision&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;llm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;replan_prompt&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;revision&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;revision&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;null&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;plan&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;revision&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;synthesise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;goal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;completed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the plan-and-execute pattern from the last post made concrete. The orchestrator works from a checklist but checks after each result whether the checklist still makes sense. The loop terminates when the plan is empty, not when a fixed number of steps has run.&lt;/p&gt;




&lt;h2&gt;
  
  
  What frameworks add
&lt;/h2&gt;

&lt;p&gt;Writing an orchestrator from scratch gives you control and understanding, but production use cases introduce problems the snippet above does not handle: state that needs to persist across restarts, workflows that need branching and loops, and debugging when something goes wrong three levels deep. This is where the frameworks come in.&lt;/p&gt;

&lt;h3&gt;
  
  
  LangGraph
&lt;/h3&gt;

&lt;p&gt;LangGraph represents a workflow as a &lt;strong&gt;directed graph&lt;/strong&gt; - nodes are agents or functions, edges are transitions between them, and a centralized &lt;code&gt;StateGraph&lt;/code&gt; holds shared state across the whole run.&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;langgraph.graph&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;StateGraph&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;END&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;TypedDict&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WorkflowState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TypedDict&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;goal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;plan&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;list&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;dict&lt;/span&gt;
    &lt;span class="n"&gt;final_answer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;

&lt;span class="n"&gt;graph&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;StateGraph&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;WorkflowState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;planner&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;planner_node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;researcher&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;researcher_node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;coder&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;coder_node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;synthesiser&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;synthesiser_node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_conditional_edges&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;planner&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;route_to_worker&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;           &lt;span class="c1"&gt;# function that reads state and picks next node
&lt;/span&gt;    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;research&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;researcher&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;code&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;coder&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;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;researcher&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;synthesiser&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;coder&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;synthesiser&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;synthesiser&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;END&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set_entry_point&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;planner&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;compile&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The graph-based model earns its complexity because it makes branching and cycles explicit. The conditional edge above is not hidden inside a prompt - it is code. You can read the graph and know exactly what routes exist. LangGraph also ships with &lt;strong&gt;checkpointers&lt;/strong&gt; that persist state to disk or a database, so a workflow that crashes halfway through can resume from the last checkpoint rather than starting over.&lt;/p&gt;

&lt;p&gt;The honest tradeoff: a simple workflow that would take 40 lines in plain Python takes closer to 120 in LangGraph. You pay in boilerplate. You get auditability, resumability, and explicit control flow in return.&lt;/p&gt;

&lt;h3&gt;
  
  
  AutoGen
&lt;/h3&gt;

&lt;p&gt;AutoGen takes a different approach. Instead of a graph, it models orchestration as &lt;strong&gt;message-passing between agents&lt;/strong&gt;. A &lt;code&gt;GroupChat&lt;/code&gt; manager decides which agent speaks next based on context, and agents broadcast their replies so everyone shares the same conversation history.&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;autogen&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;AssistantAgent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;UserProxyAgent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;GroupChat&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;GroupChatManager&lt;/span&gt;

&lt;span class="n"&gt;planner&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;AssistantAgent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;planner&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;system_message&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Break goals into tasks.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;researcher&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;AssistantAgent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;researcher&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;system_message&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Search and retrieve facts.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;coder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;AssistantAgent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;coder&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;system_message&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Write and run Python code.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;critic&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;AssistantAgent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;critic&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;system_message&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Review outputs for errors.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;group_chat&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;GroupChat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;agents&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;planner&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;researcher&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;coder&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;critic&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;
    &lt;span class="n"&gt;max_round&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;manager&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;GroupChatManager&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;groupchat&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;group_chat&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;planner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;initiate_chat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;manager&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Build a data pipeline for X.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;GroupChatManager&lt;/code&gt; is the orchestrator here. AutoGen v0.4 rebuilt this around an &lt;strong&gt;actor model&lt;/strong&gt; where each agent runs independently and communicates through typed messages - a cleaner design for truly concurrent workflows.&lt;/p&gt;

&lt;p&gt;The full-context broadcast is AutoGen's key architectural bet: every agent sees the whole conversation, which means specialist agents can catch problems earlier in the chain. The cost is that the context window fills faster in long workflows.&lt;/p&gt;

&lt;h3&gt;
  
  
  CrewAI
&lt;/h3&gt;

&lt;p&gt;CrewAI uses a &lt;strong&gt;role-driven&lt;/strong&gt; model. You define a crew of agents with named roles, assign tasks, and let the framework handle delegation. Configuration-first rather than code-first - most of the setup lives in YAML:&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;crewai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Crew&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Process&lt;/span&gt;

&lt;span class="n"&gt;researcher&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;role&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Researcher&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;goal&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Find accurate information&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                   &lt;span class="n"&gt;backstory&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Expert at web research&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;search_tool&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="n"&gt;writer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;role&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Writer&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;goal&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Produce clear summaries&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
               &lt;span class="n"&gt;backstory&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Experienced technical writer&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;research_task&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Research topic X&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;researcher&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;write_task&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Write a summary of the research&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;crew&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Crew&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;agents&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;researcher&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;tasks&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;research_task&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;write_task&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;process&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sequential&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;crew&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;kickoff&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;Process.hierarchical&lt;/code&gt; switches to an orchestrator model where a manager agent routes tasks dynamically rather than following a fixed sequence. CrewAI is the fastest path from idea to running prototype, but teams consistently report hitting its ceiling 6–12 months in when workflows grow beyond sequential or simple hierarchical patterns - at which point a migration to LangGraph tends to follow.&lt;/p&gt;

&lt;p&gt;The most honest guidance: start from scratch to understand the pattern, then adopt a framework when you need what it specifically offers - not because frameworks are the default. LangGraph is the current production default for teams that need long-running, resumable workflows with explicit control flow. CrewAI is the right choice when you need something working this week and can accept the ceiling. AutoGen is strongest when agents genuinely need to debate and revise rather than execute a fixed plan.&lt;/p&gt;




&lt;h2&gt;
  
  
  The orchestrator's failure modes
&lt;/h2&gt;

&lt;p&gt;The orchestrator is the single point of failure in a multi-agent system, which means its failure modes are expensive.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Over-delegation.&lt;/strong&gt; The orchestrator sends a task to a worker that is underspecified. The worker returns garbage. The orchestrator synthesises the garbage. Build task schemas - typed descriptions of what a worker expects - and validate them before dispatch, not after.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Plan rigidity.&lt;/strong&gt; An upfront plan that doesn't re-evaluate when results diverge will execute confidently toward a wrong answer. Build in a replan check after any result that introduces new information.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Silent worker failures.&lt;/strong&gt; Workers that fail quietly return None or an empty string, which the orchestrator may synthesise as if it were real output. Workers should fail loudly with typed errors that the orchestrator can inspect and route around.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Context overload.&lt;/strong&gt; The orchestrator accumulates results from every worker. In a long workflow, its context fills with raw worker outputs. Pass summaries, not raw transcripts, unless the raw content is genuinely needed for synthesis.&lt;/p&gt;




&lt;p&gt;The orchestrator's value is its deliberate ignorance of the details. It does not know how to search the web, run code, or call an API. It knows what needs doing and who should do it. That separation - reasoning about work versus doing work - is what allows multi-agent systems to scale beyond what any single agent could manage alone.&lt;/p&gt;

&lt;p&gt;The loop is still the heartbeat. The orchestrator is the brain that decides how many loops to start, what they should do, and when to stop.&lt;/p&gt;

</description>
      <category>techtrails</category>
      <category>ai</category>
      <category>genai</category>
      <category>agents</category>
    </item>
    <item>
      <title>Single-Agent vs Multi-Agent System</title>
      <dc:creator>Deepak Patil</dc:creator>
      <pubDate>Sat, 01 Aug 2026 18:33:43 +0000</pubDate>
      <link>https://dev.to/techtrails/single-agent-vs-multi-agent-system-4mde</link>
      <guid>https://dev.to/techtrails/single-agent-vs-multi-agent-system-4mde</guid>
      <description>&lt;p&gt;&lt;em&gt;When one loop is enough - and when you need a team&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The previous post ended with a loop: reason, act, observe, repeat. That loop, running inside a single agent, can handle a surprising range of tasks. But spend enough time building agents and you'll hit a wall. The task is too long for one context window. Two subtasks need to run at the same time. One part of the problem requires a specialist that would be noise everywhere else. When you hit that wall, you have a choice: push harder on the single agent or split the work across multiple agents. Knowing which to reach for - and why - is what this post is about.&lt;/p&gt;




&lt;h2&gt;
  
  
  What a single agent actually is
&lt;/h2&gt;

&lt;p&gt;Before comparing, it's worth being precise. A single agent is one model, one context window, and one tool set, running one loop. Everything it has learned about the task lives in that growing history of thoughts, actions, and observations. Its memory is its context.&lt;/p&gt;

&lt;p&gt;That constraint is the source of both its simplicity and its limits.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where a single agent excels:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tasks that fit comfortably in one context window&lt;/li&gt;
&lt;li&gt;Linear workflows where each step depends on the last&lt;/li&gt;
&lt;li&gt;Problems where keeping a shared mental model matters more than speed&lt;/li&gt;
&lt;li&gt;Prototyping - one loop is trivial to trace and debug.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Where it breaks down:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Long tasks that exceed the context limit midrun&lt;/li&gt;
&lt;li&gt;Tasks with independent subtasks that could be parallelised&lt;/li&gt;
&lt;li&gt;Workflows that need different capabilities in different phases&lt;/li&gt;
&lt;li&gt;Any situation where one agent failing silently kills the whole job&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  What a multi-agent system adds
&lt;/h2&gt;

&lt;p&gt;A multi-agent system is two or more agents coordinating to complete a task. Coordination can mean many things - one agent spawning others, agents running in parallel and reporting back, and a pipeline where each agent's output is the next agent's input. The common thread is that no single agent owns the whole task.&lt;/p&gt;

&lt;p&gt;This unlocks three things:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Parallelism.&lt;/strong&gt; If you need to research five companies simultaneously, a single agent does them sequentially. A multi-agent system spawns five subagents and gets all five results at once. For I/O-bound tasks - anything involving search, API calls, or file reads - this is the primary win.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Specialisation.&lt;/strong&gt; A coding agent prompted and tooled for writing Python is better at writing Python than a generalist agent. A multi-agent system lets you route subtasks to agents built for them - a planner, a researcher, a coder, a critic — each with the right system prompt and the right tools.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Context management.&lt;/strong&gt; Each subagent gets a fresh, focused context. Instead of one agent accumulating 50,000 tokens of noise from early steps, a subagent receives only what it needs to do its job. The orchestrator summarises and routes; the workers stay sharp.&lt;/p&gt;




&lt;h2&gt;
  
  
  The orchestrator–worker pattern
&lt;/h2&gt;

&lt;p&gt;The most common multi-agent architecture is a two-level hierarchy: one &lt;strong&gt;orchestrator&lt;/strong&gt; and one or more &lt;strong&gt;workers&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The orchestrator receives the goal, makes a plan, and delegates subtasks. It does not do the work itself - it decides &lt;em&gt;what&lt;/em&gt; the work is and &lt;em&gt;who&lt;/em&gt; does it. Workers receive a scoped task, run their own loop, and return a result. They don't know about each other or the overall goal.&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;orchestrator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;goal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;worker_agents&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;plan&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;llm&lt;/span&gt;&lt;span class="p"&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;Break this goal into subtasks: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;goal&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="c1"&gt;# plan = [{"task": "...", "agent": "researcher"}, ...]
&lt;/span&gt;
    &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&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;step&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;plan&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;worker&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;worker_agents&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;step&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;agent&lt;/span&gt;&lt;span class="sh"&gt;"&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="n"&gt;step&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;task&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;worker&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="n"&gt;step&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;task&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

    &lt;span class="n"&gt;final_answer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;llm&lt;/span&gt;&lt;span class="p"&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;Synthesise these results: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;results&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;final_answer&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each &lt;code&gt;worker.run()&lt;/code&gt; is the same agent loop from the previous post - reason, act, observe, repeat - but scoped to a single subtask. The orchestrator never picks up a tool itself; it reads a plan and routes. The workers never see the big picture; they just solve their piece.&lt;/p&gt;

&lt;p&gt;This separation matters. It keeps orchestrator context lean (plans and results, not tool noise) and keeps worker context focused (one task, right tools, nothing else).&lt;/p&gt;




&lt;h2&gt;
  
  
  Parallelising with subagents
&lt;/h2&gt;

&lt;p&gt;When subtasks are independent, run workers concurrently. In Python, &lt;code&gt;asyncio&lt;/code&gt; or &lt;code&gt;ThreadPoolExecutor&lt;/code&gt; are the usual choices:&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;concurrent.futures&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ThreadPoolExecutor&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;run_parallel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tasks&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nc"&gt;ThreadPoolExecutor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_workers&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;tasks&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;futures&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;submit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;tasks&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;result&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;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt;
                &lt;span class="p"&gt;[(&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;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;futures&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two things to watch. First, &lt;strong&gt;rate limits&lt;/strong&gt;: five agents hitting the same API simultaneously will hit quotas faster than one agent doing it sequentially. Build in back-off logic at the worker level, not just the orchestrator level. Second, &lt;strong&gt;result merging&lt;/strong&gt;: parallel results arrive out of order and may conflict. The orchestrator's synthesis step needs to handle gaps and contradictions, not assume clean, uniform output.&lt;/p&gt;




&lt;h2&gt;
  
  
  When multi-agent is the wrong answer
&lt;/h2&gt;

&lt;p&gt;Multi-agent systems have real costs, and reaching for them too early is one of the most common mistakes in agent engineering.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Complexity compounds.&lt;/strong&gt; A single agent failing is easy to diagnose - you read the trace. Multiple agents failing is a distributed systems problem. Which agent failed? Did the orchestrator misparse the result? Did the worker receive a bad task? Every hop is a new failure surface.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Latency can get worse, not better.&lt;/strong&gt; Parallelism helps I/O-bound tasks. For CPU-bound or model-call-bound work, the overhead of spawning agents, merging results, and making extra orchestration calls can exceed what a single focused agent would have taken.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Context hand-offs lose information.&lt;/strong&gt; When the orchestrator summarises a worker's result to pass to the next, it makes decisions about what to keep. Those decisions are lossy. A single agent that ran the whole task never had to summarise itself.&lt;/p&gt;

&lt;p&gt;The honest default: start with a single agent. Add a second agent when you have a concrete bottleneck - context overflow, a parallelism win you can measure, or a capability mismatch you cannot solve with a better prompt and better tools.&lt;/p&gt;




&lt;h2&gt;
  
  
  A practical decision framework
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Situation&lt;/th&gt;
&lt;th&gt;Reach for&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Task fits in context, linear flow&lt;/td&gt;
&lt;td&gt;Single agent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Task exceeds context mid-run&lt;/td&gt;
&lt;td&gt;Orchestrator + summarising subagents&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Independent subtasks, I/O-bound&lt;/td&gt;
&lt;td&gt;Parallel workers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Phases need different tool sets&lt;/td&gt;
&lt;td&gt;Specialist workers per phase&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Need a second opinion on outputs&lt;/td&gt;
&lt;td&gt;Critic agent in the loop&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Prototyping or debugging&lt;/td&gt;
&lt;td&gt;Single agent - always start here&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;p&gt;A single agent is not a stepping stone to multi-agent. It is the right architecture for a large class of tasks and the one you should default to until you have a specific reason to split work. Multi-agent systems earn their complexity when tasks genuinely exceed what one context window can hold, when parallelism produces a real speed win, or when specialist agents meaningfully outperform a generalist on a defined subtask.&lt;/p&gt;

&lt;p&gt;The loop does not change. What changes are, who owns which part of it, and how do the pieces report back?&lt;/p&gt;

</description>
      <category>ai</category>
      <category>techtrails</category>
      <category>agents</category>
      <category>genai</category>
    </item>
    <item>
      <title>Agent Memory &amp; Context Engineering</title>
      <dc:creator>Deepak Patil</dc:creator>
      <pubDate>Tue, 28 Jul 2026 18:41:11 +0000</pubDate>
      <link>https://dev.to/techtrails/agent-memory-context-engineering-1mb5</link>
      <guid>https://dev.to/techtrails/agent-memory-context-engineering-1mb5</guid>
      <description>&lt;p&gt;How agents remember - and why deciding what to forget is the real skill&lt;/p&gt;

&lt;p&gt;An agent that starts every step with a blank mind cannot really pursue a goal. It would reintroduce itself to you on every message, forget what it just tried, and repeat the same mistake forever. &lt;strong&gt;Memory&lt;/strong&gt; is what turns a stateless model into something that accumulates - that knows who you are, what it has already done, and what it learned last Tuesday. This post is about how that works and, more importantly, about the discipline of deciding what an agent should remember at all.&lt;/p&gt;

&lt;h1&gt;
  
  
  The context window is not memory.
&lt;/h1&gt;

&lt;p&gt;The first thing to unlearn: a model’s context window is not its memory. The context window is &lt;strong&gt;working memory - RAM, not a hard drive.&lt;/strong&gt; It is finite, it is reset on every request, and every token in it costs money and dilutes the model’s attention. Stuffing an entire conversation history and knowledge base into the prompt does not scale, and past a point it actively &lt;em&gt;hurts&lt;/em&gt; - the model loses the important signal in a sea of stale detail. Real memory lives outside the window and is selectively loaded into it when needed.&lt;/p&gt;

&lt;h1&gt;
  
  
  Four kinds of memory
&lt;/h1&gt;

&lt;p&gt;Borrowing loosely from cognitive science, agent memory is usually split into four types, and good systems use all of them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Short-term/working memory&lt;/strong&gt; - the current conversation and the agent’s recent thoughts and observations. Lives in the context window.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Long-term episodic memory&lt;/strong&gt; - a record of &lt;em&gt;what happened&lt;/em&gt;: past conversations, decisions, and the outcomes of previous tasks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Long-term semantic memory&lt;/strong&gt; - facts and knowledge: who the user is, domain information, documents. This is what retrieval-augmented generation pulls from.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Procedural memory&lt;/strong&gt; - &lt;em&gt;how to do things&lt;/em&gt;: learned skills, tool-use patterns, and reusable strategies.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Short-term memory: the rolling buffer
&lt;/h1&gt;

&lt;p&gt;The simplest memory is just keeping recent turns in the prompt. The problem is that conversations outgrow the window, so the standard move is to keep the last few turns verbatim and &lt;strong&gt;summarise&lt;/strong&gt; the older ones into a compact note:&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;build_context&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;history&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;window&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;recent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;history&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;window&lt;/span&gt;&lt;span class="p"&gt;:]&lt;/span&gt;
    &lt;span class="n"&gt;older&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;history&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;window&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;older&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;summary&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;llm&lt;/span&gt;&lt;span class="p"&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;Summarize this conversation so far:&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;older&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="k"&gt;return&lt;/span&gt; &lt;span class="p"&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;Summary so far: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;summary&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="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;recent&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;recent&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This keeps the prompt bounded while preserving the gist of what came before. It is crude, but it is the backbone of almost every chat agent in production.&lt;/p&gt;

&lt;h1&gt;
  
  
  Long-term memory: embeddings and vector search
&lt;/h1&gt;

&lt;p&gt;To remember across sessions, an agent writes information to an external store and retrieves it later by meaning rather than exact keywords. The mechanism is &lt;strong&gt;embeddings&lt;/strong&gt;: each piece of text is converted into a high-dimensional vector, stored in a vector database, and later retrieved by finding the vectors closest to the current query. This is what lets an agent recall a relevant fact even when you phrase your question completely differently from how the fact was stored.&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="c1"&gt;# Write a memory
&lt;/span&gt;&lt;span class="n"&gt;vec&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;embed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;User prefers window seats and vegetarian meals.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pref-1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;vector&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;vec&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;User prefers window seats and vegetarian meals.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Later, retrieve by meaning
&lt;/span&gt;&lt;span class="n"&gt;query_vec&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;embed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;book me a flight to Delhi&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;hits&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query_vec&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;top_k&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;hits&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="err"&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt; &lt;span class="c1"&gt;# injected into the prompt
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That retrieval step is what gives an agent its long memory without bloating the context window: you store everything but load only the handful of memories relevant to the moment.&lt;/p&gt;

&lt;h1&gt;
  
  
  Why vector search alone isn’t enough
&lt;/h1&gt;

&lt;p&gt;Vector similarity is powerful but blunt, and it is worth knowing its limits before you lean on it. Similarity relies on &lt;strong&gt;relevance - not recency, not authority, not workflow state.&lt;/strong&gt; It will happily surface an outdated preference the user changed yesterday or a fact from a draft that was later overruled, simply because the words are close. It does not understand which memory is current, which is authoritative, or where you are in a multi-step task. Production memory systems layer on recency weighting, source ranking, and explicit state to compensate. Memory in 2026 is treated as a real engineering discipline with measurable trade-offs, not a database you bolt on and forget.&lt;/p&gt;

&lt;h1&gt;
  
  
  Context engineering: the real skill
&lt;/h1&gt;

&lt;p&gt;All of this rolls up into the discipline people increasingly call &lt;strong&gt;context engineering&lt;/strong&gt;: deliberately deciding what goes into the context window on every single step. Prompt engineering asks &lt;em&gt;How do I word the instruction?&lt;/em&gt; Context engineering asks &lt;em&gt;What information should the model see right now, and what should I leave out?&lt;/em&gt; It is closer to managing a tight working-memory budget than to writing clever prompts.&lt;/p&gt;

&lt;p&gt;A recent and influential pattern is &lt;strong&gt;Agentic Context Engineering (ACE)&lt;/strong&gt;, which treats context as something the agent actively curates through a three-role loop: a &lt;strong&gt;Generator&lt;/strong&gt; produces an attempt, a &lt;strong&gt;Reflector&lt;/strong&gt; evaluates it and flags what was missing or wrong, and a &lt;strong&gt;Curator&lt;/strong&gt; distils the lesson into a growing “playbook” that improves future context. Reported results show meaningful accuracy gains on agent benchmarks &lt;em&gt;without retraining the underlying model&lt;/em&gt; - the improvement comes entirely from feeding it better context. That is the whole thesis of context engineering in one experiment.&lt;/p&gt;

&lt;h1&gt;
  
  
  Practical patterns to start with
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Summarise old turns, keeping recent ones verbatim&lt;/strong&gt; - bounded prompt, preserved gist.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Retrieve, don’t dump&lt;/strong&gt; - pull only the top few relevant memories per step instead of the whole store.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tag memories with time and source&lt;/strong&gt; so you can prefer recent, authoritative information over stale matches.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Write back what matters&lt;/strong&gt; - after a task, save the durable facts and lessons, not the entire transcript.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  The takeaway
&lt;/h1&gt;

&lt;p&gt;Memory is what separates a chatbot from an agent that genuinely accumulates competence over time. But the headline isn’t “store everything” - it’s the opposite. The skill is curation: deciding, on every step, the smallest set of information that lets the model act well and leaving the rest in long-term storage until it’s needed. Treat context as critical infrastructure, and your agents get sharper, cheaper, and more reliable all at once.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Next in the series:&lt;/strong&gt; One agent can only do so much. We’ll look at multi-agent systems - orchestration, the A2A protocol, and how to split a goal across a team of specialised agents without the whole thing collapsing into chaos.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>genai</category>
      <category>techtrails</category>
      <category>agents</category>
    </item>
    <item>
      <title>Tools, Function Calling &amp; MCP</title>
      <dc:creator>Deepak Patil</dc:creator>
      <pubDate>Thu, 23 Jul 2026 16:29:21 +0000</pubDate>
      <link>https://dev.to/techtrails/tools-function-calling-mcp-1ood</link>
      <guid>https://dev.to/techtrails/tools-function-calling-mcp-1ood</guid>
      <description>&lt;p&gt;How agents reach into the real world - and how to do it without creating a security nightmare&lt;/p&gt;

&lt;p&gt;A language model on its own is a brain in a jar. It can reason beautifully about the weather and tell you nothing about whether it is actually raining outside, because it has no senses and no hands. &lt;strong&gt;Tools&lt;/strong&gt; are the senses and hands. They are the single feature that turns a model that can &lt;em&gt;talk&lt;/em&gt; about booking a flight into an agent that can actually book one. In the last post we saw the agent loop; this post is about the &lt;em&gt;Act&lt;/em&gt; step inside that loop.&lt;/p&gt;

&lt;h1&gt;
  
  
  What a tool actually is
&lt;/h1&gt;

&lt;p&gt;Strip away the jargon and a tool is two things: a function, and a description the model can read. The function is ordinary code - a database query, an HTTP call, a shell command. The description is a schema that tells the model the tool’s name, what it does, and what arguments it takes. The model never sees your code; it only sees the schema and decides, in the moment, whether this tool is the right one for the goal in front of it.&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;get_weather&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;city&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;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Return current conditions for a city.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;weather_api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;current&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;city&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# The schema is what the MODEL sees:
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&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;get_weather&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;description&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;Get current weather conditions for a city.&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;parameters&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&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;object&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;properties&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;city&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&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;string&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;description&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;City name, e.g. &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Mumbai&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;required&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;city&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  The one rule that keeps you safe: decide vs. execute
&lt;/h1&gt;

&lt;p&gt;Here is the most important sentence in this entire post. &lt;strong&gt;The model decides; your code executes.&lt;/strong&gt; When a model “calls a tool,” it does not run anything - it returns a structured request that &lt;em&gt;names&lt;/em&gt; a function and its arguments. Your application receives that request, decides whether it is allowed, runs the real function, and feeds the result back into the loop.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The LLM should decide what to do, but never be the thing that does it. Keep a layer of your own code between the model’s intent and any real-world effect.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That gap between intent and execution is where you put validation, permission checks, rate limits, and human approval for anything dangerous. Collapse that gap - let the model run code directly - and you have handed an unpredictable system the keys to your infrastructure.&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="c1"&gt;# The full decide -&amp;gt; execute -&amp;gt; observe cycle
&lt;/span&gt;
&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;history&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;schemas&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;call&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tool_calls&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="nf"&gt;is_allowed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="err"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt; &lt;span class="c1"&gt;# YOUR guardrail
&lt;/span&gt;        &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Error: not permitted.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&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;REGISTRYcall&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="err"&gt;&amp;nbsp;&lt;/span&gt; &lt;span class="c1"&gt;# YOUR code runs it
&lt;/span&gt;    &lt;span class="n"&gt;history&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&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;tool&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;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;str&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;span class="n"&gt;final&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;history&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="err"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt; &lt;span class="c1"&gt;# model uses the results
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Designing tools the model can actually use
&lt;/h1&gt;

&lt;p&gt;An agent is only as capable as its tools are well-designed, and most agent failures trace back to a badly described or badly scoped tool rather than a weak model. A few principles go a long way:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Name and describe for the model, not for you.&lt;/strong&gt; cancel_order(order_id) with a one-line description of when to use it beats a clever internal name the model has to guess about.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep each tool narrow.&lt;/strong&gt; One tool, one job. A single do_everything tool with a mode flag forces the model to reason about your implementation instead of the task.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validate inputs and fail informatively.&lt;/strong&gt; Return &lt;em&gt;“Error: city ‘Xyz’ not found, did you mean a valid city name?”&lt;/em&gt; rather than a stack trace. The model reads that error and corrects itself on the next loop.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prefer idempotency.&lt;/strong&gt; Agents retry. A tool that charges a card twice when called twice is a liability; design so repeats are safe.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  The M×N problem, and why MCP exists
&lt;/h1&gt;

&lt;p&gt;Once tools work, a scaling problem appears. If you have M agent applications and N systems you want to connect (Slack, GitHub, your database, Google Drive), the naive world requires M×N custom integrations - every app re-implementing a connector to every system. The &lt;strong&gt;Model Context Protocol (MCP)&lt;/strong&gt;, introduced by Anthropic and now broadly adopted, collapses that into M+N. MCP is an open standard - often described as “USB-C for AI tools” - that defines a common way for a model to discover and call tools exposed by any compliant server.&lt;/p&gt;

&lt;p&gt;The division of labour in the 2026 agent stack is clean: &lt;strong&gt;MCP standardizes how agents talk to tools and data; the Agent-to-Agent (A2A) protocol standardizes how agents talk to each other.&lt;/strong&gt; Build a tool once as an MCP server and any MCP-aware client - LangGraph, CrewAI, ADK, a desktop assistant - can use it without bespoke glue.&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="c1"&gt;# A minimal MCP server exposing one tool (Python SDK)
&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;mcp.server.fastmcp&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;FastMCP&lt;/span&gt;

&lt;span class="n"&gt;mcp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;FastMCP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;weather-server&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nd"&gt;@mcp.tool&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;get_weather&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;city&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;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Get current weather conditions or a city.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;weather_api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;current&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;city&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;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;mcp&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="err"&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt; &lt;span class="c1"&gt;# any MCP client can now discover and call get_weather
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The payoff is an ecosystem effect: the catalogue of ready-made MCP servers keeps growing, so connecting an agent to a new system increasingly means &lt;em&gt;pointing it at an existing server&lt;/em&gt; rather than writing an integration.&lt;/p&gt;

&lt;h1&gt;
  
  
  Tools are your attack surface
&lt;/h1&gt;

&lt;p&gt;Every tool you give an agent is also a door someone could walk through. A tool that runs shell commands or sends money is exactly as dangerous in an agent’s hands as in an attacker’s, and prompt injection - hostile instructions hidden in a web page or document the agent reads - can trick an agent into misusing the tools it has. Treat tool access as a security boundary, not a convenience:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Least privilege.&lt;/strong&gt; Give each agent the narrowest set of tools its job requires - nothing more.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Never auto-execute irreversible actions.&lt;/strong&gt; Payments, deletions, and trades should require explicit human confirmation, not an agent’s say-so.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validate and sanitize all tool inputs&lt;/strong&gt;, exactly as you would for any untrusted user, because in effect they are&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Tools are what make an agent useful, and MCP is making them composable across the whole ecosystem. But the discipline that matters most is the gap you keep between the model’s decision and the real action - that gap is where your validation, permissions, and human oversight live. Get the tool design and that boundary right and you have an agent that is both genuinely capable and safe to put in front of real users.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>genai</category>
      <category>techtrails</category>
      <category>agents</category>
    </item>
    <item>
      <title>Inside The Agent Loop</title>
      <dc:creator>Deepak Patil</dc:creator>
      <pubDate>Tue, 21 Jul 2026 16:26:15 +0000</pubDate>
      <link>https://dev.to/techtrails/inside-the-agent-loop-2l7j</link>
      <guid>https://dev.to/techtrails/inside-the-agent-loop-2l7j</guid>
      <description>&lt;p&gt;How an agent actually thinks and acts: ReAct, tool calling, and the loop that powers every agent&lt;/p&gt;

&lt;p&gt;In the first post, we described an agentic system as software that can plan, reason, use tools, and execute multi-step workflows. This sentence hides the most important idea in the whole field. &lt;em&gt;What is actually happening when an agent “thinks”?&lt;/em&gt; The honest answer is surprisingly simple, and once you see it, every agent framework on the market stops looking like magic and starts looking like a single design pattern repeated with variations.&lt;/p&gt;

&lt;p&gt;The pattern is a loop. A plain language model answers your prompt once and stops. An agent wraps that same model in a loop (its output is fed as its next input and so on) that keeps running - reasoning, taking an action, observing the result, and reasoning again - until the goal is met. That loop is the heartbeat of every agent you will ever build.&lt;/p&gt;

&lt;h1&gt;
  
  
  From one-shot answers to a loop
&lt;/h1&gt;

&lt;p&gt;A chatbot is a function: text in, text out, done. The model never finds out whether its answer was any good. An agent breaks that single shot into a cycle. After each step it gets feedback from the real world and uses that feedback to decide what to do next. This is the difference between a student who writes an exam answer and walks away and a mechanic who turns a bolt, checks whether the engine starts, and adjusts.&lt;/p&gt;

&lt;p&gt;The most influential way to structure that cycle is the &lt;strong&gt;ReAct&lt;/strong&gt; pattern, introduced by Yao et al. in 2022. ReAct stands for &lt;strong&gt;Reason + Act&lt;/strong&gt;, and it interleaves three things on every turn:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Thought&lt;/strong&gt; - a short chain-of-thought where the model reflects on the situation and decides what to do.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Action&lt;/strong&gt; - a concrete step, usually calling a tool or an API.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Observation&lt;/strong&gt; - the result that action produced, fed straight back into the model.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By forcing the model to reason in the open &lt;em&gt;and&lt;/em&gt; ground each decision in a real observation, ReAct reduces hallucination: the model cannot quietly invent a fact when the next line of the transcript is the actual output of a search it just ran.&lt;/p&gt;

&lt;h1&gt;
  
  
  A traced example
&lt;/h1&gt;

&lt;p&gt;Suppose the goal is "What &lt;em&gt;was the closing price of the stock the CEO of Tesla most recently tweeted about?”&lt;/em&gt; A ReAct trace might look like this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Thought: I need to find Elon Musk's most recent tweet about a stock.&lt;/p&gt;

&lt;p&gt;Action: search_tweets(user="elonmusk", topic="stock")&lt;/p&gt;

&lt;p&gt;Observation: "Just bought more $X ..." (posted 2h ago)&lt;/p&gt;

&lt;p&gt;Thought: The ticker is X. I need today's closing price.&lt;/p&gt;

&lt;p&gt;Action:&amp;nbsp;get_quote(ticker="X")&lt;/p&gt;

&lt;p&gt;Observation: { "close": 41.80, "currency": "USD" }&lt;/p&gt;

&lt;p&gt;Thought: I now have the answer.&lt;/p&gt;

&lt;p&gt;Action: finish("The closing price was $41.80.")&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Notice that no single model call could have answered this. The agent had to act, look at what came back, and only then decide its next move. That is the entire value proposition of the loop.&lt;/p&gt;

&lt;h1&gt;
  
  
  Building the loop from scratch
&lt;/h1&gt;

&lt;p&gt;Stripped of any framework, an agent loop is about a dozen lines. The model returns a structured decision; your code executes it and feeds the result back:&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;run_agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;goal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_steps&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;history&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;system_prompt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;goal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tools&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;_&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_steps&lt;/span&gt;&lt;span class="p"&gt;):&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;llm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;history&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# model reasons + picks an action
&lt;/span&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;decision&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;finish&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;decision&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;answer&lt;/span&gt;
        &lt;span class="n"&gt;tool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tools&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;span class="n"&gt;action&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;tool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;decision&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;# YOUR code runs the tool
&lt;/span&gt;        &lt;span class="n"&gt;history&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&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;span class="n"&gt;history&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&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;Observation: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;result&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="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Stopped: step budget exhausted.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three details in that snippet matter more than they look. First, the &lt;strong&gt;loop has a hard step budget&lt;/strong&gt; (max_steps). Without it, a confused agent will happily call tools forever and burn through your API bill. Second, &lt;strong&gt;the model never executes anything&lt;/strong&gt; - it only &lt;em&gt;names&lt;/em&gt; an action and arguments; your code decides whether and how to run it. Third, every observation is appended to history, so the model’s context grows with what it has learned.&lt;/p&gt;

&lt;h1&gt;
  
  
  ReAct text vs. native tool calling
&lt;/h1&gt;

&lt;p&gt;There are two ways to get that decision out of the model. The original ReAct approach asks the model to &lt;em&gt;write&lt;/em&gt; its thoughts and actions as text, which you then parse. Modern models offer &lt;strong&gt;native tool calling&lt;/strong&gt; (also called function calling): you hand the model a set of typed function schemas, and it returns a structured JSON object naming the function and its arguments - no fragile text parsing required.&lt;/p&gt;

&lt;h1&gt;
  
  
  Native tool calling: the model returns structured intent, not prose.
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;tools&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;name&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;get_quote&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;description&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;Get the latest market quote for a ticker symbol.&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;parameters&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&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;object&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;properties&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ticker&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&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;string&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;required&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ticker&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="p"&gt;}]&lt;/span&gt;

&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;history&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;call&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tool_calls&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="err"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span class="c1"&gt;# {name: "get_quote", args: {ticker: "X"}}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The trade-off is real and worth understanding. Text-based ReAct is &lt;strong&gt;transparent and model-agnostic&lt;/strong&gt; - you can read the reasoning, and it works on any model, even ones without a tool-calling API. Native tool calling is &lt;strong&gt;more efficient and reliable&lt;/strong&gt; - structured output, fewer round trips, and the model can request several tools at once - but the reasoning behind a call is less visible. In practice most production agents use native tool calling and recover transparency through tracing and logging.&lt;/p&gt;

&lt;h1&gt;
  
  
  When one loop isn’t enough: plan-and-execute
&lt;/h1&gt;

&lt;p&gt;Pure ReAct decides its next step one observation at a time, which is flexible but can wander on long tasks. A common evolution is &lt;strong&gt;plan-and-execute&lt;/strong&gt;: the agent first drafts a full plan and then executes the steps, replanning only when reality diverges. Separating slow, expensive planning from fast tactical execution tends to handle complex multi-step workflows more efficiently than reacting from scratch every turn. You can think of ReAct as improvising and plan-and-execute as working from a checklist you’re allowed to revise.&lt;/p&gt;

&lt;h1&gt;
  
  
  Where loops go wrong
&lt;/h1&gt;

&lt;p&gt;The loop is powerful precisely because it is open-ended, and that is also where the failure modes live. Agents get stuck repeating the same failing action, loop until the budget runs out, or call an expensive tool dozens of times. The defenses are unglamorous but essential: a hard step limit, detection of repeated identical actions, a cost ceiling, and clear tool error messages so the model can &lt;em&gt;recover&lt;/em&gt; rather than retry blindly. Treat every observation as something the model might misread, and design your tools to fail loudly and informatively.&lt;/p&gt;

&lt;h1&gt;
  
  
  The takeaway
&lt;/h1&gt;

&lt;p&gt;Every agent - from a customer-support bot to GitHub Copilot’s agent mode - is, at its core, this loop: “reason, act, observe, repeat, until done." "Frameworks add memory, multiple agents, and orchestration on top, but they are all variations on the same heartbeat. Once you can write the loop yourself, you understand agents from the inside, and every framework becomes a convenience rather than a mystery.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Next in the series, the&lt;/strong&gt; &lt;em&gt;Act&lt;/em&gt; step deserves its own post. We’ll go deep on tools, function calling, and the Model Context Protocol - how agents actually reach into the world without becoming a security liability.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>techtrails</category>
      <category>genai</category>
    </item>
    <item>
      <title>Introduction to Agentic Systems</title>
      <dc:creator>Sarthak Jain</dc:creator>
      <pubDate>Sun, 19 Jul 2026 17:11:55 +0000</pubDate>
      <link>https://dev.to/techtrails/introduction-to-agentic-systems-53pi</link>
      <guid>https://dev.to/techtrails/introduction-to-agentic-systems-53pi</guid>
      <description>&lt;h3&gt;
  
  
  LLM’s are part of everyday life
&lt;/h3&gt;

&lt;p&gt;With the rise of LLM’s over the past decade there has been surge in development/usage of textual chat applications. Chatbots using these LLM models are becoming ineradicable parts of human life. &lt;/p&gt;

&lt;p&gt;Considering this organizations are trying to build bots, softwares tailoring the user experience for their businesses. Simply put, Agentic Systems are just LLM’s on loop, and they represent the next step in this evolution. Instead of simply responding to prompts, they can plan, reason, make decisions, use tools, and execute multi-step workflows to achieve a goal.&lt;/p&gt;

&lt;p&gt;For eg. You ask gemini to add an event on your calendar.&lt;/p&gt;

&lt;h3&gt;
  
  
  An Agentic System
&lt;/h3&gt;

&lt;p&gt;As defined by Google &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Agentic AI is an advanced form of&amp;nbsp;artificial intelligence focused on autonomous decision-making and action. Unlike traditional AI, which primarily responds to commands or analyzes data, agentic AI can set goals, plan, and execute tasks with minimal human intervention. This emerging technology has the potential to revolutionize various industries by automating complex processes and optimizing workflows.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Agentic system is an AI system that is focused on orchestration and operation of agents to perform actions by using LLMs as underlying technology. To simplify, an agentic system is nothing but a real world organization where each worker (Agent) performs a specific goal contributing towards the broader organizational goal. &lt;/p&gt;

&lt;p&gt;As the AI systems are evolving there is need of bringing complex workflows within AI systems to cater varied customer use-cases. These workflows involve multiple actions and decisions which traditional LLM’s are not capable of performing. This leads to the introduction of agents which is an&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;autonomous entity designed to perform specific tasks&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;An agent is a standalone system which uses LLM at its core and is tailored to → understand complex user objectives → break it down in small and precise tasks → perform analysis → plan execution → perform the tasks with provided context and tools → reach the desired objective by completing all sub tasks.&lt;/p&gt;

&lt;h3&gt;
  
  
  Working of Agents
&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fattu1js54m4kj0vjizvb.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fattu1js54m4kj0vjizvb.jpg" alt="AI Agent Lifecycle" width="716" height="507"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;An agent works as an individual worker or part of multiple workers in the system. An individual agent is designed to perform a single task with higher efficiency and correctness. An agent has following components: &lt;/p&gt;

&lt;p&gt;Goal → Reasoning Engine → Context → Tools → Feedback&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Goal : Goal can be defined as a objective which needs to be achieved.&lt;/li&gt;
&lt;li&gt;Reasoning Engine : A reasoning engine is a LLM which is called using a special prompt to get the specific task done.&lt;/li&gt;
&lt;li&gt;Context : Every agent has context of its own which is related to the task it’s supposed to achieve.&lt;/li&gt;
&lt;li&gt;Tools : Tools are external integrations that helps the agent to complete it’s task.&lt;/li&gt;
&lt;li&gt;Feedback : With every objective an agentic systems learns and becomes more accurate in future.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every agentic system starts with a base agent (In Single Agent System) that starts the initial flow of the task. A general use of base agent is to understand the user prompt and generate the plan to achieve desired goal. &lt;/p&gt;

&lt;p&gt;In case of multi agent systems a base agent is responsible to break user query down into completable smaller tasks or goals. It acts as a orchestrator for the entire multi-agent system. Once the tasks are decided, a base agent calls respective agents and assigns them sub tasks along with input if any. Others agents may be single or again a part of multi agent system. The worker agents complete the sub tasks either by reasoning, calling tools, interacting with external systems or even fetching data from various sources. The base agent then combines the outcomes of sub-agents in calling order → and synthesizes the final output by transforming the results.&lt;/p&gt;

&lt;h3&gt;
  
  
  Agentic System In Action
&lt;/h3&gt;

&lt;p&gt;A real world use-case of Agentic System is “Github Copilot Agent Mode” which is available today in most of the IDE’s. It is the next evolution in AI assisted software development. It can achieve multi step tasks including reading files, analyzing the code, performing code edits, running cli commands and many more. &lt;/p&gt;

&lt;p&gt;It can be used for: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Researching the architecture&lt;/li&gt;
&lt;li&gt;Fixing Bugs&lt;/li&gt;
&lt;li&gt;Improving test coverage and code quality&lt;/li&gt;
&lt;li&gt;Updating Documentation&lt;/li&gt;
&lt;li&gt;Resolving code errors&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Details on how it works can be found here - &lt;/p&gt;

&lt;p&gt;&lt;a href="https://code.visualstudio.com/blogs/2025/02/24/introducing-copilot-agent-mode#_how-it-works" rel="noopener noreferrer"&gt;introducing-copilot-agent-mode#_how-it-works&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is a sample working agent code in Java built with ADK - &lt;a href="https://github.com/Deepcodr/JobPilotAgent" rel="noopener noreferrer"&gt;https://github.com/Deepcodr/JobPilotAgent&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Beyond the prompt
&lt;/h3&gt;

&lt;p&gt;Agentic Systems represent a significant shift in AI development. Rather than simply responding to prompts, it enables AI to tackle complex, multi-step tasks that traditional applications struggle to handle.&lt;br&gt;
For developers, understanding agentic systems is becoming increasingly important as organizations move toward autonomous workflows and AI-driven operations. The future of AI is not just about generating answers; it's about taking meaningful actions to achieve outcomes.&lt;/p&gt;

</description>
      <category>llm</category>
      <category>techtrails</category>
      <category>aiagents</category>
    </item>
  </channel>
</rss>
