Retrieval-Augmented Generation
检索增强生成,一种结合信息检索和生成模型的技术,RAG 模型通过将检索和生成两个过程结合起来,利用外部知识库来增强生成模型的能力
大致理解:
bash+-------------------+ +-------------------+ +-------------------+ | 用户输入 Query | --> | 检索器 Retriever | --> | 相关文档片段列表 | +-------------------+ +-------------------+ +-------------------+ | v +-------------------+ | 生成器 Generator | | (融合 Query 和 | | 相关文档生成答案) | +-------------------+ | v +-------------------+ | 最终生成回答 | +-------------------+
更细维度理解:
bash[用户输入 Query] | v +--------------------+ | 查询编码器 (Query Encoder) | | (BERT/Transformer等) | +--------------------+ | v (查询向量) +--------------------+ | 文档检索器 (Vector Search) | <--- [知识库文档集合的文档向量] +--------------------+ | v (Top-K 相关文档) +--------------------+ | 文档编码器 (Document Encoder) | +--------------------+ | v (文档向量) +-------------------------------------+ | 结合 Query 向量与文档向量融合 | | (有的实现会拼接文本,有的用交叉注意力)| +-------------------------------------+ | v +--------------------+ | 生成器(Seq2Seq模型,如BART、T5) | | 以 Query + 检索文档上下文为输入 | +--------------------+ | v [生成最终答案]
document.txt内容
bash第一回 灵根育孕源流出 心性修持大道生 混沌未分天地乱,茫茫渺渺无人见。自从盘古破鸿蒙,开辟从兹清浊辨。 覆载群生仰至仁,发明万物皆成善。欲知造化会元功,须看西游释厄传。 话说东胜神洲傲来国,有一座花果山,山顶一块仙石,自开天辟地以来,吸收日月精华,孕育灵气。忽一日,石裂诞生一石猴,五官俱备,四肢皆全。那猴在山中学会行走跳跃,灵明异常。山中群猴见之,皆以为王,尊为“美猴王”。 一日,众猴嬉戏水帘洞,言道:“谁敢潜入瀑布之后,吾等拜之为王。”石猴奋勇向前,纵身跃入水帘,得一洞天福地。众猴大喜,齐拜为王,美猴王自此称雄花果山。 美猴王心有所思,曰:“生老病死,实为苦事,吾欲访道求仙。”遂辞群猴,泛海而行,历尽艰辛,拜入须菩提祖师门下,得名“孙悟空”,学得长生不老之术、七十二变、筋斗云等法术,名动三界。 然因嬉闹天宫,大闹龙宫地府,被天尊压于五行山下,待唐僧西行取经,方得重见天日。后随唐僧历经九九八十一难,终成正果,封为斗战胜佛。 此正是:天不生我齐天大圣,万古如长夜。大闹天宫虽狂傲,修得正果亦称奇。 第一回 宴桃园豪杰三结义 斩黄巾英雄首立功 话说天下大势,分久必合,合久必分。周末七国分争,并入于秦。及秦灭之后,楚、汉分争,又并入于汉。 汉室自高祖斩白蛇而起,传至灵帝,政衰朝纲不振。时有黄巾贼张角作乱,号称“太平道”,率众起义,号称“苍天已死,黄天当立,岁在甲子,天下大吉”。 时有一人,姓张名飞,屠猪为业。见国难当头,感叹道:“国家多难,正宜豪杰奋起!”张飞招募乡勇,愿共讨贼。涿郡之中,有一刘备,乃中山靖王之后,性宽厚仁德,志在匡扶汉室。又有一关羽,年少壮健,义气深重,亦愿共举义旗。 三人志同道合,于桃园中设香案,焚香盟誓: “我们三人,虽异姓,愿结为兄弟。今日之后,生死与共,福祸相依。不得背义忘恩,违背此誓,天人共戮!” 于是张飞为弟,关羽为兄,刘备居中,结为异姓兄弟,世称“桃园三结义”。 三人起兵讨贼,连破黄巾,立下首功,威名渐显。
先将模型下载到本地 huggingface.io(网络太差了)
bashfrom sentence_transformers import SentenceTransformer
model = SentenceTransformer('sentence-transformers/all-MiniLM-L6-v2')
model.save("/root/local_models/all-MiniLM-L6-v2")
文档.txt --> 向量化 + 建索引 --> 检索相关片段 --> DeepSeek 生成回答
一个基本的RAG阅读文档能力并打印,
qa.run(...) 会自动:
把问题转为向量;
在 FAISS 中找最相关的文档段落;
把文档段 + 问题输入给 DeepSeek;
返回回答。
bash(venv) root@ECS-2642685781:~# python3
Python 3.12.3 (main, Jun 18 2025, 17:59:45) [GCC 13.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>
>>>
>>> from langchain_community.document_loaders import TextLoader
>>> from langchain_community.vectorstores import FAISS
>>> # from langchain_community.embeddings import HuggingFaceEmbeddings
>>> from langchain_huggingface import HuggingFaceEmbeddings
>>> from langchain.chains import RetrievalQA
>>> from langchain_openai import ChatOpenAI
>>>
>>> import os
>>>
>>> # 设置 DeepSeek API
>>> os.environ["OPENAI_API_KEY"] = "sk-your key"
>>> os.environ["OPENAI_API_BASE"] = "https://api.deepseek.com/v1"
>>>
>>> # 1. 加载文档
>>> loader = TextLoader("document.txt")
>>> docs = loader.load()
>>>
>>> # 2. 向量化(建议用 HuggingFace 本地 embedding,避免调 API 计费)
>>> embedding = HuggingFaceEmbeddings(model_name="/root/local_models/all-MiniLM-L6-v2") # 可选 model_name,如 all-MiniLM-L6-v2
>>> db = FAISS.from_documents(docs, embedding) # 将文档转为向量,建立索引数据库
>>>
>>> # 3. 构建 RAG 问答链
>>> llm = ChatOpenAI(model="deepseek-chat", temperature=0) #初始化了一个 LLM,实际调用的是 DeepSeek 模型
>>> qa = RetrievalQA.from_chain_type( # 创建了一个结合 retriever + LLM 的问答系统
... llm=llm,
... retriever=db.as_retriever()
... )
>>>
>>> # 4. 提问
>>> if __name__ == '__main__':
... question = "这篇文档主要讲了什么?"
... answer = qa.run(question)
... print(f"Q: {question}\nA: {answer}")
...
<stdin>:3: LangChainDeprecationWarning: The method `Chain.run` was deprecated in langchain 0.1.0 and will be removed in 1.0. Use :meth:`~invoke` instead.
Q: 这篇文档主要讲了什么?
A: 这篇文档主要讲了两部中国古典名著的开篇故事:
1. **《西游记》第一回**:讲述了孙悟空(美猴王)的诞生和早期经历。包括他从花果山仙石中诞生、成为猴王、为求长生不老而拜师学艺(获得七十二变、筋斗云等神通),以及因大闹天宫被压五行山下的故事。最后点明他后来跟随唐僧西天取经并修成正果。
2. **《三国演义》第一回**:讲述了东汉末年黄巾起义时期,刘备、关羽、张飞三人"桃园三结义"的故事。描述了三人因国家动乱而结为异姓兄弟,共同起兵讨伐黄巾军并立下首功的经过。
两段文字都是中国四大名著的开篇章节,分别交代了主要人物的出身和故事背景。
>>>
非RAG,直接对话大模型
bash>>> from langchain_openai import ChatOpenAI
>>> llm = ChatOpenAI(model="deepseek-chat", temperature=0)
>>>
>>> # 不依赖任何上下文或文档
>>> question = "孙悟空是怎么出生的?"
>>> answer = llm.invoke(question)
>>>
>>> print(f"[非RAG问答]\nQ: {question}\nA: {answer}")
[非RAG问答]
Q: 孙悟空是怎么出生的?
A: content='孙悟空的出生在中国古典名著《西游记》中有详细描述,其来历充满神话色彩。以下是关键情节:\n\n1. **仙石孕育** \n 孙悟空诞生于东胜神洲傲来国的花果山。山顶有一块高三丈六尺五寸(象征周天365度)、围圆二丈四尺(对应二十四节气)的**仙石**,自开天辟地以来吸收日月精华,内育仙胞。\n\n2. **石破天惊** \n 一日仙石迸裂,产出一颗石卵,见风后化作一只**石猴**(即孙悟空)。出生时双目射出金光,直冲凌霄宝殿,惊动了玉皇大帝。\n\n3. **天地异象** \n 玉帝派千里眼、顺风耳探查,得知是花果山石猴出世,认为“乃天地精华所生”,未予深究,为后续大闹天宫埋下伏笔。\n\n4. **文化寓意** \n - **反叛象征**:无父无母的设定暗喻对传统宗法秩序的挑战。 \n - **道教元素**:石头尺寸暗合天文历法,体现道教“天人合一”思想。 \n - **原型争议**:有学者认为其形象可能受印度神猴哈奴曼或中国无支祁传说影响。\n\n补充细节: \n- 吴承恩在原著第一回“灵根育孕源流出”重点描写了这一情节。 \n- 动画电影《大圣归来》等改编作品常以巨石崩裂场景致敬原著。 \n- 福建武夷山、江苏连云港等地均有所谓“孙悟空出生地”的旅游景点,但均属民间附会。\n\n这一诞生过程奠定了孙悟空超越三界、不受束缚的角色基调,成为全书反抗精神的图腾式开场。' additional_kwargs={'refusal': None} response_metadata={'token_usage': {'completion_tokens': 381, 'prompt_tokens': 7, 'total_tokens': 388, 'completion_tokens_details': None, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 0}, 'prompt_cache_hit_tokens': 0, 'prompt_cache_miss_tokens': 7}, 'model_name': 'deepseek-chat', 'system_fingerprint': 'fp_8802369eaa_prod0623_fp8_kvcache', 'id': '5fee4aa6-4704-47a2-90f5-e13c92f6ce6d', 'service_tier': None, 'finish_reason': 'stop', 'logprobs': None} id='run--6a6f1ea9-b7d4-4662-9eee-7cbdc72ca8ed-0' usage_metadata={'input_tokens': 7, 'output_tokens': 381, 'total_tokens': 388, 'input_token_details': {'cache_read': 0}, 'output_token_details': {}}
>>>
RAG,再对话大模型
bash>>> from langchain_community.document_loaders import TextLoader
>>> from langchain_community.vectorstores import FAISS
>>> from langchain_huggingface import HuggingFaceEmbeddings
>>> from langchain.chains import RetrievalQA
>>> from langchain_openai import ChatOpenAI
>>>
>>> import os
>>> os.environ["OPENAI_API_KEY"] = "sk-your key"
>>> os.environ["OPENAI_API_BASE"] = "https://api.deepseek.com/v1"
>>>
>>> # 加载文档
>>> loader = TextLoader("document.txt")
>>> docs = loader.load()
>>>
>>> # 向量化:本地模型
>>> embedding = HuggingFaceEmbeddings(model_name="/root/local_models/all-MiniLM-L6-v2")
>>> db = FAISS.from_documents(docs, embedding)
>>>
>>> # 构建 RAG QA
>>> llm = ChatOpenAI(model="deepseek-chat", temperature=0)
>>> qa = RetrievalQA.from_chain_type(
... llm=llm,
... retriever=db.as_retriever()
... )
>>>
>>> # RAG 问答
>>> question = "孙悟空是怎么出生的?"
>>> answer = qa.run(question)
>>> print(f"[RAG问答]\nQ: {question}\nA: {answer}")
[RAG问答]
Q: 孙悟空是怎么出生的?
A: 根据《西游记》第一回的描述,孙悟空的出生非常神奇:
他是由东胜神洲傲来国花果山顶的一块仙石孕育而生的。这块仙石自开天辟地以来就存在,长期吸收日月精华,孕育灵气。突然有一天,仙石迸裂,从中诞生出一只石猴。这只石猴生来就五官俱全,四肢齐备,能够行走跳跃,灵性非凡。
后来这只石猴因为勇敢地跳入水帘洞,被群猴尊为"美猴王",也就是后来的孙悟空。
>>> exit()
原pdf内容部分信息
bash 3) 更新方式分为手动更新和自动更新
手动更新: 业务流脚本列表 tab, 触发“ 更新用例关联” 即可实时更新当前项目业务流
与 devops 用例的关联状态和关联 devops 用例 id( 其他字段为实时更新--最近一次执
行时间、 执行状态)
自动更新: 每天凌晨 1:00, 平台会定时自动更新前一天的数据, 根据业务流与关联用
例的唯一性【框架 id+业务流 id+用例 id】 进行匹配并更新
bashfrom langchain_community.document_loaders import TextLoader
from langchain_community.vectorstores import FAISS
from langchain_huggingface import HuggingFaceEmbeddings
from langchain.chains import RetrievalQA
from langchain_openai import ChatOpenAI
import os
os.environ["OPENAI_API_KEY"] = "sk-your key"
os.environ["OPENAI_API_BASE"] = "https://api.deepseek.com/v1"
# # 加载文档, 从文件中读取文本内容,并封装成 LangChain 需要的文档对象(Document 列表)
# loader = TextLoader("document.txt")
# docs = loader.load()
from langchain_community.document_loaders import PyPDFLoader
loader = PyPDFLoader("自定义框架-allure类型操作手册.pdf")
docs = loader.load()
# 向量化:本地模型
embedding = HuggingFaceEmbeddings(model_name="./local_models/all-MiniLM-L6-v2") # 句子级语义嵌入 (Sentence Embedding)
db = FAISS.from_documents(docs, embedding) # 使用 FAISS 将所有向量构建为一个 内存中的向量索引(IndexFlatL2)
# 构建 RAG QA
llm = ChatOpenAI(model="deepseek-chat", temperature=0)
qa = RetrievalQA.from_chain_type(
llm=llm,
retriever=db.as_retriever()
)
# RAG 问答
question = "更新方式分为手动更新和自动更新?"
answer = qa.run(question)
print(f"[RAG问答]\nQ: {question}\nA: {answer}")
输出结果
bash/home/lixuefu/env_langchain-test/bin/python /home/lixuefu/langchain-test/rag-pdf.py
/home/lixuefu/langchain-test/rag-pdf.py:33: LangChainDeprecationWarning: The method `Chain.run` was deprecated in langchain 0.1.0 and will be removed in 1.0. Use :meth:`~invoke` instead.
answer = qa.run(question)
[RAG问答]
Q: 更新方式分为手动更新和自动更新?
A: 是的,根据提供的上下文,更新方式分为以下两种:
1. **手动更新**
- 操作路径:在「业务流脚本列表」tab中触发【更新用例关联】按钮
- 功能:实时更新当前项目的业务流与DevOps用例的关联状态、关联用例ID(其他字段如最近执行时间、执行状态也会实时更新)
2. **自动更新**
- 触发时间:每天凌晨1:00
- 规则:平台自动更新前一天的数据,根据业务流与关联用例的唯一性(框架ID+业务流ID+用例ID)进行匹配更新
> 注意:手动更新可即时生效,自动更新为定时任务。具体规则可参考“数据更新说明”中的悬浮提示。
Process finished with exit code 0
bashfrom langchain_community.document_loaders import TextLoader
from langchain_community.vectorstores import FAISS
from langchain_huggingface import HuggingFaceEmbeddings
from langchain.chains import RetrievalQA
from langchain_openai import ChatOpenAI
import os
os.environ["OPENAI_API_KEY"] = "sk-your key"
os.environ["OPENAI_API_BASE"] = "https://api.deepseek.com/v1"
# # 加载文档, 从文件中读取文本内容,并封装成 LangChain 需要的文档对象(Document 列表)
# loader = TextLoader("document.txt")
# docs = loader.load()
from langchain_community.document_loaders import PyPDFLoader
loader = PyPDFLoader("登录注册流程全梳理.pdf")
docs = loader.load()
# 向量化:本地模型
embedding = HuggingFaceEmbeddings(model_name="./local_models/all-MiniLM-L6-v2") # 句子级语义嵌入 (Sentence Embedding)
db = FAISS.from_documents(docs, embedding) # 使用 FAISS 将所有向量构建为一个 内存中的向量索引(IndexFlatL2)
# 构建 RAG QA
llm = ChatOpenAI(model="deepseek-chat", temperature=0)
qa = RetrievalQA.from_chain_type(
llm=llm,
retriever=db.as_retriever()
)
# RAG 问答
question = "假如你是一名资深测试工程师,麻烦根据文档,编写登录注册的测试用例,要求尽可能覆盖所有的场景"
answer = qa.run(question)
print(f"[RAG问答]\nQ: {question}\nA: {answer}")
bash/home/lixuefu/env_langchain-test/bin/python /home/lixuefu/langchain-test/rag-pdf.py
/home/lixuefu/langchain-test/rag-pdf.py:33: LangChainDeprecationWarning: The method `Chain.run` was deprecated in langchain 0.1.0 and will be removed in 1.0. Use :meth:`~invoke` instead.
answer = qa.run(question)
[RAG问答]
Q: 假如你是一名资深测试工程师,麻烦根据文档,编写登录注册的测试用例,要求尽可能覆盖所有的场景
A: # 登录注册测试用例
## 一、一键登录测试用例
### 1. 正常流程
- **用例1**: 首次使用一键登录功能,验证能否成功注册新账号
- **用例2**: 已注册用户使用一键登录,验证能否成功登录
- **用例3**: 验证一键登录后用户信息是否正确显示
### 2. 异常流程
- **用例4**: 网络异常情况下尝试一键登录,验证错误提示
- **用例5**: 设备不支持一键登录功能时,验证降级处理
## 二、手机短信验证码登录/注册测试用例
### 1. 正常流程
- **用例6**: 新用户使用手机号+验证码注册,验证注册流程
- **用例7**: 已注册用户使用手机号+验证码登录,验证登录流程
- **用例8**: 验证短信验证码5分钟内有效
- **用例9**: 验证短信验证码成功一次后重置计数
### 2. 异常流程
- **用例10**: 输入错误验证码,验证提示信息
- **用例11**: 使用过期验证码登录,验证提示信息
- **用例12**: 1天内连续5次发送验证码未验证,第6次需要图形验证码
- **用例13**: 输入非11位手机号,验证格式校验
- **用例14**: 输入非13/14/15/16/17/18/19开头的手机号,验证格式校验
## 三、密码登录测试用例
### 1. 正常流程
- **用例15**: 正确手机号+密码登录,验证登录成功
- **用例16**: 验证上次登录手机号自动填充功能
- **用例17**: 点击"忘记密码"跳转重置密码页
### 2. 异常流程
- **用例18**: 同一账号/设备连续6次错误密码,验证滑块验证码弹出
- **用例19**: 滑块验证通过后,验证错误计数清零
- **用例20**: 未注册账号尝试密码登录,验证提示信息
- **用例21**: 未勾选协议条款点击登录,验证晃动效果和提示
- **用例22**: 密码输入框特殊字符测试
## 四、重置密码测试用例
### 1. 正常流程
- **用例23**: 通过手机号+验证码成功重置密码
- **用例24**: 重置密码后使用新密码登录
- **用例25**: 验证上次登录手机号自动填充功能
### 2. 异常流程
- **用例26**: 同一账号/设备超过5次验证码请求,第6次需要图形验证码
- **用例27**: 输入错误图形验证码,验证提示信息
- **用例28**: 设置过短/过长密码,验证系统处理
- **用例29**: 验证码输入非6位数字,验证格式校验
## 五、安全规则测试用例
### 1. 图形验证码规则
- **用例30**: 验证1天内连续5次发送验证码未验证,第6次需要图形验证码
- **用例31**: 验证过自然天后计数重置
- **用例32**: 验证成功验证一次后计数重置
### 2. 滑块验证规则
- **用例33**: 验证同一账号/设备连续6次错误密码后弹出滑块
- **用例34**: 滑块验证通过后错误计数清零
- **用例35**: 滑块验证失败后继续计数
## 六、兼容性测试用例
- **用例36**: 不同机型测试一键登录功能
- **用例37**: 不同网络环境测试登录流程
- **用例38**: 不同操作系统版本测试滑块验证功能
## 七、性能测试用例
- **用例39**: 验证短信验证码发送响应时间
- **用例40**: 高并发场景下登录接口性能测试
- **用例41**: 滑块验证服务响应时间测试
## 八、UI/UX测试用例
- **用例42**: 验证协议条款晃动效果
- **用例43**: 验证各页面手机号输入框格式提示
- **用例44**: 验证错误提示信息的准确性和友好性
以上测试用例覆盖了文档中提到的所有业务规则、正常逻辑和异常逻辑场景,包括一键登录、短信验证码登录、密码登录、重置密码等核心功能,以及相关的安全规则和用户体验要求。
Process finished with exit code 0
「知识库 + 向量检索 + LLM 问答」的全套链路
bash| 模块 | 是否用了 | 说明 | | ------------- | ---- | ------------------- | | 文档加载 | ✅ | PDF 转文本 | | 文本向量化 | ✅ | 本地 MiniLM 模型 | | 向量索引构建(知识库) | ✅ | FAISS | | 检索器 Retriever | ✅ | `db.as_retriever()` | | 大模型生成 | ✅ | `ChatOpenAI` | | RAG 流程封装 | ✅ | `RetrievalQA` |
本文作者:lixf6
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!