<?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: Arif Sefa</title>
    <description>The latest articles on DEV Community by Arif Sefa (@arif_sefa_f2d991d373eb93e).</description>
    <link>https://dev.to/arif_sefa_f2d991d373eb93e</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%2Fuser%2Fprofile_image%2F4182886%2F507adbfb-5920-4e39-addf-aea59af1c415.png</url>
      <title>DEV Community: Arif Sefa</title>
      <link>https://dev.to/arif_sefa_f2d991d373eb93e</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/arif_sefa_f2d991d373eb93e"/>
    <language>en</language>
    <item>
      <title>AI Evals: Stop Trusting Your Agent's “Done”</title>
      <dc:creator>Arif Sefa</dc:creator>
      <pubDate>Tue, 03 Nov 2026 12:42:15 +0000</pubDate>
      <link>https://dev.to/arif_sefa_f2d991d373eb93e/ai-evals-stop-trusting-your-agents-done-334d</link>
      <guid>https://dev.to/arif_sefa_f2d991d373eb93e/ai-evals-stop-trusting-your-agents-done-334d</guid>
      <description>&lt;p&gt;AI agents are getting pretty good at doing things.&lt;/p&gt;

&lt;p&gt;But an agent can complete a task without actually doing it correctly.&lt;/p&gt;

&lt;p&gt;Imagine this scenario.&lt;/p&gt;

&lt;p&gt;You give your coding agent a Jira ticket:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Add a credit card limit update feature to the payment service.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The agent reads the ticket, searches the repository, finds the relevant service, implements the changes, writes tests, and reports:&lt;/p&gt;

&lt;p&gt;"Implementation completed. All tests passed."&lt;/p&gt;

&lt;p&gt;Looks good, right?&lt;/p&gt;

&lt;p&gt;But let's look a little closer.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Did it find the correct payment service?&lt;/li&gt;
&lt;li&gt;Did it follow the existing architecture?&lt;/li&gt;
&lt;li&gt;Did it validate the user's authorization?&lt;/li&gt;
&lt;li&gt;Did it accidentally modify unrelated files?&lt;/li&gt;
&lt;li&gt;Did it actually execute the tests?&lt;/li&gt;
&lt;li&gt;Did it use the correct MCP tools?&lt;/li&gt;
&lt;li&gt;Could it have completed the task with fewer steps?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The agent says it's done. But how do we know?&lt;/p&gt;

&lt;p&gt;This is where &lt;strong&gt;Evals (Evaluations)&lt;/strong&gt; come in.&lt;/p&gt;

&lt;p&gt;I think Evals are becoming one of the most important parts of AI engineering, especially as we move from simple LLM applications to autonomous agents and multi-agent workflows.&lt;/p&gt;

&lt;p&gt;Let's look at how we can actually implement them.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Evals Are Not Just Another Type of Test
&lt;/h2&gt;

&lt;p&gt;Traditional software testing is built around predictable behavior.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;calculateCreditCardLimit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We know the input, we know the expected output, and we can verify the result.&lt;/p&gt;

&lt;p&gt;AI systems are different.&lt;/p&gt;

&lt;p&gt;The same task can produce different outputs depending on the model, prompt, context, available tools, and execution environment.&lt;/p&gt;

&lt;p&gt;Consider asking an AI agent:&lt;/p&gt;

&lt;p&gt;"Find the credit card limit update implementation and explain how it works."&lt;/p&gt;

&lt;p&gt;There might be several valid ways to investigate the codebase.&lt;/p&gt;

&lt;p&gt;One agent might search by endpoint name. Another might start from the controller. Both could eventually find the correct implementation.&lt;/p&gt;

&lt;p&gt;Requiring exactly the same execution sequence would be unnecessarily restrictive.&lt;/p&gt;

&lt;p&gt;Instead, we need to evaluate whether the agent reached the correct result and whether its execution was reasonable.&lt;/p&gt;

&lt;p&gt;I find it useful to think about Evals as another layer in our engineering workflow.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Traditional testing&lt;/th&gt;
&lt;th&gt;AI evaluation&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Does the API return the expected response?&lt;/td&gt;
&lt;td&gt;Did the agent implement the correct API behavior?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Do unit tests pass?&lt;/td&gt;
&lt;td&gt;Did the agent write meaningful tests and execute them?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Does the function handle invalid input?&lt;/td&gt;
&lt;td&gt;Did the agent understand and handle the edge cases?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Does the application meet performance requirements?&lt;/td&gt;
&lt;td&gt;Did the agent complete the task within an acceptable budget?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Does the integration work?&lt;/td&gt;
&lt;td&gt;Did the agent select and use the right tools?&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;These approaches complement each other.&lt;/p&gt;

&lt;p&gt;We still need unit tests, integration tests, and end-to-end tests. Evals help us understand whether the AI system can reliably produce the changes those tests are supposed to verify.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Start With Real Tasks, Not Random Prompts
&lt;/h2&gt;

&lt;p&gt;Before building an evaluation system, we need a collection of tasks to evaluate.&lt;/p&gt;

&lt;p&gt;Let's continue with our credit card example.&lt;/p&gt;

&lt;p&gt;Imagine we have a coding agent connected to Jira, GitLab, and an internal codebase through MCP.&lt;/p&gt;

&lt;p&gt;I would start with a small dataset containing different types of engineering tasks.&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"CC-001"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"category"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"code-discovery"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"input"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Find the credit card limit update implementation."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"expected"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"behavior"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Identify the correct controller and service."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"mustNotModifyFiles"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"CC-002"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"category"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"feature-implementation"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"input"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Add authorization validation to credit card limit updates."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"expected"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"behavior"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Validate card ownership before updating the limit."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"testsRequired"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"CC-003"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"category"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"bug-fixing"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"input"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Fix the issue where invalid credit card limits are accepted."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"expected"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"behavior"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Reject invalid limits and preserve existing behavior."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"testsRequired"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"CC-004"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"category"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"architecture-analysis"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"input"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Explain the credit card limit update flow."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"expected"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"behavior"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Explain the BFF, API and service interactions."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"mustNotModifyFiles"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="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;These four scenarios already test different capabilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Understanding an existing codebase.&lt;/li&gt;
&lt;li&gt;Implementing a new feature.&lt;/li&gt;
&lt;li&gt;Fixing a bug.&lt;/li&gt;
&lt;li&gt;Understanding system architecture.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But don't stop at happy paths.&lt;/p&gt;

&lt;p&gt;Add scenarios such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The Jira ticket has incomplete requirements.&lt;/li&gt;
&lt;li&gt;The relevant API documentation is missing.&lt;/li&gt;
&lt;li&gt;An MCP server returns a timeout.&lt;/li&gt;
&lt;li&gt;The repository contains multiple implementations of the same feature.&lt;/li&gt;
&lt;li&gt;The agent encounters an existing test failure.&lt;/li&gt;
&lt;li&gt;Two agents attempt to modify the same file.&lt;/li&gt;
&lt;li&gt;The user requests an operation without sufficient authorization.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A good evaluation dataset should represent the problems your agent will encounter in real life.&lt;/p&gt;

&lt;p&gt;One practice I particularly like is turning production failures into permanent evaluation cases.&lt;/p&gt;

&lt;p&gt;If an agent makes a mistake today, we should be able to detect the same mistake in tomorrow's evaluation run.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Deterministic Evals: Let Code Check the Result
&lt;/h2&gt;

&lt;p&gt;Not every evaluation needs another AI model.&lt;/p&gt;

&lt;p&gt;In fact, if we can verify something with ordinary code, we should.&lt;/p&gt;

&lt;p&gt;Let's say our coding agent implements the credit card limit update feature.&lt;/p&gt;

&lt;p&gt;We want to check:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Was the correct service modified?&lt;/li&gt;
&lt;li&gt;Was authorization validation added?&lt;/li&gt;
&lt;li&gt;Were tests created?&lt;/li&gt;
&lt;li&gt;Did the tests actually pass?&lt;/li&gt;
&lt;li&gt;Were unrelated files modified?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We can write a simple evaluator.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;AgentResult&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;modifiedFiles&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="nl"&gt;toolCalls&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="nl"&gt;testsPassed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;evaluateCreditCardFeature&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AgentResult&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;correctServiceModified&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;modifiedFiles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;file&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;payment-service&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;

    &lt;span class="na"&gt;testsAdded&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;modifiedFiles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;file&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;endsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;.spec.ts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;

    &lt;span class="na"&gt;testsExecuted&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toolCalls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;run_tests&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;

    &lt;span class="na"&gt;testsPassed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;testsPassed&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can evaluate the actual result instead of trusting the agent's final message.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"correctServiceModified"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"testsAdded"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"testsExecuted"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"testsPassed"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="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;The agent did most of the work, but the implementation isn't ready.&lt;/p&gt;

&lt;p&gt;This is a much more useful result than simply receiving "Task completed."&lt;/p&gt;

&lt;h3&gt;
  
  
  Where can deterministic checks help?
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;What we want to evaluate&lt;/th&gt;
&lt;th&gt;How we can check it&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;API contract&lt;/td&gt;
&lt;td&gt;OpenAPI / JSON Schema&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Type correctness&lt;/td&gt;
&lt;td&gt;TypeScript compiler&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Unit tests&lt;/td&gt;
&lt;td&gt;Jest / Vitest&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Code quality&lt;/td&gt;
&lt;td&gt;ESLint&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Security issues&lt;/td&gt;
&lt;td&gt;Semgrep / CodeQL&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Modified files&lt;/td&gt;
&lt;td&gt;Git diff&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tool usage&lt;/td&gt;
&lt;td&gt;Agent execution trace&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Database changes&lt;/td&gt;
&lt;td&gt;SQL assertions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;API behavior&lt;/td&gt;
&lt;td&gt;Integration tests&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For example, after the agent finishes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn nx &lt;span class="nb"&gt;test &lt;/span&gt;payment-service
yarn nx run payment-service:lint
yarn nx run payment-service:build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important detail is that the evaluator executes these commands independently.&lt;/p&gt;

&lt;p&gt;We shouldn't accept an agent's statement that tests passed as proof that they actually passed.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Tool Selection: Did the Agent Use the Right Tools?
&lt;/h2&gt;

&lt;p&gt;This becomes especially interesting when we start using MCP.&lt;/p&gt;

&lt;p&gt;Imagine our agent has access to these tools:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tools&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;search_jira&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;search_repository&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;read_file&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;get_api_documentation&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;run_tests&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;create_merge_request&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now give it this task:&lt;/p&gt;

&lt;p&gt;"Find the current credit card limit update implementation and explain its behavior."&lt;/p&gt;

&lt;p&gt;A reasonable execution might look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. search_repository
2. read_file
3. get_api_documentation
4. Generate explanation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But imagine this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. search_jira
2. create_merge_request
3. search_repository
4. read_file
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The agent has performed unnecessary and potentially dangerous actions.&lt;/p&gt;

&lt;p&gt;We can inspect its tool calls and compare them with the expected behavior.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;evaluateToolUsage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;actualTools&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;
  &lt;span class="nx"&gt;requiredTools&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;
  &lt;span class="nx"&gt;forbiddenTools&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;missing&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;requiredTools&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;tool&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;actualTools&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;forbidden&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;forbiddenTools&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;tool&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;actualTools&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;passed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;missing&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;forbidden&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;missing&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;forbidden&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;evaluateToolUsage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;search_repository&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;read_file&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;get_api_documentation&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;search_repository&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;read_file&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;create_merge_request&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The expected result is a passing evaluation.&lt;/p&gt;

&lt;p&gt;Of course, there can be multiple valid execution paths. We don't need to force every agent to call tools in exactly the same order.&lt;/p&gt;

&lt;p&gt;What matters is whether it used the necessary tools, avoided forbidden actions, and achieved the intended result.&lt;/p&gt;

&lt;p&gt;This is particularly important when building an MCP router with hundreds of available endpoints.&lt;/p&gt;

&lt;p&gt;A model might be capable of using tools, but that doesn't mean it will always select the right one.&lt;/p&gt;

&lt;p&gt;Tool selection itself should be evaluated.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Trajectory Evals: The Final Answer Isn't the Whole Story
&lt;/h2&gt;

&lt;p&gt;A trajectory is the sequence of actions an agent takes while completing a task.&lt;/p&gt;

&lt;p&gt;Consider two agents working on the same credit card feature.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Agent A&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. Read Jira task
2. Search repository
3. Identify payment service
4. Read existing implementation
5. Check API documentation
6. Implement changes
7. Run unit tests
8. Fix failing test
9. Report result
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Agent B&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. Read Jira task
2. Search entire repository
3. Read 35 unrelated files
4. Search the same code again
5. Call MCP tool 6 times
6. Generate implementation
7. Skip tests
8. Report success
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both might produce similar final responses.&lt;/p&gt;

&lt;p&gt;But their execution quality is very different.&lt;/p&gt;

&lt;p&gt;We should evaluate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Number of tool calls.&lt;/li&gt;
&lt;li&gt;Unnecessary file reads.&lt;/li&gt;
&lt;li&gt;Repeated operations.&lt;/li&gt;
&lt;li&gt;Token consumption.&lt;/li&gt;
&lt;li&gt;Recovery from failures.&lt;/li&gt;
&lt;li&gt;Whether the agent verified its changes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A simple trace evaluator might look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;AgentTrace&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;toolCalls&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;filesRead&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;retries&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;testsExecuted&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;durationMs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;totalTokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;evaluateTrajectory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;trace&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AgentTrace&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;toolEfficiency&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;trace&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toolCalls&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;contextEfficiency&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;trace&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;filesRead&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;retryStability&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;trace&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;retries&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;verification&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;trace&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;testsExecuted&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;timeBudget&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;trace&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;durationMs&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;120&lt;/span&gt;&lt;span class="nx"&gt;_000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;tokenBudget&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;trace&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;totalTokens&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="nx"&gt;_000&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These numbers are just examples. A code-discovery task and a multi-file feature implementation shouldn't have the same execution budget.&lt;/p&gt;

&lt;p&gt;The goal isn't to make agents use as few tools as possible.&lt;/p&gt;

&lt;p&gt;It's to understand whether the tools and context they consume actually contribute to solving the task.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. LLM-as-a-Judge: When We Need Another Model to Evaluate the Result
&lt;/h2&gt;

&lt;p&gt;Some things are difficult to verify with deterministic tests.&lt;/p&gt;

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

&lt;p&gt;"Explain how credit card limit updates work in this codebase."&lt;/p&gt;

&lt;p&gt;There can be multiple correct explanations, so exact string matching isn't particularly useful.&lt;/p&gt;

&lt;p&gt;We can use another LLM as an evaluator.&lt;/p&gt;

&lt;p&gt;The process is straightforward:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The agent completes the task.&lt;/li&gt;
&lt;li&gt;We collect its response.&lt;/li&gt;
&lt;li&gt;A judge model receives the task, reference information, and response.&lt;/li&gt;
&lt;li&gt;The judge evaluates the response against a defined rubric.&lt;/li&gt;
&lt;li&gt;We store the scores and explanation.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Example judge prompt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You are evaluating an AI coding agent.

Task:
Explain how credit card limit updates work.

Reference information:
- The request enters through the BFF.
- The payment API handles the request.
- The service validates card ownership.
- The business layer validates the requested limit.
- The repository persists the updated limit.

Evaluate using these criteria:

1. Technical correctness: 0-5
2. Completeness: 0-5
3. Relevance: 0-5
4. Unsupported assumptions: 0-5

Do not reward confident language.
Penalize invented implementation details.
Highlight missing authorization checks.

Return structured JSON.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Possible result:&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;"technical_correctness"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"completeness"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"relevance"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"unsupported_assumptions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"reason"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"The answer explains the BFF and service layers but misses the ownership validation."&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;This is useful when comparing different models or prompt configurations.&lt;/p&gt;

&lt;p&gt;For example, we could compare a local Qwen model with another coding model using the same tasks and the same evaluation criteria.&lt;/p&gt;

&lt;p&gt;However, an LLM judge can also be wrong.&lt;/p&gt;

&lt;p&gt;It may prefer a confident but inaccurate answer, overlook a technical detail, or score the same answer differently across runs.&lt;/p&gt;

&lt;p&gt;For critical checks, combine LLM judging with deterministic assertions and human review.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. RAG Evals: Did We Retrieve the Right Information?
&lt;/h2&gt;

&lt;p&gt;Evals are not limited to coding agents.&lt;/p&gt;

&lt;p&gt;Consider a RAG system that searches internal engineering documentation.&lt;/p&gt;

&lt;p&gt;Question:&lt;/p&gt;

&lt;p&gt;"How does the credit card limit update process work?"&lt;/p&gt;

&lt;p&gt;The retrieval system returns five documents.&lt;/p&gt;

&lt;p&gt;But what if the correct API documentation isn't among them?&lt;/p&gt;

