ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Hindsight 实体解析深度解析:为什么 Agent 记忆用共现图而非 Embedding 来消歧

Hindsight 实体解析深度解析:为什么 Agent 记忆用共现图而非 Embedding 来消歧 Hindsight 实体解析深度解析为什么 Agent 记忆用共现图而非 Embedding 来消歧【免费下载链接】hindsightHindsight: Agent Memory That Learns项目地址: https://gitcode.com/GitHub_Trending/hindsight2/hindsight本篇技术指南围绕 Hindsight 的实体解析Entity Resolution机制展开它是 Agent 记忆层判断Sarah、Sarah Chen与she是否指向同一个人的核心决策模块。文章将拆解 Hindsight 基于名称相似度、共现图与时间近因的三信号加权评分方案并结合仓库源码说明entity_cooccurrences共现图如何完成同名人消歧、context与 enum 实体标签两把可靠杠杆的用法以及三张核心数据表的落地形态。读完你将理解为何保守合并对记忆系统是更优策略并能直接在自己的 Hindsight 部署中验证与调优解析行为。TL;DR实体解析Entity Resolution判定两条不同的 mentionSarah、Sarah Chen、she是否指向同一真实世界实体并把它们关联起来。Hindsight 在事实抽取阶段用 LLM 抽取实体但解析阶段不使用 Embedding也不依赖 LLM 判断。解析是一个加权评分名称相似度0.5 共现重叠0.3 时间近因0.2总分越过0.6阈值即解析到已有实体否则新建实体。共现图entity_cooccurrences表是差异化武器实体与谁一起出现决定了两个同名的人能否被区分开。系统刻意保守不确定时不合并而是依赖检索期的图谱链路补齐绝不冒险折叠记录。想要前置保证解析可靠retain 时传入context字符串或把已知人员名单声明为enum 实体标签让 mention 按精确匹配映射到固定词表。实体解析到底在解决什么问题三个术语经常被混用但它们并不相同实体抽取Entity Extraction从一句话中把 Sarah 拉出来。实体解析Entity Resolution判断这次出现的 Sarah 和上周存储的 Sarah 是同一个人。基于实体的检索Entity-based RetrievalAgent 提问时用已解析的身份把相关历史全部取回。记忆系统三者缺一不可但解析是最难的环节。抽取是成熟的 LLM 任务检索本质是一次数据库 join而解析是夹在中间的判断题——记忆层正是在这里悄然成功或失败。偏左犯错是过度合并两个同名 Alex 被折叠成一条自相矛盾的记录Agent 会自信地把内部冲刺信息告诉客户。偏右犯错是合并不足Sarah 与 Sarah Chen 保持分离一次关于 Sarah 的召回会漏掉她一半的历史。解析的全部工作就是同时避开这两个陷阱。显而易见的方法以及 Hindsight 为什么不用2026 年的默认直觉是把每个实体 mention 做 Embedding按余弦相似度合并或者问 LLM 这两个是同一个人吗。两种方法都有效且各有真实优势——Embedding 能捕捉字符串匹配抓不到的语义等价LLM 能推理分数无法体现的上下文。但它们在记忆场景下的失败模式比在搜索场景下更致命Embedding 相似度是黑盒。当它错误地把客户 Apple和水果 Apple合并时你无法轻易看出原因不重新 Embedding 就无法调优。每个实体、每条事实都调用一次 LLM 又慢又非确定而且会偶尔且不可预测地把两个陌生人判定为同一个人。Hindsight 优化的是另一个性质错误的合并应当罕见、廉价可调试、且永不静默。因此解析运行在工程师可以直接读懂的信号上。这个取舍是诚实的——Embedding 确实能捕获一些本方案漏掉的等价关系但漏掉是安全的不过是多一条重复记录而避免掉的错误才是危险的一条被污染的记忆。三个信号0.5 / 0.3 / 0.2 的加权评分当一条新事实进入时其抽取出的每个实体都会与同一记忆 bank 中的已有实体逐一匹配。对每个候选Hindsight 计算加权分数score name_similarity * 0.5 # difflib SequenceMatcher, 0–1 score cooccurrence_overlap * 0.3 # shared neighbors in the graph score temporal_proximity * 0.2 # recency, within a 7-day window if best_score 0.6: resolve_to(best_candidate) # same entity else: create_new_entity() # mint a fresh record这段伪代码与仓库中的真实实现一一对应。在 entity_resolver.py 的_resolve_from_candidates评分循环中名称相似度权重 0.5使用 Python 标准库difflib.SequenceMatcher的字符串比率。Sarah vs Sarah 得 1.0Sarah vs Sarah Chen 约 0.7。候选的获取依赖 PostgreSQL 的pg_trgmtrigram 索引entity_lookuptrigram策略一个大型 bank 只需返回每个 mention 的一小撮模糊匹配而非全表扫描——源码注释中记录这能把每个实体的数据传输从 165K 行降到约 5~20 行见_resolve_entities_batch_trigram。共现重叠权重 0.3是最有意思的信号下一节专门展开。时间近因权重 0.2把解析推向近期出现过的实体。如果匹配名称两天前刚出现过能拿到大部分时间权重如果六个月前出现的则几乎拿不到。你正在谈论的人更可能是你指的那个人。源码中时间窗口为 7 天days_diff 7时temporal_score max(0, 1.0 - days_diff / 7)再乘 0.2 计入总分。0.6阈值就是保守旋钮。一个 mention 必须跨过这个真实门槛才能并入已有记录达不到就新建实体而不是猜测——重复可恢复坏合并不可逆。值得补充的源码细节评分之前还有一道三角锁。候选必须先通过 pg_trgm 相似度下限merge_min_similarity默认 0.3与逐词兼容性检查_tokens_are_compatible防止John Smith/Jane Smith这类共享长词的名称靠整体相似度蒙混过关源码注释以 0.47 trigram、0.80 sequence ratio 的具体数字记录了这个真实 bug。而0.6阈值采用四舍五入到 6 位后比较规避了二进制浮点数导致恰好 0.6 却判定失败的边界问题。共现图如何完成消歧仅靠名称相似度无法区分两个同名 Alex但共现图可以。Hindsight 维护一张entity_cooccurrences表每当两个实体在同一条事实中出现它们的配对计数就加一。经过几周对话积累这张图就构成了谁和谁一起出现的地图——正是它承担了消歧的重任。设想这样一个场景你的 bank 里有两个 Alex。一个是前端团队的 Alex与 React、Sprint 14、staging deploy 共现另一个是Acme 的客户 Alex与 renewal、SOC 2 review、Acme 共现。同名但在图里处于两个完全不同的邻域。一条新事实落地Alex flagged a blocker on the Acme renewal.。mention Alex 按名字拉出两个候选名称相似度打平都是 1.0。但这条事实还提到了 Acme 和 renewal——与客户 Alex 的共现重叠很高与工程师 Alex 的重叠为零。0.3 的图权重打破了平局事实挂到了正确的 Alex 名下。仅凭名字任何 Embedding 都做不到这件事因为名字完全相同。解决它的信号不是实体是什么而是它在什么旁边。这正是多数直接 embed设计丢掉的部分。仓库实现印证了这套机制在_resolve_from_candidates中每个 mention 携带的nearby_entities与候选实体的共现邻居集合做交集加权。更精细的是_cooccurrence_weight——共现伙伴的区分度会被反平方根衰减1 / sqrt(degree)。一个像user这样的枢纽实体与几乎所有东西共现若不加权它会与罕见伙伴投出相同分量的一票足以把新人的事实错误合并到无关实体上源码注释记录了 issue #3751。看到过 1 个其他实体的伙伴保留完整票权看到过 100 个的只值 0.1看到过 1500 个的只值 0.026。解析后的实体如何驱动检索解析如果不能改变 Agent 召回的内容就只是纸上谈兵。它驱动的是实体链路扩展entity-link expansion——Hindsight 并行混合检索的实体分支。当查询命中一组种子事实时Hindsight 收集这些事实中的实体沿实体出发扩展到所有提及同一实体的其他事实按候选与种子共享的实体数量打分。问一句 whats the status of the Acme renewal落在几条种子事实上扩展就会把触碰 Acme-Alex、renewal、SOC 2 review 的所有事实都拉进来哪怕它们从未使用 status 这个词。这就是解析质量会复利的原因每一次正确的解析都在事实之间加厚链路让检索用更少的提示词触达更多相关历史。它也与语义链路、因果链路、时间感知链路并行共存而非替代——一次实体匹配的遗漏往往能被另一条检索策略兜住。如何确保实体正确解析解析器按设计偏向保守这意味着有些时候它会保持两条记录分离而你可能希望它们合并。当解析准确率至关重要时你有两把杠杆且它们都作用在评分之前、抽取之时——远比事后祈祷名称相似度越过 0.6 可靠。给抽取器提供上下文每次 retain 调用都可以在内容之外带一个可选的context字符串。它被直接织入抽取提示词并在归因谁说了什么、谁做了什么时优先于模型的默认假设。这对对话记录与多方文本尤其重要——I、she、the customer 单独看都是歧义的。告诉抽取器房间里都有谁第一人称陈述就会归到正确的人名下而不是默认归给 Agent。抽取出的实体从一开始就指向你点名的那些人解析需要猜测的空间就小得多。client.retain( contenttranscript, contextSupport call between agent Maria Lopez and customer John Doe (Acme)., )使用 enum 模式的实体标签如果你已经知道完整的演员表——一个项目的人员、一个产品目录、一套支持分类体系——就不要让解析器重新发现它。把这些值声明为 bankentity_labels配置中的实体标签entity label抽取就会被约束为把每个 mention 映射到其中之一。底层实现中value类型的标签会编译成 Pydantic 的Literal[...]约束见 entity_labels.py 的build_labels_modelvalues元组被构造为Literal[values]模型无法返回清单之外的值。而标签实体按精确匹配解析不走模糊评分——Sarah、Sarah Chen、she 全部折叠到你定义的那一个规范值上0.6阈值完全退出游戏实现见_resolve_from_candidates中is_label分支仅做LOWER(canonical_name)大小写不敏感精确比对。{ entity_labels: { attributes: [ { key: person, type: value, values: [ { value: sarah-chen, description: Eng lead, frontend }, { value: alex-kim, description: PM, growth } ] } ] } }enum 模式是 Hindsight 提供的最可靠的解析杠杆。代价是它只适用于已知且有界的集合固定团队或有限目录很理想边用边发现的开放演员表就不合适。开放场景下context字段加共现图才是正确工具。如果你已在上游识别好实体也可以通过 retain 调用的entities字段直接传入。数据模型一览三张表承载了整个系统它们的朴素本身就是亮点entities每行一个规范实体含canonical_name、mention_count、first_seen、last_seen以及UNIQUE (bank_id, LOWER(canonical_name))约束——在数据库层面做大小写不敏感的排重。模型定义见 models.py唯一索引在初始迁移 5a366d414dce_initial_schema.py 中创建。unit_entities事实与实体的多对多关联junction table见 models.py。entity_cooccurrences共现图本身(entity_id_1, entity_id_2, cooccurrence_count, last_cooccurred)带CHECK (entity_id_1 entity_id_2)保证每对只存一次见 models.py。写入走INSERT ... ON CONFLICT ... DO UPDATE累加计数并取GREATEST更新时间。不需要外部图数据库也不需要为实体单独建向量库。存储层就是承载一切的同一套嵌入式 PostgreSQL这让自托管保持一条 Docker 命令的简洁。工程诚实的部分不进营销图表的细节才是真正的工作量所在。标签按精确匹配解析是有意为之。像pedagogy:scaffolding这样的受控词表实体完全跳过模糊匹配——因为 trigram 相似度会欣然合并两个本应不同的标签值悄悄毁掉一套分类体系。这个边界情况源自一个真实 bug源码注释中的 GH-1558。Unicode 小写化是个陷阱。Python 的str.lower()与 PostgreSQL 的LOWER()在土耳其点号 İ 上行为不一致Python 产出两个字符Postgres 只产出一个。如果应用在一侧小写、数据库在另一侧那么 İstanbul 与自身比对都会失败。Hindsight 让比较两侧都由数据库做小写化保证双方一致——_resolve_from_candidates中冲突回退 SELECT 的注释完整记录了这一坑Python 产出i\u0307stanbulPostgres 产出istanbul并且专门用test_resolve_entities_batch_handles_unicode_lower_conflicts测试钉住该行为见 test_entity_resolver.py。并发 retain 存在竞态。两个 worker 可能同时尝试创建同一个实体。新实体以INSERT ... ON CONFLICT DO NOTHING写入再用随后的SELECT找到胜出的那一行于是一次竞态只产出一个实体而不是两个或一个错误。mention 计数与共现更新被延迟到事务提交后、按固定锁顺序刷新flush_pending_stats按 entity_id 与(entity_id_1, entity_id_2)排序执行executemany避免循环锁依赖导致的死锁。batch 内去重与候选上限同样值得注意同一 retain 中新建的表面变体大小写、emoji、后缀、错别字会在写入前按内存中的 trigram 相似度聚簇成一个实体_intrabatch_canonical_map相似度阈值默认 0.5而每个 mention 的评分候选被entity_resolution_max_candidates默认 200封顶并在每 256 个候选之间主动让出事件循环_SCORING_YIELD_EVERY避免大 batch 的同步字符串比较阻塞 worker 的健康探针GH-3211。它不做的事诚实面对边界比功能清单更重要。Hindsight不会追溯合并规范实体。如果 Sarah 和 Sarah Chen 最终成为两条记录后来的共现会加强它们之间的图链路但不会把两者折叠成一个。也没有实体拆分操作如果两个真实的人早期被错误合并系统没有内置办法把他们拆开。同样没有别名表——身份是从名字加图结构中涌现出来的而不是一份精心维护的映射。这些是刻意的选择不是疏漏。追溯合并与拆分恰恰是批量执行时会灾难性出错的操作而保守路径——宁可重复读取时靠图——让失败模式保持平淡。如果你的用例需要激进的规范化那是有充分理由去评估其他系统的Hindsight 优化的方向是不污染记忆。如何亲眼看一看如果你在运行 Hindsight实体表可以直接查询mention_count告诉你哪些实体主导了一个 bankentity_cooccurrences展示邻域结构。这是核对你的 Agent 到底认为世界长什么样的好方法。你可以自托管整套系统后直接检查这张图或在云端免费层起步。常见问题Hindsight 用 Embedding 做实体解析吗不用。Embedding 驱动的是系统其他部分的语义检索而实体解析本身使用字符串相似度、共现图和时间近因。目标是可调试的保守合并而非最大化召回。它如何区分两个同名的人靠邻居。共现图记录哪些实体一起出现所以 Alex 靠近 Acme 与 Alex 靠近 Sprint 14 解析到不同的记录即使名字完全相同。不确定时会怎样新建实体。解析只在加权分数越过0.6时合并。一条重复记录可以容忍一次错误合并会污染 Agent 对一个人的记忆因此系统偏向安全的那类错误。如何确保正确的实体被合并两把杠杆都在抽取阶段。retain 时传context字符串告诉抽取器谁在场归因时优先采用以及在演员表已知时把这些值声明为 enum 实体标签让 mention 按精确匹配映射到固定词表。两者都比事后依赖名称相似度评分可靠。如果后来得知两条记录是同一个能合并吗不能自动完成。它们之间的共现链路会加强帮助检索同时触达两者但 Hindsight 不会追溯折叠规范实体也没有拆分操作。延伸阅读仓库内文档 hindsight-docs/blog/2026-06-02-entity-labels-automatic-memory-tagging实体标签受控词表一侧的深入介绍。解析与合并背后的引擎入口memory_engine.py、retain/orchestrator.py。实体相关测试hindsight-api-slim/tests/下test_entity_resolver.py含 Unicode 小写冲突、标签实体、模糊评分边界、per-mention resolve 标志等用例、test_entity_intrabatch_clustering.py钉住内存 trigram 相似度与 Postgres 逐字节一致。【免费下载链接】hindsightHindsight: Agent Memory That Learns项目地址: https://gitcode.com/GitHub_Trending/hindsight2/hindsight创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表