LangChain + LangGraph AI应用开发完全教程

教程简介

零基础LangChain + LangGraph AI应用开发完全教程,涵盖LangChain核心架构、Chain构建、Agent智能体、Tool工具系统、Memory记忆管理、LangGraph状态图编排、多Agent协作、RAG集成、流式输出、生产部署等核心技能,配有完整智能客服系统实战项目,适合AI开发者系统学习。

LangChain + LangGraph AI 应用开发完全教程

从零基础到生产部署,一站式掌握 LangChain 与 LangGraph 的核心能力


目录

  1. LangChain 概述与安装
  2. 核心概念总览
  3. LLM 与 ChatModel 使用
  4. Prompt Template 与 Few-shot
  5. Output Parser 输出解析
  6. Chain 链式调用
  7. Agent 智能体
  8. Tool 工具系统开发
  9. Memory 记忆管理
  10. LangGraph 核心概念与 StateGraph
  11. LangGraph 节点与边的定义
  12. 多 Agent 协作模式
  13. RAG 集成实战
  14. 流式输出处理
  15. 生产部署最佳实践
  16. 实战项目:智能客服系统

1. LangChain 概述与安装

1.1 什么是 LangChain

LangChain 是一个用于构建大语言模型(LLM)应用的开源框架。它提供了一套标准化的抽象层,让开发者可以轻松地将 LLM 与外部数据源、工具和工作流进行集成。其核心价值在于:

  • 模块化设计:每个组件可独立使用,也可灵活组合
  • 生态丰富:支持数百种模型、向量数据库和工具的集成
  • 生产就绪:内置链路追踪、错误处理和可观测性支持

1.2 安装与环境配置

# 创建虚拟环境
python -m venv langchain-env
source langchain-env/bin/activate  # Linux/Mac
# langchain-env\Scripts\activate   # Windows

# 安装核心包
pip install langchain langchain-core langchain-community

# 安装特定模型提供者(按需选择)
pip install langchain-openai        # OpenAI
pip install langchain-anthropic     # Anthropic
pip install langchain-ollama        # 本地 Ollama

# 安装 LangGraph
pip install langgraph

# 安装常用工具包
pip install langchainhub chromadb   # 向量数据库
pip install tavily-python           # 搜索工具

1.3 环境变量设置

import os

# 推荐使用 .env 文件管理密钥
# pip install python-dotenv
from dotenv import load_dotenv
load_dotenv()

# 或直接设置
os.environ["OPENAI_API_KEY"] = "your-api-key-here"
os.environ["TAVILY_API_KEY"] = "your-tavily-key"

⚠️ 安全提示:永远不要将 API Key 硬编码在代码中,使用环境变量或密钥管理服务。


2. 核心概念总览

LangChain 的架构围绕四大核心概念构建:

┌─────────────────────────────────────────────────┐
│                  LangChain 生态                   │
├──────────┬──────────┬──────────┬─────────────────┤
│ Model I/O│  Chains  │  Agents  │     Memory      │
│ 模型输入输出 │  链式调用  │  智能体   │     记忆管理    │
├──────────┴──────────┴──────────┴─────────────────┤
│              Tools & Retrieval                    │
│              工具系统与检索                         │
├─────────────────────────────────────────────────┤
│              LangGraph(编排层)                   │
└─────────────────────────────────────────────────┘
  • Model I/O:标准化的模型输入(Prompt)→ 模型调用(LLM)→ 输出解析(Parser)流程
  • Chains:将多个组件串联成可复用的工作流
  • Agents:让 LLM 自主决策使用哪些工具、按什么顺序执行
  • Memory:为无状态的 LLM 添加上下文记忆能力

3. LLM 与 ChatModel 使用

LangChain 提供两种模型接口:LLM(文本补全)和 ChatModel(对话补全)。

3.1 ChatModel 基础使用

from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage, SystemMessage, AIMessage

# 初始化模型
llm = ChatOpenAI(
    model="gpt-4o-mini",
    temperature=0.7,      # 控制随机性,0-2
    max_tokens=1024,      # 最大输出 token 数
    timeout=30,           # 请求超时(秒)
)

# 方式一:直接调用
response = llm.invoke("什么是量子计算?")
print(response.content)

# 方式二:使用消息列表(推荐)
messages = [
    SystemMessage(content="你是一位物理学教授,用通俗语言解释概念。"),
    HumanMessage(content="什么是量子纠缠?"),
]
response = llm.invoke(messages)
print(response.content)

