定制功能
如何自行定义参数、流程和工具。
Categories:
添加工具与 MCP Server 工具
面向可修改本仓库代码的高级用户,以下说明如何:
- 添加一个新工具(供本地/Agent 内调用)
- 将工具暴露为 MCP Server 工具(供外部 IDE/客户端调用)
- 控制选择哪些工具被暴露与如何调用
涉及关键位置:
vagent/tools/uctool.py
:工具基类 UCTool、to_fastmcp(LangChain Tool → FastMCP Tool)vagent/util/functions.py
:import_and_instance_tools
(按名称导入实例)、create_verify_mcps
(启动 FastMCP)vagent/verify_agent.py
:装配工具清单,start_mcps
组合并启动 Servervagent/cli.py
/vagent/verify_pdb.py
:命令行与 TUI 内的 MCP 启动命令
1) 工具体系与装配
- 工具基类 UCTool:
- 继承 LangChain BaseTool,内置:call_count 计数、call_time_out 超时、流式/阻塞提示、MCP Context 注入(ctx.info)、防重入等。
- 推荐自定义工具继承 UCTool,获得更好的 MCP 行为与调试体验。
- 运行期装配(VerifyAgent 初始化):
- 基础工具:RoleInfo、ReadTextFile
- 嵌入工具:参考检索与记忆(除非
--no-embed-tools
) - 文件工具:读/写/查找/路径等(可在 MCP 无文件工具模式下剔除)
- 阶段工具:由 StageManager 按工作流动态提供
- 外部工具:来自配置项
ex_tools
与 CLI--ex-tools
(通过import_and_instance_tools
零参实例化)
- 名称解析:
- 短名:类/工厂函数需在
vagent/tools/__init__.py
导出(例如from .mytool import HelloTool
),即可在ex_tools
写HelloTool
- 全路径:
mypkg.mytools.HelloTool
/mypkg.mytools.Factory
- 短名:类/工厂函数需在
2) 添加一个新工具(本地/Agent 内)
规范要求:
- 唯一 name、清晰 description
- 使用 pydantic BaseModel 定义 args_schema(MCP 转换依赖)
- 实现 _run(同步)或 _arun(异步);继承 UCTool 可直接获得超时、流式与 ctx 注入
示例 1:同步工具(计数问候)
from pydantic import BaseModel, Field
from vagent.tools.uctool import UCTool
class HelloArgs(BaseModel):
who: str = Field(..., description="要问候的人")
class HelloTool(UCTool):
name: str = "Hello"
description: str = "向指定对象问候,并统计调用次数"
args_schema = HelloArgs
def _run(self, who: str, run_manager=None) -> str:
return f"Hello, {who}! (called {self.call_count+1} times)"
注册与使用:
- 临时:
--ex-tools mypkg.mytools.HelloTool
- 持久:项目
config.yaml
ex_tools:
- mypkg.mytools.HelloTool
(可选)短名注册:在 vagent/tools/__init__.py
导出 HelloTool
后,可写 --ex-tools HelloTool
。
示例 2:异步流式工具(ctx.info + 超时)
from pydantic import BaseModel, Field
from vagent.tools.uctool import UCTool
import asyncio
class ProgressArgs(BaseModel):
steps: int = Field(5, ge=1, le=20, description="进度步数")
class ProgressTool(UCTool):
name: str = "Progress"
description: str = "演示流式输出与超时处理"
args_schema = ProgressArgs
async def _arun(self, steps: int, run_manager=None):
for i in range(steps):
self.put_alive_data(f"step {i+1}/{steps}") # 供阻塞提示/日志缓冲
await asyncio.sleep(0.5)
return "done"
说明:UCTool.ainvoke 会在 MCP 模式下注入 ctx,并启动阻塞提示线程;当 sync_block_log_to_client=True
时会周期性 ctx.info
推送日志,超时后返回错误与缓冲日志。
3) 暴露为 MCP Server 工具
工具 → MCP 转换(vagent/tools/uctool.py::to_fastmcp
):
- 必须:args_schema 继承 BaseModel;不支持“注入参数”签名。
- UCTool 子类会得到 context_kwarg=“ctx” 的 FastMCP 工具,具备流式交互能力。
Server 端启动:
- VerifyAgent.start_mcps 组合工具:
tool_list_base + tool_list_task + tool_list_ext + [tool_list_file]
vagent/util/functions.py::create_verify_mcps
将工具序列转换为 FastMCP 工具并启动 uvicorn(mcp.streamable_http_app()
)。
如何选择暴露范围:
- CLI:
- 启动(含文件工具):
--mcp-server
- 启动(无文件工具):
--mcp-server-no-file-tools
- 地址:
--mcp-server-host
,端口:--mcp-server-port
- 启动(含文件工具):
- TUI 命令:
start_mcp_server [host] [port]
/start_mcp_server_no_file_ops [host] [port]
4) 客户端调用流程
FastMCP Python 客户端(参考 tests/test_mcps.py
):
from fastmcp import Client
client = Client("http://127.0.0.1:5000/mcp", timeout=10)
print(client.list_tools())
print(client.call_tool("Hello", {"who": "UCAgent"}))
IDE/Agent(Claude Code、Copilot、Qwen Code 等):将 httpUrl
指向 http://<host>:<port>/mcp
,即可发现并调用工具。
5) 生命周期、并发与超时
- 计数:UCTool 内置 call_count;非 UCTool 工具由
import_and_instance_tools
包装计数。 - 并发保护:is_in_streaming/is_alive_loop 防止重入;同一实例不允许并发执行。
- 超时:
call_time_out
(默认 20s)+ 客户端 timeout;阻塞时可用put_alive_data
+sync_block_log_to_client=True
推送心跳。
6) 配置策略与最佳实践
- ex_tools 列表为“整体覆盖”,项目
config.yaml
需写出完整清单。 - 短名 vs 全路径:短名更便捷,全路径适用于私有包不修改本仓库时。
- 无参构造/工厂:装配器直接调用
(...)()
,复杂配置建议在工厂内部处理(读取环境/配置文件)。 - 文件写权限:MCP 无文件工具模式下不要暴露写类工具;如需写入,请在本地 Agent 内使用或显式允许写目录。
通过环境变量注入外部工具(EX_TOOLS)
配置文件支持 Bash 风格环境变量占位:$(VAR: default)
。你可以让 ex_tools
从环境变量注入工具类列表(支持模块全名或 vagent.tools
下的短名)。
- 在项目的
config.yaml
或用户级~/.ucagent/setting.yaml
中写入:
ex_tools: $(EX_TOOLS: [])
- 用环境变量提供列表(必须是可被 YAML 解析的数组字面量):
export EX_TOOLS='["SqThink","HumanHelp"]'
# 或使用完整类路径:
# export EX_TOOLS='["vagent.tools.extool.SqThink","vagent.tools.human.HumanHelp"]'
-
启动后本地对话与 MCP Server 中都会出现这些工具。短名需要在
vagent/tools/__init__.py
导出;否则请使用完整模块路径。 -
与 CLI 的
--ex-tools
选项是合并关系(两边都会被装配)。
7) 常见问题排查
- 工具未出现在 MCP 列表:未被装配(ex_tools 未配置/未导出)、args_schema 非 BaseModel、Server 未按预期启动。
- 调用报“注入参数不支持”:工具定义包含 LangChain 的 injected args;请改成显式 args_schema 参数。
- 超时:调大
call_time_out
或客户端 timeout;在长任务中输出进度维持心跳。 - 短名无效:未在
vagent/tools/__init__.py
导出;改用全路径或补导出。
完成以上步骤后:你的工具既能在本地对话中被 ReAct 自动调用,也能通过 MCP Server 暴露给外部 IDE/客户端统一调用。