📑目录
- [一、提示链模式(Prompt Chaining)](#一、提示链模式(Prompt Chaining))
- [1.1 概念](#1.1 概念)
- [1.2 模式实践](#1.2 模式实践)
- 二、并行化模式 (Parallelization)
- [2.1 概念](#2.1 概念)
- [2.2 模式实践](#2.2 模式实践)
- 三、路由模式 (Routing)
- [3.1 概念](#3.1 概念)
- [3.2 模式实践](#3.2 模式实践)
- 四、协调者-工作者模式 (Orchestrator-Workers)
- [4.1 概念](#4.1 概念)
- [4.2 核心机制:动态路由与 Send 对象](#4.2 核心机制:动态路由与 Send 对象)
- [4.3 模式实践](#4.3 模式实践)
- 五、评估器-优化器模式 (Evaluator-Optimizer)
- [5.1 概念](#5.1 概念)
- [5.2 核心机制](#5.2 核心机制)
- [5.3 模式实践](#5.3 模式实践)
- 六、工作流模式的选型矩阵与工程考量
- [6.1 核心维度对比](#6.1 核心维度对比)
- [6.2 业务拓扑决策树](#6.2 业务拓扑决策树)
- 七、综合大实战:智能研报生成系统
- [7.1 定义全局状态与数据结构](#7.1 定义全局状态与数据结构)
- [7.2 节点定义(路由、并行、生成、评估)](#7.2 节点定义(路由、并行、生成、评估))
- [7.3 构建复合图拓扑](#7.3 构建复合图拓扑)
在构建基于大语言模型(LLM)的智能体应用时,工作流模式是预先定义好的执行路径。就像工厂的流水线一样,每个步骤都有明确的输入输出和顺序。根据不同的需求场景,LangGraph 提供了多种工作流构建范式。
一、提示链模式(Prompt Chaining)
1.1 概念
提示链就像流水线一样,前一个步骤的输出作为下一个步骤的输入 。这就跟进行内容创作时一样,需要 "大纲" →"初稿"→"润色"→"最终稿",且每个步骤的输出需要传输给下一个步骤,才能确保内容质量逐步提升。

为什么需要提示链?
在复杂的 LLM 应用中,如果将庞大且复杂的任务一次性交给大模型,往往会导致上下文超载、遗漏关键细节或产生严重的"幻觉"。提示链的核心思想是"分而治之",它具有以下优势:
-
降低单次 Prompt 复杂度:让模型每次只专注单一的子任务(例如:本节点只负责生成大纲)。
-
提升结果准确性与稳定性:通过多个步骤的渐进式打磨,显著提升最终输出的质量。
-
便于中间干预与校验:在步骤之间,可以方便地插入代码校验逻辑(如检查大纲格式是否正确),或接入人工审核(Human-in-the-loop),确保整体方向不偏离。
1.2 模式实践
创建一个模拟上述内容创作的工作流。
第一步:定义输入输出的方式
python
class InputState(TypedDict):
topic: str # 用户输入的主题
class OutputState(TypedDict):
final_content: str # 最终的内容
class OverallState(InputState,OutputState):
outline: str # 第一步:生成的大纲
draft: str # 第二步:生成的初稿
polished_draft: str # 第三步:润色后的稿件
第二步:生成大纲
python
PROMPT_1 = (
"根据主题生成文章大纲。\n"
"主题:{topic}\n"
"要求:"
"1.只需两个最核心标题"
"2.不用进行说明,只返回最终大纲"
)
def generate_outline(state:OverallState):
"""根据主题生成内容大纲"""
print("*"*50)
print("大纲生成中...\n")
prompt=PROMPT_1.format(topic=state['topic'])
outline=model.invoke([HumanMessage(content=prompt)]).content
print(f"大纲已生成:\n{outline}\n")
return {
"outline":outline,
}
第三步:基于大纲生成初稿
python
PROMPT_2 = (
"根据以下内容生成文章完整初稿。\n"
"主题:{topic}\n"
"大纲:"
"{outline}\n"
"要求:"
"1.每个标题下,最多使用三句话的内容即可"
"2.不用进行说明,只返回最终结果"
)
def generate_draft(state:OverallState):
"""根据大纲生成完整初稿"""
print("*"*50)
print(f"生成初稿中...\n")
prompt=PROMPT_2.format(topic=state['topic'],outline=state['outline'])
draft=model.invoke([HumanMessage(content=prompt)]).content
print(f"初稿已生成:\n{draft}\n")
return {"draft":draft}
第四步:润色稿件
python
PROMPT_3 = (
"根据文章初稿进行润色。\n"
"主题:{topic}\n"
"初稿:"
"{draft}\n"
"要求:"
"1.润色后,文章不能太长"
)
def polish_content(state:OverallState):
"""对初稿进行润色优化"""
print("*"*50)
print(f"文章润色中...\n")
prompt=PROMPT_3.format(topic=state['topic'],draft=state['draft'])
polished=model.invoke([HumanMessage(content=prompt)]).content
print(f"润色完成,内容如下:\n{polished}\n")
return {"polished_draft":polished}
第五步:生成最终稿
python
PROMPT_4 = (
"根据润色版文章,生成文章终稿。\n"
"主题:{topic}\n"
"大纲:"
"{outline}\n"
"润色版文章:"
"{polished_draft}\n"
)
def finalize_content(state:OverallState):
"""生成最终版本的内容"""
prompt=PROMPT_4.format(topic=state['topic'],outline=state['outline'],polished_draft=state['polished_draft'])
final_content=model.invoke([HumanMessage(content=prompt)]).content
return {"final_content":final_content}
第六步:构建图
python
#构建工作流
builder = StateGraph(
OverallState,
input_schema=InputState,
output_schema=OutputState
)
#添加节点
builder.add_node(generate_outline) # 节点1:生成大纲
builder.add_node(generate_draft) # 节点2:生成初稿
builder.add_node (polish_content) # 节点3:润色稿件
builder.add_node(finalize_content) # 节点4:生成最终稿
#连接节点(直线流程)
builder.add_edge(START, "generate_outline")
builder.add_edge("generate_outline","generate_draft")
builder.add_edge("generate_draft","polish_content")
builder.add_edge("polish_content","finalize_content")
builder.add_edge("finalize_content", END)
#编译工作流
chain = builder.compile()
result = chain.invoke({"topic":"人工智能的未来发展"})
print("=" * 50)
print("最终创作结果:")
print("=" * 50)
print(result["final_content"])
print("=" * 50)
运行输出
text
**************
内容大纲生成中...
大纲已生成:
#人工智能的未来发展
##1.技术趋势与创新方向
###1.1自然语言处理的进步
###1.2机器学习与深度学习的演变
###1.3强人工智能的可能性
##2.应用领域与社会影响
###2.1医疗行业的变革
###2.2自动化与就业市场的关系
###2.3伦理与监管的挑战
**************
生成初稿中...
初稿已生成:
(内容较多,已省略)
**************
文章润色中...
润色完成,内容如下:
(内容较多,已省略)
=================
最终创作结果:
(内容较多,已省略)
=================
二、并行化模式 (Parallelization)
2.1 概念
并行化是指将一个大任务拆解为多个互不依赖的子任务,让它们同时进行,最后再统一汇总结果。在多角度、多维度的复杂问题分析中,这种模式非常高效。
业务场景举例:
假设要研发一款主打城市通勤的"智能电动自行车",在立项前需要进行多维度调研:
-
市场分析:用户关注续航里程、车身重量、防盗能力,并对"骑行社交"(组队、分享路线)有浓厚兴趣。
-
竞品分析:传统品牌车型智能化不足;互联网品牌车型续航和线下售后服务是其短板。
-
技术分析:评估更轻量化的电池材料与车身设计以提升续航和便携性,并开发基于GPS和移动网络的智能防盗系统与社交功能App集成。
这三个分析任务彼此独立、没有先后依赖关系。如果串行处理,总耗时是三者之和;而采用并行处理,总耗时取决于最慢的那个任务,不仅省时,汇总后的综合报告也更能提升决策质量。

2.2 模式实践
以下代码实现了一个工作流,并行执行三个维度的分析,最后整合成全面的产品研发建议。
第一步:定义状态 (State)
python
from typing import TypedDict
from langgraph.constants import START, END
from langgraph.graph import StateGraph
#1. 定义输入模式(仅外部输入)
class InputState(TypedDict):
concept: str # 概念(如:城市通勤智能电动自行车)
# 2. 定义输出模式(仅最终输出)
class OutputState(TypedDict):
report: str # 汇总报告
# 3. 定义内部完整状态(包含输入、输出和中间并行结果)
class AnalysisState(InputState, OutputState):
market: str # 市场分析结果
competitor: str # 竞品分析结果
tech: str # 技术分析结果
第二步:定义并行执行的节点
三个节点接收完整的 AnalysisState,各自处理后,返回自己负责的那个字段。由于这三个字段互不相同,LangGraph 底层的状态更新机制(Reducer)会自动将它们合并,不会产生覆盖冲突。
python
# 三个并行分析任务(实际场景中这里可以调用大模型或外部API)
def market_task(state: AnalysisState):
"""市场分析"""
return {"market": "用户关注续航、重量、防盗,对骑行社交有兴趣..."}
def competitor_task(state: AnalysisState):
"""竞品分析"""
return {"competitor": "传统品牌智能化不足,互联网品牌续航和售后差..."}
def tech_task(state: AnalysisState):
"""技术分析"""
return {"tech": "轻量化电池车身、GPS防盗、社交App集成..."}
第三步:定义汇总节点
汇总节点也必须声明为接收完整的 AnalysisState,这样它才能读取到并行任务返回的三个中间状态。
python
# 汇总结果
def combine_results(state: AnalysisState):
"""生成最终报告"""
report = "产品分析报告\n\n"
report += f"市场分析:\n{state['market']}\n\n"
report += f"竞品分析:\n{state['competitor']}\n\n"
report += f"技术分析:\n{state['tech']}\n\n"
report += "建议:聚焦续航、防盗、社交功能的平衡发展"
return {"report": report}
第四步:构建工作流图
这是并行化的核心:从 START 节点分出三条边指向三个子任务;等这三个子任务结束后,再统一指向 combine 节点。
python
# 构建工作流
builder = StateGraph(
AnalysisState,
input_schema=InputState, # 限制输入
output_schema=OutputState # 过滤输出
)
# 添加节点
builder.add_node("market", market_task)
builder.add_node("competitor", competitor_task)
builder.add_node("tech", tech_task)
builder.add_node("combine", combine_results)
# 1. 并行分发:START 同时指向三个分析节点
builder.add_edge(START, "market")
builder.add_edge(START, "competitor")
builder.add_edge(START, "tech")
# 2. 结果汇聚:三个分析节点完成后,都指向汇总节点
builder.add_edge("market", "combine")
builder.add_edge("competitor", "combine")
builder.add_edge("tech", "combine")
# 3. 结束
builder.add_edge("combine", END)
workflow = builder.compile()
# 使用
result = workflow.invoke({"concept": "城市通勤智能电动自行车"})
print(result["report"])
三、路由模式 (Routing)
3.1 概念
路由模式(Routing)在系统架构中也称为"智能分流"。其核心逻辑是:根据输入内容的特征,动态决定执行哪一个下游分支。在构建 LLM 应用时,面对用户的多样化输入,系统通常需要先进行意图识别,再将请求分发给专用的处理模块。以智能客服系统为例:

路由模式不仅避免了单一 Prompt 处理所有任务导致的上下文混乱,还能让不同的分支按需调用对应的工具或知识库,提升响应质量。
3.2 模式实践
以下代码实现了一个智能客服路由系统。其核心设计在于条件路由机制:
-
动态路径选择:借助大模型的结构化输出(Structured Output)能力,将用户意图强制分类为特定枚举值,避免解析错误。
-
分支隔离:不同类型的问题由专用处理器独立处理。
第一步:定义状态模式
python
from langchain.chat_models import init_chat_model
from langgraph.constants import START, END
from langgraph.graph import StateGraph
from typing_extensions import Literal, TypedDict
from pydantic import BaseModel, Field
class State(TypedDict):
input: str # 用户输入
decision: str # 路由决策(中间状态)
output: str # 最终输出
第二步:定义路由决策的数据结构(利用 Pydantic 和 Literal 强制约束输出)
python
class Route(BaseModel):
step: Literal["pre_sale", "after_sale", "technical"] = Field(
description="根据用户问题类型决定路由到售前、售后还是技术处理"
)
第三步:路由决策节点(调用大模型进行分类)
python
def model_call_router(state: State):
"""分析用户输入,决定问题类型"""
model = init_chat_model("gpt-4o-mini")
# 使用 with_structured_output 确保模型返回符合 Route 结构的数据
decision = model.with_structured_output(Route).invoke(state["input"])
return {"decision": decision.step}
第四步:定义三个独立的处理节点
python
def pre_sale_handler(state: State):
"""处理售前咨询"""
return {"output": "售前咨询已处理,处理内容....."}
def after_sale_handler(state: State):
"""处理售后问题"""
return {"output": "售后问题已处理,处理内容....."}
def technical_handler(state: State):
"""处理技术问题"""
return {"output": "技术问题已处理,处理内容....."}
第五步:路由函数:根据决策返回下一个要执行的节点名称
python
def route_decision(state: State):
if state["decision"] == "pre_sale":
return "pre_sale_handler"
elif state["decision"] == "after_sale":
return "after_sale_handler"
elif state["decision"] == "technical":
return "technical_handler"
第六步:构建路由工作流
python
router_builder = StateGraph(State)
# 添加所有节点
router_builder.add_node(pre_sale_handler)
router_builder.add_node(after_sale_handler)
router_builder.add_node(technical_handler)
router_builder.add_node(model_call_router)
# 先经过路由决策节点
router_builder.add_edge(START, "model_call_router")
# 添加条件边:根据 route_decision 的返回值动态选择分支
router_builder.add_conditional_edges(
"model_call_router",
route_decision,
["pre_sale_handler", "after_sale_handler", "technical_handler"]
)
# 所有分支最终都指向结束节点
router_builder.add_edge("pre_sale_handler", END)
router_builder.add_edge("after_sale_handler", END)
router_builder.add_edge("technical_handler", END)
router_workflow = router_builder.compile()
第七步:测试运行
python
test_cases = [
"我想了解一下你们产品的价格和功能", # 售前咨询
"我购买的产品有质量问题,需要退货", # 售后问题
"这个软件安装后无法正常运行,报错代码0x80070005", # 技术问题
"请问你们的售后服务政策是什么", # 售前咨询
"我的订单已经发货但还没收到", # 售后问题
"如何配置数据库连接参数" # 技术问题
]
for test_case in test_cases:
print("*" * 50)
result = router_workflow.invoke({"input": test_case})
print(f"用户问题: {test_case}\n{result['output']}")
运行结果:
text
**************************************************
用户问题: 我想了解一下你们产品的价格和功能
售前咨询已处理,处理内容.....
**************************************************
用户问题: 我购买的产品有质量问题,需要退货
售前咨询已处理,处理内容.....
**************************************************
用户问题: 这个软件安装后无法正常运行,报错代码0x80070005
技术问题已处理,处理内容.....
**************************************************
用户问题: 请问你们的售后服务政策是什么
售后问题已处理,处理内容.....
**************************************************
用户问题: 我的订单已经发货但还没收到
售前咨询已处理,处理内容.....
**************************************************
用户问题: 如何配置数据库连接参数
技术问题已处理,处理内容.....
(注:在运行结果中,部分问题时被模型误判的,例如"产品有质量问题需要退货"被分到了售前。这反映了 LLM 分类的实际不确定性。在实际工程中,若需高准确率,可通过优化 Prompt 中的分类定义,或加入规则引擎兜底。)
四、协调者-工作者模式 (Orchestrator-Workers)
4.1 概念
协调者-工作者模式(Orchestrator-Workers)是处理复杂、未知结构任务的典型架构。其核心逻辑是:由一个中心节点(协调者)对任务进行动态拆解与规划,再将子任务派发给多个执行节点(工作者)并发处理,最后由汇总节点(合成器)将结果整合输出。
与并行化模式(Parallelization)的核心区别:
-
并行化:任务的分支数量在设计时(静态)就已确定。例如,固定并发执行"市场、竞品、技术"三项分析。
-
协调者-工作者:任务的分支数量与具体内容在运行时(动态)由协调者决定。例如,在处理一份长文档时,协调者需要先阅读文档结构,发现需要拆分为 5 个章节,随后动态分配 5 个 worker 并发执行;如果拆分为 10 个章节,则分配 10 个 worker。
4.2 核心机制:动态路由与 Send 对象
在传统的图结构(如之前的章节)中,我们通过 add_edge 定义静态的连接。但在协调者-工作者模式中,由于 worker 的数量未知,我们需要在运行时动态生成边。LangGraph 通过条件边(Conditional Edges)返回 Send 对象来实现这一机制。
📌 Send 两个参数:
- 目标节点的名称(例如 "llm_call")。
- 要传递给该节点的局部状态(Payload)。
当条件边返回一个 Send 对象列表时,LangGraph 会根据列表的长度,动态创建对应数量的并行分支,并将各自的 payload 独立传递给 worker 节点。
4.3 模式实践
以下代码实现了一个"长报告生成系统"。协调者根据 topic 生成包含 3 个章节的大纲,随后动态分配 3 个 Worker 并发生成各章节内容,最后汇总为完整报告。
python
from langchain.chat_models import init_chat_model
from langgraph.constants import START, END
from langgraph.graph import StateGraph
from langgraph.types import Send
from typing import Annotated, TypedDict, List
import operator
from pydantic import BaseModel
# 1. 定义全局状态
class State(TypedDict):
topic: str
sections: List[Section] # 顺便明确为 Pydantic 对象列表
# 【关键修改 2】将元素类型从 str 改为 SectionResult 字典
completed_sections: Annotated[List[SectionResult], operator.add]
final_report: str
class Section(BaseModel):
name: str
description: str
class Sections(BaseModel):
sections: List[Section]
class SectionResult(TypedDict):
index: int # 用于最后排序的依据
content: str # 大模型生成的文本
# 2. 初始化模型
model = init_chat_model("gpt-4o-mini")
planner = model.with_structured_output(Sections)
# 3. 协调者节点:生成计划
def orchestrator(state: State):
"""根据主题生成大纲,并分配给 worker"""
report_sections = planner.invoke(
f"为主题 '{state['topic']}' 制定报告大纲,包含3个章节"
)
return {"sections": report_sections.sections}
# 4. 任务分配函数:动态创建 Worker
def assign_workers(state: State):
"""任务分配:使用 enumerate 为每个章节分配一个 index"""
worker_tasks = []
for index, section in enumerate(state["sections"]):
# 将 section 和 index 一起发给 Worker,后续按index排序合并,保证合并后不乱序
worker_tasks.append(
Send("llm_call", {"section": section, "index": index})
)
return worker_tasks
# 5. 工作者节点:执行局部任务
def llm_call(state: dict):
"""Worker:执行局部任务,并在返回结果中带上 index"""
# 这里的 state 是 Send 传递过来的局部字典
section = state["section"]
index = state["index"]
result = model.invoke(
f"编写报告章节:{section.name},内容要求:{section.description}"
)
return {"completed_sections": [{"index": index, "content": result.content}]}
# 6. 合成器节点:汇总结果
def synthesizer(state: State):
"""合成器:按 index 排序并汇总结果"""
completed_sections = state["completed_sections"]
# 按 index 从小到大对并发返回的结果进行排序
sorted_sections = sorted(completed_sections, key=lambda x: x["index"])
# 提取排好序的 content
ordered_contents = [item["content"] for item in sorted_sections]
# 拼接为最终文本
final_report = "\n\n---\n\n".join(ordered_contents)
return {"final_report": final_report}
# 7. 构建图
builder = StateGraph(State)
# 添加节点
builder.add_node("orchestrator", orchestrator)
builder.add_node("llm_call", llm_call)
builder.add_node("synthesizer", synthesizer)
# 构建边
builder.add_edge(START, "orchestrator")
# 关键:从协调者到工作者的条件边
builder.add_conditional_edges(
"orchestrator",
assign_workers,
["llm_call"] # 动态创建的所有分支都指向 llm_call 节点
)
# 所有 worker 完成后,统一指向合成器
builder.add_edge("llm_call", "synthesizer")
builder.add_edge("synthesizer", END)
worker_workflow = builder.compile()
# 8. 运行测试
response = worker_workflow.invoke({"topic": "中国近代史"})
print(response)
运行结果
text
json
{
"topic": "中国近代史",
"sections": [
{
"name": "第一章:近代史概述",
"description": "介绍中国近代史的背景与重要性,涵盖社会、经济、文化等多个方面的变化。"
},
{
"name": "第二章:鸦片战争与列强侵华",
"description": "探讨鸦片战争对中国的影响,以及随后的列强侵华与民族觉醒进程。"
},
{
"name": "第三章:辛亥革命与新文化运动",
"description": "分析辛亥革命及其后果,以及新文化运动对中国现代化的推动作用。"
}
],
"completed_sections": [
"## 第一章:近代史概述\n\n中国近代史...",
"## 第二章:鸦片战争与列强侵华\n\n鸦片战争是...",
"## 第三章:辛亥革命与新文化运动\n\n辛亥革命... "
],
"final_report": "## 第一章:近代史概述\n\n中国近代史...\n\n---\n\n## 第二章:鸦片战争与列强侵华\n\n鸦片战争是...\n\n---\n\n## 第三章:辛亥革命与新文化运动\n\n辛亥革命..."
}
五、评估器-优化器模式 (Evaluator-Optimizer)
5.1 概念
评估器-优化器模式通过引入闭环反馈回路(Feedback Loop)来提升大模型的输出质量。其核心流转逻辑为:
-
生成(Generate):由生成节点(Generator)根据输入完成任务初稿。
-
评估(Evaluate):由评估节点(Evaluator)对初稿的质量进行审查或打分。
-
反馈与迭代(Optimize):若评估未达标,系统将带着评估反馈(Feedback)重新进入生成节点进行优化;若评估通过,则结束流程。
该模式适用于输出质量难以一次性保证、且存在明确评估标准的场景,例如:高质量文本生成、复杂代码编写与自动审查、多轮数据提取等。相较于单次 Prompt 提示,它能有效降低大模型的幻觉与逻辑漏洞。
5.2 核心机制
在 LangGraph 中,该模式依赖条件边(Conditional Edges)构建循环结构(Cycle)。
条件路由:评估节点执行后,通过条件边决定下一步走向。通常需要定义一个路由函数,解析评估结果并返回目标节点(如返回 "generate" 或 END)。
终止条件:为防止模型在"生成-评估"之间陷入无限死循环,必须在状态(State)中记录迭代次数,并在路由函数中设定最大重试阈值(Max Iterations)。
5.3 模式实践
以下代码实现了一个"代码生成与自动审查"的工作流。生成器负责编写 Python 代码,评估器负责检查代码的语法与安全性,若不通过则打回重做。
python
from langchain.chat_models import init_chat_model
from langgraph.graph import StateGraph, START, END
from typing import TypedDict, Literal
from pydantic import BaseModel, Field
# 初始化模型
model = init_chat_model("gpt-4o-mini")
# 1. 定义状态
class State(TypedDict):
task: str # 待完成的任务
draft: str # 当前的生成内容(草稿)
feedback: str # 评估节点的反馈意见
is_approved: bool # 评估是否通过
iterations: int # 当前迭代次数(用于防死循环)
# 定义评估结果的结构化输出
class Evaluation(BaseModel):
is_approved: bool = Field(description="代码是否满足需求且无严重错误")
feedback: str = Field(description="如果不通过,请提供具体的修改建议;如果通过,填入'PASS'")
evaluator = model.with_structured_output(Evaluation)
# 2. 生成器节点
def generate_node(state: State):
task = state["task"]
feedback = state.get("feedback", "")
iterations = state.get("iterations", 0) + 1
prompt = f"请完成以下任务:{task}\n"
if feedback and feedback != "PASS":
prompt += f"上一版代码存在以下问题,请修正:\n{feedback}\n"
result = model.invoke(prompt).content
return {
"draft": result,
"iterations": iterations,
# 每次重新生成后,重置评估状态
"is_approved": False,
"feedback": ""
}
# 3. 评估器节点
def evaluate_node(state: State):
draft = state["draft"]
prompt = f"请作为资深Code Reviewer,审查以下代码:\n{draft}\n"
prompt += "评估标准:1. 语法正确;2. 逻辑严密;3. 无安全漏洞。"
evaluation = evaluator.invoke(prompt)
return {
"is_approved": evaluation.is_approved,
"feedback": evaluation.feedback
}
# 4. 路由函数(控制循环与退出)
def route_evaluation(state: State):
# 达到最大迭代次数(如3次),强制退出以防死循环
if state["iterations"] >= 3:
print(">>> 达到最大重试次数,强制退出。")
return END
if state["is_approved"]:
print(">>> 评估通过,流程结束。")
return END
else:
print(f">>> 评估未通过,打回重写。反馈:{state['feedback']}")
return "generate"
# 5. 构建图
builder = StateGraph(State)
# 添加节点
builder.add_node("generate", generate_node)
builder.add_node("evaluate", evaluate_node)
# 构建边
builder.add_edge(START, "generate")
builder.add_edge("generate", "evaluate")
# 核心:从评估器到(生成器 / END)的条件边
builder.add_conditional_edges(
"evaluate",
route_evaluation,
["generate",END]
)
workflow = builder.compile()
# 6. 运行测试
task = "写一个Python函数,使用正则表达式从URL中提取所有的查询参数,并返回一个字典。"
result = workflow.invoke({"task": task, "iterations": 0})
print("\n--- 最终代码 ---\n")
print(result["draft"])
📌 架构扩展:引入人机交互 (Human-in-the-loop)
评估器并不一定必须由大模型(LLM)充当。在 LangGraph 中,可以非常容易地将评估节点替换为
人工审核(例如,在发布重要新闻稿、或执行高危运维脚本前)。实现方式通常是利用 LangGraph 的interrupt 机制或外部状态检查。
六、工作流模式的选型矩阵与工程考量
在前面的五个小节中,我们详细拆解了 LangGraph 的五种基础工作流模式。然而,在真实的工程落地中,业务需求往往不是单一的。作为架构师或开发者,我们不仅要会"写"这些模式,更要懂"选"模式。
6.1 核心维度对比
在 LLM 应用开发中,响应延迟(Latency)、生成质量(Quality) 和 Token 成本(Cost) 往往构成一个不可兼得的"不可能三角"。我们对五种模式的工程表现进行横向对比:
| 工作流模式 | 响应延迟 | Token 成本 | 输出质量上限 | 适用场景特征 |
|---|---|---|---|---|
| 提示链 (Prompt Chaining) | 中等 (串行叠加) | 中等 (按步累加) | 较高 | 任务必须按步骤完成,如:写大纲 -> 填内容 -> 润色。 |
| 并行化 (Parallelization) | 低 (受限于最慢分支) | 高 (同时并发) | 中等 | 多维度数据收集、独立评估。对总时长敏感的业务。 |
| 路由模式 (Routing) | 低 (仅走一条分支) | 低 (按需调用) | 中等 | 意图识别、智能客服分流。避免无关上下文干扰。 |
| 协调者-工作者 | 较高 (动态规划+并发) | 极高 (根据任务拆分) | 较高 | 处理复杂长文档、代码库分析等无法预设步骤的任务。 |
| 评估器-优化器 | 极高 (多轮循环重试) | 极高 (反复调用) | 最高 | 代码生成、核心文案撰写。对错误零容忍的高精尖场景。 |
📌 工程建议:如果前端要求接口在 3 秒内返回,请绝对不要使用"评估器-优化器"或"协调者-工作者",这两种模式天然适合放入异步任务队列(如 Celery)中后台执行。
6.2 业务拓扑决策树
面对一个具体的业务需求,你可以按照以下决策树(Decision Tree)快速定位所需的工作流模式:
#mermaid-svg-zxYa46Z7dgvuz8GV{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-zxYa46Z7dgvuz8GV .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-zxYa46Z7dgvuz8GV .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-zxYa46Z7dgvuz8GV .error-icon{fill:#552222;}#mermaid-svg-zxYa46Z7dgvuz8GV .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-zxYa46Z7dgvuz8GV .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-zxYa46Z7dgvuz8GV .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-zxYa46Z7dgvuz8GV .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-zxYa46Z7dgvuz8GV .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-zxYa46Z7dgvuz8GV .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-zxYa46Z7dgvuz8GV .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-zxYa46Z7dgvuz8GV .marker{fill:#333333;stroke:#333333;}#mermaid-svg-zxYa46Z7dgvuz8GV .marker.cross{stroke:#333333;}#mermaid-svg-zxYa46Z7dgvuz8GV svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-zxYa46Z7dgvuz8GV p{margin:0;}#mermaid-svg-zxYa46Z7dgvuz8GV .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-zxYa46Z7dgvuz8GV .cluster-label text{fill:#333;}#mermaid-svg-zxYa46Z7dgvuz8GV .cluster-label span{color:#333;}#mermaid-svg-zxYa46Z7dgvuz8GV .cluster-label span p{background-color:transparent;}#mermaid-svg-zxYa46Z7dgvuz8GV .label text,#mermaid-svg-zxYa46Z7dgvuz8GV span{fill:#333;color:#333;}#mermaid-svg-zxYa46Z7dgvuz8GV .node rect,#mermaid-svg-zxYa46Z7dgvuz8GV .node circle,#mermaid-svg-zxYa46Z7dgvuz8GV .node ellipse,#mermaid-svg-zxYa46Z7dgvuz8GV .node polygon,#mermaid-svg-zxYa46Z7dgvuz8GV .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-zxYa46Z7dgvuz8GV .rough-node .label text,#mermaid-svg-zxYa46Z7dgvuz8GV .node .label text,#mermaid-svg-zxYa46Z7dgvuz8GV .image-shape .label,#mermaid-svg-zxYa46Z7dgvuz8GV .icon-shape .label{text-anchor:middle;}#mermaid-svg-zxYa46Z7dgvuz8GV .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-zxYa46Z7dgvuz8GV .rough-node .label,#mermaid-svg-zxYa46Z7dgvuz8GV .node .label,#mermaid-svg-zxYa46Z7dgvuz8GV .image-shape .label,#mermaid-svg-zxYa46Z7dgvuz8GV .icon-shape .label{text-align:center;}#mermaid-svg-zxYa46Z7dgvuz8GV .node.clickable{cursor:pointer;}#mermaid-svg-zxYa46Z7dgvuz8GV .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-zxYa46Z7dgvuz8GV .arrowheadPath{fill:#333333;}#mermaid-svg-zxYa46Z7dgvuz8GV .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-zxYa46Z7dgvuz8GV .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-zxYa46Z7dgvuz8GV .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-zxYa46Z7dgvuz8GV .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-zxYa46Z7dgvuz8GV .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-zxYa46Z7dgvuz8GV .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-zxYa46Z7dgvuz8GV .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-zxYa46Z7dgvuz8GV .cluster text{fill:#333;}#mermaid-svg-zxYa46Z7dgvuz8GV .cluster span{color:#333;}#mermaid-svg-zxYa46Z7dgvuz8GV div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-zxYa46Z7dgvuz8GV .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-zxYa46Z7dgvuz8GV rect.text{fill:none;stroke-width:0;}#mermaid-svg-zxYa46Z7dgvuz8GV .icon-shape,#mermaid-svg-zxYa46Z7dgvuz8GV .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-zxYa46Z7dgvuz8GV .icon-shape p,#mermaid-svg-zxYa46Z7dgvuz8GV .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-zxYa46Z7dgvuz8GV .icon-shape .label rect,#mermaid-svg-zxYa46Z7dgvuz8GV .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-zxYa46Z7dgvuz8GV .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-zxYa46Z7dgvuz8GV .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-zxYa46Z7dgvuz8GV :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 是
否
是
否
是
否
是
否
是
否
是
否
开始: 分析业务需求
任务能拆解为
固定步骤吗?
步骤之间有严格的
先后依赖关系吗?
需要从多个独立维度
收集信息吗?
提示链模式
并行化模式
拆分的子任务数量
在设计时是固定的吗?
输入的类型复杂多变吗?
并行化模式
协调者-工作者模式
路由模式
对最终结果的正确性
要求极高吗?
评估器-优化器模式
七、综合大实战:智能研报生成系统
本节将把前序章节中的路由、并行、提示链、评估器四种模式进行组合,构建一个企业级的"智能研报系统"。
业务需求:
- 接收用户问题。
- 判断是"宏观分析"还是"个股研报"。
- 如果是个股,并行调用工具获取财报数据、新闻舆情。
- 汇总数据,生成研报初稿。
- 引入合规与质量评估器,如果不合格,带上修改意见打回重写。
- 最终输出报告。
7.1 定义全局状态与数据结构
python
from typing import TypedDict, Literal, Annotated, List
from langgraph.graph import StateGraph, START, END
from langgraph.types import Send
from langchain.chat_models import init_chat_model
from langchain_core.messages import HumanMessage, SystemMessage
from pydantic import BaseModel, Field
import operator
model = init_chat_model("gpt-4o-mini")
class State(TypedDict):
user_query: str # 用户原始输入
report_type: str # 路由结果:macro / stock
financial_data: str # 财报数据
news_data: str # 新闻舆情
report_draft: str # 研报初稿
feedback: str # 评估反馈
is_approved: bool # 是否通过
iterations: int # 迭代次数
final_output: str # 最终输出
class RouteDecision(BaseModel):
type: Literal["macro", "stock"] = Field(description="识别输入的类型:宏观分析还是个股研报")
7.2 节点定义(路由、并行、生成、评估)
python
# 1. 路由节点
def router_node(state: State):
structured_llm = model.with_structured_output(RouteDecision)
decision = structured_llm.invoke(f"判断以下问题属于宏观分析还是个股研报:{state['user_query']}")
return {"report_type": decision.type}
# 2. 并行数据抓取节点(模拟)
def fetch_financial(state: State):
return {"financial_data": "公司Q3营收同比增长20%,净利润超预期..."}
def fetch_news(state: State):
return {"news_data": "近期行业政策利好,机构密集调研,市场情绪积极..."}
# 3. 初稿生成节点
def generate_report(state: State):
feedback = state.get("feedback", "")
prompt = f"根据以下数据撰写研报初稿。\n财报:{state.get('financial_data', '无')}\n舆情:{state.get('news_data', '无')}\n"
if feedback:
prompt += f"\n上次修改意见:{feedback},请重点修正。"
result = model.invoke(prompt).content
return {
"report_draft": result,
"iterations": state.get("iterations", 0) + 1,
"is_approved": False,
"feedback": ""
}
# 4. 质量评估节点
class EvalResult(BaseModel):
is_approved: bool = Field(description="研报质量是否合格")
feedback: str = Field(description="修改建议,若合格填PASS")
def evaluate_report(state: State):
structured_llm = model.with_structured_output(EvalResult)
eval_res = structured_llm.invoke(f"请作为首席分析师,审查以下研报质量:\n{state['report_draft']}")
return {
"is_approved": eval_res.is_approved,
"feedback": eval_res.feedback
}
# 5. 汇总导出节点
def export_final(state: State):
return {"final_output": f"【最终研报】\n{state['report_draft']}"}
7.3 构建复合图拓扑
python
builder = StateGraph(State)
# 添加节点
builder.add_node("router", router_node)
builder.add_node("fetch_financial", fetch_financial)
builder.add_node("fetch_news", fetch_news)
builder.add_node("generate", generate_report)
builder.add_node("evaluate", evaluate_report)
builder.add_node("export", export_final)
# 1. 起点路由
builder.add_edge(START, "router")
# 2. 动态路由分发 (Routing)
def route_decision(state: State):
if state["report_type"] == "stock":
return ["fetch_financial", "fetch_news"] # 返回列表,触发并行
return "generate" # 宏观分析直接生成
builder.add_conditional_edges(
"router",
route_decision,
["fetch_financial", "fetch_news", "generate"]
)
# 3. 并行汇聚 -> 生成初稿 (Fan-in)
builder.add_edge("fetch_financial", "generate")
builder.add_edge("fetch_news", "generate")
# 4. 生成 -> 评估 (Prompt Chaining)
builder.add_edge("generate", "evaluate")
# 5. 评估路由 (Evaluator-Optimizer)
def route_evaluation(state: State):
if state["iterations"] >= 3:
print(">>> 达到最大重试次数,强制通过。")
return "export"
if state["is_approved"]:
return "export"
print(f">>> 评估未通过,打回重写。意见:{state['feedback']}")
return "generate"
builder.add_conditional_edges(
"evaluate",
route_evaluation,
{"generate": "generate", "export": "export"}
)
builder.add_edge("export", END)
research_workflow = builder.compile()
# 运行测试
print("=== 测试个股研报 ===")
res = research_workflow.invoke({"user_query": "帮我分析一下宁德时代最近的财报和舆情,写一份研报"})
print(res["final_output"])
📌 总结:在实际的 AI 工程落地中,极少存在单一的纯粹模式。真正的企业级应用,往往是这五种模式的深度嵌套与组合。