3.2 使用本地模型(Ollama)

from langchain_ollama import ChatOllama

llm = ChatOllama(
    model="qwen2.5:7b",   # Ollama 已下载的模型
    temperature=0.7,
)

response = llm.invoke("用Python写一个快速排序")
print(response.content)

3.3 模型参数调优

# 使用 with_structured_output 约束输出格式
from pydantic import BaseModel, Field

class MovieReview(BaseModel):
    title: str = Field(description="电影名称")
    rating: float = Field(description="评分,1-10")
    summary: str = Field(description="一句话总结")
    recommend: bool = Field(description="是否推荐")

structured_llm = llm.with_structured_output(MovieReview)
review = structured_llm.invoke("评价一下《盗梦空间》这部电影")
print(review.title)    # 盗梦空间
print(review.rating)   # 9.0

4. Prompt Template 与 Few-shot

4.1 基础 Prompt Template

from langchain_core.prompts import ChatPromptTemplate

# 简单模板
prompt = ChatPromptTemplate.from_template(
    "请将以下文本翻译成{language}:\n\n{text}"
)
formatted = prompt.invoke({"language": "法语", "text": "你好世界"})
print(formatted)

4.2 多角色对话模板

prompt = ChatPromptTemplate.from_messages([
    ("system", "你是一位{role},擅长用{style}的方式回答问题。"),
    ("human", "{question}"),
])

chain = prompt | llm
result = chain.invoke({
    "role": "Python 教师",
    "style": "幽默风趣",
    "question": "装饰器是什么?"
})
print(result.content)

4.3 Few-shot 提示

from langchain_core.prompts import FewShotChatMessagePromptTemplate

examples = [
    {"input": "今天天气真好", "output": "正面"},
    {"input": "这个产品太差了", "output": "负面"},
    {"input": "一般般吧", "output": "中性"},
    {"input": "服务态度非常棒!", "output": "正面"},
]

example_prompt = ChatPromptTemplate.from_messages([
    ("human", "{input}"),
    ("ai", "{output}"),
])

few_shot_prompt = FewShotChatMessagePromptTemplate(
    example_prompt=example_prompt,
    examples=examples,
)

final_prompt = ChatPromptTemplate.from_messages([
    ("system", "你是情感分析专家,判断文本情感:正面、负面或中性。"),
    few_shot_prompt,
    ("human", "{input}"),
])

chain = final_prompt | llm
result = chain.invoke({"input": "这家餐厅的菜品很一般,但服务不错"})
print(result.content)  # 中性

5. Output Parser 输出解析

5.1 StrOutputParser(最常用)

from langchain_core.output_parsers import StrOutputParser

chain = prompt | llm | StrOutputParser()
result = chain.invoke({"input": "你好"})
# result 直接是字符串,而非 AIMessage

5.2 JsonOutputParser

from langchain_core.output_parsers import JsonOutputParser

parser = JsonOutputParser(pydantic_object=MovieReview)

prompt = ChatPromptTemplate.from_messages([
    ("system", "你是影评专家。{format_instructions}"),
    ("human", "评价电影:{movie}"),
])

chain = prompt.partial(format_instructions=parser.get_format_instructions()) | llm | parser
result = chain.invoke({"movie": "星际穿越"})
print(type(result))  # <class 'dict'>

5.3 自定义输出解析器

from langchain_core.output_parsers import BaseOutputParser

class CommaSeparatedParser(BaseOutputParser):
    """将输出解析为逗号分隔的列表"""

    def parse(self, text: str) -> list[str]:
        return [item.strip() for item in text.strip().split(",")]

    @property
    def _type(self) -> str:
        return "comma_separated"

prompt = ChatPromptTemplate.from_template(
    "列出5种{category},用逗号分隔,不要编号:"
)

chain = prompt | llm | CommaSeparatedParser()
result = chain.invoke({"category": "编程语言"})
print(result)  # ['Python', 'JavaScript', 'Java', 'Go', 'Rust']

6. Chain 链式调用

6.1 LLMChain(基础链)

from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
from langchain_core.output_parsers import StrOutputParser

prompt = ChatPromptTemplate.from_template("用一句话解释:{concept}")
llm = ChatOpenAI(model="gpt-4o-mini")

