大语言模型技术指南:Function Calling、Tool Use、Agent 框架的工作机制与参数要点
前一篇我们把大模型生产服务拆成了更工程化的几个层面:
- 高并发如何扛住
- 监控指标应该盯什么
- 限流什么时候必须做
- 故障恢复怎么避免整片服务被拖死
但当底层推理服务逐渐稳定之后,上层应用很快会进入另一个阶段:
单纯"会聊天"的模型已经不够了,系统开始要求模型去调用工具、访问外部信息、分解任务、执行多步流程。
这时候,很多团队会同时碰到一批新问题:
- Function Calling 和 Tool Use 到底是不是一回事?
- 为什么模型明明"知道"要查天气,却不一定能正确生成工具参数?
- 为什么 Agent demo 很聪明,一进生产就开始无限循环、乱调工具、成本飙升?
tool_choice、temperature、max_steps、超时、重试、观察窗口这些参数到底怎么配?- 什么时候应该让模型自由规划,什么时候应该把流程写死?
这些问题背后,本质上不是"模型会不会调用函数",而是:
你是不是在把语言模型,从一个文本生成器,变成一个会感知环境、调用外部能力、并基于反馈持续决策的执行系统。
这篇文章就集中讲这个问题。
我想按四层来拆:
- Function Calling 是什么,它解决了哪一层问题
- Tool Use 的完整闭环是怎么跑起来的
- Agent 为什么不是"多调几个工具"这么简单
- 工程上最关键的参数、约束和防失控机制应该怎么配
如果你已经从"给模型一个 prompt"走到了"让模型接搜索、数据库、浏览器、代码执行、业务 API",这一篇基本就是理解 Agent 系统的起点。
一、先说结论:Function Calling、Tool Use、Agent 是三层能力,不要混成一个词
很多讨论里,这三个词会被混用。
但如果不拆开,系统设计很容易做乱。
1)Function Calling:让模型按约定格式提出"调用请求"
Function Calling 解决的核心问题是:
不要让模型用自然语言随便描述"我想调某个接口",而是让它输出结构化、机器可解析的调用意图。
比如你定义一个函数:
get_weather(city, date)
理想情况下,模型不应该输出:
- "我建议查询一下上海明天的天气。"
而应该输出类似:
- 工具名:
get_weather - 参数:
{"city":"上海","date":"tomorrow"}
所以 Function Calling 的重点不是"真的执行了函数",而是:
- 工具描述如何暴露给模型
- 参数 schema 是否足够清晰
- 模型是否能稳定产出合法参数
- 上层程序是否能安全地解析结果
它本质上是一个结构化输出接口层。
2)Tool Use:让模型提出调用,再由系统真的去执行,并把结果回灌
Tool Use 比 Function Calling 多了一步。
它要求系统形成完整闭环:
- 模型判断是否需要工具
- 模型产出工具名与参数
- 外部执行器实际调用工具
- 工具返回结果
- 结果再喂回模型
- 模型基于新观察继续回答或继续决策
所以 Tool Use 的关键,不只是 schema,而是执行与反馈。
这意味着系统开始面对真实世界的不确定性:
- 工具会超时
- 参数可能不合法
- 返回可能为空
- 外部 API 会失败
- 多个工具结果可能互相矛盾
从这一层开始,问题就不再只是"输出格式对不对",而是"系统行为稳不稳定"。
3)Agent:让模型在多步循环里持续做"思考---行动---观察"
Agent 则更进一步。
Agent 不是一次调用,而是一个循环:
- 根据目标决定下一步干什么
- 选择工具或子任务
- 执行动作
- 观察结果
- 判断是否继续、修改计划或结束
所以 Agent 系统真正增加的,不是某个 API 字段,而是:
决策链路变长了。
一旦链路变长,问题会同步放大:
- 错一步会不会越错越远
- 工具调用会不会不断累积成本
- 是否会进入循环
- 是否会误用危险工具
- 观测结果如何被压缩进上下文
- 什么时候该停,什么时候该交还给人
因此最实用的理解方式是:
- Function Calling 是结构化调用接口
- Tool Use 是调用闭环
- Agent 是多步决策系统
别把它们当成一件事。
二、为什么大模型需要工具:不是因为模型不聪明,而是因为它天然受三类限制
很多人第一次接触 Agent,会误以为"工具是给弱模型补能力"。
其实不准确。
更本质的原因是:
1)模型参数不是实时世界
模型再大,也只是把训练时见过的统计规律压进参数里。
所以它天然不擅长直接解决这类问题:
- 今天上海下不下雨
- 当前数据库里有多少订单
- 某个网页现在显示什么内容
- 某个代码仓库最新的 CI 状态如何
这些都不是"语言知识"问题,而是实时外部状态问题。
工具调用的意义,就是把模型和实时环境接起来。
2)模型参数不是精确执行器
即使模型知道"应该算一下",也不代表它适合自己算。
例如:
- 复杂数学计算
- SQL 查询
- 调 API
- 文件系统操作
- 浏览器点击和页面读取
很多任务不是靠更会说话解决,而是靠把确定性执行交给专门系统。
3)模型参数不是长期工作流管理器
多步任务里,模型经常会遇到:
- 中间状态需要保存
- 失败需要重试
- 某步结果要传给下一步
- 超时和权限要检查
- 有些动作需要人工确认
这些都更像系统工程,而不是单轮问答。
所以工具和 Agent 的存在,不是在替代模型,而是在承认模型的边界。
一句话概括:
模型负责理解、规划和生成;工具负责访问世界、执行动作和返回确定性结果。
三、Function Calling 到底怎么工作:本质是"给模型一个受限动作空间"
很多平台把 Function Calling 讲成一个 API 能力,但从机制上看,它更像是:
你把一组允许动作,以 schema 的形式显式告诉模型。
1)工具定义通常至少包含三类信息
一个可用的工具描述,至少要说清楚:
- 工具名称
- 工具用途说明
- 参数结构与字段约束
比如一个搜索工具,不能只写:
search(query)
更好的描述通常会补清:
- 这个工具适合查实时信息
query应该是具体问题而不是空泛主题top_k的取值范围是什么- 什么情况下不应该调用它
因为模型不是编译器。
它是否会选对工具、填对参数,很大程度取决于你给的描述是不是足够可判别。
2)schema 设计越模糊,模型越容易"看起来懂了,实际上乱调"
最常见的问题包括:
- 字段名太抽象,模型不知道该填什么
- 多个工具功能重叠,模型难以区分
- 参数可选项过多,模型容易臆造值
- 描述里没有反例,模型不知道什么时候不该调
比如:
action_typedataoptions
这种字段名从工程师角度觉得通用,但从模型角度很难判断语义边界。
通常更好的 schema 原则是:
- 字段名尽量语义明确
- 枚举值尽量少且边界清晰
- 必填参数要少而关键
- 描述中写清适用场景和禁用场景
3)Function Calling 不是"保证正确调用",只是提高调用可控性
这里要避免一个误解。
很多人以为只要开了 Function Calling,模型就会像一个严格遵循类型系统的程序。
事实并不是。
模型仍然可能:
- 选错工具
- 漏填参数
- 生成不合法枚举
- 在该直接回答时硬调工具
- 在该调工具时假装自己知道答案
所以 Function Calling 更像是:
把原本完全自由的文本输出,压缩到了一个更容易校验、更容易拒绝、更容易重试的空间。
这已经很重要,但还不等于"问题解决了"。
四、Tool Use 的完整链路:不是模型输出完就结束,而是进入一个可失败的执行系统
一旦开始真的调工具,系统就从"生成问题"进入"执行问题"。
一条典型链路通常长这样:
- 用户提出目标
- 模型判断是否需要工具
- 模型输出工具名和参数
- 系统校验参数合法性
- 执行器发起实际调用
- 工具返回结果或错误
- 系统把结果压缩成 observation 回给模型
- 模型决定结束、追问、改参数或继续调用其他工具
这条链路里,几乎每一层都可能出错。
1)参数校验是第一道闸门
别直接把模型生成的参数无脑交给执行器。
至少要做:
- 类型校验
- 必填字段检查
- 枚举值检查
- 长度与范围限制
- 危险字符过滤
- 权限相关校验
因为模型生成的是"高概率文本",不是天然可信输入。
2)执行器和模型要解耦
一个很重要的工程原则是:
模型负责提出动作,执行器负责真正落地动作。
不要让模型自己拥有无限制执行权。
更稳妥的架构通常是:
- 模型只能请求工具
- 工具白名单由系统控制
- 执行器做权限检查、超时、审计、重试
- 某些高风险动作必须人工确认
这样做的好处是,模型即使判断错了,也不会直接越过系统边界。
3)返回结果必须做"观察压缩"
工具结果不是越原始越好。
如果你把大量 HTML、JSON、日志全文、不相关字段原封不动塞回上下文,很容易出问题:
- 上下文膨胀
- 干扰模型判断
- token 成本飙升
- 重要信息被淹没
更好的做法通常是:
- 只保留必要字段
- 明确标注状态:成功、失败、空结果
- 对长结果做截断和摘要
- 保留关键证据而不是全部噪音
Observation 的质量,会直接影响 Agent 下一步判断质量。
五、Agent 为什么容易"看起来很强,实际上很脆"
很多 Agent demo 的问题,不是第一步不会,而是第二步以后开始失控。
这正是多步系统的典型风险。
1)一步错误,可能在后续步骤被放大
比如模型第一步把用户需求理解错了。
在单轮问答里,后果可能只是答案偏一点。
但在 Agent 里,错误会继续传播:
- 选错工具
- 查询错对象
- 得到错误 observation
- 基于错误 observation 再规划下一步
- 最后形成一本正经但方向完全错误的结果
所以 Agent 最难的不是"能不能开始",而是误差会不会连锁扩散。
2)自由规划越强,行为越难预测
让模型自由选择工具、自由拆任务、自由决定何时结束,看起来更智能。
但代价是:
- 行为稳定性下降
- 成本更难控
- 线上问题更难复现
- 安全边界更难验证
因此生产上很少是"纯自由 Agent"。
更常见的做法是:
- 有限工具集
- 有限步数
- 明确终止条件
- 对高风险动作加审批
- 对关键链路做半结构化流程编排
3)Agent 的瓶颈常常不是模型能力,而是上下文管理
多步循环以后,上下文会迅速膨胀。
问题包括:
- 历史 observation 越来越长
- 早期关键约束被后续内容冲淡
- 模型开始遗忘初始目标
- token 成本不断累积
所以成熟系统通常不会无脑把全量过程一直塞在上下文里。
而是会做:
- 中间状态结构化存储
- 历史步骤摘要化
- 关键约束单独保留在 scratchpad 之外
- 对 observation 做窗口裁剪
Agent 的稳定性,很大程度取决于你如何管理上下文,而不是只取决于底座模型多强。
六、最关键的几个参数,到底该怎么理解
下面把工程里最常见、也最容易被误用的一批参数拆开讲。
1)tool_choice:让模型自由选,还是强制用某个工具
它本质上控制的是:
- 是否允许模型自己决定要不要调用工具
- 是否要求模型必须调用指定工具
- 是否禁止工具调用,直接自然语言回答
适用建议:
- 开放问答场景:可让模型自由选择,但要有兜底规则
- 确定流程场景:强制指定工具更稳
- 测试/评估场景:固定工具选择更容易对比
如果某个步骤理论上就必须查数据库,那就别让模型"思考是否要查"。
直接强制调用通常更稳。
2)temperature:在 Agent 里通常比聊天更应该保守
在一般聊天里,稍高一点的随机性可能更自然。
但在工具调用和 Agent 任务里,温度过高通常意味着:
- 工具选择更飘
- 参数填充更不稳定
- 多步链路更难复现
- 同一任务重复执行结果差异更大
经验上:
- 结构化输出、检索、数据库查询、代码执行前的规划,温度通常应偏低
- 只有在创意生成、候选方案发散时,才适合适度提高
别把 Agent 当成创作模型来配采样参数。
3)max_steps:它不是随便设的保险丝,而是成本与风险阀门
这是 Agent 系统里最重要的保护参数之一。
它控制的是:
- 一个任务最多允许多少轮"思考---行动---观察"循环
值太小:
- 合法复杂任务做不完
值太大:
- 容易死循环
- 成本失控
- 失败被拖很久才暴露
比较实用的思路是:
- 简单任务给小步数
- 复杂任务按任务模板给不同上限
- 接近上限时触发总结或交还人工
max_steps 本质上是 Agent 的预算参数,不是可有可无的默认值。
4)超时参数:必须区分模型超时、工具超时、总任务超时
很多系统只有一个统一 timeout,这通常不够。
更合理的拆法是:
- 单次模型生成超时
- 单次工具执行超时
- 整个任务总超时
- 排队等待超时
因为这四种超时背后的原因不同:
- 模型慢,可能是上下文过长或服务拥堵
- 工具慢,可能是外部 API 或网络问题
- 总任务慢,可能是循环过多
- 排队超时,可能是系统容量问题
只有拆开,你才知道该优化哪一层。
5)重试参数:不是所有失败都该重试
重试看起来很合理,但在 Agent 里尤其危险。
因为一次失败重试,可能触发:
- 更多 token 消耗
- 更多外部 API 调用
- 更长任务链路
- 重复副作用
应该区分:
- 可重试错误:临时超时、短暂网络错误、限流
- 不可重试错误:参数非法、权限不足、业务约束不满足
并且要配:
- 最大重试次数
- 指数退避
- 幂等设计
- 对有副作用操作加去重键
否则 Agent 很容易把一个瞬时异常放大成连环调用事故。
6)观察窗口与上下文裁剪参数:决定 Agent 会不会"越做越糊涂"
很多框架喜欢把完整过程塞回上下文。
短期看方便,长期看风险大。
需要明确控制:
- 保留最近几步 observation
- 历史步骤何时摘要化
- 哪些系统约束要常驻上下文
- 哪些中间结果只放外部状态,不回灌模型
这个参数组,常常比"换更强模型"更影响系统稳定性。
七、生产里真正重要的,不是让 Agent 更自由,而是让它更可控
很多团队刚做 Agent 时,目标是"尽可能像人一样自主"。
但一到生产,优先级就会变成另外四件事:
- 可预测
- 可审计
- 可回放
- 可止损
1)工具白名单和权限分级必须做
不是所有工具都应该暴露给同一个 Agent。
更安全的设计通常是:
- 只暴露任务所需最小工具集
- 读操作和写操作分开
- 外部副作用工具单独审批
- 按用户身份、租户、环境做权限切分
一个能调用十个工具的 Agent,不一定比一个只会调两个工具的 Agent 更好。
它可能只是更危险。
2)高风险动作要有人类确认节点
例如:
- 发邮件
- 下单
- 删除数据
- 修改数据库
- 执行生产命令
- 对外发送消息
这些动作不应该只因为模型"很有把握"就直接执行。
更稳妥的模式是:
- 先生成行动建议
- 明确展示将调用的工具和参数
- 等待人工确认
- 再执行
这会牺牲一点流畅性,但能换来可控性。
3)日志与轨迹必须能回放
Agent 系统出了问题,如果你只能看到"最终回答错了",基本是排不动的。
至少要能回放:
- 每一步 prompt 或系统状态
- 每一步工具选择
- 参数内容
- observation 内容
- 错误类型
- 总步数、总 token、总耗时
否则你根本不知道问题出在:
- 模型判断错
- schema 不清晰
- 工具返回脏数据
- 裁剪策略把关键信息截掉了
- 超时和重试策略互相打架
4)要有明确终止条件,而不是"直到模型说结束"
终止条件最好是多重的:
- 达到目标
- 达到最大步数
- 达到总超时
- 达到成本预算
- 连续若干步没有有效进展
- 连续重复同一工具调用
如果终止条件只有"模型自己决定结束",那系统迟早会遇到无限循环或伪完成。
八、什么时候该上 Agent,什么时候其实不需要 Agent
这是一个很实用的问题。
因为很多任务被包装成 Agent,其实只是流程没有设计好。
适合 Agent 的场景
通常有这几个特征:
- 任务路径不固定
- 需要根据中间结果动态决策
- 可能涉及多个工具协作
- 需要多步搜索、筛选、验证
- 人工事先难以写死全部流程
比如:
- 多源信息检索与交叉验证
- 复杂报表分析
- 浏览器任务自动化
- 代码库定位问题并尝试修复
- 需要探索式完成的开放任务
不适合 Agent 的场景
如果流程本来就很确定,其实更适合工作流而不是 Agent。
例如:
- 查数据库 → 填模板 → 返回结果
- 固定字段抽取 → JSON 输出
- 固定 API 查询 → 结果整形
- 审批通过后执行一个确定动作
这类任务用编排式 workflow 往往更稳、更便宜、更容易调试。
一个很实用的判断标准是:
如果你能把流程规则稳定写清楚,就优先写流程;只有当中间决策真的不可预定义时,再引入 Agent。
九、一个更接近现实的 Agent 系统,通常长什么样
如果把一个相对成熟的 Agent 系统抽象一下,常见结构会是:
- 任务入口层:接收用户目标,做身份与权限校验
- 规划/决策层:决定下一步是回答、调用工具还是继续搜索
- 工具执行层:白名单工具、参数校验、权限控制、超时与重试
- 状态管理层:保存任务状态、中间结果、历史摘要、预算消耗
- 观测与审计层:日志、轨迹、指标、告警、回放
- 人工接管层:高风险动作确认、失败兜底、人工纠偏
在这个结构里,底座模型只是中间的一部分。
真正决定 Agent 能否进入生产的,不只是模型是否足够聪明,而是:
- 工具边界有没有收好
- 状态有没有管理好
- 错误有没有隔离好
- 成本有没有预算好
- 人有没有办法及时接管
十、三条最实用的落地建议
如果你准备把 Function Calling 或 Agent 接到真实业务里,我最建议先做好下面三件事。
建议一:先从"单工具闭环"做起,不要一开始就追求通用 Agent
先把一个明确任务跑稳:
- 什么时候调用
- 参数怎么生成
- 返回结果怎么压缩
- 失败怎么处理
等单工具闭环稳定后,再扩到多工具协作。
这比一开始堆十几个工具、追求"全能代理"靠谱得多。
建议二:把 schema 设计当成产品设计,而不是顺手写个 JSON
工具名、参数名、字段描述、枚举值、适用边界,都会直接影响模型行为。
很多所谓"模型不会调工具",本质上其实是 schema 写得太差。
建议三:优先把预算和终止条件做严,再追求智能感
先控制好:
- 最大步数
- 总超时
- 工具超时
- 重试上限
- 可用工具范围
- 高风险动作审批
把系统先做稳,再考虑让 Agent 更自由。
生产系统里,"可控的 80 分"通常比"偶尔惊艳、偶尔翻车的 95 分"更有价值。
十一、最后总结:Agent 不是一个 API 功能,而是一种把模型接入环境的系统设计
很多人第一次接触 Function Calling 和 Agent,会觉得这只是模型厂商加的几个新字段。
但如果从工程角度看,真正变化很大。
因为从这一刻起,模型不再只是回答问题,而是在:
- 理解目标
- 选择动作
- 调用工具
- 读取反馈
- 在多步循环里持续决策
所以这篇最核心的结论可以浓缩成一句话:
Function Calling 解决的是"怎么结构化提出调用请求",Tool Use 解决的是"怎么形成执行闭环",Agent 解决的是"怎么在多步环境里持续做决策"。
而生产里的关键,从来不是把 Agent 做得多像人,而是把它做得:
- 有边界
- 有预算
- 有审计
- 有终止条件
- 出错后能止损
如果这些都没有,Agent 往往只是一个更贵、更难排障的 prompt 套壳系统。
如果这些都做好了,模型才真正有机会从"会说话"走向"会做事"。