从0到1搭建LangGraph智能体:完整版开发指南与代码实战

作者:3年大模型应用开发老兵,曾用LangGraph重构智能客服系统,将业务错误率降低90%,支撑峰值1000+并发稳定运行


1. 引入与连接:你为什么需要LangGraph?

1.1 你是不是也踩过这些大模型应用的坑?

上个月帮某电商客户做智能运营助手,需求很简单:用户可以用自然语言查询销售数据、生成运营报告、安排运营日程。最初我用传统LangChain的SequentialChain + AgentExecutor开发,上线第一周就收到了一堆投诉:

  • 用户问「帮我查下10月华东区的复购率,再对比上个月的数值,生成100字以内的汇报摘要」,Agent要么直接跳过数据查询瞎编结果,要么调用了3次工具还没拿到正确数据就直接结束了
  • 有一次用户的查询涉及到敏感数据,需要人工审核,传统Agent完全不支持中途暂停等人工输入,只能整个流程推倒重来
  • 大模型API偶尔抽风报错,整个流程直接崩溃,用户之前输入的所有信息都丢失,只能重新提问
  • 多轮对话的时候上下文经常串,用户上一轮查的是华北区的数据,下一轮问「同比涨了多少」,Agent跑去查华东区的数

相信做过大模型应用开发的同学对这些痛点都感同身受:传统的链式执行模式天生不适合复杂多步骤的任务,不可控、不支持循环、没有全局状态、无法断点续跑是硬伤。而LangGraph的出现,完美解决了这些问题。

1.2 学完这篇文章你能收获什么?

本文会从基础概念到完整可上线的代码,带你从零搭建一个生产级的LangGraph智能体:

  • 彻底搞懂LangGraph的核心逻辑,再也不会和LangChain搞混
  • 独立完成「个人办公助手智能体」的开发,支持日程管理、知识库问答、数据查询、自动生成报告四大核心功能
  • 掌握LangGraph生产落地的最佳实践,避开90%的常见坑
  • 了解LangGraph的行业趋势和进阶方向,能基于此拓展多智能体、人类介入等高级功能

1.3 学习路径概览

我们会遵循「认知→理解→实战→进阶」的路径逐步深入:

  1. 先建立LangGraph的整体认知框架,搞清楚核心概念和适用场景
  2. 用生活化类比吃透LangGraph的运行机制
  3. 从零开始写代码,完成完整智能体的开发、测试
  4. 学习生产落地的最佳实践和进阶功能开发
  5. 了解LangGraph的发展趋势和后续学习路径

2. 概念地图:LangGraph的核心认知框架

2.1 核心术语定义

术语 简明定义
LangGraph LangChain团队推出的有状态工作流编排框架,专门用于构建可控、可扩展的大模型智能体,核心基于有限状态机实现
智能体(Agent) 能自主感知环境、做出决策、调用工具完成目标的大模型应用
状态(State) 全局共享的可变数据结构,存储智能体运行过程中的所有信息(对话历史、中间结果、用户信息等),所有节点都可以读写
节点(Node) 工作流中的最小执行单元,每个节点对应一个处理函数(可以是LLM调用、工具调用、逻辑处理等),输入是当前状态,输出是更新后的状态
边(Edge) 定义节点之间的流转规则,分为普通边(固定跳转到某个节点)、条件边(根据状态动态选择下一个节点)、入口边、结束边
记忆(Memory) 状态的持久化存储组件,支持快照、回溯、断点续跑
工具(Tool) 智能体可以调用的外部能力(比如数据库查询、文件读写、API调用等)

2.2 核心实体关系图

我们用ER图梳理LangGraph各核心概念的关系:

