【LangGraph】如何使用 LangGraph

本文介绍了如何使用 LangGraph 来构建和管理基于大型语言模型(LLM)的复杂工作流。从安装开始,逐步讲解核心步骤、关键概念、代码示例,以及如何在实际场景中应用 LangGraph。


目录

  1. 安装和环境准备
  2. LangGraph 的核心概念回顾
  3. 构建一个 LangGraph 工作流:分步指南
  4. 代码示例:简单工作流
  5. 高级功能:条件边、循环和工具调用
  6. 结合 LangChain 和 LangSmith
  7. 实际应用场景示例
  8. 调试和优化
  9. 常见问题和注意事项
  10. 学习资源和下一步

1. 安装和环境准备

在使用 LangGraph 之前,你需要设置开发环境并安装必要的依赖。

1.1 安装 LangGraph 和 LangChain

LangGraph 是 LangChain 生态的一部分,因此需要安装 LangChain 和 LangGraph。

pip install langchain langgraph

如果你计划使用特定的 LLM(如 OpenAI 的 GPT 模型),还需要安装对应的客户端库。例如:

pip install langchain-openai  # 用于 OpenAI API

1.2 配置 API 密钥

如果使用外部 LLM 服务(如 OpenAI、Anthropic),需要配置 API 密钥。可以通过环境变量设置:

export OPENAI_API_KEY="your-api-key"

或者在代码中手动设置(不推荐用于生产环境):

import os
os.environ["OPENAI_API_KEY"] = "your-api-key"

1.3 验证安装

运行以下代码,检查是否正确安装:

from langgraph.graph import StateGraph
print("LangGraph installed successfully!")

2. LangGraph 的核心概念回顾

在开始使用之前,快速回顾 LangGraph 的核心概念(详细介绍见前文):

  • 状态(State):一个数据结构(如字典或类),用于存储工作流的上下文信息,在节点间传递和更新。
  • 节点(Node):执行具体任务的函数(如调用 LLM、处理数据),接收状态并返回更新后的状态。
  • 边(Edge):定义节点之间的连接,可以是无条件的(直接跳转)或条件边(基于状态跳转)。
  • 图(Graph):由节点和边组成的结构,表示整个工作流,使用 StateGraph 类定义。

LangGraph 的执行逻辑是:输入初始状态 → 图按节点和边定义的顺序执行 → 不断更新状态 → 直到达到终止条件。


3. 构建一个 LangGraph 工作流:分步指南

以下是使用 LangGraph 构建工作流的标准步骤:

3.1 定义状态

状态是工作流的核心,用于存储和传递信息。可以使用 Python 的 TypedDict 或自定义类来定义状态。

示例状态定义:

from typing import TypedDict

class State(TypedDict):
    input: str  # 用户输入
    output: str  # 处理结果

3.2 创建节点

节点是执行任务的函数,接收状态并返回更新后的状态。每个节点是一个 Python 函数。

示例节点:

def process_input(state: State) -> State:
    state["output"] = f"处理输入: {state['input']}"
    return state

def finalize_output(state: State) -> State:
    state["output"] += " -> 已完成"
    return state

3.3 定义边

边指定节点之间的执行顺序。可以使用:

  • add_edge 添加无条件边。
  • add_conditional_edges 添加条件边。

3.4 构建图

使用 StateGraph 类创建图,添加节点、边,并设置入口和出口。

from langgraph.graph import StateGraph, START, END

# 创建图
workflow = StateGraph(State)

# 添加节点
workflow.add_node("process_input", process_input)
workflow.add_node("finalize_output", finalize_output)

# 添加边
workflow.add_edge("process_input", "finalize_output")
workflow.add_edge(START, "process_input")  # 设置入口
workflow.add_edge("finalize_output", END)  # 设置出口

# 编译图
graph = workflow.compile()

3.5 执行工作流

使用 invoke 方法运行图,传入初始状态。

result = graph.invoke({"input": "Hello, LangGraph!", "output": ""})
print(result)

4. 代码示例:简单工作流

以下是一个完整的简单工作流示例,展示如何处理用户输入并生成输出。

from typing import TypedDict
from langgraph.graph import StateGraph, START, END

# 定义状态
class State(TypedDict):
    input: str
    output: str

# 定义节点
def process_input(state: State) -> State:
    state["output"] = f"处理输入: {state['input']}"
    return state

