# Engineering Patterns Beat Model Power: What the Google AI Agents Challenge Actually Proved

Published: 2026-09-10 · Tag: AI
Canonical: https://vondraysanford.com/writing/2026-09-10-engineering-patterns-beat-model-power-what-the-google-ai-age.html
Author: Vondray Sanford (https://vondraysanford.com)

> Google's AI Agents Challenge surfaced something most people building multi-agent systems already suspect but rarely say out loud: the model isn't the bottleneck. The architecture is.

Google's AI Agents Challenge surfaced something most people building multi-agent systems already suspect but rarely say out loud: the model isn't the bottleneck. The architecture is. The post-mortem on the strongest submissions found four consistent engineering patterns separating winners from also-rans: bidirectional MCP, async orchestration, structured inter-agent communication, and treating agents like services. None of those are AI-specific problems. They're software engineering problems that happen to involve inference.

I've been running my own multi-agent experiments with [AgentReview](https://vondraysanford.com) and a few other side projects, and reading through these findings felt like someone had audited my own architecture notes. Below is what each pattern means in practice, and why it shows up in every system that survives contact with real workloads.

## Bidirectional MCP Is Not Optional in Serious Agent Systems

The MCP (Model Context Protocol) conversation has largely been about giving agents access to tools: letting a model reach out and call something external. That's uni-directional: agent asks, tool responds. The winning submissions went further and wired up bidirectional MCP, meaning agents could also expose themselves as MCP servers and be called by other agents.

This is a significant architectural shift. When every agent is both a client and a server, you stop thinking about a pipeline and start thinking about a service mesh. An orchestrator doesn't need to know the implementation details of a subordinate agent. It just needs to know its interface. That's the same contract-first thinking we use when designing REST APIs or gRPC services in enterprise systems.

In AgentReview, I ran into this exact wall. My reviewer agents were doing fan-out fine, but synthesis was brittle because the orchestrator had to understand each reviewer's output schema to stitch results together. If I'd treated each reviewer as an MCP server with a defined response contract from day one, that coupling goes away. The orchestrator calls a known interface and gets a known shape back. Not glamorous. Just good API design applied one layer up.

## Async Orchestration Is the Only Orchestration That Scales

The second pattern that showed up consistently was async-first orchestration. I'm less surprised by this one. If you've ever built a high-volume data processing pipeline in .NET, you already know that synchronous chaining is a trap. It feels clean until one slow step balloons your latency for every step downstream.

Multi-agent systems have the same problem, and inference adds a massive variable: model response time is non-deterministic in a way that a database query usually isn't. A single agent task can take 800ms or 8 seconds depending on context length, model load, and whether you're hitting a local endpoint or a cloud API. Awaiting each step sequentially means that variance compounds.

The winning teams fanned out agent tasks as async work items, let them run concurrently, then brought results back to a synthesis step only after all branches resolved, or after a timeout with partial results. In .NET terms, this is `Task.WhenAll` thinking applied to agent orchestration. In Python it's `asyncio.gather`. The concept isn't new. What's new is people are finally applying it to agent graphs instead of bolting agents into synchronous request-response loops.

```
// Rough .NET sketch of fan-out + gather for agent tasks
var reviewTasks = agents.Select(agent => agent.ReviewAsync(pr, cancellationToken));
var results = await Task.WhenAll(reviewTasks);
var synthesis = await orchestrator.SynthesizeAsync(results, cancellationToken);

```

That pattern is dead simple. The complexity is in defining what happens when one agent times out or returns a low-confidence result. That's where the actual design time should go.

## Treating Agents Like Services Changes How You Debug Everything

The deeper insight from the challenge results is that winning teams thought about agents as services rather than magic. That means versioning, health checks, structured logging, and defined contracts. The agent layer is just another tier in a system you already know how to operate.

I looked into how the top-performing architectures handled failure modes, and the consistent thread was observability. Winning submissions could answer questions like: which agent produced this result? How long did it take? Did it fall back to a secondary strategy? You can't answer those questions if your agents are black boxes talking to each other over unstructured strings.

This maps directly to something I learned building enterprise data systems. When a bulk operation touches thousands of records and something goes wrong, you need to know exactly where in the pipeline the failure occurred. The fix is structured logging and correlation IDs baked in from the start, not better error handling. Agent systems work the same way. Each agent invocation should carry a trace ID. Each inter-agent message should have a schema. When something breaks in production, you need the data to reconstruct what happened.

On my DGX Spark setup where I run local inference, I've started treating each model endpoint as a service with its own latency SLA. If a local Llama call exceeds my threshold, I don't block. I log, potentially fall back, and move on. That mindset only works if you've already set up the observability scaffolding to see it happening.

## Where to Focus If You're Building This Now

If you're building a multi-agent system right now and spending most of your time on prompt engineering, you're probably optimizing the wrong layer. The Google challenge results suggest the teams who won had strong fundamentals: clean interfaces, async design, and real observability. The model was table stakes.

Three things worth prioritizing, whether you're starting fresh or refactoring something that already exists:

Define your inter-agent contract before you write any agent logic. What does an agent accept as input? What does it always return? Treat that as an interface definition. Wire up async from day one, because retrofitting it into a synchronous orchestration layer is painful. Add a correlation ID to every agent invocation and log it. You'll want it the first time something goes wrong at step four of a six-step graph.

The "raw model power" narrative is compelling because it lets you offload hard engineering decisions to the model. The teams who built the strongest systems didn't do that. They built well-architected software that happened to have inference in the loop. That's a bar any experienced engineer can clear, and it's the right bar to aim for.
