AI Agent 工程实践(24):Tool Registry
系列:AI Agent 工程实践
上一篇:第 23 篇《Provider 抽象层设计》
下一篇:第 25 篇《Memory Service》
一、开场:一次安全审计发现的"幽灵工具"
有个团队做安全审计,要列出"Agent 总共能调哪些工具、每个权限多大"。结果没人答得上来——工具是 30 多个散落各处的函数,有的在 utils/,有的在 services/,有的直接写在 agent 文件里。审计花了一周,还漏了一个能执行 shell 命令的内部工具,差点出事。
问题不是"工具多",是工具没有被统一管理。上篇(23)讲了模型怎么收口,这篇讲工具怎么收口——Tool Registry。
二、问题背景:散落函数 vs 统一注册
散落版:
# tools/email.py
def send_email(to, body): ...
# tools/sql.py
def run_query(sql): ... # 能删库,但没人列得清
# agent/customer_agent.py 里又直接写了个 get_weather()
注册版:
# 任何地方用工具,都从 Registry 取,且经过权限校验
from tools.registry import ToolRegistry
reg = ToolRegistry()
reg.call("send_email", to=to, body=body) # 自动校验权限 + 记录审计
差别:send_email 调不调得成,由 Registry 决定,而不是由"谁 import 了它"决定。
三、错误尝试:三种工具管理翻车
错误 1:工具是裸函数,直接 import 调用
谁都能 from tools.sql import run_query 然后执行。没有统一入口,权限、日志、审计全靠各调用点自觉——自觉从来靠不住。
错误 2:权限写在调用处
if user.role == "admin":
run_query(sql) # 权限判断散落 20 个调用点
加一个"财务只能查不能改"的规则,要改 20 处。权限该随工具走,不该随调用走。
错误 3:schema 和函数分离
函数签名改了,但喂给 LLM 的 JSON schema 没同步,模型按旧 schema 传参,运行时类型错误。工具的"说明书"(schema)和"实现"(函数)必须同源。
四、关键观察:一个工具 = 5 件套
好的工具管理,每个工具是五件事的绑定:
- Tool:名字 + 描述(给 LLM 看的语义)。
- Schema:输入参数结构(给 LLM 和校验用)。
- Permission:谁能调、什么条件下能调。
- Executor:真正执行的函数。
- Registry:把上面四件注册到一起,统一提供
list / get / call。
Registry 是入口,Permission 是闸门,Schema 是契约,Executor 是引擎,Tool 是它们的身份证。 五件不全,工具就不"受控"。
五、最终方案:Registry 长什么样
tools/
├── registry.py # ToolRegistry:register / list / get / call(带权限+审计)
├── base.py # Tool 定义(name/description/schema/permission/executor)
├── email.py # 工具实现:register Tool(...)
├── sql.py # 同上,permission 标注"只读"
└── schemas.py # 参数校验(可选,复杂场景)
Tool 定义示例:
Tool(
name="send_email",
description="向指定地址发送邮件",
schema={"to": "string", "body": "string"},
permission=Permission(roles=["admin", "service"]),
executor=send_email_impl,
)
Registry.call 做的事:
def call(self, name, **args):
tool = self.get(name)
if not tool.permission.allows(current_user): # 闸门
raise PermissionDenied(name)
tool.schema.validate(args) # 契约校验
audit.log("tool_call", name, current_user) # 审计
return tool.executor(**args) # 执行
调用流(Mermaid):
flowchart TD
A[Agent 决定调工具] --> R[ToolRegistry.call name]
R --> P{权限校验}
P -->|拒绝| DENY[PermissionDenied]
P -->|通过| V[Schema 校验]
V --> AU[审计日志]
AU --> E[Executor 执行]
六、设计权衡:什么时候用 Registry
| 场景 | 建议 | 理由 |
|---|---|---|
| 2–3 个内部工具、无权限要求 | 直接函数调用 | Registry 是负债 |
| 多工具 / 有敏感操作 / 要审计 | 必须 Registry | 权限+审计是刚需 |
| 工具要开放给外部 / 多 Agent 共享 | Registry + 版本 | 统一治理边界 |
反过度工程:不要为了 2 个工具上一套带 UI 的注册中心。Registry 的核心是"统一入口 + 权限闸门 + schema 同源",不是某个炫酷框架。
七、总结
- ✅ 散落函数 = 审计黑洞 + 权限失控;30 个工具没人列得清是真实风险。
- ✅ 三种翻车:裸函数直调、权限写调用处、schema 与实现分离。
- ✅ 一个工具 = 5 件套:Tool(身份证)+ Schema(契约)+ Permission(闸门)+ Executor(引擎)+ Registry(入口)。
- ✅
Registry.call统一做权限校验 + schema 校验 + 审计 + 执行,调用方只传名字和参数。 - ✅ 反过度工程:Registry 要的是"统一入口+权限+同源",不是复杂框架。
下一篇,钻进 memory/ —— 为什么 Memory 不该属于 Agent,而要独立成服务。(25)
参考资料(带用途说明)
- 本系列(23)Provider 抽象层设计:本文与(23)同构——(23)收口模型,(24)收口工具,都是"变化轴内聚"思想的体现。
- 本系列(22)AI Agent 项目应该如何分层:本文是
tools/层的展开,讲清边界与接口。 - 本系列(14)MCP——为什么它正在成为 Agent 的 USB 接口:MCP 本质是工具的"外部注册协议",与本文 Registry 理念相通。
- 本系列(13)Tool Calling——Agent 为什么要学会用工具:本文是(13)"工具能力"的工程化落地(统一管理)。
本文是 AI Agent 工程实践系列的第 24 篇(第四阶段第四篇)。
系列导航
上一篇:第 23 篇《Provider 抽象层设计》
下一篇:第 25 篇《Memory Service》
更多推荐

所有评论(0)