<?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: Sachin Magon</title>
    <description>The latest articles on DEV Community by Sachin Magon (@sachin_magon).</description>
    <link>https://dev.to/sachin_magon</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%2F3918743%2F55147036-a7f1-4c08-bb47-09d3d23f2eff.png</url>
      <title>DEV Community: Sachin Magon</title>
      <link>https://dev.to/sachin_magon</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sachin_magon"/>
    <language>en</language>
    <item>
      <title>Things I learned building my first multi-agent AI system on Azure + NVIDIA</title>
      <dc:creator>Sachin Magon</dc:creator>
      <pubDate>Mon, 29 Jun 2026 21:15:09 +0000</pubDate>
      <link>https://dev.to/sachin_magon/things-i-learned-building-my-first-multi-agent-ai-system-on-azure-nvidia-325p</link>
      <guid>https://dev.to/sachin_magon/things-i-learned-building-my-first-multi-agent-ai-system-on-azure-nvidia-325p</guid>
      <description>&lt;p&gt;I recently built a multi-agent customer support system on Azure AI Foundry and NVIDIA NIM. First time doing anything like this. Made four predictions upfront about what would happen. Three of them were wrong.&lt;br&gt;
Here is what I actually learned.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. "Tokens" is not a unit of cost&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It is a unit of work. The price per unit of work varies by 5-10x depending on which model did the work. I was tracking total token count across both the small 9B model and the large 49B model as if they cost the same. They do not. Total tokens went up in the optimized version. Cost in dollars probably went down. I was measuring the wrong thing the whole time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. A verbatim hash cache on natural language traffic deflects ~0% of queries&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I predicted 25-40% cache deflection. The actual number was 0%. Every query in my test set was a unique string, so the hash-based cache never had a single chance to fire. A verbatim cache is not a simpler version of a semantic cache. It is a different thing entirely. If your workload is natural language, build semantic similarity caching from day one, not as an upgrade later.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. configure_azure_monitor() does not capture OpenAI SDK calls by default&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You need to install and initialize opentelemetry-instrumentation-httpx explicitly:&lt;/p&gt;

&lt;p&gt;pip install opentelemetry-instrumentation-httpx==0.61b0&lt;/p&gt;

&lt;p&gt;from opentelemetry.instrumentation.httpx import HTTPXClientInstrumentor&lt;br&gt;
HTTPXClientInstrumentor().instrument()&lt;/p&gt;

&lt;p&gt;Without this, your App Insights Logs will show customMetric and &lt;br&gt;
performanceCounter entries (CPU, memory) but nothing about what your &lt;br&gt;
agent actually did.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Pin your OpenTelemetry versions or everything breaks&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Installing opentelemetry-instrumentation-httpx without version pinning pulled in opentelemetry-api 1.42.1. But azure-monitor-opentelemetry-exporter needs opentelemetry-api==1.40. The conflict is silent until things start misbehaving. Pin everything to the 0.61b0 / 1.40.0 line:&lt;/p&gt;

&lt;p&gt;pip install \&lt;br&gt;
  "opentelemetry-api==1.40.0" \&lt;br&gt;
  "opentelemetry-instrumentation==0.61b0" \&lt;br&gt;
  "opentelemetry-instrumentation-httpx==0.61b0" \&lt;br&gt;
  "opentelemetry-semantic-conventions==0.61b0" \&lt;br&gt;
  "opentelemetry-util-http==0.61b0"&lt;/p&gt;

&lt;p&gt;Then run pip check to confirm no broken requirements.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Short-lived Python scripts exit before OTel's batch exporter fires&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;OpenTelemetry batches traces and sends them every few seconds in the &lt;br&gt;
background. If your script finishes before that timer fires, the traces are dropped silently. Not delayed. Gone. Add an atexit flush:&lt;/p&gt;

&lt;p&gt;import atexit&lt;br&gt;
from opentelemetry import trace&lt;/p&gt;

&lt;p&gt;def _flush():&lt;br&gt;
    provider = trace.get_tracer_provider()&lt;br&gt;
    if hasattr(provider, "force_flush"):&lt;br&gt;
        provider.force_flush()&lt;/p&gt;

