1. 当概率正确成为工程瓶颈为什么我们需要一个编译器过去两年我参与过好几个把大模型能力嵌进生产系统的项目。最开始大家都很兴奋觉得只要提示词写得够好模型就能稳定输出想要的结果。但真正上线跑一段时间之后几乎每个团队都会撞上同一堵墙同一个输入今天对明天错换个措辞又错。你没法跟业务方解释这个功能有 92% 的概率是对的因为业务方要的是 100% 可交付。这就是标题里说的赌 AI 的正确率。所谓赌本质上是把系统的确定性寄托在模型的随机采样上。温度调低一点、加几个 few-shot 例子、再套一层自我校验正确率能从 80% 提到 95%但那剩下的 5% 依然像定时炸弹。更麻烦的是这 5% 的失败往往不是均匀分布的它集中在边界情况、长尾输入、格式稍微变一变的场景里而这些恰恰是生产环境里最容易出问题的地方。所以当我看到造了一个编译器这个说法时第一反应是这个思路对味了。编译器的核心价值从来不是让源代码跑得更准而是把一种不确定的、人类友好的表达翻译成一种确定的、机器可执行的表达。如果能把 AI 的输出从一段可能对也可能错的自然语言变成一段经过校验、结构确定的中间表示那正确率这件事就从赌变成了验证。这篇文章我想聊的不是某个具体产品的使用手册而是这类AI 编译器背后的完整思路它到底编译了什么、为什么编译能解决正确率问题、中间表示该怎么设计、校验层要卡在哪几个位置、以及我在实际落地时踩过的那些坑。如果你正在做 AI 应用、正在被输出稳定性折磨或者只是好奇编译器这个老概念怎么套到新问题上这篇应该能给你一些能直接抄的作业。2. 拆解AI 编译器它到底把什么编译成了什么2.1 传统编译器的三段式为什么能直接迁移过来先回忆一下传统编译器在干什么。前端做词法分析和语法分析把源代码变成抽象语法树AST中端做优化和变换把 AST 转成中间表示IR后端做代码生成把 IR 变成目标机器的指令。整条链路的核心思想是每一段都只对自己那一层的正确性负责层与层之间用严格定义的接口隔开。把这个结构套到 AI 应用上映射关系其实非常自然。前端对应的是把用户的自然语言需求解析成结构化的意图中端对应的是对意图做校验、补全、消歧、优化后端对应的是把校验过的意图生成最终可执行的产物——这个产物可能是一段代码、一个 API 调用序列、一份配置文件或者一段结构化数据。关键在于传统编译器里前端解析出来的 AST 是可以被程序检查的。你可以写一个 visitor 遍历它检查类型是否匹配、变量是否声明。而如果我们让 AI 直接输出最终产物中间没有任何可检查的结构那就只能靠再问一遍 AI 对不对来校验这又回到了赌正确率的老路。2.2 中间表示IR才是这套方案的心脏我越来越觉得做 AI 应用和做编译器最大的共同点是中间表示设计得好不好决定了整个系统的上限。IR 设计得好校验逻辑就能写得干净、覆盖全面IR 设计得烂校验层就会变成一堆 if-else 的泥潭。那 AI 场景下的 IR 应该长什么样我的经验是它至少要满足三个条件。第一结构是封闭的也就是说所有可能的字段、所有可能的取值都在一个预先定义好的 schema 里不允许模型自由发挥新增字段。第二语义是无歧义的同一个意思只有一种表达方式不能出现删除和移除两种写法。第三可静态检查不依赖运行就能判断出大部分错误比如引用了不存在的变量、参数类型不匹配、必填字段缺失。举个具体的例子。假设你要做一个根据自然语言生成数据处理脚本的功能。如果直接让模型输出 Python 代码那校验就只能靠跑一遍看报不报错甚至跑通了结果也可能是错的。但如果先让模型输出一个 IR比如{ operation: filter, source: orders, condition: { field: amount, operator: greater_than, value: 1000 } }那校验层就可以做很多事检查source是否在已知的数据源列表里、operator是否是允许的枚举值、value的类型是否和field的声明类型匹配。这些检查全是确定性的不涉及任何模型调用跑一次几毫秒而且结果 100% 可靠。2.3 编译和让 AI 更准是两件不同的事这里有个认知上的分水岭我想单独强调一下。很多人一遇到 AI 输出不准第一反应是去优化模型——换更大的模型、调更好的提示词、加更多的示例。这条路不是不能走但它有个天花板你永远无法把概率模型的错误率降到零。而编译器的思路是我不指望模型一次就对我指望的是模型的错误能被我的校验层抓住。模型输出 IR校验层检查 IR检查不过就打回去让模型重试或者直接报错给用户。这样一来系统的整体正确率不再等于模型的单次正确率而是等于模型在 N 次重试内输出合法 IR 的概率。只要单次合法率不是低得离谱重试几次之后整体正确率就能逼近 100%。我实测过一个场景模型单次输出合法 IR 的概率大概在 85% 左右允许重试 3 次整体成功率能到 99.9% 以上。这个数字放在生产环境里才算是能跟业务方交代的。3. 从自然语言到结构化 IR前端解析的实操细节3.1 意图识别和槽位填充别一上来就上大模型前端解析这块我的建议可能有点反直觉不要所有东西都交给大模型。很多团队一上来就让模型端到端地输出完整 IR结果发现模型在小事上特别容易翻车比如把日期格式搞错、把数字和字符串搞混。更稳的做法是分层。第一层用规则或者小模型做意图分类判断用户这句话属于哪一类操作第二层针对每一类操作用专门的提示词做槽位填充。这样做的好处是每一类的提示词可以写得很聚焦模型不需要同时处理理解意图和提取参数两件事出错率会明显下降。我做过一个对比同样是提取时间范围这个槽位端到端提示词的准确率大概 78%而拆成先判断有没有时间意图再专门提取时间两步之后准确率能到 94%。多花的那点调用成本完全值得。3.2 提示词里必须写死的几条约束写前端解析的提示词时有几条约束我建议你直接抄进模板里它们能挡掉大量低级错误。输出必须是纯 JSON不要有任何解释性文字。模型很爱在 JSON 前后加一句好的这是结果这会让下游解析直接崩掉。枚举字段只能从给定列表里选并且把列表完整列在提示词里。不要让模型自己发明取值。缺失的字段用 null不要省略。省略字段会让 schema 校验变得复杂统一用 null 表示没提取到校验逻辑会干净很多。数字就是数字不要加引号。这个坑我踩过模型有时候会把1000输出成1000类型校验直接挂掉。提示这些约束最好在提示词里用必须禁止这种强语气写并且配上正反例。实测下来带反例的提示词比只讲规则的提示词合法输出率高 10 个百分点以上。3.3 解析失败时的降级策略前端解析不可能 100% 成功关键是失败之后怎么办。我的做法是分三级降级。第一级如果模型输出的 JSON 解析失败先做一次修复性重试把原始输出和错误信息一起喂回去让模型自己修。第二级如果重试还是失败就退回到一个更宽松的解析器比如用正则去捞关键字段能捞多少算多少。第三级如果连关键字段都捞不到就直接返回一个明确的无法理解错误让用户重新表述。这里有个细节降级路径一定要有日志。我见过太多团队降级逻辑写了但没埋点结果线上出了问题根本不知道有多少请求走了降级。我的习惯是每一级降级都打一个带 request_id 的日志每周拉一次数据看降级率降级率一涨就说明提示词或者模型该调了。4. 校验层怎么设计把赌变成查4.1 静态校验不跑代码就能挡掉八成错误校验层的第一道关是静态校验也就是不执行任何实际操作纯粹检查 IR 本身是否合法。这部分能挡掉的错误比例高得惊人我统计过自己的项目大概 80% 的模型错误在这一关就被拦下了。静态校验具体查什么我列一个清单你可以对照着建自己的校验规则。校验类型检查内容典型错误Schema 校验字段是否存在、类型是否正确把数字写成字符串枚举校验取值是否在允许列表内操作符写成gt而不是greater_than引用校验引用的资源是否存在引用了不存在的数据表类型一致性字段类型和操作是否匹配对字符串字段做数值比较必填校验必填字段是否为空缺少 source 字段范围校验数值是否在合理区间分页大小写成 100000这张表里的每一条实现起来都不复杂但组合起来威力很大。关键是校验规则要集中管理不要散落在各个业务代码里。我的做法是单独建一个校验模块所有规则注册进去IR 进来之后统一跑一遍返回一个错误列表。这样加规则、改规则都只动一个地方。4.2 语义校验静态查不出来的那些坑静态校验能查格式对不对但查不出意思对不对。比如用户说把上个月的订单按金额排序模型输出的 IR 里时间范围写成了上上个月格式完全合法但语义错了。这类错误就得靠语义校验。语义校验怎么做我的经验是把能确定的语义约束显式写出来。比如时间范围可以校验开始时间是否早于结束时间、是否在合理的历史区间内。比如排序字段可以校验它是否真的存在于目标数据源里。这些约束本质上还是确定性的检查只是需要一点领域知识。还有一类语义错误更隐蔽就是模型过度理解。用户说帮我看看最近的销售情况模型可能自作主张地加了一堆过滤条件。这种错误静态和语义校验都查不出来只能靠回显确认——把解析出来的 IR 用自然语言翻译回去给用户看让用户确认。这一步虽然多了一次交互但在高风险操作上非常值得。4.3 重试机制怎么重试才不浪费 token校验不通过就要重试但重试不是简单地把同样的提示词再发一遍。那样做模型很可能犯同样的错误。有效的重试必须把错误信息带回去。我的做法是校验层返回的错误列表会格式化成一个简短的说明附在重试提示词里比如上次输出中 operator 字段的值gt不合法合法值包括 greater_than、less_than、equal_to。模型看到具体错在哪修正的概率会高很多。重试次数也要控制。我的经验是最多重试 2 到 3 次再多的话要么是提示词本身有问题要么是这个输入超出了模型能力范围继续重试只是浪费钱。重试的时候可以适当降低温度让输出更保守一些。注意重试的提示词里不要带完整的对话历史只带原始输入、上次输出和错误信息就够了。带太多历史会让模型分心反而更容易出错。5. 后端生成从 IR 到最终产物的最后一公里5.1 代码生成用模板不要用模型IR 校验通过之后最后一步是生成最终产物。这一步我的建议非常明确能用模板就用模板不要让模型再生成一遍。因为 IR 已经是结构化的了把它映射成代码、配置或者 API 调用本质上是一个确定性的转换用模板引擎比如 Jinja2就够了又快又稳。我见过一些团队IR 校验通过之后又让模型根据 IR 生成代码结果模型在生成代码的时候又引入了新的错误。这完全是多此一举。IR 存在的意义之一就是把需要模型发挥的部分和纯机械转换的部分隔开后端就该是纯机械的。5.2 生成产物的二次校验即便是模板生成的产物上线前也建议做一次二次校验。比如生成的是 SQL可以用 SQL 解析器检查语法生成的是 API 调用序列可以检查调用顺序和依赖关系。这一步相当于编译器的后端优化 验证能挡住模板本身写错导致的 bug。二次校验还有个好处就是能发现 IR 设计上的缺陷。如果某个 IR 结构总是导致模板生成出问题那说明这个 IR 的设计需要调整。这种反馈循环是让整套系统越用越稳的关键。5.3 执行前的沙箱和权限控制如果最终产物是要真正执行的比如跑一段代码、调一个写接口那执行前一定要有沙箱和权限控制。这部分不是 AI 特有的问题但 AI 场景下尤其重要因为输入是不可控的自然语言你没法预判用户会说出什么。我的做法是所有生成的产物先在一个受限环境里试跑确认没有副作用之后再放到正式环境。权限方面IR 里涉及的操作要映射到具体的权限点用户没有权限的操作直接在校验层就拒掉不要等到执行的时候才报错。6. 实战中踩过的坑那些文档不会告诉你的细节6.1 模型对否定和例外的处理特别弱这是我踩得最狠的一个坑。用户说查一下除了北京以外的所有订单模型经常把除了漏掉直接输出查北京订单。静态校验完全查不出来因为 IR 格式完全合法。后来我的解决办法是在提示词里专门针对否定词做强化把除了不包括排除非这些词单独列出来要求模型遇到这些词必须生成对应的 exclude 字段。同时在语义校验里加一条如果原始输入里出现了否定词但 IR 里没有 exclude 相关字段就判定为可疑触发回显确认。6.2 多轮对话里的 IR 合并是个大麻烦单轮解析相对好做多轮就麻烦了。用户先说查一下上个月的订单然后说再加上金额大于 1000 的条件。第二句话的 IR 是增量式的需要和第一句的 IR 合并。合并逻辑写不好就会出现条件覆盖、字段冲突各种问题。我的经验是多轮场景下不要做 IR 合并而是做IR 重写。也就是每一轮都把完整的历史对话重新解析一遍生成一个全新的完整 IR。这样做虽然多花一点 token但逻辑简单太多不会出现合并冲突。实测下来重写的稳定性远高于合并。6.3 别忽视空输入和超长输入空输入和超长输入是两个极端但都特别容易出问题。空输入的时候模型有时候会硬编一个 IR 出来而不是老老实实说没听懂。超长输入的时候模型容易丢失中间的信息只处理开头和结尾。针对空输入我的做法是在前端加一个长度检查太短的输入直接走规则匹配不进模型。针对超长输入做分块处理每块单独解析最后再合并意图。这两个处理都不复杂但能挡掉不少莫名其妙的线上问题。6.4 校验规则本身也会过拟合这是个比较隐蔽的坑。校验规则写多了之后你会发现有些规则开始误伤合法输入。比如你为了挡住某个错误加了一条很严的规则结果把一些本来合法的边界情况也挡了。我的应对办法是每一条校验规则都要有对应的测试用例包括正例和反例。加规则的时候先跑一遍全量测试用例确认没有误伤再上线。另外校验失败率这个指标要持续监控如果某条规则的失败率突然飙升很可能就是它误伤了。7. 什么场景适合上这套方案什么场景别硬套7.1 适合的场景输出结构固定、错误代价高这套方案不是万能的。它最适合的场景有两个特征输出结构相对固定以及错误代价高。比如生成数据库查询、生成 API 调用、生成配置文件、生成工单流转指令这些场景输出结构清晰一旦出错后果严重用编译器思路来做非常划算。反过来如果是开放式创作类的场景比如写文案、写故事输出本来就没有唯一正确答案那硬套 IR 和校验层就是自找麻烦。这类场景该用模型就用模型正确率本来就不是核心指标。7.2 成本账要算清楚上这套方案是有成本的。前端要写提示词、要维护 schema中端要写校验规则后端要写模板整体开发量比直接调模型大不少。所以上线之前一定要算账这套方案挡掉的错误值不值这些开发成本。我的经验是如果这个功能每天调用量在几百次以上或者单次错误的业务代价很高比如涉及资金、涉及数据安全那这套方案绝对值得。如果只是内部工具、调用量很小那可能先用简单的提示词工程顶着等量上来了再重构。7.3 渐进式落地别想着一口吃成胖子最后说个落地节奏的问题。我见过一些团队一上来就想把整套编译器架构搭全结果做了两个月还没上线。更稳的做法是渐进式先做前端解析和静态校验把最明显的错误挡住这一步就能解决大部分问题。跑一段时间看看剩下的错误都是什么类型再针对性地加语义校验和重试机制。这样每一步都有可衡量的收益也不会因为架构太复杂而拖慢上线。我自己做的时候第一版只做了 schema 校验错误率就从 15% 降到了 6%加上重试之后降到 1% 以下再加上语义校验才做到 0.1% 这个量级。每一步的投入产出比都很清楚。这套东西做下来我最大的体会是AI 应用要做得稳靠的不是让模型更聪明而是让系统更严谨。模型负责把模糊的人类表达翻译成结构化的意图剩下的交给确定性的代码去校验、去生成、去执行。把这两件事分开正确率就不再是一个需要赌的东西而是一个可以被工程手段保证的指标。这个思路我觉得在接下来很长一段时间里都会是 AI 落地的主流打法。