[控场AI]
· 6 分钟阅读· 3,400 字

别急着部署AI Agent:工具调用与函数调用的完整设计指南

别急着部署AI Agent:工具调用与函数调用的完整设计指南

工具调用给大模型装上「手」,但参数校验、错误处理与安全防护才是落地难点。

文章系统讲解了如何让大语言模型从「会说话」变成「会干活」。核心机制是工具调用(Function Calling):模型不再输出易碎的 JSON 文本,而是发出结构化调用请求,由应用侧代码验证并执行,再把结果回传模型,形成多步执行循环。每个工具由名称、描述与 JSON Schema 构成,描述质量直接决定模型选工具的准确性,属于提示词工程。文章强调执行权始终在应用侧,并给出工程准则:所有参数按不可信输入校验、禁止拼接进 shell 或 SQL、错误作为反馈回传而非让循环崩溃、设置重试与步数上限。安全是真正难点,需应对工具输出中的提示注入,配合最小权限凭证、不可逆操作人工审批与全量调用日志。最后按检索、动作、计算、写入四类工具划分风险面,并给出生产环境的流式返回、预算控制、trace 与版本管理等实践。

大语言模型本质上只是一个文本生成器——它能写出邮件模板,却发不出邮件;能描述查询逻辑,却读不到数据库。把模型从"会说话"变成"会干活",靠的是工具调用(Tool Use)与函数调用(Function Calling)。这篇内容源自一期系统性讲解视频,围绕一个核心问题展开:如何给模型装上"手",以及装好这双手需要付出什么代价。

文本不够用:为什么模型必须有"手"

模型可以描述一个动作,但无法真正执行它。让它用自由文本输出 JSON 是极其脆弱的做法——多一个词、少一个括号,解析就失败了,而且没有任何契约能保证输出合法。真正的业务状态存在于 API、数据库和文件系统里,一句话描述请求不会改变任何东西,必须有东西去调用外部系统、执行操作、拿回结果。

自由文本输出JSON极易断裂

函数调用解决的正是这个断裂点:模型不再"祈祷"一段文字能被解析,而是发出一个结构化调用,明确指名工具与参数。系统可以验证并可靠执行这个结构,描述才真正变成动作。

工具的本质:名字、描述与JSON Schema

一个工具由三部分构成:名称、描述、JSON Schema。名称是标识,描述告诉模型这个工具做什么、什么时候用,Schema 定义参数的类型(string、number 等)以及哪些必填、哪些可选。

值得强调的是,工具描述本身就是提示词工程。描述含糊,模型就会选错工具;描述清晰,选择才可靠。以 get_weather 为例:名称表明意图,描述写明"查询某城市的当前天气",Schema 规定 city 为必填字符串——模型读完这些信息,就知道回答天气问题必须提供城市。

Schema 定义模型可选的工具与输入

JSON Schema 是一种用于描述和验证 JSON 数据结构的声明式规范(IETF 标准草案),它定义了对象可以包含哪些属性、每个属性的类型(如 string、number、boolean、object、array)、哪些字段必填、数值范围、字符串正则模式等约束。在函数调用中,模型正是依据工具提供的 JSON Schema 来生成合法参数——Schema 既是给模型看的「参数说明书」,也是运行时校验的「合同模板」。主流模型厂商(如 OpenAI 的 function calling、Anthropic 的 tool use)都采用 JSON Schema 子集来描述参数,因为它与 JSON 数据天然对齐,且能表达嵌套对象与数组,足以覆盖绝大多数 API 入参形态。

执行循环:模型请求、代码执行、模型继续

工具调用的运行机制是一个多步循环:

  1. 把对话历史和所有可用工具的 Schema 一起发给模型;
  2. 模型返回一个工具调用(而非最终答案),指明工具名和参数;
  3. 你的代码负责真正执行工具并捕获结果——模型本身无法运行代码或访问外部系统;
  4. 把结果追加进对话,再次调用模型;
  5. 重复,直到模型给出最终答案而非新的工具调用。

这个循环的关键认知是:执行权始终在你手里,模型只负责"申请"。

