design.md 18 KB

Tool Agent 设计文档

1. 概述

  • 项目名称:tool_agent
  • 目标:可自动封装、接入、部署、编写工具的 Agent + 工具库系统
  • 目标用户:其他 Agent 系统(作为工具供应商)

2. 系统架构

tool_agent 由三个核心角色协作:

┌─────────────────────────────────────────────────────────┐
│                    RouterAgent(常驻)                    │
│  main 启动时即运行,负责:                                │
│  - 对外接口(FastAPI: /health, /tools, /run_tool, /chat)│
│  - CodingAgent 调度(接收任务书 → 创建工具)             │
│  - 工具注册表 + 状态管理                                 │
│  - 全局状态监控(工具/CodingAgent/ServiceAgent 窗口)    │
├─────────────────────────────────────────────────────────┤
│                  ServiceAgent(按需创建)                 │
│  每个 chat_id 对应一个独立对话 session:                  │
│  - 只读查询工具表、工具组、后端运行时、状态              │
│  - 与外部 Agent 交流,解答工具使用问题                   │
│  - 撰写任务书 → 提交给 RouterAgent                      │
│  - 一个实例,多个 chat_id 窗口并发                       │
├─────────────────────────────────────────────────────────┤
│                  CodingAgent(按需唤醒)                  │
│  接收 RouterAgent 的任务书:                              │
│  - 自主编码、测试、部署工具                              │
│  - 注册工具到 Registry                                   │
└─────────────────────────────────────────────────────────┘

2.1 调用层与后端执行环境

所有工具对外统一为 本地 Python/FastAPI 调用层(uv 管理), 内部后端执行环境(backend_runtime)分三类:

外部调用者(其他 Agent / HTTP 客户端)
  │
  ▼
统一调用层(本地 Python + FastAPI HTTP 接口)
  │
  ├─ backend_runtime: local   → 本地 Python 运行时(纯 uv 子进程)
  ├─ backend_runtime: docker  → Docker 容器运行时
  └─ backend_runtime: remote  → 远程 API / 云端服务

2.2 消息流

外部 Agent
  │
  ├─ IM 消息 ──→ IMClient ──→ ChatWindow(chat_id) ──→ SessionManager ──→ ServiceAgent
  │                                                                          │
  ├─ HTTP /chat ─────────────────────────────────────→ SessionManager ──→ ServiceAgent
  │                                                                          │
  │                                                    需要创建工具时:       │
  │                                                    submit_task() ────→ RouterAgent
  │                                                                          │
  │                                                                    CodingAgent
  │                                                                          │
  └─ HTTP /run_tool ──→ Dispatcher ──→ 工具进程 ←── 注册完成 ←──────────────┘

2.3 工具组(Tool Group)

需要固定配合使用的工具组成工具组,定义在 data/groups.json。 例如 RunComfy 生命周期管理组:launch → run → stop。

3. 三层架构

外部 Agent 请求
       │
       ▼
┌─────────────────────────────────────┐
│        注册层 (Registry)             │
│  - 工具元数据 CRUD (registry.json)   │
│  - 工具组管理 (groups.json)          │
│  - 按类别/关键字/后端运行时搜索      │
└──────────────┬──────────────────────┘
               │
               ▼
┌─────────────────────────────────────┐
│   路由层 (Router) — 兼任对外网关     │
│  - FastAPI 对外接口                  │
│  - 来源管理 (SourceStore)            │
│  - 工具启停 (ToolStatusManager)      │
│  - 请求分发 (Dispatcher)             │
│  - CodingAgent 调度                  │
│  - 全局状态监控                      │
└──────────────┬──────────────────────┘
               │
               ▼
┌─────────────────────────────────────┐
│        运行层 (Runtime)              │
│  - LocalRunner (uv 本地进程)         │
│  - DockerRunner (Docker 容器)        │
│  - 远程 API 直接转发                 │
└─────────────────────────────────────┘

4. 对外接口

仅暴露 4 个 HTTP 接口:

