TraptureIQ Guides Topology

ADK never tells you how your agents are wired. The timing does.

There is no “this is a ParallelAgent” attribute anywhere on the wire. Which means the diagram in your README is a claim, not a measurement, and the most expensive bug in multi-agent systems is the one where the two quietly stop matching. It returns the right answer, raises no error, and runs three times slower than you designed it to.

Updated August 2026 · 7 min read · Written against ADK 2.6.2

Ask a team to draw their agent system and you get a clean diagram: a router, three specialists, a parallel research block, a summariser. Ask what the deployed system actually does and the honest answer is usually "that, we think". Nothing verifies the diagram, so it drifts, and it drifts silently, because a structural regression in an agent system does not throw.

The bug that raises no error

Here is the failure this whole area exists to catch. A ParallelAgent whose branches end up executing one after another still returns the correct answer. It costs the same in tokens. No exception, no log line, no status change.

AS DESIGNED · concurrency ratio 2.8finishes in 4.1sAS OBSERVED · concurrency ratio 1.02finishes in 11.9sSame answer. Same cost. No error raised. Three times the latency, and nothing in a log says so.
The same three-branch block, designed and observed. Identical output, identical spend, three times the latency, and the only evidence is in the timestamps.

The signal is the concurrency ratio: the sum of child durations divided by the parent's wall-clock duration. Genuinely parallel branches push it towards the number of branches. A ratio near 1.0 means they queued. That single number is the difference between an agent that feels fast and one users abandon, and it is absent from every log you have.

How structure is recovered from a flat stream

Every span carries a parent, a start time and an end time. That is enough to reconstruct composition using interval algebra, without anybody declaring anything:

  • Root: the span with no parent in the trace.
  • Sequential: sibling spans whose intervals do not overlap and run in a consistent order.
  • Parallel: siblings whose intervals overlap materially. The overlap is the evidence; the class name never appears.
  • Loop: the same agent recurring under the same parent, which is how an iteration shows up when nothing announces it.

The result is a graph nobody maintains. It cannot go stale, because it is regenerated from what ran, which is exactly the property a hand-drawn diagram lacks.

Why this beats a declared graph

Most tooling in this space asks you to describe your graph: decorators, a registration call, a YAML file. That produces a diagram of your intentions, and the maintenance burden lands on the person least likely to remember it, whoever adds a sub-agent six months later under deadline.

A declared graph cannot detect drift, by construction

If the structure comes from a declaration, then the declaration is the truth, and a deployed system that diverges from it produces… a matching diagram. The one class of bug you most want to catch is the one a declared graph is definitionally blind to.

Put money on the graph

Structure alone is interesting. Structure with spend on it changes decisions. Once the graph is derived, each node can carry the cost of the calls made underneath it, and the question "which branch is expensive" becomes a glance instead of an investigation.

Two rules keep that honest, both learned the hard way:

  • Deduplicate before you attribute. ADK emits two spans sharing one LLM event id per model call. Joining cost to spans on that id without deduplicating reports double the real spend, uniformly, plausibly, across the whole graph. See ADK agent cost.
  • Never add tool cost to agent cost. What is derivable for a tool is the cost of the model call that consumed its output: an upper bound, not a disjoint share. Summing the two counts the same money twice.

Derived topology is computed from the same spans the cost figures come from, so the graph and the invoice cannot disagree about what happened. It is also cached with an explicit sync rather than recomputed per request. Reconstructing a graph from raw spans on every page load is a good way to make an observability tool the slowest thing in your stack.

What to check on your own system this week

  • Concurrency ratio on every parallel block. If it is near 1.0, your parallelism is decorative.
  • Unexpected loops. A recurring agent under one parent that you did not design as a loop is usually a retry or a hand-off cycle.
  • Depth you did not intend. Hand-off chains grow quietly; each hop is latency and another chance to lose context.
  • The expensive branch. Then go and read its prompt. See prompt management for changing it without a deploy.

Questions people actually ask

Does ADK report whether agents ran in parallel?

No. ADK emits no attribute describing agent composition. There is no marker distinguishing a ParallelAgent from a SequentialAgent on the wire. The structure has to be reconstructed from the span tree and the start and end timestamps of each span.

How can I tell if my ParallelAgent is actually running in parallel?

Compare the sum of the child span durations against the wall-clock duration of their parent. If the ratio is near 1.0 the branches ran one after another; genuinely concurrent branches produce a ratio close to the number of branches. Nothing raises an error either way.

What is agent topology drift?

The gap that opens when the deployed structure of a multi-agent system stops matching the intended design: a sub-agent added, a hand-off changed, a parallel block degraded to serial. Derived topology detects it because it reflects what ran, not what was declared.

Can topology be derived without changing agent code?

Yes. It comes from the same OpenTelemetry spans ADK already emits, so it needs no decorators, no graph definition and no registration step that goes stale when somebody adds a sub-agent.

Measure it on your own agent

Two environment variables, no change to agent.py. Free for 14 days.