工具调用常被包装成模型的原生能力,但它的底层机制可能比想象中朴素得多。

发生了什么

Hacker News上出现一篇题为《How AI tool calling works (40 lines of vanilla JavaScript)》的帖子,作者用约40行不依赖任何框架的原生JavaScript,实现了一个可运行的AI工具调用流程。

其核心逻辑大致是:把可用工具的名称、用途和参数结构以文本形式写进系统提示,让模型在需要时输出一段约定格式的调用请求;程序解析这段请求,在本地执行对应函数,再把返回值作为新一轮消息追加进对话,重新发给模型,如此循环直到模型不再请求工具、直接给出最终回答。整个过程没有魔法,只有字符串拼接、JSON解析和一个while循环。

为什么重要

主流大模型API都提供结构化的tool use或function calling字段,SDK也把它封装成一两行调用。便利的代价是黑箱化:很多开发者以为模型真的“知道”如何调用外部函数,实际上模型做的只是生成符合约定格式的文本,真正的执行、参数校验、错误处理、循环终止全部由客户端代码负责。

这篇短文的价值在于把这层抽象剥掉。它提醒人们,工具调用的可靠性瓶颈往往不在模型,而在协议设计——提示词是否清晰、schema是否严格、模型输出解析是否健壮、工具报错后如何回灌给模型。这些工程细节决定了Agent能否稳定运行,也解释了为什么同样的模型在不同框架下表现差异巨大。

影响与看点

对开发者而言,亲手实现一遍最小循环,是理解Agent框架内部机制的最快路径。此后再看LangChain、各家SDK的tool抽象,会更容易判断哪些是必要的工程加固,哪些只是包装。

对工具与平台方而言,这也意味着工具调用的互操作性仍停留在“约定”层面。不同厂商的调用格式、并行调用支持、流式返回处理各不相同,跨模型迁移成本由此产生。

值得关注的点有三个:一是模型输出解析的容错,模型偶尔会输出多余文字或非法JSON,生产环境必须处理;二是循环的终止条件与步数上限,否则容易陷入反复调用;三是安全边界,本地执行模型指定的函数等同于把控制权部分交给模型,权限与沙箱设计不可省略。

一个独立判断:工具调用不是模型能力的分水岭,而是工程纪律的分水岭——真正拉开差距的,是谁把这条朴素的循环做得更稳、更可观测。