Appearance
章节4:LangChain应用开发
学习目标
- 掌握 LangChain 核心组件:Model / Prompt / Chain
- 理解 LCEL 表达式语言(管道式链式调用)
- 掌握 Memory 记忆系统(BufferMemory / SummaryMemory)
- 学会 Tools 工具调用与 Function Calling
- 熟悉 Retriever 检索器与文档加载器
核心知识点
4.1 核心组件:Model / Prompt / Chain
定义
LangChain 三大核心抽象:
| 组件 | 作用 | 常用类 |
|---|---|---|
| Model | 封装 LLM 调用 | ChatOpenAI, OllamaLLM |
| Prompt | 管理提示词模板 | PromptTemplate, ChatPromptTemplate |
| Chain | 串联多个组件 | LLMChain, SequentialChain |
代码示例:Model + Prompt + Chain 基础用法
python
# pip install langchain langchain-openai
from langchain_openai import ChatOpenAI
from langchain.prompts import PromptTemplate
from langchain.chains import LLMChain
# 1. Model —— 初始化模型
llm = ChatOpenAI(
model="gpt-4o",
temperature=0.7,
api_key="your-api-key"
)
# 2. Prompt —— 定义模板
prompt = PromptTemplate(
input_variables=["topic", "style"],
template="请以{style}的风格写一段关于{topic}的简短介绍,不超过100字。"
)
# 3. Chain —— 串联
chain = LLMChain(llm=llm, prompt=prompt)
# 4. 执行
result = chain.invoke({"topic": "人工智能", "style": "幽默"})
print(result["text"])python
# ChatPromptTemplate —— 支持多角色消息
from langchain.prompts import ChatPromptTemplate, MessagesPlaceholder
chat_prompt = ChatPromptTemplate.from_messages([
("system", "你是一个{role},擅长{field}方面的咨询。"),
("user", "{question}"),
MessagesPlaceholder(variable_name="history"), # 对话历史占位
])
chain = chat_prompt | llm
result = chain.invoke({
"role": "资深算法工程师",
"field": "自然语言处理",
"question": "为什么Transformer比RNN更适合处理长文本?",
"history": []
})
print(result.content)4.2 LCEL 表达式语言
定义
LCEL(LangChain Expression Language):使用 | 管道操作符将组件串联成执行链,类似 Unix 管道或函数式编程的组合风格。
输入 → PromptTemplate → LLM → OutputParser → 输出
│ │ │ │
└─────────┴────────┴────────┘
用 | 连接代码示例:LCEL 链式调用
python
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import PromptTemplate
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(model="gpt-4o")
# 基础 LCEL 链
prompt = PromptTemplate.from_template("用{language}写一首关于{subject}的诗,4行。")
chain = prompt | llm | StrOutputParser()
result = chain.invoke({"language": "中文", "subject": "程序员"})
print(result)python
# 复杂 LCEL 链:分支 + 合并
from operator import itemgetter
# 两个并行的翻译链
en_prompt = PromptTemplate.from_template("将以下内容翻译为英文:{text}")
jp_prompt = PromptTemplate.from_template("将以下内容翻译为日文:{text}")
en_chain = en_prompt | llm | StrOutputParser()
jp_chain = jp_prompt | llm | StrOutputParser()
# 合并链
from langchain_core.runnables import RunnableParallel
parallel_chain = RunnableParallel(
english=en_chain,
japanese=jp_chain
)
# 最终格式化
format_prompt = PromptTemplate.from_template(
"原文:{text}\n\n英文:{english}\n日文:{japanese}"
)
format_chain = format_prompt | llm | StrOutputParser()
# 完整 LCEL 管道
full_chain = {
"text": itemgetter("text"), # 透传原始输入
"english": en_chain,
"japanese": jp_chain
} | format_chain
result = full_chain.invoke({"text": "你好,今天天气真好!"})
print(result)4.3 Memory 记忆系统
定义
Memory 让 Chain 具备"记忆"能力,在多轮对话中记住之前的交互内容。
| 记忆类型 | 原理 | 适用场景 |
|---|---|---|
| ConversationBufferMemory | 完整保存所有对话历史 | 短期对话 |
| ConversationSummaryMemory | 定期总结压缩历史 | 长对话 |
| ConversationBufferWindowMemory | 只保留最近 K 轮 | 控制 Token 消耗 |
| VectorStoreRetrieverMemory | 按相关性检索历史 | 超长会话 |
代码示例:对话记忆
python
from langchain.memory import ConversationBufferMemory
from langchain.chains import ConversationChain
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(model="gpt-4o")
# 缓冲区记忆
memory = ConversationBufferMemory(return_messages=True)
conversation = ConversationChain(
llm=llm,
memory=memory,
verbose=True # 输出内部步骤
)
# 多轮对话
print(conversation.predict(input="你好!我叫张三。"))
print(conversation.predict(input="我是Python开发者。"))
print(conversation.predict(input="你还记得我叫什么名字吗?")) # 应该记得python
# 摘要记忆 —— 节省 Token
from langchain.memory import ConversationSummaryMemory
summary_memory = ConversationSummaryMemory(
llm=llm,
max_token_limit=200 # 摘要最大 Token 数
)
# 长对话时,系统会自动将历史压缩为摘要
conv_with_summary = ConversationChain(
llm=llm,
memory=summary_memory,
verbose=True
)4.4 Tools 工具调用与 Function Calling
定义
Tool / Function Calling 让 LLM 能够调用外部工具(搜索、计算、数据库查询等),极大地扩展了模型的能力边界。
用户请求 "北京市今天的天气怎么样?"
│
▼
LLM 判断需要调用天气 API
│
▼
Tool: get_weather("北京") → "晴,22-28°C"
│
▼
LLM 用工具结果生成最终回答代码示例:自定义工具与 Function Calling
python
from langchain.tools import tool
from langchain_openai import ChatOpenAI
from langchain.agents import create_tool_calling_agent, AgentExecutor
from langchain.prompts import ChatPromptTemplate
# 1. 定义工具
@tool
def calculate(expression: str) -> str:
"""计算数学表达式的结果"""
try:
result = eval(expression, {"__builtins__": {}}, {})
return f"计算结果: {result}"
except Exception as e:
return f"计算错误: {e}"
@tool
def get_current_time() -> str:
"""获取当前时间"""
from datetime import datetime
return datetime.now().strftime("%Y-%m-%d %H:%M:%S")
# 2. 创建 Agent
llm = ChatOpenAI(model="gpt-4o")
tools = [calculate, get_current_time]
prompt = ChatPromptTemplate.from_messages([
("system", "你是一个智能助手,可以使用工具来回答问题。"),
("human", "{input}"),
("placeholder", "{agent_scratchpad}"),
])
agent = create_tool_calling_agent(llm, tools, prompt)
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
# 3. 执行
agent_executor.invoke({"input": "计算 123 × 456 + 789 等于多少,并告诉我现在几点了?"})4.5 Retriever 检索器与文档加载
定义
Document Loader(文档加载器):从各种源加载文档(PDF、网页、CSV、数据库)。
Retriever(检索器):根据查询从文档集合中检索相关片段,是 RAG 与 LangChain 的桥梁。
代码示例:文档加载与检索
python
# pip install langchain-community pypdf chromadb
# 文档加载
from langchain_community.document_loaders import PyPDFLoader, TextLoader, WebBaseLoader
# 加载 PDF
# loader = PyPDFLoader("document.pdf")
# documents = loader.load()
# 加载网页
# web_loader = WebBaseLoader("https://example.com")
# web_docs = web_loader.load()
# 加载文本文件
text_loader = TextLoader("notes.txt", encoding="utf-8")
text_docs = text_loader.load()python
# 向量检索器 —— ChromaDB + LangChain 集成
from langchain_openai import OpenAIEmbeddings
from langchain_community.vectorstores import Chroma
from langchain.text_splitter import RecursiveCharacterTextSplitter
# 1. 分块
splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=50)
# chunks = splitter.split_documents(documents)
# 2. 创建向量存储
# vector_store = Chroma.from_documents(
# documents=chunks,
# embedding=OpenAIEmbeddings(),
# persist_directory="./chroma_langchain"
# )
# 3. 创建检索器
# retriever = vector_store.as_retriever(
# search_type="similarity",
# search_kwargs={"k": 3}
# )
# 4. 使用检索器
# results = retriever.invoke("你的问题")
# for doc in results:
# print(f"[{doc.metadata.get('source', 'unknown')}] {doc.page_content[:100]}")python
# RetrievalQA Chain —— 开箱即用的 RAG 链
from langchain.chains import RetrievalQA
# qa_chain = RetrievalQA.from_chain_type(
# llm=llm,
# chain_type="stuff", # stuff | map_reduce | refine | map_rerank
# retriever=retriever,
# return_source_documents=True
# )
# response = qa_chain.invoke({"query": "文档的核心内容是什么?"})
# print(response["result"])
# print("来源文档:", [doc.metadata["source"] for doc in response["source_documents"]])小结与练习
小结
- LangChain 的三大核心抽象 Model / Prompt / Chain 构成了应用开发的基础
- LCEL 表达式语言用
|管道符实现简洁的链式组合,是 LangChain 推荐的开发范式 - Memory 系统让 LLM 应用具备多轮对话能力,BufferMemory 和 SummaryMemory 覆盖不同场景
- Tool / Function Calling 让 LLM 可以调用外部工具,能力边界大幅扩展
- Retriever + Document Loader + Vector Store 是构建 RAG 应用的开发基础
练习题
- 基础题:使用 ChatPromptTemplate + ChatOpenAI + StrOutputParser 构建一个 LCEL 链,实现"翻译+解释"功能。
- 实践题:构建一个带有 ConversationBufferMemory 的聊天机器人,让它能记住用户的名字和偏好,并在后续对话中调用。
- 实践题:实现一个自定义 Tool(如查询天气或计算器),并用 AgentExecutor 让 LLM 自动调用它。
- 综合题:结合 Document Loader + Text Splitter + ChromaDB + RetrievalQA,构建一个完整的本地文档问答系统。