第一章:大模型应用开发基础框架入门
1.1 开发框架认知
- 什么是大模型应用开发框架?
大模型(LLM)本身只是一个"大脑",它没有记忆,读不到你的本地文件,也无法联网。开发框架(如 LangChain)的作用就是给这个大脑装上**眼睛(数据连接)、 耳朵(输入处理)、嘴巴(输出生成)和手(工具调用)**,让开发者能用代码把模型和业务逻辑串联起来。 - LangChain vs. LlamaIndex:选型指南
- LangChain :全能型选手。擅长构建复杂的 Agent、多步工作流、调用各种 API。如果你想做一个能查天气、能写代码、能聊天的全能助手,选 LangChain。
- LlamaIndex :数据专精型选手。专注于数据的索引、检索和增强(RAG)。如果你只需要做一个极其强大的文档问答系统,LlamaIndex 的数据处理能力更强。
- 现状 :两者正在融合,LangChain 也在加强 RAG 能力,LlamaIndex 也在增加 Agent 功能。目前业界主流是 LangChain 为主,LlamaIndex 为辅。
1.2 LangChain 核心组件深度解析
LangChain 的架构可以概括为四大模块:Model I/O (模型交互)、Data Connection (数据连接)、Memory (记忆)、Chains(链/流程)。
1.2.1 模型 I/O 封装
这是与 LLM 对话的接口。
- Chat Models vs. LLMs :
- LLMs:传统的文本补全模型(如 GPT-3),输入一段话,预测下一段话。
- Chat Models :专为对话设计(如 GPT-4, Claude),输入是
System(人设)、Human(用户)、AI(助手)的消息列表。 - 选型 :**99% 的场景请使用
ChatModel**,因为它更稳定且支持多轮对话。
- 输出控制 :
- 流式输出:像打字机一样逐字显示,提升用户体验。
- 结构化输出 :强制模型输出 JSON 格式(如
{"name": "张三", "age": 25}),方便代码后续处理。
- Prompt 模板 :
不要把 Prompt 写死在字符串里。使用PromptTemplate可以像 Python 的 f-string 一样动态插入变量。
python
from langchain_core.prompts import ChatPromptTemplate
# 定义模板
prompt = ChatPromptTemplate.from_messages([
("system", "你是一个专业的{role},请用{tone}的语气回答问题。"),
("human", "{input}")
])
# 动态填充
final_prompt = prompt.invoke({"role": "程序员", "tone": "幽默", "input": "什么是死循环?"})
# 输出: System: 你是一个专业的程序员... Human: 什么是死循环?
1.2.2 数据连接(Data Connection)
这是 RAG 的核心,让模型"读"到你的私有数据。
- 文本向量化:将文字转化为计算机能理解的数字向量。例如,"猫"和"狗"的向量距离很近,和"汽车"的距离很远。
- 文档加载与切割 :
- Loader:读取 PDF, Word, Markdown。
- Splitter :将长文档切成小块(Chunk)。RecursiveCharacterTextSplitter 是最常用的,它会优先按段落切,切不开再按句子切。
- 向量数据库选型 :
- FAISS:Facebook 开源,内存级索引,速度极快,适合本地开发和中小规模数据。
- Chroma:轻量级,自带持久化存储,适合快速原型。
- Milvus / Pinecone:企业级,支持海量数据(亿级)和高并发,适合生产环境。
1.2.3 Memory 记忆封装
LLM 本身是无状态的(Stateless),它记不住上一句说了什么。Memory 组件负责把历史对话塞回 Prompt 中。
- ConversationBufferMemory:简单粗暴,保存所有历史对话。缺点是容易超出 Token 限制。
- ConversationSummaryMemory:用 LLM 把历史对话总结成一段摘要,节省 Token。
- ConversationBufferWindowMemory:只保留最近的 K 轮对话(如最近 5 句)。
1.2.4 链(Chain)与 LCEL
Chain 是把组件串起来的逻辑。LangChain 推出了 **LCEL (LangChain Expression Language)**,这是一种声明式的语法,让代码更简洁、原生支持异步和流式。
核心概念:Runnable
在 LCEL 中,Prompt、Model、解析器都是 Runnable 对象,可以用 | 符号像管道一样连起来。
python
# LCEL 语法:Prompt -> Model -> 输出解析
chain = prompt | model | StrOutputParser()
result = chain.invoke({"input": "你好"})
1.3 LangChain 综合实战项目:企业专属知识库问答系统
我们将结合上述所有组件,搭建一个**"金融政策问答助手"**。
项目流程:
- 加载:读取金融政策文档。
- 切分:将文档切块。
- 向量化:存入 FAISS 向量库。
- 检索:用户提问,从库中找相关片段。
- 生成:将片段和问题发给 LLM,生成答案。
环境准备
bash
pip install langchain langchain-community langchain-openai faiss-cpu pypdf
实现过程
python
import os
from langchain_community.document_loaders import PyPDFLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_openai import OpenAIEmbeddings, ChatOpenAI
from langchain_community.vectorstores import FAISS
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough
# 1. 配置环境 (请替换为你的 API Key)
os.environ["OPENAI_API_KEY"] = "sk-xxxxxx"
# ==========================================
# 第一步:数据连接 (Data Connection)
# ==========================================
def build_knowledge_base(file_path):
print("正在加载文档...")
# 1. 加载 PDF
loader = PyPDFLoader(file_path)
documents = loader.load()
# 2. 文本切分 (Chunking)
# chunk_size=500: 每块500字符, overlap=100: 重叠100字符保持上下文
text_splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=100)
docs = text_splitter.split_documents(documents)
print(f"文档切分完成,共 {len(docs)} 个片段。")
# 3. 向量化与存储 (Embedding & VectorStore)
# 使用 OpenAI 的 Embedding 模型,也可以换成本地的 sentence-transformers
embeddings = OpenAIEmbeddings()
vectorstore = FAISS.from_documents(docs, embeddings)
# 4. 转换为检索器 (Retriever)
# 每次检索最相关的 3 个片段
retriever = vectorstore.as_retriever(search_kwargs={"k": 3})
return retriever
# ==========================================
# 第二步:模型 I/O 与 链 (Chain)
# ==========================================
def create_rag_chain(retriever):
# 1. 定义 Prompt 模板
# 使用 format_docs 将检索到的多个文档片段拼接成字符串
template = """
你是一个专业的金融政策顾问。请仅根据以下提供的参考资料回答问题。
如果资料中没有答案,请直接说"抱歉,知识库中未找到相关信息"。
参考资料:
{context}
用户问题:
{question}
回答:
"""
prompt = ChatPromptTemplate.from_template(template)
# 2. 定义模型
model = ChatOpenAI(model="gpt-4o", temperature=0) # temperature=0 保证回答严谨
# 3. 构建 LCEL 链
# 核心逻辑:
# 输入 {"question": "xxx"}
# -> context 由 retriever 获取
# -> question 由 RunnablePassthrough 透传
# -> 组装进 prompt
# -> 发给 model
# -> 解析输出
rag_chain = (
{"context": retriever, "question": RunnablePassthrough()}
| prompt
| model
| StrOutputParser()
)
return rag_chain
# ==========================================
# 第三步:运行实战
# ==========================================
if __name__ == "__main__":
# 假设当前目录下有一个 policy.pdf 文件
# 如果没有,代码会报错,实际使用请确保文件存在
try:
# 1. 构建知识库 (实际项目中这步通常离线完成)
# retriever = build_knowledge_base("policy.pdf")
# 为了演示代码可运行,这里用模拟数据替代文件加载
from langchain_core.documents import Document
mock_docs = [
Document(page_content="2026年最新政策:小微企业贷款利率下调至3.5%。"),
Document(page_content="申请流程:需携带营业执照和法人身份证到柜台办理。")
]
embeddings = OpenAIEmbeddings()
vectorstore = FAISS.from_documents(mock_docs, embeddings)
retriever = vectorstore.as_retriever()
# 2. 创建问答链
chain = create_rag_chain(retriever)
# 3. 提问
question = "现在小微企业的贷款利率是多少?"
print(f"\n用户提问: {question}")
# 4. 流式输出 (Streaming)
print("AI 回答: ", end="", flush=True)
for chunk in chain.stream(question):
print(chunk, end="", flush=True)
except Exception as e:
print(f"运行出错: {e}")
核心逻辑图解
相关文档片段
用户提问
检索器 Retriever
Context
Question
Prompt 模板
大模型 ChatModel
最终回答
本章总结
通过本章, LangChain 的四大核心:Model I/O (对话接口)、Data Connection (知识库)、Memory (记忆)和 Chain(流程编排)。后续主要是向高级 Agent 进阶。