数据截至 (上游 commit 0076f21220aa)
节点基类、节点类型与全局状态
前几章讲「图怎么编译、怎么停续」。本章下到节点层:一个节点执行时经历什么、13 种节点都是谁、节点之间怎么传数据。
1. 节点的统一执行骨架
所有节点继承 BaseNode(nodes/base.py:20)。它把「执行一个节点」固化成一条统一流水线,各节点只需实现自己的 _run:
run(state): # nodes/base.py:189
① 若被用户 stop → 抛 IgnoreException
② 若执行次数 ≥ max_steps → 抛 IgnoreException(防循环跑飞)
③ 回调 on_node_start
④ result = self._run(exec_id) # ← 子类实现的真正逻辑
⑤ 把 result 的每个 key 写进全局变量池
⑥ current_step += 1
⑦ finally: 回调 on_node_end(带日志)
对应源码骨架:
# nodes/base.py:189-223(节选)
def run(self, state):
if self.stop_flag: raise IgnoreException('stop by user')
if self.current_step >= self.max_steps: raise IgnoreException('... max times')
self.callback_manager.on_node_start(...)
result = self._run(exec_id)
if result:
for key, value in result.items():
self.graph_state.set_variable(self.id, key, value) # ← 输出进变量池
self.current_step += 1
...
self.callback_manager.on_node_end(...)
return state
两个要点:
max_steps在节点级强制(nodes/base.py:215)。 配合图级recursion_limit(第 01 章),双重防护循环失控。- 节点输出统一进变量池(
nodes/base.py:228-230)。 节点不直接互相调用,而是「我把结果存到变量池[我的id][key],下游自己来取」——彻底解耦。
注意 run 返回的 state 原样透传:BISHENG 没把业务数据塞进 LangGraph 的 state(那只是个占位的 TempState,graph_engine.py:22),真正的数据流全走自己的 GraphState 变量池。
2. 13 种节点速览
| 节点 | 干什么 | 文件 |
|---|---|---|
start | 初始化时间/聊天历史/预设问题/用户信息,发开场白 | nodes/start/start.py |
end | 终点,连到 LangGraph 的 END | nodes/end/end.py |
input | 等用户输入(对话或表单),解析上传文件 | nodes/input/input.py |
output | 给用户发消息;可要求用户填写/选择(中断) | nodes/output/output.py |
llm | 调用大模型,支持单条/批处理、流式输出 | nodes/llm/llm.py |
agent | 带工具的 agent | nodes/agent/agent.py |
condition | 按条件路由到不同分支 | nodes/condition/condition.py |
code | 执行用户写的 Python main() | nodes/code/code.py |
rag | 检索增强生成 | nodes/rag/rag.py |
knowledge_retriever | 知识库检索 | nodes/knowledge_retriever/... |
qa_retriever | QA 库检索 | nodes/qa_retriever/... |
tool | 调用工具 | nodes/tool/tool.py |
report | 用变量填充 docx 模板生成报告 | nodes/report/report.py |
(另有 note 注释节点和 fake_output 内部节点,不算可执行业务节点。)