接口 方法 说明
/health GET 健康检查
/tools GET 完整工具表(含后端分类、工具组、运行状态)
/run_tool POST 调用工具 {tool_id, params}
/chat POST 与 ServiceAgent 对话 {message, chat_id}

4.1 /tools 响应示例

{
  "backend_runtimes": [
    {"backend_runtime": "local", "name": "本地 Python 运行时", "tool_count": 5},
    {"backend_runtime": "docker", "name": "Docker 容器运行时", "tool_count": 0},
    {"backend_runtime": "remote", "name": "远程 API / 云端服务", "tool_count": 0}
  ],
  "groups": [
    {
      "group_id": "runcomfy_lifecycle",
      "name": "RunComfy 生命周期管理",
      "tool_ids": ["launch_comfy_env", "runcomfy_workflow_executor", "runcomfy_stop_env"],
      "usage_order": ["launch_comfy_env", "runcomfy_workflow_executor", "runcomfy_stop_env"]
    }
  ],
  "tools": [
    {
      "tool_id": "image_stitcher",
      "name": "图片拼接工具",
      "category": "cv",
      "backend_runtime": "local",
      "group_ids": [],
      "state": "stopped"
    }
  ]
}

4.2 /chat 请求/响应

// 请求
{"message": "有哪些图片处理工具?", "chat_id": "user_A_window_1"}

// 响应
{"response": "当前有 image_stitcher...", "chat_id": "user_A_window_1"}

5. 内部通信

5.1 来源类型(SourceType)

SourceType 说明 通信方式
local 本地 uv 项目 uv run 启动 HTTP 服务,httpx 调用
docker Docker 容器 端口映射 HTTP
remote 远程 API / 云端服务 直接转发 HTTP

5.2 请求分发流程

POST /run_tool {tool_id, params}
       │
       ▼
ToolStatusManager.get_status(tool_id)
       │ 未运行?
       ▼
ToolStatusManager.start_tool(tool_id)
  ├─ local:  uv run python main.py --port {free_port}
  ├─ docker: 检查容器端口映射
  └─ remote: 直接标记 running
       │
       ▼
Dispatcher.dispatch(tool_id, params)
  → httpx.post("http://127.0.0.1:{port}{endpoint_path}", json=params)
       │
       ▼
返回结果

5.3 端口分配

对外(固定):
  8001        - FastAPI

对内(动态):
  uv 本地工具  - 随机空闲端口(socket bind 0)
  Docker 工具  - 容器内部端口映射
  远程工具     - 无需端口,直接转发

6. Agent 角色详解

6.1 RouterAgent

常驻进程,main 启动时即运行。

职责

  • 管理工具注册表(Registry)和状态表(ToolStatusManager)
  • 调度 CodingAgent 执行工具创建任务
  • 监控全局状态(工具、CodingAgent 任务、ServiceAgent 窗口)
  • 对外暴露 FastAPI 接口

全局状态查询 (router.get_system_status()):

{
  "tools": {"total": 5, "active": 5},
  "coding_agent": {
    "running_count": 1,
    "running_task_ids": ["create_a1b2c3d4"],
    "queued_count": 0,
    "recent_tasks": [
      {"task_id": "create_a1b2c3d4", "status": "pending", "task_spec": "..."}
    ]
  },
  "service_agent": {
    "total_windows": 3,
    "im_connected": true,
    "windows": [
      {"chat_id": "user_A_w1", "sdk_session_id": "...", "has_im_window": true}
    ]
  }
}

6.2 ServiceAgent

按需创建,一个实例管理多个 chat_id 窗口。

职责

  • 只读查询工具表、工具组、后端运行时、工具状态
  • 与外部 Agent 对话,解答工具使用问题
  • 撰写任务书提交给 RouterAgent

工具列表(6 个):

工具 权限 说明
list_tools 列出所有工具
get_tool_details 查看工具详情(参数、Schema)
list_groups 列出工具组及使用顺序
list_backend_runtimes 列出后端执行环境类型
check_task_status 查询任务进度
submit_task 撰写任务书提交给 RouterAgent

