TOOL_USAGE_GUIDE.md 18 KB

工具使用完整流程指南

本文档详细说明如何使用 Tool Agent 系统中的工具,从工具注册到实际调用的完整流程。

目录


系统架构概览

┌─────────────────────────────────────────────────────────────┐
│                         用户/客户端                           │
└────────────────────┬────────────────────────────────────────┘
                     │
                     │ HTTP Request
                     ▼
┌─────────────────────────────────────────────────────────────┐
│                    Router (FastAPI)                          │
│                   端口: 8001 (默认)                          │
│  ┌──────────────────────────────────────────────────────┐  │
│  │  API 端点:                                            │  │
│  │  • GET  /health      - 健康检查                      │  │
│  │  • GET  /tools       - 查看工具列表                  │  │
│  │  • POST /run_tool    - 调用工具                      │  │
│  │  • POST /chat        - ServiceAgent对话              │  │
│  └──────────────────────────────────────────────────────┘  │
│                                                              │
│  ┌──────────────┐  ┌──────────────┐  ┌─────────────────┐  │
│  │  Registry    │  │   Status     │  │   Dispatcher    │  │
│  │  工具注册表   │  │   Manager    │  │   请求分发器     │  │
│  └──────────────┘  └──────────────┘  └─────────────────┘  │
└────────────────────┬────────────────────────────────────────┘
                     │
                     │ HTTP 调用
                     ▼
┌─────────────────────────────────────────────────────────────┐
│                      工具实例层                              │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐     │
│  │ Local Tool   │  │ Docker Tool  │  │ Remote API   │     │
│  │ (uv环境)     │  │ (容器)       │  │ (云端服务)    │     │
│  │ 端口: 8001+  │  │ 端口: 映射   │  │ 端口: 外部   │     │
│  └──────────────┘  └──────────────┘  └──────────────┘     │
└─────────────────────────────────────────────────────────────┘

工具使用流程

流程1: 查看可用工具

用户
  │
  │ 1. GET /tools
  ▼
Router
  │
  │ 2. 读取 registry.json
  ▼
返回工具列表
  │
  │ 包含:
  │ • 工具ID、名称、描述
  │ • 输入/输出Schema
  │ • 运行状态 (active/stopped)
  │ • 后端类型 (local/docker/remote)
  ▼
用户选择工具

流程2: 调用工具 (完整流程)

┌─────────┐
│  用户    │
└────┬────┘
     │
     │ 1. 准备调用参数
     │    {
     │      "tool_id": "image_stitcher",
     │      "params": {
     │        "images": ["base64...", "base64..."],
     │        "direction": "horizontal"
     │      }
     │    }
     ▼
┌──────────────────────────────────────────┐
│  POST /run_tool                          │
│  Router 接收请求                          │
└────┬─────────────────────────────────────┘
     │
     │ 2. 查找工具元数据
     ▼
┌──────────────────────────────────────────┐
│  ToolRegistry.get(tool_id)               │
│  • 验证工具是否存在                       │
│  • 获取 input_schema                     │
│  • 获取 backend_runtime                  │
└────┬─────────────────────────────────────┘
     │
     │ 3. 检查工具状态
     ▼
┌──────────────────────────────────────────┐
│  ToolStatusManager.get_active_endpoint() │
│  • 检查工具是否运行中                     │
│  • 获取端点URL和端口                      │
│  • 获取HTTP方法 (POST/GET)               │
└────┬─────────────────────────────────────┘
     │
     │ 4. 如果工具未运行,自动启动
     ▼
┌──────────────────────────────────────────┐
│  ToolStatusManager.start_tool()          │
│  • Local: uv run main.py --port {port}  │
│  • Docker: docker start {container_id}  │
│  • Remote: 无需启动                      │
└────┬─────────────────────────────────────┘
     │
     │ 5. 分发请求到工具实例
     ▼
┌──────────────────────────────────────────┐
│  Dispatcher.dispatch()                   │
│  • 构造HTTP请求                          │
│  • 添加认证头 (如需要)                   │
│  • 发送到工具端点                        │
│    http://localhost:{port}/{endpoint}    │
└────┬─────────────────────────────────────┘
     │
     │ 6. 工具处理请求
     ▼
┌──────────────────────────────────────────┐
│  Tool Instance (FastAPI)                 │
│  • 参数验证 (Pydantic)                   │
│  • 执行业务逻辑                          │
│  • 返回结果                              │
└────┬─────────────────────────────────────┘
     │
     │ 7. 返回结果给用户
     ▼
