LangGraph 快速入门
一、为什么需要 LangGraph?🤔
传统的 LangChain 是单向输出的(A -> B -> C)。但在复杂的现实场景中,我们往往需要:
-
循环 (Loops):如果模型翻译得不好,让它重新翻译。
-
条件分支 (Conditional Branching):如果输入是中文,走翻译流程;如果是数学题,走计算流程。
-
状态管理 (State):在多轮对话中记住之前的每一步发生了什么。
二、LangGraph 的核心三要素 🧱
构建一个“图”主要涉及三个概念:
-
State (状态):这是在图的各个节点之间传递的“记忆”。通常是一个字典,记录了当前的对话历史或处理结果。
-
Nodes (节点):就是你的函数。每一个节点接收当前的状态,处理后返回更新的状态。我们的
final_chain就可以作为一个节点。 -
Edges (边):决定了数据如何从一个节点流向下一个节点。
三、动手设计:一个“带自检功能”的翻译官 👮♂️
我们要构建这样一个流程:
-
节点 A (Translator):执行翻译。
-
节点 B (Checker):检查翻译结果(例如:检查是否包含敏感词,或者是否漏掉了标点)。
-
条件边:如果 Checker 觉得没问题,结束;如果觉得有问题,回到 Translator 重新翻译。
1. 定义状态和节点
为了实现“自检”并能让翻译官“重试”,我们的 State (状态) 至少需要包含这两个关键信息:
-
is_successful(是否成功):一个布尔值,作为“开关”来决定流程是走向【结束】还是回到【翻译】。 -
feedback(修改意见):一段字符串,记录 Checker 发现的具体问题(比如:“术语不专业”或“漏掉了第二段”)。
1. 定义状态 (State)
from typing import TypedDict
class GraphState(TypedDict):
text: str # 原文
target_lang: str # 目标语言
translation: str # 翻译结果
feedback: str # 检查意见
is_ok: bool # 是否通过检查
2. 翻译节点 (Translator)
这里的 Prompt 会根据是否有 feedback 动态调整:
def translator_node(state: GraphState):
text = state["text"]
target = state["target_lang"]
feedback = state.get("feedback", "")
if feedback:
# 如果有意见,要求“修改”
prompt = f"原译文有问题:{feedback}\n请根据意见重新翻译原文:{text}\n目标语言:{target}"
else:
# 如果没有意见,要求“初次翻译”
prompt = f"请将以下文本翻译为{target}:{text}"
# 模拟模型调用
# response = model.invoke(prompt)
print(f"--- 正在翻译 ---")
return {"translation": "假装这是模型生成的翻译结果"}
3. 检查节点 (Checker)
这个节点负责当“考官”:
def checker_node(state: GraphState):
translation = state["translation"]
# 逻辑判断:比如检查长度,或者调用另一个模型来打分
if "待定" in translation: # 举个例子
return {"is_ok": False, "feedback": "译文不完整,请补充。"}
else:
return {"is_ok": True, "feedback": ""}
2. 编排工作流 (Router)
最后,我们需要一个“导航员”来决定下一步去哪。如果 is_ok 为 False,它会把控制权交回给 translator_node。
条件边 (Conditional Edge) 是让 LangGraph 具备“思考”能力的灵魂。它允许程序根据当前状态(State)的值动态决定下一步的走向。
为了帮你实现在办公内网运行的“自检翻译助手”,我们需要完成最后一块拼图。
1. 完整的逻辑流图 🕸️
在 LangGraph 中,我们的工作流逻辑如下:
| 节点/边 | 描述 |
|---|---|
| START | 流程开始,进入 translator 节点。 |
| Translator 节点 | 根据原文(及反馈意见)生成译文。 |
| Checker 节点 | 检查译文,并在状态中标记 is_ok。 |
| 条件边 (Router) | 如果 is_ok 为 True -> 跳转到 END如果 is_ok 为 False -> 回到 translator。 |
2. 代码实现示例 (Python) 💻
你可以直接在内网环境参考以下结构来编写你的图:
from langgraph.graph import StateGraph, END
# 1. 初始化图(传入我们之前定义的 GraphState)
workflow = StateGraph(GraphState)
# 2. 添加节点
workflow.add_node("translator", translator_node)
workflow.add_node("checker", checker_node)
# 3. 设置起跑点
workflow.set_entry_point("translator")
# 4. 连接普通边:翻译完必须去检查
workflow.add_edge("translator", "checker")
# 5. 设置核心:条件边
def router(state):
# 根据状态返回下一个节点的名称
if state["is_ok"]:
return "end"
else:
return "retry"
workflow.add_conditional_edges(
"checker", # 从 checker 节点出发
router, # 使用 router 函数判断走向
{
"end": END, # 如果返回 "end",流程结束
"retry": "translator" # 如果返回 "retry",回到翻译节点
}
)
# 6. 编译并运行
app = workflow.compile()
防止程序陷入“死循环”,增加一个**重试计数(retry_count)变量,能让程序在尝试一定次数后优雅地停止,而不是无休止地消耗计算资源。
我们可以将 retry_count 加入到 GraphState 中,并在 translator 节点中累加它。
3. 完整的翻译助手
这是一个结合了 LangChain(处理文本)、LangGraph(处理逻辑循环)和 自检机制 的完整逻辑代码框架。
from typing import TypedDict
from langgraph.graph import StateGraph, END
# 1. 定义状态包
class GraphState(TypedDict):
text: str
target_lang: str
translation: str
feedback: str
is_ok: bool
retry_count: int # 🔢 关键字段:记录重试次数
# 2. 定义 Translator 节点
def translator_node(state: GraphState):
current_retry = state.get("retry_count", 0)
text = state["text"]
feedback = state.get("feedback", "")
# 构造提示词:如果有反馈意见,则要求修改
if feedback:
prompt = f"修改意见:{feedback}\n请根据意见重新翻译原文:{text}"
else:
prompt = f"请翻译原文:{text}"
print(f"--- 正在进行第 {current_retry + 1} 次翻译 ---")
# 这里替换为你内网模型的调用逻辑
# response = model.invoke(prompt)
return {
"translation": "模型生成的译文内容",
"retry_count": current_retry + 1
}
# 3. 定义 Checker 节点
def checker_node(state: GraphState):
translation = state["translation"]
# 模拟检查逻辑:如果包含“错误”字样则不通过
if "错误" in translation:
return {"is_ok": False, "feedback": "译文中包含敏感词或错误。"}
else:
return {"is_ok": True, "feedback": ""}
# 4. 定义路由逻辑 (实现条件边)
def decide_to_go(state: GraphState):
# 💡 这里的逻辑解决了死循环问题
if state["is_ok"] or state["retry_count"] >= 3:
return "end"
else:
return "retry"
# 5. 编排工作流
workflow = StateGraph(GraphState)
workflow.add_node("translator", translator_node)
workflow.add_node("checker", checker_node)
workflow.set_entry_point("translator")
workflow.add_edge("translator", "checker")
workflow.add_conditional_edges(
"checker",
decide_to_go,
{
"end": END,
"retry": "translator"
}
)
app = workflow.compile()