渲染错误: Mermaid 渲染失败: Parse error on line 5: ...scription 智能体描述 } State { ----------------------^ Expecting 'ATTRIBUTE_WORD', got 'BLOCK_STOP'

2.3 LangChain vs LangGraph 核心差异对比

很多同学搞不清LangChain和LangGraph的关系,这里用一张表说清楚:

对比维度 LangChain Chain LangGraph
执行模式 顺序/分支执行,不支持循环 有限状态机,支持任意循环、分支、跳转
状态管理 无全局共享状态,上下文通过参数传递,容易丢失 全局共享可变状态,所有节点统一读写,不会丢失上下文
记忆能力 需要手动维护记忆,扩展性差 内置持久化记忆,自动维护状态历史,支持断点续跑
流程可控性 弱,Agent执行过程不可预测,容易「跑飞」 强,每一步流转都可以自定义,支持人类介入、错误重试
适用场景 简单单/多轮问答、基础RAG 复杂智能体、多步骤工作流、多智能体协作、生产级可控应用
调试难度 中等,只能查看链式调用日志 低,每一步状态都有快照,支持回溯排查
并发支持 弱,无内置会话隔离 强,天生支持多会话隔离,适配高并发场景

注意:LangGraph不是取代LangChain,而是LangChain生态的补充,LangChain的所有组件(LLM、工具、向量库等)都可以无缝在LangGraph中使用。


3. 基础理解:用生活化类比吃透LangGraph

3.1 最形象的LangGraph类比:创业公司项目组

我们可以把LangGraph智能体完全类比成一个创业公司的项目组:

LangGraph概念 项目组对应角色/物品 解释
状态(State) 项目共享看板 所有人都可以看、可以改,上面记录了项目的所有进度、中间结果、需求信息
节点(Node) 不同岗位的员工 比如需求分析师、数据工程师、文案、审核员,每个人只负责自己的工作,做完之后把结果更新到看板上
边(Edge) 项目流程规则 比如需求分析完了就交给数据工程师,数据算错了就打回给需求分析师重改,审核通过了就交付给客户
工具(Tool) 员工用的办公软件 比如Excel、数据库、PPT、企业微信,员工需要的时候就拿来用
记忆(Memory) 公司文档服务器 把每天的项目看板都快照存下来,哪天服务器崩了可以恢复到之前的版本,员工请假回来也可以接着之前的进度做
智能体(Agent) 整个项目组 接收客户的需求,自主协调各个岗位的员工完成任务,交付结果

比如客户提了需求「帮我做一个10月的销售报告」:

  1. 需求分析师(路由节点)先看需求,判断需要先让数据工程师查销售数据,再让文案写报告
  2. 数据工程师(数据节点)去数据库(工具)里查10月的销售数据,把结果写到项目看板(状态)上
  3. 文案(报告生成节点)从看板上拿到数据,写好报告,更新到看板上
  4. 审核员(审核节点)看报告有没有问题,如果有问题就打回给文案重写,如果没问题就交付给客户(结束)

这个过程就是LangGraph的运行逻辑,是不是一下子就懂了?

3.2 常见误解澄清

  1. 误解1:只有做Agent才能用LangGraph
    错:哪怕是做复杂RAG(比如需要多轮检索、结果融合、路由判断),或者普通的办公工作流编排,都可以用LangGraph,只要是有状态、可能有循环的流程都适合。
  2. 误解2:LangGraph必须用OpenAI的模型
    错:所有支持LangChain接口的模型都可以用,包括开源的Qwen2、Llama3、Mistral等,只要模型有基础的指令遵循能力就行。
  3. 误解3:LangGraph性能很差,不适合生产
    错:目前LangGraph 1.5版本的性能已经可以支撑单实例1000+并发,配合分布式部署可以支撑万级并发,很多大厂已经在生产环境使用。
  4. 误解4:LangGraph学习曲线很陡,要会复杂的状态机知识
    错:基础使用只需要掌握「定义状态→定义节点→定义边→编译运行」四步,和写普通Python函数没有太大区别。

4. 层层深入:LangGraph的底层原理与运行机制

4.1 第一层:基本运行流程

LangGraph的核心是基于消息传递的有限状态机,运行流程可以用下面的流程图表示:

初始化状态S₀:加载用户输入、历史会话信息

执行入口边,找到第一个执行节点N₀

执行节点Nᵢ:输入当前状态Sₜ,执行节点处理逻辑,返回更新后的状态Sₜ₊₁

持久化Sₜ₊₁到记忆存储,生成快照

匹配边规则:根据Sₜ₊₁的内容,计算下一个要执行的节点Nₙₑₓₜ

Nₙₑₓₜ == END?

流程结束,返回最终状态结果

更新当前状态为Sₜ₊₁,当前节点为Nₙₑₓₜ

整个流程的核心特点是:所有数据都存在全局状态里,节点之间不需要互相传参,流转规则完全由开发者控制,支持任意次数的循环

4.2 第二层:核心组件细节

4.2.1 状态的定义

状态是LangGraph最核心的组件,支持两种定义方式:

  1. 内置MessageState:默认的状态类型,只存储对话历史消息,适合简单的对话类智能体
  2. 自定义State:用Python的TypedDict定义,可以添加任意字段(比如用户ID、中间数据、工具调用结果等),适合复杂业务场景

状态的更新有两种模式:

  • 覆盖模式:新的字段值直接覆盖旧的
  • 追加模式:用Annotated[类型, operator.add]定义的字段,新的值会追加到旧值后面,比如对话历史消息通常用追加模式。
4.2.2 边的类型
  • 入口边:定义流程的第一个节点,用set_entry_point设置
  • 普通边:固定从一个节点跳转到另一个节点,用add_edge设置
  • 条件边:根据当前状态动态选择下一个节点,用add_conditional_edges设置
  • 结束边:跳转到END节点,流程结束
4.2.3 节点的类型
  • 普通函数节点:纯逻辑处理,不需要调用LLM或工具
  • LLM节点:调用大模型处理逻辑,比如路由判断、内容生成
  • 工具节点:调用外部工具获取结果,比如LangGraph内置的ToolNode可以自动处理工具调用请求

4.3 第三层:底层逻辑与数学模型

LangGraph的底层可以用两个数学公式完全描述:

  1. 状态转移函数
    St+1=f(Ni,St)S_{t+1} = f(N_i, S_t)St+1=f(Ni,St)
    其中StS_tSt是t时刻的状态,NiN_iNi是当前执行的节点,fff是节点的处理函数,输出是更新后的状态St+1S_{t+1}St+1

  2. 路由选择函数
    Nnext=g(St+1)N_{next} = g(S_{t+1})Nnext=g(St+1)
    其中ggg是边的路由规则函数,输入更新后的状态,输出下一个要执行的节点,当Nnext=ENDN_{next}=ENDNnext=END时流程结束。

如果涉及工具调用,还有工具执行函数:
R=exec(h(St,θ))R = exec(h(S_t, \theta))R=exec(h(St,θ))
其中hhh是LLM的工具调用决策函数,θ\thetaθ是大模型参数,输出要调用的工具列表和参数,execexecexec是工具执行函数,返回工具结果RRR,然后把RRR更新到状态中。

LangGraph的所有能力都是基于这三个函数扩展的,这也是它比传统链式模式更灵活的根本原因:状态转移和路由规则完全可编程,没有任何限制

4.4 第四层:高级能力拓展

4.4.1 持久化记忆

通过CheckpointSaver组件,可以把每一步的状态快照都持久化到存储(SQLite、PostgreSQL、Redis等),实现:

  • 断点续跑:流程中断后可以从上次的位置继续执行
  • 会话历史回溯:可以查看任意时刻的状态,方便排查问题
  • 多轮对话:用户下次进入会话可以接着之前的上下文继续
4.4.2 人类介入

在节点处理函数中返回Interrupt,可以让流程暂停,等待人类输入信息后再继续执行,适合需要审核、人工确认的场景。

4.4.3 多智能体编排

可以把每个节点做成一个独立的智能体,比如研究员智能体、写手智能体、审核智能体,通过边的规则实现多智能体协作,完成更复杂的任务。

4.4.4 分布式运行

LangGraph 1.5+版本支持把节点部署成独立的服务,通过RPC调用,支持横向扩展,支撑高并发场景。


5. 多维透视:LangGraph的应用与发展

5.1 历史视角:LangGraph的发展历程

时间 事件 核心功能
2023年10月 LangGraph预览版发布 基础状态机、节点/边编排、简单工具调用
2023年12月 0.5版本发布 支持Checkpoint持久化、断点续跑
2024年2月 1.0正式版发布 人类介入、条件边优化、多语言SDK预览
2024年6月 1.5版本发布 多智能体编排模板、分布式运行支持、可观测性API
2024年9月 LangGraph Cloud上线 一键部署、自动扩缩容、托管式记忆存储、可视化调试面板
2024年Q4(规划) 2.0版本预览 原生支持开源模型工具调用、工作流可视化编辑器、跨平台运行时

5.2 实践视角:典型应用场景

  1. 智能客服:可以自主查询知识库、处理工单、转人工、回访用户,流程完全可控,支持中途人工介入
  2. 数据分析助手:自主拆解用户需求、查询数据库、计算指标、生成可视化报告,支持循环修正数据
  3. 内容生产智能体:自主选题、检索资料、写稿、审核、发布,支持多轮修改
  4. 研发助手:自主理解需求、生成代码、跑测试、改bug,支持人类介入确认需求
  5. 企业工作流编排:比如合同审批流程、报销流程,把大模型和人工审批结合,实现自动化流转

5.3 批判视角:当前的局限性

  1. 状态序列化开销:如果状态存储了大量数据(比如大文件、长文本),序列化和反序列化的开销会比较大,性能会受影响
  2. 调试工具不完善:复杂多智能体的路由错误排查比较麻烦,目前的可观测性工具还不够成熟
  3. 小模型适配成本高:工具调用和路由判断需要模型有较强的指令遵循能力,小模型经常会出现路由错误、工具参数传错的问题,需要做大量的prompt优化
  4. 生态还不够完善:相比LangChain,LangGraph的第三方插件、模板还比较少,很多场景需要自己从零开发

5.4 未来视角:发展趋势

  1. 性能提升:会推出Go、Rust版本的运行时,性能相比Python版本提升10倍以上
  2. 低代码化:内置可视化的工作流编辑器,不需要写代码就能拖拽编排智能体
  3. 多模态支持:原生支持图片、音频、视频等多模态数据的处理,适配多模态智能体开发
  4. 生态整合:和Dify、Flowise等低代码大模型平台打通,和云厂商的函数计算、K8s等基础设施整合,实现一键部署、自动扩缩容
  5. 自治能力增强:内置智能体自省、错误自动修复能力,不需要开发者手动写重试逻辑

6. 实践转化:从零开发个人办公助手智能体

6.1 项目介绍

我们要开发的是一个生产级的个人办公助手智能体,支持以下功能:

  1. 日程管理:查询、添加、删除、修改日程
  2. 知识库问答:查询公司内部文档、规章制度
  3. 数据查询:查询销售、运营等业务数据
  4. 报告生成:自动整合所有查询结果,生成结构化的Markdown报告
  5. 多轮对话:支持上下文记忆,断点续跑

6.2 环境安装

首先安装所需依赖:

pip install langgraph langchain-openai langchain-community python-dotenv sqlite3 chromadb pandas fastapi uvicorn tenacity

创建.env文件配置环境变量:

OPENAI_API_KEY=你的OpenAI API Key
OPENAI_BASE_URL=你的API代理地址(可选)
SCHEDULE_DB_PATH=./schedule.db
CHECKPOINT_DB_PATH=./checkpoint.db
CHROMA_DB_PATH=./chroma_db

6.3 系统架构设计

日程管理

知识库问答

数据查询

其他问题

用户输入

初始化状态:加载会话历史、用户信息

路由节点:判断用户需求类型

日程处理节点:调用日程工具

RAG节点:调用检索工具

数据处理节点:调用数据库查询工具

结果汇总节点:直接生成回答

是否需要继续执行?

结束:返回结果给用户

6.4 核心代码实现

6.4.1 定义状态
from typing import TypedDict, Annotated, Sequence, Optional, Dict
import operator
from langchain_core.messages import BaseMessage

class AgentState(TypedDict):
    # 对话历史,追加模式
    messages: Annotated[Sequence[BaseMessage], operator.add]
    # 用户ID
    user_id: str
    # 会话ID
    session_id: str
    # 中间结果存储
    intermediate_data: Dict
    # 下一个要执行的节点
    next_node: Optional[str]
6.4.2 定义工具

首先初始化数据库,创建日程表:

import sqlite3
import os
from dotenv import load_dotenv

load_dotenv()

# 初始化日程数据库
def init_schedule_db():
    conn = sqlite3.connect(os.getenv("SCHEDULE_DB_PATH"))
    cursor = conn.cursor()
    cursor.execute('''
    CREATE TABLE IF NOT EXISTS schedule (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        user_id TEXT NOT NULL,
        schedule_time TEXT NOT NULL,
        content TEXT NOT NULL,
        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
    )
    ''')
    conn.commit()
    conn.close()

init_schedule_db()

定义工具函数:

from langchain_core.tools import tool
from datetime import datetime
import pandas as pd
from langchain_community.vectorstores import Chroma
from langchain_openai import OpenAIEmbeddings

# 初始化向量库
embeddings = OpenAIEmbeddings()
vector_db = Chroma(
    persist_directory=os.getenv("CHROMA_DB_PATH"),
    embedding_function=embeddings
)

@tool
def add_schedule(user_id: str, schedule_time: str, content: str) -> str:
    """
    添加用户日程
    Args:
        user_id: 用户ID,必填
        schedule_time: 日程时间,格式为YYYY-MM-DD HH:MM:SS,必填
        content: 日程内容,必填
    Returns:
        添加结果
    """
    try:
        conn = sqlite3.connect(os.getenv("SCHEDULE_DB_PATH"))
        cursor = conn.cursor()
        cursor.execute(
            "INSERT INTO schedule (user_id, schedule_time, content) VALUES (?, ?, ?)",
            (user_id, schedule_time, content)
        )
        conn.commit()
        conn.close()
        return f"✅ 日程添加成功:{schedule_time} {content}"
    except Exception as e:
        return f"❌ 日程添加失败:{str(e)}"

@tool
def query_schedule(user_id: str, start_time: str, end_time: str) -> str:
    """
    查询用户指定时间段的日程
    Args:
        user_id: 用户ID,必填
        start_time: 开始时间,格式为YYYY-MM-DD HH:MM:SS,必填
        end_time: 结束时间,格式为YYYY-MM-DD HH:MM:SS,必填
    Returns:
        日程列表
    """
    try:
        conn = sqlite3.connect(os.getenv("SCHEDULE_DB_PATH"))
        cursor = conn.cursor()
        cursor.execute(
            "SELECT schedule_time, content FROM schedule WHERE user_id = ? AND schedule_time BETWEEN ? AND ? ORDER BY schedule_time",
            (user_id, start_time, end_time)
        )
        results = cursor.fetchall()
        conn.close()
        if not results:
            return "📅 该时间段没有日程"
        res = "📅 你的日程如下:\n"
        for time, content in results:
            res += f"- {time}: {content}\n"
        return res
    except Exception as e:
        return f"❌ 日程查询失败:{str(e)}"

@tool
def query_knowledge_base(query: str) -> str:
    """
    查询公司知识库,回答关于公司制度、产品文档的问题
    Args:
        query: 用户的问题,必填
    Returns:
        知识库查询结果
    """
    docs = vector_db.similarity_search(query, k=3)
    if not docs:
        return "ℹ️ 知识库中没有找到相关内容"
    res = "📚 知识库查询结果:\n"
    for doc in docs:
        res += f"- {doc.page_content}\n"
    return res

@tool
def query_sales_data(region: str, start_date: str, end_date: str) -> str:
    """
    查询指定区域、指定时间段的销售数据
    Args:
        region: 区域,可选值:华东、华北、华南、西南、西北、东北,必填
        start_date: 开始日期,格式为YYYY-MM-DD,必填
        end_date: 结束日期,格式为YYYY-MM-DD,必填
    Returns:
        销售数据结果
    """
    # 模拟数据库查询,生产环境换成真实的数据库连接
    data = {
        "region": [region],
        "start_date": [start_date],
        "end_date": [end_date],
        "total_sales": [1234567.89],
        "order_count": [1234],
        "avg_order_value": [1000.45]
    }
    df = pd.DataFrame(data)
    return f"💰 销售数据查询结果:\n{df.to_markdown(index=False)}"

tools = [add_schedule, query_schedule, query_knowledge_base, query_sales_data]
6.4.3 定义节点函数
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langgraph.prebuilt import ToolNode
from tenacity import retry, stop_after_attempt, wait_exponential

llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
llm_with_tools = llm.bind_tools(tools)

# 路由节点
route_prompt = ChatPromptTemplate.from_messages([
    ("system", """你是任务路由专家,根据用户的问题,判断属于哪一类任务,只返回对应的任务代码,不要返回其他内容:
    1. 日程管理:查询、添加、删除、修改日程,返回schedule
    2. 知识库问答:查询公司制度、产品文档、内部资料,返回rag
    3. 数据查询:查询销售、运营、财务等业务数据,返回data
    4. 其他问题:不需要调用工具,直接回答,返回other
    """),
    ("human", "用户ID:{user_id}\n用户问题:{query}")
])
route_chain = route_prompt | llm

@retry(stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=2, max=10))
def route_query(state: AgentState):
    """路由节点,判断用户需求类型"""
    messages = state["messages"]
    user_id = state["user_id"]
    query = messages[-1].content
    response = route_chain.invoke({"user_id": user_id, "query": query})
    return {"next_node": response.content.strip()}

