核心思想
在 State 里显式放一个计数器字段(如 revision_count、retry_count、attempts),每绕一圈循环加 1,在路由函数中判断“超过阈值就走 END 或降级”,而不是让框架的 recursion_limit 兜底。
这不是“调大 limit 硬扛”,而是“业务逻辑主动叫停”。

from typing import Annotated, Literal
from typing_extensions import TypedDict
from langgraph.graph import StateGraph, START, END
from langgraph.managed import RemainingSteps
from langgraph.types import Command
# ===== 1. 状态定义:显式计数器 =====
class State(TypedDict):
query: str
result: str
revision_count: int # ← 业务计数器:绕了多少圈
remaining_steps: RemainingSteps # ← 系统级步数(兜底,非必须)
# ===== 2. 节点定义 =====
def agent(state: State) -> dict:
"""模拟模型决策:可能建议重写,也可能结束"""
# 模拟逻辑:前两次都说“需要重写”,第三次说“完成”
if state["revision_count"] < 2:
return {"result": "需要进一步完善"}
else:
return {"result": "最终答案"}
def rewrite(state: State) -> dict:
"""重写节点:计数器 +1"""
return {
"revision_count": state["revision_count"] + 1,
# 可以在这里清空其他字段(如用 Overwrite)
}
# ===== 3. 路由函数:业务熔断 =====
def should_continue(state: State) -> Literal["rewrite", END]:
"""业务级熔断:超过2次就结束"""
print(f"当前重写次数:{state['revision_count']},剩余步数:{state['remaining_steps']}")
# 方法② 的核心:业务计数器
if state["revision_count"] >= 2:
# 超过阈值 → 结束(即使模型还想重写)
print("⚠️ 达到业务重写上限,强制结束")
return END
# 如果模型认为需要重写,且还没超限
if "需要完善" in state["result"]:
return "rewrite"
return END
# ===== 4. 建图 =====
builder = StateGraph(State)
builder.add_node("agent", agent)
builder.add_node("rewrite", rewrite)
builder.add_edge(START, "agent")
# 条件边:agent 决定是否继续
builder.add_conditional_edges(
"agent",
should_continue,
{"rewrite": "rewrite", END: END}
)
# 循环边:rewrite 回到 agent(形成环)
builder.add_edge("rewrite", "agent")
# 编译
graph = builder.compile()
# ===== 5. 运行测试 =====
result = graph.invoke({
"query": "帮我写一篇文章",
"revision_count": 0, # 初始化计数器
})
print(f"\n最终结果:{result['result']}")
print(f"总重写次数:{result['revision_count']}")
运行过程与输出
当前重写次数:0,剩余步数:25
当前重写次数:1,剩余步数:24
当前重写次数:2,剩余步数:23
⚠️ 达到业务重写上限,强制结束
最终结果:最终答案
总重写次数:2
- 第 1 次:
revision_count=0,模型说“需要完善” → 去rewrite→ 计数器变 1 - 第 2 次:
revision_count=1,模型说“需要完善” → 去rewrite→ 计数器变 2 - 第 3 次:
revision_count=2,路由函数直接返回END,不管模型说什么
生产环境模板
把这段代码当成“计数器循环”的标准模板:
class MyState(TypedDict):
# ... 其他字段
max_retries: int = 2 # 业务阈值(可配置)
retry_count: int = 0 # 计数器
def core_node(state: MyState) -> dict:
"""核心业务节点"""
# ... 执行逻辑
return {"result": ...}
def retry_node(state: MyState) -> dict:
"""重试节点:只加计数,不做其他"""
return {"retry_count": state["retry_count"] + 1}
def route(state: MyState) -> Literal["retry", END]:
"""路由:业务熔断"""
if state["retry_count"] >= state["max_retries"]:
return END # 超过阈值 → 结束
if state["result"] == "需要重试":
return "retry"
return END
总结
方法② 的本质:把“循环多少次”的决定权从框架的 recursion_limit 里拿出来,变成你业务代码里一个显式、可控、可测试的字段。
- 它让你能精确控制“最多重写 2 次”,而不是“最多跑 25 个 super-step”
- 它让路由函数能做出业务语义明确的判断(“重写超限了,转人工”)
- 它和
RemainingSteps形成双重保险,一个管业务,一个管系统
755

被折叠的 条评论
为什么被折叠?