&lt;p&gt;The model might still generate a convincing explanation using unrelated documents.&lt;/p&gt;

&lt;p&gt;We need to evaluate two different things:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Retrieval quality:&lt;/strong&gt; Did we find the right information?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Answer quality:&lt;/strong&gt; Did the model use that information correctly?&lt;/p&gt;

&lt;p&gt;Let's define a small dataset:&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"question"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"How is a credit card limit updated?"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"expectedDocuments"&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="s2"&gt;"credit-card-api.md"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"payment-service.md"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"expectedFacts"&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="s2"&gt;"ownership validation"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"limit validation"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"database update"&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;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"question"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"What happens when a limit update fails?"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"expectedDocuments"&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="s2"&gt;"credit-card-error-handling.md"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"expectedFacts"&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="s2"&gt;"error response"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"validation failure"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"retry behavior"&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;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;There are several useful retrieval metrics.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Recall@K&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Did the correct documents appear in the top K results?&lt;/p&gt;

&lt;p&gt;Suppose there are three expected documents and the retriever returns only one of them in its top five results.&lt;/p&gt;

&lt;p&gt;[&lt;br&gt;
Recall@5 = \frac{1}{3}&lt;br&gt;
]&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Precision@K&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;How many retrieved documents were relevant?&lt;/p&gt;

&lt;p&gt;If only two of the five returned documents are relevant:&lt;/p&gt;

&lt;p&gt;[&lt;br&gt;
Precision@5 = \frac{2}{5}&lt;br&gt;
]&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;MRR (Mean Reciprocal Rank)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;How high does the first relevant document appear?&lt;/p&gt;

&lt;p&gt;If the first relevant document is at position two:&lt;/p&gt;

&lt;p&gt;[&lt;br&gt;
RR = \frac{1}{2}&lt;br&gt;
]&lt;/p&gt;

&lt;p&gt;These metrics help us identify whether the problem is in retrieval or generation.&lt;/p&gt;

&lt;p&gt;For example, a model might produce the correct answer even though the retriever returned the wrong documents.&lt;/p&gt;

&lt;p&gt;That doesn't mean the RAG system is reliable. The model might simply have guessed correctly.&lt;/p&gt;
&lt;h2&gt;
  
  
  8. Multi-Agent Evals: Individual Agents Can Work, But the System Can Still Fail
&lt;/h2&gt;

&lt;p&gt;Let's take a step further.&lt;/p&gt;

&lt;p&gt;Imagine we have a multi-agent development workflow.&lt;/p&gt;

&lt;p&gt;A Jira ticket enters the system, and several agents work together.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                   Jira Ticket
                        |
                        v
                  Planner Agent
                        |
                 Task Decomposition
                        |
           +------------+------------+
           |            |            |
           v            v            v
       Backend       Frontend       Tester
        Agent          Agent         Agent
           |            |            |
           v            v            v
        API Code      UI Code     Test Results
           |            |            |
           +------------+------------+
                        |
                        v
                   Review Agent
                        |
                        v
                   Final Result
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;How do we evaluate this?&lt;/p&gt;

&lt;p&gt;We should evaluate each agent separately.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Agent&lt;/th&gt;
&lt;th&gt;What should we evaluate?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Planner&lt;/td&gt;
&lt;td&gt;Did it identify all requirements and dependencies?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Backend&lt;/td&gt;
&lt;td&gt;Did it implement the correct business rules?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Frontend&lt;/td&gt;
&lt;td&gt;Did it integrate the API correctly?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tester&lt;/td&gt;
&lt;td&gt;Did it create meaningful test scenarios?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reviewer&lt;/td&gt;
&lt;td&gt;Did it identify security and architectural problems?&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;But individual performance isn't enough.&lt;/p&gt;

&lt;p&gt;We also need to evaluate coordination.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Did the frontend agent start before the API contract was ready?&lt;/li&gt;
&lt;li&gt;Did two agents modify the same file?&lt;/li&gt;
&lt;li&gt;Did the planner forget an important requirement?&lt;/li&gt;
&lt;li&gt;Did the reviewer inspect the latest implementation?&lt;/li&gt;
&lt;li&gt;Did the orchestrator recover when one agent failed?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is where workflow-level evaluation becomes important.&lt;/p&gt;

&lt;p&gt;An agent might be excellent at writing code but unreliable when coordinating with other agents.&lt;/p&gt;

&lt;p&gt;The same principle applies to distributed agent architectures: communication, task ownership, shared state, and failure handling are all part of the evaluation.&lt;/p&gt;

&lt;h2&gt;
  
  
  9. Regression Evals: Don't Let Improvements Break Existing Behavior
&lt;/h2&gt;

&lt;p&gt;Here's a situation that will probably look familiar to anyone experimenting with prompts and models.&lt;/p&gt;

&lt;p&gt;You update your system prompt to improve backend code generation.&lt;/p&gt;

&lt;p&gt;Your backend agent performs better.&lt;/p&gt;

&lt;p&gt;But suddenly, it starts modifying more files than necessary during frontend tasks.&lt;/p&gt;

&lt;p&gt;Without regression evaluations, you might not notice until production.&lt;/p&gt;

&lt;p&gt;A simple workflow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;             Prompt / Model Change
                       |
                       v
                   Run Evals
                       |
                       v
                 Compare Results
                       |
                 +-----+-----+
                 |           |
              Improved    Degraded
                 |           |
                 v           v
               Accept     Investigate
                 |           |
                 v           v
               Deploy     Fix / Revert
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Before&lt;/th&gt;
&lt;th&gt;After&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Backend success&lt;/td&gt;
&lt;td&gt;78%&lt;/td&gt;
&lt;td&gt;91%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Frontend success&lt;/td&gt;
&lt;td&gt;92%&lt;/td&gt;
&lt;td&gt;76%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tool accuracy&lt;/td&gt;
&lt;td&gt;89%&lt;/td&gt;
&lt;td&gt;94%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Average tokens&lt;/td&gt;
&lt;td&gt;28K&lt;/td&gt;
&lt;td&gt;35K&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The new prompt improved backend performance but damaged frontend performance and increased token consumption.&lt;/p&gt;

&lt;p&gt;This is why every meaningful change to a model, prompt, tool, context strategy, or orchestration logic should trigger relevant evaluations.&lt;/p&gt;

&lt;p&gt;I would treat this as part of the normal development lifecycle, just like running unit and integration tests before merging a change.&lt;/p&gt;

&lt;h2&gt;
  
  
  10. Let's Build a Small Evaluation Runner With TypeScript
&lt;/h2&gt;

&lt;p&gt;So far, we've discussed different evaluation techniques.&lt;/p&gt;

&lt;p&gt;Let's put some of them together.&lt;/p&gt;

&lt;p&gt;We don't need a complex platform to get started. A simple evaluation runner is enough to demonstrate the idea.&lt;/p&gt;

&lt;p&gt;Our runner should:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Load evaluation scenarios.&lt;/li&gt;
&lt;li&gt;Execute the agent.&lt;/li&gt;
&lt;li&gt;Collect the execution result.&lt;/li&gt;
&lt;li&gt;Run deterministic checks.&lt;/li&gt;
&lt;li&gt;Record latency and token usage.&lt;/li&gt;
&lt;li&gt;Generate a report.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;First, define the contracts.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;EvalCase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;requiredTools&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
    &lt;span class="nl"&gt;forbiddenTools&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
    &lt;span class="nl"&gt;mustNotModifyFiles&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;boolean&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="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;AgentExecution&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;answer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;modifiedFiles&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="nl"&gt;toolCalls&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="nl"&gt;testsPassed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;durationMs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;totalTokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;EvalResult&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;passed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;failures&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="nl"&gt;durationMs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;totalTokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let's implement the evaluator.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;evaluateCase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;testCase&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;EvalCase&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;executeAgent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&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;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;AgentExecution&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;EvalResult&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;execution&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;executeAgent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;testCase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;failures&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tool&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;testCase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;requiredTools&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;execution&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toolCalls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tool&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;failures&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Missing tool: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;tool&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&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="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tool&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;testCase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;forbiddenTools&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;execution&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toolCalls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tool&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;failures&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Forbidden tool used: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;tool&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&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="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;testCase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mustNotModifyFiles&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
    &lt;span class="nx"&gt;execution&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;modifiedFiles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;failures&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Unexpected file modifications&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;testCase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;passed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;failures&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;failures&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;durationMs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;execution&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;durationMs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;totalTokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;execution&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;totalTokens&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, run the dataset.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;runEvaluation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;EvalCase&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;
  &lt;span class="nx"&gt;executeAgent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&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;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;AgentExecution&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;EvalResult&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;testCase&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;evaluateCase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;testCase&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;executeAgent&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;passed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;passed&lt;/span&gt;
  &lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;length&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="na"&gt;total&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;passed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;failed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;passed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;successRate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;passed&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;averageTokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;totalTokens&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="o"&gt;/&lt;/span&gt;
      &lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;results&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a deliberately small implementation. A production runner would also need isolated workspaces, test-result assertions, execution timeouts, structured traces, repeated runs, and error classification.&lt;/p&gt;

&lt;p&gt;Also notice that the evaluator doesn't trust the agent's final response. It checks the actual execution data.&lt;/p&gt;

&lt;p&gt;That's the idea.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Evaluation should be an executable part of your engineering process, not a manual review of a successful demo.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  11. Open-Source Projects Worth Exploring
&lt;/h2&gt;

&lt;p&gt;You don't have to build everything from scratch. These three projects are good starting points.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Promptfoo
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/promptfoo/promptfoo" rel="noopener noreferrer"&gt;https://github.com/promptfoo/promptfoo&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Probably one of the easiest ways to start experimenting with Evals.&lt;/p&gt;

&lt;p&gt;It supports:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Prompt and model comparisons.&lt;/li&gt;
&lt;li&gt;Custom JavaScript assertions.&lt;/li&gt;
&lt;li&gt;LLM-as-a-Judge.&lt;/li&gt;
&lt;li&gt;RAG evaluations.&lt;/li&gt;
&lt;li&gt;Coding agent evaluations.&lt;/li&gt;
&lt;li&gt;Cost and latency checks.&lt;/li&gt;
&lt;li&gt;Regression testing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What makes it particularly interesting for coding agents is that it can evaluate actual agent execution, inspect traces, and run tasks in separate workspaces.&lt;/p&gt;

&lt;p&gt;A good starting point:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.promptfoo.dev/docs/guides/evaluate-coding-agents/" rel="noopener noreferrer"&gt;https://www.promptfoo.dev/docs/guides/evaluate-coding-agents/&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2. OpenAI Evals
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/openai/evals" rel="noopener noreferrer"&gt;https://github.com/openai/evals&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;An open-source framework for evaluating LLMs and LLM-based systems.&lt;/p&gt;

&lt;p&gt;It provides a framework for defining evaluation tasks, creating custom evaluators, and running repeatable experiments.&lt;/p&gt;

&lt;p&gt;It's useful when you want to build evaluation datasets around your own use cases rather than relying only on generic benchmarks.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Inspect AI
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/UKGovernmentBEIS/inspect_ai" rel="noopener noreferrer"&gt;https://github.com/UKGovernmentBEIS/inspect_ai&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;An open-source evaluation framework developed by the UK AI Security Institute.&lt;/p&gt;

&lt;p&gt;What makes it interesting is its support for more complex agent evaluations.&lt;/p&gt;

&lt;p&gt;It provides building blocks for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Datasets.&lt;/li&gt;
&lt;li&gt;Agents and tools.&lt;/li&gt;
&lt;li&gt;Scorers.&lt;/li&gt;
&lt;li&gt;Sandboxed execution.&lt;/li&gt;
&lt;li&gt;Multi-step tasks.&lt;/li&gt;
&lt;li&gt;Tool-using and multi-agent workflows.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It also supports custom and MCP tools, making it worth exploring if you're building systems that interact with external services.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;I think we're entering a different phase of AI development.&lt;/p&gt;

&lt;p&gt;We're no longer just building applications that generate text. We're building systems that can make decisions, modify codebases, interact with infrastructure, and execute entire workflows.&lt;/p&gt;

&lt;p&gt;That changes how we should think about quality.&lt;/p&gt;

&lt;p&gt;A successful demo tells us that an agent can complete a task under certain conditions.&lt;/p&gt;

&lt;p&gt;An evaluation suite tells us how reliably it performs across different tasks and conditions.&lt;/p&gt;

&lt;p&gt;For me, this is the important distinction:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Don't measure your agent by its best execution. Measure it by how consistently it gets things right.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Building an agent is one challenge.&lt;/p&gt;

&lt;p&gt;Knowing when to trust it is another.&lt;/p&gt;

</description>
      <category>agents</category>
      <category>ai</category>
      <category>softwaredevelopment</category>
      <category>testing</category>
    </item>
    <item>
      <title>Your AI Doesn’t Have a Model Problem. It Has a Data Problem.</title>
      <dc:creator>Arif Sefa</dc:creator>
      <pubDate>Thu, 29 Oct 2026 20:18:16 +0000</pubDate>
      <link>https://dev.to/arif_sefa_f2d991d373eb93e/your-ai-agent-doesnt-have-a-model-problem-it-has-a-data-problem-28n9</link>
      <guid>https://dev.to/arif_sefa_f2d991d373eb93e/your-ai-agent-doesnt-have-a-model-problem-it-has-a-data-problem-28n9</guid>
      <description>&lt;p&gt;&lt;em&gt;Why building reliable AI systems requires more than choosing a better LLM.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A book I read a while ago has been on my mind again recently: &lt;em&gt;Designing Data-Intensive Applications&lt;/em&gt; by Martin Kleppmann.&lt;/p&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%2Fwww.oreilly.com%2Fcovers%2Furn%253Aorm%253Abook%253A9781491903063%2F296w%2F%3Fformat%3Dwebp" 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%2Fwww.oreilly.com%2Fcovers%2Furn%253Aorm%253Abook%253A9781491903063%2F296w%2F%3Fformat%3Dwebp" alt="Designing Data-Intensive Applications by Martin Kleppmann — O'Reilly Media" width="296" height="388"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I found myself going back to it, and this time, I started looking at some of its ideas through a different lens: AI systems.&lt;/p&gt;

&lt;p&gt;We spend a lot of time discussing which model to use, how to improve prompts, and how to build better agent workflows. But many of the problems I keep running into aren't really about the model itself.&lt;/p&gt;

&lt;p&gt;They're about data. How it's retrieved, how it stays up to date, how state is managed, and how different parts of a system stay consistent.&lt;/p&gt;

&lt;p&gt;These are familiar engineering problems. We've been dealing with them long before LLMs became part of our daily work.&lt;/p&gt;

&lt;p&gt;And I think many of the lessons from Kleppmann's book are just as relevant to AI agents as they are to traditional distributed systems.&lt;/p&gt;

&lt;p&gt;Let's look at a few examples.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. RAG Is a Data Engineering Problem, Too
&lt;/h2&gt;

&lt;p&gt;Retrieval-Augmented Generation (RAG) is often presented as a straightforward solution: index your documents, retrieve relevant chunks, and send them to an LLM.&lt;/p&gt;

&lt;p&gt;In practice, getting retrieval right is much harder.&lt;/p&gt;

&lt;p&gt;Imagine building an AI assistant that understands a large banking application. A developer asks:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Where is the credit card detail screen, and which backend endpoint provides its data?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The answer might involve several parts of a monorepo:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A React Native screen&lt;/li&gt;
&lt;li&gt;A BFF implemented with NestJS&lt;/li&gt;
&lt;li&gt;A GraphQL query or REST endpoint&lt;/li&gt;
&lt;li&gt;A .NET microservice&lt;/li&gt;
&lt;li&gt;Shared UI components and business logic&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A basic vector search might retrieve a file containing the words “credit card details.” But that doesn't necessarily tell us how the data flows through the application.&lt;/p&gt;

&lt;p&gt;The relevant information may be spread across several files, and the relationships between them matter as much as the files themselves.&lt;/p&gt;

&lt;p&gt;This is where data architecture starts to matter.&lt;/p&gt;

&lt;p&gt;A more useful retrieval system could combine:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Semantic search:&lt;/strong&gt; Find code and documents related to the question, even when they use different terminology.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keyword search:&lt;/strong&gt; Find exact endpoint names, symbols, identifiers, and error codes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code relationships:&lt;/strong&gt; Follow imports, function calls, API contracts, and dependencies.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Metadata filters:&lt;/strong&gt; Restrict results to the relevant application, language, or project.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The goal isn't simply to retrieve text that looks relevant. It's to reconstruct enough of the underlying system to answer the question correctly.&lt;/p&gt;

&lt;p&gt;This is closely related to a broader idea in &lt;em&gt;Designing Data-Intensive Applications&lt;/em&gt;: the way we organize, index, and derive data has a direct impact on what our systems can do with it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A better model can't reliably compensate for information that your retrieval system never found.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Your Data Can Be Correct and Your Answer Can Still Be Wrong
&lt;/h2&gt;

