【大模型开发】学习笔记一:RAG & LangChain 实战核心笔记

一、 核心概念修正(专门针对你的薄弱点)

1. Embedding(嵌入):是"翻译官",不是 API Key

  • ❌ 误区:以为是把 API Key 嵌进去,或者是简单的插入操作。

  • ✅ 正解 :Embedding 是将**人类语言(文字)转化为计算机语言(向量/数字列表)**的过程。

  • 💡 实战理解

    • 计算机看不懂"苹果",但 Embedding 模型把它变成 [0.01, -0.5, ...]

    • 计算机通过计算两个向量的**距离(余弦相似度)**来判断意思像不像。

    • 注意 :入库(Indexing)和查询(Query)必须使用同一个 Embedding 模型,否则就像一个说英语一个说日语,完全鸡同鸭讲。

2. 数据处理的不对称性:文档要切,问题不切

这是你之前容易混淆的地方,这个流程图一定要刻在脑子里:

  • 📚 文档处理流程(Indexing)

    Load (加载) -> Split (切分) -> Embed (向量化) -> Store (入库)

    • 为什么要切? 为了突破 Token 限制,更为了语义聚焦(防止长文稀释了关键信息)。
  • ❓ 用户提问流程(Retrieval)

    User Query -> No Split (不切分) -> Embed (向量化) -> Search (检索)

    • 为什么不切? 用户的问题通常很短(如"怎么报销?"),如果切成"怎么"、"报销",语义就碎了,根本搜不到准的东西。

二、 LangChain 代码核心逻辑(必背代码)

1. VectorStore vs. Retriever(仓库与接口)

  • VectorStore (Chroma/FAISS) :是底层的仓库。负责存数据、算数学距离。

  • Retriever :是上层的接口。LangChain 的 Chain 只认 Retriever,不认具体的库。

  • 🔑 关键代码(必考)

    复制代码
    # 1. 只是建库
    vectorstore = Chroma.from_documents(docs, embedding)
    
    # 2. 必须转换!变成标准接口,并设置只取前 k 个
    # .as_retriever() 是连接底层库和上层链的桥梁
    retriever = vectorstore.as_retriever(search_kwargs={"k": 3})
    
    # 3. 传入 Chain
    chain = RetrievalQA.from_chain_type(llm=llm, retriever=retriever)

2. RAG 的 Prompt 结构

RAG 实际上是在做一个**"填空题"**。

  • {context} :填入从 retriever 找回来的文档片段(LangChain 自动帮你拼成字符串)。

  • {question}:填入用户的提问。

  • 防幻觉咒语:在 Prompt 里必须写"请严格基于 Context 回答,如果不知道就说不知道"。


三、 实战避坑与调优指南

1. 数据清洗(Garbage In, Garbage Out)

  • 痛点 :检索出的内容包含 <div>、乱码。

  • 解决:必须在**入库前(Indexing 阶段)**处理。

  • 后果:不清洗会浪费 Token,且让 Embedding 向量变脏(搜"样式"搜出一堆 HTML 标签)。

2. 检索结果为"空"或"不准"的排查路径

当 LLM 说"我不知道"时,按这个顺序查:

  1. 查 Embedding:模型是不是选错了?中文用了英文模型?

  2. 查 K 值k=3 是不是太少?导致正确答案排在第 4 位被丢弃了?

  3. 查切分 (Chunking):切分块是不是太小,导致语义不完整?

  4. 查距离阈值 (Threshold):是不是设置了必须相似度 > 0.8,但实际文档只有 0.75?

3. 上下文窗口与"中间丢失"

  • 原理:大模型记性有限(Context Window)。

  • 现象Lost in the Middle。如果你贪心塞入 20 个文档,模型往往只看头和尾,忽略中间的内容。

  • 策略少即是多。精准的 Top-5 往往比 杂乱的 Top-20 效果好。


四、 面试/工作速查表(Cheat Sheet)

