RAG 开发‑01 LangChain 简介 笔记
1. LangChain 基础介绍
- 诞生:由 Harrison Chase 于2022 年 10 月创建
- 定位:围绕大语言模型 LLM 构建的 Python 第三方开发框架
- 关键点:LangChain 本身不开发大模型
- 核心理念:
- 为各式各样 LLM 提供统一通用接口
- 将 LLM 相关各类组件 “链接” 串联起来
- 降低复杂 LLM 应用的开发难度,快速搭建 LLM 业务应用
- 地位:做 RAG 检索增强生成的主力开发框架
2. LangChain 六大核心模块
表格
| 模块 | 作用 |
|---|---|
| Prompts | 提示词优化,提示词工程(模板、Few‑Shot 等) |
| Models | 统一调用各类大模型(通义千问、GPT、本地 Ollama 等) |
| History | 会话记忆,管理聊天历史记录,实现多轮对话 |
| Indexes | 文档索引,文档加载、切分、向量化、文档分析管理,RAG 核心模块 |
| Chains | 执行链,把多个组件拼接串联,按流水线顺序执行业务逻辑 |
| Agent | 智能体,让大模型自主思考、调用工具、完成复杂任务 |
3. 总结
- LangChain 是 LLM 业务开发的集大成 Python 库,提供全套开箱即用 API。
- 覆盖能力:提示词工程、模型调用、会话记忆、文档处理、链式执行、Agent 智能体。
- 学习路径:后续 RAG 开发全部基于 LangChain 框架完成。
通俗理解
不用 LangChain:自己手写代码处理提示词、文档分割、向量库调用、拼接消息,全部从零写。 使用 LangChain:直接调用封装好的 API,把各个组件 “拼接链接”,快速实现 RAG、聊天机器人、智能体。
RAG 开发‑02 LangChain 的环境部署 笔记
1、需要安装的包
安装命令(推荐使用清华镜像源,下载更快)
bash
pip install langchain langchain-community langchain-ollama dashscope chromadb -i https://pypi.tuna.tsinghua.edu.cn/simple表格
| 包名 | 作用 |
|---|---|
| langchain | LangChain 核心包,基础能力 |
| langchain‑community | 社区扩展包;对接阿里云通义千问等第三方模型需要该包 |
| langchain‑ollama | Ollama 对接包,调用本地 Ollama 部署大模型 |
| dashscope | 阿里云通义千问官方 Python SDK |
| chromadb | 轻量级本地向量数据库,RAG 用来存储向量 |
2、安装校验
- 命令行输入
python进入 python 交互环境 - 执行导入:
python
运行
import langchain没有报错代表环境安装成功。
3、常见小提示
- 镜像源
-i https://pypi.tuna.tsinghua.edu.cn/simple,解决国内 pip 下载慢、超时问题。 - 建议使用虚拟环境,防止包版本冲突。
- 版本:课程使用
langchain‑1.2.1、langchain‑community‑0.4.1。 - 导入不报错不等于全部功能可用,后续用到对应模块缺包时再补装。
RAG 介绍 课程笔记
一、什么是 RAG
RAG(Retrieval‑Augmented Generation)检索增强生成公式:RAG = 检索技术 + LLM 提示
含义:从外部数据源检索相关信息,补充给大模型,修正、完善模型回答。
二、原生大模型存在 4 大痛点
- 知识滞后:模型训练完成后知识固定,不会自动更新
- 领域知识不足:训练数据多为公开互联网数据,缺少企业内部、专业私有知识
- 幻觉问题:输出看起来合理、实际错误的编造内容
- 数据安全:私有内部数据不能直接喂给公有大模型
✅ RAG 对应的解决能力:
- 加载私有 / 领域知识库
- 支持实时最新文档
- 减少幻觉,降低生成不确定性
- 提升数据安全性
对比微调 Fine‑tuning:RAG不需要重训模型,只更新知识库,成本更低、迭代更快。
三、RAG 两条工作主线
离线准备线(索引 Indexing,知识库预处理):提前执行,一次处理多次使用
文档/私有知识加载 → 文本分割(chunk) → 向量化(Embedding) → 存入向量数据库在线服务线(检索 + 生成,用户提问时实时跑):用户每一次问答都会走
用户提问 → 检索环节 → Prompt融合(问题+检索到的上下文) → LLM生成回答
四、RAG 三大标准阶段
1. 索引阶段 Indexing(离线)
- 加载各类文档文件
- 提取文档文本内容
- 文本切分,生成文本块
chunk - 对 chunk 做 Embedding 文本向量化
- 将向量 + 原始文本存入向量数据库
2. 检索阶段 Retriever(在线)
- 用户问题
query做向量化 - 在向量库做相似度匹配,取出最相似的
top_k个文本块
3. 生成阶段 Generation(在线)
- 把检索出来的上下文片段 + 用户原始问题,拼接组装到 Prompt
- 将完整 Prompt 交给大模型,输出答案
五、核心本质
大模型本质只做:输入→输出。RAG 的本质:在输入大模型之前做加工,把检索拿到的参考资料塞到 prompt 输入里,不给模型凭空记忆的机会。
六、RAG 核心价值
- 解决知识时效性:接入最新文档,不用重训模型,回答与时俱进
- 降低大模型幻觉:回答依托检索到的真实资料,减少编造
- 成本优于微调:更新知识只改知识库,不用训练权重,效率高
- 支持私有内部知识库,保护业务数据
面试简答版(可以背)
RAG 分为离线索引、在线检索、生成三个阶段。离线把文档加载、切分、向量化存入向量库;用户提问时,问题向量化检索相似片段,把片段和问题一起封装进 Prompt 交给 LLM 输出。主要解决大模型知识过时、领域知识缺失、幻觉问题,对比微调不需要训练模型,成本更低。
RAG 开发‑04 向量的基础概念笔记
一、向量库在 RAG 中的位置
RAG 分为离线流程(索引)、在线流程(检索 + 生成)两大阶段,向量库是核心存储节点。
- 离线流程(索引阶段)知识 / 文档信息 → 向量嵌入(向量化) → 存入向量库
文档处理链路:知识库 (书籍 / 文档 / 报告) → 提取文本字符串 → 切分 chunk 文本块 → 向量嵌入 → 写入向量库
- 在线流程(检索 + 生成阶段)用户提问 → 向量嵌入(向量化) → 向量库做相似度匹配
用户问题链路:用户输入问题 → 向量化得到问题向量 → 和向量库内向量做相似匹配,召回 Top‑K 相关文本块 → 把原始问题 + 召回参考片段组装成 Prompt → 交给大模型 LLM 输出最终回答。
二、向量 (Vector) 是什么
向量:文本的数学身份证把一段文本的语义信息,转换成一串固定长度数字列表,让计算机可以读懂语义,做相似度计算。
- 作用:让计算机判断两段文字是不是同一个意思,不看字面,看语义。
- 示例:
- “如何快速学习 RAG”
- “RAG 如何快速学会” 两句话字面不一样,语义一致,生成出来的向量数字序列很接近。
三、向量嵌入(生成向量)
- 向量嵌入:文本→向量的转换过程依靠文本嵌入模型完成,例:
text‑embedding‑v1。
原理:深度学习模型,抽取文本语义特征,输出固定长度数字序列。
四、向量相似度计算:余弦相似度
拿到两段文本的向量,使用余弦相似度算法,计算语义相似程度。
- 相似度取值范围:0~1,越接近 1 代表语义越相似。 例子:
- A:如何快速学打篮球 → [0.2,0.5,0.8]
- B:打篮球怎么学得快 → [0.18,0.52,0.79]
- C:运动后吃什么好呢 → [0.9,0.1,0.2] 计算结果:
- A 与 B 相似度:0.999789(语义高度接近)
- A 与 C 相似度:0.361446(语义不相关)
五、向量维度
向量维度:代表描述文本的抽象语义特征数量,每一维数字代表文本在该语义特征上的得分 / 强度。 举例:
- 3 维向量:情绪、动作、倾向 3 个特征
- 1536 维向量 (text‑embedding‑v1 输出):1536 个抽象语义特征
维度权衡
- ✅维度越高:保存语义信息越丰富,语义匹配精度越高
- ❌维度越高:存储、计算、检索开销变大,性能压力上升
工程选择:精度和性能之间做权衡,1536 维是工业常用选择
六、核心知识点总结
- 向量:文本语义转为固定长度数字数组,计算机用来做语义比对。
- 向量生成(嵌入):文本嵌入模型(text‑embedding‑v1)。
- 向量比对:余弦相似度算法,数值越靠近 1 语义越像。
- 向量维度:语义特征数量;维度↑精度↑,存储计算开销↑;1536 维常用。
- RAG 完整链路:文档加载→切分 chunk→embedding 向量化→入库;用户 query 向量化→向量库相似度检索召回→拼接 prompt→LLM 生成答案。
⭐面试简答版(方便背诵)
问:什么是文本向量 /embedding? 答:文本向量是文本的数学身份证,通过嵌入模型把文本语义转为定长数字列表。语义相近文本向量数值接近,我们使用余弦相似度计算向量相似度。向量维度代表语义特征数量,维度越高语义表达越强,但存储计算成本上升。在 RAG 中,文档切分 chunk 后转向量存入向量库;用户查询也转向量,检索召回语义相关片段,辅助大模型回答。
余弦相似度 课程笔记
一、概念
余弦相似度:忽略向量长度,只看向量在高维空间的方向夹角,夹角越小,向量越相似。
RAG 场景:文本会转为向量,余弦相似度用来判断两段文本语义是否相近。
- 值范围:
[-1,1]1:方向完全相同(最相似)0:方向垂直,完全无关-1:方向完全相反
二、公式
\(cosine\ similarity(\vec A,\vec B)=\frac{\vec A \cdot \vec B}{||\vec A|| \times ||\vec B||}\)
- 点积(分子):两个向量同维度相乘,全部累加
\(dot = A_0*B_0 + A_1*B_1 + ...+A_n*B_n\) 2.模长(分母部分):单个向量每个维度平方求和,再开根号
\(||vec||=\sqrt{vec_0^2+vec_1^2+...+vec_n^2}\) 3. 余弦相似度 = 点积 ÷ (向量 A 模长 × 向量 B 模长)
示例
向量 A=[0.5,0.5],向量 B=[0.7,0.7]
- 点积 =
0.5*0.7 + 0.5*0.7 = 0.7 - A 模长 = \(\sqrt{0.5^2+0.5^2}\)
- B 模长 = \(\sqrt{0.7^2+0.7^2}\)
- 余弦相似度 = \(0.7 \div (\sqrt{0.5^2+0.5^2} * \sqrt{0.7^2+0.7^2}) = 1.0\),代表方向完全一致。
三、RAG 中的意义
文本 Embedding 之后得到向量,余弦相似度用来做向量检索,找出知识库中和用户问题语义最接近的片段。只关心语义方向,不关心向量的长度大小。
四、完整可运行代码
python
运行
import numpy as np def get_dot(vec_a, vec_b): """计算2个向量的点积,2个向量同维度数字乘积之和""" if len(vec_a) != len(vec_b): raise ValueError("2个向量必须维度数量相同") dot_sum = 0 for a, b in zip(vec_a, vec_b): dot_sum += a * b return dot_sum def get_norm(vec): """计算单个向量的模长:对向量的每个数字求平方在求和在开根号""" sum_square = 0 for v in vec: sum_square += v * v # numpy sqrt函数完成开根号 return np.sqrt(sum_square) def cosine_similarity(vec_a, vec_b): """余弦相似度:2个向量的点积 除以 2个向量模长的乘积""" result = get_dot(vec_a, vec_b) / (get_norm(vec_a) * get_norm(vec_b)) return result if __name__ == '__main__': vec_a = [0.5, 0.5] vec_b = [0.7, 0.7] vec_c = [0.7, 0.5] vec_d = [-0.6, -0.5] print("ab:", cosine_similarity(vec_a, vec_b)) print("ac:", cosine_similarity(vec_a, vec_c)) print("ad:", cosine_similarity(vec_a, vec_d))运行输出
plaintext
ab: 0.9999999999999999 ac: 0.9863939238321437 ad: -0.9961537343407902ab 输出接近 1,代表向量 A 和 B 同向;ad 接近‑1 代表方向几乎相反。
易错坑点
代码中括号不能写错:
python
运行
# ❌错误写法,运算优先级出错 result = get_dot(vec_a, vec_b) / get_norm(vec_a) * get_norm(vec_b) # ✅正确写法,分母是两个模长相乘,必须括号包裹 result = get_dot(vec_a, vec_b) / (get_norm(vec_a) * get_norm(vec_b))RAG 开发‑06 LangChain 调用大语言模型 笔记
⭐星级:★★★ 分值:10 分
一、LangChain 三类模型
LangChain 提供统一接口,支持 3 大类模型:
- LLMs(大语言模型)Transformer 架构,大参数量,面向文本生成;输入字符串,输出字符串。
注意:
qwen‑max属于 LLM;qwen3‑max属于 ChatModel 聊天模型,不要混用。
Chat Models(聊天模型)在 LLM 基础上专门优化对话轮次交互,面向聊天对话场景。
Embeddings Models(嵌入模型)接收文本输入,输出文本向量,用于 RAG 检索。
第三方模型实现大多放在
langchain_community包。 Ollama 本地模型:独立包langchain_ollama。
二、两个模型源下载地址
- HuggingFace:https://huggingface.co/models
- ModelScope 魔搭:https://modelscope.cn/models
三、核心 API
model.invoke(input="你的问题"):同步调用模型,传入字符串 prompt,返回模型生成文本。
四、可运行完整代码
1)调用阿里云通义千问 LLM(qwen‑max)
前置:安装依赖
pip install langchain‑community dashscope环境变量配置:DASHSCOPE_API_KEY阿里云 API‑KEY
python
运行
# 02LangChain访问阿里云通义千问大模型.py from langchain_community.llms.tongyi import Tongyi # 实例化LLM对象,qwen‑max是大语言模型,不要传qwen3‑max(聊天模型) model = Tongyi(model="qwen-max") # invoke方法发起提问 res = model.invoke(input="你是谁呀能做什么?") # 打印结果 print(res)2)调用 Ollama 本地 LLM(qwen3:4b)
前置:
- 安装依赖
pip install langchain‑ollama- 本地 Ollama 软件必须启动;执行过
ollama pull qwen3:4b拉取模型
python
运行
# 03LangChain访问Ollama本地模型.py from langchain_ollama import OllamaLLM # 实例化本地Ollama模型对象 model = OllamaLLM(model="qwen3:4b") # invoke调用 res = model.invoke(input="你是谁呀能做什么?") print(res)五、关键注意点
- 包来源区分
- 通义千问 LLM:
langchain_community.llms.tongyi.Tongyi - Ollama 本地 LLM:
langchain_ollama.OllamaLLM
- 模型名称区分:
qwen‑max:LLM 大语言模型;qwen3‑max:Chat 聊天模型,二者不能混用。 - Ollama 运行前提:Ollama 服务后台运行,模型已经提前 pull 下载,否则报错。
- 统一调用方式:实例化模型对象后,一律用
.invoke(input="xxx")做推理。
面试简答记忆点
LangChain 对各种大模型做了封装,对外提供统一 invoke 接口; 云模型来自 langchain_community,Ollama 本地模型来自 langchain_ollama; LLM 输入输出都是原始字符串,ChatModel 是消息对象。
调用大模型(LangChain 视角)
调用大模型核心就两步:
- 创建大模型实例:指定模型、api‑key、参数,完成模型对象初始化
- 调用
invoke()方法执行:传入输入内容,发起请求,拿到模型返回结果
代码示例
python
运行
from langchain_openai import ChatOpenAI # 第一步:创建大模型实例 llm = ChatOpenAI( model="gpt‑3.5‑turbo", api_key="你的key", temperature=0.7 ) # 第二步:invoke() 执行调用,传入prompt res = llm.invoke("讲一个简短小故事") print(res.content)补充小知识点
invoke()是 LangChain 标准统一调用接口,不管是 chat 模型、普通 LLM、Chain 都用invoke()- 返回值不是字符串,是消息对象,需要
.content取出文本结果 - 老版本还有
predict()/__call__,现在官方推荐统一使用invoke()
07 LangChain 模型的流式输出 笔记
核心知识点 ⭐⭐⭐(面试高频)
LangChain 1.0+ 基于Runnable统一接口,几乎所有组件(模型、prompt、chain、检索器)都支持下面两套方法:
invoke():同步一次性调用,等待模型全部生成完毕,一次性返回完整结果。- 优点:简单,直接拿到完整字符串
- 缺点:用户需要等待全部生成,体验像卡住,网页聊天框不会一个字一个字蹦出来
stream():流式输出,逐段返回生成内容(chunk 块),返回迭代器,可以 for 循环遍历。- 优点:模拟 ChatGPT 打字效果,边生成边展示,用户体感更快
- 缺点:需要循环接收每一小段文本,代码多一层 for 循环
关键概念:
chunk:模型返回的一小段碎片文本,多次 chunk 拼接起来才是完整回答。
print 参数解释
python
运行
print(chunk, end="", flush=True)end="":打印不要换行,文字连续输出flush=True:强制刷新缓冲区,立刻把文字打印到控制台,不要缓存攒一堆再输出
模型区分
qwen‑max:LLM 大语言模型,输出纯文本字符串,适合本示例qwen3‑max:Chat 聊天模型,返回消息对象,.content拿文本,不要混用
流程对比
- invoke 两步:①创建模型实例 ②
invoke()→拿到完整结果 - stream 两步:①创建模型实例 ②
stream()→拿到迭代器,for 循环读取每一块 chunk
注意:stream 返回的不是最终字符串,是可迭代对象,必须 for 循环遍历读取。
完整可运行代码(旧版 community,课程原版,能跑但是会有弃用警告)
python
运行
# 04LangChain的流式输出.py from langchain_community.llms.tongyi import Tongyi # 第一步:创建模型实例 model = Tongyi(model="qwen-max") # 第二步:调用stream 获取流式迭代器 res = model.stream(input="你是谁呀能做什么?") # for循环遍历迭代器,取出每一块chunk for chunk in res: print(chunk, end="", flush=True)✨新版无警告代码(langchain‑alibaba,推荐以后写这个)
python
运行
# 先安装依赖:pip install langchain-alibaba from langchain_alibaba import Tongyi # 第一步:创建模型实例 model = Tongyi(model="qwen-max") # 第二步:stream流式调用 res = model.stream(input="你是谁呀能做什么?") # 循环打印每一个片段 for chunk in res: print(chunk, end="", flush=True)invoke 和 stream 对照完整示例(放一起对比记忆)
python
运行
# 04LangChain的流式输出.py from langchain_community.llms.tongyi import Tongyi model = Tongyi(model="qwen-max") # -------- invoke 一次性输出 -------- print("==== invoke一次性输出 ====") result = model.invoke("简单介绍python") print(result) # -------- stream 流式打字机输出 -------- print("\n==== stream流式输出 ====") stream_res = model.stream("简单介绍python") for chunk in stream_res: print(chunk, end="", flush=True)面试简答背诵
问:LangChain invoke 和 stream 区别? 答:
invoke():一次性调用,等待模型全部生成完成,返回完整结果;适合后台脚本处理。stream():流式调用,返回迭代器,循环拿到每一段 chunk,实现边生成边输出;适合前端聊天界面,实现打字效果。- 两者是 Runnable 接口的标准方法,模型、Chain、提示词模板都统一支持这两个 API。
拓展小补充(还有 batch 方法)
batch([问题1,问题2]):批量传入多个问题,一次性批量调用多个请求。
Runnable 三大方法:
invoke(单个)、stream(流式)、batch(批量)。
08 LangChain 调用聊天模型 ChatModels 笔记
⭐⭐⭐⭐ 重点:LLM(大语言模型) vs ChatModel(聊天模型)
- LLM(Tongyi):输入输出都是纯字符串,
model="qwen‑max" - ChatModel(ChatTongyi):输入输出是消息对象 Message,
model="qwen3‑max",专门用于多轮对话,是现在开发主流。
三种消息对象(langchain_core.messages)
表格
| 消息类 | 对应 OpenAI 角色 | 作用 |
|---|---|---|
SystemMessage | system | 系统提示,设定 AI 角色、规则、背景,放在消息列表最前面 |
HumanMessage | user | 用户发送给 AI 的问题 |
AIMessage | assistant | AI 历史返回的回答,用于多轮上下文记忆 |
messages 是列表,按对话顺序存放消息,实现多轮对话记忆。 ChatModel 返回的 chunk 不是字符串对象,要用
.content属性拿到文本内容。
Runnable 接口同样生效
聊天模型同样支持三大方法:
invoke(messages):一次性返回完整消息对象stream(messages):流式迭代返回 chunk,chunk.content拿文本batch([msg1,msg2]):批量请求
注意坑:写
print(chunk)会打印对象;必须写print(chunk.content),否则输出一堆对象描述文本。
代码 1:仅 HumanMessage(单轮对话,课程原版)
文件名:05LangChain调用聊天模型.py
python
运行
# 课程原版(会有弃用警告,可以跑) from langchain_community.chat_models.tongyi import ChatTongyi from langchain_core.messages import HumanMessage # 1.初始化聊天模型 qwen3‑max是聊天模型 chat_model = ChatTongyi(model="qwen3-max") # 2.构造消息列表 messages = [ HumanMessage(content="给我写一首唐诗") ] # 3.stream流式输出 res = chat_model.stream(input=messages) for chunk in res: # .content获取文本内容 print(chunk.content, end="", flush=True)代码 2:SystemMessage + HumanMessage(设定 AI 角色)
python
运行
from langchain_community.chat_models.tongyi import ChatTongyi from langchain_core.messages import HumanMessage, SystemMessage chat_model = ChatTongyi(model="qwen3-max") messages = [ SystemMessage(content="你是一名来自边塞的诗人"), HumanMessage(content="给我写一首唐诗") ] res = chat_model.stream(input=messages) for chunk in res: print(chunk.content, end="", flush=True)代码 3:SystemMessage + HumanMessage + AIMessage(模拟多轮上下文)
AIMessage 用来填入 AI 历史回答,让模型参考上一轮输出格式、内容。
python
运行
from langchain_community.chat_models.tongyi import ChatTongyi from langchain_core.messages import HumanMessage, SystemMessage, AIMessage chat_model = ChatTongyi(model="qwen3-max") messages = [ SystemMessage(content="你是一名来自边塞的诗人"), HumanMessage(content="给我写一首唐诗"), AIMessage(content="锄禾日当午,汗滴禾下土,谁知盘中餐,粒粒皆辛苦。"), HumanMessage(content="按照你上一个回复的格式,再写一首唐诗。") ] res = chat_model.stream(input=messages) for chunk in res: print(chunk.content, end="", flush=True)✨新版无弃用警告代码(langchain‑alibaba,推荐工程使用)
python
运行
# pip install langchain-alibaba from langchain_alibaba import ChatTongyi from langchain_core.messages import HumanMessage, SystemMessage, AIMessage chat_model = ChatTongyi(model="qwen3-max") messages = [ SystemMessage(content="你是一名来自边塞的诗人"), HumanMessage(content="给我写一首唐诗") ] res = chat_model.stream(input=messages) for chunk in res: print(chunk.content, end="", flush=True)invoke 完整示例(一次性返回,对比记忆)
python
运行
from langchain_alibaba import ChatTongyi from langchain_core.messages import HumanMessage chat_model = ChatTongyi(model="qwen3-max") messages = [HumanMessage(content="简单介绍LangChain")] # invoke返回完整消息对象 resp_msg = chat_model.invoke(input=messages) # .content取出字符串 print(resp_msg.content)📝面试简答背诵
Q:LLM 和 ChatModel 有什么区别?
- LLM 输入输出都是普通字符串,适合简单单轮调用;
- ChatModel 输入输出是消息对象(SystemMessage/HumanMessage/AIMessage),天然支持多轮对话上下文;
- ChatModel 调用返回的结果对象,需要读取
.content属性获取文本内容; - ChatModel 同样遵循 Runnable 接口,支持
invoke / stream / batch。
易错点总结
- ❌错误:
print(chunk),打印对象;✅正确:print(chunk.content) - 区分模型:
qwen‑max给 LLM;qwen3‑max给 ChatModel,不要混用。 - messages 是列表,顺序很重要,SystemMessage 一般放列表最前面。