def finalize_output(state: State) -> State:
    state["output"] += " -> 已完成"
    return state

# 创建图
workflow = StateGraph(State)
workflow.add_node("process_input", process_input)
workflow.add_node("finalize_output", finalize_output)
workflow.add_edge(START, "process_input")
workflow.add_edge("process_input", "finalize_output")
workflow.add_edge("finalize_output", END)

# 编译和运行
graph = workflow.compile()
result = graph.invoke({"input": "Hello, LangGraph!", "output": ""})
print(result)

输出

{'input': 'Hello, LangGraph!', 'output': '处理输入: Hello, LangGraph! -> 已完成'}

这个示例展示了:

  • 一个简单的状态(包含 inputoutput)。
  • 两个节点:process_inputfinalize_output
  • 线性工作流:从 STARTprocess_input,再到 finalize_output,最后到 END

5. 高级功能:条件边、循环和工具调用

LangGraph 的强大之处在于支持动态逻辑、循环和工具调用。以下是实现这些功能的方法。

5.1 条件边

条件边允许根据状态动态选择下一个节点。使用 add_conditional_edges 定义条件逻辑。

示例:根据输入内容决定下一步:

from typing import TypedDict
from langgraph.graph import StateGraph, START, END

class State(TypedDict):
    input: str
    output: str
    needs_processing: bool

def check_input(state: State) -> State:
    state["needs_processing"] = len(state["input"]) > 5  # 输入长度大于5需要处理
    return state

def process_input(state: State) -> State:
    state["output"] = f"处理输入: {state['input']}"
    return state

def skip_processing(state: State) -> State:
    state["output"] = "输入太短,无需处理"
    return state

# 条件函数
def route(state: State) -> str:
    return "process_input" if state["needs_processing"] else "skip_processing"

# 创建图
workflow = StateGraph(State)
workflow.add_node("check_input", check_input)
workflow.add_node("process_input", process_input)
workflow.add_node("skip_processing", skip_processing)
workflow.add_edge(START, "check_input")
workflow.add_conditional_edges("check_input", route, {
    "process_input": "process_input",
    "skip_processing": "skip_processing"
})
workflow.add_edge("process_input", END)
workflow.add_edge("skip_processing", END)

# 编译和运行
graph = workflow.compile()
result = graph.invoke({"input": "Hi", "output": "", "needs_processing": False})
print(result)

输出(输入 “Hi”):

{'input': 'Hi', 'output': '输入太短,无需处理', 'needs_processing': False}

输出(输入 “Hello, LangGraph!”):

{'input': 'Hello, LangGraph!', 'output': '处理输入: Hello, LangGraph!', 'needs_processing': True}

5.2 循环

LangGraph 支持循环,适合需要反复执行的场景(如 agent 多次调用工具)。可以通过条件边返回到之前的节点。

示例:循环直到满足条件:

from typing import TypedDict
from langgraph.graph import StateGraph, START, END

class State(TypedDict):
    counter: int
    output: str

def increment(state: State) -> State:
    state["counter"] += 1
    state["output"] = f"当前计数: {state['counter']}"
    return state

def should_continue(state: State) -> str:
    return "increment" if state["counter"] < 3 else END

# 创建图
workflow = StateGraph(State)
workflow.add_node("increment", increment)
workflow.add_edge(START, "increment")
workflow.add_conditional_edges("increment", should_continue, {
    "increment": "increment",
    END: END
})

# 编译和运行
graph = workflow.compile()
result = graph.invoke({"counter": 0, "output": ""})
print(result)

输出

{'counter': 3, 'output': '当前计数: 3'}

5.3 工具调用

LangGraph 可以与 LangChain 的工具集成,动态调用外部 API 或函数。

示例:使用 LLM 和搜索工具:

from langchain_openai import ChatOpenAI
from langchain_core.tools import tool
from typing import TypedDict
from langgraph.graph import StateGraph, START, END

# 定义工具
@tool
def search(query: str) -> str:
    """模拟搜索工具"""
    return f"搜索结果 for {query}: 找到了一些信息!"

# 定义状态
class State(TypedDict):
    input: str
    output: str
    needs_search: bool

# 节点:调用 LLM 判断是否需要搜索
def call_llm(state: State) -> State:
    llm = ChatOpenAI(model="gpt-4o-mini")
    prompt = f"用户输入: {state['input']}\n是否需要搜索?回答 'yes' 或 'no'。"
    response = llm.invoke(prompt).content
    state["needs_search"] = response.lower() == "yes"
    state["output"] = "正在处理..."
    return state