# 使用 LCEL(LangChain Expression Language)管道语法
chain = prompt | llm | StrOutputParser()

result = chain.invoke({"concept": "微服务架构"})
print(result)

6.2 SequentialChain(顺序链)

# 场景:先生成文章大纲,再根据大纲撰写正文

outline_prompt = ChatPromptTemplate.from_template(
    "请为以下主题生成一个5点的文章大纲:\n主题:{topic}"
)

write_prompt = ChatPromptTemplate.from_template(
    "根据以下大纲,撰写一篇500字的文章:\n大纲:{outline}"
)

# 方式一:使用 RunnablePassthrough 传递中间结果
from langchain_core.runnables import RunnablePassthrough

chain = (
    {"outline": outline_prompt | llm | StrOutputParser()}
    | RunnablePassthrough.assign(
        article=lambda x: (write_prompt | llm | StrOutputParser()).invoke(
            {"outline": x["outline"]}
        )
    )
)

result = chain.invoke({"topic": "人工智能在医疗领域的应用"})
print("大纲:", result["outline"])
print("文章:", result["article"])

6.3 并行执行与分支

from langchain_core.runnables import RunnableParallel

# 同时生成英文和中文版本
en_prompt = ChatPromptTemplate.from_template("Translate to English: {text}")
zh_prompt = ChatPromptTemplate.from_template("翻译成中文:{text}")

parallel_chain = RunnableParallel(
    english=en_prompt | llm | StrOutputParser(),
    chinese=zh_prompt | llm | StrOutputParser(),
)

result = parallel_chain.invoke({"text": "天道酬勤"})
print(result["english"])  # Heaven rewards diligence
print(result["chinese"])  # 天道酬勤

7. Agent 智能体

7.1 ReAct Agent

ReAct(Reasoning + Acting)是最经典的 Agent 模式:LLM 先推理(Thought),再行动(Action),观察结果(Observation),循环直到完成任务。

from langchain_openai import ChatOpenAI
from langchain.agents import AgentExecutor, create_react_agent
from langchain_core.tools import tool
from langchain_core.prompts import PromptTemplate

@tool
def search_weather(city: str) -> str:
    """查询指定城市的天气信息"""
    # 实际项目中接入天气 API
    weather_data = {"北京": "晴,25°C", "上海": "多云,22°C"}
    return weather_data.get(city, f"未找到{city}的天气数据")

@tool
def calculate(expression: str) -> str:
    """计算数学表达式"""
    try:
        result = eval(expression)
        return str(result)
    except Exception as e:
        return f"计算错误: {e}"

llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)

react_prompt = PromptTemplate.from_template("""
Answer the following questions as best you can. You have access to the following tools:

{tools}

Use the following format:

Question: the input question
Thought: reasoning about what to do
Action: the action to take, should be one of [{tool_names}]
Action Input: the input to the action
Observation: the result of the action
... (this Thought/Action/Action Input/Observation can repeat N times)
Thought: I now know the final answer
Final Answer: the final answer to the original input question

Begin!

Question: {input}
Thought:{agent_scratchpad}
""")

agent = create_react_agent(llm, [search_weather, calculate], react_prompt)
agent_executor = AgentExecutor(agent=agent, tools=[search_weather, calculate], verbose=True)

result = agent_executor.invoke({"input": "北京今天多少度?如果升温5度是多少?"})
print(result["output"])

7.2 使用 LangGraph 构建现代 Agent

LangGraph 是 LangChain 团队推出的图编排框架,比传统 AgentExecutor 更灵活:

from langgraph.prebuilt import create_react_agent

llm = ChatOpenAI(model="gpt-4o-mini")

# 一行代码创建 ReAct Agent
agent = create_react_agent(llm, tools=[search_weather, calculate])

result = agent.invoke({"messages": [("human", "北京天气怎么样?")]})
for msg in result["messages"]:
    print(f"{msg.type}: {msg.content}")

8. Tool 工具系统开发

8.1 使用 @tool 装饰器

from langchain_core.tools import tool
from typing import Optional

@tool
def get_stock_price(symbol: str, market: str = "A股") -> str:
    """获取股票的当前价格。

    Args:
        symbol: 股票代码,如 '600519'
        market: 市场类型,A股或美股
    """
    # 模拟数据
    prices = {"600519": 1800.00, "AAPL": 195.50}
    price = prices.get(symbol, "未知")
    return f"{symbol} 当前价格:{price}"

