- 新增 CLIPluginAdapter 统一接口 (backend/app/core/agent_adapter.py) - 新增 LLM 服务层,支持 Anthropic/OpenAI/DeepSeek/Ollama (backend/app/services/llm_service.py) - 新增 Agent 执行引擎,支持文件锁自动管理 (backend/app/services/agent_executor.py) - 新增 NativeLLMAgent 原生 LLM 适配器 (backend/app/adapters/native_llm_agent.py) - 新增进程管理器 (backend/app/services/process_manager.py) - 新增 Agent 控制 API (backend/app/routers/agents_control.py) - 新增 WebSocket 实时通信 (backend/app/routers/websocket.py) - 更新前端 AgentsPage,支持启动/停止 Agent - 测试通过:Agent 启动、批量操作、栅栏同步 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
25 KiB
25 KiB
Swarm - 多 Agent 协作系统设计文档
版本:1.0 日期:2026-03-04 作者:Swarm Team
目录
1. 项目概述
1.1 核心目标
构建一个通用的多 Agent 协作框架,支持:
- 多工具接入:Claude Code CLI、Kimi CLI、OpenCode 等命令行 AI 工具
- 会议驱动协作:通过会议流程组织 Agent 间的协作
- 资源自动管理:声明式资源管理,Agent 无需手动处理锁
- 协作共识:Agent 之间通过讨论达成共识,而非简单投票
- 动态角色:AI 根据任务自动分析并分配角色
- 多模型支持:支持多种 LLM,智能路由与故障转移
1.2 设计原则
| 原则 | 说明 |
|---|---|
| 插件化 | CLI 工具通过适配器层接入,实现统一接口 |
| 声明式 | Agent 只声明意图,系统自动管理资源 |
| 会议驱动 | Workflow 定义会议节点,栅栏同步触发 |
| 协作共识 | 多轮讨论、迭代提案、AI 收敛判断 |
| AI 分配 | LLM 分析任务自动分配最优角色 |
| 可靠性 | 超时 + 心跳 + finally + 看门狗多层保障 |
2. 系统架构
2.1 整体架构图
┌─────────────────────────────────────────────────────────────────────────────┐
│ 用户界面层 │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Web UI │ │ CLI 工具 │ │ API 接口 │ │ VSCode 插件 │ │
│ │ (React/TS) │ │ (Node.js) │ │ (Express) │ │ (TypeScript)│ │
│ └──────────────┘ └──────────────┘ └──────────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────────────────────────────┘
↕
┌─────────────────────────────────────────────────────────────────────────────┐
│ 协调层 (Python) │
│ ┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐ │
│ │ Workflow Engine │ │ Meeting Scheduler│ │ Resource Manager │ │
│ │ (工作流编排) │ │ (栅栏同步) │ │ (文件锁+心跳) │ │
│ └──────────────────┘ └──────────────────┘ └──────────────────┘ │
│ ┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐ │
│ │ Role Allocator │ │ Consensus Engine │ │ Model Router │ │
│ │ (AI角色分配) │ │ (协作共识) │ │ (多模型路由) │ │
│ └──────────────────┘ └──────────────────┘ └──────────────────┘ │
└─────────────────────────────────────────────────────────────────────────────┘
↕
┌─────────────────────────────────────────────────────────────────────────────┐
│ Agent 适配层 │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ CLIPluginAdapter Interface │ │
│ │ + execute() + join_meeting() + write_state() + read_others() │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ ↓ │
│ ┌────────────┐ ┌────────────┐ ┌────────────┐ ┌────────────┐ │
│ │ ClaudeCode │ │ KimiCLI │ │ OpenCode │ │ 自定义... │ │
│ │ Adapter │ │ Adapter │ │ Adapter │ │ Adapter │ │
│ └────────────┘ └────────────┘ └────────────┘ └────────────┘ │
└─────────────────────────────────────────────────────────────────────────────┘
↕
┌─────────────────────────────────────────────────────────────────────────────┐
│ 模型层 │
│ ┌────────────┐ ┌────────────┐ ┌────────────┐ ┌────────────┐ │
│ │ Anthropic │ │ OpenAI │ │ Google │ │ DeepSeek │ │
│ │ API │ │ API │ │ API │ │ API │ │
│ └────────────┘ └────────────┘ └────────────┘ └────────────┘ │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ Ollama (本地模型) │ │
│ └────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────────┘
↕
┌─────────────────────────────────────────────────────────────────────────────┐
│ 共享存储层 (.doc/) │
│ ├── agents/ ├── dialogues/ ├── progress/ │
│ ├── resources/ ├── meetings/ ├── cache/ │
│ └── workflow/ │
└─────────────────────────────────────────────────────────────────────────────┘
3. 插件化 CLI 工具适配
3.1 统一接口设计
interface CLIPluginAdapter:
"""CLI 工具适配器统一接口"""
id: str
name: str
version: str
# 核心能力
def execute(task: Task) -> Result:
"""执行任务"""
pass
def join_meeting(meeting_id: str) -> None:
"""加入会议等待队列"""
pass
def write_state(state: dict) -> None:
"""写入自己的状态文件"""
pass
def read_others(agent_id: str) -> dict:
"""读取其他 Agent 的状态"""
pass
def update_heartbeat() -> None:
"""更新心跳"""
pass
3.2 预置适配器
| 适配器 | CLI 工具 | 特点 |
|---|---|---|
| ClaudeCodeAdapter | Claude Code CLI | MCP 支持,代码审查强 |
| KimiCLIAdapter | Kimi CLI | ACP 协议,Zsh 集成 |
| OpenCodeAdapter | OpenCode | 快速代码生成 |
| CustomAdapter | 自定义 | 扩展接口 |
3.3 适配器实现示例
class ClaudeCodeAdapter(CLIPluginAdapter):
def __init__(self, config: dict):
self.id = "claude-code-001"
self.name = "Claude Code"
self.config = config
self.executor = TaskExecutor(self.id, resource_manager)
def execute(self, task: Task) -> Result:
# 通过 TaskExecutor 自动管理资源
return self.executor.execute(task.description)
def join_meeting(self, meeting_id: str):
return meeting_scheduler.wait_for_meeting(self.id, meeting_id)
4. 资源管理与文件锁
4.1 核心设计
声明式资源管理:Agent 只需要声明"我要修改这个文件",系统自动获取锁、执行任务、释放锁。
4.2 TaskExecutor 包装层
class TaskExecutor:
"""任务执行器 - 自动管理资源生命周期"""
def execute(self, task_description: str) -> str:
# 1. 解析意图,识别需要的文件
required_files = self._parse_required_files(task_description)
# 2. 获取所有需要的锁
self._acquire_all_locks(required_files, task_description)
try:
# 3. 执行实际任务
result = self._do_execute(task_description)
return result
finally:
# 4. 无论发生什么,都释放锁
self._release_all_locks()
4.3 可靠性保障机制
| 机制 | 解决问题 | 触发方式 |
|---|---|---|
| 超时释放 | 锁忘记释放 | 定时器扫描 |
| 心跳机制 | Agent 挂了检测 | 定时器 + 心跳超时 |
| Lease 上下文管理器 | 代码异常退出 | Python with / finally |
| 生命周期 Hooks | 进程崩溃清理 | atexit + 看门狗 |
| 看门狗进程 | 整个系统挂了 | 独立进程监控 |
| 原子操作 | 并发冲突 | 文件锁 |
4.4 Agent 使用方式
# Agent 代码 - 完全不需要关心锁
class ClaudeCodeAgent:
def fix_login_bug(self):
# 只需要描述任务,锁完全透明
result = self.executor.execute(
"修改 src/main.py 修复登录 bug"
)
return result
5. 会议与共识机制
5.1 栅栏同步
class MeetingScheduler:
"""会议调度器 - 实现栅栏同步"""
def wait_for_meeting(self, agent_id: str, meeting_id: str):
"""
Agent 调用此方法表示"我准备好了,等会议"
最后一个到达的 Agent 触发会议
"""
queue = self._load_queue()
# 加入等待队列
queue[meeting_id]["waiting_agents"].append(agent_id)
# 检查是否所有人都准备好了
if self._is_everyone_ready(meeting_id):
self._start_meeting(meeting_id)
return "meeting_started"
return "waiting"
5.2 协作式共识流程
┌─────────────────────────────────────────────────────────────┐
│ 协作共识流程 │
│ │
│ 第一阶段:收集初步想法 │
│ Agent A: "建议用 JWT,因为..." │
│ Agent B: "我建议用 Session,因为..." │
│ Agent C: "两者结合可能更好..." │
│ │
│ 第二阶段:讨论与迭代(最多5轮) │
│ → Agent 互相质疑、补充、融合 │
│ → 根据讨论更新提案 │
│ → 检查收敛性 │
│ │
│ 第三阶段:生成共识版本 │
│ → 合并相似提案 │
│ → 记录讨论过程 │
│ → 生成会议文件 │
└─────────────────────────────────────────────────────────────┘
5.3 会议文件结构
---
meeting_id: requirement_review_20260304_103000
date: 2026-03-04
attendees: [claude-code-001, kimi-cli-002, opencode-003]
consensus_type: collaborative
iterations: 3
---
# 需求评审会议
## 参会者
- `claude-code-001` (权重: 1.5)
- `kimi-cli-002` (权重: 1.0)
- `opencode-003` (权重: 1.2)
## 讨论过程
### 第一轮:初步想法
[各 Agent 的初步提案...]
### 第二轮:讨论
[互相质疑、补充的过程...]
### 第三轮:迭代
[根据讨论更新的提案...]
## 最终共识
[达成的共识内容...]
## 贡献记录
| Agent | 主要贡献 |
|-------|---------|
| claude-code-001 | ... |
| kimi-cli-002 | ... |
| opencode-003 | ... |
## 后续行动
1. [ ] ...
2. [ ] ...
6. 动态角色分配
6.1 AI 驱动的角色分配
class AIRoleAllocator:
"""AI 驱动的角色分配器"""
def allocate_roles(self, task: Task, available_agents: List[str]) -> dict:
"""
分析任务,自动分配角色给各 Agent
"""
# 获取所有 Agent 的能力描述
agent_capabilities = self._get_agent_capabilities(available_agents)
# 构造提示词,让 AI 分析
prompt = f"""
你是一个团队协调 AI,需要为以下任务分配角色。
## 任务描述
{task.description}
## 可用的 Agent 及其能力
{self._format_capabilities(agent_capabilities)}
请分析任务需求,为每个 Agent 分配最合适的角色。
"""
# 调用 LLM 分析
response = self.llm_client.complete(prompt)
allocation = json.loads(response)
# 应用角色分配
for assignment in allocation["role_assignments"]:
self._apply_role(
assignment["agent_id"],
assignment["role"],
assignment["reason"]
)
return allocation
6.2 可用角色
| 角色 | 名称 | 能力 | 权重 |
|---|---|---|---|
| pm | 产品经理 | 需求分析、优先级排序、用户故事 | 1.5 |
| architect | 架构师 | 系统设计、技术选型、性能规划 | 1.5 |
| developer | 开发者 | 编码、单元测试、代码审查 | 1.0 |
| qa | 测试工程师 | 测试用例、自动化测试、bug报告 | 1.2 |
| reviewer | 代码审查者 | 代码审查、安全检查、性能分析 | 1.3 |
7. 多模型支持
7.1 智能路由策略
class MultiModelRouter:
"""多模型路由器"""
def route(self, task: Task, context: dict) -> str:
"""
智能路由:根据任务类型选择最合适的模型
"""
task_type = self._classify_task(task)
routing_rules = {
"complex_reasoning": ("anthropic", "claude-opus-4.6"),
"code_generation": ("anthropic", "claude-sonnet-4.6"),
"simple_task": ("anthropic", "claude-haiku-4.6"),
"cost_sensitive": ("deepseek", "deepseek-chat"),
"local_privacy": ("ollama", "llama3"),
"multimodal": ("google", "gemini-2.5-flash")
}
provider, model = routing_rules.get(task_type, default)
return self.providers[provider].complete(model, task, context)
7.2 故障转移
def route_with_failover(self, task: Task, context: dict) -> str:
"""带故障转移的路由"""
primary_route = self._get_primary_route(task)
fallback_routes = self._get_fallback_routes()
# 尝试主路由
try:
return self._execute_route(primary_route, task, context)
except Exception:
pass
# 尝试备选路由
for route in fallback_routes:
try:
return self._execute_route(route, task, context)
except Exception:
pass
# 全部失败,使用最简单的本地模型
return self._execute_local_fallback(task, context)
8. 共享存储结构
.doc/
├── agents/ # Agent 注册与状态
│ ├── registry.json # 所有已注册 Agent 列表
│ ├── claude-code-001/ # 每个 Agent 的独立目录
│ │ ├── config.json # Agent 配置
│ │ ├── state.json # 当前状态
│ │ ├── history.json # 历史记录
│ │ └── capabilities.json # 能力声明
│ └── ...
│
├── dialogues/ # Agent 间对话记录
│ └── [agent_a]_[agent_b]_[timestamp].json
│
├── progress/ # 工程进度
│ ├── project_state.json # 项目整体状态
│ ├── milestones.json # 里程碑
│ └── tasks.json # 任务列表
│
├── resources/ # 资源分配
│ ├── resource_pool.json # 资源池状态
│ ├── file_locks.json # 文件锁
│ └── allocation_log.json # 分配日志
│
├── meetings/ # 会议记录与共识
│ ├── [YYYY-MM-DD]/
│ │ └── [HHMMSS]_[meeting_name].md
│ └── meeting_template.md
│
├── cache/ # 实时缓存
│ ├── meeting_queue.json # 会议等待队列
│ ├── message_bus.json # 消息总线快照
│ ├── lock_state.json # 锁状态缓存
│ └── heartbeats.json # Agent 心跳
│
├── workflow/ # 工作流定义
│ ├── project_workflow.yaml # 项目工作流
│ ├── meeting_definitions.yaml # 会议定义
│ └── consensus_rules.yaml # 共识规则
│
└── shared/ # 共享资源
├── knowledge_base/ # 知识库
├── templates/ # 模板文件
└── conventions/ # 编码规范
9. 技术栈
9.1 后端 (Python)
| 组件 | 技术选择 |
|---|---|
| 核心框架 | Python 3.12+ |
| 异步运行时 | asyncio |
| LLM 调用 | anthropic, openai, langchain |
| 文件操作 | pathlib, aiofiles |
| 进程管理 | subprocess, multiprocessing |
| 定时任务 | APScheduler |
9.2 前端 (TypeScript)
| 组件 | 技术选择 |
|---|---|
| 框架 | React 18 + TypeScript |
| UI 库 | shadcn/ui + Tailwind CSS |
| 状态管理 | Zustand |
| 实时通信 | WebSocket |
| HTTP 客户端 | fetch / axios |
9.3 API 层 (Node.js)
| 组件 | 技术选择 |
|---|---|
| 框架 | Express / Fastify |
| 类型检查 | TypeScript |
| 实时通信 | Socket.IO |
| 进程通信 | child_process |
附录
A. 参考项目
B. 更新日志
| 版本 | 日期 | 变更 |
|---|---|---|
| 1.0 | 2026-03-04 | 初始版本 |
| 1.1 | 2026-03-04 | 添加人类参与系统设计 |
C. 人类参与系统
C.1 设计概述
人类参与者通过 humans.json 文件参与协作,无需 API 或 UI 调用。
核心特点:
- 单一共享文件
humans.json - 事件驱动通知机制
- 按优先级区分处理
- 自动合并到会议讨论
C.2 文件结构
.doc/
├── agents/ # Agent 目录
├── humans.json # 人类输入共享文件
├── meetings/ # 会议文件
├── events/ # 事件通知
└── task_queue.json # 任务队列
C.3 humans.json 结构
{
"version": "1.0",
"last_updated": "2026-03-04T14:30:00Z",
"participants": {
"user001": {
"name": "张三",
"role": "tech_lead",
"status": "online",
"avatar": "👤"
}
},
// 任务需求
"task_requests": [
{
"id": "req_001",
"from": "user001",
"timestamp": "2026-03-04T14:28:00Z",
"priority": "high", // high | medium | low
"type": "correction",
"title": "登录验证方式调整",
"content": "建议改用 Session + Redis",
"target_files": ["src/auth/login.py"],
"suggested_agent": "claude-code-001",
"urgent": true,
"status": "pending"
}
],
// 会议发言
"meeting_comments": [
{
"id": "comment_001",
"from": "user001",
"meeting_id": "design_review",
"timestamp": "2026-03-04T14:25:00Z",
"type": "proposal",
"priority": "normal",
"content": "建议使用 SQLite,保持简单",
"status": "pending"
}
],
// 人类状态
"human_states": {
"user001": {
"status": "online",
"current_focus": "reviewing",
"preferred_contact": "async"
}
}
}
C.4 事件驱动流程
人类写入 humans.json
↓
文件监听器触发
↓
写入 events/notification_stream.json
↓
┌───────┴────────┐
│ │
↓ ↓
会议通知 任务通知
│ │
↓ ↓
Agent 收到 Agent 收到
会议通知 任务通知
│ │
↓ ↓
读取会议 读取任务
评论部分 requests
│ │
↓ ↓
参与讨论 按优先级
处理任务
C.5 任务优先级处理
| 优先级 | 处理方式 | 示例 |
|---|---|---|
| high + urgent | 立即中断当前任务 | 安全漏洞修复、生产故障 |
| high | 尽快处理,完成当前任务后 | 功能调整、架构变更 |
| medium | 加入队列,按序处理 | 功能增强、文档补充 |
| low | 空闲时处理 | 优化建议、非紧急任务 |
C.6 会议中的人类发言显示
## 讨论记录
### Agent 提案
**claude-code-001 (14:20)**:
> 建议使用 JWT + Refresh Token...
### 人类发言(高优先级)
**user001 [HUMAN] ⚠️ (14:22)**:
> 我反对使用 JWT。我们的数据量不大,SQLite + Session 就够了。
>
> **优先级:HIGH**
### Agent 响应
**kimi-cli-002 (14:23)**:
> 收到用户反馈,重新评估方案...
C.7 前端输入实现
前端提供任务输入栏,输入后:
- 写入
humans.json的task_requests - 记录发送时间戳
- 触发文件监听事件
- Agent 读取并处理
// 提交任务
function submitTask(content, priority = "medium") {
const request = {
id: `req_${Date.now()}`,
from: "user001",
timestamp: new Date().toISOString(),
priority: priority,
type: "user_task",
content: content,
status: "pending"
};
// 写入 humans.json
humans.task_requests.push(request);
// 保存文件...
}
文档结束