&lt;p&gt;Consider another scenario.&lt;/p&gt;

&lt;p&gt;An API endpoint changes during a refactoring. The code is updated, the tests pass, and the application works as expected.&lt;/p&gt;

&lt;p&gt;But the AI assistant still uses an old index.&lt;/p&gt;

&lt;p&gt;A developer asks about the endpoint, and the assistant confidently returns the previous implementation.&lt;/p&gt;

&lt;p&gt;The model might reason perfectly from the information it received. The problem is that the information is no longer current.&lt;/p&gt;

&lt;p&gt;This is a data freshness problem.&lt;/p&gt;

&lt;p&gt;Traditional data systems have dealt with similar challenges for years: replication lag, stale caches, delayed processing, and derived data that falls behind its source.&lt;/p&gt;

&lt;p&gt;AI systems introduce another layer of derived data. Embeddings, code summaries, knowledge graphs, and retrieval indexes are all representations of an underlying source.&lt;/p&gt;

&lt;p&gt;When that source changes, these representations need to be updated.&lt;/p&gt;

&lt;p&gt;A practical indexing pipeline might look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Source code changes
       |
       v
Detect changed files
       |
       v
Rebuild affected chunks and relationships
       |
       v
Update search indexes
       |
       v
Make updated knowledge available to agents
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a large repository, rebuilding everything after every change may be too expensive. Incremental indexing, dependency tracking, and background processing can make the pipeline more efficient.&lt;/p&gt;

&lt;p&gt;The important part is having a clear strategy for keeping derived data in sync with its source.&lt;/p&gt;

&lt;p&gt;This is also why an AI assistant should be able to identify where its information came from and, when necessary, check the current source before making a claim.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Retrieval quality isn't just about relevance. It's also about freshness.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Multi-Agent Systems Need Reliable State, Not Just Memory
&lt;/h2&gt;

&lt;p&gt;Multi-agent systems are often described in terms of roles: a planner, a designer, a frontend developer, a backend developer, and a tester.&lt;/p&gt;

&lt;p&gt;That sounds reasonable. But what happens when one agent fails halfway through a workflow?&lt;/p&gt;

&lt;p&gt;Imagine a system that creates a GitLab merge request, runs tests, and asks a reviewer agent to inspect the changes.&lt;/p&gt;

&lt;p&gt;The review request times out. The orchestrator doesn't know whether the operation failed or whether the result was simply delayed.&lt;/p&gt;

&lt;p&gt;It retries the operation.&lt;/p&gt;

&lt;p&gt;Depending on how the workflow is implemented, the system might create duplicate work, lose track of the original task, or report a result that doesn't reflect the actual state of the merge request.&lt;/p&gt;

&lt;p&gt;Adding another agent won't solve this problem.&lt;/p&gt;

&lt;p&gt;The workflow needs explicit state.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;TaskStatus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pending&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;running&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;completed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;failed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;retrying&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;AgentTask&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TaskStatus&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;attempts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;result&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;unknown&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;error&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is only a starting point. A production implementation would also need persistent storage, task ownership, timestamps, retry policies, and a way to recover after a process restarts.&lt;/p&gt;

&lt;p&gt;For operations with side effects, idempotency is important too. Retrying a task should not blindly repeat an action that has already succeeded.&lt;/p&gt;

&lt;p&gt;A reliable workflow should be able to answer questions such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which tasks have completed?&lt;/li&gt;
&lt;li&gt;Which agent currently owns a task?&lt;/li&gt;
&lt;li&gt;What happens if an agent crashes?&lt;/li&gt;
&lt;li&gt;Can a task be safely retried?&lt;/li&gt;
&lt;li&gt;How do we recover after the orchestrator restarts?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are familiar distributed-systems questions.&lt;/p&gt;

&lt;p&gt;An LLM can decide what to do next, but the surrounding system must reliably track what has already happened.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Memory helps an agent remember context. State helps a workflow remain correct. They are not the same thing.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  4. A Larger Context Window Doesn't Replace Good Data Architecture
&lt;/h2&gt;

&lt;p&gt;When an AI system struggles with a large codebase, one tempting solution is to give the model more context.&lt;/p&gt;

&lt;p&gt;Sometimes that helps. But it doesn't remove the need to decide which information matters.&lt;/p&gt;

&lt;p&gt;Suppose your repository contains hundreds of projects and more than a million lines of code.&lt;/p&gt;

&lt;p&gt;Sending thousands of files into a model's context window isn't necessarily useful, even if the model technically supports it. Much of that information will be irrelevant to the current task.&lt;/p&gt;

&lt;p&gt;And if the relevant relationship between two files is missing, adding more unrelated files won't automatically make that relationship clear.&lt;/p&gt;

&lt;p&gt;A more useful approach is to build a pipeline that selects and organizes information before it reaches the model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User question
     |
     v
Understand the task
     |
     v
Retrieve relevant files and symbols
     |
     v
Follow dependencies and references
     |
     v
Rank and filter the results
     |
     v
Build focused context
     |
     v
LLM generates an answer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This approach can reduce unnecessary context, improve relevance, and make the system easier to debug.&lt;/p&gt;

&lt;p&gt;It also creates opportunities to cache results, reuse indexes, and apply access controls before sensitive information reaches a model.&lt;/p&gt;

&lt;p&gt;The context window is a resource. The data pipeline determines how effectively we use it.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. AI Agents Need Observability Beyond Logs
&lt;/h2&gt;

&lt;p&gt;Traditional application observability helps us understand what happened inside a system through logs, metrics, and traces.&lt;/p&gt;

&lt;p&gt;Agentic systems need much of the same infrastructure, but there are additional questions to answer.&lt;/p&gt;

&lt;p&gt;Suppose an agent returns an incorrect answer. Looking only at the final response won't tell us why.&lt;/p&gt;

&lt;p&gt;Was the source data outdated? Did retrieval return the wrong documents? Did a tool call fail? Did the model misinterpret the result? Did an earlier agent pass incomplete information to the next one?&lt;/p&gt;

&lt;p&gt;To investigate the problem, we need visibility into the entire execution.&lt;/p&gt;

&lt;p&gt;For an agent workflow, useful signals include:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Signal&lt;/th&gt;
&lt;th&gt;What it helps us understand&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Retrieved documents&lt;/td&gt;
&lt;td&gt;What information the agent actually saw&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tool calls and results&lt;/td&gt;
&lt;td&gt;Which external operations were performed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;State transitions&lt;/td&gt;
&lt;td&gt;How the workflow progressed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Retries and failures&lt;/td&gt;
&lt;td&gt;Where execution became unreliable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Model and token usage&lt;/td&gt;
&lt;td&gt;Cost, latency, and resource consumption&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Final output and evaluation&lt;/td&gt;
&lt;td&gt;Whether the result met the expected criteria&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Consider a coding agent that claims a bug is fixed.&lt;/p&gt;

&lt;p&gt;A useful trace should help us determine which files it inspected, what changes it proposed, whether tests actually ran, and whether the test results support its conclusion.&lt;/p&gt;

&lt;p&gt;This is more than logging the model's prompt and response. It's observing the behavior of a system that combines probabilistic reasoning with deterministic software components.&lt;/p&gt;

&lt;p&gt;Without that visibility, debugging becomes guesswork.&lt;/p&gt;

&lt;p&gt;And without evaluations, we may not even notice that a change to the retrieval pipeline has made the system worse.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. The Common Thread: Reliable Systems Still Need Reliable Foundations
&lt;/h2&gt;

&lt;p&gt;Looking at AI agents through the lens of data-intensive applications changes how we approach their design.&lt;/p&gt;

&lt;p&gt;Instead of asking only, “Which model should we use?”, we can ask a broader set of engineering questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Is the information complete and up to date?&lt;/li&gt;
&lt;li&gt;Can we trace where an answer came from?&lt;/li&gt;
&lt;li&gt;Is workflow state persisted and recoverable?&lt;/li&gt;
&lt;li&gt;Can we retry failed operations safely?&lt;/li&gt;
&lt;li&gt;Can we observe and evaluate the entire execution?&lt;/li&gt;
&lt;li&gt;Can the system scale without retrieving unnecessary information?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These questions don't replace model selection, prompt engineering, or agent design. They complement them.&lt;/p&gt;

&lt;p&gt;A powerful model is still important. But it operates within a larger system, and the quality of that system places real limits on what the model can accomplish.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Revisiting &lt;em&gt;Designing Data-Intensive Applications&lt;/em&gt; reminded me that many of the difficult problems in AI engineering aren't entirely new.&lt;/p&gt;

&lt;p&gt;We are building new kinds of applications, but we still need to deal with data consistency, derived indexes, distributed execution, state management, fault tolerance, and observability.&lt;/p&gt;

&lt;p&gt;The difference is that we now have LLMs making decisions and interacting with these systems.&lt;/p&gt;

&lt;p&gt;That makes the engineering around them more important, not less.&lt;/p&gt;

&lt;p&gt;If you're building AI agents, don't focus exclusively on making the model smarter. Pay attention to the data it sees, the state it maintains, and the systems it depends on.&lt;/p&gt;

&lt;p&gt;Because sometimes, the problem isn't that your AI agent can't reason.&lt;/p&gt;

&lt;p&gt;It's that the system hasn't given it the right information to reason about.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Further reading&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Martin Kleppmann, &lt;em&gt;&lt;a href="https://dataintensive.net/" rel="noopener noreferrer"&gt;Designing Data-Intensive Applications&lt;/a&gt;&lt;/em&gt;, O'Reilly Media, 2017.&lt;/p&gt;

&lt;p&gt;The book explores the principles behind reliable, scalable, and maintainable data systems, including storage and retrieval, replication, consistency, batch processing, and stream processing. Many of those principles remain useful when designing the infrastructure behind modern AI agents.&lt;/p&gt;

</description>
      <category>data</category>
      <category>agents</category>
      <category>systemdesign</category>
      <category>ai</category>
    </item>
    <item>
      <title>Your MCP Server Needs Better Design for Better Agents</title>
      <dc:creator>Arif Sefa</dc:creator>
      <pubDate>Sat, 24 Oct 2026 17:01:31 +0000</pubDate>
      <link>https://dev.to/arif_sefa_f2d991d373eb93e/your-mcp-server-needs-better-design-for-better-agents-1ka6</link>
      <guid>https://dev.to/arif_sefa_f2d991d373eb93e/your-mcp-server-needs-better-design-for-better-agents-1ka6</guid>
      <description>&lt;p&gt;I’ve been thinking about MCP design a lot lately, especially the gap between &lt;strong&gt;making a tool available&lt;/strong&gt; and &lt;strong&gt;making an agent use it well&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It’s easy to wrap an API in an MCP server, expose a bunch of tools, and call it done. Then the agent picks the wrong tool, guesses a parameter, retries a few times, and burns context just trying to figure out what we meant. The protocol may be working perfectly; the experience still isn’t great.&lt;/p&gt;

&lt;p&gt;So what does a &lt;em&gt;good&lt;/em&gt; MCP server actually look like? I think it comes down to a few practical choices: how we name and scope tools, how much context we expose, where Skills fit, and how we keep the whole thing safe in production.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxk3hgxsclpton5rkaiv9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxk3hgxsclpton5rkaiv9.png" alt="MCP security architecture showing a host, client, and server capabilities" width="800" height="706"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Simple architecture visual: &lt;a href="https://coderlegion.com/14163/the-end-of-glue-code-why-mcp-is-the-usb-c-moment-for-ai-systems" rel="noopener noreferrer"&gt;Coder Legion — The End of Glue Code&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Don’t start by turning everything into MCP
&lt;/h2&gt;

&lt;p&gt;MCP is useful when a capability needs to be reused by different clients, maintained independently, or kept behind a clear security and execution boundary. But it isn’t the right answer for every function an agent calls.&lt;br&gt;
&lt;/p&gt;

&lt;pre data-lang="mermaid"&gt;&lt;code&gt;flowchart LR
    U[User request] --&amp;gt; A[Agent]
    A --&amp;gt; D{Shared capability?}
    D -- No --&amp;gt; F[Local function]
    D -- Yes --&amp;gt; M[MCP server]
    M --&amp;gt; B[Business system]&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;&lt;strong&gt;Use a local function&lt;/strong&gt; for a small, private operation that only one application needs. &lt;strong&gt;Consider MCP&lt;/strong&gt; when multiple compatible clients need the same integration, the integration needs independent deployment or credentials, or you want a governed boundary between an agent and a system.&lt;/p&gt;

&lt;p&gt;For example, a single application formatting a date does not need an MCP server. A company-wide, read-only service that lets approved agents search Jira issues, retrieve service documentation, or inspect deployment status may benefit from one.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;My rule of thumb:&lt;/strong&gt; don’t ask “Can I wrap this in MCP?” Ask “What do I gain by putting this capability behind a shared, independently governed interface?”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  2. Design tools for the way agents actually use them
&lt;/h2&gt;

&lt;p&gt;A common first attempt is to expose an existing REST API almost one-to-one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET /customers/{id}
GET /customers/{id}/accounts
GET /accounts/{id}/transactions
GET /transactions/{id}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That can be appropriate for predictable, low-level operations. But an agent may not know which endpoint to call first, which identifiers are required, or which of the 40 returned fields matter.&lt;/p&gt;

&lt;p&gt;Instead, design a small set of &lt;strong&gt;task-oriented tools&lt;/strong&gt; around the questions users actually ask:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;find_customer(query)
list_customer_accounts(customer_id)
get_account_summary(account_id, period)
get_transaction_details(transaction_id)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The tool names should describe an action in domain language. Avoid vague names such as &lt;code&gt;process_data&lt;/code&gt;, &lt;code&gt;execute&lt;/code&gt;, or &lt;code&gt;get_info&lt;/code&gt;. Avoid exposing internal database column names if the agent has no reason to know them.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example: a tool schema that guides the agent
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Too vague&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"search"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Search records"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"inputSchema"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"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;"object"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"properties"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"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;"string"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"q"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"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;"string"&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;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;&lt;strong&gt;More useful&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"search_service_docs"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Search approved engineering documentation. Use for questions about service behavior, ownership, and integration steps. Does not search source code or production logs."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"inputSchema"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"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;"object"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"properties"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"query"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"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;"string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"A concise question or set of technical keywords"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"service"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"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;"string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"enum"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"cards"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"payments"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"accounts"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"identity"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"limit"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"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;"integer"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"minimum"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"maximum"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"default"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&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;span class="nl"&gt;"required"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"query"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"additionalProperties"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="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;The second schema tells the model what the tool is for, what it should not be used for, and which values are valid. Defaults and limits reduce the amount of guessing. That’s the goal: not a clever description, but fewer avoidable mistakes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Practical guidelines&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use domain words the user and model both understand.&lt;/li&gt;
&lt;li&gt;Make required fields genuinely required; default common optional fields.&lt;/li&gt;
&lt;li&gt;Use enums and numeric bounds where the domain is finite.&lt;/li&gt;
&lt;li&gt;Keep parameter counts manageable. Around eight or fewer is a useful heuristic, not a protocol limit.&lt;/li&gt;
&lt;li&gt;Explain when &lt;em&gt;not&lt;/em&gt; to use a tool if overlap with another tool is likely.&lt;/li&gt;
&lt;li&gt;Keep descriptions informative but not encyclopedic: every token competes for context.&lt;/li&gt;
&lt;/ul&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%2Fwww.splunk.com%2Fcontent%2Fdam%2Fsplunk-blogs%2Fimages%2Fmedia_1687d99880b74e2a42e2c4b5168d1d920ef36a1be.png%3Fformat%3Dpng%26optimize%3Dmedium%26width%3D750" 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%2Fwww.splunk.com%2Fcontent%2Fdam%2Fsplunk-blogs%2Fimages%2Fmedia_1687d99880b74e2a42e2c4b5168d1d920ef36a1be.png%3Fformat%3Dpng%26optimize%3Dmedium%26width%3D750" alt="MCP tools, resources, and prompts connect an agent to external systems" width="750" height="496"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Another view of the MCP building blocks: &lt;a href="https://www.splunk.com/en_us/blog/security/securing-ai-agents-model-context-protocol.html" rel="noopener noreferrer"&gt;Splunk — Securing AI agents with MCP&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Reduce tool confusion and context bloat
&lt;/h2&gt;

&lt;p&gt;More tools don’t automatically make an agent more capable. If a client loads hundreds of similar tool definitions, the model has more to read and more chances to choose the wrong one. This is one of the most important trade-offs in MCP design: too little guidance creates confusion, but too much guidance also eats into the context window.&lt;br&gt;
&lt;/p&gt;

&lt;pre data-lang="mermaid"&gt;&lt;code&gt;flowchart TD
    Q[User request] --&amp;gt; R[Find relevant tool]
    R --&amp;gt; T[Call focused tool]
    T --&amp;gt; S[Return concise result]
    S --&amp;gt; D[Fetch details if needed]&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;A useful pattern is &lt;strong&gt;progressive disclosure&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Keep the always-visible tool catalog small and clear.&lt;/li&gt;