@tool
def send_notification(
    recipient: str,
    message: str,
    priority: Optional[str] = "normal"
) -> str:
    """发送通知消息给指定用户。

    Args:
        recipient: 接收者ID或邮箱
        message: 通知内容
        priority: 优先级,可选 low/normal/high
    """
    return f"已发送 [{priority}] 通知给 {recipient}: {message}"

8.2 StructuredTool(高级定义)

from langchain_core.tools import StructuredTool
from pydantic import BaseModel, Field

class SearchInput(BaseModel):
    query: str = Field(description="搜索关键词")
    max_results: int = Field(default=5, description="最大返回结果数")
    language: str = Field(default="zh", description="搜索语言")

def search_web(query: str, max_results: int = 5, language: str = "zh") -> str:
    """模拟网络搜索"""
    return f"找到 {max_results} 条关于 '{query}' 的结果"

search_tool = StructuredTool.from_function(
    func=search_web,
    name="web_search",
    description="在互联网上搜索信息",
    args_schema=SearchInput,
)

8.3 工具包(Toolkit)

from langchain_core.tools import BaseTool

class MathToolkit:
    """数学计算工具集"""

    def get_tools(self) -> list[BaseTool]:
        return [
            tool(self.add),
            tool(self.multiply),
            tool(self.power),
        ]

    def add(self, a: float, b: float) -> float:
        """两数相加"""
        return a + b

    def multiply(self, a: float, b: float) -> float:
        """两数相乘"""
        return a * b

    def power(self, base: float, exponent: float) -> float:
        """幂运算"""
        return base ** exponent

9. Memory 记忆管理

9.1 ConversationBufferMemory(完整记忆)

from langchain.memory import ConversationBufferMemory
from langchain_openai import ChatOpenAI
from langchain.chains import ConversationChain

memory = ConversationBufferMemory(return_messages=True)

llm = ChatOpenAI(model="gpt-4o-mini")
conversation = ConversationChain(
    llm=llm,
    memory=memory,
    verbose=True,
)

# 多轮对话
conversation.invoke({"input": "我叫张三"})
conversation.invoke({"input": "我是一名程序员"})
conversation.invoke({"input": "你还记得我的名字和职业吗?"})
# 模型会记住之前的信息

9.2 ConversationSummaryMemory(摘要记忆)

from langchain.memory import ConversationSummaryMemory

# 当对话很长时,自动压缩为摘要
memory = ConversationSummaryMemory(
    llm=ChatOpenAI(model="gpt-4o-mini"),
    return_messages=True,
)

conversation = ConversationChain(llm=llm, memory=memory)
# 适合长对话场景,自动管理 token 用量

9.3 在 LangGraph 中管理状态

from langgraph.graph import StateGraph, MessagesState, START, END
from langgraph.prebuilt import ToolNode

# MessagesState 内置了 messages 列表,天然支持对话记忆
def agent_node(state: MessagesState):
    response = llm.invoke(state["messages"])
    return {"messages": [response]}

graph = StateGraph(MessagesState)
graph.add_node("agent", agent_node)
graph.add_edge(START, "agent")
graph.add_edge("agent", END)

app = graph.compile()

# 每次调用都传入完整的历史消息
result = app.invoke({"messages": [("human", "你好")]})

10. LangGraph 核心概念与 StateGraph

10.1 什么是 LangGraph

LangGraph 是基于图的 AI 应用编排框架。与传统的线性 Chain 不同,它允许你构建:

  • 有环图:支持循环和条件分支
  • 有状态的工作流:自动管理状态传递
  • 人机协作:支持 Human-in-the-Loop
  • 持久化:支持检查点和断点续传

10.2 StateGraph 基础

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

# 定义状态结构
class WorkflowState(TypedDict):
    # 使用 Annotated 和 operator.add 实现"追加"而非"覆盖"
    messages: Annotated[list, operator.add]
    step_count: int
    status: str

# 创建图
graph = StateGraph(WorkflowState)

# 定义节点函数
def step_one(state: WorkflowState) -> dict:
    return {
        "messages": ["步骤1完成"],
        "step_count": state["step_count"] + 1,
    }

def step_two(state: WorkflowState) -> dict:
    return {
        "messages": ["步骤2完成"],
        "step_count": state["step_count"] + 1,
        "status": "done",
    }

