📋 文章目录
AI 助手只会说话,不能做事。这个问题大家都知道,OpenAI 用 Function Calling 协议给了一个解决方案——让 LLM 在对话中识别需要调用的工具,由外部服务执行。但协议只解决了一半问题:谁来提供这些工具?谁来执行?谁来保证安全?
我给自己的 AI 助手(OpenClaw 龙虾)搭了一个工具服务器,叫 Lobster。它跑在云服务器上,龙虾通过 Function Calling 调用 Lobster 的 API,从"只会说话"变成"能办实事"。这篇文章不讲 Lobster 的具体工具清单,而是讲这套架构的思路——ToolRegistry 模式、Function Calling 桥接、安全分层、可观测性、插件扩展。这些模式你可以拿去复用,给任何 AI 助手搭工具服务器。
第一个问题:怎么让 AI 助手"看见"你的工具
AI 助手要调用工具,首先得知道有哪些工具可用、每个工具需要什么参数。OpenAI 定义了 Function Calling 格式——一个 JSON Schema,包含工具名、描述、参数定义。但你的工具是 Python 函数、CLI 命令、HTTP 请求,格式各不相同。怎么把它们统一转换成 AI 能理解的标准格式?
Lobster 的做法是 ToolRegistry。核心很简单:每个工具注册时提供四样东西——名字、描述、参数定义(JSON Schema)、执行函数。注册完成后,ToolRegistry 自动把所有工具转换成 OpenAI Function Calling 格式。
注册之后,AI 助手拿工具列表就是一次 HTTP 请求:
返回的是标准 Function Calling JSON,可以直接喂给任何支持函数调用的 LLM——GPT、Claude、DeepSeek、本地 Ollama 模型,都行。
这个模式的好处是:你的工具实现是 Python 函数,但暴露给 AI 的格式是标准化的。加一个新工具,只需要写一个 register() 调用,不用操心格式转换。ToolRegistry 负责从注册信息到 Function Calling JSON 的映射,你只管写业务逻辑。
第二个问题:怎么让 AI 助手"调用"你的工具
AI 助手知道了工具列表,在对话中判断需要查股票时,它返回一个函数调用指令:
你的服务器需要接收这个指令,找到对应的 handler,执行,返回结果。Lobster 用 FastAPI 搭了一个 API 服务器,每个注册的工具自动映射到一个执行端点:
ToolRegistry 收到请求后做三件事:查找注册的 handler、执行、返回结果。查找是按名字索引的 O(1) 操作,执行是直接调用 Python 函数,返回是统一的 JSON 格式。
完整的交互链路:LLM 识别意图 → 生成函数调用 → Lobster API 接收 → ToolRegistry 查找并执行 → 结果返回给 LLM → LLM 用真实数据组织回答。用户全程只跟 AI 助手对话,工具调用是透明的。
这里有一个设计选择:你的 API 服务器也可以只暴露一个统一的 /execute 端点,不按工具名分路由。Lobster 选了按工具名分路由(/tools/{tool_name}/execute),好处是每个工具的 API 调用日志更清晰,调试时一看就知道调了哪个工具。如果你的工具数量不多,统一端点也够用。
第三个问题:让 AI 能做事,但不能乱做事
这是最容易被忽略的问题。你的 AI 助手能读写文件、执行命令、发 HTTP 请求了——它也就能误删文件、跑危险命令、请求内网地址。在云服务器上给 AI 开放执行能力,安全边界就是底线。
Lobster 在每个工具执行前加了一层安全验证,分三个维度:
路径安全。 file_read、file_write 等文件操作工具只能访问允许的目录。默认限制在当前工作目录,你可以通过配置扩展允许范围,但 AI 不能跳出边界去读 /etc/passwd 或者写 /root/.bashrc。
命令安全。 run_shell 工具有一个黑名单:rm -rf /、mkfs、dd if=、fork 炸弹、chmod 777 /、wget 这些危险命令直接拦截。你也可以配置白名单模式,只允许预设的安全命令。
URL 安全。 http_get、http_post 只允许 http/https 协议,并且阻断 localhost、127.0.0.1、0.0.0.0——防止 AI 被诱导去请求你服务器上的内部服务(SSRF 防护)。
还有一个针对 Python 代码的特殊检测:run_python 工具在执行前扫描五个高危模式——os.system、subprocess、eval()、exec()、import——匹配到任何一个就拒绝执行。计算器工具用 ast.parse + operator 映射替代 eval(),只允许算术运算。
这些验证不是装饰性的可选层,是每次工具执行的必经关卡。你的 AI 助手越能做事,你就越需要限制它能做的事。安全验证和工具能力应该同步增长——每加一个新工具,就想想它可能被怎么滥用,然后加对应的防护。
第四个问题:怎么知道 AI 调了什么、调得怎么样
工具服务器跑在云上,你不在旁边盯着。AI 调了哪些工具、哪个最慢、哪个失败率最高——这些信息你需要能看到。
Lobster 做了两层可观测性:
执行统计。 每次工具调用都记录到 ~/.lobster/stats/,持久化跨会话。统计包括:总调用次数、成功/失败次数、平均执行时间、最近调用历史。你可以看到最常用的工具排行、最慢的调用、错误率最高的工具。这些数据帮你判断哪些工具值得优化、哪些可能有问题。
缓存。 ToolRegistry 内置了一个 LRU 缓存,带 TTL 过期机制。同一个股票代码一分钟内不重复请求新浪财经 API——因为行情数据 60 秒内变化不大,缓存命中率直接降低外部 API 调用量。缓存也有统计:命中率、缓存大小、过期清理次数。
两层设计是互补的:统计告诉你宏观趋势(哪个工具用得多、哪个慢),缓存给你微观优化(减少重复调用、降低延迟)。如果你搭自己的工具服务器,这两层都值得做——不需要很复杂,一个 JSON 文件记统计 + 一个 OrderedDict 做缓存就够起步了。
第五个问题:怎么加新工具
你的 AI 助手需要的能力会不断变化。今天只需要查股票,明天可能需要读邮件,后天需要调用你公司的内部 API。工具服务器不能是封闭的——需要有一个低成本的扩展机制。
Lobster 做了两层扩展:
注册扩展。 加一个新工具就是一行 registry.register()。你在任何 Python 模块里写 handler 函数,然后调用注册,ToolRegistry 自动把它纳入 Function Calling 格式。不需要改 API 服务器代码,不需要手动写 JSON Schema——注册时提供的参数定义会自动转换。
插件扩展。 ~/.lobster/plugins/*/plugin.py 自动加载。你创建一个目录,放一个 plugin.py 文件,定义你的工具,下次启动 Lobster 时自动发现和注册。有模板生成器帮你快速创建插件骨架。
这两层的区别是:注册扩展适合你自己开发的工具(你知道代码在哪里,直接 import 就行),插件扩展适合别人贡献的工具或者你想隔离的工具(独立目录,不耦合主代码)。你的项目可能只需要注册扩展就够了,但保留插件机制意味着未来可以零成本地加第三方工具。
关于 MCP
你可能注意到了,Anthropic 推出了 MCP(Model Context Protocol),正在成为工具集成的新趋势。Cursor、VS Code、各种 Agent 框架都在接入 MCP。这和 Function Calling 是什么关系?
MCP 和 Function Calling 解决的是同一个问题——让 AI 调用外部工具。但场景不同。MCP 是为 IDE 和本地工具集成设计的,AI Agent 通过 MCP 协议连接本地工具服务器,适合开发场景。Function Calling 是为云端 AI 助手设计的,LLM 在对话流中生成工具调用指令,由你的服务器执行,适合部署在云上的助手。
Lobster 用 Function Calling 格式,因为它跑在云服务器上,龙虾也在云端。这是对的。但如果你要做 IDE 集成或本地 Agent,MCP 是更合适的协议。
好消息是:ToolRegistry 模式和协议无关。你的工具注册、安全验证、缓存、统计这些架构层不依赖 Function Calling 的具体格式。换到 MCP,你只需要改一层——从 Function Calling JSON 转成 MCP Tool 定义格式——底下的 handler、安全验证、缓存、统计全部复用。架构思路是通用的,协议格式是可替换的。
架构总结
把上面五个问题串起来,Lobster 的架构是这样的:
工具注册层(ToolRegistry)统一管理所有工具的元数据和执行函数,自动转换成 LLM 能理解的标准格式。API 服务器层(FastAPI)把每个注册工具映射到 HTTP 端点,让 AI 助手通过网络调用。安全验证层在每次执行前做路径、命令、URL 三维校验,保证 AI 能做事但不能乱做事。可观测性层记录执行统计和缓存数据,让你对 AI 的每一次工具调用有掌控。扩展层通过注册和插件两种方式加新工具,保证工具集可以持续增长。
这五层每一层都是独立的,你可以按需取舍。如果你只需要最简方案:一个 ToolRegistry + 一个 FastAPI 服务器就够了。安全验证和缓存可以后加,插件系统可以不做。重要的是先把"AI 调用 → 工具执行 → 结果返回"这条链路跑通,然后再逐步加固。
给 AI 助手搭工具服务器,核心不是工具本身,而是这套架构。你的工具集会变——今天是股票和代码分析,明天可能是邮件和日历。但 ToolRegistry 模式、安全分层、可观测性、扩展机制这些架构层,不管工具怎么变,都能稳稳地托住。
源码导航
| 架构层 | 源码文件 | 说明 |
|---|---|---|
| 工具注册 | tools.py | ToolRegistry、14 内置工具、安全验证 |
| API 服务器 | api_cmd.py | FastAPI 端点、OpenAI Function Calling 格式 |
| 安全验证 | tools.py | validate_path / validate_command / validate_url / _check_python_dangerous |
| 执行统计 | stats.py | ToolStatsTracker、持久化统计 |
| 缓存 | cache.py | LRU 缓存、TTL 过期、命中率统计 |
| 金融工具 | investment.py | stock_quote 等投资工具注册 |
| Serena 集成 | serena_client.py | 代码智能框架对接 |
| 记忆存储 | memory_store.py | TF-IDF + Levenshtein 模糊搜索 |
| 插件系统 | plugin.py | 自动发现和加载自定义插件 |
| 配置管理 | config.py | .env 加载、LobsterConfig |
| LLM 客户端 | llm_client.py | EnhancedLLMClient、对话管理、缓存、重试 |
发表回复