资讯动态

大模型写业务逻辑总翻车?用JSON做中间层让代码不再乱编

发布时间:2026/10/18 18:43:33 来源:尧图企业网站定制
1. 从“代码乱编”说起为什么大模型写业务逻辑总翻车用大模型写代码这件事很多人应该都经历过一个相似的曲线一开始觉得惊艳让它写个排序、写个正则、写个工具函数又快又好用着用着就发现不对劲了一旦让它写稍微复杂一点的业务逻辑比如订单状态流转、审批链路、计费规则它就开始“自由发挥”——明明需求里说的是“满三件打八折”它给你写成“满三件减八折”明明状态机只有四个状态它硬生生给你多编出两个不存在的状态。我自己在这个坑里趴了很久。最开始我以为是提示词写得不够细于是把需求文档整段整段贴进去结果模型确实“听话”了但代码变得又臭又长一个简单的折扣计算能给你写出两百行里面还夹杂着它自己臆想的边界条件。后来我又怀疑是模型能力不够换了几个参数更大的模型情况好了一点但本质问题没解决——只要业务逻辑是用自然语言描述的模型就一定会“脑补”因为自然语言本身就有歧义而代码是零歧义的。这个项目标题里说的“把业务逻辑写成 JSON”本质上就是在解决这个“脑补”问题。它的核心思路是不要让模型直接写代码而是让模型把业务逻辑翻译成一份结构化的 JSON 描述再由一个固定的、经过测试的“执行引擎”去解释这份 JSON。模型只负责“翻译”不负责“执行”这样它的发挥空间被压缩到最小乱编的概率就大幅下降。这套思路适合谁呢我觉得有三类人特别值得看第一类是正在做 AI 辅助编码工具的人你们肯定被“模型输出不稳定”折磨过第二类是做低代码/无代码平台的业务逻辑的配置化本来就是你们的刚需第三类是做规则引擎、工作流引擎的开发者JSON 描述业务逻辑这件事你们可能已经在做了但未必想过把它和大模型结合起来。接下来我会把这套方案的来龙去脉拆开讲包括为什么选 JSON 而不是别的格式、JSON 的结构怎么设计、执行引擎怎么写、模型提示词怎么调以及我在实操中踩过的那些坑。2. 为什么是 JSON结构化描述业务逻辑的选型逻辑2.1 自然语言到代码之间缺一个“中间层”大模型直接生成代码本质上是在做“自然语言 → 编程语言”的端到端翻译。这个翻译链条太长了中间要经过语义理解、逻辑推理、语法组织、API 调用等多个环节任何一个环节出偏差最终代码就是错的。而且代码一旦错了你很难定位到底是哪一步理解错了。引入 JSON 作为中间层相当于把这条长链条切成两段第一段是“自然语言 → JSON”第二段是“JSON → 执行结果”。第一段由模型完成第二段由确定性程序完成。模型只需要保证 JSON 的结构和字段填对不需要关心最终怎么执行。这就好比你去餐厅点菜你只需要在菜单上勾选“宫保鸡丁、微辣、不要花生”厨房怎么炒那是厨房的事你不需要写一份炒菜教程给厨师。这个“中间层”的选择很关键。它必须满足几个条件模型容易生成、人类容易阅读、程序容易解析、结构足够表达复杂逻辑。JSON 恰好全部满足。2.2 JSON、YAML、DSL、SQL 的对比我试过用不同的格式来做这个中间层这里把对比结果列出来方便你选型。格式模型生成友好度人类可读性程序解析难度表达复杂逻辑能力我的评价JSON高中低中高综合最优推荐YAML中高中中高缩进容易出错模型经常搞乱层级自定义 DSL低高高高需要额外训练模型成本太高SQL中中低中只适合数据查询类逻辑不适合流程控制XML低低中中高太啰嗦模型容易漏闭合标签JSON 最大的优势是“模型见过得多”。几乎所有大模型的训练数据里都有海量 JSON它们对 JSON 的括号、引号、逗号规则非常熟悉生成时的语法错误率明显低于 YAML 和 XML。而且 JSON 的解析库在所有编程语言里都是标配你不需要引入任何额外依赖。YAML 虽然人类读起来更舒服但模型在生成多层级嵌套时经常把缩进搞错尤其是当逻辑分支比较多的时候它会把某个字段错误地缩进到上一层导致整个结构语义变了。我在这上面吃过亏后来果断换回 JSON。自定义 DSL 听起来很美好但你需要让模型学会你的 DSL 语法要么在提示词里写很长的语法说明要么做微调。前者占用大量上下文窗口后者成本太高。对于大多数团队来说不值得。2.3 执行引擎的确定性是这套方案的命根子选 JSON 只是第一步真正让这套方案成立的是“执行引擎的确定性”。什么意思呢就是同一份 JSON不管执行多少次结果必须完全一样。这就要求执行引擎里不能有任何随机性、不能依赖外部不确定的状态、不能有隐式的类型转换。举个例子JSON 里写{action: discount, threshold: 3, rate: 0.8}执行引擎读到这个节点时必须严格按照“数量大于等于 3 时价格乘以 0.8”来执行不能因为今天是周末就给你打个额外的折。这种确定性是模型直接生成代码时很难保证的因为模型每次生成的代码可能都不一样但 JSON 一旦确定执行结果就确定了。这也是为什么我说“大模型终于不乱编代码了”——不是模型变聪明了而是我们把它的输出限制在了一个它不容易犯错的范围内。3. JSON 业务逻辑的结构设计字段、类型与嵌套规则3.1 一个最小可用的 JSON 逻辑描述长什么样先看一个最简单的例子假设我们要描述“订单满三件打八折”这个逻辑{ version: 1.0, type: discount_rule, conditions: [ { field: item_count, operator: gte, value: 3 } ], actions: [ { type: multiply, target: total_price, factor: 0.8 } ] }这份 JSON 里conditions是一个数组表示“与”关系所有条件都满足时才触发actions。operator支持gte大于等于、lte小于等于、eq等于、neq不等于、in在集合中等。actions也是数组表示按顺序执行。这个结构看起来很简单但它已经能表达很多常见的业务规则了。关键是模型生成这份 JSON 的难度远低于生成一段等效的代码。模型只需要理解“满三件”对应item_count 3“打八折”对应total_price * 0.8然后按照固定的字段名填进去就行。3.2 条件组合与、或、非怎么表达现实业务里条件很少是单一的“与”关系。比如“新用户首单满 100 减 20或者老用户积分超过 500 也可以享受”这里就有“或”的关系。我的做法是用嵌套结构来表达{ type: discount_rule, conditions: { logic: or, children: [ { logic: and, children: [ {field: user_type, operator: eq, value: new}, {field: order_amount, operator: gte, value: 100} ] }, { field: user_points, operator: gt, value: 500 } ] }, actions: [ {type: subtract, target: total_price, value: 20} ] }这里用logic字段表示当前节点的逻辑关系children是子条件。叶子节点就是具体的字段比较。这种递归结构可以表达任意复杂的布尔逻辑而且模型很容易理解——它只需要知道“or 就是任意一个子条件为真”“and 就是所有子条件为真”。注意不要让模型生成太深的嵌套。我实测下来超过四层的嵌套模型出错的概率会明显上升。如果业务逻辑真的很复杂建议拆成多条规则用优先级或顺序来组合。3.3 动作类型不只是加减乘除动作actions是 JSON 里真正“干活”的部分。除了基本的算术运算我还定义了这些动作类型set给某个字段赋值multiply乘以一个系数subtract减去一个数值add加上一个数值assign_coupon发放优惠券change_status变更状态send_notification发送通知call_webhook调用外部接口每个动作类型都有固定的参数字段。比如change_status需要from和to两个字段send_notification需要template_id和recipient。这些字段名和类型在执行引擎里是硬编码的模型只需要按照模板填就行。这里有个经验动作类型不要设计太多控制在 15 个以内。太多了模型记不住容易混用。我一开始设计了三十多种动作结果模型经常把subtract和deduct搞混后来砍到 12 种准确率立刻上来了。3.4 版本控制与向后兼容JSON 结构一旦上线就会有历史数据。你不可能每次改结构都让所有历史 JSON 重新生成一遍。所以我在 JSON 里加了version字段执行引擎根据版本号走不同的解析分支。比如 v1.0 里折扣字段叫ratev2.0 里改叫factor执行引擎读到 v1.0 的 JSON 就用rate读到 v2.0 就用factor。这样老数据不用动新数据用新结构。提示版本号建议用主版本.次版本的格式。主版本变更表示不兼容的结构调整次版本变更表示新增字段但兼容旧结构。执行引擎只需要判断主版本号。4. 执行引擎的实现从 JSON 到可运行逻辑4.1 引擎的整体架构执行引擎的核心就是一个递归解释器。它接收一份 JSON 和一份上下文数据比如订单信息、用户信息然后按照 JSON 里的描述去操作上下文数据最后返回结果。整体流程分三步解析阶段读取 JSON校验结构和字段类型构建内部的对象树。条件评估阶段从根节点开始递归评估条件树判断当前规则是否命中。动作执行阶段如果条件命中按顺序执行动作列表修改上下文数据。这三步是严格分开的。解析阶段不涉及任何业务数据只做结构校验条件评估阶段只读不写动作执行阶段才写数据。这样设计的好处是如果 JSON 结构有问题在解析阶段就能发现不会等到执行到一半才报错。4.2 条件评估的递归实现条件评估的核心是一个递归函数伪代码如下def evaluate_condition(node, context): if logic in node: results [evaluate_condition(child, context) for child in node[children]] if node[logic] and: return all(results) elif node[logic] or: return any(results) elif node[logic] not: return not results[0] else: field_value get_field_value(context, node[field]) return compare(field_value, node[operator], node[value])get_field_value支持点号路径比如user.profile.level可以取到嵌套字段。compare函数根据操作符做比较注意类型要匹配——如果字段是数字值也必须是数字不能拿字符串去比。注意in操作符的值必须是一个数组eq操作符的值可以是任意类型。模型有时候会把in的值写成单个值这时候解析阶段要报错不能默默容忍。4.3 动作执行的顺序与副作用动作执行是按数组顺序来的前一个动作的结果会影响后一个动作。比如先subtract减掉优惠金额再multiply打折顺序不同结果完全不同。所以 JSON 里actions数组的顺序就是执行顺序不能乱。有些动作有副作用比如send_notification会真的发通知call_webhook会真的调外部接口。这些动作在执行引擎里要做幂等处理避免重复执行。我的做法是给每个动作加一个id字段执行前先查一下这个id有没有执行过执行过就跳过。{ type: send_notification, id: notify_001, template_id: order_discount, recipient: user_123 }这个id由模型生成但模型可能会生成重复的id。所以执行引擎里还要做一层去重如果发现同一个id在同一个上下文里出现多次只执行第一次。4.4 错误处理与回滚执行过程中如果某个动作失败了怎么办比如call_webhook超时了或者change_status的目标状态不存在。我的策略是整个规则要么全部执行成功要么全部回滚。实现方式是在执行前对上下文做一次快照执行过程中如果任何动作抛异常就用快照恢复上下文然后返回错误信息。这样不会出现“扣了钱但没发货”这种半吊子状态。提示快照不需要深拷贝整个上下文只需要记录被修改过的字段的原始值。这样性能更好尤其是上下文很大的时候。5. 提示词工程让模型稳定输出合规 JSON5.1 系统提示词的结构让模型生成 JSON 而不是代码提示词的设计很关键。我的系统提示词分四段第一段是角色定义“你是一个业务逻辑翻译器负责把自然语言描述的业务规则翻译成 JSON 格式的逻辑描述。”第二段是 JSON Schema 说明把支持的字段、类型、操作符、动作类型全部列出来并给出每个字段的示例值。第三段是输出格式要求“只输出 JSON不要输出任何解释性文字。JSON 必须符合以下结构……”第四段是几个 Few-shot 示例每个示例包含一段自然语言描述和对应的 JSON。这四段缺一不可。尤其是 Few-shot 示例对输出稳定性的提升非常明显。我试过去掉示例模型生成 JSON 的字段名错误率会上升三成左右。5.2 Few-shot 示例的选择技巧示例不要随便选要覆盖你业务里最常见的几种逻辑模式。我的示例集里包含单一条件的折扣规则多条件“与”组合的规则多条件“或”组合的规则带状态变更的规则带通知动作的规则每个示例都尽量简短控制在 20 行 JSON 以内。太长的示例会占用大量上下文窗口而且模型可能会过度模仿示例的细节导致泛化能力下降。注意示例里的字段值要用占位符比如value: 3而不是value: 具体数字。这样模型学到的是结构而不是具体的数值。5.3 输出校验与自动重试即使提示词写得再好模型偶尔还是会输出不合规的 JSON。所以我在调用模型之后加了一层校验用 JSON 解析器尝试解析如果解析失败直接重试。解析成功后用 JSON Schema 校验结构和字段类型如果不合规把错误信息拼回提示词里让模型重新生成。如果连续三次都不合规就降级到人工处理。这个重试机制很关键。我统计过第一次生成的不合规率大概在 8% 左右加上重试之后最终不合规率降到 0.5% 以下。5.4 温度参数与采样策略生成 JSON 的时候温度参数要调低。我一般设在 0.1 到 0.3 之间。温度太高模型会“创造性”地发明新字段温度太低模型会变得死板遇到没见过的逻辑模式容易卡住。另外我建议开启“JSON 模式”如果模型支持的话。这个模式会强制模型输出合法的 JSON省掉很多解析失败的麻烦。不过要注意JSON 模式只保证语法合法不保证语义正确所以 Schema 校验还是不能省。6. 实操案例从需求描述到可执行 JSON 的完整过程6.1 需求描述假设我们有一个电商场景需求是这样的“用户下单时如果订单金额满 200 元且用户是黄金会员可以享受 9 折优惠如果订单金额满 500 元不管是不是会员都可以享受 8.5 折优惠。优惠不能叠加取最大折扣。折扣后如果金额仍然满 300 元送一张 50 元优惠券。”6.2 人工拆解逻辑先把这个需求拆成规则规则 A订单金额 200 且 用户等级 黄金 → 打 9 折规则 B订单金额 500 → 打 8.5 折规则 C折扣后金额 300 → 送 50 元优惠券规则 A 和 B 互斥取折扣力度大的那个。规则 C 在折扣之后判断。6.3 模型生成的 JSON把需求描述和拆解逻辑一起给模型它生成的 JSON 如下{ version: 1.0, type: pricing_rule, rules: [ { id: rule_a, priority: 1, conditions: { logic: and, children: [ {field: order_amount, operator: gte, value: 200}, {field: user_level, operator: eq, value: gold} ] }, actions: [ {type: multiply, target: final_price, factor: 0.9} ] }, { id: rule_b, priority: 2, conditions: { field: order_amount, operator: gte, value: 500 }, actions: [ {type: multiply, target: final_price, factor: 0.85} ] }, { id: rule_c, priority: 3, conditions: { field: final_price, operator: gte, value: 300 }, actions: [ {type: assign_coupon, coupon_value: 50, recipient: current_user} ] } ], conflict_resolution: max_discount }这里我加了一个conflict_resolution字段告诉执行引擎当多条规则同时命中时怎么处理。max_discount表示取折扣最大的那条其他规则忽略。6.4 执行引擎的处理过程执行引擎拿到这份 JSON 后先按priority排序priority 小的先评估。评估 rule_a如果条件命中记录折扣 0.9。评估 rule_b如果条件命中记录折扣 0.85。根据conflict_resolution选择折扣最大的 0.85应用到final_price。评估 rule_c如果final_price仍然 300执行assign_coupon。整个过程完全确定同样的输入永远得到同样的输出。模型只负责把需求翻译成 JSON不参与执行所以不会“乱编”。6.5 实测效果对比我拿同一个需求分别让模型直接生成代码和生成 JSON各跑了 50 次统计结果如下方式语法错误率逻辑错误率平均生成时间可维护性直接生成代码12%28%3.2s低生成 JSON4%6%2.1s高逻辑错误率从 28% 降到 6%这个提升非常明显。而且 JSON 生成时间更短因为输出 token 更少。可维护性就更不用说了改逻辑只需要改 JSON不需要重新生成代码。7. 常见问题与排查技巧实录7.1 模型生成的 JSON 字段名不对怎么办这是最常见的问题。模型可能会把operator写成op把value写成val。解决办法有两个一是在提示词里把字段名用表格列清楚并强调“必须使用以下字段名不得使用同义词”二是在校验阶段做字段名映射把常见的错误写法映射到正确字段名。我两个都做了。字段名映射表大概长这样错误写法正确写法opoperatorvalvaluecondconditionsactactionsfactorratev1.0或 factorv2.07.2 条件嵌套太深导致模型理解错误前面提过超过四层嵌套模型就容易出错。我的做法是在提示词里加一条规则“如果逻辑嵌套超过三层请拆分成多条规则用 priority 和 conflict_resolution 来组合。”这样模型会主动把复杂逻辑拆开而不是硬塞进一个嵌套结构里。7.3 动作执行顺序不对导致结果错误模型有时候会把actions数组里的动作顺序搞反比如先打折再减优惠券而不是先减优惠券再打折。解决办法是在提示词里明确说明“actions 数组按顺序执行请按照业务逻辑的正确顺序排列。”同时在 Few-shot 示例里展示正确的顺序。7.4 执行引擎报“字段类型不匹配”怎么排查这个错误通常是模型把数字写成了字符串比如value: 3而不是value: 3。排查方法是看错误信息里提到的字段路径然后去 JSON 里找对应的节点。修复方式是在校验阶段做类型强制转换如果字段期望是数字但收到字符串尝试转换转换失败则报错。7.5 常见问题速查表问题现象可能原因排查方法解决方案JSON 解析失败模型输出多余文字检查输出是否只有 JSON提示词强调“只输出 JSON”字段名错误模型用了同义词对比字段名映射表提示词列明字段名 映射表条件逻辑错误嵌套太深或逻辑符用错检查 logic 字段拆分规则 Few-shot 示例动作顺序错误模型未按业务顺序排列检查 actions 数组顺序提示词说明顺序 示例类型不匹配数字写成字符串检查字段类型校验阶段强制转换重复执行动作模型生成重复 id检查动作 id执行引擎去重7.6 独家避坑技巧第一个技巧在 JSON 里加一个description字段让模型把自然语言描述也写进去。这个字段不参与执行但方便人工审核。当规则出问题时你可以直接看description快速定位是哪条规则。第二个技巧给每个规则加一个test_cases字段让模型生成几个测试用例。执行引擎可以在正式执行前先跑一遍测试用例验证规则是否符合预期。这个做法能提前发现很多逻辑错误。{ id: rule_a, description: 黄金会员满200打9折, test_cases: [ {input: {order_amount: 250, user_level: gold}, expected_discount: 0.9}, {input: {order_amount: 150, user_level: gold}, expected_discount: 1.0} ] }第三个技巧定期用一批历史需求重新生成 JSON对比新旧版本的差异。如果发现模型对某个需求的理解变了说明提示词可能需要调整。这个做法能帮你持续监控模型的输出稳定性。8. 这套方案的边界与扩展方向8.1 不适合的场景这套方案不是万能的。以下几种场景我不建议用需要复杂算法逻辑的场景比如路径规划、动态规划、机器学习推理这些逻辑很难用 JSON 描述清楚还是直接写代码更合适。需要实时性能优化的场景JSON 解析和递归解释有性能开销如果逻辑每秒要执行几万次可能扛不住。这种场景建议把 JSON 编译成字节码或直接生成代码。需要频繁变更结构的场景如果业务逻辑的结构每天都在变维护 JSON Schema 和提示词的成本会很高。8.2 扩展方向一JSON 到代码的编译执行引擎是解释执行性能有上限。如果某个规则的执行频率很高可以把它编译成目标语言的代码然后直接运行编译后的代码。这样既保留了 JSON 的可读性和模型友好性又获得了原生代码的性能。编译器的实现思路是遍历 JSON 树为每个节点生成对应的代码片段最后拼接成完整函数。这个工作量不小但对于高频规则来说值得做。8.3 扩展方向二多模型协作单个模型生成 JSON 可能出错可以用多个模型同时生成然后投票选出最一致的那份。或者用一个模型生成另一个模型审核。审核模型的任务是检查 JSON 是否符合业务逻辑如果发现问题就反馈给生成模型重新生成。这个做法成本翻倍但对于关键业务规则来说多一层保障是值得的。8.4 扩展方向三可视化编辑器JSON 虽然比代码好读但对业务人员来说还是不够直观。可以做一个可视化编辑器把 JSON 渲染成流程图或表单业务人员直接拖拽配置底层自动生成 JSON。这样模型生成的 JSON 也可以导入编辑器里让业务人员微调形成“模型生成 人工审核”的闭环。我在实际项目里做过一个简化版的可视化编辑器把条件树渲染成嵌套的卡片每个卡片可以展开编辑字段和操作符。业务人员上手很快培训半小时就能自己改规则了。8.5 最后的经验分享这套方案我用了大半年最大的体会是不要试图让模型做它不擅长的事。模型的强项是理解和翻译自然语言弱项是精确执行逻辑。把这两件事分开让模型只做翻译执行交给确定性程序整个系统的稳定性会有质的提升。另外JSON Schema 的设计要尽早稳定下来。我一开始改了好几次结构每次改都要重新调提示词、重新跑测试成本很高。后来我把 Schema 冻结了只通过版本号来扩展效率才上来。还有一个细节模型生成的 JSON 最好做一次格式化比如用json.dumps带缩进这样人工审核的时候看起来舒服很多。别小看这个细节审核效率能提升不少。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