# 添加节点和边
graph.add_node("step_one", step_one)
graph.add_node("step_two", step_two)
graph.add_edge(START, "step_one")
graph.add_edge("step_one", "step_two")
graph.add_edge("step_two", END)

# 编译并运行
app = graph.compile()
result = app.invoke({"messages": [], "step_count": 0, "status": "pending"})
print(result)
# {'messages': ['步骤1完成', '步骤2完成'], 'step_count': 2, 'status': 'done'}

11. LangGraph 节点与边的定义

11.1 条件边(Conditional Edges)

def should_continue(state: WorkflowState) -> str:
    """根据状态决定下一步"""
    if state["step_count"] >= 3:
        return "finish"
    return "continue"

def process_step(state: WorkflowState) -> dict:
    return {"step_count": state["step_count"] + 1, "messages": [f"处理第{state['step_count']+1}步"]}

def finish_node(state: WorkflowState) -> dict:
    return {"status": "completed", "messages": ["全部完成!"]}

graph = StateGraph(WorkflowState)
graph.add_node("process", process_step)
graph.add_node("finish", finish_node)

graph.add_edge(START, "process")
# 条件边:根据返回值跳转到不同节点
graph.add_conditional_edges(
    "process",
    should_continue,
    {"continue": "process", "finish": "finish"},
)
graph.add_edge("finish", END)

app = graph.compile()
result = app.invoke({"messages": [], "step_count": 0, "status": "pending"})

11.2 带工具调用的 Agent 图

from langgraph.prebuilt import ToolNode
from langchain_core.messages import HumanMessage

@tool
def lookup_database(query: str) -> str:
    """查询数据库获取信息"""
    return f"数据库查询结果:关于'{query}'的数据"

tools = [lookup_database]
tool_node = ToolNode(tools)

def agent(state: MessagesState):
    response = llm.bind_tools(tools).invoke(state["messages"])
    return {"messages": [response]}

def should_use_tool(state: MessagesState):
    last_msg = state["messages"][-1]
    if hasattr(last_msg, "tool_calls") and last_msg.tool_calls:
        return "tools"
    return "end"

graph = StateGraph(MessagesState)
graph.add_node("agent", agent)
graph.add_node("tools", tool_node)

graph.add_edge(START, "agent")
graph.add_conditional_edges("agent", should_use_tool, {"tools": "tools", "end": END})
graph.add_edge("tools", "agent")  # 工具执行完后回到 agent

app = graph.compile()
result = app.invoke({"messages": [HumanMessage(content="查询今天的销售数据")]})

12. 多 Agent 协作模式

12.1 Supervisor 模式

from typing import Literal

# 定义各专家 Agent
def researcher_agent(state: MessagesState):
    """研究员:负责信息收集"""
    prompt = "你是研究员,负责收集和整理信息。"
    response = llm.invoke([("system", prompt)] + state["messages"])
    return {"messages": [response]}

def writer_agent(state: MessagesState):
    """撰稿人:负责内容撰写"""
    prompt = "你是撰稿人,根据提供的素材撰写文章。"
    response = llm.invoke([("system", prompt)] + state["messages"])
    return {"messages": [response]}

def supervisor_agent(state: MessagesState) -> dict:
    """主管:决定下一步由谁执行"""
    prompt = """你是项目主管。根据当前进展,决定下一步:
    - 如果需要更多信息,选择 'researcher'
    - 如果信息足够可以撰写,选择 'writer'
    - 如果任务完成,选择 'FINISH'
    """
    response = llm.invoke([("system", prompt)] + state["messages"])
    # 解析响应决定路由
    content = response.content.lower()
    if "writer" in content:
        next_step = "writer"
    elif "finish" in content:
        next_step = "FINISH"
    else:
        next_step = "researcher"
    return {"next": next_step, "messages": [response]}

# 构建 Supervisor 图
from typing import TypedDict

class SupervisorState(TypedDict):
    messages: Annotated[list, operator.add]
    next: str

graph = StateGraph(SupervisorState)
graph.add_node("supervisor", supervisor_agent)
graph.add_node("researcher", researcher_agent)
graph.add_node("writer", writer_agent)

graph.add_edge(START, "supervisor")
graph.add_conditional_edges(
    "supervisor",
    lambda x: x["next"],
    {"researcher": "researcher", "writer": "writer", "FINISH": END},
)
graph.add_edge("researcher", "supervisor")
graph.add_edge("writer", "supervisor")

