
RuntimeError: dictionary keys changed during iteration
快速结论:此报错发生在 RAGFlow 的 GraphRAG 知识图谱生成任务的实体解析合并阶段。由于多个异步协程并发修改同一个 nx.Graph 对象,导致在迭代 graph.neighbors() 等字典视图时视图失效。优先排查 rag/graphrag/entity_resolution.py 和 rag/graphrag/general/extractor.py 中的并发控制逻辑。
问题场景
用户在 RAGFlow 中运行 GraphRAG 知识图谱生成任务,配置了实体解析(Resolution)和社区检测(Community)。任务在实体解析完成候选对合并后,合并阶段崩溃,报错 RuntimeError: dictionary keys changed during iteration。用户环境为 Kubernetes Pod(Linux amd64),8 vCPU / 16 GB RAM,LLM 提供方为 Azure OpenAI(gpt-5.4),嵌入模型为 text-embedding-3-large,文档存储为 Elasticsearch。任务运行约 13.2 小时后失败,重试后在同一位置再次失败。
报错原文
[ERROR][Exception]: dictionary keys changed during iteration
原因分析
在 rag/graphrag/entity_resolution.py 合并阶段,代码创建了多个并发异步任务来修改同一个 nx.Graph 对象:
max_concurrent_tasks = 5
semaphore = asyncio.Semaphore(max_concurrent_tasks)
async def limited_merge_nodes(graph, nodes, change):
async with semaphore:
await self._merge_graph_nodes(graph, nodes, change, task_id)
tasks = []
for sub_connect_graph in nx.connected_components(connect_graph):
merging_nodes = list(sub_connect_graph)
tasks.append(asyncio.create_task(limited_merge_nodes(graph, merging_nodes, change)))
await asyncio.gather(*tasks, return_exceptions=False)
asyncio.Semaphore(5) 允许最多 5 个协程同时持有信号量。如果 _merge_graph_nodes 在迭代 graph.nodes 或 graph.neighbors()(返回活字典视图)时 await(例如等待 LLM 摘要调用),控制权会交给另一个协程,后者可能会添加/删除节点,从而使前一个协程的字典视图失效,触发该错误。根本原因在于连通组件分区只保证待合并节点之间不重叠,但它们的邻居节点可能重叠,因此两个协程仍可能修改共享图对象的重叠区域。
环境排查
- 确认 RAGFlow 版本:v0.24.0-531-gc3387cd5b(或相关提交 ID)
- 确认 Python 版本(容器内部版本)
- 确认 LLM 提供方和模型:Azure OpenAI(gpt-5.4)
- 确认图库版本:networkx(
nx.Graph) - 检查
rag/graphrag/entity_resolution.py和rag/graphrag/general/extractor.py中的并发控制逻辑
解决步骤
- 修改
rag/graphrag/general/extractor.py中的_merge_graph_nodes方法:将graph.neighbors(node1)的迭代改为快照方式,防止字典视图失效。即将第 322 行:
for neighbor in graph.neighbors(node1):
改为:
for neighbor in list(graph.neighbors(node1)): - 检查并处理其他可能受影响的迭代:将相同的快照模式应用于所有在并发上下文中直接迭代图视图的代码。特别是
graph.nodes[node1](第 319 行)和graph.get_edge_data(...)(第 325/329 行),如果并发任务在检查和访问之间删除了该节点/边,这些操作也可能受影响。 - 备选方案(可优先尝试):如果上述快照方案不能完全解决问题,可以将
asyncio.Semaphore(5)改为asyncio.Semaphore(1),将合并操作序列化。但这会降低并发性能,应作为临时方案。 - 提交修复:将修改后的代码重新部署到 RAGFlow 实例并重启任务。
验证方法
重新运行 GraphRAG 知识图谱生成任务。确认实体解析合并阶段不再抛出 RuntimeError: dictionary keys changed during iteration,任务进度正常推进到社区检测阶段。监控日志中不应出现 progress: -1.0 或重试计数增加。