&lt;li&gt;Offer a lightweight discovery/search tool when the catalog is large.&lt;/li&gt;
&lt;li&gt;Load detailed schemas, domain vocabulary, or instructions only when needed.&lt;/li&gt;
&lt;li&gt;Return a compact summary by default and provide a separate detail operation.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For example, &lt;code&gt;search_transactions&lt;/code&gt; might return transaction ID, date, merchant, and amount. A separate &lt;code&gt;get_transaction_details&lt;/code&gt; tool can return status, fees, and settlement information when needed.&lt;/p&gt;

&lt;p&gt;This is often better than returning 50 fields on every call.&lt;/p&gt;

&lt;h3&gt;
  
  
  Choosing a strategy
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Strategy&lt;/th&gt;
&lt;th&gt;Good when&lt;/th&gt;
&lt;th&gt;Main trade-off&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Clearer descriptions&lt;/td&gt;
&lt;td&gt;You need a quick improvement without backend refactoring&lt;/td&gt;
&lt;td&gt;Longer descriptions consume more context&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Better schemas and defaults&lt;/td&gt;
&lt;td&gt;Inputs have predictable types and valid values&lt;/td&gt;
&lt;td&gt;Schemas need maintenance as the domain changes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Split tools by task&lt;/td&gt;
&lt;td&gt;One tool currently does too many things&lt;/td&gt;
&lt;td&gt;More tools can increase discovery complexity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;On-demand discovery&lt;/td&gt;
&lt;td&gt;The catalog is large or changes often&lt;/td&gt;
&lt;td&gt;Adds a discovery call and some latency&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Server-side interpretation&lt;/td&gt;
&lt;td&gt;Requests use complex business language and must behave consistently&lt;/td&gt;
&lt;td&gt;Adds inference cost, latency, and another component&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;One agent-backed tool&lt;/td&gt;
&lt;td&gt;You need to hide a complex workflow behind a stable interface&lt;/td&gt;
&lt;td&gt;Less transparency; harder debugging and higher operational cost&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Do not start with a server-side LLM just to compensate for poor names and schemas. First try clearer tool boundaries, validation, defaults, and compact results. Add model-based interpretation only when evaluation shows it is needed.&lt;/p&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%2F9ylkg0rcc0pcl7j1s3xj.jpeg" 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%2F9ylkg0rcc0pcl7j1s3xj.jpeg" alt="Skills and MCP serve different but complementary roles in an AI agent setup" width="800" height="787"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Visual comparison of Skills and MCP: &lt;a href="https://blog.dailydoseofds.com/p/what-are-agent-skills-and-how-agents" rel="noopener noreferrer"&gt;Daily Dose of Data Science&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Tools, resources, prompts, and skills are not interchangeable
&lt;/h2&gt;

&lt;p&gt;MCP exposes different primitives for different jobs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Tools&lt;/strong&gt; perform actions or computations: &lt;code&gt;create_ticket&lt;/code&gt;, &lt;code&gt;search_logs&lt;/code&gt;, &lt;code&gt;get_payment_status&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resources&lt;/strong&gt; expose context or data: &lt;code&gt;service://payments/runbook&lt;/code&gt;, &lt;code&gt;schema://customer&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prompts&lt;/strong&gt; provide reusable prompt templates or workflows a client can offer to a user.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Skills&lt;/strong&gt; are usually instruction packages that explain &lt;em&gt;how to approach a task&lt;/em&gt;, often with supporting files, examples, or scripts. Their behavior depends on the host that loads them.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A skill can tell an agent how to investigate a failed payment. MCP tools can provide the live capabilities it needs to query a payment status or inspect an approved log source.&lt;br&gt;
&lt;/p&gt;

&lt;pre data-lang="mermaid"&gt;&lt;code&gt;flowchart LR
    U[Investigate failed payment] --&amp;gt; SK[Skill: playbook]
    SK --&amp;gt; A[Agent]
    A --&amp;gt; M[MCP tools and resources]
    M --&amp;gt; O[Evidence-based summary]&lt;/code&gt;&lt;/pre&gt;



&lt;h3&gt;
  
  
  MCP vs. skills: a practical comparison
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Question&lt;/th&gt;
&lt;th&gt;MCP&lt;/th&gt;
&lt;th&gt;Skill&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Primary job&lt;/td&gt;
&lt;td&gt;Standardized access to capabilities and context&lt;/td&gt;
&lt;td&gt;Instructions for performing a task well&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Can execute an external operation?&lt;/td&gt;
&lt;td&gt;Yes, through a tool handler&lt;/td&gt;
&lt;td&gt;Not inherently; may direct the agent to tools or scripts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Can explain a multi-step method?&lt;/td&gt;
&lt;td&gt;Possible, but not its main purpose&lt;/td&gt;
&lt;td&gt;Yes—this is a core strength&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Portability&lt;/td&gt;
&lt;td&gt;Across compatible MCP clients, subject to supported features and auth&lt;/td&gt;
&lt;td&gt;Depends on host skill format and supported loading behavior&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Typical failure mode&lt;/td&gt;
&lt;td&gt;Tool ambiguity, unsafe access, poor schemas, latency&lt;/td&gt;
&lt;td&gt;Instructions may not load, may be stale, or may reference unavailable tools&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The “MCP is dead; Skills won” debate gets less useful when it assumes we have to choose one. A Skill can tell an agent &lt;em&gt;when and how&lt;/em&gt; to investigate a problem; MCP can provide the actual capability to query a service or retrieve data. There is overlap, of course. A small workflow might be perfectly fine as a Skill that uses tools the host already has. I’d choose based on the runtime, reuse, and governance needs—not the latest hot take.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Don’t turn your whole Swagger file into a tool catalog
&lt;/h2&gt;

&lt;p&gt;Imagine you have a Swagger/OpenAPI file with 500 endpoints. Exposing all 500 as MCP tools might feel like the quickest route, but it usually pushes the hard part onto the model: figuring out which endpoint matters, what sequence to call, and which fields are valid.&lt;/p&gt;

&lt;p&gt;A discovery layer can help, but it should narrow the options to approved operations—not decide permissions.&lt;/p&gt;

&lt;p&gt;A better design adds a discovery and policy layer:&lt;br&gt;
&lt;/p&gt;

&lt;pre data-lang="mermaid"&gt;&lt;code&gt;flowchart TD
    O[Swagger / OpenAPI] --&amp;gt; I[Index and group endpoints]
    I --&amp;gt; G[Allowlist and authorization]
    G --&amp;gt; M[Discover focused MCP tool]
    M --&amp;gt; V[Validate and call API]
    V --&amp;gt; R[Normalize result and errors]&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;For example, index endpoint metadata such as operation ID, method, path, summary, tags, request schema, response schema, and required scopes. Search that index using keywords and semantic similarity if useful. But retrieval should only help select from an &lt;strong&gt;approved&lt;/strong&gt; catalog; it must not grant permissions.&lt;/p&gt;

&lt;p&gt;Expose focused operations such as &lt;code&gt;get_card_summary&lt;/code&gt; or &lt;code&gt;list_payment_methods&lt;/code&gt; when they map to meaningful user tasks. Keep raw endpoint access behind a deliberate, restricted tool only if advanced workflows truly need it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;JSON index or vector database?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Start with a generated JSON index when the catalog is manageable and exact keyword/tag search works.&lt;/li&gt;
&lt;li&gt;Add embeddings or hybrid search when users describe operations in natural language and vocabulary differs from API terminology.&lt;/li&gt;
&lt;li&gt;Keep the source of truth in OpenAPI; regenerate the index and test it in CI.&lt;/li&gt;
&lt;li&gt;Never treat a vector match as authorization or proof that an operation is safe.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  6. Make failure useful
&lt;/h2&gt;

&lt;p&gt;A tool call will fail sometimes. The design question is whether the failure helps the agent recover or leaves it guessing.&lt;/p&gt;

&lt;p&gt;An MCP tool is a contract between an uncertain caller and a real system. Validate every argument server-side—even if the schema is strict—because clients, models, and callers can still be wrong.&lt;/p&gt;

&lt;p&gt;A useful result should be compact, structured when appropriate, and explicit about what happened.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Weak error&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Request failed"&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;&lt;strong&gt;Actionable error&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"INVALID_PERIOD"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"The period must be one of: 7d, 30d, 90d."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"retryable"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="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;A good error tells the agent what can be corrected without exposing stack traces, secrets, internal hostnames, or sensitive data. In other words: be specific about the fix, not about your internal implementation.&lt;/p&gt;

&lt;p&gt;Design for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Bounded output:&lt;/strong&gt; pagination, result limits, field selection, summaries, and detail-on-demand.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Predictable errors:&lt;/strong&gt; stable error codes and useful recovery hints.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Timeouts and cancellation:&lt;/strong&gt; downstream calls must not hang indefinitely.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Retries:&lt;/strong&gt; retry only transient failures; avoid blindly retrying non-idempotent actions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Idempotency:&lt;/strong&gt; for operations such as creating a ticket or initiating a payment, support an idempotency key or equivalent deduplication mechanism.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Explicit state:&lt;/strong&gt; if a multi-step operation needs a durable handle, return an opaque workflow or resource ID and validate it on every subsequent call.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For long or multi-stage tasks, avoid pretending one giant tool call is always the best interface. Use explicit stages, durable state, and status checks where they improve observability and recovery.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Security can’t live in the tool description
&lt;/h2&gt;

&lt;p&gt;A description saying “only use this carefully” is not a security control. The server has to enforce the rules even when the model gets the call wrong.&lt;/p&gt;

&lt;p&gt;MCP does not make an unsafe backend safe. It can make a capability easier for an agent to reach, so access control and execution boundaries matter.&lt;/p&gt;

&lt;h3&gt;
  
  
  A safer request path
&lt;/h3&gt;



&lt;pre data-lang="mermaid"&gt;&lt;code&gt;flowchart LR
    A[Agent] --&amp;gt; P[Authenticate and authorize]
    P --&amp;gt; V[Validate request]
    V --&amp;gt; H[Run tool safely]
    H --&amp;gt; L[Audit and monitor]&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;&lt;strong&gt;Minimum production checklist&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Apply least privilege to tools, service accounts, database roles, and filesystem access.&lt;/li&gt;
&lt;li&gt;Enforce authorization on the server for every call; never rely on a tool description or model judgment.&lt;/li&gt;
&lt;li&gt;Separate read-only tools from write or destructive tools.&lt;/li&gt;
&lt;li&gt;Require explicit user confirmation for consequential actions, such as deleting records, sending messages externally, or moving money.&lt;/li&gt;
&lt;li&gt;Validate paths, URLs, identifiers, enum values, and payload sizes. Prevent path traversal, SSRF, SQL injection, and command injection.&lt;/li&gt;
&lt;li&gt;Use parameterized queries and safe process APIs; do not concatenate model-generated text into SQL or shell commands.&lt;/li&gt;
&lt;li&gt;Keep secrets out of prompts, tool descriptions, errors, and logs.&lt;/li&gt;
&lt;li&gt;Treat tool outputs, retrieved documents, and remote content as untrusted input: they may contain prompt-injection instructions.&lt;/li&gt;
&lt;li&gt;Pin and review server dependencies, scan code, sandbox where appropriate, and monitor changes to tool definitions and behavior.&lt;/li&gt;
&lt;li&gt;Use authenticated transport for remote servers, and verify identity, token audience, scopes, and authorization boundaries.&lt;/li&gt;
&lt;li&gt;Record who called what, with which authorization context, and what outcome occurred—without logging unnecessary sensitive payloads.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A tool called &lt;code&gt;delete_customer&lt;/code&gt; is not safe merely because its description says “be careful.” Enforce the rules in code. For high-impact actions, use a two-phase design:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;prepare_transfer(amount, destination)
  -&amp;gt; transfer summary + policy checks + confirmation token

confirm_transfer(confirmation_token)
  -&amp;gt; execute only if token is valid, unexpired, and bound to the approved request
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The token should be server-generated and bound to the exact action, actor, and relevant parameters. Confirmation must not become a generic approval for a different action.&lt;/p&gt;

&lt;h2&gt;
  
  
  8. A few patterns I’d choose—and a few I’d avoid
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Prefer&lt;/th&gt;
&lt;th&gt;Avoid&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;get_payment_status(payment_id)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;do_operation(type, payload)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Intent is clearer and arguments are easier to validate&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Small, domain-focused servers&lt;/td&gt;
&lt;td&gt;One giant server for every company system&lt;/td&gt;
&lt;td&gt;Limits blast radius and simplifies ownership&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Short default responses + detail tools&lt;/td&gt;
&lt;td&gt;Returning every field by default&lt;/td&gt;
&lt;td&gt;Reduces token cost and noise&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Server-side authorization&lt;/td&gt;
&lt;td&gt;“The model knows not to do that”&lt;/td&gt;
&lt;td&gt;Models are not security boundaries&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Read/write separation&lt;/td&gt;
&lt;td&gt;One tool with hidden destructive modes&lt;/td&gt;
&lt;td&gt;Makes risk and approval requirements explicit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Stable error codes + recovery hints&lt;/td&gt;
&lt;td&gt;Raw stack traces or “failed”&lt;/td&gt;
&lt;td&gt;Supports reliable recovery without leaking internals&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Evaluation fixtures and telemetry&lt;/td&gt;
&lt;td&gt;“It worked in my demo”&lt;/td&gt;
&lt;td&gt;Makes regressions measurable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MCP where reuse/isolation matter&lt;/td&gt;
&lt;td&gt;MCP for every helper function&lt;/td&gt;
&lt;td&gt;Avoids needless infrastructure and latency&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  The trade-offs you should acknowledge
&lt;/h3&gt;

&lt;p&gt;MCP brings a common interface and a useful integration boundary, but it also adds serialization, process/network hops, configuration, version compatibility, and another component to operate. Tool discovery and rich schemas can consume context. A standardized protocol does not guarantee standardized business semantics. And security risks still exist at the tool, identity, and downstream-system layers.&lt;/p&gt;

&lt;p&gt;The answer isn’t to dismiss MCP or put everything behind it. It’s to measure whether the boundary earns its keep: does it improve reuse, safety, consistency, or operations enough to justify the extra moving parts?&lt;/p&gt;

&lt;h2&gt;
  
  
  9. Test whether the agent can use the tools—not just whether the code runs
&lt;/h2&gt;

&lt;p&gt;Unit tests can prove that a handler works for valid input. They cannot prove that an agent will select it correctly.&lt;/p&gt;

&lt;p&gt;Build an evaluation set with realistic requests:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;“Show my latest card payment” (clear intent)&lt;/li&gt;
&lt;li&gt;“What happened to the payment from yesterday?” (ambiguous identifiers)&lt;/li&gt;
&lt;li&gt;“Delete all test records” (potentially destructive)&lt;/li&gt;
&lt;li&gt;“Find the card endpoint” (domain-language mismatch)&lt;/li&gt;
&lt;li&gt;“Show me everything” (output explosion risk)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Track at least:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Correct tool selection&lt;/li&gt;
&lt;li&gt;Argument validity&lt;/li&gt;
&lt;li&gt;Task completion and factual correctness&lt;/li&gt;
&lt;li&gt;Number of tool calls and retries&lt;/li&gt;
&lt;li&gt;Latency, errors, and token usage&lt;/li&gt;
&lt;li&gt;Unauthorized-action rejection&lt;/li&gt;
&lt;li&gt;Regression rate after schema or description changes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Test against more than one model if your server is meant to support multiple clients. Use deterministic fixtures for business rules and separate model-dependent evaluations from ordinary unit tests. Include adversarial inputs and malicious content in retrieved data.&lt;/p&gt;

&lt;h2&gt;
  
  
  10. How I’d build a first version
&lt;/h2&gt;

&lt;p&gt;For a new MCP server, build in this order:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Define the boundary:&lt;/strong&gt; users, systems, data, permissions, and operations in scope.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pick a few high-value tasks:&lt;/strong&gt; avoid exposing the entire backend on day one.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Design schemas:&lt;/strong&gt; clear names, tight constraints, safe defaults, and bounded output.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Separate primitives:&lt;/strong&gt; tools for actions, resources for context, prompts for reusable templates; use skills for task instructions when the host supports them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Implement policy in code:&lt;/strong&gt; authentication, authorization, validation, approval, timeouts, and idempotency.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Add observability:&lt;/strong&gt; correlation IDs, structured logs, metrics, traces, and audit events.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Create evals before broad rollout:&lt;/strong&gt; include happy paths, ambiguous prompts, edge cases, and attack scenarios.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Measure and iterate:&lt;/strong&gt; improve tool discovery and descriptions using actual failure data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Version and govern:&lt;/strong&gt; review changes to tool names, schemas, permissions, and semantics as API changes.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The point isn’t to expose more tools
&lt;/h2&gt;

