- AI Agent
- 大模型
- 后端
- 任务调度
【免费下载链接】XAgent
An Autonomous LLM Agent for Complex Task Solving
ToolServer 是 XAgent 的工具执行后端:它以 Docker 容器为隔离单元,为 XAgent 的 Agent 提供文件编辑、Python Notebook、网页浏览、Shell 和 Rapid API 五类内置工具,并通过一套 Manager—Monitor—Node 的三级架构管理这些容器实例的生命周期。本文以 ToolServer/README.md 为核心骨架,结合 ToolServer/ToolServerManager/main.py、ToolServer/ToolServerNode/main.py 及 docker-compose.yml 等仓库源码,完整梳理其架构原理、配置文件参数、部署流程与全部 API 端点,读完后可独立部署 ToolServer,并能对照源码理解每一个接口的真实行为。
一、ToolServer 在 XAgent 体系中的定位
对 LLM Agent 而言,"会想"不等于"会做"——执行 Python 代码、访问网页、编辑文件、调用第三方 API 这些动作必须落在一个可控的执行环境中。XAgent 的解决方案就是把所有工具的执行下沉到一个独立的服务端 ToolServer 中,Agent 侧只通过 HTTP 接口与其交互。这样带来两个关键收益:
- 安全隔离:工具在 Docker 容器内运行,Agent 生成的 shell 命令、Python 代码不会直接触碰宿主机;
- 会话化资源管理:每个任务会话独占一个容器实例,用完即关,避免状态互相污染。
从 XAgent 侧的调用链可以印证这一点。XAgentServer 通过环境变量TOOLSERVER_URL指向 ToolServerManager(见 docker-compose.yml 中XAgentServer.environment的- TOOLSERVER_URL=http://ToolServerManager:8080),而 Agent 框架内的 XAgent/toolserver_interface.py 中的ToolServerInterface类负责封装全部交互:lazy_init在初始化时调用/get_cookie领取容器会话,close方法在任务结束时调用/close_session归还资源。可以说 ToolServer 是 XAgent "手和脚"的集中承载者。
二、三大组件:Manager、Monitor 与 Node
ToolServer/README.md 将 ToolServer 划分为三个部分,各自职责与源码对应关系如下:
| 组件 | 职责 | 源码位置 |
|---|---|---|
| ToolServerManager | 创建和管理 ToolServerNode 实例,对外提供统一 API | ToolServer/ToolServerManager/main.py |
| ToolServerMonitor | 监控 Node 状态,自动剔除异常实例 | ToolServer/ToolServerManager/node_checker.py |
| ToolServerNode | 真正提供工具的执行容器 | ToolServer/ToolServerNode/main.py |
2.1 Manager:会话创建与请求路由
Manager 是一个 FastAPI 应用(ToolServer/ToolServerManager/main.py#L16),它本身不执行任何工具,而是承担两件核心工作:
(1)按需创建 Node 容器并下发 cookie。当客户端 POST/get_cookie时,Manager 会:
- 依据
manager.yml中node.creation_kwargs直接调用 Docker SDK 启动一个xagentteam/toolserver-node:latest容器(main.py#L127-L131); - 把容器 ID 写入响应 cookie
node_id,同时把 IP、端口、状态、健康度、最近请求时间等元数据存入 MongoDB(ToolServerNode文档模型见 ToolServer/ToolServerManager/models.py); - 调用
wait_for_node_startup每秒探测一次容器健康状态,直到creation_wait_seconds(默认 30 秒)超时(main.py#L75-L106)。
(2)按 cookie 路由请求到具体 Node。启动时 Manager 会遍历redirect_to_node_path配置,把一批路径动态注册为路由(main.py#L48-L53)。当前 assets/config/manager.yml 中注册的重定向路径包括/、/execute_tool、/get_available_tools、/get_json_schema_for_tools、/get_json_schema_for_envs、/retrieving_tools、/register_new_tool、/upload_file、/download_file、/download_workspace、/get_workspace_structure。每个被重定向的请求都会经过route_to_node(main.py#L228-L269):校验 cookie 中的node_id有效且容器 running → 更新该节点的last_req_time(这个时间戳正是空闲回收的依据)→ 以http://<node_ip>:<port>为目的地转发原始请求。
2.2 Monitor:内嵌于 Manager 的健康巡检循环
README 中描述的独立 "ToolServerMonitor" 组件,在当前实现中是以协程形式内嵌在 Manager 进程里的:main.py的 startup 钩子在builtin_monitor: true时启动check_nodes_status_loop异步任务(main.py#L31-L45)。巡检循环每health_check_interval(默认 1 秒)执行一次check_nodes_status(node_checker.py#L11-L54),做三件事:
- 对账:数据库中每个节点都去 Docker 侧核实,容器已不存在的节点直接从数据库删除;
- 同步状态:把容器的
State.Status与健康检查状态回写到数据库; - 空闲回收:若节点 running 且
last_req_time距现在超过idling_close_minutes(默认 30 分钟),执行container.stop()(node_checker.py#L51-L54)——这就是 README 提到的"idle 后自动关闭 Node 实例"的具体实现。
此外,NodeChecker文档模型会记录当前 Manager 的 pid,Manager 重启时可据此清理残留巡检任务,保证同一套数据库下巡检循环不会重复运行。
2.3 Node:工具注册与执行环境
Node 容器启动时(ToolServer/ToolServerNode/main.py#L22-L33)会:
- 尝试启动容器内的 docker 服务(
service docker start,配合privileged: true,使 Node 内部也能再跑容器); - 实例化
ToolRegister(位于 ToolServer/ToolServerNode/core/register/register.py),加载全部已注册工具与环境; - 调用
build_tool_embeddings基于 ToolServer/ToolServerNode/assets/doc_embeding.npy 预构建工具文档的向量索引,供/retrieving_tools做相似度检索。
内置工具按"环境(env)"组织,对应 ToolServer/ToolServerNode/core/envs/ 下的filesystem.py(文件编辑)、pycoding.py(Python 代码执行)、web.py(网页浏览),扩展工具如 ToolServer/ToolServerNode/extensions/envs/rapidapi.py、ToolServer/ToolServerNode/extensions/envs/shell.py 等。README 列出的五类工具与配置项的对应关系:
| 工具 | 能力 | 关键配置(node.yml) |
|---|---|---|
| 文档编辑器 | 读写、修改工作目录中的文件 | filesystem.work_directory: /app/workspace/、filesystem.ignored_list(过滤.git、node_modules、site-packages等目录) |
| Python Notebook | 执行 Python 代码、验证想法、绘图 | notebook.timeout: 300、notebook.save_name: python_notebook.ipynb |
| 网页浏览器 | 搜索并访问网页(headless Chrome) | web.browser、web.headless、bing.api_key(留空则退回备用搜索 DuckDuckGo) |
| Shell | 执行任意 shell 命令、安装程序、托管服务 | shell.timeout: 300 |
| Rapid API | 检索并调用 Rapid API 工具集中的 API | rapidapi.api_key、rapidapi.endpoint,依赖 ToolServer/ToolServerNode/assets/rapidapi_high_quality_apis.json 等资产文件 |
如需开发新工具,仓库提供了完整指南 ToolServer/ToolServerNode/assets/HOW_TO_BUILD_NEW_TOOLS_CN.md,且 Node 端还暴露了/register_new_tool接口支持运行时动态注册(ToolServer/ToolServerNode/main.py#L226-L249)。
三、配置详解:assets/config/ 下的三个关键文件
ToolServer/README.md 指出配置统一存放在assets/config/,修改后需重启 ToolServer 生效。docker-compose.yml将宿主机./assets/config以 bind 方式挂载到命名卷toolserverconfig,并映射进 Manager 与 Node 两个容器的/app/assets/config,因此改宿主机配置即可同时生效于所有新建容器,无需重新构建镜像。
3.1 manager.yml:Manager 与 Node 的创建策略
assets/config/manager.yml 的关键项:
builtin_monitor: True # 是否在 Manager 进程内运行节点巡检循环 node: creation_wait_seconds: 30 # /get_cookie 时等待节点就绪的最长秒数(探测间隔 1s) idling_close_minutes: 30 # 空闲多少分钟后 Monitor 自动 stop 该容器 health_check: true # 是否启用 docker healthcheck 判定节点可用性 health_check_interval: 1 # 巡检循环轮询间隔(秒) port: 31942 # Node 内部 FastAPI 服务端口 creation_kwargs: # 传给 docker.containers.run() 的完整参数 image: "xagentteam/toolserver-node:latest" network: "tool-server-network" privileged: true # 置 false 可禁止 Node 内使用 docker detach: true volumes: - "toolserverconfig:/app/assets/config" healthcheck: test: ["CMD", "bash", "-c", "curl -f -sS 'http://localhost:31942/' > /dev/null || exit 1"] interval: 1000000000 # 纳秒,1s timeout: 3000000000 retries: 3 redirect_to_node_path: # 哪些路径由 Manager 透传给 Node post: [/execute_tool, /get_available_tools, ...] get: [/]README 特别强调:若不希望 XAgent 在 ToolServerNode 内再使用 docker(例如限制其安装程序、托管服务的能力),将node.privileged改为false。因为 Node 启动时会执行service docker start,而 dockerd 在非特权容器中无法运行,工具注册阶段会相应降级。
3.2 node.yml:Node 侧工具行为参数
assets/config/node.yml 控制 Node 内各工具的运行时行为,除上表外还有几处值得注意:
retriver段定义了工具检索的 embedding 端点(text-embedding-ada-002、维度 1536)以及预置向量文件embedding_file、id2tool_file——/retrieving_tools的相似度计算正是基于这份离线向量 ToolServer/ToolServerNode/assets/doc2tool.json;toolregister.env_max_tools_display: 10对应 README 中"available_envs的 tools 列表最多返回 50 条/每环境展示上限"类截断逻辑(ToolServer/ToolServerNode/core/register/register.py 中的展示数量控制);enabled_extensions段通过模块路径动态启用扩展工具,例如取消注释extensions.envs.rapidapi即加载 Rapid API 环境。
README 提醒:要在node.yml中填入bing.api_key启用必应搜索(不填则走备用搜索 DuckDuckGo),填入rapidapi.api_key与rapidapi.endpoint启用 Rapid API。
3.3 docker-compose.yml:超时与网络
README 提到遇到 ToolServer 超时应调整docker-compose.yml中services.ToolServerManager.command里-t后的值。在当前 docker-compose.yml 中该值为:
command: ["--workers","2","-t","600"]即 Manager 以 gunicorn 2 个 worker 启动,请求超时设为 600 秒。由于 Shell、Notebook 等工具本身允许 300 秒的执行超时,且 Agent 任务链可能串联多次工具调用,遇到长任务超时时可调大该值。另外注意 Manager 容器挂载了/var/run/docker.sock——这是它能以 Python SDK 直接创建、停止、删除 Node 容器的前提。
四、构建与启动
前置条件是宿主机安装docker与docker-compose。两种启动方式(摘自 ToolServer/README.md):
# 方式一:直接拉取官方镜像启动 docker compose up # 方式二:先自行构建镜像再启动 docker compose build docker compose updocker compose build会使用仓库内 dockerfiles/ToolServerManager/Dockerfile 与 dockerfiles/ToolServerNode/Dockerfile 构建xagentteam/toolserver-manager:latest与xagentteam/toolserver-node:latest。完整的 docker-compose.yml 还会同时拉起db(MongoDB,供 Manager 存节点元数据)、XAgentServer、xagent-mysql、xagent-redis等服务,构成完整的 XAgent 服务栈;若只关心 ToolServer,可单独运行其中的ToolServerManager与db服务。所有容器通过名为tool-server-network的 bridge 网络互通(manager.yml中creation_kwargs.network与 compose 的networks.default.name均指向它),Manager 正是靠这个网络拿到 Node 的 IP 进行转发。
五、API 完整说明
以下端点说明基于 ToolServer/README.md 的 API 章节,并校正/补全了源码中的真实参数名与行为细节。所有请求都发往 Manager 的 8080 端口,Manager 再把工具类请求透传给 cookie 绑定的 Node。
提示:README 中写作
/get_cookies,实际源码注册的端点为/get_cookie(ToolServer/ToolServerManager/main.py#L108,XAgent 客户端同样调用/get_cookie,见 XAgent/toolserver_interface.py#L94-L95)。
5.1 /get_cookie:建立会话
POST 请求,无参数。Manager 立即创建一个新的 Node 容器,返回消息与版本号,并把node_idcookie 写入响应。此后所有工具请求都必须携带该 cookie,Manager 据此定位目标 Node;cookie 无效会返回 403,Node 非 running 返回 503(main.py#L243-L248)。若creation_wait_seconds内容器未就绪,返回 503 "Node creation timeout!"。
5.2 /get_available_tools:获取全部工具
无需参数,返回三段信息(实现见 ToolServer/ToolServerNode/main.py#L127-L140):
{ "available_envs": [ { "name": "env1", "description": "description1", "tools": ["tool1", "tool2"] } ], "available_tools": ["tool1", "tool2"], "tools_json": [ { "name": "tool1", "description": "description1", "parameters": { "type": "object", "properties": { "param1": { "type": "string", "description": "description1" }, "param2": { "type": "integer", "description": "description2" } }, "required": ["param1", "param2"] } } ] }注意两点截断策略:available_envs中每个环境列出的工具数量受node.yml的toolregister.env_max_tools_display限制(README 标注上限 50);available_tools不包含被标记为隐藏的内部工具(如ShellEnv_read_stdout这类用于 450 重试的内部工具)。
5.3 /retrieving_tools:按问题检索工具
给定问题,返回语义最相关的 top_k 个工具(实现见 ToolServer/ToolServerNode/main.py#L142-L173)。请求体:
{ "question": "question", "top_k": 10 }top_k在源码中的默认值为 5。返回:
{ "retrieved_tools": ["tool1", "tool2"], "tools_json": [ { "name": "tool1", "description": "...", "parameters": { } } ] }从源码结构看,检索走ada_retriever(ToolServer/ToolServerNode/utils/retriever.py):用预构建的doc_embeding.npy向量与doc2tool.json的 id2tool 映射做相似度排序;若 Rapid API 扩展已启用,其 API 同样参与检索结果。
5.4 /get_json_schema_for_tools 与 /get_json_schema_for_envs:按名取 schema
两个端点用于"指名道姓"地获取工具/环境的 JSON schema(实现分别见 main.py#L176-L199 与 main.py#L201-L224)。源码中的参数名是tool_names与env_names:
{ "tool_names": ["tool1", "tool2"] }{ "env_names": ["env1", "env2"] }返回结构一致地分为"命中的部分 + 缺失列表",便于 Agent 感知自己拼错或引用了不存在的名字:
{ "tools_json": [ { "name": "tool1", "description": "...", "parameters": {} } ], "missing_tools": ["tool3"] }{ "envs_json": [ { "name": "env1", "description": "description1", "tools": ["tool1", "tool2"] } ], "missing_envs": ["env3"] }5.5 /execute_tool:执行工具与 450 异步重试协议
执行指定工具,源码参数名为tool_name与arguments(另可选env_name指定在哪个环境中执行同名工具)(main.py#L251-L289):
{ "tool_name": "tool1", "arguments": { "param1": "value1", "param2": "value2" } }成功时返回体由wrap_tool_response统一包装为type: simple / composite / binary三种形态之一(XAgent 侧的unwrap_tool_response会拆包,binary 数据落地到local_workspace,见 XAgent/toolserver_interface.py#L29-L66)。
450 状态码是 ToolServer 最有特色的协议:它表示"工具尚未执行完毕,需要后续调用才能拿到完整结果"(典型场景是 Shell 里启动了长时命令,需要先读 stdout)。触发链路是:工具抛出OutputNotReady异常 → Node 将其转为 450 响应(main.py#L280-L281)。响应体示例(README 原样保留):
{ "detail": { "type": "retry", "next_calling": "ShellEnv_read_stdout", "arguments": {} } }next_calling指明下一次应调用的工具名,Agent 按其指引再次 POST/execute_tool直至拿到最终输出。这套"可中断-可续跑"的协议让 ToolServer 能够承载超出一对请求/响应模型的长耗时操作。
5.6 /close_session 与 /release_session:归还与销毁会话
任务结束时 XAgent 客户端会调用/close_session(XAgent/toolserver_interface.py#L97-L101):
- /close_session(main.py#L181-L200):Manager 获取容器并
stop(),容器停止但保留,理论上可通过/reconnect_session重启续用(main.py#L152-L179); - /release_session(main.py#L202-L226):
kill()容器后remove()彻底删除,并释放其占用的数据库记录。
这两个端点体现了 ToolServer 的会话资源语义:close 是"暂停",release 是"销毁"。此外即使客户端不调用,Monitor 的空闲回收(idling_close_minutes)也会兜底关闭长期无请求的节点。
六、小结:把 XAgent 接入 ToolServer 的最小路径
综合以上各节,一条可落地的接入路线是:
docker compose up启动全栈,Manager 监听宿主机 8080 端口(docker-compose.yml 的ports: 8080:8080);- 按需在 assets/config/node.yml 填入
bing.api_key、rapidapi.api_key,按需在 assets/config/manager.yml 调整node.privileged与idling_close_minutes,重启生效; - XAgent 侧配置
TOOLSERVER_URL(或本地运行时use_selfhost_toolserver对应的 URL),ToolServerInterface会自动完成/get_cookie→ 工具调用 →/close_session的完整会话; - 遇到长任务超时,优先调大
docker-compose.yml中-t值与notebook.timeout/shell.timeout,并注意 450 重试协议需要 Agent 侧按next_calling指引继续调用。
这样,ToolServer 便成为 XAgent 可水平扩展、可安全销毁、可动态检索增强的工具执行底座;而 ToolServer/ToolServerNode/assets/HOW_TO_BUILD_NEW_TOOLS_CN.md 中的新工具开发指南,则是继续扩充这份工具清单的入口。
- AI Agent
- 大模型
- 后端
- 任务调度
【免费下载链接】XAgent
An Autonomous LLM Agent for Complex Task Solving
相关推荐
XAgent 自主 LLM 代理实战指南:Dispatcher-Planner-Actor 架构、ToolServer 安全沙箱与完整部署流程
XAgent 自主 LLM 代理实战指南:Dispatcher Planner Actor 架构、ToolServer 安全沙箱与完整部署流程 本文以 XAge
AI Agent大模型后端任务调度CARLA Traffic Manager 完全指南:架构解析、Python API 配置与多实例部署实战
CARLA Traffic Manager 完全指南:架构解析、Python API 配置与多实例部署实战 导读 Traffic Manager(以下简称 TM
自动驾驶科研仿真Node Exporter 完整指南:安装部署、Collector 架构与高级配置实战
Node Exporter 完整指南:安装部署、Collector 架构与高级配置实战 Prometheus Node Exporter 是一个用 Go 编写、
可观测性指标监控运维
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考