目录
【示例5.1】文档摘要工作流完整程序实现(LangGraph_linear_workflow.py)。
5.1.1 线性工作流核心概念
工作流是智能体系统运转的核心骨架,本小节立足LangGraph框架,系统讲解智能体工作流的设计方法。从基础的线性工作流入手,帮助读者掌握按序执行任务的标准化搭建流程。
1. 线性工作流设计概念解释
线性工作流是最基础的工作流形式,任务按预定义顺序依次执行,前一步的输出作为后一步的输入。其特点是结构清晰、易于调试,适用于流程固定、依赖明确的场景,如“用户提问→调用工具获取数据→生成回答”。
在LangGraph中,线性工作流通过StateGraph定义状态,并通过add_edge指定节点之间的单向依赖关系,形成类似A→B→C→END的流水线。
2. 工具调用
(1)LangGraph核心组件:
- StateGraph:工作流图的核心容器,负责定义节点、边和状态结构。
- State:状态载体,存储流程中所有数据(输入、中间结果、输出),支持动态修改。
- Node:工作流的执行单元,可以是函数、LLM调用、工具调用等逻辑。
- Edge:节点间的连接关系,在线性流程中为“顺序边”(从节点A直接指向节点B)。
- Graph:编译后的工作流实例,通过graph.invoke()触发执行。
(2)常用工具:如Requests(API调用)、TavilySearch(搜索工具)、PythonREPLTool(在安全沙箱中执行 Python 代码)、SQLDatabaseToolkit(封装了 SQL 查询、表查看等操作)、自定义数据处理函数等。
3. LangGraph框架定位
LangGraph是LangChain生态下的状态机工作流框架,专为大语言模型(LLM)应用的复杂流程编排设计。其核心优势在于:
- 显式的状态管理(State Management):通过可修改的状态对象串联整个工作流。
- 可组合性(Composability):支持节点(Node)的灵活组合与复用。
- 可观测性(Observability):内置日志、追踪能力,便于调试。
- 循环与分支支持:相比线性脚本,天然支持复杂逻辑跳转(本书聚焦线性流程)。
线性工作流是LangGraph最基础的应用场景,核心特征是节点按固定顺序执行,无分支、无循环,适用于“数据预处理→LLM调用→结果后处理”等确定性流程。
5.1.2 实战案例:线性工作流的实现
线性工作流的设计遵循“定义状态→实现节点→构建图→执行与调试”4步流程,本小节以文档摘要工作流状态为例进行讲解。此工作流的完整代码参看配套资源中的代码文件5.1.2.py。
1. 定义状态结构(State)
状态是工作流的数据总线,需明确存储“输入数据→中间结果→输出结果”。LangGraph支持以下两种状态定义方式:
- 简单场景:使用TypedDict定义强类型状态(推荐)。
- 复杂场景:使用pydantic.BaseModel定义带校验的状态。
from typing import TypedDict, Optional
# 定义状态结构:存储原始文档、预处理后的文本、LLM摘要结果
class SummaryState(TypedDict):
raw_document: str # 输入:原始文档
processed_text: Optional[str] # 中间结果:预处理后的文本
summary: Optional[str] # 输出:LLM生成的摘要
2. 实现节点逻辑(Node)
节点是工作流的执行单元,每个节点接收State作为输入,修改并返回新的State。在线性流程中,节点按“预处理→LLM调用→后处理”的顺序设计。
1)节点1:文档预处理(文本清洗)
功能:去除原始文档中的多余空格、换行,提取核心内容。
def process_document(state: SummaryState) -> SummaryState:
"""预处理原始文档:清洗文本格式"""
raw_doc = state["raw_document"]
# 清洗逻辑:去除多余空格、换行,统一格式
processed = raw_doc.strip().replace("\n\n", "\n").replace(" ", " ")
# 返回更新后的状态
return {"processed_text": processed}
2)节点2:DeepSeek LLM摘要生成
功能:调用DeepSeek API,基于预处理文本生成摘要。
from dotenv import load_dotenv
import os
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
# 加载环境变量(API Key)
load_dotenv()
# 初始化 qwen-plus LLM(非流式输出,适合线性流程)
llm = ChatOpenAI(
model="qwen-plus",
api_key=os.getenv("DASHSCOPE_API_KEY"), # 从 .env 读取
base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",
temperature=0
)
# 定义摘要提示词模板(指令+上下文)
summary_prompt = ChatPromptTemplate.from_messages([
("system", "你是专业的文本摘要助手,需基于以下文本生成简洁、准确的摘要,不添加额外信息,长度控制在300字以内。"),
("human", "文本内容:{processed_text}")
])
# 构建摘要链(提示词+LLM+输出解析器)
summary_chain = summary_prompt | llm | StrOutputParser()
def generate_summary(state: SummaryState) -> SummaryState:
"""调用DeepSeek LLM生成文本摘要"""
processed_text = state["processed_text"]
# 执行摘要链
summary = summary_chain.invoke({"processed_text": processed_text})
# 返回更新后的状态
return {"summary": summary}
3)节点3:摘要后处理(格式优化)
功能:对 LLM 生成的摘要进行格式优化(如分段、添加标题)。
def format_summary(state: SummaryState) -> SummaryState:
"""后处理摘要结果:优化格式"""
summary = state["summary"]
# 格式优化逻辑:添加标题、分段
formatted_summary = f"### 文档摘要\n\n{summary.replace('. ', '.\n')}"
# 返回最终状态
return {"summary": formatted_summary}
3. 构建线性工作流图(StateGraph)
通过StateGraph串联节点,在线性流程中使用add_edge(from_node, to_node)定义顺序关系,最后通过compile()生成可执行的图实例。
from langgraph.graph import StateGraph, END
# 1. 初始化状态图(绑定状态结构)
graph_builder = StateGraph(SummaryState)
# 2. 添加节点(每个节点映射到对应的处理函数)
graph_builder.add_node("process_doc", process_document) # 节点1:预处理
graph_builder.add_node("generate_summary", generate_summary) # 节点2:LLM摘要
graph_builder.add_node("format_summary", format_summary) # 节点3:后处理
# 3. 定义线性边(顺序执行:预处理→摘要生成→格式优化→结束)
graph_builder.add_edge("process_doc", "generate_summary")
graph_builder.add_edge("generate_summary", "format_summary")
graph_builder.add_edge("format_summary", END) # 最后一个节点指向END(工作流结束)
# 4. 设置入口节点(工作流起始点)
graph_builder.set_entry_point("process_doc")
# 5. 编译生成工作流实例
summary_graph = graph_builder.compile()
4. 执行工作流与调试
通过graph.invoke(input_state)触发工作流执行,输入状态需包含入口节点依赖的初始数据(如raw_document)。LangGraph支持可视化工作流结构,便于调试。
1)执行工作流
# 测试用原始文档(可替换为实际文档)
raw_document = """
LangGraph 是 LangChain 生态系统中的一个框架,专门用于构建状态ful、可循环的工作流。它基于状态机的思想,允许开发者定义节点和边,通过状态对象管理整个工作流的数据流转。与传统的线性脚本相比,LangGraph提供了更好的可扩展性和可观测性,特别适合 LLM 应用中的复杂流程编排,例如多轮对话、文档分析、工具调用链等场景。LangGraph 的核心组件包括 StateGraph、State、Node 和 Edge,这些组件共同构成了灵活且强大的工作流系统。
"""
# 执行工作流:输入初始状态(仅包含raw_document)
result = summary_graph.invoke({
"raw_document": raw_document
})
# 输出结果
print("最终摘要:")
print(result["summary"])
2)可视化工作流(可选)
LangGraph支持通过graph.draw()生成工作流结构图(需安装pygraphviz依赖):
pip install pygraphviz
# 生成PNG格式的工作流图(保存到本地)
summary_graph.draw("summary_workflow.png")
print("工作流图已保存为 summary_workflow.png")
5. 流程执行解析
- 初始状态:仅包含raw_document(原始文档)。
- 节点1(process_doc):清洗原始文档,更新processed_text。
- 节点2(generate_summary):读取processed_text,调用DeepSeek LLM生成摘要,更新summary。
- 节点3(format_summary):优化summary格式,最终状态包含所有字段。
- 工作流结束:返回最终状态,提取summary作为输出。
5.1.3 实战案例:文档摘要工作流的实现
LangGraph线性工作流的核心价值在于将“离散的LLM调用+数据处理”封装为结构化、可维护的流程,相比传统脚本来说具有以下优点:
- 状态管理更清晰:通过统一的State对象避免全局变量。
- 可扩展性更强:节点可独立修改、复用,支持后续扩展分支/循环。
- 可观测性更好:支持日志追踪、流程可视化,便于问题定位。
【示例5.1】文档摘要工作流完整程序实现(LangGraph_linear_workflow.py)。
# 1. 导入核心依赖库(仅保留必要组件)
from typing import TypedDict, Optional
from dotenv import load_dotenv
import os
import requests
from langgraph.graph import StateGraph, END
# 2. 加载环境变量(DASHSCOPE_API_KEY)
load_dotenv()
DASHSCOPE_API_KEY = os.getenv("DASHSCOPE_API_KEY")
# 校验API Key是否存在
if not DASHSCOPE_API_KEY:
raise ValueError("
请在.env文件中配置DASHSCOPE_API_KEY!")
# 3. 定义工作流状态结构(保持简洁)
class SummaryState(TypedDict):
raw_document: str # 输入:原始文档
processed_text: Optional[str] # 中间结果:预处理后的文本
summary: Optional[str] # 输出:LLM生成的摘要
# 4. 直接实现DASHSCOPE_API_KEY调用(无任何LangChain封装依赖)
def call_deepseek_api(user_content: str, temperature: float = 0.3, max_tokens: int = 500) -> str:
"""直接调用DeepSeek API,不依赖LangChain任何模块"""
url = "https://dashscope.aliyuncs.com/api/v1/services/aigc/ text-generation/generation"
headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {DASHSCOPE_API_KEY}"
}
# 完整的API请求体(包含system指令和user内容)
data = {
"model": "deepseek-chat",
"messages": [
{
"role": "system",
"content": "你是专业的文本摘要助手,需基于以下文本生成简洁、准确的摘要,不添加额外信息,长度控制在300字以内。"
},
{
"role": "user",
"content": user_content
}
],
"temperature": temperature,
"max_tokens": max_tokens,
"stream": False,
"stop": None
}
try:
# 发送API请求
response = requests.post(url, headers=headers, json=data, timeout=60)
response.raise_for_status() # 抛出HTTP错误(4xx/5xx)
result = response.json()
# 提取LLM生成的内容
return result["choices"][0]["message"]["content"].strip()
except requests.exceptions.Timeout:
return "
LLM调用超时,请检查网络连接或重试。"
except requests.exceptions.ConnectionError:
return "
网络连接失败,请确保能访问DeepSeek API。"
except requests.exceptions.HTTPError as e:
return f"
API请求错误(状态码:{response.status_code}):{e.response.text[:200]}"
except Exception as e:
return f"
LLM调用失败:{str(e)[:100]}"
# 5. 工作流节点逻辑(完全独立,无外部依赖)
def process_document(state: SummaryState) -> SummaryState:
"""节点1:文档预处理(清洗文本格式)"""
raw_doc = state["raw_document"]
# 增强清洗:处理换行、空格、制表符、全角空格
processed = (raw_doc.strip()
.replace("\n\n", "\n")
.replace(" ", " ")
.replace("\t", " ")
.replace(" ", " ") # 中文全角空格
.replace("\r", "")) # 回车符
return {"processed_text": processed}
def generate_summary(state: SummaryState) -> SummaryState:
"""节点2:调用DeepSeek API生成摘要"""
try:
processed_text = state["processed_text"]
if not processed_text or len(processed_text) < 10:
raise ValueError("预处理后的文本为空或过短")
# 直接调用API(无须LangChain提示词模板)
summary = call_deepseek_api(user_content=processed_text)
return {"summary": summary}
except Exception as e:
error_msg = f"
摘要生成失败:{str(e)}"
print(error_msg)
return {"summary": error_msg}
def format_summary(state: SummaryState) -> SummaryState:
"""节点3:摘要后处理(优化格式)"""
summary = state["summary"]
line_break = "\n"
# 中英文句号分句,避免格式混乱
split_summary = summary.replace(". ", f".{line_break}").replace("。 ", f"。{line_break}")
# 最终格式化(添加标题,去除末尾多余换行)
formatted_summary = f"### 文档摘要{line_break}{line_break}{split_summary}".rstrip(line_break)
return {"summary": formatted_summary}
# 6. 构建LangGraph线性工作流(核心逻辑不变)
def build_summary_graph():
"""构建并返回工作流实例(仅依赖LangGraph核心)"""
graph_builder = StateGraph(SummaryState)
# 添加节点
graph_builder.add_node("process_doc", process_document) # 预处理
graph_builder.add_node("generate_summary", generate_summary) # 生成摘要
graph_builder.add_node("format_summary", format_summary) # 格式优化
# 定义线性执行顺序:预处理 → 生成摘要 → 格式优化 → 结束
graph_builder.add_edge("process_doc", "generate_summary")
graph_builder.add_edge("generate_summary", "format_summary")
graph_builder.add_edge("format_summary", END)
# 设置入口节点
graph_builder.set_entry_point("process_doc")
return graph_builder.compile()
# 7. 可视化工作流(可选,失败不影响核心功能)
def visualize_graph(graph, save_path: str = "summary_workflow.png"):
"""简化可视化逻辑,避免依赖报错"""
try:
graph.draw(save_path, format="png")
print(f"\n
工作流可视化图已保存至:{os.path.abspath(save_path)}")
except Exception:
print("\n
可视化功能未启用(需安装pygraphviz和Graphviz软件,不影响核心功能)")
# 8. 主函数(执行入口)
if __name__ == "__main__":
# 测试用原始文档(可替换为任意文本)
raw_document = """
LangGraph 是 LangChain 生态系统中的一个框架,专门用于构建有状态、可循环的工作流。它基于状态机的思想,允许开发者定义节点和边,并通过状态对象管理整个工作流的数据流转。与传统的线性脚本相比,LangGraph 提供了更好的可扩展性和可观测性, 特别适合 LLM 应用中的复杂流程编排,例如多轮对话、文档分析、工具调用链等场景。LangGraph 的核心组件包括 StateGraph、State、Node 和 Edge, 这些组件共同构成了灵活且强大的工作流系统。此外,LangGraph 还支持与 LangChain 生态的其他工具无缝集成,如提示词模板、向量数据库、工具调用等,进一步降低了复杂 LLM 应用的开发门槛。
"""
# 初始化工作流
print("
正在初始化LangGraph线性工作流...")
summary_graph = build_summary_graph()
# 可视化工作流(可选)
visualize_graph(summary_graph)
# 执行工作流
print("\n
正在执行文档摘要工作流...")
result = summary_graph.invoke({
"raw_document": raw_document
})
# 输出最终结果
print("\n" + "="*60)
print("
最终摘要结果:")
print("="*60)
print(result["summary"])
print("="*60)
运行输出:
正在初始化LangGraph线性工作流...
可视化功能未启用(需安装pygraphviz和Graphviz软件,不影响核心功能)
正在执行文档摘要工作流...
============================================================
最终摘要结果:
============================================================
### 文档摘要
LangGraph是LangChain生态系统中的框架,用于构建有状态、可循环的工作流。它基于状态机思想,通过定义节点和边,利用状态对象管理数据流转。相比传统线性脚本,LangGraph具有更好的可扩展性和可观测性,适用于LLM应用中的复杂流程编排,如多轮对话、文档分析和工具调用链。其核心组件包括StateGraph、State、Node和Edge,共同构成灵活的工作流系统。此外,LangGraph能与LangChain生态中的提示词模板、向量数据库等工具无缝集成,降低复杂LLM应用的开发门槛。


365

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