会话管理

  • SessionManager 按 chat_id 管理 Claude SDK session
  • 每个 chat_id 独立的对话记忆(通过 SDK resume 机制)
  • 同一个 ServiceAgent 实例并发处理多个窗口

6.3 CodingAgent

按需唤醒,接收 RouterAgent 的任务书。

工具列表(10 个):

分类 工具 说明
Docker create_docker_env 创建容器(端口映射/挂载/GPU)
Docker run_in_docker 容器内执行命令(前台/后台)
Docker rebuild_docker_ports 重建容器加端口映射
Docker destroy_docker_env 销毁容器
uv create_uv_project 创建 uv 项目
uv run_in_uv 在 uv 环境中运行命令
uv uv_add_dependency 添加依赖
文件 write_file 写文件(overwrite/append)
文件 read_file 读文件
注册 register_tool 注册工具到 Registry

7. IM Client 接入

7.1 架构

IM Server (WebSocket, port 8000)
    ↕
IMClient (单 WebSocket 连接,contact_id="tool_agent")
    ├─ ChatWindow(chat_id_1) ──→ SessionManager ──→ ServiceAgent session_1
    ├─ ChatWindow(chat_id_2) ──→ SessionManager ──→ ServiceAgent session_2
    └─ ChatWindow(chat_id_3) ──→ SessionManager ──→ ServiceAgent session_3

7.2 消息路由

  • 外部 Agent 发送消息时指定 receiver_chat_id,定向到对应窗口
  • 未指定 receiver_chat_id 时广播到所有窗口
  • 回复时带上 receiver_chat_id = sender_chat_id,消息回到对方窗口

7.3 并发模型

  • 一个 IMClient 实例管理多个 ChatWindow
  • 每个 ChatWindow 有独立的 pending.json / chatbox.jsonl
  • SessionManager 收到通知后,按 chat_id 路由到对应 ServiceAgent session
  • 同一个 ServiceAgent 实例并发处理,Claude SDK session 隔离对话记忆

8. 数据模型

8.1 ToolMeta(工具元数据)

{
  "tool_id": "image_stitcher",
  "name": "图片拼接工具",
  "description": "将多张图片拼接成一张",
  "category": "cv",
  "backend_runtime": "local",
  "group_ids": [],
  "input_schema": {},
  "output_schema": {},
  "stream_support": false,
  "status": "active"
}

8.2 ToolSource(工具来源)

{
  "type": "local",
  "host_dir": "tools/local/image_stitcher",
  "endpoint_path": "/",
  "http_method": "POST",
  "internal_port": 0
}

8.3 ToolRoute(运行状态)

{
  "tool_id": "image_stitcher",
  "sources": [{"type": "local", "host_dir": "..."}],
  "active_source": 0,
  "state": "running",
  "pid": 12345,
  "port": 52341
}

8.4 BackendRuntime(后端执行环境枚举)

说明
local 本地 Python 运行时(纯 uv 子进程)
docker Docker 容器运行时
remote 远程 API / 云端服务

8.5 ToolGroup(工具组)

{
  "group_id": "runcomfy_lifecycle",
  "name": "RunComfy 生命周期管理",
  "description": "云端 ComfyUI 环境的完整生命周期",
  "category": "remote",
  "tool_ids": ["launch_comfy_env", "runcomfy_workflow_executor", "runcomfy_stop_env"],
  "usage_order": ["launch_comfy_env", "runcomfy_workflow_executor", "runcomfy_stop_env"],
  "usage_example": "先 launch 获取 server_id,再 run 执行 workflow,最后 stop 释放资源"
}

9. 目录结构