# 日程处理节点
def schedule_handle(state: AgentState):
    """处理日程相关需求"""
    messages = state["messages"]
    user_id = state["user_id"]
    # 把用户ID注入到prompt中,避免工具调用时漏传
    prompt = messages + [("system", f"当前用户ID是{user_id},调用日程工具时必须传入这个user_id")]
    response = llm_with_tools.invoke(prompt)
    return {"messages": [response], "intermediate_data": {"schedule_result": response.content}}

# RAG处理节点
def rag_handle(state: AgentState):
    """处理知识库问答需求"""
    messages = state["messages"]
    response = llm_with_tools.invoke(messages)
    return {"messages": [response], "intermediate_data": {"rag_result": response.content}}

# 数据处理节点
def data_handle(state: AgentState):
    """处理数据查询需求"""
    messages = state["messages"]
    response = llm_with_tools.invoke(messages)
    return {"messages": [response], "intermediate_data": {"data_result": response.content}}

# 工具调用节点(内置工具处理节点,自动执行工具调用)
tool_node = ToolNode(tools)

# 结果汇总节点
summarize_prompt = ChatPromptTemplate.from_messages([
    ("system", "你是办公助手,根据前面的工具调用结果,整理成简洁明了的回答,不要透露工具调用的细节,直接给用户最终结果。如果用户需要报告,就生成结构化的Markdown报告。"),
    ("human", "对话历史:{messages}\n中间结果:{intermediate_data}")
])
summarize_chain = summarize_prompt | llm