&lt;p&gt;The best MCP server isn’t the one with the longest tool list. It’s the one an agent can use without guessing, retrying needlessly, or being given more access than it needs.&lt;/p&gt;

&lt;p&gt;Use MCP when a shared, governed interface is worth the extra boundary. Use Skills to explain a repeatable way of working when the host supports them. Use a direct function when that’s all you need. And combine the approaches when each has a clear job.&lt;/p&gt;

&lt;p&gt;For me, the design goal is simple: &lt;strong&gt;make the right action easy to choose, hard to misuse, and straightforward to debug.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>agents</category>
      <category>ai</category>
      <category>mcp</category>
      <category>architecture</category>
    </item>
    <item>
      <title>ACP: AI Agents Need a Common Language</title>
      <dc:creator>Arif Sefa</dc:creator>
      <pubDate>Wed, 21 Oct 2026 16:58:33 +0000</pubDate>
      <link>https://dev.to/arif_sefa_f2d991d373eb93e/acp-ai-agents-need-a-common-language-1c8j</link>
      <guid>https://dev.to/arif_sefa_f2d991d373eb93e/acp-ai-agents-need-a-common-language-1c8j</guid>
      <description>&lt;p&gt;&lt;em&gt;From isolated AI assistants to interoperable agent systems, with practical examples in software development, banking, and distributed systems.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;What happens when your AI agents are good at their jobs but terrible at working together?&lt;/p&gt;

&lt;p&gt;Your backend agent is written in Python. Your frontend agent runs on TypeScript. Your testing agent uses a different framework, and your incident analysis agent lives in another service.&lt;/p&gt;

&lt;p&gt;Individually, everything works. But the moment you try to connect them, you start writing adapters, translating payloads, handling different execution models, and maintaining a growing collection of custom integrations.&lt;/p&gt;

&lt;p&gt;I've been thinking about this problem while exploring multi-agent development workflows. The interesting challenge isn't just getting an agent to complete a task. It's making independently developed agents collaborate without coupling the entire system to one framework or runtime.&lt;/p&gt;

&lt;p&gt;That's where &lt;strong&gt;Agent Communication Protocol (ACP)&lt;/strong&gt; becomes interesting.&lt;/p&gt;

&lt;p&gt;In this article, we'll explore the original IBM/BeeAI ACP approach, walk through practical examples, compare ACP with MCP and A2A, and discuss what these protocols mean when you're building a real multi-agent system.&lt;/p&gt;

&lt;p&gt;One important note before we begin: ACP can refer to different projects. This article focuses on the original IBM/BeeAI Agent Communication Protocol, whose development has since converged with the A2A ecosystem.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ACP&lt;/strong&gt; was designed to standardize communication between independently implemented AI agents.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MCP&lt;/strong&gt; focuses on how AI applications connect to tools, resources, and external capabilities.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A2A&lt;/strong&gt; provides a standardized approach to communication and task delegation between agents.&lt;/li&gt;
&lt;li&gt;These protocols address different integration boundaries and can complement one another.&lt;/li&gt;
&lt;li&gt;A protocol doesn't replace orchestration, security, observability, or reliable error handling.&lt;/li&gt;
&lt;li&gt;For new implementations, check the current A2A specification and official ACP migration guidance before choosing a protocol or SDK.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  1. The problem isn't building agents. It's connecting them.
&lt;/h2&gt;

&lt;p&gt;Building a single AI agent is becoming relatively straightforward. Frameworks provide model integrations, tool calling, memory, planning, and workflow execution.&lt;/p&gt;

&lt;p&gt;The harder problem appears when you want multiple agents to collaborate.&lt;/p&gt;

&lt;p&gt;Consider three independently developed agents:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A research agent that uses Python.&lt;/li&gt;
&lt;li&gt;A reporting agent that runs on Node.js.&lt;/li&gt;
&lt;li&gt;A visualization agent that uses a separate service.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each agent might work perfectly on its own. However, they may expose completely different interfaces.&lt;/p&gt;

&lt;p&gt;One expects:&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;"query"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Analyze monthly revenue"&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;Another expects:&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;"task_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;"report"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"parameters"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"metric"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"revenue"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"period"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"monthly"&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;And the third might require a CSV file uploaded to a particular endpoint.&lt;/p&gt;

&lt;p&gt;Now the orchestrator needs to understand all three interfaces, translate requests, handle errors, and interpret the results.&lt;/p&gt;

&lt;p&gt;Add five more agents, and the integration layer becomes another software product you have to maintain.&lt;/p&gt;

&lt;p&gt;This is the actual problem: &lt;strong&gt;agents can be intelligent individually but still be incompatible as a system.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A communication protocol aims to standardize the interaction layer without requiring every agent to use the same internal implementation.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. What exactly is ACP?
&lt;/h2&gt;

&lt;p&gt;The Agent Communication Protocol developed by IBM Research and the BeeAI ecosystem is an open protocol intended to make AI agents interoperable.&lt;/p&gt;

&lt;p&gt;The core idea is simple:&lt;/p&gt;

&lt;p&gt;An agent should be able to communicate through a predictable interface without requiring the caller to understand its internal implementation.&lt;/p&gt;

&lt;p&gt;For example, the caller shouldn't need to know whether the receiving agent uses Python or TypeScript, LangGraph or a custom execution engine, a cloud-hosted LLM or a locally deployed model.&lt;/p&gt;

&lt;p&gt;The caller needs to understand the agent's capabilities, how to send a request, and how to interpret the response.&lt;/p&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%2Fhhnbl7knv6602g4lel5h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhhnbl7knv6602g4lel5h.png" alt="Multi-agent system architecture with an orchestrator, specialized agents, and a shared communication layer" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Illustration: An orchestrator coordinates specialized agents through a communication layer. Source: &lt;a href="https://cogitx.ai/blog/multi-agent-ai-systems-architecture-guide-for-engineering-leaders" rel="noopener noreferrer"&gt;CogitX — Multi-Agent AI Systems Architecture Guide&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Conceptually, the architecture looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                  User Request
                       |
                       v
                Orchestrator Agent
                       |
              Standardized Interface
                       |
           +-----------+-----------+
           |           |           |
           v           v           v
      Research      Coding      Testing
       Agent        Agent        Agent
       Python      TypeScript    Python
           |           |           |
           v           v           v
       Research      Code        Test
        Result      Changes      Report
           |           |           |
           +-----------+-----------+
                       |
                       v
                 Final Response
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The agents remain independent. The communication layer provides a common way for them to exchange requests and results.&lt;/p&gt;

&lt;p&gt;This distinction matters. ACP is a communication protocol, not a magic system that automatically makes agents intelligent, coordinates every decision, or guarantees correct results.&lt;/p&gt;

&lt;p&gt;You still need application logic to decide which agent should do what, when to invoke it, and what to do if something goes wrong.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. A practical example: building a feature with multiple agents
&lt;/h2&gt;

&lt;p&gt;Let's use a realistic software development scenario.&lt;/p&gt;

&lt;p&gt;A developer enters this request:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Add a virtual card creation screen, implement the corresponding backend endpoint, and write tests for the new flow.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The orchestrator breaks the request into tasks.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: The planner identifies the work
&lt;/h3&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;"task"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Implement virtual card creation"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"subtasks"&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="s2"&gt;"Inspect the existing card creation flow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"Implement the backend endpoint"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"Build the mobile screen"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"Write integration tests"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"Review security and validation"&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;This is an illustrative application-level task description, not a prescribed ACP wire format.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: The orchestrator delegates to specialized agents
&lt;/h3&gt;

&lt;p&gt;The backend agent receives the API task. The frontend agent receives the screen requirements. The testing agent receives the expected behavior and acceptance criteria.&lt;/p&gt;

&lt;p&gt;Each agent can use its own framework and tools.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Agents return structured results
&lt;/h3&gt;

&lt;p&gt;For example, the backend agent might produce:&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;"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;"completed"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"summary"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Implemented virtual card creation endpoint"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"artifacts"&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="s2"&gt;"VirtualCardController.cs"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"CreateVirtualCardRequest.cs"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"VirtualCardService.cs"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"tests"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"passed"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"failed"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&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;The frontend agent could return a similar result containing its changed files, UI behavior, and test status.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: The orchestrator combines the results
&lt;/h3&gt;

&lt;p&gt;It checks dependencies, determines whether the frontend can integrate with the endpoint, and sends any failures back to the relevant agent.&lt;/p&gt;

&lt;p&gt;The testing agent might discover that the backend accepts a missing cardholder identifier. The orchestrator can route that finding back to the backend agent for correction.&lt;/p&gt;

&lt;p&gt;The important point is that the agents don't have to share the same runtime or implementation framework to participate in the same workflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. What happens when an agent needs another agent?
&lt;/h2&gt;

&lt;p&gt;Suppose a customer support agent receives this request:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;My virtual card was created successfully, but I can't see it in the mobile application.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The support agent doesn't necessarily have the expertise or permissions to diagnose the entire issue.&lt;/p&gt;

&lt;p&gt;It may need help from several specialized agents:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A card-service agent checks whether the virtual card exists.&lt;/li&gt;
&lt;li&gt;An API diagnostics agent investigates the backend response.&lt;/li&gt;
&lt;li&gt;A mobile diagnostics agent checks the card-list rendering flow.&lt;/li&gt;
&lt;li&gt;A reporting agent combines the findings.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;An illustrative interaction might look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Support Agent
     |
     | Diagnose missing virtual card
     v
Orchestrator
     |
     +----&amp;gt; Card Agent
     |          |
     |          +----&amp;gt; Card exists
     |
     +----&amp;gt; API Agent
     |          |
     |          +----&amp;gt; Response is successful
     |
     +----&amp;gt; Mobile Agent
                |
                +----&amp;gt; Card list uses stale cached data

     |
     v
Orchestrator combines evidence
     |
     v
Support Agent returns diagnosis
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice that the agents don't need access to one another's private prompts, internal reasoning, or entire memory stores.&lt;/p&gt;

&lt;p&gt;They need a well-defined way to exchange the information required for the task.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Collaboration doesn't have to mean sharing everything.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In a real implementation, the orchestrator would also need to validate permissions, ensure that sensitive customer information is handled appropriately, and distinguish confirmed findings from hypotheses.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. ACP's design: why HTTP matters
&lt;/h2&gt;

&lt;p&gt;One of the notable characteristics of the IBM/BeeAI ACP design is its HTTP-native, REST-oriented approach.&lt;/p&gt;

&lt;p&gt;That is useful because most production systems already understand HTTP.&lt;/p&gt;

&lt;p&gt;You can inspect requests, test endpoints, apply standard networking infrastructure, and integrate with existing authentication and observability systems.&lt;/p&gt;

&lt;p&gt;The original protocol supports synchronous and asynchronous interactions, streaming through Server-Sent Events (SSE), and messages containing different kinds of content.&lt;/p&gt;

&lt;p&gt;Let's look at what these concepts mean for developers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Synchronous communication
&lt;/h3&gt;

&lt;p&gt;A caller sends a request and waits for the result.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Client
  |
  | Request
  v
Classification Agent
  |
  | Result
  v
Client
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An illustrative request might be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"task"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"classify_support_ticket"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"input"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"My card payment was declined"&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;The corresponding application-level response could be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"category"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"card_payment"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"confidence"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.94&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;These JSON objects illustrate the task and result; they are not intended to define ACP's exact wire schema.&lt;/p&gt;

&lt;h3&gt;
  
  
  Asynchronous communication
&lt;/h3&gt;

&lt;p&gt;Now imagine asking an agent to analyze a repository containing hundreds of projects.&lt;/p&gt;

&lt;p&gt;That job might take several minutes. Keeping an HTTP request open for the entire execution may be inconvenient or unreliable.&lt;/p&gt;

&lt;p&gt;Instead, the caller can initiate a task, receive an identifier, and check its progress later.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Orchestrator
     |
     | Start repository analysis
     v
Analysis Agent
     |
     | Return task identifier
     v
Orchestrator
     |
     | Continue other work
     |
     | Check status later
     v
Analysis Agent
     |
     | Completed result
     v
Orchestrator
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An illustrative task record could be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"task_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"repo-analysis-42"&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;"running"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"progress"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"completed"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"total"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;8&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;Later, the agent might return:&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;"task_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"repo-analysis-42"&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;"completed"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"result"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"services_analyzed"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"dependencies_found"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;46&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"issues_identified"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;7&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;These are conceptual application-level examples rather than canonical ACP payloads.&lt;/p&gt;

&lt;p&gt;The architectural benefit is that the caller doesn't need to block while the agent performs a long-running task.&lt;/p&gt;

&lt;h3&gt;
  
  
  Streaming communication
&lt;/h3&gt;

&lt;p&gt;Sometimes waiting for the complete response isn't ideal either.&lt;/p&gt;

&lt;p&gt;Imagine a code review agent analyzing a large merge request. The user wants to see findings as they become available.&lt;/p&gt;

&lt;p&gt;A streaming interaction can expose progress and incremental output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Review started
    |
    +--&amp;gt; Inspecting changed files
    |
    +--&amp;gt; Checking dependency changes
    |
    +--&amp;gt; Found a possible authorization issue
    |
    +--&amp;gt; Reviewing test coverage
    |
    +--&amp;gt; Final report available
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is useful for developer tools, interactive assistants, monitoring dashboards, and long-running research workflows.&lt;/p&gt;

&lt;p&gt;The exact streaming events and payloads depend on the protocol implementation and the application's contract.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Agent discovery: how do you know which agent to call?
&lt;/h2&gt;

&lt;p&gt;Suppose your organization has 50 agents.&lt;/p&gt;

&lt;p&gt;Some analyze logs, some review code, others investigate payment failures, and a few generate reports.&lt;/p&gt;

&lt;p&gt;Hardcoding every agent into the orchestrator creates a maintenance problem. Every time a new agent is added, the orchestrator may need another integration.&lt;/p&gt;

&lt;p&gt;Discovery addresses a related problem: identifying available agents and understanding their declared capabilities.&lt;/p&gt;

&lt;p&gt;Imagine an agent description 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;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"log-analysis-agent"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Analyzes application logs and identifies likely causes of failures"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"capabilities"&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="s2"&gt;"error_correlation"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"request_trace_analysis"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"failure_summary"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"input_types"&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="s2"&gt;"text/plain"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"application/json"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"output_types"&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="s2"&gt;"application/json"&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;This is an illustrative agent manifest, not an exact ACP specification.&lt;/p&gt;

&lt;p&gt;The orchestrator can use this metadata to determine that the log analysis agent is a candidate for a request involving an HTTP 500 error.&lt;/p&gt;

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

&lt;blockquote&gt;
&lt;p&gt;Find the likely reason why virtual card creation failed for a specific request.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The orchestrator identifies the task as log analysis, selects an agent that advertises the relevant capability, and delegates the work.&lt;/p&gt;

&lt;p&gt;A different request, such as generating a chart from the findings, could be routed to a visualization agent.&lt;/p&gt;

&lt;p&gt;Discovery becomes particularly valuable when agents are developed by different teams or deployed independently.&lt;/p&gt;

&lt;p&gt;One important limitation: declared capabilities are not proof that an agent can solve a task correctly. A production system still needs validation, access control, health monitoring, and fallback behavior.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. A real-world example: investigating a failed payment
&lt;/h2&gt;

&lt;p&gt;Let's move from the development team to a banking environment.&lt;/p&gt;

&lt;p&gt;A payment request failed. The user wants to know why.&lt;/p&gt;

&lt;p&gt;Several systems may be involved:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The mobile application.&lt;/li&gt;
&lt;li&gt;A backend-for-frontend (BFF).&lt;/li&gt;
&lt;li&gt;The payment service.&lt;/li&gt;
&lt;li&gt;An authorization service.&lt;/li&gt;
&lt;li&gt;An external payment provider.&lt;/li&gt;
&lt;li&gt;Centralized logs and tracing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A traditional diagnostic script might follow a fixed sequence of API calls. An agent-based system can instead delegate specialized investigations and combine their evidence.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                    Incident Request
                           |
                           v
                    Triage Agent
                           |
             +-------------+-------------+
             |             |             |
             v             v             v
         Log Agent      API Agent     Payment Agent
             |             |             |
             v             v             v
        HTTP 500       Request DTO    Provider timeout
             |             |             |
             +-------------+-------------+
                           |
                           v
                     Evidence Review
                           |
                           v
                     Final Diagnosis
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The log agent might find a correlated error. The API agent could confirm that the request reached the correct endpoint. The payment agent might identify a timeout from the external provider.&lt;/p&gt;

