Tool Use 到底能保证什么?搞懂这条边界,你的 LLM 提取再也不会"格式炸了"

一个所有人都踩过的坑

你写了个 prompt 让 LLM 输出 JSON。Examples 给了三个,instruction 写得清清楚楚:"Output ONLY valid JSON, no markdown, no commentary"。

99 次它老实照做。第 100 次它给你来一句:"Here's the JSON you requested:" 后面跟一段 markdown 代码块。

或者更恶心的------JSON 倒是出了,但少了个逗号、多了个尾随逗号、字符串里有未转义的引号,json.loads() 直接炸。

你加 retry,加 regex 兜底,加更狠的 prompt。问题永远不能彻底根除。

因为你解决问题的层级错了。

Tool Use 系统有两层,分开看才能想清楚

scss 复制代码
[模型] → 生成 tool_use 参数(概率性)
   ↓
[API 层 schema 验证] → 校验通过(deterministic)
   ↓
[你的代码] → 拿到符合 schema 的 JSON

这两层做的事完全不一样。把它们分清楚,是理解所有 LLM 结构化输出问题的钥匙。

Deterministic 的部分:API 给你的硬保证

当你用 tool_use 而不是 prompt-based JSON 时,下面这些东西API 在底层强制保证

  • 返回的类型结构 ------一定是 tool_use block,一定包含你定义的字段
  • 字段类型 ------你定义 age: integer,绝不会收到字符串
  • enum 约束 ------你定义 status: enum["pending", "approved"],绝不会收到第三个值
  • required 字段一定存在(这点要小心,下面会讲为什么)
  • JSON 语法合法------不会出现缺括号、引号、逗号这种 prompt-based JSON 最常翻车的事故

API 在模型生成 tool_use 时强制 输出匹配 schema 的结构。如果模型试图输出不合规的内容,API 会限制 token 选择空间或重试(实现细节因模型而异),最终保证你拿到的 tool_use 一定符合 schema。这是 constrained sampling 或类似机制在底层做的事。

这是结构层的 deterministic 保证。你拿到的东西在格式上一定能 parse,一定符合契约。

Probabilistic 的部分:LLM 永远的命门

但有些东西,schema 锁不住------它们活在语义这一层,不是结构层:

字段值的语义对错。 age: 25 是合法 integer,但申请人真实年龄可能是 35。schema 不知道也管不了。

字段值的存在性。 如果字段是 required 但源文档里没这个信息,模型会编造一个值来满足 required 约束------这是大坑。schema 不会让模型说"我不知道",它只会让模型说"我必须给你一个 integer,那就给个看起来合理的"。这就是 fabrication 风险的根源。

跨字段一致性。 start_date: "2025-01-01"end_date: "2024-12-01" 各自合法,但语义上矛盾------结束日期早于开始日期。schema 拦不住。

复杂条件依赖。 比如"如果 employment_status=student,则 employer 字段应为空"------这种 schema 表达不了。

用一个例子把边界画出来

json 复制代码
tool_schema = {
    "name": "extract_application",
    "input_schema": {
        "type": "object",
        "properties": {
            "name": {"type": "string"},
            "age": {"type": "integer", "minimum": 18},
            "status": {"type": "string", 
                       "enum": ["full_time", "part_time", "contract"]}
        },
        "required": ["name", "age", "status"]
    }
}

Deterministic 给你的保证:

✅ 一定是 JSON object ✅ name 一定是 string ✅ age 一定是 ≥ 18 的 integer ✅ status 一定是三个 enum 值之一 ✅ 三个字段一定都存在

Deterministic 给不了的保证:

name 是不是真的从文档里读出来的(可能编造一个 "John Smith") ❌ age: 25 是不是申请人真实年龄 ❌ 文档里写 "intern" 时模型该选哪个 enum 值(可能瞎选 part_time) ❌ 文档没写 age 时------模型会编一个来满足 required 约束,绝不会拒绝输出

值得反复盯着看这两组对比。 上半部分是 API 帮你扛的,下半部分是你自己要扛的。

为什么 prompt-based JSON 是双重赌博

把 tool_use 跟其他常见做法摆在一起对比,你会看到一个很扎心的事实:

做法 JSON 合法性 Schema 合规 字段值正确
regex + retry 概率性 概率性 概率性
prompt + examples 概率性 概率性 概率性
两步法(先文本后格式化) 第一步概率性,第二步概率性 概率性 错误在两步间放大
tool_use Deterministic Deterministic 概率性(无解,所有方案都一样)

tool_use 把能 deterministic 的部分 全锁死了。剩下的概率性部分(值的正确性)是 LLM 本质问题,任何方案都解决不了 ------但 tool_use 至少保证了一件事:当值正确时,结构一定正确

