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.

MaGe Linux Operations
MaGe Linux Operations
MaGe Linux Operations
Multi-Agent Collaboration: Designing Responsibility Boundaries & Coordination for Production Incident Response

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_service
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

MCPObservabilityincident-responsemulti-agentA2ALangGraphagent orchestrationpermission isolation
MaGe Linux Operations
Written by

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.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.