&lt;p&gt;atexit.register(_flush)&lt;/p&gt;

&lt;p&gt;This guarantees buffered traces get pushed out before the process exits.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. Nemotron Nano and Super put output in reasoning_content, not content&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;On short prompts, both models spend their token budget on internal &lt;br&gt;
reasoning and never produce a content field. It comes back as None. &lt;br&gt;
msg.content.strip() then crashes with AttributeError.&lt;/p&gt;

&lt;p&gt;Always extract text like this:&lt;/p&gt;

&lt;p&gt;text = (&lt;br&gt;
    msg.content&lt;br&gt;
    or getattr(msg, "reasoning_content", None)&lt;br&gt;
    or "(no response)"&lt;br&gt;
)&lt;/p&gt;

&lt;p&gt;This applies everywhere you read model output: classifiers, answer &lt;br&gt;
functions, test scripts, all of it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;7. The NVIDIA model name in the catalog is not the API model string&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;nvidia/nemotron-nano-9b-v2 returns 404. The actual API string has a &lt;br&gt;
double prefix:&lt;/p&gt;

&lt;p&gt;nvidia/nvidia-nemotron-nano-9b-v2&lt;/p&gt;

&lt;p&gt;Go to build.nvidia.com, open the model card, click the Python tab, and copy the model= value directly. Do not guess from the catalog name.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;8. max_tokens=10 does not work for reasoning models doing classification&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I set max_tokens=10 for my classifier call, expecting a one-word label back. Nemotron Nano spent all 10 tokens on reasoning trace and never produced a label. content came back None. Set at least max_tokens=100 for any call to a reasoning model, even simple classification tasks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;9. Routing decisions need their own log line&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I built a router, ran 81 queries through it, got a full benchmark result, and still cannot tell you with confidence what it routed where. The per-category tables in my benchmark were grouped by ground-truth label, not by what the router actually decided. These are not the same thing. &lt;br&gt;
Log the routing decision explicitly on every query, separate from &lt;br&gt;
everything else.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;10. Graceful degradation cannot be tested in a sequential benchmark&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I built a downshift mechanism that triggers when the reasoning model's rolling p95 latency exceeds 4000ms. It requires 20 samples in the window before it can activate. My entire eval set had 12 reasoning queries. The mechanism was guaranteed to never trigger before I ran a single query. &lt;br&gt;
To test saturation behavior you need either a much larger dataset or a dedicated concurrent load test, not a sequential single-pass benchmark.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;11. Homebrew Python 3.12 has a libexpat conflict on some macOS versions&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;python3.12 -m venv .venv fails with:&lt;/p&gt;

&lt;p&gt;ImportError: Symbol not found: _XML_SetAllocTrackerActivationThreshold&lt;/p&gt;

&lt;p&gt;Homebrew's Python was compiled against a newer libexpat than what macOS ships. The fix is pyenv:&lt;/p&gt;

&lt;p&gt;brew install pyenv&lt;br&gt;
pyenv install 3.12.13&lt;br&gt;
pyenv local 3.12.13&lt;br&gt;
python -m venv .venv&lt;/p&gt;

&lt;p&gt;Everything works after that.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;12. The operational layer is harder than the model layer&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Every mistake in this list is something I built, measured, or configured wrong. None of them are problems with Azure AI Foundry or NVIDIA NIM. The models worked. The platforms worked. The gaps were all in how I instrumented, tested, and measured the system around them.&lt;/p&gt;

&lt;p&gt;That is probably the most useful thing I learned.&lt;/p&gt;

