feat(entity-linker): 实体关联记忆全链路 - #114
Conversation
|
|
|
head_sha: 变更摘要本 PR 实现了实体关联记忆(entity-linker)的全链路功能:从记忆内容中抽取实体、建立"实体 → 关联记忆 id"反向索引并持久化到 Elasticsearch,到召回阶段通过实体锚定记忆候选。同时, 主要改动
|
|
head_sha: 代码审查所有 34 个文件已审查完毕。以下是汇总。 审查结论汇总
整体风险评估:中等偏低。核心链路(Docker 构建、配置展开、bootstrap 注册、ES 存储、builder/recaller 编排)无阻断性问题。唯一的 P2 问题(英文 2 字符实体丢失)在中文场景(本项目主要面向)不触发,但英文模式下会影响 NER 召回覆盖率。三个 P3 项均为非关键质量改进。建议在合入前修复 P2 问题。 逐文件审查结果
💬 仅评论 |
| ent_tokens[-1].i + 1, | ||
| 0.95, | ||
| 0, | ||
| ) |
There was a problem hiding this comment.
head_sha: 1cf91231969c92622f1dc7076bb93b8662747f9c
🟡 Medium Priority
建议:在 _add_ner_candidates 和 _add_proper_name_candidates 调用 _add_candidate 时传入 language="en"(显式但语义不变),同时将 _add_candidate 内英文最小长度从 2 放宽为 1(与中文一致),然后在英文路单独增加更细粒度的无效词/停用词过滤。
| ), | ||
| normalizer=EntityNormalizer(), | ||
| admission_policy=EntityIndexAdmissionPolicy(), | ||
| ) |
There was a problem hiding this comment.
head_sha: 1cf91231969c92622f1dc7076bb93b8662747f9c
🟡 Medium Priority
changed line: _build 函数(第 111-130 行)中 entity linker 的构造链路——EntityStoreProducer.dep() → EntityLinkService(...) 以及内部的 EntityExtractor(...) / EmbedderProducer.dep()——没有任何 try/except 保护。
affected behavior: 若 entity store 后端不可达、spaCy 模型未安装、或 EntityLinkService 构造过程抛出任何异常,整个 _build 函数崩溃,导致 HybridIndexBuilder 无法创建,fulltext + vector 索引构建也一并不可用。
failure mode: 这与 EntityIndexBuilder 自身的设计原则矛盾——entity 索引被明确定义为"增强层,坏了不拖累主流程"(见 entity_index_builder.py docstring 第 6 行),但 producer 工厂函数没有任何降级保护,entity 链路故障会级联到整个索引子系统。
suggested fix: 将 entity linker 构造逻辑包裹在 try/except 中,失败时 log warning 并保持 entity_linker = None,让系统以降级模式运行(只有 fulltext + vector,无 entity 索引)。
建议:将第 112-130 行的 entity linker 构造逻辑用 try: ... except Exception as exc: logger.warning(...); entity_linker = None 包裹,失败时保持 entity_linker=None 以降级模式继续。
|
|
||
|
|
||
|
|
||
|
|
There was a problem hiding this comment.
head_sha: 1cf91231969c92622f1dc7076bb93b8662747f9c
🟡 Medium Priority
changed line: HybridIndexBuilder.remove_with_scope(第 90-93 行)仅委托给 _fulltext_builder 和 _vector_builder,未调用 _entity_builder 的任何清理方法。
affected behavior: 当通过 scope 批量删除索引条目时,fulltext/vector 索引被正确清理,但 ES 中对应的实体文档及其 linked_memory_ids 不会被更新——这些 entity 记录仍保留已被删除的 memory_id,成为孤立链接。
failure mode: 召回侧通过实体检索命中这些孤立 entity 记录后,取到的 linked_memory_ids 指向已不存在的 memory,导致召回结果含无效 unit_id;后续检索链路可能因查不到对应 unit 而出错或返回空结果。
suggested fix: 要么为 EntityIndexBuilder 增加 remove_with_scope 方法(利用 space_id + unit_ids 进行 unlink),要么在 HybridIndexBuilder.remove_with_scope 中至少记录 warning 并在文档中标注 entity 索引不会随 scope 删除。
| 为 `EntityIndexBuilder` 增加 `remove_with_scope(self, unit_ids: list[str], scope: Scope) -> None` 方法,内部对每个 unit_id 调用 `self._linker.unlink_memory(space_id=space_id_from_scope(scope), memory_id=uid)`;然后在 `HybridIndexBuilder.remove_with_scope` 中增加 `if self._entity_builder is not None: self._entity_builder.remove_with_scope(unit_ids, scope)`。 |
869e138 to
71019d8
Compare
71019d8 to
093cd82
Compare
|
head_sha: 大特性要在docs feature construction里添加设计文档 |
1a33f43 to
65b1d94
Compare
|
head_sha: 路径不对,应该在 construction下继承extractor.py,并在extractor_impl里实现 |
|
head_sha: 命名不符合规则,能否继承graph实现 |
|
head_sha: 默认实现应装配到stroage.py里 |
新增实体反向索引链路:写入侧 HybridIndexBuilder 组合 EntityIndexBuilder,
经 EntityLinkService 抽实体→归一化→embedding→写 entity 索引;召回侧新增
EntityRecaller 两阶段匹配(hash 精确 + 向量 kNN),接入 pipeline_retriever。
EntityStore 走 Elasticsearch,复用主链路同集群。
EntityExtractor 国际化:
- spacy_models.py: get_nlp_full 接受 model_name 按名缓存单例,失败不重试
- extractor.py: 加 model_name/language,五路抽取按语言分流——NER/专名 span/
名词短语三路走中文或英文分支,技术标识符/引号两路语言无关复用
- 中文 NER 接受双套标签集(NAME/ORGANIZATION/LOCATION + PERSON/ORG/GPE)
- 中文专名 span 去掉 isupper() 判断,改靠 PROPN 或 nr/ns/nt/nz 词性
- 中文 noun_chunks 不可用时整路返空降级
- _add_candidate 加 language 参数,中文最小长度阈值降到 1(2字实体如张三/北京)
- 写入侧(hybrid_index_builder)与召回侧(entity_recaller)工厂均注入
config.get("entity_extractor_model", "en_core_web_sm")
镜像构建按配置装 spaCy 模型:
- local/online Dockerfile 加 ARG SPACY_MODELS=en,构建期 python -m spacy
download 装入 site-packages
- compose build.args 从 .env 传入 SPACY_MODELS,决定装中/英/两者
- config.yml/.env.example 加 entity_extractor_model 与 SPACY_MODELS 说明
65b1d94 to
d253a27
Compare
Paired: GitHub #114 ↔ GitCode !194
What type of PR is this?
/kind
Self-checklist:(请自检,在[ ]内打上x,我们将检视你的完成情况,否则会导致pr无法合入)