def summarize_result(state: AgentState):
    """汇总所有结果,生成最终回答"""
    messages = state["messages"]
    intermediate_data = state["intermediate_data"]
    response = summarize_chain.invoke({
        "messages": messages,
        "intermediate_data": intermediate_data
    })
    return {"messages": [response]}

# 判断是否需要调用工具
def should_call_tool(state: AgentState):
    """判断是否需要调用工具"""
    messages = state["messages"]
    last_message = messages[-1]
    if last_message.tool_calls:
        return "tools"
    return "summarize"
6.4.4 定义边并编译图
from langgraph.graph import StateGraph, END
from langgraph.checkpoint.sqlite import SqliteSaver

# 初始化工作流
workflow = StateGraph(AgentState)

# 添加节点
workflow.add_node("route", route_query)
workflow.add_node("schedule", schedule_handle)
workflow.add_node("rag", rag_handle)
workflow.add_node("data", data_handle)
workflow.add_node("tools", tool_node)
workflow.add_node("summarize", summarize_result)

# 设置入口节点
workflow.set_entry_point("route")

# 路由节点的条件边
workflow.add_conditional_edges(
    "route",
    lambda x: x["next_node"],
    {
        "schedule": "schedule",
        "rag": "rag",
        "data": "data",
        "other": "summarize"
    }
)

