用LangChain构建你的第一个AI应用
从零开始,使用LangChain框架构建完整的AI应用。
前言
LangChain是目前最流行的LLM应用开发框架,它提供了丰富的组件和抽象,让开发者能够快速构建复杂的AI应用。
今天,我们将通过一个实战项目,学习LangChain的核心概念和最佳实践。
一、LangChain核心概念
框架架构
┌─────────────────────────────────────────────────────────────┐
│ LangChain 架构 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 应用层 │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Chains │ │ Agents │ │ Callbacks │ │
│ │ 链式调用 │ │ 智能代理 │ │ 回调处理 │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │
│ 核心层 │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Prompts │ │ LLMs │ │ Memory │ │
│ │ 提示模板 │ │ 语言模型 │ │ 记忆 │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │
│ 数据层 │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Documents │ │ Embeddings │ │VectorStores │ │
│ │ 文档处理 │ │ 向量化 │ │ 向量存储 │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
核心组件
| 组件 | 功能 | 说明 |
|---|---|---|
| Models | 模型接口 | 支持OpenAI、HuggingFace等 |
| Prompts | 提示管理 | 模板化、动态提示 |
| Memory | 记忆系统 | 对话历史、长期记忆 |
| Indexes | 数据索引 | 文档处理、向量存储 |
| Chains | 链式调用 | 组合多个组件 |
| Agents | 智能代理 | 自主决策、工具调用 |
二、环境搭建
安装依赖
# 安装LangChain
pip install langchain langchain-openai langchain-community
# 安装向量数据库
pip install chromadb
# 安装文档处理
pip install pypdf unstructured
# 安装其他工具
pip install tiktoken python-dotenv
配置环境
# .env文件
OPENAI_API_KEY=your-api-key
# 加载环境变量
from dotenv import load_dotenv
load_dotenv()
三、基础组件使用
1. LLM调用
from langchain_openai import OpenAI, ChatOpenAI
# 文本补全模型
llm = OpenAI(temperature=0.7)
result = llm.invoke("什么是机器学习?")
print(result)
# 聊天模型(推荐)
chat = ChatOpenAI(model="gpt-4", temperature=0.7)
from langchain.schema import HumanMessage, SystemMessage
messages = [
SystemMessage(content="你是一个AI科普作者"),
HumanMessage(content="请用简单的话解释神经网络")
]
response = chat.invoke(messages)
print(response.content)
2. Prompt模板
from langchain.prompts import PromptTemplate, ChatPromptTemplate
# 简单模板
template = PromptTemplate.from_template("请用{style}的风格解释{topic}")
prompt = template.format(style="幽默", topic="量子力学")
print(prompt)
# 聊天模板
chat_template = ChatPromptTemplate.from_messages([
("system", "你是一位{role}"),
("human", "{question}")
])
messages = chat_template.format_messages(
role="资深Python工程师",
question="什么是装饰器?"
)
3. 输出解析
from langchain.output_parsers import StructuredOutputParser, ResponseSchema
# 定义输出结构
response_schemas = [
ResponseSchema(name="name", description="产品名称"),
ResponseSchema(name="price", description="产品价格"),
ResponseSchema(name="features", description="产品特点列表")
]
parser = StructuredOutputParser.from_response_schemas(response_schemas)
format_instructions = parser.get_format_instructions()
prompt = PromptTemplate(
template="""
请分析以下产品信息并提取结构化数据。
{format_instructions}
产品描述:{product_desc}
""",
input_variables=["product_desc"],
partial_variables={"format_instructions": format_instructions}
)
# 使用
input_prompt = prompt.format(product_desc="iPhone 15 Pro,售价8999元,特点是钛金属边框、A17芯片、钛金属边框")
output = llm.invoke(input_prompt)
parsed = parser.parse(output)
print(parsed)
四、Chain链式调用
LLMChain
from langchain.chains import LLMChain
# 创建链
chain = LLMChain(
llm=chat,
prompt=chat_template,
verbose=True # 显示执行过程
)
# 执行
result = chain.run(role="AI专家", question="什么是大语言模型?")
print(result)
SequentialChain
from langchain.chains import SequentialChain
# 第一步:生成文章大纲
outline_chain = LLMChain(
llm=chat,
prompt=PromptTemplate.from_template("为以下主题生成文章大纲:{topic}"),
output_key="outline"
)
# 第二步:根据大纲写文章
article_chain = LLMChain(
llm=chat,
prompt=PromptTemplate.from_template("根据以下大纲写一篇800字的文章:\n{outline}"),
output_key="article"
)
# 组合链
overall_chain = SequentialChain(
chains=[outline_chain, article_chain],
input_variables=["topic"],
output_variables=["outline", "article"],
verbose=True
)
result = overall_chain({"topic": "人工智能的未来"})
print(result["article"])
LCEL (LangChain Expression Language)
from langchain_core.output_parsers import StrOutputParser
# 使用LCEL语法(推荐)
chain = chat_template | chat | StrOutputParser()
result = chain.invoke({
"role": "AI助手",
"question": "什么是LangChain?"
})
print(result)
# 添加更多步骤
from langchain_core.runnables import RunnablePassthrough
chain = (
{"question": RunnablePassthrough()}
| PromptTemplate.from_template("请详细回答:{question}")
| chat
| StrOutputParser()
)
result = chain.invoke("什么是向量数据库?")
五、Memory记忆系统
对话记忆
from langchain.memory import ConversationBufferMemory
# 创建记忆
memory = ConversationBufferMemory(
memory_key="chat_history",
return_messages=True
)
# 添加对话
memory.save_context(
{"input": "你好,我叫张三"},
{"output": "你好张三,很高兴认识你!"}
)
# 获取记忆
print(memory.load_memory_variables({}))
# {'chat_history': [HumanMessage(content='你好,我叫张三'), AIMessage(content='你好张三,很高兴认识你!')]}
# 在Chain中使用
from langchain.chains import ConversationChain
conversation = ConversationChain(
llm=chat,
memory=memory,
verbose=True
)
conversation.predict(input="你还记得我的名字吗?")
# 输出: 当然记得,你叫张三!
记忆类型对比
# 1. 完整记忆(可能超出上下文长度)
from langchain.memory import ConversationBufferMemory
# 2. 窗口记忆(只保留最近N轮)
from langchain.memory import ConversationBufferWindowMemory
window_memory = ConversationBufferWindowMemory(k=5) # 保留最近5轮
# 3. 摘要记忆(压缩历史对话)
from langchain.memory import ConversationSummaryMemory
summary_memory = ConversationSummaryMemory(llm=chat)
# 4. 实体记忆(记住实体信息)
from langchain.memory import ConversationEntityMemory
entity_memory = ConversationEntityMemory(llm=chat)
# 5. 向量存储记忆(语义检索历史)
from langchain.memory import VectorStoreRetrieverMemory
六、实战项目:文档问答助手
项目架构
┌─────────────────────────────────────────────────────────────┐
│ 文档问答助手 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 1. 文档加载 ─→ 2. 文档分割 ─→ 3. 向量化 ─→ 4. 向量存储 │
│ │
│ 5. 问题输入 ─→ 6. 向量检索 ─→ 7. 上下文构建 ─→ 8. LLM生成 │
│ │
└─────────────────────────────────────────────────────────────┘
完整代码实现
from langchain.document_loaders import PyPDFLoader, TextLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_openai import OpenAIEmbeddings, ChatOpenAI
from langchain.vectorstores import Chroma
from langchain.chains import RetrievalQA
from langchain.prompts import PromptTemplate
import os
class DocumentQA:
def __init__(self, persist_directory="./chroma_db"):
"""初始化文档问答系统"""
self.embeddings = OpenAIEmbeddings()
self.llm = ChatOpenAI(model="gpt-4", temperature=0)
self.persist_directory = persist_directory
self.vectorstore = None
def load_documents(self, file_paths):
"""加载文档"""
documents = []
for file_path in file_paths:
if file_path.endswith('.pdf'):
loader = PyPDFLoader(file_path)
else:
loader = TextLoader(file_path, encoding='utf-8')
documents.extend(loader.load())
print(f"已加载 {len(documents)} 个文档")
return documents
def split_documents(self, documents, chunk_size=1000, chunk_overlap=200):
"""分割文档"""
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=chunk_size,
chunk_overlap=chunk_overlap,
separators=["\n\n", "\n", "。", "!", "?", " ", ""]
)
chunks = text_splitter.split_documents(documents)
print(f"已分割为 {len(chunks)} 个文档块")
return chunks
def build_vectorstore(self, chunks):
"""构建向量存储"""
self.vectorstore = Chroma.from_documents(
documents=chunks,
embedding=self.embeddings,
persist_directory=self.persist_directory
)
print("向量存储构建完成")
def load_vectorstore(self):
"""加载已有的向量存储"""
self.vectorstore = Chroma(
persist_directory=self.persist_directory,
embedding_function=self.embeddings
)
def create_qa_chain(self):
"""创建问答链"""
# 自定义Prompt
prompt_template = """
你是一个专业的问答助手。请根据提供的参考资料回答问题。
要求:
1. 仅基于参考资料回答,不要添加外部知识
2. 如果资料中没有相关信息,请明确说明
3. 回答要准确、简洁、完整
4. 如果引用内容,请注明来源
参考资料:
{context}
问题:{question}
回答:"""
PROMPT = PromptTemplate(
template=prompt_template,
input_variables=["context", "question"]
)
# 创建问答链
qa_chain = RetrievalQA.from_chain_type(
llm=self.llm,
chain_type="stuff",
retriever=self.vectorstore.as_retriever(
search_type="mmr",
search_kwargs={"k": 4}
),
chain_type_kwargs={"prompt": PROMPT},
return_source_documents=True
)
return qa_chain
def ask(self, question):
"""提问"""
if not self.vectorstore:
raise ValueError("请先构建或加载向量存储")
qa_chain = self.create_qa_chain()
result = qa_chain({"query": question})
return {
"answer": result["result"],
"sources": [
{
"content": doc.page_content[:200] + "...",
"source": doc.metadata.get("source", "未知")
}
for doc in result["source_documents"]
]
}
# 使用示例
def main():
# 创建系统
qa_system = DocumentQA()
# 加载并处理文档
documents = qa_system.load_documents(["doc1.pdf", "doc2.txt"])
chunks = qa_system.split_documents(documents)
qa_system.build_vectorstore(chunks)
# 问答
while True:
question = input("\n请输入问题(输入'quit'退出):")
if question.lower() == 'quit':
break
result = qa_system.ask(question)
print(f"\n回答:{result['answer']}")
print(f"\n来源:{len(result['sources'])} 个文档")
if __name__ == "__main__":
main()
七、实战项目:智能客服机器人
完整实现
from langchain_openai import ChatOpenAI
from langchain.memory import ConversationBufferMemory
from langchain.chains import ConversationalRetrievalChain
from langchain.prompts import PromptTemplate
from langchain.vectorstores import Chroma
from langchain_openai import OpenAIEmbeddings
class CustomerServiceBot:
def __init__(self, knowledge_base_path):
"""初始化客服机器人"""
self.llm = ChatOpenAI(model="gpt-4", temperature=0)
# 加载知识库
self.vectorstore = Chroma(
persist_directory=knowledge_base_path,
embedding_function=OpenAIEmbeddings()
)
# 创建记忆
self.memory = ConversationBufferMemory(
memory_key="chat_history",
return_messages=True,
output_key="answer"
)
# 创建对话链
self.qa_chain = self._create_chain()
def _create_chain(self):
"""创建对话检索链"""
# 客服Prompt
prompt = PromptTemplate.from_template("""
你是一个专业、友好的客服助手。请根据知识库内容回答客户问题。
指导原则:
1. 回答要专业、准确、友好
2. 如果知识库中没有答案,诚实告知并提供替代建议
3. 对于投诉类问题,表示理解并提供解决方案
4. 必要时引导客户联系人工客服
历史对话:
{chat_history}
相关知识:
{context}
客户问题:{question}
回答:""")
chain = ConversationalRetrievalChain.from_llm(
llm=self.llm,
retriever=self.vectorstore.as_retriever(search_kwargs={"k": 3}),
memory=self.memory,
combine_docs_chain_kwargs={"prompt": prompt},
return_source_documents=True,
verbose=True
)
return chain
def chat(self, message):
"""对话"""
result = self.qa_chain({"question": message})
response = {
"answer": result["answer"],
"sources": [
doc.metadata.get("source", "知识库")
for doc in result.get("source_documents", [])
]
}
return response
def reset(self):
"""重置对话"""
self.memory.clear()
# 使用示例
bot = CustomerServiceBot("./knowledge_base")
# 对话
print(bot.chat("你们的产品支持退换货吗?"))
print(bot.chat("退款多久能到账?"))
print(bot.chat("我买的商品有质量问题,怎么处理?"))
八、最佳实践
性能优化
# 1. 使用缓存
from langchain.cache import InMemoryCache
import langchain
langchain.llm_cache = InMemoryCache()
# 2. 批量处理
from langchain.schema import Document
batch_docs = [Document(page_content=text) for text in texts]
vectorstore = Chroma.from_documents(batch_docs, embeddings)
# 3. 异步调用
async def async_process(questions):
tasks = [chain.ainvoke({"question": q}) for q in questions]
results = await asyncio.gather(*tasks)
return results
# 4. 流式输出
from langchain.callbacks.streaming_stdout import StreamingStdOutCallbackHandler
llm = ChatOpenAI(
streaming=True,
callbacks=[StreamingStdOutCallbackHandler()]
)
错误处理
from langchain.callbacks import StdOutCallbackHandler
from langchain.chains import LLMChain
def safe_invoke(chain, inputs, max_retries=3):
"""安全的链调用"""
for attempt in range(max_retries):
try:
return chain.invoke(inputs)
except Exception as e:
print(f"第{attempt + 1}次尝试失败: {e}")
if attempt == max_retries - 1:
raise
time.sleep(2 ** attempt) # 指数退避
return None
小结
| 组件 | 用途 | 关键API |
|---|---|---|
| Models | 模型调用 | ChatOpenAI, OpenAI |
| Prompts | 提示管理 | PromptTemplate |
| Chains | 链式调用 | LLMChain, RetrievalQA |
| Memory | 记忆系统 | ConversationBufferMemory |
| VectorStores | 向量存储 | Chroma, FAISS |
| Retrievers | 检索器 | vectorstore.as_retriever() |
思考与练习
-
思考题:
- LCEL语法相比传统Chain有什么优势?
- 如何选择合适的Memory类型?
-
动手练习:
- 构建一个基于PDF文档的问答系统
- 为问答系统添加对话记忆功能
-
延伸阅读:
下期预告
下一篇文章,我们将深入探讨:本地部署大模型:Ollama实战指南
会解答这些问题:
- 如何在本地运行开源大模型?
- Ollama的核心功能有哪些?
- 如何优化本地模型性能?
关注专栏,不错过后续更新!
作者:ECH00O00 本文首发于掘金专栏《AI科普实验室》 欢迎评论区交流讨论,点赞收藏就是最大的鼓励 ❤️