2 minute read

“Imagination is the key ingredient to a happy life.” — Unknown

拆解大模型交付深水区:如何用 Schema 推理构建高确定性的 AI 工程体系

当你的 RAG 系统连最简单的财报数字都算不对时,问题往往不在向量检索,而在你给模型发放的那张“答题卡”。

现在AI FDE工程师的主要工作早已不是写复杂的prompt提示词,或者什么炫酷的loop engineering, graph, vibe coding。最核心的商业如何落地,如何解决用户的痛点,而不是“一杯正经的胡说八道”, 这里通过几个文章来深入探讨在AI项目落地时的一些技术,以及有志于走向AI FDE或者相关工作人员的技术指南。

🎯 周三下午四点的“对账危机”

周三下午四点,会议室的空气凝固了。

算法工程师小陈指着屏幕上的向量召回日志,嗓音有些沙哑:“检索召回率我们已经做到了 98%,上下文窗口里清清楚楚放着目标年度的 10-K 财报表格,切块没丢、嵌入模型没偏,这绝对不是 RAG 检索层的问题。”

负责业务交付的老林把打印出来的财报拍在桌上,脸色铁青:“客户要的是‘研发费用同比去年增长了百分之几’。财报上写着前年 4.2 亿、去年 5.1 亿,结果你们的智能问答助手直接吐出一个 {"value": 12.4%}。真实答案是 21.43%!客户在验收会上当场质问,我们算出来的数字到底有没有经过大脑?”

负责把模型输出对接进后级报表系统的晓峰也满肚子苦水:“我按前后端契约定义了 JSON Schema,要求大模型以标准 JSON 返回。为了让后端解析不出错,我强制要求模型只返回 valueunit 字段。后端接口一次都没有崩过,格式校验 100% 通过。”

三个人都做对了自己职责范围内的事:

  1. 小陈给出了精准的表格检索上下文。
  2. 晓峰给出了最严谨的强类型 API 接口定义。
  3. 老林坚守了金融交付必须分毫不差的业务底线。

没有任何人偷懒,也没有人写出低级 Bug。

但系统在生产环境里就是会一本正经地胡说八道。真正的问题不在检索,也不在提示词里有没有写“请仔细计算”,而在一个被绝大多数工程师忽视的底层物理定律——自回归语言模型的计算发生在哪里?


🧠 30 秒速览:两种 Schema 设计的本质代价

在大模型应用交付中,同样是定义 JSON 输出,字段的排列顺序决定了模型是“盲猜”还是“深思熟虑”。

方案类型 Schema 字段排列顺序 模型计算发生的位置 幻觉率 (数值计算类) 相对 Token 成本 延迟 (TTFT / 吞吐)
传统答案优先型 {"value": ..., "unit": ...} 零计算空间(被迫单步预测) 极高 (典型值 > 35%) 基准成本 (1x) 极快(首字即答案)
思维链前置型 {"reasoning": ..., "evidence": ..., "value": ...} 推理字段生成的几百个 Token 内 极低 (显著收敛) 增加 1.5x - 2.5x Output Tokens 延迟增加数百毫秒

📌 本节要点:大模型没有隐式“思考时钟”,它的所有推理算力都挂载在它吐出的每一个 Token 上。让最终答案先于推导过程输出,等于逼迫模型在毫无算力缓冲的情况下凭直觉押注。


💡 核心心智模型:不能打草稿的高考考生

想象你把一位数学系高材生送进考场,给他一张极其复杂的应用题卷子,但监考官提出了一个变态要求:

“你看到题目后,不允许在草稿纸上写任何辅助线、公式或中间变量。你握着笔,落下的第一个字符必须是最终的答案数字;写完数字之后,你才可以在后面补充理由。”

这位考生就算智商再高,面对多步四则运算、反向年份排布的财报表格,也只能靠视觉直觉“蒙”一个看起来很像的数字。

这就是晓峰一开始写的 Schema 对大模型做的事情。

