上个月给某个还在迭代中的智能图谱系统做内部演示,现场翻车了。用户问了一句:“供应商名单里新增了三家公司,其中两家有历史风险记录,请问我能不能在这周发起新的采购?”规则引擎的回答是“不建议,因为风控规则第7条命中”,大概20毫秒就给出。旁边的大模型接口慢吞吞跑了两秒,给出的结论是“可以尝试,但建议谨慎”。会议室气氛瞬间凝固——两个控制源同时给了结论,一个稳但死板,一个活但飘,到底听谁的?
这恰好就是“确定性硬编码”和“概率性大模型预测”在图中竞争控制权时的真实战况。所谓“图”,可以是知识图谱、任务依赖图、决策流程图,也可以是业务流程的状态机。凡是有节点、有边、有路径选择的地方,必然存在两套逻辑在同一张图上争夺“这条路该由谁说了算”的问题。这篇文章想做的不是给一个玄学答案,而是把这个问题拆开,讲讲我实际做系统时怎么分析这个平衡点,又是怎么把它变成一套可落地的仲裁机制的。
1. 核心矛盾的本质:两种决策范式的差异比你想的大得多
先说一个概念上的基础工程判断:硬编码和概率模型不是同一个物种,它们在底层逻辑上就是两种完全不同的决策范式。理解了这个差异,后面聊平衡才有意义。
1.1 确定性硬编码:精度换弹性的规则引擎
确定性硬编码的本质是“把决策逻辑显式写死”,包括条件分支、查表规则、图搜索算法、约束求解、状态机转换。它的核心特征是:对同样的输入,无论跑多少遍,输出永远是一样的;任何一步出错,都可以通过日志和单步调试直接定位到那一行规则。
这种范式在图数据系统里特别有价值,因为图结构本身是离散的、可枚举的、强拓扑约束的。比如一个知识图谱里,“A节点的出边只有三条”“从节点X到节点Y最短路径只有两条可达”这些事实是客观确定的。用硬编码去处理这类问题,天然具备三个优势:
- 可解释性极强。每一步决策都有据可查,适合审计、合规和复盘;
- 运行成本极低。规则引擎走的是纯计算逻辑,不需要GPU和云端推理;
- 行为可预测。系统面对边界情况时不会乱来,即使错了也是稳定地错,好修好改。
但硬编码的代价同样明显。当业务规则多到一定程度,规则之间开始互相打架,维护成本指数上升。更重要的是,现实世界的语义问题往往无法用精确条件表达。比如“判断一条采购审批是否属于‘高风险’”,除非业务方给出严格定义,否则你根本没法把“风险”写成一条布尔表达式。
1.2 概率性大模型预测:用泛化换常识的临时判断
大模型的预测逻辑完全不同。它不维护任何显式的规则表,而是把海量文本中隐含的知识压缩成参数,然后根据输入上下文计算一个概率分布,再从分布中采样或取最大概率值作为输出。
这种机制让它在语义理解、模糊匹配、开放域问答方面有压倒性优势。你不需要提前写“苹果既可以是水果也可以是公司”这样的消歧规则,模型见过足够多的语料,天然就能根据上下文判断。在带复杂语义关系的图中,模型也更能捕捉到隐含的关联和常识约束。
但概率预测的问题和它的优势同样致命:第一,它对同一输入可能给出不同输出,尤其在温度参数调高的时候;第二,模型会一本正经地编造不存在的“事实”,也就是幻觉问题;第三,模型给出的置信度分数并不总是和真实正确率一一对应。更麻烦的是,大模型推理需要显著的计算资源和延迟预算,如果图里的每条路径选择都靠模型“拍脑袋”,系统的响应速度和成本都会失控。
1.3 为什么在“图”上竞争会被放大
很多人以为规则和大模型的冲突只在文本问答里出现,其实真正放大矛盾的是图结构。图的特征就是“路径可选、节点关联、状态转移”,一个决策往往不是孤立的判断,而是沿着图的分支不断往下走的连锁反应。硬编码在图里负责提供拓扑约束,比如“这个节点不能连到那个节点”“这条路径的累计耗时不能超过上限”;大模型则负责处理语义信号,比如“用户问的真正意图是什么”“哪个候选节点在业务含义上和问题最匹配”。
问题来了:当两者给出的路径建议不一致时,系统的行为就分裂了。更麻烦的是,图的组合爆炸让“穷举所有冲突场景并提前写好应对规则”这件事变得不可行,这也正是为什么不能简单粗暴地让规则全权接管,也不能干脆把方向盘全交给模型。你需要的是一个结构性的仲裁机制,而不是一个“看心情”的临时判断。
2. 图中“竞争控制权”的典型场景:拆三个最常踩的例子
为了把问题具象化,我拆三个具体场景,这三个场景我都在实际项目中遇到过。
2.1 场景一:知识图谱上的路径选择
假设你有一个企业知识图谱,节点是员工、部门、项目、技术栈,边是“任职于”“负责”“依赖”“关联”。当用户提问“技术部里谁最适合接手这个遗留系统”,系统需要沿着图找到一条从问题语义到推荐人选的路径。
硬编码的做法是:建立一套权重规则,比如“有该系统相关经验加5分”“在部门层级上更接近加3分”“职称高一级加1分”,然后沿着图遍历所有候选节点,取总分最高者。这种方式稳定,可解释,但分数规则很难覆盖复杂的语义组合,比如候选人A的经验写在简历里、没有明确的图谱关联边,就漏掉了。
大模型的做法:把整个子图序列化成文本,让模型直接输出推荐人选。这种方式能捕捉常识和潜在关联,但模型可能推荐一个在图中根本不存在关联路径的节点,或者给出一个已经被跨调走的旧员工——因为它依赖的是训练时的知识,而不是当前图的实时状态。
两个控制源都认为自己有权决定“推荐谁”,这就是赤裸裸的控制权竞争。
2.2 场景二:任务编排与状态流转移
另一种常见冲突在任务编排图里,尤其是带状态机的业务流程。比如一条审批流:申请提交→自动规则校验→人工复核→财务打款。每个环节有一个状态集合,一条边代表“条件满足时允许迁移”。
确定性硬编码负责管理状态机的合法性:某状态必须经过前置状态才能到达,某个权限角色只能触发某类迁移。大模型则可以用于理解用户提交的模糊请求,比如用户说“这笔款比较急,能不能走加急通道”,模型需要判断这是否构成“加急”的语义条件。
冲突来了:规则说“加急通道必须满足金额小于5万且风险等级为低”,模型却认为这次申请“从表述和上下文看有加急的合理需求”。到底放行还是不放行?放错了是资金风险,不放是业务梗阻。这个场景里的每一步都可能被一个“合理但不符合规则”的模型建议打到规则墙上去,体验立刻变糟。
2.3 场景三:实体链接与关系消歧
第三类常见问题发生在图数据的入口环节——实体链接。比如一条文本提到“苹果”,系统要在图谱中决定它指代的是水果“苹果”还是科技公司“苹果”。规则可以用前后词匹配、词典表来做硬消歧;大模型则直接用上下文理解来猜。
正常情况下,两种方式在大部分样本上结论一致。但总有一小撮故意刁钻的输入,比如“苹果酝酿新机型”,“苹果”二字出现在一条供应链新闻里,词典规则认为“苹果”与“新机型”关联,命中科技公司;模型则基于新闻语境也判断为科技公司,看起来一致。可如果词典里恰好没有“新机型”这个词,规则就只能靠常识兜底说“返回最常见含义”,而模型仍然能精准命中。这就是覆盖率差异带来的竞争——规则没有漏掉错误,但漏掉了正确,它也想“有权处理这个输入”。
这三个场景的共同点是:无论哪种控制源,都有自己擅长的区域和明显的盲区。谁都不能完全替代对方,但谁都不愿意让权。
为了更直观对比,我做了一张简表:
| 对比维度 | 确定性硬编码 | 概率性大模型预测 |
|---|---|---|
| 输出稳定性 | 完全可复现 | 同输入可能不同输出 |
| 可解释性 | 高,链式定位 | 低,内部决策难以追因 |
| 语义泛化能力 | 弱,依赖人工覆盖 | 强,可处理模糊输入 |
| 图结构约束保障 | 强,天然保证合法路径 | 弱,可能产出虚假关联 |
| 运行成本与延迟 | 极低,毫秒级 | 高,秒级且按量计费 |
| 维护方式 | 人工维护规则库 | 数据训练调优模型 |
这张表看下来,结论其实很清晰:你不可能只选一边。你需要的是“确定性优先、概率性兜底、仲裁机制居中调停”的混合决策架构。
3. 寻找最佳平衡点:一套三层动态仲裁机制的设计思路
下面这部分是全文的核心。我直接给出我习惯用的仲裁框架,并说明每层的设计理由,你可以直接当成一套可复用模板来参考。
3.1 第一原则:不是二选一,而是分域而治
先说最重要的方法论:不要试图在“规则对还是模型对”之间做单一选择,那是伪命题。正确的做法是,把整个图决策空间分成“硬约束域”和“软语义域”。
- 硬约束域:由不可违背的业务底线、技术约束、合规要求组成。比如状态机的合法迁移、资金风险红线、用户权限范围、节点白名单。这些必须由确定性硬编码完全接管,大模型不得干预。
- 软语义域:由可以弹性解释、偏向体验和效率的决策组成。比如候选推荐顺序、文本总结风格、意图识别中非关键部分的判断、关联关系的权重微调。这些可以交给大模型。
分域而治的设计理由很简单:把错误代价最高的决策全部放入硬约束域,可以让系统在灾难面前永远有底线。剩下的部分即便模型犯错,造成的损失也在可接受范围内,可以通过后续校验和泛化纠错弥补。
3.2 第一层仲裁:规则前置校验与路径合法性强制约束
在模型开始推理之前,先用规则引擎把图空间中根本不该出现的路径剪掉。具体操作包括:
- 节点白名单/黑名单:确定哪些节点不允许出现在结果链中;
- 有向可达性预检:从起点出发,穷举所有合法路径;
- 时间窗约束:某些边只在特定时间窗口内允许参与决策;
- 角色权限过滤:某些路径只对特定权限角色开放。
这一层的执行是“零容忍”的,所有模型候选路径都必须先过这一关。过了才允许进入下一层,不过的直接打回。
为什么要前置而不是后置?因为大模型在受限空间内生成候选时,如果提前知道“很多路径本来就不合法”,它的输出质量会明显更高。你把约束都剪干净了,模型就没机会跑偏到合规死角里。
3.3 第二层仲裁:规则命中优先,未命中再交模型生成候选
在硬约束全部满足的前提之下,第二个仲裁维度是“规则覆盖率”。
具体逻辑:
- 先用确定性规则集对当前输入做匹配。
- 如果规则命中且有明确输出,直接复用规则输出,不再调用模型。
- 只有规则未命中、无法给出明确结论时,才把问题交给大模型,让模型在合法的路径子集中生成候选路径。
- 模型输出的候选必须再次通过一个“规则后置校验器”,校验器会检查路径合法性、节点存在性、关系约束和业务规则一致性。校验不通过则丢弃。
这一步解决了一个最关键的问题:硬编码负责“减少模型的使用次数”,模型只负责“覆盖规则的空白缝隙”。这样既控制了延迟和成本,也保证了输出的合法性和可解释性上限。
从我实测经验看,大部分图决策系统中,规则能覆盖的场景往往在60%到80%之间。多余的部分交给模型,模型的实际流量只占全部请求的一小部分,整体系统的稳定性和成本都能得到显著改善。
3.4 第三层仲裁:置信度分级与动态阈值调整
模型生成候选之后,系统需要决定“是否直接采用”。这里不能只看模型自报的置信度,因为大模型的自信心和准确率经常不对齐。我的做法是建立一个多因素裁决分数,综合考虑:
- 模型的原始置信度分数(提示词中要求模型输出);
- 后置校验器的规则吻合度,例如候选路径与已知合法路径的相似度;
- 历史知识库命中情况,例如该候选结果在过去是否被验证过;
- 上下文稳定性因子,例如这个输入是否容易受到措辞微调的影响。
对这个综合裁决分数做分级处理。一般我会分三档:
| 分级 | 综合裁决分数 | 处理策略 |
|---|---|---|
| 高置信 | 高于阈值上限 | 直接采纳,进入自动执行链路 |
| 中置信 | 介于上下限之间 | 采纳,但打上“建议复核”标记并记录完整证据链 |
| 低置信 | 低于阈值下限 | 不直接采纳,回退到规则默认值或等待人工处理 |
这个“动态阈值”不是拍脑袋定的。我的建议是先用历史日志离线跑一版分数分布和真实结果,把“低置信区间的错误率”和“高置信区间的覆盖率”找出来,再基于错误代价和覆盖率目标去选阈值。真实业务中,根据错误后果的严重程度动态调整阈值往往更合理:如果这个决策导致资金损失,阈值调高;如果只是内容推荐,阈值可以适当放低。
3.5 成本感知:给模型设预算而不是给它无限权限
最后一层仲裁其实是成本层的。大模型调用不是免费的,延迟也不是可忽略的。在竞争控制权的问题里,模型不应该有“随时被调用”的权利。我会给系统设定一个“模型调用预算”,比如每分钟最多调用N次、每个请求最多调用M次、超出预算直接进入规则兜底。
这么做不仅是为了省钱。更重要的原因是,当你限制了模型的调用量,规则系统就会被迫自我增强——那些反复触发模型调用的高频场景,会被逐渐固化成新的规则模板。这就像把一个刚入职的实习生(模型)放在一个老带徒的环境里,先让他只处理特殊情况,见多了再把常见逻辑沉淀成制度(规则)。这样模型压力减小,规则库也越来越完备,整个循环是正向的。
4. 实操改造记录:从一个模拟项目看平衡工程是怎么落地的
理论说再多,不如看看实际改造过程中会遇到什么。我挑一个比较典型的“专家知识问答与推荐系统”来复盘,这套系统本质就是一个带有大量知识图谱关系的决策系统,正好合适。
4.1 项目原始状态:规则与大模型“并行让路”的混乱期
这个系统一开始的设计很天真:请求进来,先用规则引擎跑一遍,如果规则没有命中,就直接调大模型接口拿答案。看起来没问题,但实际运行一个月后发现三个痛病:
第一是“接缝处产生真空地带”。规则引擎认为“未命中就是不想管”,大模型认为“既然让我回答,我就要负责回答得漂亮”。可是规则引擎有边界条件,比如某类输入在法律上不应该回答,但规则没有明确写出来,模型拿到请求后以为有问必答,直接产生了一个不合规且无法解释的回答。用户看不到规则的那种“确定性保护”,只看到一个荒谬的输出。
第二是“规则与模型同一选项给出不同答案”。本意是规则未命中时才调模型,但问题的格式千变万化,规则引擎其实常常“部分命中”。例如规则已经判断出城市是A,但模型整体推理后认为城市是B。按照原先的流程,规则未完全命中会被当成未命中,模型直接覆盖了规则的中间结论。这就是典型的控制权竞争导致的决策覆盖。
第三是系统对模型“形成了路径依赖”。团队发现只要放开让模型回答,用户满意度有时候确实高。于是越来越多的场景被引导到模型上去,规则引擎逐渐被架空,可响应延迟从500毫秒飙升到平均2.1秒,且出错时根本没有复盘抓手。
4.2 改造过程:三层仲裁机制的具体落地步骤
改造并不是推翻重来,而是把决策过程从“并行让路”改成“分层仲裁”。我跟团队做的核心工作是这四步:
第一步,把全部决策点清单化,区分硬约束和软语义。把所有图路径上的决策点列成一份表格,每个决策点标记“错误代价”和“可逆性”。比如“是否允许放行一笔资金”是不可逆的高代价决策;“推荐给用户哪一篇技术文档”是可逆的低代价决策。表格画完之后,不可逆的全部划入硬约束域,可逆的才允许模型介入。这一步是整个改动里最花时间的,但也是最值得的,因为很多开发根本不清楚哪个决策是不可逆的,等出事才反应过来。
第二步,搭建规则前置校验器。写一段通用的剪枝层代码,在模型被调用之前,先把所有边界和约束前置检查完。这个校验器需要直接访问图数据库,执行物理路径验证。当时我们用了几十行图查询逻辑,把生产环境里“允许参与决策的节点集合”和“合法边集合”全部拉出来,然后要求任何模型候选必须在这些集合内。
第三步,加入规则后置校验器。这一步比前置校验更重要。大模型的每一条输出路径,都会再回到规则引擎里做一次完整合法性检查。检查的内容包括:终点节点是否合法、路径是否可达、是否满足所有硬约束、是否和用户权限匹配。校验不通过的输出会被打上“规则冲突”标签,直接丢弃并返回规则默认值。这个“默认值”的设计很关键,我会在后面避坑部分细说。
第四步,建立置信度分级与反馈闭环。每一条模型候选在通过后置校验之后,还要经过综合裁决分数分级。高置信的自动放行,中置信的写入复核队列,低置信的回退默认值。同时,所有决策日志都记录“规则命中情况”“模型候选”“校验结果”“最终采纳结果”,这套日志就是后续调阈值的依据。
4.3 改完后看到的直接变化
改造上线后,效果是比较明显的。先从技术指标看:
- 模型调用比例:从原本“未命中就调”的隐性高调用,改为目标式调用后,实际只有约20%的请求会真正走到模型层;
- 平均响应时间:从原来的2.1秒降到0.45秒,因为绝大多数请求直接走了规则快路径;
- 规则覆盖率:从改造前的67%提升到91%,主要原因是前置校验器逼着大家把模糊场景写成了新规则;
- 可解释性事故:从平均每周发生3-4起,降到几乎为零,因为所有模型输出都必须在规则边界内。
业务侧的感受更直观:用户再没遇到过“规则说不行但模型说行”的撕裂感。因为仲裁机制让规则在底线问题上一票否决,模型只会在规则允许的空间里做优化和推荐。即使某些推荐结果不是最优,也至少是安全且合法的。
4.4 调优参数时的实际感受
平衡点不是一次调出来的,我看到不少团队卡在阈值上。说几个实操心得:
置信度阈值很难“一次定死”。第一版我们把高置信阈值设成0.95,结果发现模型候选被大量打回,系统的灵活性完全消失,规则覆盖率虽然高但推荐质量明显下降,用户开始抱怨“系统太死板”。后来我们线下分析了历史日志,发现0.87到0.91之间的候选实际正确率已经足够安全,于是把高置信阈值放宽到0.89,系统立刻活过来了。
规则后置校验器的“回退默认值”一定要设计得合理。回退不是“空着不答”,而是提前为每种语义场景准备一个安全兜底答案,比如“未找到符合条件的候选,请走人工复核通道”。如果没有这个默认值,系统会在冲突时直接报错或返回空白,反而比错答更影响体验。
模型候选生成时的“温度”建议调低。在图中做路径决策时,不需要模型发挥太多创造性,把温度设到0.2以下能显著减少模型在边界处随机游走的情况,配合后置校验器,通过率会高不少。
5. 常见问题与排查技巧实录
这部分整理了我实际踩过、也看到同行踩过的一些典型的坑,按“场景-现象-排查思路-解法”的方式整理成速查表,方便你直接对照。
5.1 动态阈值到底怎么定才算合理
很多团队把阈值当成一个固定的超参数,设完就再也不管。其实阈值应该跟随系统的运行状态动态调整。
我的建议是:上线初期用一个保守的静态阈值(比如0.9),然后运行两周,把所有“中置信区间”的决策日志抽出来做人工评估。统计出“如果采用该候选,错误率是多少”“如果回退默认值,用户流失率是多少”。用这两个指标做一次成本权衡,就能得到一个比拍脑袋准得多的阈值区间。
每隔一个月重复一次这个动作,因为业务数据、模型版本、规则库都在变,阈值也需要跟着微调。你甚至可以做成一个简单的自动脚本:每天统计决策准确率和覆盖率,当覆盖率连续三天低于预期时自动把阈值下调0.02,当准确率连续三天下降时自动上调0.02。这不复杂,但很实用。
5.2 规则和模型在同一决策点上各执一词
这是最常见也最麻烦的场景。规则说“不放行”,模型说“放行更优”,系统到底选谁?
我的处理原则是:按决策的“逆程度”来排优先级。涉及安全、合规、资金、人命的决策,规则永远一票否决;涉及内容推荐、文案润色、排序微调的决策,模型可以拥有优先权。具体落到工程上,就是给每条规则标注一个“冲击等级”,冲击等级高的规则在仲裁时优先级天然高于任何模型输出。这种“按等级排序”的设计比单纯看置信度分数可靠得多,因为置信度是模型自己的衡量尺,而冲击等级是业务方对后果的共同判断。
5.3 大模型的置信度分数感觉不太可信
确实不可信,这是个已知问题,不要过度依赖模型自报的置信度。我见过模型给自己打了0.97的置信度,但输出里包含一个完全不存在的图谱实体。
处理思路有两个。一是做“置信度校准”,用历史数据拟合模型分数和真实正确率之间的映射函数,校准后得到的分数比原始分数靠谱很多。二是做“交叉验证”,把同一个问题用两种不同方式问两次,比如一次直接问、一次要求分步推理,看两次答案是否一致。一致性高的答案才是高置信候选。
5.4 规则库越补越大,最后自己内部打架了
很多系统跑着跑着规则库开始自我冲突,这也是一种典型的“熵增”。解决方式是为规则引入明确的“优先级表达式”,而不是让人肉眼去排查。举个例子,规则A说“金额高于10万的采购禁止自动通过”,规则B说“总部审批过的采购可以直接通过”。这两条规则在“总部审批过的10万以上采购”场景下冲突。正确的做法并不是删掉某一条,而是给规则增加优先级字段,比如“覆盖型规则”和“例外型规则”,并写明“总部审批例外可覆盖金额上限限制”。
5.5 大模型开始输出“过时信息”或者“被污染的上下文”
泛化模型的知识有截止日期,而且它读取的上下文越长,越容易受到无关信息的干扰。在图的场景里,模型可能会读到一个很久以前就已经失效的节点关系,然后自信地推荐一条不存在的路径。
对策是在送入模型之前,先把候选路径的实时状态从图数据库里取出来,做成“带时戳的上下文”一并交给模型,同时在规则后置校验器里加入“节点状态有效期检查”。如果节点在某日期之后已经失效,即使模型推荐了,校验器也会拦下来。这本质上是让模型永远基于“当前真实的图快照”做预测,而不是基于它自己记忆中的世界。
5.6 模型调用超时拖垮整个链路
大模型接口偶尔会变慢。如果你的主链路是同步等待模型返回的,那模型一旦超时整个请求也跟着超时。我是这样处理的:给模型调用设置一个“熔断时间”,比如300毫秒。超过这个时间还没返回,系统直接放弃模型候选,走规则默认值。并发量超过阈值时也一样,直接降级为纯规则模式,宁可牺牲一点灵活性,也不能让整个系统跟着模型的延迟一起崩溃。
这里有个小技巧:把模型调用从主链路中拆出去,改成异步“预取”。比如用户在浏览前几条候选时,系统已经在后台预生成后续候选路径。这样真正需要模型结果时,结果往往已经准备好了,延迟体感会低很多。
6. 关于平衡点的工程师心得:契约比聪明更重要
聊到最后,我想说一个跟技术无关但跟工程品味有关的体会。
做混合决策系统,最难的地方不是模型调优,也不是规则编写,而是所有人(业务方、开发、产品)对系统边界的共同想象。如果业务方认为“系统应该尽量聪明”,开发就会拼命往模型上堆能力;如果业务方认为“系统必须永远可靠”,开发又会把所有东西都硬化成规则。真正健康的系统设计,应该从一开始就明确一张“决策契约”:哪些地方模型说了算、哪些地方规则一票否决、哪些地方需要人工参与仲裁。这个契约不是技术文档,而是整个团队共同的思维底座。
我自己的设计习惯是:先画一张“决策路由图”,把系统里所有可能出现控制权竞争的位置标出来,然后为每个位置写上默认控制方、备选控制方、切换条件和失败兜底。系统上线之后,定期对照这张图检查实际行为是否还和契约一致。很多时候你会发现,随着规则库膨胀和模型升级,某些节点的实际控制方早已悄悄偏离了契约,而所有人还蒙在鼓里。
关于“最佳平衡点”,我最后再分享一个实战经验:最佳平衡点往往不在“五五开”,也不在“规则保底、模型偶尔出场”这种简单比例里,而在“规则的硬约束面足够大,模型的弹性活动空间足够受控”这种结构性设计里。硬编码负责圈出一个安全、可解释、低成本的决策边界,大模型只在这个边界内做精细化选择和语义补齐,两者各司其职,系统才能既稳又活。
如果你正在做带图结构、带规则系统、又接了大模型的产品,希望这套仲裁思路能给你一个具体的落地抓手。别急着让模型变得更聪明,先让规则变得可协商、让边界变得清晰,平衡点自然就浮出水面了。