LangChain 框架功能详解和使用案例
LangChain 提供了一套模块化的工具和抽象,使开发者能够将 LLM 与外部数据源、记忆机制、工具调用和逻辑控制流结合起来,从而构建可扩展、可维护、具有上下文感知能力的智能应用,比如聊天机器人、问答系统、文档摘要器、自动化代理(Agents)等。
| 场景 | 使用的 LangChain 组件 |
|---|---|
| 智能客服 | Memory + Chain + LLM |
| 知识库问答 | Retrieval + RAG + Vector DB |
| 自动化办公助理 | Agents + Tools(如 Gmail、Excel、API) |
| 代码生成助手 | LLM + Prompt + OutputParser |
| 多轮推理任务 | Agents + Plan-and-execute |
LangChain 的架构围绕以下几个核心概念展开:
模型管理(LLM)
支持多种 LLM 提供商(如 OpenAI、qWen、Hugging Face、Google、Ollama 等)。
提供统一接口调用不同模型:
LLM(文本生成):
ChatOpenAI,ChatTongyi(Qwen),ChatOllama,ChatAnthropicEmbedding(向量化):
OpenAIEmbeddings,DashScopeEmbeddings(Qwen),OllamaEmbeddings多模态模型:
ChatGoogleVertexAI(支持图像+文本)
Ollama
1 | from langchain_ollama import OllamaEmbeddings, ChatOllama |
OpenAI
1 | from langchain_openai import ChatOpenAI, OpenAIEmbeddings |
千问
1 | from langchain_community.chat_models import ChatTongyi |
提示工程(Prompt)
构建和管理提示词模板,支持动态填充、少量示例(few-shot)等。
PromptTemplate:传统字符串模板
ChatPromptTemplate:支持多轮对话消息(System/Human/AI)
FewShotPromptTemplate:带示例的提示
MessagesPlaceholder:用于 Agent 中的动态消息插槽
1 | from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder |
1 | from langchain_core.prompts import PromptTemplate |
链式编排(Chain)
将多个组件串联成流水线。
LLMChain:Prompt + LLM
SequentialChain:多步骤顺序执行
RetrievalQA:RAG 问答链
ConversationalRetrievalChain:带记忆的 RAG
自定义 Chain:通过
RunnableSequence或RunnableLambda
1 | from langchain.chains import RetrievalQA |
直接手动构建链
1 | from langchain_community.chat_models import ChatTongyi |
智能决策(Agents)
让 LLM 自主调用工具(如搜索、数据库、API)。
Tools:封装函数为工具(
@tool装饰器)Agent Types:
openai-tools:兼容 OpenAI Function Calling(推荐)react:ReAct 思维链self-ask-with-search:自问自答AgentExecutor:执行循环(Thought → Action → Observation)
-
调用和执行DB
1
2
3
4
5
6
7
8
9
10from langchain_community.agent_toolkits import create_sql_agent
db = SQLDatabase.from_uri(f"sqlite:///{DB_PATH}")
llm = ChatOllama(base_url="http://localhost:11434", model="qwen3:4b", temperature=0)
agent = create_sql_agent(llm=llm, db=db, agent_type="openai-tools")
try:
result = agent.invoke({"input": query})
return result["output"]
except Exception as e:
return f"数据库查询失败: {str(e)}" -
调用和执行Tool
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36from langchain.agents import create_openai_tools_agent, AgentExecutor
from langchain_ollama import OllamaEmbeddings, ChatOllama
llm = ChatOllama(base_url="http://localhost:11434", model="qwen3:4b", temperature=0)
# 定义 Tool
tools = [
Tool(
name="订单与用户查询",
func=query_database,
description="用于查询用户的订单状态、购买记录、个人信息等结构化数据。"
),
Tool(
name="客服知识库查询",
func=query_knowledge_base,
description="用于查询退换货政策、产品使用说明、常见问题等非结构化知识。"
)
]
prompt = ChatPromptTemplate.from_messages([
("system", "你是一个智能客服助手。请根据用户问题选择合适的工具:\n"
"- 如果问题涉及订单、发货、用户信息等,请使用‘订单与用户查询’工具。\n"
"- 如果问题涉及退货、政策、产品说明等,请使用‘客服知识库查询’工具。\n"
"请用简洁、友好的中文回答。"),
MessagesPlaceholder("chat_history"),
("human", "{input}"),
MessagesPlaceholder("agent_scratchpad")
])
# 管理 LLM、工具 和 提示词
agent = create_openai_tools_agent(llm, tools, prompt)
executor = AgentExecutor(agent=agent, tools=tools, verbose=True, handle_parsing_errors=True)
response = executor.invoke({
"input": user_input,
"chat_history": chat_history.messages
})
工具调用(Tool)
1 | from langchain_core.tools import Tool |
1 | from langchain.tools import tool |
状态记忆(Memory)
-
保存对话历史:让 LLM 知道上下文
-
维护状态:跟踪用户偏好、任务进度
-
支持多轮交互:如填表、分步任务
| 类型 | 适用场景 | 特点 |
|---|---|---|
| ConversationBufferMemory | 简单对话 | 保存全部历史(可能超 token) |
| ConversationBufferWindowMemory | 长对话 | 仅保存最近 N 轮 |
| ConversationSummaryMemory | 超长对话 | 用 LLM 生成摘要 |
| EntityMemory | 实体跟踪 | 记住人物/物品属性 |
| VectorStoreRetrieverMemory | 知识库问答 | 从向量库检索相关记忆 |
使用场景
| 场景 | 推荐 Memory 类型 |
|---|---|
| 简单聊天机器人 | ConversationBufferMemory |
| 长对话(>10轮) | ConversationBufferWindowMemory(k=5) |
| 超长对话(>50轮) | ConversationSummaryMemory |
| 角色扮演/实体跟踪 | ConversationEntityMemory |
| 知识库问答 | VectorStoreRetrieverMemory |
| 生产环境持久化 | RedisChatMessageHistory |
基础记忆
ConversationBufferMemory 的 简单对话链
1 | from langchain.memory import ConversationBufferMemory |
1 | # 查看记忆内容 |
窗口记忆(长对话)
避免 token 超限,只保留最近 3 轮:Window Memory
1 | from langchain.memory import ConversationBufferWindowMemory |
摘要记忆(超长对话)
用 LLM 自动摘要历史:Summary Memory
1 | from langchain.memory import ConversationSummaryMemory |
特别注意:
如果
return_messages=True则存储的对象为 List[BaseMessage],获取时需要转换为 文本内容,一般需要注入 记忆注入点MessagesPlaceholder("chat_history"),还有压缩时summary_prompt的影响,是独立存储时才需要获取最近几轮的切片操作。
1
2
3
4
5 # 将消息转为文本
history = "\n".join(
f"{'用户' if m.type == 'human' else '客服'}: {m.content}"
for m in self.get_summary_recent(6) # 最近6轮
)如果
return_messages=False,不需要注入MessagesPlaceholder("chat_history")。
实体记忆
记住对话中提到的实体属性(如人物、物品):EntityMemory
1 | from langchain.memory import ConversationEntityMemory |
向量记忆(知识库)
从向量数据库中检索相关记忆(适合知识库),向量记忆:VectorStoreRetrieverMemory
1 | from langchain.memory import VectorStoreRetrieverMemory |
Agent 工具
让 Agent 记住工具调用历史:
1 | from langchain.agents import AgentType, initialize_agent |
持久化记忆
保存到文件
1 | import pickle |
保存到 Redis(生产推荐)
1 | from langchain.memory import ConversationBufferMemory |
保存到 PostgreSQL
1 | from langchain_community.chat_message_histories import PostgresChatMessageHistory |
高级技巧
-
自定义 Memory Key
1
2
3
4memory = ConversationBufferMemory(
memory_key="conversation_history", # 自定义 key
input_key="user_input" # 指定输入 key
) -
LangGraph 中使用 Memory
1
2
3
4
5
6
7
8
9
10
11
12
13from langgraph.graph import StateGraph, END
class AgentState(TypedDict):
messages: Annotated[list, add_messages]
memory: dict # 自定义 memory 字段
def call_model(state: AgentState):
# 从 state["memory"] 读取历史
response = llm.invoke(state["messages"])
return {"messages": [response]}
workflow = StateGraph(AgentState)
workflow.add_node("agent", call_model)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64# LangGraph 中的自定义记忆
from typing import Annotated, Sequence
from langchain_core.messages import BaseMessage, HumanMessage, AIMessage
from langgraph.graph import StateGraph, START, END
from langgraph.graph.message import add_messages
from langchain_openai import ChatOpenAI
import os
from dotenv import load_dotenv
load_dotenv()
# 定义状态
class GraphState(TypedDict):
messages: Annotated[Sequence[BaseMessage], add_messages]
user_name: str # 自定义记忆字段
# 节点函数
def call_model(state: GraphState):
llm = ChatOpenAI(model="gpt-4o")
response = llm.invoke(state["messages"])
return {"messages": [response]}
def extract_name(state: GraphState):
"""从对话中提取用户名"""
if not state.get("user_name"):
for msg in reversed(state["messages"]):
if isinstance(msg, HumanMessage):
if "我叫" in msg.content:
name = msg.content.split("我叫")[-1].strip("。!")
return {"user_name": name}
return {"user_name": state.get("user_name", "")}
# 构建图
def create_graph():
workflow = StateGraph(GraphState)
workflow.add_node("extract_name", extract_name)
workflow.add_node("call_model", call_model)
workflow.set_entry_point("extract_name")
workflow.add_edge("extract_name", "call_model")
workflow.add_edge("call_model", END)
return workflow.compile()
def main():
app = create_graph()
print("=== LangGraph 记忆测试 ===")
inputs = {"messages": [HumanMessage(content="你好!我叫林然")]}
result = app.invoke(inputs)
print(f"\nAI 回答: {result['messages'][-1].content}")
print(f"提取的用户名: {result['user_name']}")
# 第二轮对话
inputs2 = {
"messages": result["messages"] + [HumanMessage(content="你还记得我吗?")],
"user_name": result["user_name"]
}
result2 = app.invoke(inputs2)
print(f"\n第二轮回答: {result2['messages'][-1].content}")
if __name__ == "__main__":
main() -
记忆过滤(敏感信息)
1
2
3
4
5class SafeMemory(ConversationBufferMemory):
def save_context(self, inputs, outputs):
# 过滤身份证/手机号
inputs = {k: v.replace("138****1234", "[PHONE]") for k, v in inputs.items()}
super().save_context(inputs, outputs)
上下文理解
从之前的历史记录中获取信息,并注入到当前对话中。
-
从 langgraph 的 AgentState 对象中获取 summary,然后通过LLM提取关键上下文数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42# 1. 获取原始问题
original_query = "介绍一下这个商品"
# 2. 结合摘要和最近消息,重写查询
summary = state.get("summary", "")
recent_msgs = state["messages"][-3:] # 最近2-3条
# 构建上下文字符串
context_parts = []
if summary:
context_parts.append(f"背景摘要:{summary}")
for msg in recent_msgs[:-1]: # 不包含当前问题
role = "用户" if isinstance(msg, HumanMessage) else "客服"
context_parts.append(f"{role}: {msg.content}")
context_str = "\n".join(context_parts)
# 3. 让 LLM 重写查询(消除指代)
if context_str.strip():
rewrite_prompt = [
SystemMessage(content="你是一个查询重写助手。请结合对话上下文,将用户的当前问题改写为一个独立、明确、无指代的完整问题。"),
HumanMessage(content=f"上下文:\n{context_str}\n\n当前问题:{original_query}\n\n改写后的问题:")
]
rewritten = llm.invoke(rewrite_prompt)
enhanced_query = rewritten.content.strip()
else:
enhanced_query = original_query
print(f"[RAG 调试] 原始查询: '{original_query}' → 增强查询: '{enhanced_query}'")
# 4. 用增强查询执行 RAG
retriever = init_rag().as_retriever(k=3)
docs = retriever.invoke(enhanced_query)
context = "\n\n".join([d.page_content for d in docs]) or "知识库中未找到相关信息。"
answer_prompt = ChatPromptTemplate.from_messages([
("system", "你是客服,请根据以下资料简洁回答问题,不要反问。"),
("human", f"资料:{context}\n\n问题:{enhanced_query}")
])
rag_chain = answer_prompt | llm | StrOutputParser()
result = rag_chain.invoke({"context": context, "query": enhanced_query}) -
从 langgraph 的 AgentState 对象中获取 summary,然后自己解析提取关键上下文数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20# 1. 从对话历史中提取用户身份
user_name = None
for msg in state["messages"]:
if isinstance(msg, HumanMessage):
content = msg.content
if "我是" in content or "我叫" in content or "我的名字是" in content:
# 简单提取姓名(可扩展为 NER)
for keyword in ["我是", "我叫", "我的名字是"]:
if keyword in content:
name = content.split(keyword)[-1].strip("。!?,. ")
if name:
user_name = name
break
if user_name:
break
# 2. 改写用户查询,显式包含用户名
original_query = state["messages"][-1].content
enhanced_query = f"(当前用户姓名:{user_name}){original_query}" if user_name else original_query
print(f"[DB 调试] 增强后查询: {enhanced_query}") -
从
ConversationSummaryMemory对象中获取 chat_history,然后通过LLM解析提取关键上下文数据1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36# 创建自动摘要记忆
summary_prompt = PromptTemplate.from_template(
"请将以下对话压缩成一段简洁的中文摘要,保留关键信息(如用户姓名、订单、问题类型):\n\n{summary}\n\n当前对话:\nHuman: {new_lines}\nAI:"
)
summary_memory = ConversationSummaryMemory(
llm=self.llm,
memory_key="chat_history",
return_messages=False, # 如果是 True 以消息对象形式返回,兼容 Agent。 如果 False 则返回纯文本摘要
human_prefix="Human",
ai_prefix="AI",
prompt=summary_prompt # 自定义摘要 prompt
)
def get_summary_recent(self, recent_n=6):
"""获取最近 N 条对话消息"""
messages = summary_memory.load_memory_variables({})["chat_history"]
if len(messages) > recent_n:
return messages[-recent_n:] # 最近 N 条
return messages
def extract_last_user_name(self) -> str:
recent_messages = self.get_summary_recent()
prompt = ChatPromptTemplate.from_messages([
("system", "你是一个信息提取助手。请仔细阅读以下对话历史,"
"并提取用户在**最近一次发言**中提到的关键信息。"
"只返回所需内容,不要解释。"),
("human", "对话历史:{history}\n\n"
"问题:用户最近提到的姓名是什么?如果没有,返回“未知”。\n"
"姓名:")
])
chain = prompt | self.llm | StrOutputParser()
return chain.invoke({"history": recent_messages})
状态图(LangGraph)
用于构建 可控、循环、分支、多智能体协作 的复杂工作流。
基于状态(State)驱动
支持条件分支、循环、并行
天然支持多智能体路由
可中断、可恢复、可调试
1 | from langgraph.graph import StateGraph, START, END |
基础 Demo
加载、解析、检索文档,构建问答链和模板,输出响应
1 | # 1. 加载文档 |
智能客服机器人
LangChain Agent(路由决策):
-
若问题涉及订单/用户/状态 → 调用 SQL DB 工具
-
若问题涉及政策/说明/FAQ → 调用 RAG 知识库工具(knowledge_base 文件夹下)
- return_policy.txt(退换货政策)
- product_guide.txt(产品使用指南)
-
其他问题直接调用LLM
单智能体
支持多轮对话,记忆上下文
1 | # ---------------------------- |
多智能体(LangGraph)
将单体客服系统拆分为多个专业智能体(Agents),并通过 LangGraph 实现协作控制流,能显著提升系统的模块化、可维护性和推理能力。
本智能体不支持上下文理解,更多代码和使用方式,参照 GitHub(自动摘要记忆,支持多轮对话,上下文理解)
多智能体 + LangGraph 协作流程图:
1 | # ---------------------------- |
多智能体(Chain)
1 | # ---------------------------- |