Day 76:【99天精通Python】AI 进阶 - LangChain 入门 - 给 AI 挂载"外脑"

前言

欢迎来到第76天!

在昨天的课程中,我们直接调用了 OpenAI 的 API。虽然它很聪明,但它有两个致命缺点:

  1. 知识滞后:它只知道训练截止日期之前的事情(比如 GPT-3.5 截止到 2021 年)。
  2. 私有数据盲区:它不知道你公司的内部文档,也不知道你昨天写的日记。

为了解决这个问题,我们需要 LangChain
LangChain 是目前最火的 LLM 开发框架。它可以把大模型(大脑)与外部数据源(书籍、PDF、数据库)连接起来,实现 RAG (检索增强生成)。简单说,就是让 AI 先去翻书,翻到了再回答你。

本节内容:

  • LangChain 核心概念
  • 模型 (Model) 与 提示词模板 (PromptTemplate)
  • 链 (Chain) 的概念
  • 加载本地文档 (Loader)
  • 向量数据库与检索 (VectorStore & Retriever)
  • 实战练习:本地文档问答机器人

一、环境准备

LangChain 更新极快,建议安装最新版。

pip install langchain langchain-openai chromadb pypdf

二、Model 与 Prompt

2.1 初始化模型

LangChain 封装了各种模型的接口,让我们切换模型像换衣服一样简单。

from langchain_openai import ChatOpenAI

# 初始化模型 (支持换成文心一言、通义千问等,只要有对应类)
llm = ChatOpenAI(
    api_key="sk-...", 
    base_url="...",
    temperature=0.7
)

# 直接调用
# resp = llm.invoke("你是谁?")
# print(resp.content)

2.2 提示词模板 (PromptTemplate)

我们不希望每次都手写 “请帮我翻译…”,我们可以定义一个模板,挖好坑填参数。

from langchain_core.prompts import ChatPromptTemplate

# 定义模板
prompt = ChatPromptTemplate.from_template("请将下面的文字翻译成{language}:{text}")

# 填充参数
messages = prompt.format_messages(language="法语", text="你好,世界")
# print(messages)

三、链 (Chain):LangChain 的灵魂

Chain 把 Prompt、Model 和 OutputParser 串联起来。
LangChain 使用 LCEL (LangChain Expression Language) 语法,用 | 管道符连接。

from langchain_core.output_parsers import StrOutputParser

# 1. Prompt
prompt = ChatPromptTemplate.from_template("给我讲一个关于{topic}的笑话")

# 2. Model
model = ChatOpenAI(api_key="...")

# 3. Parser (把对象转为纯字符串)
parser = StrOutputParser()

# 4. 组装链条
chain = prompt | model | parser

# 5. 运行
res = chain.invoke({"topic": "程序员"})
print(res)

四、RAG 实战:让 AI 读懂你的 PDF

RAG 的流程是:

  1. 加载 (Load):读取 PDF/Txt 文件。
  2. 切分 (Split):把长文章切成小块(Chunk)。
  3. 嵌入 (Embed):把文字变成向量(一串数字),存入向量数据库。
  4. 检索 (Retrieve):用户提问 -> 找最相似的片段。
  5. 生成 (Generate):把片段 + 问题扔给 AI -> 生成答案。

4.1 加载与切分

from langchain_community.document_loaders import PyPDFLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter

# 1. 加载 PDF
loader = PyPDFLoader("my_paper.pdf") # 请准备一个 PDF 文件
docs = loader.load()

# 2. 切分 (每块 1000 字符,重叠 200)
text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
splits = text_splitter.split_documents(docs)

print(f"切分成了 {len(splits)} 个片段")

4.2 向量化存储 (Chroma)

我们需要一个 Embedding 模型 来计算向量。OpenAI 提供了 text-embedding-3-small

from langchain_openai import OpenAIEmbeddings
from langchain_community.vectorstores import Chroma

# 初始化 Embedding 模型
embedding = OpenAIEmbeddings(api_key="...")

# 创建向量数据库 (并在内存中存储)
vectorstore = Chroma.from_documents(documents=splits, embedding=embedding)

# 创建检索器 (Retriever)
retriever = vectorstore.as_retriever()

4.3 构建 RAG 链

from langchain.chains import create_retrieval_chain
from langchain.chains.combine_documents import create_stuff_documents_chain

# 1. 定义 RAG 的 Prompt
# {context} 是检索出来的文档片段,{input} 是用户问题
rag_prompt = ChatPromptTemplate.from_template("""
基于以下上下文回答问题:
<context>
{context}
</context>

问题:{input}
""")

# 2. 文档处理链 (把检索到的文档塞进 Prompt)
document_chain = create_stuff_documents_chain(llm, rag_prompt)

# 3. 最终检索链 (检索 + 生成)
retrieval_chain = create_retrieval_chain(retriever, document_chain)

# 4. 提问
response = retrieval_chain.invoke({"input": "这篇文章的主要结论是什么?"})
print(response["answer"])

五、持久化向量数据库

上面的代码每次运行都要重新读取 PDF 和计算向量(费钱又费时)。我们可以把向量数据库保存到硬盘。

# 保存到 ./db 目录
vectorstore = Chroma.from_documents(
    documents=splits, 
    embedding=embedding, 
    persist_directory="./chroma_db"
)

# 下次直接加载
vectorstore = Chroma(
    persist_directory="./chroma_db", 
    embedding=embedding
)

六、常见问题

Q1:Embedding 是什么?

Embedding 是把文字变成向量(数字列表)。意思相近的词,在向量空间距离更近(如"猫"和"狗"近,和"桌子"远)。这是 RAG 检索的核心原理。

Q2:中文支持怎么样?

OpenAI 的 Embedding 对中文支持不错。如果要用国产的,可以替换为 HuggingFace 或 智谱AI 的 Embedding 类。

Q3:Token 限制?

RAG 的好处就是不需要把整本书发给 AI,只发相关的几段,大大节省了 Token。


七、小结

RAG 流程

Document (文档)

Splitter (切分)

Embedding (向量化)

VectorStore (向量库)

User Question

Retriever (检索)

Prompt (问题+上下文)

LLM (生成)

Answer

关键要点

  1. LangChain 是胶水,把 LLM 和各种工具粘在一起。
  2. LCEL (|) 语法让代码链条清晰可见。
  3. RAG 是目前企业应用 LLM 最主流的模式。

八、课后作业

  1. 多文档问答:修改代码,支持读取一个文件夹下所有的 .txt.pdf 文件,构建一个更强大的知识库。
  2. 历史记忆:查阅 create_history_aware_retriever,给 RAG 加上对话历史记忆功能,让它能理解"第二个结论是什么"这种指代性问题。
  3. 换模型:尝试接入国内大模型(如文心、通义),通常只需要更换 ChatOpenAI 为对应的类(需安装对应 SDK)。

下节预告

Day 77:计算机视觉 (OpenCV) 基础 - 文字处理腻了?明天我们玩点视觉的。教你用 Python 控制摄像头,识别人脸!


系列导航

  • 上一篇:Day 75 - AI应用OpenAI
  • 下一篇:Day 77 - 计算机视觉OpenCV(待更新)
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