&lt;p&gt;An example of a structured finding:&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;"finding"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Payment provider timeout"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"evidence"&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;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;"payment-service"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"observation"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Provider request exceeded the configured timeout"&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;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;"application-logs"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"observation"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"The payment request returned HTTP 500"&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;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;"medium"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"recommended_next_step"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Check provider availability and retry policy"&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;This example deliberately separates evidence from the recommendation.&lt;/p&gt;

&lt;p&gt;The agent should not claim that the provider caused the failure merely because it found an HTTP 500. The evidence must support that conclusion.&lt;/p&gt;

&lt;p&gt;This is where a robust agent architecture goes beyond connecting endpoints: it needs traceability, structured results, and a way to distinguish observed facts from inferred explanations.&lt;/p&gt;

&lt;p&gt;ACP can help standardize agent communication. It does not, by itself, guarantee accurate diagnoses or provide the entire incident orchestration system.&lt;/p&gt;

&lt;h2&gt;
  
  
  8. ACP vs. MCP vs. A2A: what is the difference?
&lt;/h2&gt;

&lt;p&gt;These names are easy to confuse because they all appear in discussions about agentic AI.&lt;/p&gt;

&lt;p&gt;The easiest way to understand them is to ask what kind of interaction you're trying to standardize.&lt;/p&gt;

&lt;h3&gt;
  
  
  MCP: connecting an AI application to tools and data
&lt;/h3&gt;

&lt;p&gt;The Model Context Protocol (MCP) provides a standard way for AI applications to access tools, resources, and prompts exposed by MCP servers.&lt;/p&gt;

&lt;p&gt;For example, a coding assistant might use MCP to access GitLab merge requests, an Elasticsearch query tool, a database schema, a filesystem, or an internal API.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AI Assistant
     |
     | Call search_logs tool
     v
MCP Server
     |
     v
Elasticsearch
     |
     v
Search Results
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The main question is: &lt;em&gt;How does the AI application access an external capability through a standard interface?&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  ACP: standardizing communication between agents
&lt;/h3&gt;

&lt;p&gt;The IBM/BeeAI ACP design focuses on enabling agents implemented in different environments to exchange messages through a common interface.&lt;/p&gt;

&lt;p&gt;For example, a support agent can request a diagnosis from a specialized incident agent without needing to know how that agent performs its internal analysis.&lt;/p&gt;

&lt;p&gt;The main question is: &lt;em&gt;How can independently developed agents communicate with one another?&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  A2A: interoperable agent-to-agent communication
&lt;/h3&gt;

&lt;p&gt;Google introduced the Agent2Agent (A2A) protocol to enable agents to discover and collaborate with one another across different platforms.&lt;/p&gt;

&lt;p&gt;It provides a standardized way to describe agent capabilities and interact with remote agents, including task-oriented workflows.&lt;/p&gt;

&lt;p&gt;The main question is: &lt;em&gt;How can agents built by different teams and organizations work together through a common protocol?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7nvp5v709bmgvnajjkv4.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7nvp5v709bmgvnajjkv4.webp" alt="Comparison of MCP and A2A showing tool integration versus agent-to-agent communication" width="800" height="639"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Illustration: MCP and A2A address different communication boundaries. Source: &lt;a href="https://jimmysong.io/zh/book/agentic-design-patterns/15-inter-agent-communication/" rel="noopener noreferrer"&gt;Jimmy Song — Agentic Design Patterns, Inter-Agent Communication&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Here's a simplified comparison:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;MCP&lt;/th&gt;
&lt;th&gt;IBM/BeeAI ACP&lt;/th&gt;
&lt;th&gt;A2A&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Primary focus&lt;/td&gt;
&lt;td&gt;AI applications accessing tools and context&lt;/td&gt;
&lt;td&gt;Communication between agents&lt;/td&gt;
&lt;td&gt;Communication and task delegation between agents&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Typical interaction&lt;/td&gt;
&lt;td&gt;Assistant → tool&lt;/td&gt;
&lt;td&gt;Agent → agent&lt;/td&gt;
&lt;td&gt;Client/agent → remote agent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Standardized interface&lt;/td&gt;
&lt;td&gt;Tools, resources, prompts&lt;/td&gt;
&lt;td&gt;Agent messaging and interaction&lt;/td&gt;
&lt;td&gt;Agent discovery and task interaction&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Common example&lt;/td&gt;
&lt;td&gt;Query application logs&lt;/td&gt;
&lt;td&gt;Ask a diagnostic agent to investigate&lt;/td&gt;
&lt;td&gt;Delegate a task to a remote specialist&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Orchestration&lt;/td&gt;
&lt;td&gt;Usually handled by the application&lt;/td&gt;
&lt;td&gt;Not the complete orchestration layer&lt;/td&gt;
&lt;td&gt;Application logic still coordinates the overall workflow&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This is a conceptual comparison, not a complete feature-by-feature specification.&lt;/p&gt;

&lt;p&gt;The important distinction is that MCP and agent-to-agent protocols address different interaction boundaries. They are not necessarily competing alternatives.&lt;/p&gt;

&lt;h3&gt;
  
  
  How they can work together
&lt;/h3&gt;

&lt;p&gt;Consider an incident investigation assistant.&lt;/p&gt;

&lt;p&gt;The orchestrator delegates a task to a remote diagnostic agent through an agent-to-agent interface. The diagnostic agent then uses MCP to query internal logs and access approved tools.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User
 |
 v
Incident Orchestrator
 |
 | Agent-to-agent request
 v
Diagnostic Agent
 |
 | MCP tool call
 v
Log Search Server
 |
 v
Elasticsearch
 |
 v
Diagnostic Agent
 |
 | Structured result
 v
Incident Orchestrator
 |
 v
User
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a useful architectural pattern because each protocol serves a different purpose.&lt;/p&gt;

&lt;p&gt;The agent-to-agent layer handles collaboration. The tool-access layer handles access to external capabilities.&lt;/p&gt;

&lt;p&gt;You don't need to expose the diagnostic agent's internal tool implementation to every agent that requests its help.&lt;/p&gt;

&lt;h2&gt;
  
  
  9. What does agent-to-agent communication look like?
&lt;/h2&gt;

&lt;p&gt;A useful way to understand A2A is to look at how one agent can discover and delegate work to another.&lt;/p&gt;

&lt;p&gt;For example, a research agent might need a separate data analysis agent to process a spreadsheet.&lt;/p&gt;

&lt;p&gt;The client first discovers the remote agent's declared capabilities, then sends a task using the protocol's defined interaction model.&lt;/p&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%2F9mcmui80h8v1uuome241.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9mcmui80h8v1uuome241.png" alt="A2A protocol diagram showing agent communication, task states, and optional SSE streaming" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Illustration: An A2A interaction using JSON-RPC over HTTP, with optional SSE streaming and task states. Source: &lt;a href="https://dkdndes.medium.com/let-your-ai-agents-speak-a-developers-deep-dive-into-google-s-a2a-protocol-c78d920614d4" rel="noopener noreferrer"&gt;Peter Rosemann — A Developer's Deep-Dive into Google's A2A Protocol&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Conceptually, the workflow looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Research Agent
      |
      | Discover available capabilities
      v
Remote Agent Description
      |
      | Select suitable agent
      v
Data Analysis Agent
      |
      | Execute task
      v
Structured Result
      |
      v
Research Agent
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The key idea is that the calling agent does not need to know the internal implementation of the remote agent.&lt;/p&gt;

&lt;p&gt;A2A defines the communication contract; the remote agent remains responsible for executing its task.&lt;/p&gt;

&lt;p&gt;For exact message fields, task states, and discovery behavior, consult the &lt;a href="https://a2a-protocol.org/latest/" rel="noopener noreferrer"&gt;official A2A documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  10. An important update: ACP and A2A are converging
&lt;/h2&gt;

&lt;p&gt;There is a detail worth understanding before choosing a protocol for a new project.&lt;/p&gt;

&lt;p&gt;The original IBM/BeeAI Agent Communication Protocol should not be treated as an entirely separate, equally active standard alongside A2A without qualification.&lt;/p&gt;

&lt;p&gt;IBM Research's ACP project page states that ACP is now part of A2A under the Linux Foundation and directs developers toward migration guidance.&lt;/p&gt;

&lt;p&gt;That changes how I would approach a new implementation.&lt;/p&gt;

&lt;p&gt;If you're building a new multi-agent system today, I would:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Understand the original ACP design because it provides useful architectural lessons about interoperability and lightweight agent communication.&lt;/li&gt;
&lt;li&gt;Review the current A2A specification and official migration documentation before selecting an implementation.&lt;/li&gt;
&lt;li&gt;Avoid committing to an older ACP-specific SDK or endpoint contract without checking its current maintenance status.&lt;/li&gt;
&lt;li&gt;Keep the application-level task model independent of the transport protocol where practical, making future migrations easier.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Why does this matter?&lt;/p&gt;

&lt;p&gt;Protocols evolve. A system that tightly couples business logic to a particular communication SDK can become difficult to migrate when standards and ecosystems change.&lt;/p&gt;

&lt;p&gt;A clean separation between business logic, agent capabilities, and transport adapters can reduce that risk.&lt;/p&gt;

&lt;p&gt;This is not an argument against learning ACP. Understanding why it was designed helps explain the problems that agent interoperability standards are trying to solve.&lt;/p&gt;

&lt;h2&gt;
  
  
  11. What ACP does not solve
&lt;/h2&gt;

&lt;p&gt;It's tempting to think that adopting a common protocol makes a multi-agent system interoperable, secure, and reliable automatically.&lt;/p&gt;

&lt;p&gt;It doesn't.&lt;/p&gt;

&lt;p&gt;A protocol can standardize communication, but several engineering problems remain.&lt;/p&gt;

&lt;h3&gt;
  
  
  Authentication and authorization
&lt;/h3&gt;

&lt;p&gt;An agent that can investigate a payment incident should not automatically be able to initiate a payment or access every customer's data.&lt;/p&gt;

&lt;p&gt;You still need identity, permissions, scoped credentials, and policy enforcement.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reliable execution
&lt;/h3&gt;

&lt;p&gt;What happens when an agent times out after starting a task? Can the caller retry safely? Could the operation run twice?&lt;/p&gt;

&lt;p&gt;These questions require deliberate handling of timeouts, retries, idempotency, and task state.&lt;/p&gt;

&lt;h3&gt;
  
  
  Semantic compatibility
&lt;/h3&gt;

&lt;p&gt;Two agents may both accept JSON and still disagree about what a field means.&lt;/p&gt;

&lt;p&gt;For example, one agent might interpret &lt;code&gt;amount&lt;/code&gt; as a value in major currency units while another expects minor units.&lt;/p&gt;

&lt;p&gt;A common transport format doesn't eliminate the need for clear schemas and domain contracts.&lt;/p&gt;

&lt;h3&gt;
  
  
  Observability
&lt;/h3&gt;

&lt;p&gt;When a workflow spans six agents, you need to know which agent ran, what task it received, how long it took, and where a failure occurred.&lt;/p&gt;

&lt;p&gt;Correlation IDs, distributed tracing, structured logs, and audit events are still essential.&lt;/p&gt;

&lt;h3&gt;
  
  
  Trust and untrusted output
&lt;/h3&gt;

&lt;p&gt;An agent's response is not automatically correct or safe. It could contain a mistaken diagnosis, malformed data, or instructions that should not be trusted.&lt;/p&gt;

&lt;p&gt;Validate results before using them in sensitive operations.&lt;/p&gt;

&lt;p&gt;For enterprise systems, these concerns are not optional details. They're part of the architecture.&lt;/p&gt;

&lt;h2&gt;
  
  
  12. How I would design a multi-agent system today
&lt;/h2&gt;

&lt;p&gt;If I were building an agent platform from scratch, I would separate it into four layers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;+------------------------------------------------+
|                  User Interface                |
|              Chat / Dashboard / API             |
+------------------------------------------------+
                        |
                        v
+------------------------------------------------+
|              Orchestration Layer               |
| Planning | Routing | Dependencies | Policies    |
+------------------------------------------------+
                        |
                        v
+------------------------------------------------+
|                Agent Layer                     |
|                                                |
| Research | Backend | Frontend | Test | Review  |
+------------------------------------------------+
                        |
                        v
+------------------------------------------------+
|             Integration Layer                  |
| Agent Protocol | MCP | Internal REST APIs       |
+------------------------------------------------+
                        |
                        v
+------------------------------------------------+
|           Enterprise Infrastructure            |
| GitLab | Logs | Databases | Services | CI/CD    |
+------------------------------------------------+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each layer has a different responsibility.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The UI&lt;/strong&gt; shows the task, execution progress, results, and approvals.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The orchestrator&lt;/strong&gt; plans the workflow, selects agents, manages dependencies, and decides when human input is required.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The agents&lt;/strong&gt; perform specialized work and return structured results.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The integration layer&lt;/strong&gt; connects agents to one another and to external capabilities.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The infrastructure&lt;/strong&gt; contains the actual business systems and data.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, a testing agent might discover that a backend task has completed and begin integration testing. If the tests fail, the orchestrator can send the failure report back to the backend agent.&lt;/p&gt;

&lt;p&gt;The protocol helps the agents exchange information. The orchestrator determines what happens next.&lt;/p&gt;

&lt;p&gt;That distinction is worth keeping clear when designing a system with multiple autonomous components.&lt;/p&gt;

&lt;h2&gt;
  
  
  13. The bigger idea: agents should be replaceable components
&lt;/h2&gt;

&lt;p&gt;One of the strongest arguments for agent interoperability is that you shouldn't have to rebuild your entire system every time you replace one agent.&lt;/p&gt;

&lt;p&gt;Suppose your original code review agent uses one framework and model provider.&lt;/p&gt;

&lt;p&gt;Six months later, you find a better implementation that is faster, cheaper, or more accurate.&lt;/p&gt;

&lt;p&gt;If the rest of the system depends on the agent's private APIs, memory format, and internal execution model, replacing it can be expensive.&lt;/p&gt;

&lt;p&gt;If the agent exposes a stable, well-defined interface, the replacement becomes much more manageable.&lt;/p&gt;

&lt;p&gt;The same principle applies to organizations.&lt;/p&gt;

&lt;p&gt;A logistics provider could expose an agent that estimates delivery times. A retailer could use that capability without needing to understand the provider's internal algorithms or infrastructure.&lt;/p&gt;

&lt;p&gt;The integration still needs appropriate authentication, contracts, and compatibility checks. But the architectural goal is clear: make the interaction contract stable while allowing implementations to evolve.&lt;/p&gt;

&lt;p&gt;That's a familiar idea in software engineering. We already rely on interfaces, service contracts, and abstractions to decouple systems.&lt;/p&gt;

&lt;p&gt;Agent communication protocols apply similar principles to a world in which the services being connected can reason, delegate tasks, and produce dynamic outputs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The next challenge in agentic AI isn't simply creating agents that can perform increasingly complex tasks.&lt;/p&gt;

&lt;p&gt;It's creating systems in which independently developed agents can collaborate reliably.&lt;/p&gt;

&lt;p&gt;ACP was an important step toward that goal. Its emphasis on lightweight, HTTP-native communication, asynchronous execution, and interoperability offers useful lessons for anyone building multi-agent systems.&lt;/p&gt;

&lt;p&gt;MCP and agent-to-agent protocols address different parts of the integration problem, and they can complement one another within the same architecture.&lt;/p&gt;

&lt;p&gt;At the same time, the evolution of these standards matters. IBM Research now directs developers toward A2A for the continued evolution of the original ACP work.&lt;/p&gt;

&lt;p&gt;For developers, I think the most useful takeaway is this:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Don't build a multi-agent system around the assumption that every agent will always use the same framework, model, or runtime. Build around clear capabilities and stable communication contracts instead.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The more independently your agents can evolve, the easier it becomes to experiment, replace components, and scale the system without rewriting everything around them.&lt;/p&gt;

&lt;p&gt;And that is what makes agent interoperability an engineering problem worth paying attention to.&lt;/p&gt;

&lt;h2&gt;
  
  
  References and further reading
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://www.ibm.com/think/topics/agent-communication-protocol" rel="noopener noreferrer"&gt;IBM Think — What is Agent Communication Protocol (ACP)?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://research.ibm.com/projects/agent-communication-protocol" rel="noopener noreferrer"&gt;IBM Research — Agent Communication Protocol&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/i-am-bee/agentstack/blob/main/docs/stable/community/acp-a2a-migration-guide.mdx" rel="noopener noreferrer"&gt;ACP to A2A Migration Guide&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;Note: The arXiv paper proposes a separate research approach also called ACP. It should be read as a research proposal, not as the official specification of the original IBM/BeeAI protocol. The JSON examples in this article are illustrative application-level payloads, not canonical ACP or A2A wire formats.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>architecture</category>
      <category>agenticdevelopment</category>
    </item>
    <item>
      <title>Why Most Multi-Agent Systems Don't Ship Software?</title>
      <dc:creator>Arif Sefa</dc:creator>
      <pubDate>Fri, 16 Oct 2026 18:18:24 +0000</pubDate>
      <link>https://dev.to/arif_sefa_f2d991d373eb93e/why-most-multi-agent-systems-dont-ship-software-116n</link>
      <guid>https://dev.to/arif_sefa_f2d991d373eb93e/why-most-multi-agent-systems-dont-ship-software-116n</guid>
      <description>&lt;p&gt;&lt;em&gt;Building AI agents is getting easier. Getting them to work together and deliver reliable software is a different story.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I've been spending quite a bit of time thinking about how AI agents can work together to build software.&lt;/p&gt;

