将图视为架构与将图视为数据:先有LangGraph,后有GraphRAG
为何 GraphRAG 并非向量搜索的默认升级方案,LangGraph 的控制流图与知识图谱有何不同,以及具备人工干预功能的检查点式故障分类代理。
来源: Graph as Architecture, Not Graph as Data: Why I Stopped Reaching for GraphRAG First
在新的智能体项目中,人们的第一反应往往是选择GraphRAG。这并非因为经过实测它比普通的向量搜索在团队自身的数据流上表现更优,而是因为知识图谱看起来更为先进——拥有实体、边以及结构化的遍历方式,而非仅依赖模糊的相似度判断;就如同标准化的数据架构即便在现有电子表格已能满足需求时,仍显得“更正确”一样。
关于图结构构建以及如何将海量语料转化为智能体可用的知识图谱的文章进一步强化了这种观念:将图结构视为智能体记忆的理想载体。许多设计最初并非从“是否需要超越相似度匹配的检索方式——如果需要,该采用哪种?”这样的具体问题出发,而是将其视为一种通用的检索原则,首先询问“我们是否需要图数据库?”
接连发表的两篇论文让这一假设值得重新审视,而非盲目沿用。
第一篇是评估论文《本质上的真实性能提升有多显著?GraphRAG的公正评估框架》(arXiv:2506.06331)。该论文对许多早期宣称的高胜率结果背后的“大语言模型作为评判者”的评估方法进行了审查。成对的评判者存在常见的偏见:位置偏见(交换答案顺序会使报告的胜率差异超过30个百分点)、长度偏见(更长、更复杂的答案会在风格评分上占优),以及试验偏见(相同的对比在不同重复测试中会得出不同结果)。经过修正后,某种流行方法相对于基准RAG所宣称的66.7%胜率降至约39%,甚至低于随机猜测的水平。这并非“提升幅度较小”,而是“在消除评判者偏见后,该方法在该评估中的优势可能根本不存在”。
第二个是GraphRAG-Bench(arXiv:2506.02404,几乎已在2026年的ICLR上被接受),其目的是减少对评估者胜率的依赖,转而通过十六个学科中可验证的问题,将GraphRAG方法与纯文本块检索进行对比评估。对于实际应用而言,关键结果在于:在许多实时RAG系统中最常见的简单事实查询——“X是什么”这类问题中,纯文本块检索的得分为60.9,而基于图的检索方法得分为60.1。两者实际上持平;即便加入网络构建、存储及查询复杂度等因素,该类别的检索效果也并无明显提升。
GraphRAG-Bench results by question category (approximate, from published results)
+----------------------------+---------------+---------------+------------+
| Question category | Text chunks | Graph retrieval| Winner |
+----------------------------+---------------+---------------+------------+
| Simple fact retrieval | 60.9 | 60.1 | Tie |
| Complex reasoning | 42.9 | 53.4 | Graph +10.5|
| Contextual summarization | 51.3 | 64.4 | Graph +13.1|
+----------------------------+---------------+---------------+------------+
需谨慎理解。这两篇论文都不是最终结论。基准测试的时长以月计;GraphRAG-Bench涵盖了九种方法,而另一种则是分块基准方法;在此类简单查询中表现不佳的方法仍可能适用于某种特定语料库,而其他方法则未必适用。偏差审计并非认为图结构毫无用处,而是指出某种特定的评估方式夸大了某些结论——这种说法比“图结构行不通”更为具体且有用。二者共同揭示了一个可进一步发展的观点:图检索并非向量检索的简单升级版。在需要跨多种上下文进行综合分析的复杂推理与总结任务中,图检索具有明显优势;但在占据大量实际应用场景的简单查询任务中,它并不能始终胜过普通检索方法。这一事实虽枯燥,却足以影响决策过程。
还有另一种混淆持续的时间比应有的要长:“graph”这个词承担了两种毫无关联的功能。
两种名为“graph”的事物,功能截然不同
作为数据的图正是GraphRAG通常所指的含义:从语料库中提取实体与关系构成的知识图谱,以节点和边的形式存储,用作检索基础,替代或辅助于分块文本与嵌入向量。它要回答的问题是:信息存储在何处,以及智能体如何找到相关内容?
作为架构的图则是LangGraph这类工具所代表的概念:一种用于控制流的状态机——决定下一步在何种条件下执行、当执行暂停等待人类干预时如何处理、系统崩溃后如何恢复运行。它要回答的问题是:执行是如何一步步推进的?这与事实的存储位置毫无关系。
The two meanings of "graph" in agent engineering
+------------------+---------------------------------+---------------------------------+
| Aspect | Graph as architecture | Graph as data |
+------------------+---------------------------------+---------------------------------+
| Answers | How does control flow move | Where do facts live and how |
| | between agent steps | do I retrieve the right ones |
+------------------+---------------------------------+---------------------------------+
| Nodes represent | Units of work: classify, fetch, | Entities: people, orders, |
| | decide, respond | products, concepts |
+------------------+---------------------------------+---------------------------------+
| Edges represent | Transitions and conditions | Relationships: "works for", |
| | between steps | "purchased", "caused by" |
+------------------+---------------------------------+---------------------------------+
| Typical tool | LangGraph, a hand-rolled state | Neo4j, a Cosmos DB graph API, |
| | machine, an orchestration library | a GraphRAG pipeline |
+------------------+---------------------------------+---------------------------------+
| Cost to adopt | Low. A dependency and some | High. Extraction pipeline, |
| | Python classes | graph store, query layer |
+------------------+---------------------------------+---------------------------------+
| When it's wrong | Almost never, once you have | When your questions are simple |
| to skip it | more than a couple of steps | lookups a vector or keyword |
| | and any branching | search already answers |
+------------------+---------------------------------+---------------------------------+
经过合理划分后,便能呈现出有序的结构。从本质上讲,将图结构视为架构在成本上相当低廉,且几乎能立即为那些需要处理多步骤任务的调度器带来实用价值——因此没有理由不尽早采用它。而将图结构视为数据则成本高昂,其收益取决于查询是否需要遍历关系,这一点在构建之前就可以进行判断。把成本高且具有条件性的部分当作默认选项,而将成本低且几乎适用于所有情况的处理方式放在次要位置,这种做法是反面的。正确的构建方式应该是这样的。
构建架构:具备检查点功能且可被人工中断的真正 LangGraph 智能体
设想一个简单的请求分类代理。它首先对请求进行分类,获取账户数据,判断风险是否需要人工确认,然后再给出响应。退款处理需要人工介入,而查询账户余额和订单状态则无需。这个示例虽然简单,但其所使用的机制——状态架构、条件路由、检查点以及中断处理——与实际生产环境中的机制完全相同,只是节点数量更少。
安装依赖项:
pip install langgraph langgraph-checkpoint-sqlite
所有节点都会读写共享状态:
from typing import TypedDict, Literal
class AgentState(TypedDict):
user_message: str
intent: str
risk_level: str
account_data: dict
human_decision: str
final_response: str
随后是四个节点。classify_intent功能用于为消息标记意图类型和风险等级:
def classify_intent(state: AgentState) -> dict:
message = state["user_message"].lower()
if "refund" in message or "cancel" in message:
intent, risk = "refund_request", "high"
elif "balance" in message or "order status" in message:
intent, risk = "account_lookup", "low"
else:
intent, risk = "general_question", "low"
return {"intent": intent, "risk_level": risk}
fetch_data功能可替代CRM系统、订单存储或计费API:
def fetch_data(state: AgentState) -> dict:
fake_db = {
"refund_request": {"order_id": "ORD-4471", "amount": 249.00, "status": "delivered"},
"account_lookup": {"balance": 1200.50, "last_order": "ORD-4402"},
"general_question": {},
}
return {"account_data": fake_db[state["intent"]]}
路由并非独立的节点,而是用于选择下一个处理节点的条件路径:
def needs_human(state: AgentState) -> Literal["human_review", "respond"]:
return "human_review" if state["risk_level"] == "high" else "respond"
human_review 是指 interrupt() 在运行过程中暂停整个图处理流程,并将控制权返回给调用方,同时不会丢失任何状态:
from langgraph.types import interrupt
def human_review(state: AgentState) -> dict:
decision = interrupt({
"question": f"Approve {state['intent']} for order {state['account_data'].get('order_id')}?",
"amount": state["account_data"].get("amount"),
})
return {"human_decision": decision}
respond 用于输出最终答案,必要时会纳入人工决策结果:
def respond(state: AgentState) -> dict:
if state["risk_level"] == "high":
if state.get("human_decision") == "approve":
text = f"Refund approved for {state['account_data']['order_id']}."
else:
text = "This request needs manual follow-up before we can proceed."
else:
text = f"Here's what I found: {state['account_data']}"
return {"final_response": text}
通过清晰的结构设计体现了该练习的要点:使用直观易读的控制流描述,而非在一个庞大的函数中嵌套大量条件语句:
from langgraph.graph import StateGraph, START, END
builder = StateGraph(AgentState)
builder.add_node("classify_intent", classify_intent)
builder.add_node("fetch_data", fetch_data)
builder.add_node("human_review", human_review)
builder.add_node("respond", respond)
builder.add_edge(START, "classify_intent")
builder.add_edge("classify_intent", "fetch_data")
builder.add_conditional_edges(
"fetch_data",
needs_human,
{"human_review": "human_review", "respond": "respond"},
)
builder.add_edge("human_review", "respond")
builder.add_edge("respond", END)
检查点机制正是区分持久化智能体与普通脚本的关键。LangGraph 的 SQLite 检查点功能足以满足单进程或本地运行的需求,无需外部数据库:
from langgraph.checkpoint.sqlite import SqliteSaver
with SqliteSaver.from_conn_string("support_agent_checkpoints.sqlite") as checkpointer:
graph = builder.compile(checkpointer=checkpointer)
config = {"configurable": {"thread_id": "ticket-8821"}}
result = graph.invoke({"user_message": "I want a refund for my last order"}, config)
print(result)
在退款相关的消息处理中,流程会执行分类和数据获取操作,将高风险请求转至human_review环节并停止执行:interrupt()函数会终止当前流程。此时返回的结果仅包含__interrupt__字段,说明还有任务在等待处理,并非完整的final_response。该流程可能会在此处崩溃,机器也可能需要重启;每一步的处理状态都已保存在support_agent_checkpoints.sqlite文件中。重新打开同一个文件及对应的线程ID后,流程会从暂停的位置继续执行:
with SqliteSaver.from_conn_string("support_agent_checkpoints.sqlite") as checkpointer:
graph = builder.compile(checkpointer=checkpointer)
config = {"configurable": {"thread_id": "ticket-8821"}}
snapshot = graph.get_state(config)
print(snapshot.next) # ('human_review',)
from langgraph.types import Command
final = graph.invoke(Command(resume="approve"), config)
print(final["final_response"])
Command(resume="approve")会将“批准”指令重新传入处于暂停状态的interrupt()函数,相当于由审核人员手动点击了批准。此前已分类并获取的数据无需重新计算,它们会一直保留在检查点文件中。
跳过检查点机制,将状态暂存于内存字典中“稍后再处理”,会导致一种常见的故障:在审查过程中重新启动时,正在处理的任务会消失——既没有错误提示,也没有任何痕迹——因为进程内存之外的任何部分都不知道它的存在。检查点机制的存在正是为避免这种故障模式;应将其视为图结构的一部分,而非可选项。
何时“以数据形式呈现的图”才真正体现出其复杂性
以上内容并非认为GraphRAG毫无价值,而是指出它并非最合适的最初选择——应在出现具体需求时再引入,而非仅仅因为它听起来很复杂。那些在简单查询方面表现平平、但在复杂推理/总结任务中表现出色的基准测试,恰恰反映了这种需求:需要的是能够遍历各种关系、而不仅仅是查找最接近的段落的问题。
三种需要使用知识图谱的情形:
多跳关系问题,其答案需要通过多个连接环节才能得出。“生产这款被召回零件的制造商还为其他产品线供应哪些供应商?”这类问题无法仅通过最相似的片段来解决,必须依次遍历零件→制造商→其他供应方的关系链。向量索引虽然能返回相似文本,但缺乏这种多跳关联机制。
以关系本身作为答案的问题,并不依赖上下文信息。“团队中谁同时负责过支付处理和欺诈检测工作?”这类问题需要遍历人物–服务项目–人物的关系路径。相似度搜索期望某些文档能直接说明这些人员的交集,但通常无法做到,因为这类信息仅以图形结构的形式存在。
在运营领域中,根本原因与影响链分析问题关注的是“哪些上游变化能够解释这种在三个服务间蔓延的连锁反应?”,其核心是因果关系与依赖关系,而非哪条日志内容类似“故障连锁”。对于真正的关联型运营知识而言,图表并非可有可无的辅助工具——它正是包含答案的表达形式。
如果流量数据缺乏这类结构特征——而大多数生产环境中的RAG系统确实如此——那么使用GraphRAG只会增加复杂性却无法带来实际收益,这与上述数据一致。
令牌成本陷阱:切勿在本已高昂的架构上再叠加图形数据结构
成本问题还会与另一个常见错误叠加:多智能体架构。Anthropic对其多智能体研究系统的描述显示,与单次对话相比,其处理量大约是15倍;而使用工具的单智能体架构则比普通对话高出约4倍。更值得注意的是,仅token使用量就能解释不同运行情况下约80%的性能差异;再加上工具调用次数和模型选择后,这一比例可提升到约95%。性能差距主要取决于消耗的token数量,而非调度策略的复杂程度。
这为多智能体设计提供了普遍的警示。当在多个智能体之上叠加“图即数据”结构时,这一警示更为具体:GraphRAG会在前端增加提取与构建的token开销,在查询时则需要更复杂的多跳上下文整合。在原本就已需要约15倍于简单调用token量的架构上再叠加这些开销,且如果不衡量实际差异的话,成本可能会上升一个数量级,而实际应用中的性能却未必有提升——因为大部分请求都是简单的查询,图检索对此并无帮助。
这种解决方案并不吸引人,也常常被忽视:在最终采用之前,需测量将“图作为数据”这一方法应用于实际问题分布时与真正的多智能体基线相比的令牌差异。如果流量主要以简单查询为主,那么GraphRAG相较于普通的检索、提取和查询方式并无优势。而如果确实有一部分查询需要多跳处理,相关测量结果就能体现出来,并能提供具体数值来证明成本的合理性,而非仅凭直觉判断。
测量规范与图结构的选择同样重要:应使用固定的问题集,尽可能用可验证的评分标准进行评估,并同时记录令牌差异与质量差异,这样成本与准确率就能在同一份表格中呈现。
测量规范与图表选择同样重要:保持固定的问题集,尽可能使用可验证的分级答案进行评分,并在质量变化值旁记录标记量变化值,这样成本与准确率就能显示在同一张表格中。
测量规范与图表选择同样重要:保持固定的问题集,尽可能使用可验证的分级答案进行评分,并在质量变化值旁记录标记量变化值,这样成本与准确率就能显示在同一张表格中。
测量规范与图表选择同样重要:保持固定的问题集,尽可能使用可验证的分级答案进行评分,并在质量变化值旁记录标记量变化值,这样成本与准确率就能显示在同一张表格中。
测量规范与图表选择同样重要:保持固定的问题集,尽可能使用可验证的分级答案进行评分,并在质量变化值旁记录标记量变化值,这样成本与准确率就能显示在同一张表格中。
测量规范与图表选择同样重要:保持固定的问题集,尽可能使用可验证的分级答案进行评分,并在质量变化值旁记录标记量变化值,这样成本与准确率就能显示在同一张表格中。
测量规范与图表选择同样重要:保持固定的问题集,尽可能使用可验证的分级答案进行评分,并在质量变化值旁记录标记量变化值,这样成本与准确率就能显示在同一张表格中。
逐步实施的方法
比“先选图表”更好的构建顺序是:
无论是否计划构建知识图谱,都应立即从以图形作为架构的方式来设计控制流。这种方式成本很低——仅需一些依赖关系和状态类型——一旦智能体需要处理多步操作或分支逻辑,其优势就会显现。检查点机制和中断功能并非后期才需要的奢侈配置,它们正是让智能体能够抵御崩溃以及人工审查带来的暂停情况的关键。事后再添加显式的状态机,所带来的弊端远大于从一开始就采用它。
只有在经过验证——而非仅凭假设——向量搜索在处理具体的多跳查询时确实失败之后,才添加graph as data功能。这一验证步骤至关重要:需将候选内容与现有的检索系统进行对比,找出其不足之处,并判断问题是由于关系遍历困难还是其他原因(如分块不当、缺失相关内容)。许多“RAG无法找到答案”的报告都属于后者情况;知识图谱并不能解决分块不当的问题。
在搭建图数据库之前,应使用 GraphRAG-Bench 的理念,通过对自有数据和问题进行分级、可验证的对比来评估其性能,而非像 LLM-as-judge 那样仅通过成对对比的胜率来判断——因为在经过偏见审计后,那种评估方式的可靠性其实很低。如果某个知识图在处理关键问题时无法明显优于经过良好调优的向量或关键词基准模型,那么无论这一理念在纸面上听起来多么出色,目前都还没有理由将其视为数据载体。
图结构始终具有实用价值。变化在于人们不再习惯在了解实际问题需求之前就先假定需要哪种数据结构。