Part 31 of 40 · 5 min read
Parallel agents without conflicting commitments
Experimental · Work in progress · Internal R&D
Structured concurrency, shared budgets, queue fairness and one owner for each business write.
Arunank Sharan · Kuzushi Labs ·
In this article
Three agents can read a customer brief, inspect delivery capacity and estimate document-processing cost at the same time. Three agents should not independently promise three different delivery dates to that customer.
The useful boundary is parallel evidence gathering followed by a controlled decision. Concurrency should reduce waiting where work is independent. It should not multiply the number of owners of a business commitment. This distinction matters more than whether the harness calls the workers agents, tools or activities.
Fan out reads; assemble a decision packet
A proposal-preparation task can run independent reads concurrently and return typed results with source revisions. The coordinator then checks whether the evidence is complete and fresh enough to propose terms.
import asyncio
async def fetch_fixture(name, revision, value):
await asyncio.sleep(0)
return {"name": name, "revision": revision, "value": value}
async def prepare_packet():
results = await asyncio.gather(
fetch_fixture("customer", 4, {"segment": "maintenance"}),
fetch_fixture("capacity", 9, {"available_hours": 24}),
fetch_fixture("cost", 2, {"estimate_minor": 120000}),
)
return {item["name"]: item for item in results}
packet = asyncio.run(prepare_packet())
assert packet["capacity"]["revision"] == 9
This executable fixture has no network access. In a real adapter, set individual deadlines, distinguish optional from required evidence and preserve failures in the result packet. A missing capacity result must not become zero cost or unlimited availability by default.
Cancellation is not a rollback
If one required read fails, cancel work that is no longer useful. But an external write may already have reached its provider before cancellation is observed. The coordinator must inspect operation receipts rather than assume that cancelling a coroutine undid its effect.
Keep the read fan-out separate from writes for this reason. If a task genuinely requires several external effects, model each one explicitly with its own recovery state and the compensation that the business permits. Deleting a created calendar event is a different operation from pretending it was never sent to attendees.
Put a revision fence around the shared decision
The packet might contain customer revision four and capacity revision nine. Before sending the quote, revalidate the fields that determine price and delivery. Some evidence can tolerate age; other facts are decisive. Record that policy rather than treating every source as equally fresh.
Use optimistic concurrency for the business record. If another worker changes the accepted scope, the second writer must re-read and reconsider. A database lock held across a long model call would block unrelated work and still not solve provider uncertainty.
Reserve shared resources atomically
The reference Budget object bounds a single in-process episode. It is not safe as a shared distributed counter. Several workers need a database or other transactional budget service that reserves resources before work starts.
Budget ceiling: S$10
Worker A reserves S$4 → remaining unreserved S$6
Worker B reserves S$4 → remaining unreserved S$2
Worker C requests S$4 → wait, reduce scope or request review
Provider receipts settle actual costs; unused reservations are released
Include model calls, paid search, enrichment and expensive document processing. Separate a per-task ceiling from a tenant-wide daily ceiling. A task that is individually affordable can still overload the business when thousands of similar tasks arrive.
Reservations need expiry and reconciliation, but do not release a reservation merely because the worker vanished. An accepted provider request may still produce a bill. Record uncertain spending until the provider evidence resolves it.
Bound concurrency by the constrained resource
A connector may limit requests per minute while the model provider limits tokens and the database limits concurrent transactions. One global “maximum agents” setting cannot represent all those constraints.
Use per-provider semaphores or distributed rate limits, per-tenant queue limits and bounded pending work. Apply backpressure at ingestion or scheduling when downstream queues are saturated. A queue that accepts unlimited work with no delivery estimate is merely hiding overload.
For fairness, avoid allowing one bulk enrichment campaign to starve urgent support or payment reconciliation. Weighted queues or reserved capacity can express business priority. Measure queue age by task class rather than only total throughput.
Keep workers specialised enough to evaluate
A research worker returns evidence and uncertainty. A planning worker compares options. A domain action service validates a proposed transition. Giving every worker the same unrestricted tools makes the system harder to test and easier to duplicate work inside.
The coordinator should track a bounded task graph with dependencies and a termination condition. If the research worker keeps asking the planner for clarification and the planner keeps requesting more research, stop at the configured step or cost limit and return a review packet. A conversational loop is not progress by itself.
A concurrency test worth running
Create two workers reading quote version eight. Both propose a different discount. Permit one reviewed update to create version nine, then attempt the second update using version eight. The second must fail without sending a message. Separately, run two dispatch attempts for the same operation and verify one provider effect under the adapter's stated guarantees.
Finally, saturate a low-priority queue and check that an urgent reconciliation task still starts within its intended service objective. Report the actual test environment and measured result when you run that experiment. The platform currently supplies local contracts and fixtures; a production throughput claim needs that load test, not a count of concurrently created agent objects.