┌──────────────────────────────────────────┐
│  Response                                │
│  {                                       │
│    "status": "success",                  │
│    "result": {                           │
│      "image": "base64...",               │
│      "width": 1024,                      │
│      "height": 512                       │
│    }                                     │
│  }                                       │
└──────────────────────────────────────────┘

流程3: 通过 ServiceAgent 对话调用工具

用户
  │
  │ 1. POST /chat
  │    {
  │      "message": "帮我把这两张图片横向拼接",
  │      "chat_id": "user_123"
  │    }
  ▼
Router
  │
  │ 2. 转发到 SessionManager
  ▼
ServiceAgent
  │
  │ 3. 理解用户意图
  │    • 解析需求: 图片拼接
  │    • 搜索工具: search_tools("图片拼接")
  ▼
  │ 4. 找到匹配工具
  │    • tool_id: image_stitcher
  │    • 确认参数需求
  ▼
  │ 5. 调用工具
  │    submit_task() 或 直接调用 /run_tool
  ▼
Router
  │
  │ 6. 执行工具调用 (同流程2)
  ▼
ServiceAgent
  │
  │ 7. 格式化结果返回用户
  ▼
用户收到结果

API接口说明

1. GET /health

功能: 健康检查

请求: 无参数

响应:

{
  "status": "ok"
}

2. GET /tools

功能: 获取完整工具列表

请求: 无参数

响应:

{
  "backend_runtimes": [
    {
      "backend_runtime": "local",
      "name": "本地 Python 运行时",
      "description": "使用 uv 管理的本地 Python 进程"
    },
    {
      "backend_runtime": "docker",
      "name": "Docker 容器运行时",
      "description": "运行在 Docker 容器中"
    },
    {
      "backend_runtime": "remote",
      "name": "远程 API / 云端服务",
      "description": "调用外部 API"
    }
  ],
  "groups": [
    {
      "group_id": "runcomfy_lifecycle",
      "name": "ComfyUI 生命周期管理",
      "description": "启动、执行、停止 ComfyUI 环境",
      "backend_runtime": "remote",
      "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": "图片拼接工具",
      "description": "将多张图片拼接成一张",
      "category": "cv",
      "backend_runtime": "local",
      "group_ids": [],
      "input_schema": { ... },
      "output_schema": { ... },
      "state": "running",
      "port": 8001
    }
  ],
  "total": 5
}

字段说明:

  • backend_runtimes: 后端运行环境分类
  • groups: 工具组 (相关工具的集合)
  • tools: 所有已注册工具
    • state: 工具状态 (running / stopped)
    • port: 工具运行端口 (如果正在运行)

3. POST /run_tool

功能: 调用指定工具

请求:

{
  "tool_id": "image_stitcher",
  "params": {
    "images": ["base64_image_1", "base64_image_2"],
    "direction": "horizontal",
    "spacing": 10
  }
}

响应 (成功):

{
  "status": "success",
  "result": {
    "image": "base64_result_image",
    "width": 1024,
    "height": 512
  },
  "error": null
}

响应 (失败):

{
  "status": "error",
  "result": null,
  "error": "Tool 'xxx' is not running or has no active endpoint"
}

4. POST /chat

功能: 与 ServiceAgent 对话

请求:

{
  "message": "帮我生成一张猫的图片",
  "chat_id": "user_123_session_1"
}

响应:

{
  "response": "好的,我使用 LibLib ControlNet 工具为您生成图片...",
  "chat_id": "user_123_session_1"
}

说明:

  • chat_id: 每个对话窗口的唯一标识,用于保持上下文
  • ServiceAgent 会自动搜索和调用合适的工具

使用示例

示例1: Python 客户端调用

import httpx
import base64

# 1. 查看可用工具
async with httpx.AsyncClient() as client:
    response = await client.get("http://localhost:8001/tools")
    tools = response.json()
    print(f"可用工具: {len(tools['tools'])}个")

# 2. 准备图片数据
with open("image1.png", "rb") as f:
    img1_b64 = base64.b64encode(f.read()).decode()
with open("image2.png", "rb") as f:
    img2_b64 = base64.b64encode(f.read()).decode()

# 3. 调用图片拼接工具
async with httpx.AsyncClient(timeout=60.0) as client:
    response = await client.post(
        "http://localhost:8001/run_tool",
        json={
            "tool_id": "image_stitcher",
            "params": {
                "images": [img1_b64, img2_b64],
                "direction": "horizontal",
                "spacing": 20,
                "background_color": "#FFFFFF"
            }
        }
    )
    result = response.json()

    if result["status"] == "success":
        # 保存结果
        result_img = base64.b64decode(result["result"]["image"])
        with open("result.png", "wb") as f:
            f.write(result_img)
        print(f"拼接完成! 尺寸: {result['result']['width']}x{result['result']['height']}")
    else:
        print(f"错误: {result['error']}")

