公司知识散落在不同团队写的文档里。法务写服务条款,客服写帮助文章,市场写定价页,政策团队写内部规则。迟早会有两份文档打架。
比如内部政策承诺30天内退款,公开FAQ写的是14天,市场那边不知出于什么原因写的是45天。到底哪个算数?
多数公司的答案来自一条Slack消息。有人问另一个人,对方说"我觉得30天是对的",然后大家就散了。三个月后新员工问同样的问题,那条消息早被一万条新消息埋了,FAQ还写着14天,没人说得清当初为什么这么定、是谁定的。
把裁决变成一份文档
有人做了一个工具,把这种决定变成一份有类型、可查询的文档,带着来源、理由、先例链和审计轨迹。流程是:一个智能体提出裁决建议,人来批准或推翻。人一旦拍板,这个答案会在所有地方同时生效。
检测到矛盾后,系统会创建一份"case"文档。智能体给出建议裁决,附上理由和引用的先例。人批准或覆盖它。人做出裁决后,这个决定就是应用对外提供的标准答案。
界面分三个标签页。Triage是工作队列,按阶段分组:"等待你裁决""需要提案""最近裁决"和"已被取代"。History列出历史上每一条裁决及其归属。Answers展示每个主题的标准答案以及它的来源。
六个文档类型撑起整套逻辑
作者说,他在文档类型上花的时间比任何界面代码都多。一共六种:
- source:记录性文档,含标题、来源类型、链接、内容、最后审阅时间
- topic:一条主张所涉及的主题
- claim:带归一化数值(如"30 days")的陈述,附来源引用、主题引用和置信度
- case:检测到的矛盾,包含主题、冲突主张的快照,以及可选的智能体提案
- caseEvent:只追加的日志条目,记录每次阶段流转、操作者身份和载荷快照
- instruction:裁决本身,含获胜主张或结果值,以及被推翻项、带类型的先例和取代引用
其中四个设计决定承担了大部分工作。
第一,topic是文档而不是字符串。claim的主题和instruction的适用主题指向同一个topic文档,裁决就不会因为两个字符串漂移而悄悄失效。否则"refund-window""refund window"和"Refund-Window"会变成三个不同主题,针对其中一个的裁决回答不了另一个,而且没有任何警告。
第二,数值是比较键。每条claim带一个归一化数值,比如"30 days""5 USD""12 months"。同一主题下数值不同的两条claim互相矛盾;数值相同的则一致,应用不去动它们。这是计数和比较的区别——如果只知道"这个主题上有多少条未解决主张",两份说同样话的来源看起来和冲突一模一样。
第三,先例是带类型的。当一条裁决引用更早的裁决时,引用会记录它是怎么被用的:follows表示早先裁决在此同样适用;distinguishes表示早先裁决看似适用其实不适用,并说明原因;overrules表示早先裁决是错的,现在推翻它。一个扁平的引用数组说不出这些。已发布的数据集里有一个专门展示distinguishes的案例:智能体把一条早先裁决引用为follows,而记录在案的人类裁决把同一条引用为distinguishes。两者得出同一个答案。结论活了下来,论证没有,而这一点只有先例带类型才看得出来。
第四,取代关系是记录下来的,不是推断出来的。新裁决替换旧裁决时,新instruction带一个supersedes引用,旧裁决从不删除。"这条instruction是否已被取代"由一条计数查询回答。作者说,这一点和朴素的引用检查之间的差距,让他踩了一个真实的bug。
状态机也是数据。仓库根目录的workflow.def.json声明了四个阶段——detected、proposed、ruled、superseded——以及它们之间的流转,包括哪类操作者可以触发哪条边。种子脚本写入的每个事件都要对照这张表校验。
热门跟贴