docs: add swarm mode documentation and test script

- Add comprehensive SWARM_README.md with architecture and usage
- Add test_swarm_api.py for API validation
- Document all endpoints, models, and orchestration strategies
This commit is contained in:
elipitc
2026-05-17 20:22:51 +08:00
parent b4b20f0b5a
commit 2657ef23db
2 changed files with 479 additions and 0 deletions
+247
View File
@@ -0,0 +1,247 @@
# Swarm Mode - 多Agent协作编码
## 概述
Swarm Mode是agent-manager的多Agent协作功能,允许Claude Code通过API在K8s上创建多个specialized agents协作完成编码任务。
## 架构
```
Claude Code (本地)
↓ HTTP/MCP
Agent Manager (/api/swarm/*)
↓
Swarm Orchestrator (任务分解、分配、聚合)
↓
K8s Cluster (多个独立Namespace)
├─ architect-agent (设计)
├─ coder-agent-1 (实现)
├─ coder-agent-2 (实现)
└─ reviewer-agent (审查)
↓ A2A协议通信
结果聚合 → SSE Stream → Claude Code
```
## 核心功能
### 1. 数据库模型
- **Swarm**: 蜂群主表,存储任务描述、编排策略、状态等
- **SwarmAgent**: 蜂群中的Agent实例,存储角色、配置、K8s资源信息
- **SwarmMessage**: Agent间通信消息记录
### 2. API端点
#### POST /api/swarm/create
创建新的蜂群。
**请求示例:**
```json
{
"task_description": "实现用户认证模块",
"project_context": {
"repo_url": "https://github.com/user/project",
"branch": "feature/auth",
"language": "python",
"framework": "fastapi"
},
"agents": [
{
"role": "architect",
"template": "a2a_litellm_agent",
"model": "gpt-4",
"capabilities": ["design", "planning"],
"replicas": 1
},
{
"role": "coder",
"template": "code_manager_agent",
"model": "gpt-4",
"capabilities": ["coding", "git"],
"replicas": 2
}
],
"orchestration": {
"strategy": "sequential",
"max_iterations": 3,
"timeout_minutes": 30
}
}
```
**响应示例:**
```json
{
"swarm_id": "swm_a1b2c3d4e5f6",
"status": "initializing",
"agents": [
{
"agent_id": "agi_architect_001",
"role": "architect",
"status": "pending",
"namespace": "swarm-swm-a1b2c3-architect"
}
],
"created_at": "2026-05-17T10:30:00Z"
}
```
#### GET /api/swarm/{swarm_id}/status
查询蜂群状态。
**响应示例:**
```json
{
"swarm_id": "swm_a1b2c3d4e5f6",
"status": "running",
"phase": "coding",
"progress": 65,
"agents": [...],
"metrics": {
"total_messages": 45,
"tokens_used": 125000,
"elapsed_seconds": 180
}
}
```
#### GET /api/swarm/{swarm_id}/results
SSE流式获取实时结果。
**事件类型:**
- `phase_change`: 阶段变更
- `agent_message`: Agent消息
- `artifact`: 生成的工件(代码、文档等)
- `code_diff`: 代码变更
- `result`: 最终结果
#### POST /api/swarm/{swarm_id}/stop
停止蜂群执行。
**请求示例:**
```json
{
"reason": "用户取消",
"cleanup": true
}
```
#### GET /api/swarm/{swarm_id}/logs
获取所有Agent的日志聚合。
### 3. 编排策略
- **sequential**: 顺序执行(architect → coder → reviewer)
- **parallel**: 并行执行(所有agents同时工作)
- **hybrid**: 混合模式(部分顺序、部分并行)
### 4. K8s资源管理
每个Agent运行在独立的K8s namespace中:
- Namespace命名:`swarm-{swarm_id_prefix}-{role}`
- Pod命名:`agent-{agent_id}`
- Service类型:ClusterIP(内部通信)
- 资源限制:CPU 100m-500m, Memory 256Mi-512Mi
### 5. Agent通信
Agents通过A2A协议(HTTP)直接通信:
- 消息格式:JSON-RPC 2.0
- 传输方式:HTTP POST
- 支持流式:SSE (Server-Sent Events)
## 使用示例
### Python客户端
```python
import requests
# 创建蜂群
response = requests.post("http://localhost:8000/api/swarm/create", json={
"task_description": "实现TODO API",
"agents": [
{"role": "architect", "template": "a2a_litellm_agent"},
{"role": "coder", "template": "code_manager_agent"}
],
"orchestration": {"strategy": "sequential"}
})
swarm_id = response.json()["swarm_id"]
# 监听结果
response = requests.get(
f"http://localhost:8000/api/swarm/{swarm_id}/results",
stream=True
)
for line in response.iter_lines():
if line.startswith(b'data: '):
event = json.loads(line[6:])
print(f"Event: {event['type']}")
```
### 测试脚本
运行测试脚本验证API:
```bash
conda activate data && python test_swarm_api.py
```
## 技术栈
- **FastAPI**: REST API框架
- **SQLAlchemy**: ORM数据库访问
- **Kubernetes Python Client**: K8s资源管理
- **aiohttp**: 异步HTTP客户端
- **PostgreSQL**: 数据持久化
## 文件结构
```
agent-manager/
├── database.py # 新增Swarm相关模型
├── k8s_manager.py # 新增swarm方法
├── app.py # 注册swarm router
├── api/swarm/
│ ├── __init__.py
│ ├── models.py # Pydantic请求/响应模型
│ ├── router.py # API端点
│ ├── orchestrator.py # 核心编排逻辑
│ └── agent_client.py # A2A客户端
└── test_swarm_api.py # 测试脚本
```
## 下一步
### Phase 5: Agent模板优化
- 优化a2a_litellm_agent支持swarm环境变量
- 添加状态上报机制
- 实现Agent间消息路由
### Phase 6: 集成测试
- 端到端测试完整流程
- 测试错误处理和重试
- 性能和资源测试
### Phase 7: Claude Code MCP集成
- 创建MCP server
- 定义swarm工具
- 实现流式结果返回
## 限制和注意事项
1. **当前实现为MVP版本**,Agent Pods实际部署需要K8s集群环境
2. **后台任务执行**使用FastAPI BackgroundTasks,生产环境建议使用Celery
3. **Agent间通信**假设所有agents在同一K8s集群内
4. **资源清理**需要手动调用stop接口,未实现自动TTL
5. **认证授权**未实现,需要在生产环境添加
## 贡献
欢迎提交Issue和Pull Request!
## License
MIT
+232
View File
@@ -0,0 +1,232 @@
#!/usr/bin/env python3
"""
Test script for Swarm API endpoints.
"""
import requests
import json
import time
BASE_URL = "http://localhost:8000"
def test_create_swarm():
"""Test creating a swarm"""
print("\n=== Testing Swarm Creation ===")
payload = {
"task_description": "实现用户认证模块,包括登录、注册、密码重置功能",
"project_context": {
"repo_url": "https://github.com/test/project",
"branch": "feature/auth",
"language": "python",
"framework": "fastapi"
},
"agents": [
{
"role": "architect",
"template": "a2a_litellm_agent",
"model": "gpt-4",
"capabilities": ["design", "planning"],
"system_prompt": "你是架构师,负责设计系统架构和API接口",
"replicas": 1
},
{
"role": "coder",
"template": "code_manager_agent",
"model": "gpt-4",
"capabilities": ["coding", "git"],
"system_prompt": "你是开发工程师,负责实现代码",
"replicas": 2
},
{
"role": "reviewer",
"template": "a2a_litellm_agent",
"model": "gpt-4",
"capabilities": ["review", "testing"],
"system_prompt": "你是代码审查员,负责审查代码质量",
"replicas": 1
}
],
"orchestration": {
"strategy": "sequential",
"max_iterations": 3,
"timeout_minutes": 30
},
"owner_id": "test_user"
}
try:
response = requests.post(f"{BASE_URL}/api/swarm/create", json=payload)
response.raise_for_status()
result = response.json()
print(f"✅ Swarm created successfully!")
print(f" Swarm ID: {result['swarm_id']}")
print(f" Status: {result['status']}")
print(f" Agents: {len(result['agents'])}")
for agent in result['agents']:
print(f" - {agent['role']}: {agent['agent_id']} ({agent['status']})")
return result['swarm_id']
except requests.exceptions.RequestException as e:
print(f"❌ Failed to create swarm: {e}")
if hasattr(e.response, 'text'):
print(f" Response: {e.response.text}")
return None
def test_get_swarm_status(swarm_id):
"""Test getting swarm status"""
print(f"\n=== Testing Swarm Status (ID: {swarm_id}) ===")
try:
response = requests.get(f"{BASE_URL}/api/swarm/{swarm_id}/status")
response.raise_for_status()
result = response.json()
print(f"✅ Swarm status retrieved!")
print(f" Status: {result['status']}")
print(f" Phase: {result.get('phase', 'N/A')}")
print(f" Progress: {result['progress']}%")
print(f" Total Messages: {result['metrics']['total_messages']}")
print(f" Elapsed: {result['metrics']['elapsed_seconds']}s")
return result
except requests.exceptions.RequestException as e:
print(f"❌ Failed to get swarm status: {e}")
return None
def test_stream_swarm_results(swarm_id, duration=10):
"""Test streaming swarm results"""
print(f"\n=== Testing Swarm Results Stream (ID: {swarm_id}) ===")
print(f"Streaming for {duration} seconds...")
try:
response = requests.get(
f"{BASE_URL}/api/swarm/{swarm_id}/results",
stream=True,
timeout=duration + 5
)
response.raise_for_status()
start_time = time.time()
event_count = 0
for line in response.iter_lines():
if time.time() - start_time > duration:
break
if line:
line = line.decode('utf-8')
if line.startswith('data: '):
event_count += 1
data = json.loads(line[6:])
event_type = data.get('type', 'unknown')
print(f" Event #{event_count}: {event_type}")
if event_type == 'phase_change':
print(f" Phase: {data.get('phase')}")
elif event_type == 'agent_message':
print(f" From: {data.get('from_agent_id', 'orchestrator')}")
print(f" To: {data.get('to_agent_id', 'orchestrator')}")
elif event_type == 'result':
print(f" Final Status: {data.get('status')}")
break
print(f"✅ Received {event_count} events")
except requests.exceptions.RequestException as e:
print(f"❌ Failed to stream results: {e}")
def test_stop_swarm(swarm_id):
"""Test stopping a swarm"""
print(f"\n=== Testing Swarm Stop (ID: {swarm_id}) ===")
payload = {
"reason": "Test completed",
"cleanup": False # Don't cleanup for testing
}
try:
response = requests.post(f"{BASE_URL}/api/swarm/{swarm_id}/stop", json=payload)
response.raise_for_status()
result = response.json()
print(f"✅ Swarm stopped successfully!")
print(f" Status: {result['status']}")
print(f" Stopped at: {result['stopped_at']}")
return result
except requests.exceptions.RequestException as e:
print(f"❌ Failed to stop swarm: {e}")
return None
def test_get_swarm_logs(swarm_id):
"""Test getting swarm logs"""
print(f"\n=== Testing Swarm Logs (ID: {swarm_id}) ===")
try:
response = requests.get(f"{BASE_URL}/api/swarm/{swarm_id}/logs")
response.raise_for_status()
result = response.json()
print(f"✅ Swarm logs retrieved!")
print(f" Agents: {len(result.get('agents', []))}")
for agent in result.get('agents', []):
print(f" - {agent['role']} ({agent['agent_id']})")
return result
except requests.exceptions.RequestException as e:
print(f"❌ Failed to get swarm logs: {e}")
return None
def main():
"""Run all tests"""
print("=" * 60)
print("Swarm API Test Suite")
print("=" * 60)
# Test 1: Create swarm
swarm_id = test_create_swarm()
if not swarm_id:
print("\n❌ Cannot continue tests without swarm_id")
return
# Wait a bit for initialization
print("\nWaiting 2 seconds for initialization...")
time.sleep(2)
# Test 2: Get status
test_get_swarm_status(swarm_id)
# Test 3: Stream results (for 10 seconds)
test_stream_swarm_results(swarm_id, duration=10)
# Test 4: Get logs
test_get_swarm_logs(swarm_id)
# Test 5: Stop swarm
test_stop_swarm(swarm_id)
# Final status check
print("\nFinal status check...")
test_get_swarm_status(swarm_id)
print("\n" + "=" * 60)
print("Test Suite Completed!")
print("=" * 60)
if __name__ == "__main__":
main()