示例2: curl 命令行调用

# 1. 查看工具列表
curl http://localhost:8001/tools | jq '.tools[] | {tool_id, name, state}'

# 2. 调用工具
curl -X POST http://localhost:8001/run_tool \
  -H "Content-Type: application/json" \
  -d '{
    "tool_id": "image_stitcher",
    "params": {
      "images": ["'$(base64 -w0 image1.png)'", "'$(base64 -w0 image2.png)'"],
      "direction": "horizontal"
    }
  }' | jq '.result.image' -r | base64 -d > result.png

示例3: 通过 ServiceAgent 对话

import httpx

async with httpx.AsyncClient() as client:
    # 创建对话
    response = await client.post(
        "http://localhost:8001/chat",
        json={
            "message": "帮我把两张图片横向拼接,间距10像素",
            "chat_id": "my_session_001"
        }
    )
    print(response.json()["response"])

    # 继续对话 (保持上下文)
    response = await client.post(
        "http://localhost:8001/chat",
        json={
            "message": "改成垂直拼接",
            "chat_id": "my_session_001"  # 同一个 chat_id
        }
    )
    print(response.json()["response"])

工具状态管理

工具状态生命周期

┌──────────┐
│ INACTIVE │  工具已注册但未启动
└────┬─────┘
     │
     │ start_tool()
     ▼
┌──────────┐
│ STARTING │  正在启动中
└────┬─────┘
     │
     │ 健康检查通过
     ▼
┌──────────┐
│  ACTIVE  │  工具运行中,可接受请求
└────┬─────┘
     │
     │ stop_tool() 或 超时无请求
     ▼
┌──────────┐
│ STOPPED  │  工具已停止
└──────────┘

自动启动机制

当调用 /run_tool 时:

  1. 检查状态: 如果工具状态为 stoppedinactive
  2. 自动启动:
    • Local: 执行 uv run main.py --port {port} (后台进程)
    • Docker: 执行 docker start {container_id}
    • Remote: 无需启动
  3. 健康检查: 轮询 GET /health 直到返回 {"status": "ok"}
  4. 更新状态: 标记为 running
  5. 执行请求: 转发用户请求到工具端点

端口分配规则

  • Router: 8001 (默认)
  • Local工具: 8002, 8003, 8004... (自动递增)
  • Docker工具: 容器内部端口映射到宿主机
  • Remote工具: 使用外部API的端口

工具调用流程总结

直接调用 (适合程序化调用)

用户 → POST /run_tool → Router → Dispatcher → Tool Instance → 返回结果

优点:

  • 快速、直接
  • 完全控制参数
  • 适合自动化脚本

缺点:

  • 需要了解工具的 input_schema
  • 需要手动处理错误

通过 ServiceAgent 调用 (适合自然语言交互)

用户 → POST /chat → ServiceAgent → 搜索工具 → 调用工具 → 格式化结果 → 返回用户

优点:

  • 自然语言交互
  • 自动选择合适工具
  • 智能参数推断
  • 友好的错误提示

缺点:

  • 响应稍慢 (需要LLM推理)
  • 可能需要多轮对话确认参数

常见问题

Q1: 工具调用失败,提示 "Tool is not running"?

A: 工具可能未启动。解决方法:

  1. 检查工具状态: GET /tools
  2. 手动启动工具 (如果自动启动失败):

    cd tools/local/{tool_id}
    uv run main.py --port 8002
    
    1. 检查端口是否被占用

    Q2: 如何查看工具的输入参数要求?

    A: 调用 GET /tools,查看返回的 input_schema 字段:

    tools = requests.get("http://localhost:8001/tools").json()
    tool = next(t for t in tools["tools"] if t["tool_id"] == "image_stitcher")
    print(tool["input_schema"])
    

Q3: 可以同时调用多个工具吗?

A: 可以。每个工具运行在独立端口,支持并发调用:

import asyncio

async def call_tool(tool_id, params):
    async with httpx.AsyncClient() as client:
        return await client.post(
            "http://localhost:8001/run_tool",
            json={"tool_id": tool_id, "params": params}
        )

# 并发调用
results = await asyncio.gather(
    call_tool("image_stitcher", {...}),
    call_tool("liblibai_controlnet", {...})
)

Q4: 工具调用超时怎么办?

A:

  1. 检查工具日志: tools/local/{tool_id}/tests/last_run.log
  2. 增加超时时间 (Dispatcher 默认 600秒)
  3. 优化工具性能或使用异步处理

下一步