conditional-edges

Agent 调完工具后要回到 LLM 继续推理,还是直接结束?这不能写死一条边,需要 router 读 state 决定下一跳。add_conditional_edges 把 router 返回值经 path_map 映射到节点名或 END


1. 定位

维度 内容
角色 运行时分支与环的控制
输入 → 输出 router(state) -> str → path_map → 下一节点
核心 API add_conditional_edges(source, router, path_map)
依赖 LangChain router 可读 messages 最后一条

2. 图拓扑

节点表

节点名 职责 读 State 写 State
llm 模拟决策 messages, step messages, step
tool 模拟工具 step messages, step

边表

目标 类型 router 返回值
START llm 固定
llm tool / END 条件 "tool" / "end"
tool llm 固定

path_map{"tool": "tool", "end": END}


3. invoke 生命周期(含环 ≥2 轮)

1
2
3
轮1: llm step=1 → router=tool → tool step=2
轮2: llm step=3 → router=tool → tool step=4
轮3: llm step=5 → router=end → END

每轮 superstep 可能含 1~2 个节点(llm 或 llm+tool)。


4. 原理

4.1 router 与 path_map 契约

router 返回的字符串必须是 path_map 的键;值是目标节点名或 END

4.2 形成环

tool → llm 固定边 + llm 条件边回 toolEND,即 ReAct 骨架。

4.3 Literal 类型注解

-> Literal["tool", "end"] 便于静态检查与文档。


5. 最小可运行示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
from typing import Annotated, Literal, TypedDict

from langchain_core.messages import AIMessage, BaseMessage, HumanMessage
from langgraph.graph import StateGraph, START, END
from langgraph.graph.message import add_messages


class State(TypedDict):
messages: Annotated[list[BaseMessage], add_messages]
step: int


def llm_node(state: State) -> dict:
s = state["step"] + 1
need_tool = s < 5
tag = "call_tool" if need_tool else "finish"
return {
"step": s,
"messages": [AIMessage(content=tag)],
}


def tool_node(state: State) -> dict:
return {
"step": state["step"] + 1,
"messages": [AIMessage(content="tool_result")],
}


def router(state: State) -> Literal["tool", "end"]:
last = state["messages"][-1].content
return "tool" if last == "call_tool" else "end"


builder = StateGraph(State)
builder.add_node("llm", llm_node)
builder.add_node("tool", tool_node)
builder.add_edge(START, "llm")
builder.add_conditional_edges(
"llm",
router,
{"tool": "tool", "end": END},
)
builder.add_edge("tool", "llm")

graph = builder.compile()
out = graph.invoke({"messages": [HumanMessage(content="go")], "step": 0})
print(out["step"], out["messages"][-1].content)

6. 执行追踪

轮次 节点 step 路由
1 llm 1 → tool
1 tool 2 → llm
2 llm 3 → tool
2 tool 4 → llm
3 llm 5 → END

重要配置参数

参数 类型 / 默认 作用与影响 参考起点 配置指导
router Callable 返回 path 键 读 messages/step 保持纯函数
path_map dict 键→节点/END 全覆盖 router 输出 漏键即报错
source 节点 str 条件边起点 "llm" 可 START
END 作值 常量 提前终止 "end": END 勿写字符串
环 + step 上限 业务 防死循环 max_steps 生产必加
Literal[...] 类型 自文档 两三分支 推荐

7. 易踩坑

  1. router 返回 "tools" 但 path_map 只有 "tool":KeyError 类路由错误。
  2. 无退出条件的环:step 永远不满足 end,直到递归限制。
  3. path_map 值写节点名字符串错拼:compile 不一定捕获。

小结

  • conditional_edges = router + path_map;ReAct 靠 llm ↔ tool 环 + 条件到 END。
  • router 返回值与 path_map 键集合一致
  • 含环图务必 ≥2 轮 验证并加上限计数。

参考链接

-------------本文结束感谢您的阅读-------------