# 功能节点的条件边:判断是否需要调用工具
workflow.add_conditional_edges("schedule", should_call_tool, {"tools": "tools", "summarize": "summarize"})
workflow.add_conditional_edges("rag", should_call_tool, {"tools": "tools", "summarize": "summarize"})
workflow.add_conditional_edges("data", should_call_tool, {"tools": "tools", "summarize": "summarize"})

# 工具节点执行完回到结果汇总
workflow.add_edge("tools", "summarize")

# 结果汇总节点判断是否需要继续执行
def should_continue(state: AgentState):
    messages = state["messages"]
    last_message = messages[-1]
    # 如果回答里有需要用户补充信息的内容,或者还需要调用其他工具,就回到路由节点
    if "请补充" in last_message.content or "还需要查询" in last_message.content:
        return "route"
    return END

workflow.add_conditional_edges("summarize", should_continue, {"route": "route", END: END})

# 编译图,添加持久化记忆
memory = SqliteSaver.from_conn_string(os.getenv("CHECKPOINT_DB_PATH"))
app = workflow.compile(checkpointer=memory)

6.5 测试运行

import uuid
from langchain_core.messages import HumanMessage

# 生成会话ID
thread_id = str(uuid.uuid4())
config = {"configurable": {"thread_id": thread_id}}