app = graph.compile()

12.2 并行 Agent 执行

from langgraph.graph import StateGraph

def parallel_agents(state: dict):
    """多个 Agent 并行处理不同子任务"""
    # 可以使用 asyncio.gather 并行调用多个 Agent
    import asyncio

    async def run_agents():
        tasks = [
            agent_ainvoke(state, "agent_a"),
            agent_ainvoke(state, "agent_b"),
        ]
        return await asyncio.gather(*tasks)

    results = asyncio.run(run_agents())
    return {"results": results}

13. RAG 集成实战

13.1 基础 RAG 链

from langchain_community.document_loaders import TextLoader, DirectoryLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_openai import OpenAIEmbeddings
from langchain_community.vectorstores import Chroma
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough

# 1. 加载文档
loader = DirectoryLoader("./docs", glob="**/*.txt", loader_cls=TextLoader)
documents = loader.load()

# 2. 分割文档
splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=50)
chunks = splitter.split_documents(documents)

# 3. 创建向量数据库
embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
vectorstore = Chroma.from_documents(chunks, embeddings, persist_directory="./chroma_db")
retriever = vectorstore.as_retriever(search_kwargs={"k": 4})

# 4. 构建 RAG 链
rag_prompt = ChatPromptTemplate.from_template("""
基于以下上下文回答问题。如果上下文中没有相关信息,请说明你不确定。

上下文:
{context}

问题:{question}
""")

def format_docs(docs):
    return "\n\n".join(doc.page_content for doc in docs)

rag_chain = (
    {"context": retriever | format_docs, "question": RunnablePassthrough()}
    | rag_prompt
    | llm
    | StrOutputParser()
)

result = rag_chain.invoke("公司的请假制度是什么?")
print(result)

14. 流式输出处理

14.1 基础流式输出

# 方法一:stream 方法
chain = prompt | llm | StrOutputParser()

for chunk in chain.stream({"concept": "人工智能"}):
    print(chunk, end="", flush=True)

14.2 在 LangGraph 中流式输出

# 流式输出 Agent 的思考过程
app = graph.compile()

for event in app.stream({"messages": [("human", "分析今天的市场走势")]},
                         stream_mode="updates"):
    for node, output in event.items():
        print(f"[{node}]", output)
        print("---")

14.3 异步流式

import asyncio

async def stream_response():
    async for chunk in chain.astream({"concept": "量子计算"}):
        print(chunk, end="", flush=True)

asyncio.run(stream_response())

15. 生产部署最佳实践

15.1 错误处理与重试

from langchain_core.runnables import RunnableLambda
import time

def robust_llm_call(inputs):
    """带重试的 LLM 调用"""
    max_retries = 3
    for attempt in range(max_retries):
        try:
            return llm.invoke(inputs)
        except Exception as e:
            if attempt < max_retries - 1:
                wait_time = 2 ** attempt
                print(f"重试 {attempt + 1}/{max_retries},等待 {wait_time}s: {e}")
                time.sleep(wait_time)
            else:
                raise

robust_chain = prompt | RunnableLambda(robust_llm_call) | StrOutputParser()

15.2 链路追踪(LangSmith)

import os

# 配置 LangSmith
os.environ["LANGCHAIN_TRACING_V2"] = "true"
os.environ["LANGCHAIN_API_KEY"] = "your-langsmith-key"
os.environ["LANGCHAIN_PROJECT"] = "my-project"

# 所有调用自动上报到 LangSmith 平台
# 可以在 https://smith.langchain.com 查看调用链路

15.3 缓存优化

from langchain_core.globals import set_llm_cache
from langchain_community.cache import SQLiteCache

# 启用语义缓存,避免重复调用
set_llm_cache(SQLiteCache(database_path=".langchain.db"))

# 相同的输入会直接返回缓存结果
result1 = llm.invoke("什么是机器学习?")  # 实际调用
result2 = llm.invoke("什么是机器学习?")  # 从缓存返回

16. 实战项目:智能客服系统

下面我们构建一个完整的智能客服系统,整合本教程所学的所有核心概念。

16.1 系统架构