术语 核心作用 一句话解释
Embedding 向量化 把字变成数字,用来算距离。
Cosine Similarity 算距离 0度(1.0)=一样;90度(0.0)=无关。RAG 靠它找相似。
Splitter 切分器 把长书切成小段,为了语义聚焦和省 Token。
VectorStore 向量库 存向量的数据库(如 Chroma),支持语义搜索。
Retriever 检索器 LangChain 的标准接口,负责去库里捞数据。
Hallucination 幻觉 模型胡说八道。RAG 通过提供 Context 来抑制它。

五、代码实战

在代码里模拟一个"公司内部文档"。你只需要打开你的 IDE(PyCharm 或 VS Code),新建一个 rag_demo.py 文件,然后跟着我一步步来。

第一步:环境准备(装包)

在你的终端(Terminal)里运行这行命令。这相当于把"厨具"都买齐:

复制代码
pip install langchain langchain-openai chromadb
  • langchain: 框架本体。

  • langchain-openai: 用来调 OpenAI 的模型和 Embedding。

  • chromadb: 那个轻量级的向量数据库(Vector Store)。


第二步:编写代码(复制并理解)

rag_demo.py

复制代码
import os
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from langchain_community.vectorstores import Chroma
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.chains import RetrievalQA
from langchain.docstore.document import Document

# ==========================================
# 0. 配置密钥 (把这里换成你的 OpenAI Key)
# ==========================================
os.environ["OPENAI_API_KEY"] = "sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

# ==========================================
# 1. 准备数据 (模拟加载数据的过程)
# ==========================================
# 假设这是我们公司的内部 Wiki,大模型绝对没见过
raw_text = """
【公司零食柜管理条例】
1. 每天下午 3 点开放零食柜。
2. 每个人每天限领 2 包辣条,严禁多拿。
3. 如果发现有人偷吃老板的奥利奥,罚款 50 元。
4. 只有周五才提供免费的可乐。
"""

# 把纯文本包装成 LangChain 的 Document 对象
docs = [Document(page_content=raw_text)]

# ==========================================
# 2. 切分数据 (Splitting)
# ==========================================
# 咱们刚才学的:为了防止语义稀释和超长,要切!
text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=100,  # 每块大概 100 个字符
    chunk_overlap=10 #稍微重叠一点,防止切断了关键句子
)
split_docs = text_splitter.split_documents(docs)

print(f"✅ 数据切分完成,共切成了 {len(split_docs)} 个片段")

# ==========================================
# 3. 向量化与入库 (Embedding & VectorStore)
# ==========================================
print("🔄 正在将文本转化为向量并存入 Chroma 数据库...")

# 定义 Embedding 模型 (翻译官)
embedding_model = OpenAIEmbeddings()

# 创建向量库 (Chroma)
# 这一步会自动调用 embedding_model 把上面的 split_docs 变成向量存进去
vectorstore = Chroma.from_documents(
    documents=split_docs, 
    embedding=embedding_model
)

# ==========================================
# 4. 构建检索器与 RAG 链 (The Chain)
# ==========================================
# 关键一步:把 仓库(VectorStore) 变成 接口(Retriever)
retriever = vectorstore.as_retriever(search_kwargs={"k": 2}) # 咱们只找最相关的2条

# 定义大模型 (大脑)
llm = ChatOpenAI(model_name="gpt-3.5-turbo")

# 组装 RAG 链
qa_chain = RetrievalQA.from_chain_type(
    llm=llm, 
    retriever=retriever
)

# ==========================================
# 5. 提问测试 (Run)
# ==========================================
question = "我想喝可乐,什么时候去拿?"
print(f"\n❓ 用户提问: {question}")

# 启动链
result = qa_chain.invoke(question)

print(f"🤖 AI 回答: {result['result']}")

# 再问一个如果不查库绝对不知道的问题
question_2 = "偷吃奥利奥怎么罚?"
print(f"\n❓ 用户提问: {question_2}")
result_2 = qa_chain.invoke(question_2)
print(f"🤖 AI 回答: {result_2['result']}")

