☰
Utopia 本体关系采纳机制(0007):计数决定什么成为关系——从种子谓词到统计驱动的本体增长
2026/9/25 8:31:21 网站建设 项目流程
  • 后端
  • 前端
  • 人工智能
  • RAG
  • 知识图谱
  • 知识管理
  • 搜索引擎

【免费下载链接】utopia

World's first open-source enterprise world model.

项目地址:https://gitcode.com/gh_mirrors/ont/utopia
点击查看免费下载

导读

本文基于 Utopia 项目的决策记录 docs/decisions/0007-who-decides-what-becomes-a-relation.md,剖析知识库本体中“关系(relation)”何时、由谁、如何诞生这一核心问题。你将掌握:为何从 10 个种子关系起步时 49.8% 的事实退化为无意义的related_to;为何 LLM 判断“哪些说法值得成为关系”会系统性失误;以及“计数决定采纳(counting decides adoption)”这条确定性路径——通过MIN_DOCS = 2、屈折基归并与文档并集,让同一份语料稳定产出同一个本体,并配套unadopt可撤销机制与PredicateIndex方向修正。


一、背景:种子关系与退化的related_to

1.1 问题的起点

Utopia 是开源的企业级世界模型,其知识库(KB)以“本体(ontology)”为契约。本体中实体之间的连接被称为关系(relation),例如produces、founded_by、invested_in;关系以行记录在relation_types表中(见 migrations/0004_ontology.sql)。

在 0007 决策记录撰写时,一个新知识库从10 个种子关系起步。问题随之而来:模型抽取出的绝大多数关系不在种子列表中,于是退化为related_to——一个“什么也没说”的谓词。实测数据(ai-timeline 语料:15 篇 AI 公司维基百科条目,348 个分块):49.8%的事实落在related_to上。这个比例是测量台关闭自动扩本体后的数字(run.mjs建库即置auto_extend_ontology=FALSE,而列默认值为 true)——它量的是“缺词汇时降级有多频繁”,正是 crates/utopia-server/src/predicate_match.rs 要减少的部分。

此后,0010 决策 干脆删除了related_to:它把“抽取器发现了一条边但本体没有匹配关系”这一程序状态编码成了本体里的一个内置关系,好像真的有人决定两个事物之间的关系叫“related”——没有人这么决定过。于是:

  • facts.predicate_id变为可空;
  • 无谓词事实通过 SQL 函数fact_surface_predicate(uuid)回退显示源文档的原文措辞(见 crates/utopia-store/src/graph.rs);
  • 测试 crates/utopia-store/tests/no_predicate_still_shows.rs 守护这条底线:无谓词的事实必须能在每一条读路径上可见。

1.2 旧bootstrap_ontology的六个独立缺陷

bootstrap_ontology(自动扩本体)正是为“缺词汇”设计的,但旧实现“工作得很糟”,决策记录列出六个独立原因,每个都对应一次修复:

#缺陷修复
1精确字符串匹配丢弃了本体里已有的词汇:produced_by \| ChatGPT → OpenAI错过了produces新增predicate_match(拼写、屈折、结尾by交换主宾)
2最后一篇文档失败则 KB 永远卡住:自动扩展只在成功路径入队两条路径都入队
3≥2 篇文档阈值只门控 LLM 运行;build_proposals重新查询未过滤集合,86.7% 展示给模型的措辞来自单一文档阈值同时门控候选构建
4doc_count统计仍挂在兜底谓词上的残渣,单篇灌入的 KB 永远到不了 2 篇普遍性统计全部证据(见下文 CTE)
5“Ignore”是一扇单向门:record_miss跳过被驳回的措辞,计数冻结在 1全部计数;被驳回的单独列出、可撤销
6未注明日期的事实声称天级精度(valid_precision NOT NULL DEFAULT 'day',728 与 843 条活行)可空、CHECK 绑定日期(facts.valid_from_precision,见 migrations/0003_graph.sql)

这六项修复在迁移与源码中均有对应:例如proposed_predicates的spreadCTE 从全量证据(fact_evidence的proposed_predicate)统计文档数,而非从积压(无谓词的活行)统计——两种口径下 8 个说法分处门槛两侧(按积压是“只在 1 篇”,按全量是“≥2 篇”)。