&lt;p&gt;Full benchmark results and write-up on my blog:&lt;br&gt;
&lt;a href="https://sachin.magonus.com/2026/06/17/multi-agent-poc-benchmark-foundry-nvdia-nim-results/" rel="noopener noreferrer"&gt;https://sachin.magonus.com/2026/06/17/multi-agent-poc-benchmark-foundry-nvdia-nim-results/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Framework post (the architecture and predictions before I ran anything):&lt;br&gt;
&lt;a href="https://sachin.magonus.com/2026/01/16/multi-agent-framework-foundry-nvidia/" rel="noopener noreferrer"&gt;https://sachin.magonus.com/2026/01/16/multi-agent-framework-foundry-nvidia/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>azure</category>
      <category>nvidia</category>
      <category>python</category>
    </item>
    <item>
      <title>A Framework for Building My First Multi-Agent System</title>
      <dc:creator>Sachin Magon</dc:creator>
      <pubDate>Thu, 07 May 2026 21:23:01 +0000</pubDate>
      <link>https://dev.to/sachin_magon/a-framework-for-building-my-first-multi-agent-system-3eh0</link>
      <guid>https://dev.to/sachin_magon/a-framework-for-building-my-first-multi-agent-system-3eh0</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;I lead engineering, but I have not built an agentic AI system before. Right now I am learning this space, and this post is mainly how I am thinking about it — what can go wrong, what architecture I want to try, and what I expect before even running a POC.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Why this post exists
&lt;/h2&gt;

&lt;p&gt;I have built and delivered many software systems over the years. But "agentic AI in production" feels different to me. I have done POCs and some experimental coding, but not multi-agent systems with strong operational constraints.&lt;/p&gt;

&lt;p&gt;When I started reading about agentic AI, most of the content was not very helpful at this stage:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Vendor demos show what is possible, but not what works in real production.&lt;/li&gt;
&lt;li&gt;Success stories are written after everything worked, so the path looks obvious in hindsight.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When you are starting, decisions are not obvious. So before writing production code, I am doing what I usually do — create a framework to evaluate architectures against possible failure scenarios, then document it so I can validate it later. This post is that framework.&lt;/p&gt;

&lt;h2&gt;
  
  
  The number that started my thinking
&lt;/h2&gt;

&lt;p&gt;Around 95% of enterprise GenAI pilots do not create measurable business impact (MIT report). BCG says ~70% of failures are operational, not model problems.&lt;/p&gt;

&lt;p&gt;The question is not "can we build an agent" — that is already proven. The real question is: &lt;strong&gt;what does the 5% do differently?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Most likely, the answer is in operational aspects that demos do not show — cost, latency, observability, and fallback behavior.&lt;/p&gt;

&lt;h2&gt;
  
  
  Four failure modes most tutorials skip
&lt;/h2&gt;

&lt;p&gt;These are hypotheses, not proven results.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. One model handling everything.&lt;/strong&gt; A customer support POC probably has ~50% simple FAQ, ~35% needing tool calls, ~15% complex multi-step. Using a single large model for all of it means high cost and high latency even when not needed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. No memory of repeats.&lt;/strong&gt; Customer support has many repeated questions with small variations. A basic agent calls the model every time. Caching is rarely discussed in tutorials, or treated as "later optimization" — by which time cost is already too high.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Invisible behavior.&lt;/strong&gt; Agent tells a customer their refund is processed, but it isn't. Later it becomes an escalation, and no one can explain why. Logs show API success — not agent reasoning, tool calls, or parameters.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. No graceful degradation.&lt;/strong&gt; During peak traffic, latency spikes. A good system should reduce response complexity and answer faster instead of waiting for a perfect answer.&lt;/p&gt;

&lt;h2&gt;
  
  
  What comes next
&lt;/h2&gt;

&lt;p&gt;I mapped each failure mode to an architectural decision — model routing, semantic caching, OpenTelemetry-based observability, latency-aware routing — and built a benchmark harness comparing a naive baseline against the optimized system.&lt;/p&gt;

&lt;p&gt;The full architecture, the stack rationale (NeMo Agent Toolkit + Azure AI Foundry + NVIDIA NIM), and the benchmark setup with 81 customer support queries are in the full post:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;👉 &lt;a href="https://sachin.magonus.com/2026/01/16/multi-agent-framework-foundry-nvidia/" rel="noopener noreferrer"&gt;Read the full framework, architecture, and benchmark setup →&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Benchmark numbers in a follow-up. If you're also evaluating agentic AI for the first time, I'd value pushback on whether these are the right failure modes to design around.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>agents</category>
      <category>foundry</category>
      <category>nvidia</category>
    </item>
  </channel>
</rss>