用户消息 → 意图识别 → 路由分发
                        ├── 订单查询 Agent(调用数据库工具)
                        ├── 产品咨询 Agent(RAG 检索产品文档)
                        ├── 投诉处理 Agent(需人工确认)
                        └── 通用问答 Agent

16.2 完整实现

"""智能客服系统 - 基于 LangGraph 的多 Agent 架构"""
from typing import TypedDict, Annotated, Literal
from langgraph.graph import StateGraph, START, END, MessagesState
from langgraph.prebuilt import ToolNode
from langgraph.checkpoint.memory import MemorySaver
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage, SystemMessage, AIMessage
from langchain_core.tools import tool
import operator

# ==================== 1. 定义工具 ====================

@tool
def query_order(order_id: str) -> str:
    """根据订单号查询订单状态和详情"""
    # 模拟数据库查询
    orders = {
        "ORD001": {"status": "已发货", "tracking": "SF1234567890", "items": "iPhone 15"},
        "ORD002": {"status": "待付款", "amount": "5999元", "items": "MacBook Air"},
        "ORD003": {"status": "已完成", "items": "AirPods Pro"},
    }
    order = orders.get(order_id)
    if order:
        return f"订单 {order_id}: {order}"
    return f"未找到订单 {order_id},请确认订单号是否正确"

@tool
def search_product_info(query: str) -> str:
    """搜索产品信息和常见问题"""
    # 实际项目中对接 RAG 系统
    docs = {
        "退换货": "退换货政策:7天无理由退换,15天质量问题换货。请保留原始包装。",
        "保修": "所有产品享受1年质保,Apple Care+可延长至2年。",
        "配送": "标准配送3-5个工作日,加急配送次日达(需额外收费)。",
    }
    for key, value in docs.items():
        if key in query:
            return value
    return f"未找到关于'{query}'的产品信息"

@tool
def escalate_to_human(reason: str) -> str:
    """将对话升级给人工客服"""
    return f"已转接人工客服。原因:{reason}。请稍候,客服代表将很快接入。"

# ==================== 2. 定义状态 ====================

class CustomerServiceState(TypedDict):
    messages: Annotated[list, operator.add]
    intent: str
    requires_human: bool
    conversation_id: str

# ==================== 3. 定义节点 ====================

llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)

def classify_intent(state: CustomerServiceState) -> dict:
    """意图识别节点"""
    last_msg = state["messages"][-1].content

    classification_prompt = f"""分析用户消息的意图,返回以下类别之一:
    - order_query: 查询订单状态、物流信息
    - product_info: 产品咨询、退换货、保修
    - complaint: 投诉、不满、要求赔偿
    - general: 一般问候、闲聊、其他

    用户消息:{last_msg}
    意图:"""

    response = llm.invoke([HumanMessage(content=classification_prompt)])
    intent = response.content.strip().lower()

    # 标准化意图
    for valid_intent in ["order_query", "product_info", "complaint", "general"]:
        if valid_intent in intent:
            intent = valid_intent
            break
    else:
        intent = "general"

    return {"intent": intent}

def route_intent(state: CustomerServiceState) -> str:
    """路由分发"""
    intent = state.get("intent", "general")
    if intent == "order_query":
        return "order_agent"
    elif intent == "product_info":
        return "product_agent"
    elif intent == "complaint":
        return "complaint_agent"
    return "general_agent"

def order_agent(state: CustomerServiceState) -> dict:
    """订单查询 Agent"""
    system = SystemMessage(content="""你是订单查询专员。帮助用户查询订单状态。
    使用 query_order 工具查询订单。如果用户没提供订单号,请礼貌询问。""")

    tools = [query_order]
    agent = create_react_agent(llm, tools)
    result = agent.invoke({"messages": [system] + state["messages"]})

    return {"messages": [AIMessage(content=result["messages"][-1].content)]}

def product_agent(state: CustomerServiceState) -> dict:
    """产品咨询 Agent"""
    system = SystemMessage(content="""你是产品顾问。回答用户关于产品的问题。
    使用 search_product_info 工具搜索相关信息。""")

    tools = [search_product_info]
    agent = create_react_agent(llm, tools)
    result = agent.invoke({"messages": [system] + state["messages"]})

    return {"messages": [AIMessage(content=result["messages"][-1].content)]}