二、核心决策:计数决定采纳

2.1 模型答错了那个问题

旧路径把“哪些说法值得成为关系”交给 LLM 判断。模型实测答错:

  • 漏掉了runs_on——它出现在 8 篇文档、13 条事实中,显然不是判断题;
  • 采纳了只在单一文档出现过的pledged_capital。

决策记录因此断言:“模型不是被询问的对象;数据回答了‘哪些措辞配得上成为关系’。”

2.2 三条确定性步骤

counted_relation_groups(见 crates/utopia-server/src/bootstrap_ontology.rs)实现计数采纳,不调用模型:

  1. 按屈折基归并:使用predicate_match::merge_key,sued与sues是同一个关系;
  2. 取每组的文档并集,绝不求和:同一篇文档可能两种写法都用过,相加会把一个说法单篇顶过“≥2 篇”门槛。实现通过proposed_predicate_documents拿到真实文档 ID 再取并集(见 crates/utopia-store/src/graph.rs);
  3. 过门槛MIN_DOCS = 2:组以出现事实最多的措辞命名。

源码中的门槛常量(crates/utopia-server/src/bootstrap_ontology.rs):

/// 少于这么多个够格的信号(谓词 + 类型)就不折腾——凑不出像样的提案, /// 白烧一次 LLM 调用。 const MIN_SIGNALS: usize = 3; /// 只采纳出现在这么多篇文档里的说法。**只在一篇里出现过的是那篇文档的用词, /// 不是这个组织的词汇**——而本体会反馈进抽取提示词,一次偶然会变成长期指令。 /// 副作用正好:只有一篇文档时什么都够不着门槛,于是什么也不做,下一篇再试。 const MIN_DOCS: i64 = 2;

测量结果(同一语料,related_to占比):

配置related_to占比
自动扩本体关闭55.5%
LLM 采纳(17 个关系)39.1%
计数采纳(104 个关系)25.8%

2.3 为什么确定性是“最有价值的副作用”

同一个语料产生同一个本体——测量台第一次能对这一阶段做对照实验。此前 B 与 B3 两组差 3 个百分点,无法分辨是修复生效还是运行方差,就因为中间夹着一次 LLM 调用。决策记录强调:“Deterministic adoption is the most valuable side effect.” 同时它也给出审慎的 caveats:LLM 组间差异在运行方差内(同一输入 25 vs 18 实体),只有确定性部分确定(单文档采纳 5 → 0);related_to占比不是质量指标——全部采纳会最快地降低它,而语料本身在训练数据中密集。


三、模型仍保留的问题:同义归并

3.1 计数答不了“意义”

计数能回答“哪个措辞够普遍”,但回答不了“collaborates_with与partnered_with是不是同一个意思”。这正是fold_by_meaning的工作:对PredicateIndex认不出的说法做一次嵌入,与已有关系的向量比较,距离 ≤FOLD_DISTANCE = 0.20的落到已有关系上,不新建(见 crates/utopia-server/src/bootstrap_ontology.rs)。阈值取紧是有意为之:折错一次是把两个关系永久并成一个,而不折只是多一个关系,后者便宜得多。每个候选的距离都写进日志,以便在真实语料上校准。

3.2 可撤销:unadopt

自动采纳的前提是“错了很便宜”。决策记录写道:“采纳可撤销(见graph::unadopt):错了点一下就回去,旧事实从来没被销毁过。所以判断轴不是‘有多确信’而是‘错了有多贵’。”

实现细节(crates/utopia-store/src/graph.rs 起):

  • 每次采纳写入fact_adoptions表,记录batch_id、旧/新事实 ID、模式(superseded= 新行取代旧行;merged= 并入已存在行),见 migrations/0003_graph.sql;
  • 撤销以批次为单位:unadopt作废新行、复活旧行,但不删除关系类型——它存在过本身就是历史,一个没人用的关系是惰性的。

四、_by:唯一值得处理的反向标记

4.1 数据证据

31 种_by形式,其中founded_by42 条事实;且几乎全部与主动形式共存(produces265 条)。相比之下,has_X/X_of只有两对,证据不足。

4.2 采纳前的PredicateIndex查询

PredicateIndex::lookup(crates/utopia-server/src/predicate_match.rs)在采纳前被咨询,三段匹配、顺序即优先级:

  1. 精确 key——原有行为,一字不改;
  2. 写法对齐——acquiredFrom/acquired_from/Acquired From是同一个;
  3. 屈折归一——produced与produces折到同一串(只削时态与单复数,见inflect_base:-ies→y、-ing、-ed、-s(-ss除外),最后去掉结尾e,长度守卫看削完后的结果)。

第 2、3 步各再试一次“去掉结尾的by”,命中就把主宾对调:

// 被动形:`produced_by` 去掉 by 之后才对得上 `produces`,且主宾要反过来。 // 要求至少两个词——光一个 `by` 削完是空的。 if w.len() >= 2 && w[w.len() - 1] == "by" { if let Some(id) = self.widened(&w[..w.len() - 1]) { return Some((id, true)); } }

撞车就不匹配:本体里同时有produces和produced时,两者折到同一串,选谁都是猜——宁可降级,让人来采纳。只有精确 key 不受此限。测试ambiguous_stem_declines_rather_than_guesses与passive_form_matches_and_asks_for_a_swap分别守护这两条行为。

4.3 采纳时的方向修正与签名检查

采纳路径(adopt_proposed_predicates,crates/utopia-store/src/graph.rs):

  • swap = true时主宾对调:X produced_by Y与Y produces X是同一条边;
  • 挂谓词前先过一遍签名(judge_direction,#190):抽取写入时按 domain 掰正方向或留空,而采纳是第二条写谓词的路——实测不检查会把违反率从 0 抬到 12.3%,全在包关系上;
  • 结果三态:合就挂;主语不合宾语合就对调着挂(计数进corrected);都不合就不挂,事实留在空谓词上,原文说法还在证据里;
  • 目标断言已存在则并入而非重复创建(mode = merged)。

历史教训(源码注释):第一版主宾对调时,SQL 里仍写着subject_id,于是“宾语换了、主语没换,凭空造出一条OpenAI produces OpenAI”。现在主语也显式绑定。


五、merge_key:归并键的边界

5.1 屈折归并,而非词干化

merge_key(crates/utopia-server/src/predicate_match.rs)返回一组合并键,供本体采纳路径把同一个关系的不同时态先并起来再算票数。不并的代价实测可见:sued与sues各 11 和 5 条,各自够不着“≥2 篇”门槛;并起来后,够格候选从 70 组涨到 85 组、281 条涨到 355 条。

介词不并:integrated_with与integrated_into保持两组——works_at与works_in确实可能是两回事,宁可漏。

_by也不并(待做):founded_by与founded是同一条边的两个方向。当初不并的理由是“采纳路径从旧行原样复制主语,对调不了”——那个理由已在 #109 后不成立。如今缺口只剩一处:两边都还不在本体里时(founded_by42 条、founded4 条,都够票),采纳前的PredicateIndex查询谁也匹配不上,于是各建一个、方向相反。决策记录把它列为 open question,补法是把_by折进同一组并把整组标记为需对调。

5.2 死路:Snowball 词干化

Snowball(rust-stemmers)走错了方向:词表 10 个词时捞回 49 次,换成 schema.org 的 629 个词只剩 18 次——因为它连派生后缀一起削,producer与produces都成了produc,撞车规则于是拒绝匹配。测试derivational_forms_stay_separate_from_inflected_ones守护:producer(一个人)与produces(一个动作)本来就该是两个关系,折到一起是词干器的错,不是撞车规则的错。

5.3 领头的轻动词

has_funding与funding是同一个关系,前缀是命名习惯不是意思。LEADING_AUX列表(has/have/had/is/are/was/were/be/been)只在还剩词时剥:has单独一个词是它自己,不能剥成空。测试a_leading_auxiliary_does_not_make_a_different_relation验证has_funding → funding、product → has_product双向都通。


六、其他死路与修订

6.1 死路清单(决策记录原样)

  • 主语多样性替代文档计数:实际更严格(6 增益、33 损失),且 6 个增益大多是并列主语(“A、B 和 C 提出 X”拆成三条事实)。docs >= 2 OR subjects >= 3落入同样问题。
  • 每篇文档后自动扩展:“≥2 篇文档”变成“到目前为止”的属性,归并退化——LLM 只有在同时看到acquired/acquires/acquisition_of时才能归并它们。
  • 新单文档关系的事实数阈值(≥3):它准入的前两名是最差的两名(has_property11、intends_to5);20 组中约 5 组像关系,占 KB 的 1.2%。增长中的 KB 会自己解决;静态语料有手动面板(min_docs = 0)。

6.2 修订与前提变化

  • 2026-09-02:两个前提都消失了。种子关系分三步移除(related_to于 0010,另外 8 个于 #125,mapped_to于 0011),种子函数随 #128 一并删除。新 KB 从本体包起步(0008 决策)。上述数字与今天的测量不可比:事实现在可以没有谓词(原词进fact_evidence.proposed_predicate),继任指标——空谓词占比——在 0012 决策 中于不同起点和定义下测得 25.6%。
  • 2026-09-02:本体可声明逆关系(#177/#179),方向在写入时修正(#138,留下direction_corrected痕迹)。这不闭合上文的merge_key缺口。
  • 2026-09-10:计数路径现在从它已为类与属性读取的提案中取temporal,不再为每个采纳的关系写死state——注释里支持state的理由(“temporal 在 functional 未设置时无后果”)在 0031 之后不再成立,该记录规整每一次写入。计数仍决定“是否”,模型只回答“哪一种”。

proposed_temporal实现(crates/utopia-server/src/bootstrap_ontology.rs):从提案 JSON 的relation_types段读取temporal(state|event|eternal),按 key 与 forms 双向查询,查不到一律state——三者里最保守的,不会像event那样把valid_to收成一个点。测试a_relation_takes_the_temporal_it_was_proposed_with验证:acquired是event、capital_of是eternal、employs是state,而模型编造的第四值(ongoing)当没说、落回缺省。


七、open questions:计数止步之处

  • 叙述动词进入本体。104 个关系中:reported/report11、states/stated6、describes/described5、criticizes/criticized6——文章引用来源,公司之间没有结构。它们跨文档反复出现,计数拦不住,而本体又反馈进提示词。候选方案:让同义归并的 LLM 调用回答“这些哪些是文章的腔调”,小且可逆;一个动词列表会随下一个语料而崩坏。
  • merge_key不折_by(见 5.1)。
  • 1,500 词起点对采纳循环的影响尚未测量;没有任何阈值移动过。

八、实践建议:如何观察与干预

  • 开关:自动扩本体由知识库设置auto_extend_ontology控制(缺省开,见 crates/utopia-store/src/kbs.rs)。关闭不影响“留意”:未匹配统计照常累积、照常在 Unmatched 面板可见,只是变成你点一下的提案。
  • functional永不自动:即使开关开着,functional位也永不自动设置——它驱动时态引擎自动闭合事实、生成冲突,等发现时那些闭合本身已是一串 supersede 链,不属于“错了很便宜”那类。
  • 人工面板:静态语料可用min_docs = 0的手动面板兜底。
  • 审计:自动采纳以actor = NULL记录(“系统的动作,不是谁的决定”),台账里查得到做了什么、改了多少条、以及撤销要用的批次号。
  • 测试证据:行为由 crates/utopia-server/src/predicate_match.rs 内单元测试与 crates/utopia-server/src/bootstrap_ontology.rs 的测试守护,包括方向修正、撞车拒绝、属性不可达(attributes_are_not_reachable:字面值宾语不能成为边)与中文 key 恒等通过。

结语

Utopia 的答案一句话概括:计数决定“是否”,模型只回答“哪一种”。从 10 个种子关系、49.8% 的related_to退化,到 104 个计数采纳关系、25.8% 占比,再到 0010 彻底删除兜底谓词让事实保留原文措辞——本体增长从“模型的主观判断”变成了“语料的确定性事实”,并且每一步都可撤销、可审计、可复现。若你正在设计本体驱动的抽取管线,0007 的教训是直接的:把“够不够普遍”交给数据,把“什么意思”交给模型,把“错了怎么办”交给撤销机制。

  • 后端
  • 前端
  • 人工智能
  • RAG
  • 知识图谱
  • 知识管理
  • 搜索引擎

【免费下载链接】utopia

World's first open-source enterprise world model.

项目地址:https://gitcode.com/gh_mirrors/ont/utopia
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询