怎么保质量 · Yaomancy
让 AI 讲话,不让 AI 算数:确定性事实层与生成表达层的切分
Yaomancy 把纳甲、六亲、六神、世应、伏神、旺衰、用神做成结构化 JSON 契约,由规则引擎算出可验证的事实;语言模型只在这些事实上做白话表达,不得重算。这是我控制 AI 产品幻觉的通用做法。
六爻是一套规则非常明确的传统文化体系:从起卦到装卦,每一步都有古籍记载的固定算法,输入相同,结果就相同。而语言模型最擅长的恰恰是「看起来合理」,它会在不确定的时候补出一个通顺的答案。把一套确定性的规则交给一个概率性的模型去执行,结果就是每次都通顺、每次都可能不一样。这个产品的第一个设计决定,就是不让这件事发生。
问题
如果让模型直接从起卦结果生成解读,它会给出流畅的文字,但装卦这一步的每个环节,纳甲、世应、六神,都可能在某一次生成里出错。错在哪里不可预测,而且用户无从察觉,因为错误的文字读起来和正确的一样通顺。
更麻烦的是,这类错误无法通过「写更好的提示词」根治。规则再清楚,模型也是在生成而不是在计算。要让它不算错,唯一办法是不让它算。
一条切分线
整条流程被切成两层:
- 确定性事实层。一个纯规则引擎负责起卦与装卦,输出纳甲、六亲、六神、世应、伏神、旺衰、用神等全部结构化事实。它没有任何模型调用、没有网络请求,同样的输入永远得到同样的输出。
- 生成表达层。语言模型只接收上一层算好的结构化事实,任务是用白话把这些事实说清楚,供用户理解和参考。它不被允许重新推算任何卦理,也不被允许在事实之外补充新的判断。
这条切分线的核心不是「用不用 AI」,而是谁对事实负责。事实由程序负责,程序可以被测试、被开源、被逐行核对;表达由模型负责,模型的错误最多是说得不够好,而不是说错了事实。
契约长什么样
两层之间的接口是一份 JSON 契约。每个字段都有明确的枚举取值:六亲只能是六个值之一,六神只能是六个值之一,世应是两个明确的位置索引。伏神、旺衰这些依赖节气与日辰的字段,同样由引擎按规则算出后以枚举形式给出。
契约是双向约束。对引擎来说,它规定了必须算出哪些字段,缺一个就是引擎的缺陷;对模型来说,它规定了只能引用这些字段里的内容。表达层的提示词里不放任何卦理规则,只放这份契约和一条要求:把它们说成人话,不要添加、不要更改。
术语只有一个来源
切分之后还有一个漏洞:模型在表达时可能自行「默写」领域名词,比如把某个六亲写成另一个近义说法,或者用一个它训练数据里更常见但本产品不采用的术语。名词一乱,用户就无法把解读和卦盘对应起来。
处理方式是一份 glossary,术语的唯一真源。契约中的每个枚举值在 glossary 里有且只有一个对应的中文名与一句定义。表达层的上下文里按枚举注入这些条目,模型只能使用注入的名词。术语要改,改 glossary 这一处,引擎输出、界面显示、模型表达三处同时生效。
怎么证明算得对
把事实交给程序,前提是程序自己得算得对。这一层做了三件事:
- 核心引擎以 Apache-2.0 协议开源。任何人都可以拿一个卦例,对照古籍或自己的推算逐项核对。开源不是姿态,是让「可查证」这个承诺有实际的查证入口。
- 排盘结果与两套独立的第三方实现做交叉验证。三方一致才算通过;不一致的卦例被单独记录,逐个追到规则解释的分歧点,再决定采用哪一种并写明依据。
- 历法是排盘的输入,也是最容易出错的地方。节气交节的精确时刻、子时是否换日,这两处用两套历法库互相核对,差分结果进入持续集成的回归测试。任何一次改动导致结果漂移,构建就会失败。
由此定下的口径
- 能由规则确定的事,一律由程序计算,不交给模型。
- 模型只在既定事实上做表达,不得重算、不得补充判断。
- 两层之间用带枚举的结构化契约衔接,契约是唯一接口。
- 领域术语只有一个来源,按枚举注入,禁止模型默写。
- 事实层必须可验证:开源、交叉验证、差分回归三件事缺一不可。
- 产品对外的表述始终是「可复现、可查证的规则呈现」与「理性、克制的解读参考」,不涉及任何关于结果的宣称。
结论
让 AI 讲话,不让 AI 算数。这句话在六爻这个领域里显得格外清楚,因为规则本身足够确定;但它在我做过的其他 AI 产品里同样成立:凡是能用规则算出来的,都不该交给模型猜。把事实层和表达层切开,幻觉问题就从「怎么让模型少出错」变成了「怎么让程序算对」,而后者是有标准答案、有测试方法的工程问题。