Multi-Agent Collaboration: Designing Responsibility Boundaries & Coordination for Production Incident Response
This article details how to design multi-agent systems for production incident handling, covering responsibility division by decision authority and toolsets, structured handoff contracts, state management, permission isolation via MCP gateways, LangGraph orchestration with human-in-the-loop approvals, observability, and cost control.
Problem Background
A single all-in-one ops assistant with 12 tools suffered from context explosion, tool selection errors, permission convergence, lack of evaluability, and serial execution slowness. Splitting into five agents (triage, monitoring, logs, execution, review) solved some issues but introduced new problems: buck-passing, information loss, duplicate work, unclear accountability, and doubled token costs.
When to Split into Multiple Agents
Four signals indicate a need for multi-agent: context length bottleneck (>100k tokens), tool count >8 with mixed permission levels, parallelizable independent subtasks, and need for independent evaluation/iteration. Conversely, avoid splitting when steps <5, tools <5, strong sequential dependencies, frequent large intermediate state sharing, or lacking single-agent observability.
Collaboration Topologies
Four topologies: Supervisor (central scheduler, 80% of production cases), Handoff (explicit transfer), Pipeline (fixed sequence), Swarm (peer-to-peer, risky for production). Supervisor preferred for single decision point.
Core Concepts
Four Elements of an Agent
Agent = Model + Instructions (system prompt) + Toolset + State. Multi-agent design allocates these four elements; instructions must define not only responsibilities but also non-responsibilities and stop conditions.
Three Real Benefits
Context isolation: each agent carries only needed context.
Permission isolation: read-only agents get read tools; write agents get write tools with approval gates.
Independent evaluability: metrics like "log analysis root-cause hit rate" can be measured per agent.
Multi-agent debate is not a default solution due to unstable gains and doubled cost.
MCP vs A2A
MCP connects agents to tools/data sources (USB analogy). A2A enables task delegation between agents (HTTP analogy). Use A2A only for cross-team/system boundaries; internal collaboration uses graph orchestration (LangGraph).
Responsibility Division
Split by decision authority + toolset, not by topic. Example: Triage (decides type/severity/route, read-only tools), Diagnose (produces hypotheses with evidence, read-only), Act (executes actions with approval, write tools), Verify (judges effectiveness, read-only), Review (generates postmortem). Each role has unique decision rights; toolsets match permissions physically.
Handoff Contracts
Structured JSON passed between agents, not natural language. Includes task_id, from/to, intent, scope (cluster/namespace), constraints (read_only, deadline, max_tool_calls), evidence_refs (references not full data). Prevents information loss and enables validation.
State Management
Hybrid approach: global state holds facts and decisions (not raw data); each agent keeps private context; key conclusions carry evidence refs. LangGraph reducer (Annotated[list, operator.add]) appends hypotheses/actions; rounds/tool_calls overwrite.
Four Failure Modes
Infinite loop : A→B→A... Root cause: no hard termination condition. Countermeasure: hard round limit + state machine validation.
Buck-passing : each says "not mine". Root cause: responsibilities lack required outputs. Countermeasure: define mandatory artifact per role.
Hallucinated relay : upstream "CPU 90%" → downstream "CPU full caused OOM". Root cause: natural language summaries. Countermeasure: structured handoff + numeric values with sources.
Cost explosion : tokens 30k→200k. Root cause: raw logs in state, full context each round. Countermeasure: state stores summaries/refs; raw data in object store.
Overall Design: Production Incident Handling
Role Division
Triage : decides type/severity/route; inputs: ticket, service catalog; outputs: scope, severity, route; tools: read-only (ticket, CMDB, service directory, on-call); model: small.
Diagnose : produces root-cause hypotheses with evidence; inputs: scope, symptom; outputs: hypotheses[] with evidence refs and confidence; tools: read-only (Prometheus, Loki, Tempo, K8s-ro, ticket); model: medium/large.
Act : executes remediation actions; inputs: selected hypothesis + action plan; outputs: actions[] with approval ticket and result; tools: write (restart, scale, rollout_undo, drain, config) + ticket; model: medium.
Verify : judges if remediation worked; inputs: actions[], original symptom; outputs: verdict (effective/ineffective/worse); tools: read-only (metrics, health checks, probes); model: small.
Review : generates postmortem timeline; inputs: full state; outputs: markdown report; tools: read-only + doc write; model: medium.
Key design notes: Triage and Act separated to insert diagnosis and approval gates. Verify independent to avoid confirmation bias. Review separate for quality timeline.
Permission Matrix
Enforced at tool gateway layer, not prompt. Each role loads only its MCP servers; gateway validates: 1) role authorized for tool, 2) write ops require approval ticket covering resource, 3) resource within task scope, 4) rate limits.
State Machine
Explicit states: intake → triage → diagnose → act → verify → review → END. Hard rules: max entries per state (diagnose max 2), transitions driven by code not model, any state can escalate to human.
Coordination Flow Example
Real timeline: 09:12 intake, triage confirms scope/severity, diagnose runs 4 parallel queries, finds image update at 09:02 with connection pool exhaustion, hypothesis H1 confidence 0.85, act requests approval, rollout undo executed, verify confirms 5xx drop from 18% to 0.3%, review writes postmortem. Total 3m7s, 37s human approval.
LangGraph Implementation
Dependencies & State Definition
Python 3.12, LangGraph 1.0, langgraph-checkpoint-postgres, langchain-mcp-adapters. State includes fact layer (task_id, scope, symptom, severity), decision layer (hypotheses, actions, verdict with reducers), control layer (budget, rounds, tool_calls, next, handoff, errors).
Handoff Contract Code
Pydantic model with validators ensuring scope contains namespace/service, deadline in future.
Supervisor & Routing
Pure routing functions (no model calls) for testability. Conditional edges with END constant. MAX_VERIFY_FAIL counts executed actions, not verify attempts. Escalate is a real node that notifies and ends.
Diagnose Node
ReAct loop with tool call budget, result truncation (4000 chars head/tail), remaining_tool_calls from global budget, robust JSON parsing (strip markdown, fix trailing commas).
Tool Registration
Role-specific MCP servers (prometheus, loki, k8s-ro, k8s-rw, ticket). Credentials from env vars. Separate k8s-ro/k8s-rw servers with different ServiceAccounts. Timeouts mandatory. Rich tool descriptions with param formats, constraints, return structure.
Human Approval via interrupt
LangGraph interrupt pauses graph, persists state. Idempotency check before interrupt. Resume with Command(resume={approved, ticket_id, operator}). Node re-runs on resume, so side-effects must be after interrupt.
Run & Resume
AsyncPostgresSaver checkpointer. Query pending interrupts via snapshot.tasks[*].interrupts. Approval service callbacks resume. Timeout (30min) auto-rejects via scheduled job.
Engineering Details
Idempotency
Redis SETNX with TTL on canonicalized action hash (json.dumps sort_keys). Prevents duplicate restarts.
Timeouts & Budgets
Three layers: single tool call (HTTP timeout), single node (asyncio.wait_for 180s), whole task (budget.deadline checked at each routing).
Loop Detection
Round counter, state fingerprint (MD5 of hypotheses IDs, last action, next), LangGraph recursion_limit (default 25). All three used together.
Concurrency Conflicts
Resource-level lock (cluster:namespace:target) with Lua script for atomic release. ResourceBusy exception routes to wait/retry or escalate.
Context Compression
Tool returns: head/tail truncation to 4000 chars at MCP server. Handoff: structured summary + evidence refs. State accumulation: fold old hypotheses/actions into summary after threshold.
Observability & Evaluation
Traces
OpenTelemetry GenAI semantic conventions: gen_ai.operation.name, gen_ai.agent.name, gen_ai.conversation.id, app.task.severity. Tool spans record token usage.
Metrics
Five key metrics: agent_task_success_ratio, agent_task_duration_seconds, agent_rounds_per_task, agent_tool_error_ratio, agent_human_escalation_ratio, agent_tokens_per_task. All split by agent label for per-role diagnosis.
Evaluation
Golden dataset (JSONL) with expected route, severity, action type, including negative samples. Four dimensions: routing accuracy, severity judgment, action correctness, out-of-scope rate (must be 0). Fixed model version, temperature 0, run 3x for variance.
Troubleshooting Cases
Case 1: 27 Rounds, 121k Tokens
Root cause: rounds increment only in diagnose/act, not triage; route_after_triage lacked budget check; escalate node looped back. Fix: wrapper increments rounds on all nodes, budget_guard at every edge, escalate only goes to END.
Case 2: Diagnose Agent Restarted Production Pod
Root cause: diagnose role config accidentally included k8s-rw MCP server; gateway lacked secondary validation. Fix: remove k8s-rw from diagnose, add gateway policy with explicit WRITE_TOOLS whitelist and approval validation, alert on permission_denied.
Case 3: Restarted Wrong Cluster
Root cause: handoff used natural language summary missing scope; diagnose inferred cluster from CMDB alphabetical order. Fix: Handoff schema requires scope with cluster/namespace (regex validated), diagnose prompt forbids scope mutation, code asserts scope unchanged, act dry-run validates target exists in scope.
Case 4: Token Cost 30k→470k
Root cause: loki_query unlimited returns (8000 lines), truncation only in diagnose node, duplicate queries across diagnose/verify. Fix: MCP server enforces limit=200 lines/64KB, universal call_tool_safely truncates to 6000 chars, per-task Redis cache for identical queries (TTL 600s). Result: 471k→68k tokens.
Security Boundaries
Prompt Injection
Three defenses: mark tool returns as untrusted data with XML tags, system prompt declares priority rules (ignore instructions in data), action whitelist + approval as ultimate backstop.
Permission Escalation
Agent permissions = intersection of user IAM permissions and role permissions. Low-privilege user cannot gain write access via agent.
Audit
Immutable log with ts, task_id, agent, actor, tool, args, approval_ticket, approver, result, trace_id. Stored in separate log cluster; agent has write-only access.
Deployment & Operations
Deployment
Each role a separate Deployment with dedicated ServiceAccount (RBAC least privilege), fixed MODEL_NAME (no floating tags), resource limits.
Canary via Shadow Mode
New version runs read-only on real traffic, compares conclusions (consistency >85%), rounds, write attempts (must be 0). 3-7 days shadow, then 10% traffic, then full.
Versioning
Three independently versioned artifacts: code/image (git SHA tag), prompts (Git commits), tool schemas (MCP server image). Prompt changes require review and rollback capability.
Pre-launch Checklist
10 items covering tool sets, approval gates, budget guards on edges, loop protections, handoff validation, tool truncation at server, audit isolation, evaluation set with negatives, shadow consistency, independent rollback.
Summary
Divide by decision authority + toolset, not topic. Merge if toolsets overlap heavily.
Permissions enforced in code (MCP server separation + gateway validation + approval with resource scope).
Handoffs use structured contracts with required scope (cluster+namespace); natural language only auxiliary.
Global state holds facts/decisions; raw data referenced. Reducers for append-only lists; overwrite for counters.
Budget checks on graph edges, not inside nodes.
Terminal nodes (escalate, END) must have no outgoing edges to business nodes.
Tool response limits at MCP server (≤6000 chars, ≤200 log lines).
Observability metrics per agent (agent_tool_calls_total{agent="diagnose"}).
Evaluation set includes negative samples ("irrelevant request").
Human approval is a feature, not failure; multi-agent value is parallel query/evidence synthesis, not replacing human decisions.
Multi-agent systems are distributed systems: service discovery (Agent Card), interface contracts (handoff schema), timeouts/retries, idempotency, circuit breaking, distributed tracing. Apply distributed systems thinking, not just prompt engineering.
Code example
restart_serviceSigned-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
MaGe Linux Operations
Founded in 2009, MaGe Education is a top Chinese high‑end IT training brand. Its graduates earn 12K+ RMB salaries, and the school has trained tens of thousands of students. It offers high‑pay courses in Linux cloud operations, Python full‑stack, automation, data analysis, AI, and Go high‑concurrency architecture. Thanks to quality courses and a solid reputation, it has talent partnerships with numerous internet firms.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