# 节点:执行搜索
def call_search(state: State) -> State:
    result = search.invoke(state["input"])
    state["output"] = result
    return state

# 节点:直接回答
def direct_answer(state: State) -> State:
    state["output"] = f"直接回答: {state['input']}"
    return state

# 条件函数
def route(state: State) -> str:
    return "call_search" if state["needs_search"] else "direct_answer"

# 创建图
workflow = StateGraph(State)
workflow.add_node("call_llm", call_llm)
workflow.add_node("call_search", call_search)
workflow.add_node("direct_answer", direct_answer)
workflow.add_edge(START, "call_llm")
workflow.add_conditional_edges("call_llm", route, {
    "call_search": "call_search",
    "direct_answer": "direct_answer"
})
workflow.add_edge("call_search", END)
workflow.add_edge("direct_answer", END)

# 编译和运行
graph = workflow.compile()
result = graph.invoke({"input": "今天的天气", "output": "", "needs_search": False})
print(result)

输出(假设 LLM 认为需要搜索):

{'input': '今天的天气', 'output': '搜索结果 for 今天的天气: 找到了一些信息!', 'needs_search': True}

6. 结合 LangChain 和 LangSmith

6.1 与 LangChain 集成

LangGraph 通常与 LangChain 一起使用,LangChain 提供:

  • LLM 封装:如 ChatOpenAIChatAnthropic
  • 工具支持:通过 langchain_core.tools 定义工具。
  • Prompt 管理:使用 PromptTemplate 构建结构化提示。

示例:结合 PromptTemplate 和 LLM:

from langchain_core.prompts import PromptTemplate
from langchain_openai import ChatOpenAI

prompt = PromptTemplate.from_template("处理用户输入: {input}")
llm = ChatOpenAI(model="gpt-4o-mini")

def llm_node(state: State) -> State:
    response = llm.invoke(prompt.format(input=state["input"])).content
    state["output"] = response
    return state

6.2 与 LangSmith 集成

LangSmith 是 LangChain 提供的调试和监控工具,可以可视化 LangGraph 的执行过程。

  1. 启用 LangSmith

    export LANGCHAIN_TRACING_V2="true"
    export LANGCHAIN_API_KEY="your-langsmith-api-key"
    
  2. 运行代码:LangGraph 会自动将执行日志发送到 LangSmith。

  3. 查看日志:在 LangSmith 界面中,可以看到每个节点的输入输出、状态变化和执行路径。


7. 实际应用场景示例

以下是一个实际场景:构建一个客服 Agent,能够回答用户问题或调用搜索工具。

场景描述

  • 用户输入问题。
  • Agent 判断是否需要搜索。
  • 如果需要搜索,调用搜索工具并生成回答。
  • 如果无需搜索,直接生成回答。

代码实现

from langchain_openai import ChatOpenAI
from langchain_core.tools import tool
from langchain_core.prompts import PromptTemplate
from typing import TypedDict
from langgraph.graph import StateGraph, START, END

# 定义工具
@tool
def search(query: str) -> str:
	"""模拟搜索工具"""
    return f"搜索结果: {query} 的信息"

# 定义状态
class State(TypedDict):
    input: str
    output: str
    needs_search: bool

# 定义节点
def decide_action(state: State) -> State:
    llm = ChatOpenAI(model="gpt-4o-mini")
    prompt = PromptTemplate.from_template(
        "用户问题: {input}\n回答 'yes' 如果需要搜索,'no' 如果可以直接回答。"
    )
    response = llm.invoke(prompt.format(input=state["input"])).content
    state["needs_search"] = response.lower() == "yes"
    return state

def search_node(state: State) -> State:
    result = search.invoke(state["input"])
    state["output"] = result
    return state

def answer_node(state: State) -> State:
    llm = ChatOpenAI(model="gpt-4o-mini")
    prompt = PromptTemplate.from_template("直接回答用户问题: {input}")
    response = llm.invoke(prompt.format(input=state["input"])).content
    state["output"] = response
    return state

# 条件函数
def route(state: State) -> str:
    return "search_node" if state["needs_search"] else "answer_node"