大模型本质上是自回归的逐 Token 预测器(Autoregressive next-token predictor)。当你的 Schema 规定先输出 value 时,模型在吐出 {"value": " 之后,生成下一个 Token 的前向传播(Forward Pass)只有一层的计算预算。在这一瞬间,它必须依靠注意力机制从上下文里碰运气,直接跳到最终结果。

相反,如果 Schema 规定先输出 thought_processextracted_data,再输出 calculation_formula,最后才输出 value,模型在吐出最终数字时,前面所有的推导过程已经变成了它自回归注意力上下文的一部分。每一次前向传播都在消费前面推导出来的真实事实,计算精度自然产生代差。

📌 本节要点:大模型的输出序列不是单纯的数据承载器,它同时也是模型的动态计算图。字段的先后顺序,本质上是在编排模型的执行流水线。


🏗️ 机制深潜:Token 生成与注意力计算的交汇

我们把这两种机制放在 Transformer 的计算流中对比:

flowchart TD
    subgraph 错误模式:答案优先
    A1[Prompt + Context 财报数据] --> B1[强制生成 Schema: value]
    B1 -->|无中间状态,被迫一步跳跃| C1[幻觉高发: 12.4%]
    C1 --> D1[后续补充 explanation: 强行编造理由]
    end

    subgraph 正确模式:推理前置
    A2[Prompt + Context 财报数据] --> B2[Schema 引导: extracted_entities]
    B2 --> C2[提取 2023: 5.1亿 / 2022: 4.2亿]
    C2 --> D2[Schema 引导: calculation_steps]
    D2 --> E2[执行公式: 5.1-4.2 / 4.2 = 21.43%]
    E2 --> F2[输出 value: 21.43%]
    end

在底层实现上,诸如 JSON Mode 或 Structured Outputs 技术,是通过在采样阶段使用语法掩码(Grammar Masking / Constrained Decoding)来限制 logits 的分布。如果你把约束加在最前面,模型就会在狭窄的 token 路径里丧失探索空间。

🩸 血泪提醒:千万不要以为开启了云厂商提供的 response_format: { type: "json_object" } 就万事大吉。JSON 模式只保证语法合法(括号能闭合、键值对合法),绝对不保证语义正确。如果你在 Schema 第一行放最终枚举值或数值结果,Structured Outputs 只是用更强硬的语法约束把模型逼进幻觉死胡同。


🛠️ 交付修复:重构 Schema 与契约落地

回到周三下午的会议室。老林、小陈和晓峰围在白板前,决定推翻原本为了后级解析方便而设计的“扁平 Schema”,采用推理伴随式结构(Reasoning-embedded Schema)

晓峰掏出编辑器,将原本脆弱的 Pydantic 模型进行了彻底重构:

改造前的 Schema(埋下灾难种子)

from pydantic import BaseModel, Field

class FinancialMetricResponse(BaseModel):
    # 致命错误:第一步就索要最终答案
    value: float = Field(description="最终计算出的百分比数值")
    unit: str = Field(description="单位,如 %")
    summary: str = Field(description="简短总结")

改造后的 Schema(构建计算缓冲区)

from pydantic import BaseModel, Field
from typing import List

class ExtractedFact(BaseModel):
    metric_name: str = Field(description="指标名称")
    year: int = Field(description="对应年份")
    amount: float = Field(description="财报原文中的原始金额数值")
    source_sentence: str = Field(description="原文依据句子,用于溯源校对")

class FinancialAnalysisResponse(BaseModel):
    # 1. 强制第一步:定位锚点与原文提取(打草稿:事实对齐)
    grounding_facts: List[ExtractedFact] = Field(
        description="从上下文中精准抽取计算所需的所有基准数字"
    )
    # 2. 强制第二步:显式计算公式与中间推导(打草稿:逻辑推演)
    formula_applied: str = Field(
        description="使用的数学计算公式,如 '(current - previous) / previous'"
    )
    calculation_steps: str = Field(
        description="带入具体数字的详细四则运算步骤"
    )
    # 3. 最终收敛:经过前面几百个 Token 的算力铺垫,最后输出确定性结果
    final_value: float = Field(description="最终计算结果数值")
    unit: str = Field(default="%", description="结果单位")

小陈把这份新 Schema 接入 RAG Pipeline,重新跑了一遍老林挑剔的 50 份测试集:

在生成 final_value 之前,模型先老老实实输出了 grounding_facts,把前年 4.2 亿与去年 5.1 亿从表格切块中提取出来,接着在 calculation_steps 里写下了 (5.1 - 4.2) / 4.2 = 0.9 / 4.2 = 0.214285...。最终字段落下的数字,精准变成了 21.43

后级报表系统只需要在反序列化后读取 response.final_value,而 grounding_factscalculation_steps 还可以作为审计日志展示在 UI 的“引用推导”浮层中,让老林的业务客户一眼看到计算证据。

那天傍晚六点,老林在测试报告上签了字,晓峰提交了 Schema 变更 PR,那个导致会议室空气凝固的对账接口,在接下来的整个交付周期里一次都没有被客户报障过。


⚖️ 权衡取舍:什么时候不该用推理 Schema?

天下没有免费的午餐,将 Schema 改造为推理前置型体系必然引入新的系统开销:

  1. Token 成本增加:每个请求多消耗 150 到 400 个输出 Token。在每秒数千次调用的高并发低客单价场景下,API 账单会显著抬升。
  2. 首字/完成延迟上升:因为最终有效载荷在 JSON 的后半截,后级业务拿到 final_value 的时间变长,对实时流式 UI(Streaming UI)提出更高要求。
  3. 过度格式化退化:如果 Schema 层次嵌套过深(例如超过 4 层),小型模型(如 7B/8B 级别)可能会出现 JSON 语法截断或键名混淆。

适用边界矩阵:

  • 强烈推荐:数值计算、多源交叉验证、实体关系抽取、代码生成前置分析、合规审计判定。
  • 不建议使用:简单的文本分类(如情感分析正负向)、固定模式抽取(如单手机号提取)、超低延迟检索路由意图识别。

🛠️ 线上排障实战指南

常见异常现象 根因定位 立即执行的排障动作
格式合法,但数值逻辑自相矛盾 最终字段排在前面,模型在没有上下文缓冲时瞎猜。 调整 Pydantic 类中字段顺序,将 reasoning / facts 放到最上方。
小型开源模型输出 JSON 经常被截断 max_tokens 被前面的推理消耗殆尽,没能吐出结尾闭合括号。 max_tokens 放大至预期值的 2 倍,或精简推理步骤的 description。
模型在推理字段中编造原文不存在的数据 没有显式要求“原文精准引用(Exact Match)”。 在子字段增加 source_quote 约束,提示词加入“未在正文出现的数值必须标记为 null”。
JSON Schema 校验偶发失败 提示词与 Schema 定义产生字段名歧义。 移除 Prompt 中手写的 JSON 样例,完全交由工具链生成的原生 JSON Schema 驱动。

🧭 升维认知:从大模型交付推演系统设计定律

在这场小小的接口重构背后,其实隐藏着超越 LLM 技术本身的通用系统工程法则:

1. 状态物化决定计算上限

  • 底层机制:无状态系统无法完成跨步复杂推演,算力的大小取决于系统能保留多少可回溯的中间物化状态。大模型的自回归 Token 序列就是它的物理内存。
  • 跨领域映射:现代外科手术中,主刀医生在切除复杂病灶前必须先进行“解剖标志物染色”与“多点位止血探查”,把隐蔽的神经血管走向变成视野中清晰可见的实体状态。没有前面的物化铺垫,盲切的致残率必然飙升。

    举一反三:在设计长流程分布式事务或复杂审批系统时,先问自己:下游节点是否被迫在无中间物化状态的前提下做出不可逆决策?

2. 界面顺序即执行流编排

  • 底层机制:在声明式系统与序列化系统中,数据的表达拓扑天然定义了执行者的注意力时序与资源调度路径。界面的声明顺序绝不仅仅是元数据,它就是控制流。
  • 跨领域映射:民航客机的起飞检查单(Pre-flight Checklist)永远严格遵循“从仪表盘顶部到底部、从电气到机械”的物理扫描动线,绝不会把“确认起飞动力”这项最终核准放在第一行。检查单的排布顺序就是防呆机制本身。

    举一反三:检查你的 API 契约与前端输入表单,核心决策字段是否过早暴露在依赖项校验就绪之前?

3. 审计痕迹必须是副产物而非附加物

  • 底层机制:后置补写的日志与解释大多是基于结果的“马后炮式合理化”(Post-hoc Rationalization)。真正高可信的审计轨迹,必须直接诞生在产生结果的核心计算路径上。
  • 跨领域映射:现代复式记账法(Double-entry bookkeeping)之所以统治金融系统数百年,是因为每一笔借贷资产的变化自身就包含了资金来源与去向的双向路径,而不是交易完成后由会计额外写一份主观回忆录。

    举一反三:系统中的排障 Trace 与操作审计,是业务代码流转过程中的自然投影,还是出事之后临时打桩的补丁?


🏁 明天早会就能落地的行动项

  1. 全局审查现有 Schema:打开你们后端代码里的 Pydantic 模型或 JSON Schema,搜索所有包含数值计算、逻辑判断的核心接口,检查 result / answer / status 字段是否被写在了第一行。
  2. 在测试环境进行一次“字段对调实验”:挑出 20 个历史幻觉 Case,仅仅把 explanation 提到 result 之前,在不改变 Prompt 的情况下对比两者的准确率差异。
  3. 与业务交付同学拉齐认知:在明天的早会上,向交付团队展示推导步骤在前端可视化后的“证据链”,把为了消除幻觉增加的 Token 消耗,转化为客户愿意买单的“透明可解释性”。

思维走过的路径,就是系统确定的边界。不要指望一个没有打过草稿的系统,能在终局给出现实世界的标准答案。

Updated: