名称是实体上的一条事实:utopia 实体消解如何从字符串匹配走向证据裁决
后端前端人工智能RAG知识图谱知识管理搜索引擎【免费下载链接】utopiaWorlds first open-source enterprise world model.项目地址https://gitcode.com/gh_mirrors/ont/utopia点击查看免费下载实体消解entity resolution决定哪个名字指哪个东西。utopia 的决策记录 0041docs/decisions/0041-a-name-is-a-claim-about-an-entity.md记录了这项能力的一次根本性重构名称不再是被比对、被搬运的表面字符串而是账本ledger上关于实体的一条事实召回、裁决、审核全部围绕事实与证据重新设计。本文以该决策记录为主体结合仓库内迁移脚本、store 层实现与身份基准测试完整讲解旧机制的失效原因、六项决策的内容、落地实现cut 1PR #670与测量结果读者将获得一份可对照源码逐层验证的实体消解设计指南。从一个探针和两个张伟说起决策记录开篇给出了两个具体的失败场景一台探测器的发射通告里写作海洋探测器1号此后的每一份报告里只写海探1。如果两份文档都进入系统探测器会变成两个互不相认的实体而 Review 队列里什么都没有——因为没有一个机制把它们配成一对。同一家公司的两位工程师都叫张伟。根据哪份文档先到达系统可能把他们并成一个实体或留下一个永远等人来裁的平局。这两个场景分别对应身份键identity key失效的两种方式一个字符串对应多个东西重名 namesake和多个字符串对应一个东西别名 alias。0041 的全部设计就是围绕键失效之后怎么办展开的。旧机制今天的实体消解做什么决策记录先如实描述了重构前dev分支基线的消解流程。核心入口是 store 层的resolve_mention它逐条处理提及mention而抽取任务在写事实的同时并行调用它。流程可以概括为四步加四个补充。第一步名字召回是精确字符串匹配候选实体只来自等值匹配实体的canonical_name或aliases必须等于提及的名字或等于它的recall_keys之一。recall_keys是剥掉泛用后缀后的词干及其增广形式词表定义在源码中GENERIC_SUFFIXES_CJK项目、公司、集团、部门、团队中文直接拼在词干后GENERIC_WORDS_ENproject、corp、inc、team英文按独立词处理且首尾两种语序都认Phoenix Project / Project Phoenix。name_stem剥去一个泛用后缀后返回词干recall_keys再反向增广库内是星尘项目、提及只说星尘时也能命中。除此之外没有任何其他实体被纳入考虑——这正是后续所有问题的总根源。第二步上下文向量决定归并profile_embedding是实体被提及所在各 chunk 向量的运行均值。新提及与每个候选算余弦相似度按阈值分层相似度 ≥SIM_ATTACH0.55归并到该候选相似度 SIM_NEW0.35新建实体两者之间灰区新建实体并把与候选的一对送入裁决队列。两个同名候选的分数差距不超过SIM_TIE_MARGIN0.02时说明画像分不出谁是谁——此时不归并而是对两个候选各排一条人工审核对PR #270 的规则除非corroborating_candidate在 chunk 原文里找到了某个候选的消歧宾语作为旁证PR #331比如这句话里写着财务部。第三步本名之外的名称只随合并学习merge_entities把被并方的名字追加到存活方的aliasesrevert_merge再取出来。抽取器读到的任何内容都不会成为名字——即使原文明明白白写着简称海探1这句话也不会给实体增加任何名称信息。第四步围绕主流程的四个补充containment_reviews把名字互相包含的实体对排入队列上海研究院 ⊂ 星云科技上海研究院但只对四个字符及以上的名字生效且只出候选、永不自动合并resolve_type_drift处理同名被抽成不同类型的情形同一团队可能被抽成 organization / project / concept按类型对的互斥强度分流doc_cache抽取任务内同一文档中后续出现的同类型、同小写名字的提及直接落向第一个结果没有 embedding 模型时提及归并到事实最多的候选。治理侧的 name_shape治理governance闸门里name_shape从英文词缀与介词CORPORATE_SUFFIX、 of 、s出发给名称对分类闸门拒绝合并Version或Phrase形状的对——因为模型会对 Claude 与 Claude 4 说是同一个也会对Sam Altmans efforts与 Sam Altman 说是同一个。旧机制失效的五种方式它们为什么是一个问题决策记录把失效方式逐一列清并指出它们同根同源没有桥的别名是沉默的第二个实体。海探1若出现在一篇从不写全称的文档里它匹配不上任何字符串、长度不足四个字符进不了containment_reviews于是不留任何审核行。源码注释里明确把这个洞命名并留空。上下文向量记录的是这段话在讲什么不是谁在这段话里。两个出现在同类型文档里的重名者画像几乎相同平分秋色一个人若同时出现在董事会备忘录与技术规格里画像会漂移直到某次提及掉进SIM_ATTACH之下被拆开。抽取器已经产出的证据被闲置。命名张伟的那条响应同时写着张伟 worksFor 财务部但消解发生在该事实写入之前事实只能以宾语名字在 chunk 里做子串搜索这种极弱的形式参与。结果依赖到达顺序。消解是贪心的、从不回看第一篇文档播种画像后来的文档要么附着、要么分裂。词表不会自己长大。中文后缀、英文泛用词、公司词缀、介词表覆盖的是作者当时想到的措辞且name_shape完全看不见中文名称的形状——版本/短语不合并这条保护对中文名不存在。一句话总结身份键是表面字符串主题向量只是在匹配到的字符串之间做选择。重名是一个键多个东西别名是一个东西多个键它们是同一个键失效的两面。决策 1名称是关于实体的一条事实第一项决策是整个重构的基石文本为实体使用的每一个名称都作为系统属性上的一条事实记录带出处引文、文档时间以及文本给出世界有效期时2021 年更名关闭旧名的世界有效期。entities.canonical_name保留作为界面显示的标签同时它本身也是实体的一条名称事实entities.aliases被退役——迁移把每条现有别名转成一条名称事实归属到产生它的那次合并。为什么必须是事实因为名称可能被写错、被更正、被取代、被收回——这正是账本对一切其他内容已经在做的事。作为事实名称获得两个时钟回答2019 年它叫什么世界轴与我们何时得知海探1 就是海洋探测器1号记录轴出处provenance、撤回revert导出在 RDF 导出中写作skos:altLabel。known_as值与节点的分界决策记录以name描述系统属性落地实现是内建属性known_ascrates/utopia-store/src/names.rs中的KNOWN_AS常量。关键约束是名称是值永远不是节点。名称事实把字符串放在facts.object_valueobject_id留空——与数量值走同一条通道#586、#587。画布只画带object_id的事实图的计数也只数这些所以名称不增加节点、不增加边、不增加计数。测试a_name_is_a_fact.rs直接断言记录别名后entity_detail的事实列表为空、实体度数为 0。时态引擎天然绕开known_as既不是 functional 也不是 inverse-functional重名本来就存在而temporal引擎只对声明了这两种性质之一的状态关系收口旧值、记录冲突。因此第二个名称永远不会关闭第一个、也永远不会打开冲突——名称的并存是设计内的不需要任何特判。内建属性还受到额外保护不能改成 functional、不进本体向量索引、不让本体提议把简称类值归并到它上面有测试专门验证。迁移 0055aliases 退休migrations/0055_a_name_is_a_fact.sql 是一次相当考究的数据迁移用户自建的known_askey 先让位改名known_as_uuid前8位事实原样保留每个库补一条内建known_as属性存活实体的本名各写成一条名称事实已合并实体沿merged_into链走到存活者名字事实挂在链末端并把事实 id 追加进链上每条未撤回合并的moved_subject_facts——这样撤回链上任何一环名字都跟着那一环回去重名合并产生的重复名字作废并记入invalidated_facts撤回时一并复活存活者 aliases 里剩余的条目照记最后DROP COLUMN aliases并为召回建了facts_value_text_idx索引(kb_id, lower(object_value-value))只覆盖未作废、有值的事实。迁移注释里还记录了性能考量递归走链用临时表 批量更新而不是逐行子查询否则在 20 万实体、4.5 万合并的库上要八分钟以上。决策 2抽取器上报名称服务端只核对原文名称从哪里来决策 2 划定了一个两个来源、一个契约的边界判断一段文字是在命名实体还是仅仅指称它是模型的事写进契约服务端只检查字符串是否真的在原文里。没有词表。契约在 cut 1 修订后合并为单一通道#670names: [{ ref: entity ref, name: 名称, quote: 出处引文 }]实现位于crates/utopia-server/src/extraction_open.rs的别名落库段服务端依次执行三道检查名字非空实体的引用必须能解析到已列出的东西否则打UNKNOWN_REF信号名字确实出现在 chunk 原文里span_in_quote否则打NAME_NOT_IN_TEXT信号丢弃——它不识别简称、又名、aka、formerly这些措辞也不需要识别同一个字符串不能同时是两个东西的名字若本块或本文档前面已把该名字认给另一个实体name_claimed_by_another丢弃并打信号——一个字符串不能命名两个东西这条规则不需要任何词汇表。引文默认为 chunk 原文模型写下的名称以 chunk 为证据。已知缺口模型把描述当作名称上报、却未把它声明为实体时仍然会通过——cut 1 的每次运行中海探1项目都成了海洋探测器1号的名称这是后续要处理的边界。决策 3召回有三个通道而它们都不裁决候选从三个渠道来名称通道现行与曾用的名称事实normalize_name归一化后等值匹配。曾用名仍然可召回——旧文档还在用它has_name_in只看记录轴invalidated_at不看世界轴的有效期names.rs中注释明确写了这一点名称向量通道按名称字符串的 embedding 在同类型族内取最近的名称事实top k。这是能找到海探1 ↔ 海洋探测器1号、以及两种文字书写的同一名称的通道邻居通道与本条响应中提及的事实共享独特征邻居的实体——同一谓词、同一已解析宾语且其他候选没有同时指向的那个宾语。关键立场是召回只负责提出候选从不裁决。一旦基准测试证明通道 2 能覆盖旧词表的发现能力recall_keys、GENERIC_SUFFIXES_CJK、GENERIC_WORDS_EN就退出决策 6 的节奏。决策 4证据裁决对于每个候选系统从chunk 已解析的事实与候选的现行事实之间读取证据正反两个方向支持同一个实体的证据共享一条独特征边定义同决策 3且世界有效期重叠在 ontology 声明为 inverse-functional 的谓词上取相同值且有效期重叠文本为这个实体陈述了一个名称决策 2。支持不同实体的证据反证在 ontology 声明为 functional 的谓词上取不同值且有效期重叠类型声明为 disjoint互斥同现状。事件关系不构成冲突——两个有日期的活动不是同一个槽位的两个值。两种方向都不算的数在可多值的谓词一个人可以在两家公司任职上的分歧以及共享名称在哪个方向都说明不了问题。裁决规则简洁而可审计反证排除候选。剩下唯一有正证的候选即归并剩下多个有正证的候选则新建实体并为人排一对同 #270 现状完全没有证据时走今天的老路——新建实体若通道 1 或 2 找到过候选则给裁决器排一对。上下文向量只在证据持平的候选之间打破平局其余什么都不做。当拿不准时拆开并询问——和从前一样。要让边可比一条响应内的提及在响应解析完之后才解析先解析单候选且无反证的一侧再解析歧义侧——此时歧义侧可以用它们与已解析侧之间的边。doc_cache按名字建键的做法被移除因为名字不再可信同一响应内由 handle 统一提及跨 chunk 由证据统一。决策 5到达顺序不再重要这是 cut 1 中最先落地的一步——没有它反向顺序反而更糟只写简称的文档先建出海探1写着简称海探1的那篇最后到达、把名字记在一个新建的全称实体上而两者没有任何东西配对。修订后的方案#670包含两部分共享名称即入队绝不直接合并。当一个名称已经被另一个兼容类型的实体拥有时这一对以shared_name|…进入裁决队列names::pair_shared_name由裁决器与治理闸门决定合并与否则是它们的事。裁决器与 Review 卡片会把实体的非本名显示为also known as:一行——没有这一行时裁决器在 0.90–0.95 的置信度下仍把一对分开。本名不列入所以两个重名者看起来不共享证据。同时判过不是一个的对不再重复入队resolution_reviews里status kept的对会被排除分开这个决定被记住。重新评估。实体获得新的名称事实或独特征边时它现在能召回的那些对会被重新评估并入队——走 Review 与治理闸门绝不就地合并。周期任务对共享同一名称的每组实体做同样的事。于是简称海探1的文档能找到一周前创建的海探1而基于薄弱证据作出的判断也会在更好的证据到来时被重新审视。决策 6name_shape 让位于证据闸门拒绝Version/Phrase形状是因为模型会说 Claude 与 Claude 4 相同、Sam Altmans efforts与 Sam Altman 相同。决策 4 用两条更根本的机制分别接住它们版本functional 冲突两个发布日期自动分开短语span 检查#582让Sam Altmans efforts根本成不了实体。因此name_shape与CORPORATE_SUFFIX将在基准测试证明闸门抓到的没有一条是证据漏掉的之后离开闸门。明确不做的事不做缩写、敬称、公司形式的词表——这条路上所有词表都只覆盖了作者当时想到的措辞不做学习式身份模型——决策 4 的规则小到可以通读每次归并或拆分都能说出是哪条边或哪个冲突定案的这正是 Review 卡片与审计员都需要的可解释性不做基于名称相似度的合并——通道 2 负责找候选证据负责裁决两个职责不混。度量identity 基准测试决策记录要求每次运行报告顺序差异配套的测量台在scripts/bench/identity.mjs与recall.mjs、govern.mjs并列。它的方法论值得一提一小段双语语料scripts/bench/corpora/identity/下 d00–d11 共 12 篇文档 一份真值文件scripts/bench/truth/identity.json真值把提及按所指实体分组打分是same entity的两两精确率与召回率外加送给人裁决的对数名字不参与打分——锚点按引文含quote_has、类型、角色、另一侧含other_has解析到幸存实体 id再两两比较 id 是否相同否则别名与重名会先搅乱打分本身语料覆盖一家公司两个重名者跨文档、同一文档两个重名者、一个人跨无关文档、全称简称两种到达顺序、带日期的更名、中英双名以及必须分开的近似物两家公司的技术中心、产品与其下一代、公司与一种水果每一轮正序、倒序各建一个库冻结自动扩本体、类型消解、治理、物化报告两边判决不一致的对占多少ai-timeline.duplicates.json作为回归测试并行运行。运行方式环境变量与recall.mjs相同node scripts/bench/identity.mjs --label 名字 # 正序 倒序各建一个新库 node scripts/bench/identity.mjs --label 名字 --order forward node scripts/bench/identity.mjs --score kb id # 只给已有库打分结果决策记录 status 行基线devforward F10.43reverse F10.54cut 1#670 落地后forward0.68reverse0.68两种顺序在全部 210 对上判决一致各跑一次两次 cut 1 运行 forward 相差 0.07在 DeepSeek-V3 上复查修复后dev 0.46 / 0.4021 个锚点中 2 个未解析cut 1 三次运行 0.61 / 0.44–0.53且在 V3 上即使共享名称已列出裁决器在倒序下仍能把海洋探测器1号与海探1分开——这正是 cut 3证据裁决要回答的问题。分刀实施决策记录把落地拆成五刀每刀可独立测量cut 0identity 基准测试以及dev上的基线cut 1已实现#670名称成为事实决策 1、抽取器上报名称决策 2、召回读取它们决策 3 通道 1合并与撤回搬动名称事实entities.aliases迁移并删除cut 2未开始召回通道 2 与 3名称向量、邻居cut 3未开始证据裁决决策 4响应解析完后再解析提及doc_cache按名建键退出cut 4未开始重新评估决策 5name_shape与泛用后缀词表在基准测试同意后退出决策 6。实体面板按来源与有效期列出名称、Review 卡片上的证据行将在 cut 3 落地后跟进。源码与测试导览若想深入验证本文的每个论断以下路径是最直接的入口决策全文与上下文docs/decisions/0041-a-name-is-a-claim-about-an-entity.md以及其关联记录 0009未决类型是诚实状态、0016声明的disjointWith让名字分开、0025重复项进队列由 agent 处理、0037属性上边消解实现crates/utopia-store/src/resolution.rsresolve_mention、阈值常量SIM_ATTACH/SIM_NEW/SIM_TIE_MARGIN、recall_keys、containment_reviews、resolve_type_drift名称事实模块crates/utopia-store/src/names.rsrecord、has_name_in、not_a_name、pair_shared_name、other_names抽取契约核对crates/utopia-server/src/extraction_open.rsnames落库与三道检查、NAME_NOT_IN_TEXT/NAME_CLAIMED_BY_ANOTHER信号数据迁移migrations/0055_a_name_is_a_fact.sql身份基准scripts/bench/identity.mjs、scripts/bench/truth/identity.json、scripts/bench/corpora/identity/d00-profile.txt行为测试crates/utopia-store/tests/a_name_is_a_fact.rs名称是事实、不进事实列表、合并/撤回搬运、共享名入队不合并、判过的对不再排以及同目录下的a_namesake_tie_goes_to_review_not_a_coin_flip.rs、facts_corroborate_an_identity.rs、an_untyped_name_meets_its_namesake.rs等。0041 的最终形态是把名字是字符串这一个默认假设替换为名字是账本上可修正、可撤回、带双时钟的事实召回只提候选证据才做裁决拿不准就拆开并询问。这套原则不止修好了重名与别名两类失效也让每一次身份判断都能在 Review 卡片上向人与审计员交代为什么。赞分享后端前端人工智能RAG知识图谱知识管理搜索引擎【免费下载链接】utopiaWorlds first open-source enterprise world model.项目地址https://gitcode.com/gh_mirrors/ont/utopia点击查看免费下载相关推荐Utopia 实体消解决策可追溯一次裁决记下的是为什么ADR 0026 深度解析Utopia 实体消解决策可追溯一次裁决记下的是为什么ADR 0026 深度解析 Utopia 世界首个开源企业级世界模型 https://link后端前端人工智能RAG知识图谱知识管理搜索引擎如何用h265web.js实现多协议直播播放HTTP-FLV/HLS/WebSocket实战如何用h265web.js实现多协议直播播放HTTP FLV/HLS/WebSocket实战 h265web.js是一款由常炎隆开发的高性能HEVC/H.26音视频视频直播电商平台商品名称智能纠错Fuzzywuzzy模糊字符串匹配实战指南电商平台商品名称智能纠错Fuzzywuzzy模糊字符串匹配实战指南 在电商平台运营中商品名称的准确性直接影响搜索排名和用户体验。当用户输入无线蓝牙耳机却数据清洗创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考