# 创建图
workflow = StateGraph(State)
workflow.add_node("decide_action", decide_action)
workflow.add_node("search_node", search_node)
workflow.add_node("answer_node", answer_node)
workflow.add_edge(START, "decide_action")
workflow.add_conditional_edges("decide_action", route, {
    "search_node": "search_node",
    "answer_node": "answer_node"
})
workflow.add_edge("search_node", END)
workflow.add_edge("answer_node", END)

# 编译和运行
graph = workflow.compile()
result = graph.invoke({"input": "什么是 LangGraph?", "output": "", "needs_search": False})
print(result)

输出(假设 LLM 认为需要搜索):

{'input': '什么是 LangGraph?', 'output': '搜索结果: 什么是 LangGraph? 的信息', 'needs_search': True}

8. 调试和优化

8.1 使用 LangSmith 调试

  • 检查每个节点的输入输出。
  • 分析条件边的跳转逻辑。
  • 识别性能瓶颈(如 LLM 调用时间过长)。

8.2 优化技巧

  • 减少 LLM 调用:尽量在节点中缓存结果或合并逻辑。
  • 精简状态:只存储必要的数据,减少内存占用。
  • 错误处理:在节点中添加 try-except,处理工具调用或 LLM 失败的情况。

9. 常见问题和注意事项

9.1 常见问题

  • Q:状态未正确更新?
    • A:确保节点返回了更新后的状态,且状态结构与定义一致。
  • Q:条件边跳转错误?
    • A:检查条件函数的返回值是否与 add_conditional_edges 的映射一致。
  • Q:图执行卡住?
    • A:可能是循环未正确终止,检查条件边逻辑。

9.2 注意事项

  • 状态不可变:LangGraph 默认状态是可变的,建议在节点中创建状态副本以避免意外修改。
  • 线程安全:如果在多线程环境中使用,确保状态和节点函数是线程安全的。
  • 工具调用成本:频繁调用外部工具(如搜索 API)可能增加延迟和费用,需优化调用频率。

10. 学习资源和下一步

10.1 学习资源

10.2 下一步

  • 尝试更复杂的场景,如多 Agent 协作或 RAG 工作流。
  • 探索 LangGraph 的异步支持(graph.ainvoke),提高性能。
  • 使用 LangSmith 优化你的工作流,分析性能瓶颈。

总结

使用 LangGraph 的核心在于:

  1. 定义清晰的状态结构。
  2. 编写模块化的节点函数。
  3. 通过边和条件边实现动态逻辑。
  4. 结合 LangChain 的 LLM 和工具,构建强大的工作流。
STM32F103是意法半导体(STMicroelectronics)推出的一款基于ARM Cortex-M3内核的微控制器,广泛应用于工业控制、物联网设备等领域。本资料包主要提供了STM32F103在实现RS485通信及Modbus RTU协议的主机和从机模式下的源代码实例,帮助开发者快速理解和应用这一通讯技术。 RS485是一种物理层通信标准,用于构建多点数据通信网络,具有传输距离远、抗干扰能力强的特点。它采用差分信号传输方式,可以实现双向通信,适合于长距离的工业环境。在RS485网络中,通常有一个主机(Master)和一个或多个从机(Slave),主机负责发起通信,从机响应主机的请求。 Modbus RTU(Remote Terminal Unit)是一种常用的过程控制工业通信协议,基于ASCII或RTU(远程终端单元)报文格式,常用于PLC(可编程逻辑控制器)和嵌入式系统之间的通信。Modbus RTU使用串行通信接口,如RS485,以减少布线成本和提高通信效率。 在STM32F103上实现RS485 Modbus RTU通信,首先需要配置GPIO口作为RS485的硬件接口,包括数据线(一般为RX和TX)和方向控制线(DE和RE)。DE线用于控制发送数据时的数据线方向,RE线则用于接收数据时的方向。这些设置可以通过STM32的HAL库或LL库进行编程。 接着,你需要编写Modbus RTU协议栈的实现,这包括解析和构造Modbus报文、错误检测与处理、超时管理等。Modbus RTU报文由功能码、地址、数据和CRC校验码组成。主机向从机发送请求报文,从机会根据接收到的功能码执行相应的操作,并返回响应报文。 在主机端,你需要实现发送请求和接收响应的函数,以及解析从机返回的数据。在从机端,你需要监听串口,解析接收到的请求,执行相应的功能并构造响应报文。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

彬彬侠

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值