马一丁

Normalize keyword type before matching

@@ -136,6 +136,13 @@ class QueryEngine: @@ -136,6 +136,13 @@ class QueryEngine:
136 136
137 def _matches_keywords(self, node: Node, keywords: List[str]) -> bool: 137 def _matches_keywords(self, node: Node, keywords: List[str]) -> bool:
138 """检查节点是否匹配关键词""" 138 """检查节点是否匹配关键词"""
  139 + # 防御性检查:确保 keywords 为列表类型
  140 + # 若传入字符串,逐字符迭代会导致单字符匹配(如 'a', 'e'),污染结果
  141 + if isinstance(keywords, str):
  142 + keywords = [k.strip() for k in keywords.replace(',', ' ').split() if k.strip()]
  143 + elif not isinstance(keywords, list):
  144 + keywords = []
  145 +
139 if not keywords: 146 if not keywords:
140 # 无关键词时:只匹配 section 类型(避免返回整个图谱) 147 # 无关键词时:只匹配 section 类型(避免返回整个图谱)
141 # 这样至少能获取到各引擎的段落摘要 148 # 这样至少能获取到各引擎的段落摘要
@@ -151,8 +151,16 @@ class GraphRAGQueryNode(BaseNode): @@ -151,8 +151,16 @@ class GraphRAGQueryNode(BaseNode):
151 break 151 break
152 152
153 # 4. 执行查询:按 LLM 给出的参数查询本地图谱 153 # 4. 执行查询:按 LLM 给出的参数查询本地图谱
  154 + # 规范化 keywords:确保为列表类型(LLM 可能返回字符串)
  155 + raw_keywords = decision.get('keywords', [])
  156 + if isinstance(raw_keywords, str):
  157 + # 按空格和逗号分割字符串为关键词列表
  158 + raw_keywords = [k.strip() for k in raw_keywords.replace(',', ' ').split() if k.strip()]
  159 + elif not isinstance(raw_keywords, list):
  160 + raw_keywords = []
  161 +
154 params = QueryParams( 162 params = QueryParams(
155 - keywords=decision.get('keywords', []), 163 + keywords=raw_keywords,
156 node_types=decision.get('node_types'), 164 node_types=decision.get('node_types'),
157 engine_filter=decision.get('engine_filter'), 165 engine_filter=decision.get('engine_filter'),
158 depth=decision.get('depth', 1) 166 depth=decision.get('depth', 1)