我们所有的单个组件都已准备就绪:
-
我们的节点(工作节点)
-
我们的条件边(管理者)。
现在是时候将它们全部连接成一个统一的系统了。
我们将使用LangGraph的状态图来定义我们的智能体的完整认知架构。这是我们规划智能体思维过程蓝图的地方,精确地定义信息如何从一个步骤流向另一个步骤。
我们要做的第一件事是创建一个StateGraph实例。我们将告诉它,它要传递的**"状态"** 是我们的RAGState字典。
from langgraph.graph import StateGraph, END # Import the main graph components
# Instantiate the graph, telling it to use our RAGState TypedDict as its state schema.
graph = StateGraph(RAGState)
现在我们有了一个空图。下一步是添加我们之前定义的所有节点。.add_node()方法接受两个参数:节点的唯一字符串名称,以及节点将执行的Python函数。
# Add all of our Python functions as nodes in the graph
graph.add_node("plan", plan_node) # The node that creates the initial plan
graph.add_node("retrieve_10k", retrieval_node) # The node for internal document retrieval
graph.add_node("retrieve_web", web_search_node) # The node for external web search
graph.add_node("rerank", rerank_node) # The node that performs precision reranking
graph.add_node("compress", compression_node) # The node that distills the context
graph.add_node("reflect", reflection_node) # The node that summarizes findings and updates history
graph.add_node("generate_final_answer", final_answer_node) # The node that synthesizes the final answer
现在,我们所有的专家都已就位。最后也是最关键的一步是定义连接它们的 “线路”。这就是我们使用.add_edge()和.add_conditional_edges()方法来定义控制流的地方。
# The entry point of our graph is the "plan" node. Every run starts here.
graph.set_entry_point("plan")
# After the "plan" node, we use our first conditional edge to decide which tool to use.
graph.add_conditional_edges(
"plan", # The source node
route_by_tool, # The function that makes the decision
{ # A dictionary mapping the function's output string to the destination node
"search_10k": "retrieve_10k",
"search_web": "retrieve_web",
},
)
# After retrieving from either the 10-K or the web, the flow is linear for a bit.
graph.add_edge("retrieve_10k", "rerank") # After internal retrieval, always go to rerank.
graph.add_edge("retrieve_web", "rerank") # After web retrieval, also always go to rerank.
graph.add_edge("rerank", "compress") # After reranking, always go to compress.
graph.add_edge("compress", "reflect") # After compressing, always go to reflect.
# After the "reflect" node, we hit our main conditional edge, which controls the reasoning loop.
graph.add_conditional_edges(
"reflect", # The source node
should_continue_node, # The function that calls our Policy Agent
{ # A dictionary mapping the decision to the next step
"continue": "plan", # If the decision is "continue", we loop back to the "plan" node to route the next step.
"finish": "generate_final_answer", # If the decision is "finish", we proceed to generate the final answer.
},
)
# The "generate_final_answer" node is the last step before the end.
graph.add_edge("generate_final_answer", END) # After generating the answer, the graph concludes.
print("StateGraph constructed successfully.")
这是我们智能体大脑的蓝图。让我们追踪一下流程:
-
一切总是始于计划。
-
随后,route_by_tool条件边就像一个开关,将流程导向retrieve_10k或retrieve_web。
-
无论运行哪种检索器,输出始终会通过重排序 -> 压缩 -> 反思管道。
-
这就把我们带到了最重要的部分:should_continue_node条件边。这是我们循环推理的核心。
-
如果策略代理说CONTINUE_PLAN,边缘将工作流一路发送回计划节点。我们回到计划(而不是直接到下一个检索器),以便route_by_tool能够正确地路由计划中的
下一个
步骤。
-
如果策略代理说FINISH,边缘节点将跳出循环,并将工作流发送到generate_final_answer节点。
-
最后,答案生成后,图在END处终止。
我们已经成功地定义了深度思考智能体的完整、复杂且循环的架构。现在唯一要做的就是将这个蓝图编译成可运行的应用程序,并将其可视化,看看我们构建了什么。
编译和可视化迭代工作流程
在我们的图完全连接好之后,汇编过程的最后一步是编译它。.compile()方法会获取我们对节点和边的抽象定义,并将其转化为一个具体的、可执行的应用程序。
然后,我们可以使用内置的LangGraph实用工具来生成我们图形的图表。可视化工作流程对于理解和调试复杂的智能体系统非常有帮助。它将我们的代码转换为直观的流程图,清晰地展示了智能体可能的推理路径。
所以,基本上,我们正在把蓝图变成一台真正的机器。
# The .compile() method takes our graph definition and creates a runnable object.
deep_thinking_rag_graph = graph.compile()
print("Graph compiled successfully.")
# Now, let's visualize the architecture we've built.
try:
from IPython.display import Image, display
# We can get a PNG image of the graph's structure.
png_image = deep_thinking_rag_graph.get_graph().draw_png()
# Display the image in our notebook.
display(Image(png_image))
except Exception as e:
# This can fail if pygraphviz and its system dependencies are not installed.
print(f"Graph visualization failed: {e}. Please ensure pygraphviz is installed.")
deep_thinking_rag_graph 对象现在是我们功能完备的代理。可视化代码随后调用 .get_graph().draw_png() 来生成我们构建的状态机的可视化表示。
深度思考简化管道流程(作者: 法里德·汗 )
我们可以清楚地看到:
-
初始分支逻辑,其中route_by_tool在retrieve_10k和retrieve_web之间进行选择。
-
每个研究步骤的线性处理流程(重排序 -> 压缩 -> 反思)。
-
关键的反馈回路,其中should_continue边将工作流返回到计划节点,以开始下一个研究周期。
-
一旦研究完成,通向generate_final_answer的最终“出口匝道”。
这是一个具备思考能力的系统架构。现在,让我们来对它进行测试。
运行深度思考管道
我们已经设计出了一个推理引擎。现在是时候看看它能否在我们的基线系统惨败的地方取得成功了。
我们将使用完全相同的多跳、多源挑战查询来调用我们编译的deep_thinking_rag_graph。我们将使用.stream()方法来获取代理执行的实时、逐步跟踪,观察其在解决问题时的“思维过程”。
本节的计划如下:
-
**调用图表:**我们将运行代理并观察它执行计划的过程,在工具之间切换并构建其研究历史。
-
**分析最终输出:**我们将检查最终的综合答案,看它是否成功整合了10-K报告和网络上的信息。
-
**比较结果:**我们将进行最终的并排比较,以明确凸显我们深度思考智能体的架构优势。
我们将设置初始输入,它只是一个包含original_question的字典,然后调用.stream()方法。stream方法对于调试和观察非常有用,因为它会在每个节点完成工作后输出图的状态。
# This will hold the final state of the graph after the run is complete.
final_state = None
# The initial input for our graph, containing the original user query.
graph_input = {"original_question": complex_query_adv}
print("--- Invoking Deep Thinking RAG Graph ---")
# We use .stream() to watch the agent's process in real-time.
# "values" mode means we get the full RAGState object after each step.
for chunk in deep_thinking_rag_graph.stream(graph_input, stream_mode="values"):
# The final chunk in the stream will be the terminal state of the graph.
final_state = chunk
print("\n--- Graph Stream Finished ---")
这个循环是我们的智能体活跃起来的地方。在每次迭代中,LangGraph 都会执行工作流中的下一个节点,更新RAGState,并将新状态返回给我们。我们嵌入在节点内部的rich库console.print语句将为我们提供智能体行动和决策的实时评论。
#### OUTPUT ####
--- Invoking Deep Thinking RAG Graph ---
--- 🧠: Generating Plan ---
plan:
steps:
- sub_question: What are the key risks related to competition as stated in NVIDIA's 2023 10-K filing?
tool: search_10k
...
- sub_question: What are the recent news and developments in AMD's AI chip strategy in 2024?
tool: search_web
...
--- 🔍: Retrieving from 10-K (Step 1: ...) ---
Rewritten Query: key competitive risks for NVIDIA in the semiconductor industry...
Supervisor Decision: Use `hybrid_search`. ...
--- 🎯: Reranking Documents ---
Reranked to top 3 documents.
--- ✂️: Distilling Context ---
Distilled Context Snippet: NVIDIA operates in the intensely competitive semiconductor industry...
--- 🤔: Reflecting on Findings ---
Summary: According to its 2023 10-K, NVIDIA operates in an intensely competitive semiconductor industry...
--- 🚦: Evaluating Policy ---
-> Decision: CONTINUE_PLAN | Justification: The first step...has been completed. The next step...is still pending...
--- 🌐: Searching Web (Step 2: ...) ---
Rewritten Query: AMD AI chip strategy news and developments 2024...
--- 🎯: Reranking Documents ---
Reranked to top 3 documents.
--- ✂️: Distilling Context ---
Distilled Context Snippet: AMD has ramped up its challenge to Nvidia in the AI accelerator market with its Instinct MI300 series...
--- 🤔: Reflecting on Findings ---
Summary: In 2024, AMD is aggressively competing with NVIDIA in the AI chip market through its Instinct MI300X accelerator...
--- 🚦: Evaluating Policy ---
-> Decision: FINISH | Justification: The research history now contains comprehensive summaries of both NVIDIA's stated risks and AMD's recent strategy...
--- ✅: Generating Final Answer with Citations ---
--- Graph Stream Finished ---
您可以看到我们设计的执行情况。代理:
-
**计划:**它制定了正确的两步多工具计划。
-
**执行步骤1:**使用了search_10k,将其通过完整的检索漏斗运行,并对结果进行了反思。
-
**自我评估:**策略代理发现计划尚未完成,决定继续执行计划。
-
**执行步骤2:**它正确切换到search_web工具,通过相同的漏斗运行,并再次反映。
-
**再次自我审视:**这次,策略代理发现所有必要信息都已收集齐全,并正确决定结束。
-
**合成:**工作流随后进入generate_final_answer节点。
智能体已成功处理复杂查询。现在,让我们来查看它给出的最终答案。