# Tool Agent 内部接口文档 ## 目录 1. [数据模型](#1-数据模型) 2. [工具注册表格式](#2-工具注册表格式-registryjson) 3. [来源存储格式](#3-来源存储格式-sourcesjson) 4. [容器状态表格式](#4-容器状态表格式-containersjson) 5. [任务书格式](#5-任务书格式-task_spec) 6. [内部消息格式](#6-内部消息格式-agentmessage) 7. [对外 HTTP 接口](#7-对外-http-接口) 8. [Coding Agent 工具接口](#8-coding-agent-工具接口) 9. [配置参数](#9-配置参数) 10. [Router 工具匹配与对接](#10-router-工具匹配与对接) --- ## 1. 数据模型 ### 1.1 枚举类型 > **架构约束**:所有工具对外统一为本地 Python/FastAPI 调用层(uv 管理)。 > `SourceType` / `BackendRuntime` 表示工具**内部的后端执行环境**,不是调用方式。 | 枚举 | 值 | 说明 | |------|-----|------| | ToolStatus | `active`, `inactive`, `staging`, `building` | 工具生命周期状态 | | MessageType | `tool_request`, `tool_ready`, `tool_error`, `health_alert` | 内部消息类型 | | ContainerStatus | `running`, `destroyed` | 容器状态 | | SourceType | `local`, `docker`, `remote` | 工具来源类型(后端执行环境) | | ProcessState | `stopped`, `starting`, `running`, `error` | 进程运行状态 | ### 1.2 ToolMeta(工具元信息) ```json { "tool_id": "image_compress_api", "name": "图片压缩 API", "category": "cv", "description": "基于 PIL 的图片压缩服务", "input_schema": { "type": "object", "properties": { "image_path": {"type": "string"}, "quality": {"type": "integer", "minimum": 1, "maximum": 100} }, "required": ["image_path"] }, "output_schema": { "type": "object", "properties": { "compressed_size": {"type": "integer"}, "compression_ratio": {"type": "number"} } }, "stream_support": false, "status": "active" } ``` ### 1.3 ToolSource(工具来源) ```json { "type": "local", "host_dir": "tools/local/image_compress_api", "endpoint_path": "/", "http_method": "POST", "internal_port": 0 } ``` Docker 类型: ```json { "type": "docker", "container_id": "25e884ca6cec...", "image": "ubuntu:22.04", "internal_port": 8080, "endpoint_path": "/api/compress", "http_method": "POST" } ``` Hub 类型(外部 API): ```json { "type": "remote", "remote_url": "https://api.example.com", "remote_path": "/v1/compress", "remote_api_key": "sk-***", "endpoint_path": "/v1/compress", "http_method": "POST" } ``` ### 1.4 ToolRoute(运行状态) ```json { "tool_id": "image_compress_api", "sources": [ {"type": "local", "host_dir": "tools/local/image_compress_api"} ], "active_source": 0, "state": "running", "pid": 12345, "port": 52341, "started_at": "2026-03-26T10:30:00Z", "last_error": null } ``` ### 1.5 ContainerInfo(容器信息) ```json { "container_id": "25e884ca6cecfa87e19ea737315a8773d...", "tool_id": "test_git_tool", "image": "ubuntu:22.04", "port_mapping": {"8080": 9001, "3306": 9002}, "volumes": {"C:/staging/project": "/app"}, "mem_limit": "1g", "nano_cpus": 1000000000, "use_gpu": false, "gpu_count": -1, "status": "running", "created_at": "2026-03-20T07:31:50.421101Z", "last_accessed": "2026-03-20T07:33:16.214642+00:00", "destroyed_at": null } ``` --- ## 2. 工具注册表格式 (registry.json) 路径:`data/registry.json` ```json { "tools": [ { "tool_id": "image_compress_api", "name": "图片压缩 API", "category": "cv", "description": "基于 PIL 的图片压缩", "input_schema": {}, "output_schema": {}, "stream_support": false, "status": "active" } ], "version": "2.0" } ``` ### Registry 查询接口 **ToolRegistry 类方法**: | 方法 | 参数 | 返回 | |------|------|------| | `get(tool_id)` | tool_id | ToolMeta \| None | | `list_all()` | - | list[ToolMeta] | | `list_active()` | - | list[ToolMeta] | | `find_by_category(category)` | category | list[ToolMeta] | | `search(keyword)` | keyword | list[ToolMeta] | | `register(tool)` | ToolMeta | None | | `unregister(tool_id)` | tool_id | bool | | `destroy(tool_id)` | tool_id | dict(清理结果) | --- ## 3. 来源存储格式 (sources.json) 路径:`data/sources.json` ```json { "sources": { "image_compress_api": [ { "type": "local", "host_dir": "tools/local/image_compress_api", "endpoint_path": "/", "http_method": "POST", "internal_port": 0 } ], "gpu_tool": [ { "type": "docker", "container_id": "abc123...", "internal_port": 8080, "endpoint_path": "/api/run", "http_method": "POST" } ] } } ``` ### SourceStore 接口 | 方法 | 参数 | 返回 | |------|------|------| | `load()` | - | dict[str, list[dict]] | | `save(sources)` | sources | None | | `add_source(tool_id, source)` | tool_id, ToolSource | None | | `get_sources(tool_id)` | tool_id | list[ToolSource] | | `remove_tool(tool_id)` | tool_id | None | --- ## 4. 容器状态表格式 (containers.json) 路径:`data/containers.json` ```json { "containers": [ { "container_id": "25e884ca6cec...", "tool_id": "gpu_tool", "image": "ubuntu:22.04", "port_mapping": {"8080": 9001}, "volumes": {"C:/staging/project": "/app"}, "mem_limit": "1g", "nano_cpus": 1000000000, "use_gpu": false, "status": "running", "created_at": "2026-03-20T07:31:50Z" } ] } ``` --- ## 5. 任务书格式 (task_spec) Router 生成任务书,通过 `asyncio.create_task` 提交给 CodingAgent。 ### 5.1 GitHub 项目接入任务 ```json { "type": "github_deploy", "repo_url": "https://github.com/user/project", "tool_name": "project_api", "runtime": "docker", "description": "将该项目部署为 HTTP API 工具" } ``` ### 5.2 自主编写工具任务 ```json { "type": "build_tool", "tool_name": "text_summarizer_api", "runtime": "uv", "description": "编写一个文本摘要工具,接受文本输入,返回摘要" } ``` ### 5.3 工具修复任务 ```json { "type": "repair_tool", "tool_id": "image_compress_api", "error": "HTTP 503: Service Unavailable", "description": "工具健康检查失败,需要诊断并修复" } ``` --- ## 6. 内部消息格式 (AgentMessage) Router 与 CodingAgent 通过 `MessageBus`(`asyncio.Queue`)通信。 **当前状态**:MessageBus 已实现但未集成,Router 通过直接函数调用启动 CodingAgent。 ```json { "type": "tool_request | tool_ready | tool_error | health_alert", "payload": {} } ``` ### 6.1 tool_request(Router → Coding) ```json { "type": "tool_request", "payload": { "task_spec": "{ /* 任务书 JSON */ }", "task_id": "550e8400-e29b-41d4-a716-446655440000", "description": "需要一个图片压缩工具", "reference_files": ["tools/local/example/main.py"] } } ``` ### 6.2 tool_ready(Coding → Router) ```json { "type": "tool_ready", "payload": { "tool_id": "image_compress_api", "result": "部署成功,工具已注册", "task_id": "550e8400-..." } } ``` ### 6.3 tool_error(Coding → Router) ```json { "type": "tool_error", "payload": { "tool_id": "failed_tool", "error": "依赖安装失败:torch 需要 CUDA 但未检测到 GPU", "task_id": "550e8400-..." } } ``` ### 6.4 health_alert(Router → Coding) ```json { "type": "health_alert", "payload": { "tool_id": "image_compress_api", "error": "HTTP 503", "last_healthy": "2026-03-20T10:00:00Z" } } ``` --- ## 7. 对外 HTTP 接口 基础地址:`http://localhost:8001` ### GET /health ```json // Response {"status": "ok"} ``` ### POST /search_tools 搜索可用工具列表,返回工具信息及运行状态。 ```json // Request { "keyword": "图片", "category": "cv" } // Response { "tools": [ { "tool_id": "image_compress_api", "name": "图片压缩 API", "category": "cv", "description": "基于 PIL 的图片压缩", "params": [ { "name": "image_path", "type": "string", "description": "图片路径", "required": true } ], "required_params": ["image_path"], "input_schema": {}, "output_schema": {}, "backend_runtime": "local", "host_dir": "tools/local/image_compress_api", "endpoint_path": "/", "http_method": "POST", "state": "running", "port": 52341, "pid": 12345 } ], "total": 1 } ``` ### POST /select_tool 选择并调用工具(未启动则自动启动)。 ```json // Request { "tool_id": "image_compress_api", "params": {"image_path": "/path/to/img.jpg", "quality": 85}, "stream": false } // Response { "status": "success", "result": {"compressed_size": 256000, "compression_ratio": 0.25}, "error": null } ``` ### POST /create_tool 提交新工具创建需求(异步)。 ```json // Request { "description": "需要一个图片压缩工具", "task_spec": "详细任务描述..." } // Response { "task_id": "create_a1b2c3d4", "status": "pending", "message": "Task submitted" } ``` ### GET /tasks/{task_id} 查询异步任务状态。 ```json // Response { "task_id": "create_a1b2c3d4", "status": "completed", "result": "工具已成功注册", "task_spec": "..." } ``` ### GET /tools/status 列出所有工具运行状态。 ```json // Response { "tools": [ { "tool_id": "image_compress_api", "sources": [...], "active_source": 0, "state": "running", "pid": 12345, "port": 52341 } ] } ``` ### POST /tools/{tool_id}/start 手动启动工具。 ```json // Response { "tool_id": "image_compress_api", "state": "running", "port": 52341 } ``` ### POST /tools/{tool_id}/stop 手动停止工具。 ```json // Response { "tool_id": "image_compress_api", "state": "stopped" } ``` ### POST /agent/chat 与 Router Agent 对话交互(自然语言)。 **设计理念**:外部 Agent 通过自然语言与 Router 交互,Router 理解意图后返回结构化方案,更加人性化和灵活。 **支持场景**: - 工具发现与推荐 - 工具使用方案指导 - 组合工具使用说明(如 ComfyUI) - 工具创建请求 ```json // Request { "message": "用户的自然语言请求", "context": {} // 可选的上下文信息 } // Response { "reply": "Router 的回复", "tools": [], // 相关工具列表(可选) "solution": {}, // 解决方案(可选) "task_id": "", // 任务 ID(创建工具时) "next_steps": [] // 后续操作建议 } ``` **示例 1:工具发现** ```json // Request { "message": "我需要处理图片的工具", "context": {"task": "批量压缩图片"} } // Response { "reply": "找到 2 个图片处理工具,推荐使用 image_compress_api", "tools": [ { "tool_id": "image_compress_api", "name": "图片压缩 API", "reason": "专门用于图片压缩,支持质量调节", "usage_example": { "params": {"image_path": "/path/to/image.jpg", "quality": 85} } } ], "next_steps": ["调用 /select_tool 使用该工具"] } ``` **示例 2:ComfyUI 工具使用指导** ```json // Request { "message": "如何使用 ComfyUI 的 LoadImage 和 SaveImage 节点?" } // Response { "reply": "ComfyUI 节点已通过 runcomfy 工具接入,需要三步操作", "solution": { "type": "composite_workflow", "base_tools": ["runcomfy_launch_env", "runcomfy_run_only", "runcomfy_stop_env"], "steps": [ { "step": 1, "action": "启动环境", "tool": "runcomfy_launch_env", "params": {}, "returns": "container_id" }, { "step": 2, "action": "执行 workflow", "tool": "runcomfy_run_only", "params": { "container_id": "", "workflow": { "nodes": [ {"id": 1, "type": "LoadImage", "inputs": {"image": "input.png"}}, {"id": 2, "type": "SaveImage", "inputs": {"images": ["1", 0]}} ] } } }, { "step": 3, "action": "清理环境", "tool": "runcomfy_stop_env", "params": {"container_id": ""} } ] } } ``` **示例 3:工具创建** ```json // Request { "message": "帮我创建一个文本摘要工具", "context": {"requirements": "支持中英文,最大长度 500 字"} } // Response { "reply": "已提交工具创建任务,预计 2-3 分钟完成", "task_id": "create_a1b2c3d4", "status": "pending", "tracking": "使用 GET /tasks/create_a1b2c3d4 查询进度", "estimated_time": "2-3 分钟" } ``` --- ## 8. Coding Agent 工具接口 CodingAgent 通过 `claude_agent_sdk` 暴露以下 10 个工具: ### Docker 环境 | 工具 | 必填参数 | 可选参数 | 返回 | |------|----------|----------|------| | `create_docker_env` | `image` | `mem_limit`, `nano_cpus`, `ports`, `volumes`, `use_gpu` | `container_id`, `port_mapping` | | `run_in_docker` | `container_id`, `command` | `is_background`, `timeout` | `exit_code`, `stdout`, `stderr` 或 `log_file` | | `rebuild_docker_ports` | `container_id`, `ports` | `mem_limit`, `nano_cpus` | `new_container_id`, `port_mapping` | | `destroy_docker_env` | `container_id` | — | `status`, `message` | ### 本地 uv 环境 | 工具 | 必填参数 | 可选参数 | 返回 | |------|----------|----------|------| | `create_uv_project` | `name` | `python_version` | `project_dir` | | `run_in_uv` | `project_dir`, `command` | `is_background`, `timeout` | `exit_code`, `stdout`, `stderr` | | `uv_add_dependency` | `project_dir`, `package` | `dev` | `status`, `message` | ### 文件操作 | 工具 | 必填参数 | 返回 | |------|----------|------| | `write_file` | `path`, `content` | `status`, `path`, `size` | | `read_file` | `path` | `status`, `path`, `content` | ### 注册 | 工具 | 必填参数 | 可选参数 | 返回 | |------|----------|----------|------| | `register_tool` | `tool_id`, `name`, `description`, `runtime_type`, `internal_port` | `category`, `input_schema`, `output_schema`, `container_id`, `host_dir`, `endpoint_path`, `http_method`, `group_ids` | `status`, `tool_id`, `backend_runtime`, `message` | --- ## 9. 配置参数 ### Settings(环境变量前缀:`TOOL_AGENT_`) | 参数 | 类型 | 默认值 | 说明 | |------|------|--------|------| | `fastapi_port` | int | `8001` | 对外 HTTP 端口 | | `mcp_port` | int | `8001` | MCP Server 端口 | | `docker_port_start` | int | `9001` | Docker 端口起始 | | `docker_base_image` | str | `"agent-sandbox:latest"` | 默认基础镜像 | | `docker_mem_limit` | str | `"1g"` | 默认容器内存 | | `docker_nano_cpus` | int | `1000000000` | 默认 CPU(1 核) | | `docker_ttl_seconds` | int | `1800` | 容器自动清理 TTL | | `cold_tool_idle_timeout_s` | int | `300` | 冷工具空闲超时 | | `hot_tool_max_containers` | int | `5` | 最大热工具容器数 | | `eviction_policy` | str | `"lru"` | 置换策略 | | `monthly_limit_usd` | float | `100.0` | 月预算上限 | | `single_tx_limit_usd` | float | `20.0` | 单笔上限 | | `require_approval_above_usd` | float | `10.0` | 需审批阈值 | | `health_check_interval_s` | int | `60` | 健康检查间隔 | --- ## 10. Router 工具匹配与对接 ### 10.1 职责 Router 负责与外部 Agent 对话,将自身工具库与外部工具表进行匹配和对接。 ### 10.2 工具匹配策略 当外部 Agent 请求工具时,Router 执行以下匹配逻辑: ``` 外部 Agent 请求工具 X │ ▼ Router 查询 registry.json │ ├─ 直接匹配:tool_id 或 name 完全匹配 │ → 返回工具信息,调用 /select_tool │ ├─ 模糊匹配:keyword 匹配 description │ → 返回候选列表,由外部 Agent 选择 │ ├─ 组合工具匹配:检测是否为复合工具需求 │ → 例如:ComfyUI 节点工具 │ → 检查是否有基础工具(如 runcomfy) │ → 返回基础工具 + 使用说明 │ └─ 无匹配:返回 404 → 外部 Agent 可选择提交 /create_tool 请求 ``` ### 10.3 ComfyUI 工具对接示例 **场景**:外部 Agent 请求使用 ComfyUI 内部节点(如 `LoadImage`, `SaveImage`) **Router 响应策略**: 1. **检测 ComfyUI 相关关键词**: - 请求中包含 `comfyui`, `workflow`, `node` 等关键词 - 或请求的 tool_id 包含 comfyui 相关命名 2. **查询基础工具**: - 检查 registry 中是否有 `runcomfy` 相关工具 - 例如:`runcomfy_launch_env`, `runcomfy_run_only`, `runcomfy_stop_env` 3. **返回组合工具信息**: ```json { "status": "composite_tool", "message": "ComfyUI 节点工具已通过 runcomfy 基础工具接入", "base_tools": [ { "tool_id": "runcomfy_launch_env", "name": "启动 ComfyUI 环境", "description": "启动 ComfyUI Docker 环境,返回容器 ID 和端口", "usage": "先调用此工具启动环境,获取 container_id" }, { "tool_id": "runcomfy_run_only", "name": "执行 ComfyUI Workflow", "description": "在已启动的环境中执行 workflow JSON", "usage": "传入 workflow JSON 和 container_id,执行节点流程" }, { "tool_id": "runcomfy_stop_env", "name": "停止 ComfyUI 环境", "description": "停止并清理 ComfyUI 容器", "usage": "任务完成后调用,释放资源" } ], "workflow_example": { "description": "使用 LoadImage 和 SaveImage 节点的示例", "steps": [ "1. 调用 runcomfy_launch_env 启动环境", "2. 构造 workflow JSON(包含 LoadImage, SaveImage 节点)", "3. 调用 runcomfy_run_only 执行 workflow", "4. 获取输出结果", "5. 调用 runcomfy_stop_env 清理环境" ], "workflow_json": { "nodes": [ {"id": 1, "type": "LoadImage", "inputs": {"image": "input.png"}}, {"id": 2, "type": "SaveImage", "inputs": {"images": ["1", 0]}} ] } } } ``` ### 10.4 工具对接接口 Router 提供以下内部方法支持工具匹配: | 方法 | 参数 | 返回 | 说明 | |------|------|------|------| | `match_tool(query)` | query: str | ToolMeta \| None | 精确匹配 tool_id 或 name | | `search_tools(keyword, category)` | keyword, category | list[ToolMeta] | 模糊搜索 | | `detect_composite_tool(query)` | query: str | dict \| None | 检测是否为组合工具需求 | | `get_base_tools(composite_type)` | composite_type: str | list[ToolMeta] | 获取基础工具列表 | ### 10.5 扩展:外部工具表对接 **未来规划**:Router 可对接外部工具表(如其他 Agent 系统的工具库) ```json // 外部工具表注册 POST /external_tools/register { "source": "agent_system_x", "tools_url": "https://agent-x.com/api/tools", "api_key": "sk-***" } // Router 查询时同时搜索本地 + 外部工具表 // 返回统一格式的工具列表 ``` --- ## 附录:工作日志格式 ### LocalRunner 命令日志 (last_run.log) 路径:`{project_dir}/last_run.log` ``` Command: python main.py Exit Code: 0 --- STDOUT --- Server started on port 8080 --- STDERR --- WARNING: Using development server ``` ### CodingAgent 执行日志(stdout) ``` 2026-03-26 15:09:32 [tool_agent.tool.agent] INFO: [CodingAgent] Starting task: 部署 flask 项目... 2026-03-26 15:09:35 [tool_agent.tool.agent] INFO: [TOOL_USE] create_docker_env | {"image":"python:3.12-slim","ports":[8080]} 2026-03-26 15:09:40 [tool_agent.tool.agent] INFO: [TEXT] 正在创建 Docker 环境... 2026-03-26 15:10:15 [tool_agent.tool.agent] INFO: [TOOL_USE] register_tool | {"tool_id":"flask_api",...} 2026-03-26 15:10:16 [tool_agent.tool.agent] INFO: [DONE] duration=44000ms 2026-03-26 15:10:16 [tool_agent.tool.agent] INFO: [COST] $0.12 ```