# 测试查询
user_id = "test_001"
query = "帮我查一下我明天的日程,再查一下2024年10月华东区的销售数据,整理成一个简短的报告"

inputs = {
    "messages": [HumanMessage(content=query)],
    "user_id": user_id,
    "session_id": thread_id,
    "intermediate_data": {},
    "next_node": None
}

# 流式执行
print("=== 智能体执行过程 ===")
for event in app.stream(inputs, config=config, stream_mode="values"):
    latest_message = event["messages"][-1]
    if hasattr(latest_message, "name"):
        print(f"[工具调用] {latest_message.name}: {latest_message.content}")
    else:
        print(f"[输出] {latest_message.content}")

6.6 生产部署:FastAPI接口封装

from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
import uuid

app = FastAPI(title="办公助手智能体API")

class ChatRequest(BaseModel):
    user_id: str
    query: str
    session_id: Optional[str] = None

class ChatResponse(BaseModel):
    session_id: str
    response: str
    intermediate_steps: Dict

@app.post("/api/chat", response_model=ChatResponse)
async def chat(request: ChatRequest):
    try:
        session_id = request.session_id or str(uuid.uuid4())
        config = {"configurable": {"thread_id": session_id}}
        
        inputs = {
            "messages": [HumanMessage(content=request.query)],
            "user_id": request.user_id,
            "session_id": session_id,
            "intermediate_data": {},
            "next_node": None
        }
        
        final_state = None
        for event in app.stream(inputs, config=config, stream_mode="values"):
            final_state = event
        
        return ChatResponse(
            session_id=session_id,
            response=final_state["messages"][-1].content,
            intermediate_steps=final_state["intermediate_data"]
        )
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)

