feat(search): append raw entity fields after view_node summary

view_node 按题两轮摘要(summarize_node)会吞掉 entities/visible_text
字段信号,Agent 站在证据节点上仍漏读实体(benchmark 错题 M1,案例
786-2、872-3、750-1)。dispatcher 侧在摘要后确定性追加 [实体]/[画面
文字] 原文区块,LLM 无法吞掉。

- TreeEnvironment.node_entity_fields:按层级取 card 实体字段原文,
  去空白、去重、分号拼接;空字段省键;未知节点抛 KeyError
- _handle_view_node Phase 2.5:摘要后、子节点概览前追加实体区块
- 附带 ruff format 修正 test_tree_environment.py 两处既有格式

算法 #11(树环境语义搜索)数据访问层扩展,不改搜索算法本身。
This commit is contained in:
2026-07-11 08:53:56 -04:00
parent 291a8108e1
commit 4e0e05210d
4 changed files with 226 additions and 2 deletions
+45
View File
@@ -86,6 +86,13 @@ def _collect_card_strings(
# subtitle 字段在 _node_full_text / _node_anchored_text 中单独处理
_SUBTITLE_SKIP: frozenset[str] = frozenset({"subtitle"})
# 各层级 card 的实体字段名(B 修复:dispatcher 追加原文用)
_ENTITY_FIELDS_BY_LEVEL: dict[str, tuple[str, ...]] = {
"L1": ("key_entities",),
"L2": ("entities",),
"L3": ("visible_entities",),
}
def _collect_from_obj(
obj: object,
@@ -214,6 +221,44 @@ class TreeEnvironment:
return "\n".join(parts)
def node_entity_fields(self, node_id: str) -> dict[str, str]:
"""返回节点 card 的实体/画面文字字段原文。
供 dispatcher 在按题摘要后确定性追加,防止 LLM 摘要吞掉
entities/visible_text 信号(benchmark 错题 M1 恶化因素)。
参数:
node_id: 节点 ID。
返回:
{"实体": "...", "画面文字": "..."},空字段不含对应键。
异常:
KeyError: 节点不存在。
"""
node = self._id_to_node.get(node_id)
if node is None:
raise KeyError(f"节点不存在: {node_id}")
level = _node_level(node)
out: dict[str, str] = {}
entity_values: list[str] = []
for field_name in _ENTITY_FIELDS_BY_LEVEL[level]:
for value in getattr(node.card, field_name) or []:
if isinstance(value, str) and value.strip():
entity_values.append(value.strip())
if entity_values:
out["实体"] = "; ".join(dict.fromkeys(entity_values))
text_values = [
v.strip()
for v in (getattr(node.card, "visible_text", None) or [])
if isinstance(v, str) and v.strip()
]
if text_values:
out["画面文字"] = "; ".join(dict.fromkeys(text_values))
return out
def search_similar(
self,
query: str,