Claude Code 实战(四):多 Agent 平台 — 团队协作、自主代理与 MCP 插件
单个 Agent 能力再强也有上限。本文覆盖多 Agent 平台阶段的 5 个机制,让多个 Agent 协同工作。
前言
在前三篇中,我们从一个空白的 Agent 循环出发,逐步搭建了核心闭环、系统加固和任务运行时。
单个 agent 能力再强也有上限。当工作变得更复杂时,你会自然地需要:
- 多个 agent 协同处理不同子任务
- agent 之间有清晰的通信协议
- 有些 agent 可以完全自主运行
- 不同 agent 的工作互不干扰
- 外部工具可以随时插拔接入
本文是系列最后一篇,覆盖多 Agent 平台阶段:
- Agent 团队(s15)— 多 agent 的组织结构
- 团队协议(s16)— agent 之间的通信规则
- 自主代理(s17)— 无需人工干预的独立 agent
- Worktree 隔离(s18)— 多 agent 的工作区隔离
- MCP 与插件(s19)— 外部能力接入标准
第 15 章:Agent 团队
"单 agent 是一个人在干活,agent 团队是一组人在分工协作"
从子代理到团队
在第一篇中,我们学过了子代理(Subagent)。子代理是临时的、一次性的。团队则不同:
| 子代理 | 团队成员 |
|---|---|
| 临时启动,任务完成即销毁 | 长期存在,有固定角色 |
| 只返回最终结果 | 持续通信,互相协作 |
| 没有独立身份 | 有名字、角色、职责 |
团队结构
Team Lead (协调者)
├── Coder (编码)
├── Reviewer (审查)
└── Tester (测试)
每个团队成员本质上是一个完整的 agent,有自己的:
- 角色定义(system prompt 中的身份)
- 可用工具集(不同角色可能用不同工具)
- 通信频道(如何与其他成员交流)
最小实现
class AgentTeam:
def __init__(self):
self.members = {}
self.message_queue = []
def add_member(self, name: str, role: str, tools: list = None):
self.members[name] = {
"name": name,
"role": role,
"tools": tools or ALL_TOOLS,
"system_prompt": f"You are {name}, a {role}.",
}
def delegate(self, member_name: str, task: str) -> str:
"""把任务交给指定成员"""
member = self.members[member_name]
return run_agent(
system=member["system_prompt"],
tools=member["tools"],
message=task,
)
关键
- 每个团队成员是独立的 agent 实例
- Lead 负责任务分发和结果整合
- 成员之间通过消息通信,不共享上下文
第 16 章:团队协议
"没有协议的团队,比一个人干活还乱"
问题
多个 agent 一起工作时,如果没有统一的通信规则,很快就会变成:
- 重复做同一件事
- 互相等待,谁也不知道谁在做
- 信息丢失,结果无法整合
协议要素
一个最小团队协议需要定义:
protocol = {
"message_format": {
"from": "agent_name",
"to": "agent_name | broadcast",
"type": "task | result | question | status",
"content": "...",
"priority": "high | normal | low",
},
"rules": [
"接到任务后先回复确认",
"遇到不确定的决策,上报 Lead",
"完成任务后发送结果摘要",
]
}
通信模式
| 模式 | 说明 | 示例 |
|---|---|---|
| 点对点 | 直接发给某个成员 | Coder → Reviewer: "代码写好了,请审查" |
| 广播 | 发给所有成员 | Lead → All: "项目优先级变更" |
| 上报 | 发给 Lead | Tester → Lead: "发现阻塞性 bug" |
最小实现
class TeamProtocol:
def __init__(self):
self.inbox = {name: [] for name in team_members}
def send(self, from_agent, to_agent, msg_type, content):
message = {
"from": from_agent,
"to": to_agent,
"type": msg_type,
"content": content,
"timestamp": time.time(),
}
if to_agent == "broadcast":
for name in self.inbox:
self.inbox[name].append(message)
else:
self.inbox[to_agent].append(message)
def receive(self, agent_name) -> list:
messages = self.inbox[agent_name][:]
self.inbox[agent_name].clear()
return messages
第 17 章:自主代理
"有些工作不需要人盯着,交给 agent 自己跑就行"
什么是自主代理
自主代理 = 没有人类在循环中的 agent。它能:
- 自己决定下一步做什么
- 自己判断任务是否完成
- 遇到问题自己尝试解决
- 只在真正需要时才通知人类
自主代理 vs 交互式代理
| 交互式代理 | 自主代理 |
|---|---|
| 每轮等用户输入 | 自己驱动循环 |
| 需要人类确认 | 自己做决策 |
| 适合探索和创意 | 适合重复性工作 |
| 实时反馈 | 批量处理结果 |
安全边界
自主代理必须遵守更严格的规则:
AUTONOMOUS_RULES = {
"max_iterations": 100, # 最大迭代次数
"budget_limit": 5.0, # 最大花费(美元)
"allowed_tools": ["read_file", "write_file", "bash", "search"],
"deny_commands": ["sudo", "rm -rf", "DROP TABLE"],
"notification_on": ["error", "budget_80%", "task_complete"],
}
最小实现
def run_autonomous(task: str, rules: dict) -> str:
messages = [{"role": "user", "content": task}]
iterations = 0
while iterations < rules["max_iterations"]:
iterations += 1
response = client.messages.create(
model=MODEL,
system=AUTONOMOUS_SYSTEM_PROMPT,
messages=messages,
tools=get_tools(rules["allowed_tools"]),
)
if response.stop_reason != "tool_use":
# Agent 认为任务完成了
return response.content[0].text
# 执行工具调用(经过权限检查)
for block in response.content:
if block.type == "tool_use":
if not is_allowed(block.name, block.input, rules):
result = "Permission denied in autonomous mode"
else:
result = execute(block.name, block.input)
messages.append(tool_result(result))
return "Max iterations reached. Task may be incomplete."
第 18 章:Worktree 隔离
"多个 agent 同时改代码,互相踩脚怎么办?"
问题
当多个 agent 同时在同一个代码库上工作时:
- Agent A 改了文件,Agent B 读到了半成品
- Agent A 和 Agent B 同时改同一个文件,互相覆盖
- 一个 agent 的错误影响另一个 agent 的工作环境
解决方案:Git Worktree
Git worktree 让同一个仓库同时有多个工作目录,每个目录在独立的分支上:
project/
├── .git/
├── worktree/
│ ├── agent-a/ # 分支: feature/auth
│ ├── agent-b/ # 分支: feature/api
│ └── agent-c/ # 分支: hotfix/bug-123
最小实现
class WorktreeManager:
def __init__(self, repo_path):
self.repo_path = repo_path
self.worktrees = {}
def create(self, agent_name: str, branch: str) -> str:
"""为 agent 创建独立工作目录"""
worktree_path = f"{self.repo_path}/worktree/{agent_name}"
subprocess.run([
"git", "worktree", "add", worktree_path, "-b", branch
], cwd=self.repo_path)
self.worktrees[agent_name] = {
"path": worktree_path,
"branch": branch,
}
return worktree_path
def remove(self, agent_name: str):
"""清理 agent 的工作目录"""
info = self.worktrees.pop(agent_name, None)
if info:
subprocess.run(
["git", "worktree", "remove", info["path"], "--force"],
cwd=self.repo_path,
)
def merge(self, agent_name: str, target_branch: str = "main"):
"""合并 agent 的工作到目标分支"""
info = self.worktrees[agent_name]
subprocess.run(
["git", "checkout", target_branch],
cwd=self.repo_path,
)
subprocess.run(
["git", "merge", info["branch"]],
cwd=self.repo_path,
)
关键
- 每个 agent 有独立的工作目录和分支
- 互不干扰,不会互相踩脚
- 完成后可以合并回主分支
- 工作目录可以随时创建和清理
第 19 章:MCP 与插件
"工具不必都写死在主程序里,外部进程也可以把能力接进来"
MCP 是什么
MCP(Model Context Protocol)= 一套让 agent 和外部工具程序对话的统一协议。
之前所有工具都写在你自己的 Python 代码里。但真实系统走到一定阶段,会自然地需要:让外部程序也把工具接进来,而不用每次都改主程序。
为什么放在最后
MCP 不是主循环的起点,而是主循环稳定之后的扩展层。当你已经理解了 agent loop、tool call、permission、task、worktree,MCP 本质上只是:把"工具来源"从"本地硬编码"升级成"外部可插拔"。
最小心智模型
LLM
|
| asks to call a tool
v
Agent tool router
+-- native tool -> 本地 Python handler
+-- MCP tool -> 外部 MCP server
v
return result
最小系统三件事
1. MCP Client — 启动外部进程、发送请求、接收响应
2. 工具名前缀 — 避免命名冲突:mcp__{server}__{tool}
例如:mcp__postgres__query、mcp__browser__open_tab
3. 统一路由器
if tool_name.startswith("mcp__"):
return mcp_router.call(tool_name, arguments)
else:
return native_handler(arguments)
Plugin 配置
MCP 解决"外部工具怎么通信",plugin 解决"这些外部工具怎么被发现":
{
"name": "my-db-tools",
"version": "1.0.0",
"mcpServers": {
"postgres": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-postgres"]
}
}
}
关键:MCP 工具仍然走权限管道
MCP 工具虽然来自外部,但不能绕开 permission。不然等于在系统边上开了安全后门。
完整接入流程:
启动时:
PluginLoader -> manifest -> server 配置
-> MCP client 连接 -> list_tools -> 合并进工具池
运行时:
LLM tool_use -> 权限闸门 -> native/mcp route
-> 结果标准化 -> tool_result 回到主循环
进入方式不同,但进入后必须回到同一条控制面和执行面。
三层概念
| 层级 | 是什么 | 负责什么 |
|---|---|---|
| Plugin | 配置发现 | 找到哪些外部能力可以接入 |
| MCP Server | 一个外部进程 | 暴露一组工具并处理请求 |
| MCP Tool | 单个工具 | 完成一次具体操作 |
全系列总结
4 篇文章,19 个章节,我们从一个空的 while True 循环出发,一步步搭建了一个完整的 AI Agent 平台:
| 阶段 | 篇章 | 覆盖内容 |
|---|---|---|
| 核心闭环 | 第一篇 | Agent 循环、工具使用、待办写入、子代理、技能系统、上下文压缩 |
| 系统加固 | 第二篇 | 权限系统、Hook 系统、记忆系统、系统提示词、错误恢复 |
| 任务运行时 | 第三篇 | 任务系统、后台任务、定时调度 |
| 多 Agent 平台 | 本文 | Agent 团队、团队协议、自主代理、Worktree 隔离、MCP 与插件 |
学习路径建议
- 先动手:从 s01 的 Agent 循环开始,自己写一遍
- 逐步叠加:每学一个机制,在前一个的基础上加
- 遇到问题回头:每个章节都有"建议联读",帮你找到关联
- 不要跳章:后面章节依赖前面的心智模型
进阶资源
- 原始教程:Learn Claude Code
- GitHub 源码:shareAI-lab/learn-claude-code
- Claude Code 官方文档:docs.anthropic.com
- 配置教程:Claude Code 完整配置指南
常见问题
Q: 多 Agent 和单个强 Agent 哪个更好?
取决于任务。简单任务用单 Agent 更高效(减少通信开销)。复杂任务(多种角色、独立并行、需要隔离)用多 Agent 更合适。别上来就搞团队,先确认单 Agent 真的不够用。
Q: MCP 和普通 API 调用有什么区别?
普通 API 调用是你写代码去调。MCP 是标准化协议,让任何外部工具都能用统一方式接入你的 Agent。类比:普通 API 是"自己写驱动",MCP 是"即插即用 USB"。
Q: 自主代理安全吗?
安全取决于你的规则设计。自主代理必须有:迭代次数上限、费用上限、工具白名单、危险命令黑名单。建议先用交互模式测试,确认稳定后再切换到自主模式。
Q: Worktree 会占用很多磁盘空间吗?
不会。Git worktree 是轻量的——它共享 .git 对象仓库,每个工作目录只多占工作文件的空间。一个项目多 3-5 个 worktree 通常只多几十 MB。
Q: 团队协议能用自然语言吗?
可以,但不推荐。自然语言协议容易产生歧义。建议用结构化的 JSON 消息格式,加上少量自然语言说明。这样机器好解析,人类也好理解。更多 Agent 开发技巧见 Claude Code 配置教程。
本文基于 Learn Claude Code 开源项目(GitHub: shareAI-lab/learn-claude-code)整理改编。感谢 shareAI-lab 团队的出色工作。
系列文章:
系列文章:
