Inspiration
A hub closes at 2am. 51,000 people are stranded across 20,000 bookings, and 2,888 seats exist. One duty manager decides who flies, and the queue is not getting shorter.
Reasoning is now cheap enough to give every stranded traveller their own agent. Nobody does it, because twenty thousand agents means twenty thousand model calls — and by the time you've paid for them, the seats are gone.
Unless the identical reasoning is only computed once.
What it does
Chorus gives every booking a real, independent ADK agent, and charges for the diversity of their situations, not their population. Twenty thousand agents cost 1,962 distinct thoughts and $1.89, against $19.24 if each thought alone — a 10.2× collapse.
Nothing groups the agents. None of them knows the others exist.
How we built it
Every boundary an agent crosses — model call, tool call, delegation — is intercepted at
the ADK BasePlugin boundary and recorded as an effect addressed by its entire causal
history:
$$\text{address} = H(\text{kind}, \text{role}, \text{causal parents}, \text{request})$$
Two agents arriving at the same question from the same causal position compute the same address and collide. The second is served the first one's answer for nothing. This is record-replay debugging, event sourcing, and content-addressed build graphs — three solved techniques, combined in a domain that hadn't used them.
Each agent reasons over a bucketed projection of its situation, never its name. Two stranded platinum passengers travelling alone, both needing to move within four hours, face the same decision. Their names differ. Their reasoning doesn't.
The kernel knows nothing about ADK. One file does.
Challenges we ran into
Most of what we learned came from measurements that went against us.
The collapse is lossy. We measured it rather than assuming: roughly 13% of outcomes differ from reasoning each traveller separately. Replicated three times. It's in the README.
Hand-written rules beat us. Six arms scored identically, and a regex baseline with no model at all wins on tier-weighted satisfaction. We ship that row because it's true, and it's why the escalation path exists.
Gemma scored 26.7% on urgency — below a regex. That was our prompt, not the model. One line defining the bands took it to 80.8%.
Our tracing exporter reported success while writing nothing. The Cloud Trace API was disabled, every batch was refused, and the code returned the span count anyway. "39,996 spans" reached the README and sat there while the backend held nothing. It now raises on refusal and reads the spans back to verify. There are 39,976 spans in Cloud Trace, and that number was checked by fetching them.
A round-anchor mismatch meant the console could never replay the shipped proof. Our first hypothesis was wrong; profiling redirected us. 90 calls per 96 agents became 0 calls per 200 agents — an 88× speedup, found only because we measured instead of guessed.
What we learned
The uncomfortable one: the thing that makes a demo impressive and the thing that makes a system honest are often in tension. A warm store makes the live site instant and free — which is precisely the product's thesis — but shows a visitor none of the collapse happening. We kept the honest version and wrote down the trade-off.
Interposition beats instrumentation. Because causality was recorded first (replay required it), the distributed trace is a projection of data that already existed, rather than a parallel bookkeeping system that can disagree with it.
What's next
Merge conflict resolution across branches, a global rate limit in Cloud Armor rather than per-instance, and lifting the public demo ceiling once the lattice is pre-warmed — its 2,304 cells bound total lifetime spend at about $2.22.
377 tests pass. Every number above is reproducible with a command in the README.
Built With
- blake2b
- cloud-run
- cloud-tasks
- cloud-trace
- content-addressing
- docker
- event-sourcing
- fastapi
- firestore
- gemini
- gemma
- google-adk
- google-cloud
- model-armor
- opentelemetry
- pixijs
- pytest
- python
- react
- secret-manager
- server-sent-events
- terraform
- typescript
- vertex-ai
- vite
Log in or sign up for Devpost to join the conversation.