这一机制在业界通常被称为 Function Calling(OpenAI 于 2023 年 6 月首次引入)或 Tool Use(Anthropic 等厂商的命名),二者本质相同:模型输出一个结构化的调用对象(包含工具名与参数 JSON),而非自然语言。它与更早的 ReAct 模式一脉相承——ReAct 让模型在「思考—行动—观察」之间交替,但行动部分的解析依赖自由文本,容易断裂;Function Calling 则把「行动」升级为受 Schema 约束的结构化输出,大幅提升可靠性。理解这一点有助于看清:工具调用不是全新的范式,而是把 agent 循环中的执行环节从「文本解析」替换为「契约调用」,是 agent 从实验走向生产的关键基础设施。

参数验证:把所有输入当作不可信

安全设计的第一条规则:把每一个参数都视为未经校验的输入,哪怕它来自你自己的模型。基于这个前提,需要做四件事:

  • 校验类型、范围和允许值:确认数字是数字、落在合理区间,字符串匹配白名单;
  • 禁止把参数拼进 shell 或 SQL 字符串:直接拼接用户输入等于打开注入攻击的大门,参数必须与命令或查询保持分离;
  • 校验失败时明确拒绝:返回清晰的错误而不是猜测着继续,模型看到反馈后可以用更好的参数重试,把错误变成学习循环。

工具分类决定防护策略

不同类型的工具风险面不同,防护重点也应随之调整:

  • 检索类工具读取数据,主要风险是隐私泄露,设计重点是访问边界;
  • 动作类工具产生不可逆的副作用(如转账、删数据),防护必须前置到"允许什么发生",而非事后补救;
  • 计算类工具的风险是资源耗尽,需要限制其可消耗的资源量;
  • 写入类工具的风险是数据损坏或丢失,重点是保护完整性与防丢失。

不同工具类别的风险与防护差异

错误处理:让失败成为反馈而非崩溃

工具调用失败时,正确的做法是返回错误、保持循环存活,而不是让整个 agent 崩溃。把错误文本回传给模型,它会看到"缺了参数"还是"格式不对",从而调整下一次尝试。同时必须设置重试上限和总步数上限——没有上限的 agent 会永远重复同一个失败,烧掉时间和 token。还要区分暂时性故障(重试可能成功)与参数错误(需要修正而非盲目重试),错误文本应帮助模型分辨这两类情况。

安全才是真正的难点

工具返回的内容本身可能携带提示注入——攻击者可以把隐藏指令藏在工具输出里,劫持 agent 的行为。因此工具输出永远不能完全信任。对应的三道防线是:

  • 最小权限凭证:每个工具只拿到完成本职所需的权限,即使被操纵,损害也被限制在窄范围内;
  • 不可逆操作需人工批准:删数据、动钱、代发消息这类动作必须暂停等人确认,agent 提议、人类决定;
  • 记录每次调用与结果:完整的 trace 让你能在事故后复盘,查清哪个工具或响应出了问题。

提示注入(Prompt Injection)是工具调用场景下最突出的攻击面。它指攻击者把恶意指令嵌入到模型会读到的内容中——可能是用户输入,也可能是网页、文档、邮件或工具返回结果——诱导模型偏离原定任务、泄露系统提示或执行未授权操作。当注入藏在工具输出里时,称为「间接提示注入」(Indirect Prompt Injection),危害更大,因为开发者往往只防范用户输入而信任工具返回。由于当前大模型无法从根本上区分「数据」与「指令」,提示注入尚无完美解法,业界普遍采用纵深防御:最小权限、人工审批、输出隔离、输入过滤与全量日志共同构成防线,任何单一措施都不足以独立兜底。

常见错误清单

反复出现的坑集中在四处:工具描述含糊导致模型无法区分选项;参数不做校验直接透传;没有步数上限导致循环永不终止;吞掉错误让模型失去反馈、无法纠偏。

清晰的工具描述是可靠选择的前提

生产环境的四个工程实践

上线之后,有几项实践能把系统从"能跑"提升到"可靠":流式返回工具调用让用户看到进度;为每个请求预算 token、时间和成本;为每次调用和结果生成 trace 以便调试与审计;把工具当作公开 API 一样做版本管理,区分破坏性变更与非破坏性变更。

小结

模型自己不能行动,工具调用给它一个结构化的方式,请你的代码代为行动。每个工具是名称、描述与 JSON Schema 的组合,模型靠读描述来做选择。执行循环的骨架并不复杂,真正的难点全在边缘:把参数当不可信输入来校验、把错误当反馈而非崩溃、对不可逆操作执行最小权限与人工审批。把这个设计做对,agent 才值得被部署。

分享:

相关推荐