def complaint_agent(state: CustomerServiceState) -> dict:
    """投诉处理 Agent"""
    system = SystemMessage(content="""你是投诉处理专员。
    1. 先表达歉意和理解
    2. 了解具体问题
    3. 提供解决方案
    4. 如果用户情绪激动或要求赔偿,使用 escalate_to_human 转人工""")

    tools = [escalate_to_human]
    agent = create_react_agent(llm, tools)
    result = agent.invoke({"messages": [system] + state["messages"]})

    return {"messages": [AIMessage(content=result["messages"][-1].content)]}

def general_agent(state: CustomerServiceState) -> dict:
    """通用问答 Agent"""
    system = SystemMessage(content="你是一位友好的客服助手,回答用户的一般性问题。")
    response = llm.invoke([system] + state["messages"])
    return {"messages": [response]}

# ==================== 4. 构建图 ====================

graph = StateGraph(CustomerServiceState)

# 添加节点
graph.add_node("classify", classify_intent)
graph.add_node("order_agent", order_agent)
graph.add_node("product_agent", product_agent)
graph.add_node("complaint_agent", complaint_agent)
graph.add_node("general_agent", general_agent)

# 添加边
graph.add_edge(START, "classify")
graph.add_conditional_edges("classify", route_intent, {
    "order_agent": "order_agent",
    "product_agent": "product_agent",
    "complaint_agent": "complaint_agent",
    "general_agent": "general_agent",
})
graph.add_edge("order_agent", END)
graph.add_edge("product_agent", END)
graph.add_edge("complaint_agent", END)
graph.add_edge("general_agent", END)

# 使用 Memory 实现多轮对话
memory = MemorySaver()
app = graph.compile(checkpointer=memory)

# ==================== 5. 运行系统 ====================

def chat(user_input: str, thread_id: str = "session-001"):
    """客服对话入口"""
    config = {"configurable": {"thread_id": thread_id}}

    result = app.invoke(
        {
            "messages": [HumanMessage(content=user_input)],
            "intent": "",
            "requires_human": False,
            "conversation_id": thread_id,
        },
        config=config,
    )

    return result["messages"][-1].content

# 测试对话
print("=== 订单查询 ===")
print(chat("我想查一下订单 ORD001 的状态"))

print("\n=== 产品咨询 ===")
print(chat("你们的退换货政策是什么?"))

print("\n=== 投诉处理 ===")
print(chat("我的手机屏幕碎了,你们质量太差了!我要投诉!"))

print("\n=== 多轮对话 ===")
print(chat("刚才说的订单 ORD001 大概什么时候到?", thread_id="session-001"))

16.3 部署为 API 服务

"""使用 FastAPI 部署客服系统"""
from fastapi import FastAPI
from pydantic import BaseModel
import uvicorn

app_fastapi = FastAPI(title="智能客服 API")

class ChatRequest(BaseModel):
    message: str
    session_id: str = "default"

class ChatResponse(BaseModel):
    reply: str
    intent: str
    session_id: str

@app_fastapi.post("/chat", response_model=ChatResponse)
async def chat_endpoint(request: ChatRequest):
    result = app.invoke(
        {
            "messages": [HumanMessage(content=request.message)],
            "intent": "",
            "requires_human": False,
            "conversation_id": request.session_id,
        },
        config={"configurable": {"thread_id": request.session_id}},
    )

    return ChatResponse(
        reply=result["messages"][-1].content,
        intent=result.get("intent", "unknown"),
        session_id=request.session_id,
    )

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

总结

本教程从基础到实战,系统性地介绍了 LangChain 和 LangGraph 的核心能力:

模块 核心能力 适用场景
Prompt Template 标准化提示词管理 所有 LLM 应用
Chain 线性工作流 简单的多步处理
Agent 自主决策与工具调用 复杂的动态任务
Memory 对话上下文管理 多轮对话场景
LangGraph 图编排与状态管理 复杂工作流、多 Agent 协作

下一步学习建议:

  1. 阅读 LangChain 官方文档 深入了解更多组件
  2. 探索 LangGraph 官方教程 学习高级模式
  3. 使用 LangSmith 进行链路追踪和调试
  4. 结合 RAG 构建知识增强型应用(参见本系列 RAG 教程)

📅 最后更新:2026年5月 | 📝 适用版本:LangChain ≥ 0.3、LangGraph ≥ 0.2

内容声明

本文内容为AI技术学习教程,仅供学习参考。如涉及技术问题,欢迎通过 xurj005@163.com 与我们交流。

目录