其他三个方案有一个额外的失败模式: "值对了但格式炸了" 。模型明明把名字抽对了、年龄填对了,结果 JSON 多了个逗号,整条链路废掉。这种失败本来可以避免,prompt-based JSON 自找的。

Prompt-based JSON 等于在 LLM 本来就够难的概率性问题上,又叠加了一层完全可以消除的结构性失败模式。

"Most Reliable" 不等于 "Guaranteed Correct"

这里有个常被混淆的细节。tool_use 是最可靠 的抽取方案,但不是绝对可靠。这两个词不一样:

  • Most reliable = 在所有方案中失败模式最少
  • Guaranteed correct = 永远不出错(任何 LLM 系统都不可能做到)

tool_use 消除了结构性 失败(malformed JSON、错字段名、错类型、漏字段),保留了语义性失败(值不对)。

把这件事讲清楚很重要------很多人误以为切到 tool_use 就万事大吉了,实际上你只是把战场清理出来,让你只需要处理真正难的那部分问题

剩下那部分语义错误怎么办

结构层锁死之后,剩下的语义错误要用别的招数处理:

Optional / nullable 字段,消除 fabrication 压力。 如果 age 在源文档里可能没有,就不要把它设成 required。让模型可以返回 null,比让它编一个数字强一百倍。这是治 fabrication 的根本药。

Retry with error feedback,处理可恢复的语义错误。 抽出来的数字明显不对(比如 net 比 gross 大)?把错误信号回灌给模型让它重抽。这套路适合那些有明确校验规则的字段。

Human review routing,处理不可恢复的语义错误。 模型在不熟悉的语言、不熟悉的格式上信心很低时,与其硬抽不如直接路由到人工。Schema 上挂一个 confidence 字段,低于阈值就走人工。

Calculated vs stated 双字段,让一致性约束变成信号而非编造压力。 比如一个发票同时有"金额"和"单价 × 数量"两个来源,让模型分别抽出来,下游对账。这比让模型自己保证一致性可靠得多------你把矛盾点显式化了。

这套思路放大了看,是 agent 系统的基础姿势

结构 vs 语义的分工不只是 JSON 抽取的事,它是 agentic 系统设计的基础。

比如一个多 agent 系统里,SQLAgent 的输出能被下游 NLSummarizer 可靠消费,靠的是 tool_use 锁定的结构契约 ------SQL 字符串确实是 string,确实满足 required 字段。但 SQLAgent 是否真的写对了 SQL(join 对不对、where 条件对不对),那是 evaluation agent 或 critic agent 的活,不是 schema 能解决的。

每一层都只解决它该解决的问题:

  • Schema 解决结构
  • Constrained decoding 解决格式
  • Retry / critic 解决可恢复语义错误
  • Human review 解决不可恢复语义错误

把这几层混在一起想,就永远在打地鼠。分开,每一层用合适的工具,整个系统就清爽了。

一句话总结

tool_use 给的是结构层面的 deterministic 保证------schema 合规、类型正确、必填存在、JSON 合法。

值的语义正确性是 LLM 概率本质决定的,永远是概率性的。

但 tool_use 之所以是"most reliable",因为它把能锁死的全锁死了 ,把无法锁死的部分暴露在更高层级去处理------而 prompt-based JSON 在 LLM 已经够难的概率性问题上,又叠加了一层完全可以消除的结构性失败模式

这就是为什么遇到结构化输出问题,答案几乎永远是 tool_use 而不是更好的 prompt。Prompt 调得再精巧,也是在概率性的赌场里下注;tool_use 是直接把规则刻进游戏引擎里。

相关推荐
却尘1 小时前
你的 LLM 系统在偷偷出错,季度审计才发现:Stratified Sampling 这把刀治到根上
claude
Agent产品评测局2 小时前
传统RPAvsAI Agent,制造业生产场景能力对比详解 —— 2026企业级自动化选型全景盘点
运维·人工智能·ai·chatgpt·自动化
DogDaoDao2 小时前
【GitHub】Ruflo:面向 Claude Code 的企业级多智能体编排平台深度解析
人工智能·深度学习·大模型·github·ai编程·claude·ruflo
用户44871041161432 小时前
claude接入deepseek-api使用
claude
いNeil4 小时前
海外开发者注册验证码解决方案,适配 GPT、Codex 等第三方应用
gpt
数据法师4 小时前
Sora退场,GPT Image 2.0封神!免费不限次还支持中文!
人工智能·gpt·计算机视觉
2601_957780844 小时前
GPT-5.5时代:从“指令集“到“任务契约“的Prompt工程范式迁移
大数据·人工智能·gpt·架构·prompt
winlife_5 小时前
AI 怎么验证 Unity PlayMode 行为:截图 + 输入模拟的完整闭环
人工智能·unity·游戏引擎·ai编程·claude·playmode