&lt;p&gt;At first, the idea seems pretty straightforward. Instead of asking one AI model to handle everything, we can split the work between specialized agents. One plans the tasks, another writes the frontend, another handles the backend, and another tests the result.&lt;/p&gt;

&lt;p&gt;Everyone has a role. Work can happen in parallel. In theory, we should be able to build software faster.&lt;/p&gt;

&lt;p&gt;But there's a catch.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Getting several agents to generate code is relatively easy. Getting them to produce software that actually works together is much harder.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Imagine asking a frontend agent and a backend agent to build a task management application.&lt;/p&gt;

&lt;p&gt;The frontend agent creates a beautiful task list and expects the API to return an &lt;code&gt;assignedUser&lt;/code&gt; field. Meanwhile, the backend agent implements the endpoint using a field called &lt;code&gt;assignee&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Both agents finish their tasks. Both report success. But the application doesn't work.&lt;/p&gt;

&lt;p&gt;This is a small example, but it illustrates a much bigger problem. Each agent can do a reasonable job independently while the overall system still fails.&lt;/p&gt;

&lt;p&gt;And these problems don't disappear just because we use a better model or write a more detailed prompt.&lt;/p&gt;

&lt;p&gt;The real challenge is coordinating the work.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start with the workflow, not the agents
&lt;/h2&gt;

&lt;p&gt;When designing a multi-agent system, it's tempting to start by defining different roles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A planner that breaks down requirements.&lt;/li&gt;
&lt;li&gt;A frontend agent that writes React code.&lt;/li&gt;
&lt;li&gt;A backend agent that builds APIs.&lt;/li&gt;
&lt;li&gt;A tester that checks the implementation.&lt;/li&gt;
&lt;li&gt;A reviewer that looks for bugs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is a reasonable starting point, but I think there's a more important question to answer first:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How does work move from one stage to the next?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Before deciding how many agents we need, we should understand what needs to happen for a feature to go from an idea to working software.&lt;/p&gt;

&lt;p&gt;For example, a simple development workflow could look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Requirement
    |
    v
Planning
    |
    v
Define API Contracts
    |
    +----------+
    |          |
    v          v
 Frontend    Backend
    |          |
    +-----+----+
          |
          v
       Testing
          |
          v
        Review
          |
          v
       Delivery
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice that the frontend and backend can work in parallel, but only after the API contract is defined.&lt;/p&gt;

&lt;p&gt;That small detail makes a big difference.&lt;/p&gt;

&lt;p&gt;Without a shared contract, each agent has to make assumptions. The more assumptions they make independently, the more work we may need to redo later.&lt;/p&gt;

&lt;p&gt;This is why I prefer to think about the workflow first and the agents second.&lt;/p&gt;

&lt;h2&gt;
  
  
  Let the task dependencies decide what runs in parallel
&lt;/h2&gt;

&lt;p&gt;Let's say we're building a task management application.&lt;/p&gt;

&lt;p&gt;We have five tasks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tasks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;requirements&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;dependencies&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="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;api-contract&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;dependencies&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;requirements&lt;/span&gt;&lt;span class="dl"&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="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;frontend&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;dependencies&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;api-contract&lt;/span&gt;&lt;span class="dl"&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="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;backend&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;dependencies&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;api-contract&lt;/span&gt;&lt;span class="dl"&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="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;integration-tests&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;dependencies&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;frontend&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;backend&lt;/span&gt;&lt;span class="dl"&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;p&gt;The frontend and backend don't need to wait for each other. They only need to wait for the API contract.&lt;/p&gt;

&lt;p&gt;Once that contract is ready, both tasks can start.&lt;/p&gt;

&lt;p&gt;A simple scheduler can determine which tasks are ready to run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getReadyTasks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tasks&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;completed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;tasks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;completed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dependencies&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;every&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;dependency&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class="nx"&gt;completed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dependency&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a simplified example, but the idea is straightforward: a task becomes eligible to run when its dependencies are complete.&lt;/p&gt;

&lt;p&gt;In a real implementation, we'd also track running and failed tasks, handle retries, and prevent multiple workers from claiming the same task.&lt;/p&gt;

&lt;p&gt;The important part is that we don't need to tell agents when to start by manually coordinating every step. We can let the dependency graph determine that.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Parallelism should come from the structure of the work, not from simply having multiple agents available.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  An agent saying "done" doesn't mean the task is done
&lt;/h2&gt;

&lt;p&gt;This is another problem worth thinking about.&lt;/p&gt;

&lt;p&gt;Imagine a backend agent returns the following result:&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;"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;"completed"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"summary"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Implemented the task assignment API"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"tests"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"passed"&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;Looks good, right?&lt;/p&gt;

&lt;p&gt;But what if the agent never actually ran the tests?&lt;/p&gt;

&lt;p&gt;What if it ran the wrong command? Or what if the tests failed, but the agent misunderstood the output?&lt;/p&gt;

&lt;p&gt;We shouldn't rely entirely on an agent's description of its own work.&lt;/p&gt;

&lt;p&gt;Instead, the system should run the required checks and collect the results itself.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;verifyProject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;runner&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;workspace&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;checks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;npm&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;run&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;typecheck&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]],&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;npm&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;test&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;--&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;--runInBand&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]],&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;npm&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;run&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;build&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]],&lt;/span&gt;
  &lt;span class="p"&gt;];&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&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="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;command&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;checks&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;runner&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="nx"&gt;command&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;workspace&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exitCode&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;passed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;results&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="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="na"&gt;passed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;results&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;p&gt;Here, &lt;code&gt;runner&lt;/code&gt; represents a controlled command-execution service, and the example assumes the project has the corresponding npm scripts.&lt;/p&gt;

&lt;p&gt;The distinction is simple: the agent writes the code, but the verification system checks whether it works.&lt;/p&gt;

&lt;p&gt;This doesn't mean tests can prove that software is completely correct. They can't. But they give us independent evidence instead of relying on a model's confidence.&lt;/p&gt;

&lt;h2&gt;
  
  
  What happens when something fails?
&lt;/h2&gt;

&lt;p&gt;Let's say the frontend expects this response:&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;"items"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"nextCursor"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&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;But the backend returns:&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;"data"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"total"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&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;The integration test fails.&lt;/p&gt;

&lt;p&gt;We could simply send the error back to the frontend agent and ask it to fix the problem. But that might be the wrong solution. Maybe the backend is the part that doesn't follow the agreed contract.&lt;/p&gt;

&lt;p&gt;Before asking an agent to make another change, the workflow should identify what went wrong.&lt;/p&gt;

&lt;p&gt;A useful failure report might look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;FailureReport&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;taskId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nl"&gt;category&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;implementation_defect&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;contract_mismatch&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;test_defect&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;environment_failure&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nl"&gt;summary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;evidence&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This gives the orchestrator something more useful than a generic error message.&lt;/p&gt;

&lt;p&gt;It can decide whether to retry the implementation, revisit the contract, fix the test, or ask a developer for help.&lt;/p&gt;

&lt;p&gt;I'd also put a limit on automatic retries. If the same problem persists after a couple of attempts, the system should stop and explain what happened rather than keep generating code indefinitely.&lt;/p&gt;

&lt;p&gt;Sometimes the best thing an agent can do is report that it is blocked.&lt;/p&gt;

&lt;h2&gt;
  
  
  The part I find most interesting
&lt;/h2&gt;

&lt;p&gt;For me, the interesting part of multi-agent development isn't simply making agents more autonomous.&lt;/p&gt;

&lt;p&gt;It's building a system where each piece of work has a clear purpose, where agents share the same assumptions, and where we can understand why a task succeeded or failed.&lt;/p&gt;

&lt;p&gt;That requires a few things working together:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A planner that creates useful tasks rather than vague instructions.&lt;/li&gt;
&lt;li&gt;A scheduler that respects dependencies.&lt;/li&gt;
&lt;li&gt;Shared contracts that keep implementations consistent.&lt;/li&gt;
&lt;li&gt;A controlled environment for making changes.&lt;/li&gt;
&lt;li&gt;Automated checks that produce real execution results.&lt;/li&gt;
&lt;li&gt;A review process that catches problems before delivery.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of these ideas is particularly new in software engineering. We already use dependency graphs, CI pipelines, API contracts, isolated environments, and code reviews.&lt;/p&gt;

&lt;p&gt;What's changing is that AI agents are now participating in these processes, and we need to design the surrounding system accordingly.&lt;/p&gt;

&lt;p&gt;I wouldn't start by trying to make every agent fully autonomous. I'd start with a small workflow, make it observable, and see where it breaks.&lt;/p&gt;

&lt;p&gt;Then I'd improve the parts that actually cause problems.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;Multi-agent systems can be useful, especially when a task has clear boundaries and several independent pieces of work.&lt;/p&gt;

&lt;p&gt;But adding more agents doesn't automatically make software development faster or better.&lt;/p&gt;

&lt;p&gt;If the agents don't share contracts, if their changes aren't integrated properly, or if nobody verifies the results, we may simply end up generating mistakes faster.&lt;/p&gt;

&lt;p&gt;I think the more useful question is not how many agents we can run at once.&lt;/p&gt;

&lt;p&gt;It's this:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do we turn the work of several AI agents into a software change we can actually trust?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That's the problem I'd focus on when building an AI engineering workflow.&lt;/p&gt;

</description>
      <category>agents</category>
      <category>ai</category>
      <category>softwareengineering</category>
      <category>multiagent</category>
    </item>
    <item>
      <title>CodeAct: Why AI Agents Should Write Code, Not Just Call Tools</title>
      <dc:creator>Arif Sefa</dc:creator>
      <pubDate>Tue, 13 Oct 2026 18:32:57 +0000</pubDate>
      <link>https://dev.to/arif_sefa_f2d991d373eb93e/codeact-why-ai-agents-should-write-code-not-just-call-tools-50cc</link>
      <guid>https://dev.to/arif_sefa_f2d991d373eb93e/codeact-why-ai-agents-should-write-code-not-just-call-tools-50cc</guid>
      <description>&lt;p&gt;&lt;em&gt;Executable Code Actions Elicit Better LLM Agents — Exploring a different way to build more capable AI agents.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction: Are We Building AI Agents the Hard Way?
&lt;/h2&gt;

&lt;p&gt;When building AI agents, we often focus on adding more tools, integrating more APIs, and connecting more MCP servers.&lt;/p&gt;

&lt;p&gt;The assumption is straightforward: the more tools an agent has, the more capable it becomes.&lt;/p&gt;

&lt;p&gt;But what if the real limitation isn't the number of tools available to an agent, but &lt;strong&gt;how the agent uses those tools&lt;/strong&gt;?&lt;/p&gt;

&lt;p&gt;This is the question explored by &lt;em&gt;Executable Code Actions Elicit Better LLM Agents&lt;/em&gt;, a research paper presented at ICML 2024.&lt;/p&gt;

&lt;p&gt;The paper introduces &lt;strong&gt;CodeAct&lt;/strong&gt;, an approach in which an LLM can express actions through executable code instead of relying exclusively on conventional tool-call formats.&lt;/p&gt;

&lt;p&gt;Rather than making isolated tool calls, an agent can write code that combines operations, processes intermediate results, controls execution flow, and interacts with an execution environment.&lt;/p&gt;

&lt;p&gt;The idea is simple, but its implications for agentic AI are significant.&lt;/p&gt;

&lt;p&gt;📄 &lt;a href="https://arxiv.org/html/2402.01030v4" rel="noopener noreferrer"&gt;Read the original research paper&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  1. What Is CodeAct?
&lt;/h2&gt;

&lt;p&gt;Traditional LLM agents commonly interact with tools through predefined interfaces.&lt;/p&gt;

&lt;p&gt;The model selects a tool, generates arguments, receives a result, and decides what to do next.&lt;/p&gt;

&lt;p&gt;For example, an agent might need to retrieve customer records, filter them, and generate a report.&lt;/p&gt;

&lt;p&gt;A tool-calling workflow could involve several separate calls:&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;"tool"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"get_customers"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"arguments"&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;The model then receives the results and generates another tool call:&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;"tool"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"filter_customers"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"arguments"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"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;"active"&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;Finally, it might call another tool to generate the report.&lt;/p&gt;

&lt;p&gt;This approach works well for many tasks. However, coordinating several dependent operations can require repeated model decisions, intermediate messages, and orchestration logic.&lt;/p&gt;

&lt;p&gt;CodeAct offers another possibility.&lt;/p&gt;

&lt;p&gt;The agent can express the workflow as executable code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;customers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_customers&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;active_customers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="n"&gt;customer&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;customer&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;customers&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;customer&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;active&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;report&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;generate_report&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;active_customers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;report&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The functions above represent tools exposed to the agent by its environment.&lt;/p&gt;

&lt;p&gt;The important distinction is that the agent can express the relationships between operations directly in code.&lt;/p&gt;

&lt;p&gt;It can use variables, loops, conditions, functions, and exception handling to coordinate its actions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CodeAct treats executable code as an action format, not merely as text to be displayed to the user.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  2. From Individual Tool Calls to Executable Workflows
&lt;/h2&gt;

&lt;p&gt;Consider a task that requires collecting information from three services.&lt;/p&gt;

&lt;p&gt;A conventional orchestration layer might explicitly define the sequence:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;accounts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;call_tool&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_accounts&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;cards&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;call_tool&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_cards&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;transactions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;call_tool&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_transactions&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="nf"&gt;call_tool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;combine_financial_data&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;accounts&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;accounts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cards&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;cards&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;transactions&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;transactions&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A code-based approach can combine the same operations and perform additional processing locally within the execution environment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;accounts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_accounts&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;cards&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_cards&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;transactions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_transactions&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="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;account_count&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;accounts&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;card_count&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cards&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;transaction_count&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;transactions&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;total_spending&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;transaction&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;amount&lt;/span&gt;&lt;span class="sh"&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;transaction&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;transactions&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;transaction&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;amount&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;summary&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This example assumes that the tools return data in the expected format and that positive transaction amounts represent spending.&lt;/p&gt;

&lt;p&gt;The advantage is not simply fewer lines of code. It is the ability to define data flow and control flow dynamically.&lt;/p&gt;

&lt;p&gt;An agent can decide how to process results without requiring a separate tool for every possible combination of operations.&lt;/p&gt;

&lt;h3&gt;
  
  
  Visualizing the difference
&lt;/h3&gt;



&lt;pre data-lang="mermaid"&gt;&lt;code&gt;flowchart TD
    A[User Task] --&amp;gt; B[Traditional Agent]
    B --&amp;gt; C[Tool Call 1]
    C --&amp;gt; D[Observe Result]
    D --&amp;gt; E[Tool Call 2]
    E --&amp;gt; F[Observe Result]
    F --&amp;gt; G[Tool Call 3]
    G --&amp;gt; H[Final Answer]

    A --&amp;gt; I[CodeAct-Inspired Agent]
    I --&amp;gt; J[Generate Executable Code]
    J --&amp;gt; K[Execute Multiple Operations]
    K --&amp;gt; L[Observe Execution Result]
    L --&amp;gt; M{Task Complete?}
    M -- No --&amp;gt; J
    M -- Yes --&amp;gt; N[Final Answer]&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;The diagram illustrates the conceptual difference. Actual architectures vary, and conventional agents can also support batching, loops, and multi-step execution.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Why Executable Code Is a Powerful Action Space
&lt;/h2&gt;

&lt;h3&gt;
  
  
  3.1. Dynamic control flow
&lt;/h3&gt;

&lt;p&gt;Not every task follows the same path.&lt;/p&gt;

&lt;p&gt;Imagine an agent that retrieves customer data. If the request succeeds, it analyzes the result. If it fails, it investigates the error.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;fetch_customer_data&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;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;success&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;customer&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;data&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="n"&gt;analysis&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;analyze_customer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;customer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;analysis&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;error_details&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="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;error&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Unknown error&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;investigation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;investigate_error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;error_details&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;investigation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In a rigid workflow, this branching logic might need to be defined in the orchestration layer.&lt;/p&gt;

&lt;p&gt;With executable code, the agent can express the branch directly in the action it generates.&lt;/p&gt;

&lt;h3&gt;
  
  
  3.2. Repeated operations
&lt;/h3&gt;