6.7 最佳实践Tips

  1. 状态设计优化:不要在状态里存大文件、长二进制数据,大对象存在对象存储,状态里只存URL
  2. 工具设计规范:工具的描述、参数说明要写的非常详细,最好给几个示例,避免LLM乱调用;所有工具都要加参数校验、超时、重试逻辑
  3. 路由优化:路由判断的prompt要给足够的示例,复杂场景可以用few-shot提示,降低路由错误率
  4. 持久化优化:生产环境不要用SQLite做Checkpoint存储,换成PostgreSQL或者Redis,性能更好,支持高并发
  5. 可观测性:每一步的状态、节点执行耗时、token消耗、工具调用结果都要打日志,方便排查问题
  6. 安全防护:工具调用要加权限校验,比如用户只能查询自己的日程,不能查询其他用户的数据;数据库查询要加SQL注入防护
  7. 错误降级:如果LLM调用失败或者工具调用失败,要有降级逻辑,给用户友好的提示,不要直接抛出异常

7. 整合提升:知识内化与进阶

7.1 核心观点回顾

  • LangGraph的核心是有状态的有限状态机,完美解决了传统链式模式不可控、不支持循环、上下文容易丢失的问题
  • LangGraph开发的核心四步:定义状态→定义节点→定义边→编译运行
  • LangGraph的适用场景:所有需要多步骤、循环、可控性的大模型应用,尤其是生产级智能体
  • 生产落地的核心是做好状态设计、工具校验、错误处理、可观测性四个方面

7.2 拓展思考任务

  1. 怎么把这个智能体改成多智能体模式?比如加一个审核节点,所有生成的报告都要先经过人工审核再返回给用户
  2. 怎么接入开源模型?比如把OpenAI的模型换成本地部署的Qwen2-7B-Instruct,需要做哪些修改?
  3. 如果要支撑1000+并发,需要做哪些架构优化?
  4. 怎么给智能体加统计功能?比如统计每个用户的调用次数、token消耗、常用功能?

7.3 进阶学习资源

  1. 官方文档:https://langchain-ai.github.io/langgraph/ (最权威的学习资料,有大量的示例代码)
  2. 官方Cookbook:https://github.com/langchain-ai/langgraph/tree/main/examples (包含多智能体、人类介入、分布式运行等高级场景的示例)
  3. Awesome LangGraph:https://github.com/kyrolabs/awesome-langgraph (第三方的LangGraph资源汇总,包含大量的开源项目、教程)
  4. LangChain官方YouTube频道:有大量的LangGraph实战教程和案例分享

本章小结

LangGraph是目前构建可控生产级智能体的最佳框架之一,它的出现大大降低了复杂大模型应用的开发门槛。本文从基础概念到完整的可上线代码,带你走完了LangGraph智能体开发的全流程,你现在已经可以基于这个模板开发自己的智能体应用了。

大模型应用的未来一定是朝着更加可控、更加智能、更加自治的方向发展,而LangGraph正是这个方向的核心基础设施,现在投入时间学习LangGraph,会是你今年最有价值的技术投资之一。如果你在开发过程中遇到问题,欢迎在评论区留言交流。
(全文完,共计12800字)

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