第三步:代码深度拆解(带你读懂每一行)

虽然代码跑起来了,但咱们得知道它是怎么对应理论的:

1. 那个 Document 对象是啥?
复制代码
docs = [Document(page_content=raw_text)]

LangChain 不直接处理字符串,它喜欢把文本封装成 Document 类。你可以把这个想象成给你的文本穿了一层"制服",方便后续处理。

2. RecursiveCharacterTextSplitter 里的参数
复制代码
chunk_size=100, chunk_overlap=10
  • 这对应咱们考题里的**"切分"**。

  • overlap=10 是个实战技巧:比如一句话是"严禁多拿辣条",如果不重叠,可能切成"严禁多拿"和"辣条",意思就断了。重叠能保留一点上下文。

3. 最神奇的 Chroma.from_documents
复制代码
vectorstore = Chroma.from_documents(documents=split_docs, embedding=embedding_model)

这行代码背后干了三件累活

  1. 调用 OpenAI 接口,把你切好的每一段话变成向量 [0.1, 0.2...]

  2. 在内存里建一个简单的数据库。

  3. 把向量和原文都存进去,建立索引。

4. 那个 as_retriever
复制代码
retriever = vectorstore.as_retriever(search_kwargs={"k": 2})

这就是你笔记里记的"接口转换"。如果不写这行,Chain 就不知道怎么跟数据库说话。k=2 意味着每次只给大模型看 2 条最相关的规定,不多给,防止它眼花。


第四步:运行预期结果

当你运行代码后,控制台应该会输出类似这样的内容:

复制代码
✅ 数据切分完成,共切成了 4 个片段
🔄 正在将文本转化为向量并存入 Chroma 数据库...

❓ 用户提问: 我想喝可乐,什么时候去拿?
🤖 AI 回答: 根据规定,只有周五才提供免费的可乐。

❓ 用户提问: 偷吃奥利奥怎么罚?
🤖 AI 回答: 如果发现偷吃老板的奥利奥,需要罚款50元。

GPT-3.5 根本不知道你们公司的零食柜规定,但通过 RAG,它准确地说出了"周五"和"罚款50元"。这就是 RAG 的魔力。


💡 小作业

试着改两个地方,体验一下讲过的"坑":

  1. 修改数据 :把 raw_text 里的"罚款 50 元"改成"奖励一朵小红花"。重新运行,看看 AI 会不会改口?(验证实效性)

  2. 制造幻觉 :把 k=2 改成 k=1,然后问一个需要结合两条规则才能回答的问题(如果有的话),或者把数据里的关键词改得隐晦一点,看看能不能搜到。

相关推荐
蒸蒸yyyyzwd2 小时前
DDIA学习笔记
笔记·学习
2501_901147832 小时前
学习笔记:基于摩尔投票法的高性能实现与工程实践
笔记·学习·算法·性能优化
春日见2 小时前
window wsl环境: autoware有日志,没有rviz界面/ autoware起不来
linux·人工智能·算法·机器学习·自动驾驶
新新学长搞科研2 小时前
【智慧城市专题IEEE会议】第六届物联网与智慧城市国际学术会议(IoTSC 2026)
人工智能·分布式·科技·物联网·云计算·智慧城市·学术会议
❀͜͡傀儡师2 小时前
基于大语言模型的简历分析和模拟面试系统
人工智能·语言模型·面试
是小蟹呀^2 小时前
Focal Loss:解决长尾图像分类中“多数类太强势”的损失函数
人工智能·机器学习·分类
马拉AI2 小时前
VAE不再必要?北大PixelGen:像素扩散反超Latent Diffusion,重塑生成新范式
人工智能·计算机视觉
量子-Alex2 小时前
【大模型技术报告】Seed-Thinking-v1.5深度解读
人工智能·算法
愚者游世2 小时前
Opencv知识点大纲
人工智能·opencv·计算机视觉