&lt;p&gt;Suppose an agent must inspect several repositories or services.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;repositories&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;frontend&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;backend&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;shared-libraries&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="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;repository&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;repositories&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;repository&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;search_repository&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;repository&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;payment&lt;/span&gt;&lt;span class="sh"&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;repository&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;matches&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;items&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;repository&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;matches&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A loop can coordinate repeated operations while preserving their results for later analysis.&lt;/p&gt;

&lt;p&gt;The tools still need to be available to the execution environment. CodeAct does not automatically create new external capabilities.&lt;/p&gt;

&lt;h3&gt;
  
  
  3.3. Reusing intermediate results
&lt;/h3&gt;

&lt;p&gt;An agent may need to process data from one operation before passing it to another.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;transactions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_transactions&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;high_value_transactions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="n"&gt;transaction&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;transaction&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;transactions&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;transaction&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;amount&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;10000&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;customer_ids&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;transaction&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;customer_id&lt;/span&gt;&lt;span class="sh"&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;transaction&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;high_value_transactions&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;customers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nf"&gt;get_customer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;customer_id&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;customer_id&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;customer_ids&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;high_value_transactions&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;high_value_transactions&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;related_customers&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;customers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, the agent can filter records, extract identifiers, and retrieve related entities using a single executable workflow.&lt;/p&gt;

&lt;p&gt;In a real financial application, operations would need appropriate authorization, privacy controls, and clearly defined amount semantics.&lt;/p&gt;

&lt;h3&gt;
  
  
  3.4. Composing operations into reusable functions
&lt;/h3&gt;

&lt;p&gt;Code can also make an action easier to understand and reuse.&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;investigate_customer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;customer_id&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;customer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_customer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;customer_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;transactions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_transactions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;customer_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;flagged_transactions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="n"&gt;transaction&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;transaction&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;transactions&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;transaction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;flagged&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;customer&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;customer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;transaction_count&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;transactions&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;flagged_transactions&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flagged_transactions&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;investigate_customer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;customer-123&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is useful when several operations form a logical unit of work.&lt;/p&gt;

&lt;p&gt;It also introduces a new responsibility: the environment must control which functions the generated code is allowed to invoke.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. The Execution Feedback Loop
&lt;/h2&gt;

&lt;p&gt;One of the most interesting aspects of executable actions is the possibility of observing runtime feedback.&lt;/p&gt;

&lt;p&gt;An agent does not have to stop after generating code. It can execute the code, inspect the result, and use that observation to decide what to do next.&lt;/p&gt;

&lt;p&gt;The basic cycle is:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Generate → Execute → Observe → Revise&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Consider this example.&lt;/p&gt;

&lt;p&gt;The first attempt assumes a field exists:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;fetch_customer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;customer_name&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;Suppose execution returns a &lt;code&gt;KeyError&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The agent can inspect the returned structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;fetch_customer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Available fields:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&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;response&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It might discover that the field is named &lt;code&gt;name&lt;/code&gt; instead.&lt;/p&gt;

&lt;p&gt;The next attempt can account for the actual structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;fetch_customer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;customer_name&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="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;customer_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;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;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;Unknown&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="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;customer_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This demonstrates how execution feedback can guide subsequent actions.&lt;/p&gt;

&lt;p&gt;It does not mean that the model permanently learns from every error. Rather, the error becomes an observation that can inform the next step in the current task.&lt;/p&gt;

&lt;h3&gt;
  
  
  A simplified agent loop
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Retrieve and analyze customer data&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nf"&gt;task_is_complete&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;code&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;llm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate_code&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="o"&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;observations&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;get_observations&lt;/span&gt;&lt;span class="p"&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;sandbox&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nf"&gt;record_observation&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="k"&gt;if&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;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;update_task_with_error&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;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;get_final_answer&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 conceptual pseudocode, not the exact implementation described in the research paper.&lt;/p&gt;

&lt;p&gt;A production system needs explicit termination conditions, execution limits, observation handling, and protection against endless retries.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. What Did the Researchers Discover?
&lt;/h2&gt;

&lt;p&gt;The paper introduces &lt;strong&gt;M³ToolEval&lt;/strong&gt;, a benchmark designed to evaluate tool use in tasks involving multiple tools and multiple interaction turns.&lt;/p&gt;

&lt;p&gt;The researchers evaluate 17 different LLMs to investigate how executable code actions affect agent performance.&lt;/p&gt;

&lt;p&gt;The paper reports improvements of up to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;20% in task success rate&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;30% fewer actions&lt;/strong&gt; in reported experiments&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are maximum reported improvements, not guaranteed gains across all models, benchmarks, or tasks.&lt;/p&gt;

&lt;p&gt;The findings suggest that how an agent represents and executes actions can have a significant impact on its ability to complete complex tasks.&lt;/p&gt;

&lt;p&gt;The lesson is not simply that Python is better than JSON.&lt;/p&gt;

&lt;p&gt;The more important point is that executable code offers a flexible action space in which an agent can coordinate operations, reuse intermediate results, and express conditional behavior.&lt;/p&gt;

&lt;p&gt;For tasks that require several dependent operations, this flexibility can reduce the amount of explicit orchestration required.&lt;/p&gt;




&lt;h2&gt;
  
  
  6. CodeActAgent and CodeActInstruct
&lt;/h2&gt;

&lt;p&gt;The research also introduces resources to support the approach.&lt;/p&gt;

&lt;h3&gt;
  
  
  CodeActAgent
&lt;/h3&gt;

&lt;p&gt;CodeActAgent demonstrates an agent architecture that uses executable code to interact with tools and an execution environment.&lt;/p&gt;

&lt;h3&gt;
  
  
  CodeActInstruct
&lt;/h3&gt;

&lt;p&gt;CodeActInstruct is a dataset of approximately 7,000 multi-turn interactions designed to support training models to use code as an action format.&lt;/p&gt;

&lt;p&gt;The research includes models based on Llama 2 and Mistral, exploring how models can be trained to generate executable actions instead of relying exclusively on conventional tool-call formats.&lt;/p&gt;

&lt;p&gt;This matters because the work investigates both the architecture and the model behavior needed to use it.&lt;/p&gt;

&lt;p&gt;Explore the &lt;a href="https://github.com/xingyaoww/code-act" rel="noopener noreferrer"&gt;official CodeAct implementation on GitHub&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  7. CodeAct and MCP: A Natural Combination?
&lt;/h2&gt;

&lt;p&gt;MCP provides a standardized way for AI applications to discover and invoke tools exposed by external servers.&lt;/p&gt;

&lt;p&gt;But having access to many tools does not automatically mean an agent can combine them efficiently.&lt;/p&gt;

&lt;p&gt;Imagine an agent with access to these tools:&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="nf"&gt;search_codebase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;read_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;find_references&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;get_file_structure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A conventional agent could call these tools one at a time.&lt;/p&gt;

&lt;p&gt;A CodeAct-inspired agent could coordinate them in a program:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;GET_CREDIT_CARD_DETAIL_DOCUMENT&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="n"&gt;matches&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;search_codebase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;investigation&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;match&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;matches&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;file_path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;file&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="n"&gt;source&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;read_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;file_path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;investigation&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;file&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;file_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;match&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;source_excerpt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;source&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;investigation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code above assumes the tools expose compatible return structures.&lt;/p&gt;

&lt;p&gt;The distinction is important:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;MCP&lt;/strong&gt; standardizes how tools are exposed and invoked.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CodeAct&lt;/strong&gt; explores using executable code as the format for agent actions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;An orchestration framework&lt;/strong&gt; manages execution, state, permissions, and the broader agent lifecycle.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These ideas can complement one another, but they are not interchangeable.&lt;/p&gt;

&lt;p&gt;A CodeAct-inspired architecture could use MCP tools as building blocks and generate code to coordinate them.&lt;/p&gt;




&lt;h2&gt;
  
  
  8. A Practical Developer-Agent Example: Trace an Endpoint to a Frontend Screen
&lt;/h2&gt;

&lt;p&gt;Consider a banking application built around a frontend, GraphQL, a backend-for-frontend (BFF), and several microservices.&lt;/p&gt;

&lt;p&gt;The task is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Given a service endpoint, identify which frontend screens depend on it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A useful investigation might follow this chain:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;REST endpoint
    ↓
Backend service
    ↓
BFF service or resolver
    ↓
GraphQL operation
    ↓
Frontend hook or data layer
    ↓
Component
    ↓
Screen
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A CodeAct-inspired agent could combine repository search tools to trace these relationships.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;endpoint&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/creditcards&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="n"&gt;service_matches&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;search_codebase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;endpoint&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;graphql_operations&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;match&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;service_matches&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;operations&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;find_related_graphql_operations&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;file&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;line&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;graphql_operations&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;operations&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;screens&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;operation&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;graphql_operations&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;consumers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;find_frontend_consumers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;operation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;screens&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;consumers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;endpoint&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;endpoint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;graphql_operations&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;graphql_operations&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;screens&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;screens&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The search and tracing functions are hypothetical tools. They are not built-in CodeAct functions.&lt;/p&gt;

&lt;p&gt;The agent can extend the investigation when it encounters incomplete results.&lt;/p&gt;

&lt;p&gt;For example, it might search for an operation's name, inspect the matching file, and then follow imports into the frontend.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;operation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;GET_CREDIT_CARD_DETAIL_DOCUMENT&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="n"&gt;matches&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;search_codebase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;operation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;frontend_files&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;match&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;matches&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;match&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;path&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;apps/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;frontend_files&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;match&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;path&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;path&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;libs/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;frontend_files&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;match&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;path&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="n"&gt;unique_files&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;sorted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;frontend_files&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;unique_files&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This simplified example only filters search results by path. A real implementation would need to understand the repository structure, distinguish declarations from usages, and follow imports and data dependencies.&lt;/p&gt;

&lt;h3&gt;
  
  
  A possible investigation workflow
&lt;/h3&gt;



&lt;pre data-lang="mermaid"&gt;&lt;code&gt;flowchart TD
    A[User provides endpoint] --&amp;gt; B[Search repository]
    B --&amp;gt; C[Find service implementation]
    C --&amp;gt; D[Trace BFF and resolver]
    D --&amp;gt; E[Find GraphQL operation]
    E --&amp;gt; F[Find frontend consumers]
    F --&amp;gt; G{Evidence complete?}
    G -- No --&amp;gt; H[Generate another search action]
    H --&amp;gt; B
    G -- Yes --&amp;gt; I[Return evidence-backed report]&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;This illustrates a possible CodeAct-inspired architecture, not a workflow implemented or evaluated in the paper.&lt;/p&gt;

&lt;p&gt;The value is that the agent can dynamically compose existing search capabilities instead of requiring a separate hardcoded workflow for every endpoint.&lt;/p&gt;

&lt;p&gt;However, CodeAct does not replace code indexing, semantic search, or reliable repository navigation. Those capabilities remain essential for large codebases.&lt;/p&gt;




&lt;h2&gt;
  
  
  9. Parallel Operations and Data Aggregation
&lt;/h2&gt;

&lt;p&gt;Some investigations contain independent operations that can run in parallel.&lt;/p&gt;

&lt;p&gt;For example, an agent might search the frontend, BFF, and shared libraries for the same operation.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;investigate_repository&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;repository&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;search_repository_async&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;repository&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;query&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;investigate_all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;repositories&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;frontend&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;bff&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;shared-libraries&lt;/span&gt;&lt;span class="sh"&gt;"&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="nf"&gt;investigate_repository&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;repository&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;query&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;repository&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;repositories&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;gather&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&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;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;repository&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;repository&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;repositories&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="p"&gt;}&lt;/span&gt;


&lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;investigate_all&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_CREDIT_CARD_DETAIL_DOCUMENT&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is an illustrative example. It assumes asynchronous tool functions and an execution environment that supports top-level &lt;code&gt;await&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;CodeAct does not automatically make tool calls parallel. The generated program, runtime, and available interfaces must support concurrency.&lt;/p&gt;

&lt;p&gt;Parallel execution can improve latency when operations are independent, but it requires sensible concurrency limits, error handling, and resource management.&lt;/p&gt;




&lt;h2&gt;
  
  
  10. Does CodeAct Replace Traditional Tool Calling?
&lt;/h2&gt;

&lt;p&gt;Not necessarily.&lt;/p&gt;

&lt;p&gt;Traditional tool calling remains useful when operations are simple, well-defined, and require strict argument validation.&lt;/p&gt;

&lt;p&gt;Executable code becomes more attractive when tasks involve:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Multiple dependent operations&lt;/li&gt;
&lt;li&gt;Conditional or repetitive execution&lt;/li&gt;
&lt;li&gt;Data transformation between tools&lt;/li&gt;
&lt;li&gt;Dynamic workflows&lt;/li&gt;
&lt;li&gt;Complex multi-step investigations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A hybrid design can use structured tool calls for well-defined operations and code-based orchestration when several operations need to be composed.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# A structured tool provides a trusted operation.
&lt;/span&gt;&lt;span class="n"&gt;account&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_account&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;account_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Generated code handles task-specific processing.
&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;active&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;transactions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_transactions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;account_id&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;summarize_transactions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;transactions&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;result&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;message&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;Account is not active&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The tool layer can preserve access controls and input validation while the agent uses code to coordinate the task.&lt;/p&gt;

&lt;p&gt;The best architecture depends on the task, the available tools, the model, and the required security guarantees.&lt;/p&gt;




&lt;h2&gt;
  
  
  11. The Security Challenge
&lt;/h2&gt;

&lt;p&gt;Giving an agent the ability to execute code increases its flexibility, but it also introduces risks.&lt;/p&gt;

&lt;p&gt;Generated code must not receive unrestricted access to a host machine, production database, or sensitive filesystem.&lt;/p&gt;

&lt;p&gt;A production implementation should consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sandboxed execution&lt;/li&gt;
&lt;li&gt;Execution time and memory limits&lt;/li&gt;
&lt;li&gt;Restricted filesystem and network access&lt;/li&gt;
&lt;li&gt;Explicit tool permissions&lt;/li&gt;
&lt;li&gt;Validation of sensitive operations&lt;/li&gt;
&lt;li&gt;Logging and auditing&lt;/li&gt;
&lt;li&gt;Approval requirements for high-impact actions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A hypothetical sandbox interface might look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sandbox&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;generated_code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;timeout_seconds&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;network_access&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;filesystem_access&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;restricted&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;This is an illustrative API, not a real CodeAct function. Actual security controls depend on the execution platform.&lt;/p&gt;

&lt;p&gt;The core principle is straightforward:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Give the agent flexibility over how it performs a task, but keep strict boundaries around what it is allowed to do.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Code execution should be isolated, observable, and governed by explicit permissions.&lt;/p&gt;




&lt;h2&gt;
  
  
  12. What CodeAct Does—and Does Not—Solve
&lt;/h2&gt;

&lt;p&gt;CodeAct is not a complete solution to every agent problem.&lt;/p&gt;

&lt;p&gt;It does not automatically provide:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Accurate reasoning&lt;/li&gt;
&lt;li&gt;Reliable codebase indexing&lt;/li&gt;
&lt;li&gt;Correct tool implementations&lt;/li&gt;
&lt;li&gt;Persistent learning from previous failures&lt;/li&gt;
&lt;li&gt;Guaranteed task completion&lt;/li&gt;
&lt;li&gt;Safe execution by default&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The approach changes the action space available to an agent. The quality of the outcome still depends on the model, the tools, the execution environment, and the way the task is evaluated.&lt;/p&gt;

&lt;p&gt;This is an important distinction when deciding whether to adopt CodeAct in a real application.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion: Better Agents May Need Better Ways to Act
&lt;/h2&gt;

&lt;p&gt;What makes CodeAct interesting is not simply that it allows an LLM to write Python. Models have been generating code for years.&lt;/p&gt;

&lt;p&gt;The more significant idea is treating &lt;strong&gt;executable code as a general-purpose action format for AI agents&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Instead of designing every possible sequence of tool calls in advance, we can give agents a set of capabilities and let them compose those capabilities into executable workflows.&lt;/p&gt;

&lt;p&gt;The research provides experimental evidence that this approach can improve performance on certain multi-tool tasks while reducing the number of actions required.&lt;/p&gt;

&lt;p&gt;For developers building MCP integrations, agent orchestration platforms, and AI-powered developer tools, CodeAct offers a valuable architectural perspective.&lt;/p&gt;

&lt;p&gt;Perhaps the next step in building more capable agents isn't simply adding more tools.&lt;/p&gt;

&lt;p&gt;Perhaps it's giving agents better ways to use the tools they already have.&lt;/p&gt;

&lt;h3&gt;
  
  
  Further Reading
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://arxiv.org/html/2402.01030v4" rel="noopener noreferrer"&gt;Original research paper: Executable Code Actions Elicit Better LLM Agents&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/xingyaoww/code-act" rel="noopener noreferrer"&gt;CodeAct implementation on GitHub&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>codeact</category>
      <category>development</category>
    </item>
  </channel>
</rss>