src/
├── tool_agent/
│   ├── __main__.py              # 入口:启动 Router + SessionManager + IM
│   ├── config.py                # 全局配置
│   ├── models.py                # 数据模型(ToolMeta, BackendRuntime 等)
│   ├── router/
│   │   ├── agent.py             # RouterAgent(常驻,调度 CodingAgent)
│   │   ├── server.py            # FastAPI 接口定义
│   │   ├── dispatcher.py        # 请求分发
│   │   └── status.py            # 工具状态管理 + 来源存储
│   ├── service/
│   │   ├── agent.py             # ServiceAgent(只读客服 + 任务书提交)
│   │   └── session.py           # SessionManager(chat_id 会话管理 + IM 接入)
│   ├── registry/
│   │   ├── registry.py          # 工具注册表
│   │   └── groups.py            # 工具组管理
│   ├── tool/
│   │   └── agent.py             # CodingAgent(自主编码部署)
│   └── runtime/
│       └── local_runner.py      # 本地 uv 运行器
├── im-client/                   # IM 通信客户端(独立模块)
│   ├── client.py                # IMClient + ChatWindow
│   ├── protocol.py              # 消息协议
│   ├── notifier.py              # 通知接口
│   └── tools.py                 # Agent 工具函数封装
data/
├── registry.json                # 工具注册表
├── sources.json                 # 工具来源
└── groups.json                  # 工具组配置

10. 启动流程

async def main():
    router = Router()                          # RouterAgent 初始化
    session_mgr = SessionManager(router)       # 会话管理
    router.set_session_manager(session_mgr)    # 双向引用
    router.create_app(session_manager=session_mgr)

    await session_mgr.start_im("tool_agent", "ws://localhost:8000")  # IM 连接(可选)
    await router.start(port=8001)              # FastAPI 启动

启动命令:uv run python -m tool_agent

11. KnowHub 工具表集成

11.1 双向索引架构

Tool Agent 与 KnowHub 工具表通过双向索引互相关联:

Tool Agent Registry              KnowHub 工具表
┌─────────────────────┐         ┌──────────────────────────┐
│ tool_id: launch_env │◄────────│ id: tools/image_gen/     │
│ tool_slug_ids:      │         │     comfyui              │
│   ["comfyui"]       │────────►│ toolhub_items:           │
│                     │         │   [{launch_env: "..."},  │
│ group_ids:          │         │    {runcomfy_group: ...}]│
│   ["runcomfy_group"]│         └──────────────────────────┘
└─────────────────────┘

字段说明

  • tool_slug_ids: list[str] - Tool Agent 工具关联的 KnowHub tool_slug 列表
  • toolhub_items: list[dict] - KnowHub 工具关联的 Tool Agent 工具/组列表

11.2 智能匹配机制

Router Agent 在 CodingAgent 注册完工具后,自动执行智能匹配:

匹配规则

  1. 工具名称/ID 包含 KnowHub 的 slug 或 title
  2. 工具描述包含 KnowHub 描述的关键词
  3. 分类匹配

自动更新流程

# router/agent.py:_sync_knowhub_after_register()
1. 遍历所有 registry 工具
2. 调用 _match_knowhub_tools() 智能匹配
3. 更新 registry.tool_slug_ids
4. 收集工具和组,更新 KnowHub.toolhub_items
5. 点亮 KnowHub 工具 status="已接入"

相关文件

  • src/tool_agent/models.py:58 - ToolMeta.tool_slug_ids 字段定义
  • src/tool_agent/router/agent.py:115-217 - 智能匹配和同步逻辑
  • src/tool_agent/tool_table.py - KnowHub API 客户端
  • docs/tool_table/tool-table-integration.md - 详细集成文档

12. 里程碑

阶段 内容 状态
Phase 1 Router + Registry + FastAPI + CodingAgent ✅ 已完成
Phase 2 LocalRunner + DockerRunner + 请求分发 ✅ 已完成
Phase 3 工具分类 + 工具组 + BackendRuntime 语义统一 ✅ 已完成
Phase 4 ServiceAgent + SessionManager + IM Client 接入 ✅ 已完成
Phase 5 KnowHub 工具表集成 + 智能匹配 ✅ 已完成
Phase 6 冷热调度集成 + 健康检查集成 🔲 待集成
Phase 7 中间件集成(鉴权/缓存/计量) 🔲 待集成
Phase 8 自修复 + Browser-Use + 财务管理 🔲 待实现