G5 检索与精排
系列定位:G3 把文档送进了库,G4 保证了「切出来的东西值得被检索」。 到这一步,库是好的、块是好的,可你一定会遇到这个现象: 同一份文档、同一个问题,问法稍微一变,答案就时好时坏。 G5 把官方给的三条路逐条拆开:查询改写检索(检索前)/近似检索(检索时)/reranker 精排(检索后)。 版本基准:MindSDK 26.1.0(RAG SDK)
第一段 章前定位
这课不教你什么:
- 不教建库与灌数据(装 SDK、注册解析器/切分器、上传文档)—— 那是 G3、G4 的事。
- 不教问答编排(怎么把检索结果拼成 prompt、走哪条 Chain、开不开缓存)—— 那是 G6。
- 不给「最优 k / 最优阈值 / 该用哪个 reranker 模型」 —— ⚠️ 官方没有给过任何推荐值; 本课给的是怎么在你的数据上试出这几个值。
这课要教你什么:
检索不是「查一下」,检索是三个可以分别下手的位置。 检索前改问题(问法换角度)· 检索时改取法(取几条、卡不卡阈值、走向量还是走关键词)· 检索后改排序(把真正相关的抬到最前面)。 而官方的默认值在三个位置上都不站在你这一边 —— 这是「同一个问题有时准有时不准」的主要来源。
第二段 学习目标
- 官方的检索一共有哪几个类?各自的输入是什么、输出是什么?
Retriever的k和score_threshold官方默认值分别是多少?为什么这两个默认值会让你「答不全」和「答偏」?- 查询改写检索(
MultiQueryRetriever) 具体做了什么?官方那条「prompt 和 question 语言要一致」的提醒是为什么? - BM25 那条路(
BMRetriever/FullTextRetriever) 什么时候比向量检索管用? - 精排(
Reranker) 有哪几种、怎么选?MixRetrieveReranker和另一种有什么关系? - 换 embedding 模型时,为什么整库必须重做?
- 官方那条「必须在
try/except内调用」的硬规范,不遵守会看到什么现象?
第三段 全景:一条问题在链路里被处理了三次
3.1 三个调点在链路上的位置
用户问题
│
│ ① 检索前:改问题 ── 查询改写检索(MultiQueryRetriever)
│ 一路问题 → 大模型改写成 3 个角度的问题
↓
│ ② 检索时:取法 ──── 近似检索(Retriever,向量库 topk)
│ + 关键词那条路(BMRetriever / FullTextRetriever)
↓
│ ③ 检索后:排序 ──── reranker 精排(LocalReranker / TEIReranker / MixRetrieveReranker)
↓
组装 prompt → 大模型 → 回答
官方《开发流程》里的原话就写明了这三个位置:
- 初始化检索方式,用户可以定义近似检索、查询改写检索等方式。 问题经过 embedding 模型向量化后,通过检索在知识库中找到上下文 context。
- 对检索到的上下文 context 通过 reranker 进行精排(可选),提高检索质量。
⭐ 记住这张图:这三处是可以分开下手的, 所以「效果不好」不要笼统地说「检索不行」 —— 先判断是三个位置里的哪一个。
3.2 官方的「近似检索」到底在做什么
《检索》接口参考第一句话就把机制说全了:
将待搜索的问题进行向量化后使用近似算法在向量数据库中检索相似的 topk 个向量 ID, 通过向量 ID 获取关系数据库中 topk 个相关文档。
两个要点:
| 要点 | 含义 | 直接后果 |
|---|---|---|
| 「近似」 | 向量库不是遍历比对全部向量,是近似算法 | k 之外的文档直接不参与 —— 漏了就是漏了,后面救不回来 |
| 「双库」 | 向量库出 ID,关系库用 ID 取原文 | 向量库和关系库必须一一对应(G2/G3 已讲) |
⭐ 由此得到本课最重要的一句话:
检索的上限是
topk,不是「库里有」 —— 文档在库里,但没进 topk,对大模型来说就等于不存在。
3.3 为什么「默认检索」一定答不准
把官方的默认值列成一张表,答案就出来了(这一列是本课的题眼):
| 位置 | 参数 | 官方默认值 | 默认情况下的现象 |
|---|---|---|---|
| 检索时 | Retriever.k |
1(取值范围 [1, 10000]) | 只取 1 条给大模型看 → 答不全 |
| 检索时 | Retriever.score_threshold |
None(为 None 即不使能阈值过滤) | 相关的、不相关的一起进来 |
| 检索前 | — | 不做改写 | 问法和文档措辞对不上就整个漏掉 |
| 检索后 | SingleText2TextChain.reranker |
None(默认不做精排) | 排在前面的未必最相关 |
| 向量化 | pooling_method |
cls |
换模型要重新评估(见 5.4) |
⚠️ 三个默认值叠在一起就是现场最典型的样子:
从库里按近似算法取出 1 条,不卡阈值、不精排、不改写,直接塞给大模型。 这一条要是恰好不是最相关的那条,模型就只能拿着半句不相关的材料硬答 —— 而它还会答得很流畅,所以现场很难第一眼看出问题在检索。
第四段 【如果我来做】从「答不准」到「定档」
4.0 我会按这个顺序做(顺序错了会白试一圈)
① 摸底(不改任何东西,先把"现在取了几条"看清楚)
把现在的 Retriever 参数打印出来:k=? score_threshold=? reranker=? 用哪个 embedding?
⚠️ 这一步最常见的结果是"k=1" —— 找到它,一半问题就定位了
② 定标尺(先有尺子再动手)
准备 20 个"答案一定在该文档里"的问题,记下每个答案在哪一段
⚠️ 没有这把尺子,后面每一次改动都是"我觉得好了一点"
③ 拆开跑(把检索单独拎出来跑,不接大模型)
⚠️ 大模型会掩盖检索的问题:材料不对它也能编一段像样的回答
必须直接看 source_documents 里到底给了哪几段
④ 先动"检索时"(最便宜、见效最快)
k 从默认 1 → 10~20;score_threshold 从 None → 按官方示例值起步(0.2 / 0.4 / 0.6 各试一遍)
⑤ 再动"检索前"(问法和文档对不上时用)
MultiQueryRetriever(换 3 个角度问)或 BMRetriever / FullTextRetriever(关键词那条路)
⑥ 最后动"检索后"(topk 拿回来不少,但对的没排前面时用)
LocalReranker / TEIReranker;混合检索的加权用 MixRetrieveReranker
⑦ 定档并记录(k / 阈值 / 走了哪条路 / 用了哪个模型 / 20 个问题命中几条)
⑧ 诚实(官方没给过最优值;权重公式是图片,本课不复现,请按官方原文取值 [0,1] 校验)
⭐ 这个顺序里最容易被跳过的是 ① 和 ③:
- ①:不摸底就调参 —— 调了半天,其实只要把
k从 1 改成 10 就解决大半; - ③:只看最终回答好不好 —— 而回答好坏里混着大模型自身的能力, 你根本分不清是检索没给到,还是模型没用上。
4.1 第 ① 步:摸底 —— 先确认「现在取几条」
第一件事:确认模型要跑在哪张卡上(后面 embedding 和 reranker 都要这个 ID)。
命令 npu-smi info
含义:昇腾的设备管理工具,打印每张卡的信息 —— 你要从这里拿到可用的 NPU ID 拆解:
npu-smi(昇腾设备管理工具,类似系统资源监视器)+info(子命令:查信息) 用法:直接执行;官方《向量化》原文写的是「模型运行 NPU ID,通过npu-smi info查询可用 ID」 期望:一张表,列出每张卡的 NPU ID / Chip Count / Chip ID / Product Type / 显存 / 温度 不过会怎样:命令不存在 → 驱动没装(回 A1); 有输出但 ID 不是 0 → 千万别照着示例里的dev_id=0抄(租用/容器环境常只透传部分卡,实测见过 ID 是 5 的)
第二件事:进容器、找到官方样例目录。
命令 docker exec -it ragsdk_demo bash
含义:进入 G3 里用官方镜像起的那个容器(
--name ragsdk_demo) 拆解:docker(容器工具)+exec(在运行中的容器里执行命令)+-it(交互式 + 分配终端)ragsdk_demo(容器名)+bash(进去后启动的 shell) 用法:docker exec -it ragsdk_demo bash(名字按你实际起的容器改) 期望:提示符变成容器内的 shell;官方说明容器内示例代码位于/workspace/RAGSDK_Samples不过会怎样:报No such container→ 容器名写错或容器已停(docker ps -a先看); 报权限错 → 当前用户不在 docker 组
命令 cd /workspace/RAGSDK_Samples/rag_with_api
含义:切到官方问答样例所在目录 —— 后面两条命令都在这个目录里跑 拆解:
cd(change directory,切换目录)+ 官方给的示例路径 用法:cd /workspace/RAGSDK_Samples/rag_with_api期望:切换成功,pwd打印这个路径 不过会怎样:报No such file or directory→ 镜像版本与文档不一致, 此时不要猜目录名,用find /workspace -name "rag_demo_*"找一遍
4.2 第 ③ 步:把「检索」单独拎出来跑
⭐ 这是本课最值得养成的一个习惯:不要用「最终回答」评估检索。
做法:把官方《检索》接口参考里的调用示例原样抄成一个脚本(示例里已经包含建库 + 建检索器 + invoke 三步),
只保留到 res = text_retriever.invoke(...) 为止,不接大模型。
命令 python3 retrieve_probe.py
含义:跑一个只做检索、不调大模型的探针脚本,直接看它返回了哪几段 拆解:
python3(解释器)+retrieve_probe.py(文件名是自取的, 里面的代码来自官方《检索 · 调用示例》,示例里已经建好了知识库、检索器,最后print(res)) 用法:python3 retrieve_probe.py > probe_基线.txt(先存一份基线,改参数前后对比) 期望:打印出检索到的文档列表(page_content+metadata); 重点看两件事:① 返回了几条 ② 返回的这几条里,有几条是真正相关的 不过会怎样:抛异常 → 先看是不是没包try/except(官方硬规范,见 5.6); 返回空列表 → 不是检索参数问题,回 G3 查库(库为空 / 关系库与向量库对不上); 返回的消息里提示文本过长 → 官方限制:待检索的问题长度不超过 100 万
⭐ 为什么要存基线:probe_基线.txt 是后面每一次调参的对照物 ——
没有基线,你没法证明「改了之后变好了」。
4.3 第 ④ 步:先动「检索时」(最便宜)
官方 Retriever 的两个旋钮(全部参数必须通过关键字参数传递,官方原文):
from mx_rag.retrievers import Retriever
# 所有参数需通过关键字参数传递
Retriever(vector_store=..., document_store=..., embed_func=..., k=..., score_threshold=...)
官方完整调用示例(照它改):
text_retriever = Retriever(vector_store=vector_store,
document_store=chunk_store,
embed_func=emb.embed_documents,
k=1,
score_threshold=0.2
)
res = text_retriever.invoke("请描述一下2024年高考语文作文题目")
print(res)
| 参数 | 类型 | 必选 | 官方原文说明 |
|---|---|---|---|
vector_store |
VectorStore | 必选 | 向量数据库实例(MindFAISS 等) |
document_store |
Docstore | 必选 | 关系型数据库实例(SQLiteDocstore 等) |
embed_func |
Callable | 必选 | embedding 回调函数 |
k |
int | 可选 | 检索的条目范围 topk,取值范围 [1, 10000],默认值为 1 |
score_threshold |
float | 可选 | 默认值为 None,为 None 则不使能阈值过滤功能;使用时取值范围 [0, 1],阈值取得越大,匹配越严格;越小,匹配越不严格 |
filter_dict |
Dict | 可选 | 默认 {},当前只支持对 document_id 进行过滤,id 以列表传入,列表长度不超过 1000*1000;例:{"document_id": [1, 2, 4]} |
⭐ 两个默认值就是「答不全」和「答偏」的直接来源:
k默认 1 → 只给大模型一条材料 → 只要这条不完整,答不全;score_threshold默认None→ 不筛 → 只要k调大,无关内容也一起进来 → 答偏。
所以这两件事必须成对调:
| 现象 | 先动哪个 | 方向 |
|---|---|---|
| 答案不完整、话说到一半就没了 | k |
调大(10~20 起步) |
| 答案里混进了不相关内容、答偏 | score_threshold |
从 None 改成有值,从 0.2 往上试(越严格越大) |
调大 k 后反而更差 |
两个一起 | k 大了必须配阈值,否则噪声一起进来 |
⚠️ 官方没有给过「k 该取多少」「阈值该取多少」的推荐值 ——
k=1 / score_threshold=0.2 只是示例里出现的数字,不是最优值。必须用自己的问题集试。
按文档过滤:filter_dict 还给了另一个下手处 —— 只在某几篇文档里检索:
def set_filter(filter_dict) # 官方原型
# 例:只在 document_id 为 1、2、4 这三篇里检索
{"document_id": [1, 2, 4]}
⭐ 这个参数在私有化项目里很好用:部门之间互相隔离时, 让 A 部门的提问只在 A 部门的文档 id 里检索,一行参数就够(官方限制:id 列表长度不超过 1000*1000)。
4.4 第 ⑤ 步:再动「检索前」——查询改写检索
MultiQueryRetriever 官方功能描述(原文):
将输入的 query 发送给大模型进行问题改写,然后再根据每个问题检索对应的 topk 个相似文档, 对 n 个问题*topk 个文档去重和按文本长度排序。
翻译:一次问法 → 大模型改成 3 个角度的问法 → 分别检索 → 去重排序。 它解决的就是「问法和文档措辞对不上」这件最消耗人的事。
官方参数表:
| 参数 | 类型 | 必选 | 官方说明 |
|---|---|---|---|
llm |
Text2TextLLM | 必选 | 大模型对象实例 |
prompt |
PromptTemplate | 可选 | 默认值即「从不同角度改写生成 3 个问题」;question 字符串是固定的,不能更改;input_variables 必须包含 question;template 长度 (0, 1*1024*1024] |
parser |
BaseOutputParser | 可选 | 默认 DefaultOutputParser,对大模型返回的多个问题通过数字编号进行拆分 |
llm_config |
LLMParameterConfig | 可选 | 调用大模型的参数(默认 temperature 0.5、top_p 0.95,见 G4) |
⚠️ 官方一条很容易忽略、但影响很大的提醒(原文):
prompt和question的语言类型最好保持一致,或者指明大模型回答语言类型, 否则会影响大模型回答效果。
翻译:中文库就别拿英文改写模板去套 —— 改写出来的问题可能是英文, 而你的文档是中文,检索直接对不上。
官方调用示例(注意:示例里比参数表多了 vector_store / document_store / embed_func / k / score_threshold):
from mx_rag.retrievers import MultiQueryRetriever
# 初始化检索器
multi_text_retriever = MultiQueryRetriever(llm=llm,
vector_store=vector_store,
document_store=chunk_store,
embed_func=emb.embed_documents,
k=1,
score_threshold=0.2
)
res = multi_text_retriever.invoke("请描述一下2024年高考语文作文题目?")
print(res)
⚠️ 诚实标注:官方参数表里只列了 4 个参数,而调用示例里传了 7 个。 原因是该类继承自
mx_rag.retrievers.Retriever(官方原文), 所以父类参数同样要传 —— 参数表未逐条重复列出,此处需以实际版本为准。
4.5 第 ⑤ 步的另一条路:关键词检索(BM25)
除了向量,官方还给了两条「关键词」路。它们解决的是另一类问题:
| 类 | 官方功能描述 | 输入从哪来 |
|---|---|---|
BMRetriever |
query 通过大模型提取关键词,再使用 BM25 进行 topk 检索 | 大模型提关键词 |
FullTextRetriever |
使用 BM25 对输入的 query 进行 topk 检索 | 直接用 query |
什么时候这条路比向量好:问的是专有名词、编号、型号、错误码 —— 这类「字面必须对上」的内容,向量反而容易找不准(意思相近的一堆,但并不含你要的那个编号)。
BMRetriever 官方信息:
- 继承
langchain_core.retrievers.BaseRetriever,用invoke调用,输入的 query 长度不超过 100 万; docs:List[Document],必选,列表长度取值 [0, 1000];k:可选,[1, 10000],默认 1;prompt:可选,官方默认值为「根据问题提取关键词,不超过 10 个…… 关键词尽量切分为动词、名词、或形容词等单独的词,不要长词组……关键词之间使用逗号分隔」;preprocess_func:可选,默认对字符串使用逗号进行切分。
官方调用示例:
from mx_rag.retrievers.bm_retriever import BMRetriever
bm_retriever = BMRetriever(docs=docs, llm=llm, k=10)
⭐ 注意 k=10:官方自己在这个示例里也没有用 k=1 ——
这就是「默认值不等于推荐值」的最好证据。
FullTextRetriever 一个必须知道的限制(官方原文):
document_store:MilvusDocstore 类或 OpenGaussDocstore 类,必选…… 当前只支持 MilvusDocstore 和 OpenGaussDocstore 两种。
⚠️ 也就是说:你 G3 里用 SQLiteDocstore 建的那套库,跑不了 FullTextRetriever ——
换类之前先看它要哪种关系库,否则会卡在一个很难懂的参数错误上。
(官方这条路的示例里,切分参数是 chunk_size=750, chunk_overlap=100 ——
和 G4 讲的 150 不是同一个数,又一次说明这些数字是示例值不是定值。)
4.6 第 ⑥ 步:最后动「检索后」——reranker 精排
Reranker 是抽象基类(官方原文:「重排抽象基类」),Reranker(k) 本身不能直接用。
官方明说精排的作用是「提高检索质量」(《开发流程》第 4 步)。
三个可用的实现,选择判据很清晰:
| 类 | 官方功能描述 | 什么时候选它 | 关键前提 |
|---|---|---|---|
LocalReranker |
本地使用 transformers 启动模型,提供文本相关性计算功能 | 有卡、想全在内网、不想再起服务 | 当前支持的模型:bge-reranker-large、bge-reranker-base |
TEIReranker |
连接 TEI 服务,提供文本相关性计算功能 | 已经有 TEI rerank 服务 | 基于 TEI 框架的 rerank 服务不支持 https |
MixRetrieveReranker |
提供 BM25 和稠密向量混合检索结果排序功能 | 同时走向量 + 关键词两条路,要按权重合成一份排序 | 输入的 Document 必须带 score 和 retrieval_type |
LocalReranker 官方原型与参数:
from mx_rag.reranker.local import LocalReranker
LocalReranker(model_path, dev_id, k, use_fp16)
| 参数 | 类型 | 必选 | 官方说明 |
|---|---|---|---|
model_path |
str | 必选 | 模型权重目录:路径长度不能超过 1024,不能为软链接和相对路径;单文件 ≤10GB、深度 ≤64、文件总数 ≤512;路径不能在 ["/etc","/usr/bin","/usr/lib","/usr/lib64","/sys/","/dev/","/sbin","/tmp"] 里 |
dev_id |
int | 可选 | 模型运行在哪张卡上,取值范围 [0, 63],默认 0 |
k |
int | 可选 | 精排后返回最相关的 k 个结果,[1, 10000],默认 1 |
use_fp16 |
bool | 可选 | 是否转半精度,默认 True |
⭐ 三种排序类的共同调用姿势(官方三个示例的结构是一样的):
rerank = LocalReranker.create(model_path="path to model", dev_id=0) # 先建对象
scores = rerank.rerank('你好', [doc.page_content for doc in docs]) # 再打分
res = rerank.rerank_top_k(docs, scores) # 再取 topk
print(res)
三个方法的官方返回值,一个都不能记错:
| 方法 | 官方原型 | 返回什么 |
|---|---|---|
rerank |
def rerank(query, texts, batch_size) |
numpy.array:和 texts 长度一致的数组,保存每个 text 和 query 的相关性得分 |
rerank_top_k |
def rerank_top_k(objs, scores) |
List:返回 k 个得分最高对象(「得分越高,越相似」) |
create |
@staticmethod def create(**kwargs) |
实例对象;必选参数不传会抛 KeyError(官方原文) |
两个容易踩的取值范围:
rerank 的 texts 列表长度 [1, 1000*1000]、单个元素长度 [1, 1024*1024];
batch_size [1, 1024],默认 32,且官方注明「可配置的值由设备显存决定」。
TEIReranker 的安全提醒(官方 NOTE,私有化项目必看):
当前基于 TEI 框架创建的 rerank 服务不支持 https 协议, 为安全起见可通过搭建一个 nginx 服务,使该服务与 rerank 服务处于一个可信网络。 使用时客户端以 https 方式访问 nginx,nginx 转发请求到 rerank 服务。
翻译:TEI 这条路自己不带 https,但你不能就这么裸着上内网 ——
官方的办法是前面挂一层 nginx 做转发。url 支持 /rerank、/v1/rerank 两个接口。
MixRetrieveReranker:混合检索的加权合成(参数全部是可选,且都有默认值):
from mx_rag.reranker.local import MixRetrieveReranker
MixRetrieveReranker(k, baseline, amplitude, slope, midpoint)
| 参数 | 官方说明(默认值原样抄) |
|---|---|
k |
排序后返回最相关的 k 个结果,[1, 10000],默认 100 |
baseline |
权重求取公式基础值,[0.0, 1.0],默认 0.4 |
amplitude |
权重求取公式幅度,[0.0, 1.0],默认 0.3 |
slope |
控制过渡的陡峭程度,取值大于 0,默认 1 |
midpoint |
函数值达到基础值和最大值中间点时的 query 长度,取值大于 0,默认 6 |
⚠️ 两条必须照实说的:
- 官方注明:「权重计算公式为如下所示,请确保计算结果取值为 [0, 1]」—— 但那个公式在官方文档里是一张图片,文本里没有算式。 本课不复现该公式,使用时请打开官方原文对照公式,并自检算出来的权重落在 [0, 1] 内。
- 官方注明
batch_size「该变量暂未使用」 —— 它认不认这个参数,别猜,按文档来。
输入长这样(官方示例:每个 Document 的 metadata 里带 score 与 retrieval_type):
doc_1 = Document(page_content="document1", metadata={"score": 1.0, "retrieval_type": "dense"})
doc_2 = Document(page_content="document2", metadata={"score": 2.0, "retrieval_type": "sparse"})
reranker = MixRetrieveReranker(k=100, baseline=0.4, amplitude=0.3, slope=1, midpoint=6)
res = reranker.rerank(query, docs)
⭐ retrieval_type 只有 dense(稠密向量)和 sparse(稀疏/BM25)两种
—— 这就是「混合检索」里那个「混合」的落点。
还有一个省事的入口:RerankerFactory(官方原文:「reranker 的工厂方法类」)。
官方把它支持的类型直接列在了代码里:
from mx_rag.reranker import RerankerFactory
class RerankerFactory(ABC):
_NPU_SUPPORT_RERANKER: Dict[str, Callable[[Dict[str, Any]], Reranker]] = {
"local_reranker": LocalReranker.create,
"tei_reranker": TEIReranker.create
}
调用时用 create_reranker(similarity_type="local_reranker", ...) 即可,
similarity_type 必选,可取 local_reranker / tei_reranker 两个值。
4.7 第 ⑦ 步:接进 Chain 才算生效
⭐ 这一步最容易出的事:参数写对了,但没接到 Chain 上。
官方 SingleText2TextChain 的 reranker 参数原文:
reranker:Reranker类型,可选,Reranker 对象,实现对检索的文档进行精排, 默认为None。
而官方那份「基本对话功能」的调用示例里,确实没有传 reranker:
r = Retriever(vector_store=vector_store, document_store=chunk_store,
embed_func=emb.embed_documents, k=1, score_threshold=0.6)
rag = SingleText2TextChain(retriever=r, llm=llm) # ← 只传了 retriever 和 llm
response = rag.query("mxVision软件架构包含哪些模块?",
LLMParameterConfig(max_tokens=1024, temperature=1.0, top_p=0.1))
print(response)
⭐ 这就是本课开头那个现象的直接答案:
示例能跑通,是因为它只是「能跑通」;它并不代表效果调好了。
加精排,就是在这个构造里补上 reranker= 那一个参数。
顺带记住 Chain 的返回结构(官方):source 参数默认为 True,
返回字典里 key 为 source_documents:
{"query": query, "result": data, "source_documents": [{'metadata': xxx, 'page_content': xxx}]}
⭐ 这个 source_documents 就是你做验收的证据(见第六段)——
客户问「凭什么说这段是文档里写的」,你把这一项打出来给他看就完了。
4.8 第 ⑧ 步:跑一遍官方样例,确认整条链路
命令 python3 rag_demo_query.py --embedding_url http://127.0.0.1:8080/v1/embeddings --llm_url http://127.0.0.1:1025/v1/chat/completions --model_name Qwen3-4B --query "请描述2024年高考作文题目"
含义:跑官方问答样例,一次走完「向量化 → 检索 → 组装 prompt → 大模型回答」 拆解:
rag_demo_query.py(官方样例脚本名,位于/workspace/RAGSDK_Samples/rag_with_api)--embedding_url(向量化服务地址)+--llm_url(大模型服务地址)--model_name(大模型名)+--query(问的问题) 用法:先cd /workspace/RAGSDK_Samples/rag_with_api; 三个 url 必须换成你自己部署的地址,官方明说「为示例 url 参数,具体以用户本地部署使用参数为准」 期望:官方给了验收判据 —— 「若输出包含检索到的文档内容和生成的回答,表示问答流程运行正常」, 形如{'query': '...', 'result': '...', 'source_documents': [...]}不过会怎样:报连接被拒 → 向量化服务或大模型服务没起(回 D2 查推理服务);result有内容但source_documents是空的 → 检索没给到东西, 别被一句流畅的回答骗了,回第 ③ 步用探针单独查检索
⚠️ 这条命令本身不会告诉你「检索调好了没有」 —— 它只证明链路是通的。 判据在第六段。
第五段 逐件拆开:四个检索器、三个排序器、一个向量化层
5.1 四个检索器,一张表选完
| 类 | 官方一句话功能 | 调的哪个位置 | 关键前提 |
|---|---|---|---|
Retriever |
问题向量化后用近似算法在向量库检索 topk 个向量 ID,再取关系库原文 | 检索时 | 向量库 + 关系库;k 默认 1 |
MultiQueryRetriever |
把 query 发给大模型做问题改写,对 n 个问题×topk 个文档去重并按文本长度排序 | 检索前 | 要有一个大模型(llm 必选) |
BMRetriever |
query 经大模型提取关键词,再用 BM25 做 topk 检索 | 检索时(关键词) | 要 docs([0,1000])、要 llm |
FullTextRetriever |
直接用 BM25 对 query 做 topk 检索 | 检索时(关键词) | 关系库只能是 MilvusDocstore 或 OpenGaussDocstore |
公共点(很容易忘):四个都继承 langchain_core.retrievers.BaseRetriever(BMRetriever/FullTextRetriever)
或 mx_rag.retrievers.Retriever(MultiQueryRetriever),调用方式统一是基类的 invoke;
问题长度上限官方统一写的是 不超过 100 万。
5.2 向量化层:为什么「换模型 = 重建库」
检索和建库用的是同一个 embedding,所以这一层的选择是不可返工的。
| 类 | 官方支持的模型 | 返回什么 |
|---|---|---|
TextEmbedding(本地) |
BAAI/bge-large-zh-v1.5、aspire/acge_text_embedding |
embed_documents → List[List[float]];embed_query → List[float] |
SparseEmbedding(本地稀疏) |
BAAI/bge-m3 |
embed_documents → List[Dict[int, float]](key 为 token_id,value 为 token_weights) |
TEIEmbedding(连服务) |
由 TEI 服务决定 | 同稠密;TEI embed 服务不支持 https |
⚠️ SparseEmbedding 的返回值和稠密那条完全不同 ——
它不是定长向量,是「token_id → 权重」的字典。
这就是 MixRetrieveReranker 里 sparse 那一路的输入形态。
三个必须记住的官方细节:
TextEmbedding的pooling_method:取值['cls','mean','max','lasttoken'],默认'cls'—— 换模型或换 pooling,向量就变了,必须重新评估;lock这个参数决定了它支不支持并发(官方原文):None表示不使用锁、此时该接口不支持并发;multiprocessing.Lock()支持多进程;threading.Lock()支持多线程。 ⭐ 官方在《开发流程》里说「知识库构建和在线问答支持并发」—— 而这里的实现方式是「你自己传锁进去」。 只并发不传锁,就是没并发。- 维度必须和向量库对上:G3 里
MindFAISS(x_dim=1024, ...)的 1024, 来自bge-large-zh-v1.5的 1024 维输出。 换模型不换x_dim= 检索直接出错或查不准。
⭐ 官方还给了推理加速的开关(三个动作,官方示例原文):
import os, torch_npu
from mx_rag.transformer_adapter.modeling_bert_adapter import enable_bert_speed
os.environ["ENABLE_BOOST"] = "True" # "True" 使能,"False" 不使能
torch_npu.npu.set_device(f"npu:{device_id}")
⚠️ 注意 CLIPEmbedding 一条很实用的官方提示:
embed_images 的 batch_size 「如果太大,可能导致服务器返回 500 错误,此时需要调小 batch_size」
—— 这条是「多模态检索突然报 500」的第一处理动作。
5.3 精排的三个实现,选择判据
见 4.6 的三表。这里只补一条判断线:
你的库是「纯向量」一条路 → LocalReranker(本地,模型 bge-reranker-large / -base)
→ 或 TEIReranker(连服务,注意要走 nginx 才有 https)
你的库是「向量 + BM25 两条路」→ MixRetrieveReranker(按 query 长度动态调两条路的权重)
⭐ 为什么 MixRetrieveReranker 的公式里有 midpoint(query 长度) ——
它想表达的是:问题短的时候更该信关键词,问题长的时候更该信语义。
(这是从官方参数含义推出的理解,官方只给了公式图片,未给出这条文字解释。)
5.4 ⚠️ 官方硬规范:RAG SDK 接口必须在 try/except 内调用
这是《接口参考 · 使用说明》里的原文,不是建议:
RAG SDK 接口遵循异常处理机制, 故用户必须在
try/except语句块内进行调用以及异常处理, 防止在使用的过程中出现异常抛出导致程序退出的情况。
为什么这条在检索/精排这一课尤其重要:
| 场景 | 不包 try/except 的现象 |
|---|---|
| 检索服务临时不通 | 整个问答进程直接退出 —— 而不是给用户一句「暂时查不到」 |
| reranker 模型路径配错 | 同上;且进程是在「已经检索成功之后」死的,日志里看起来检索是好的 |
| 一次回答失败 | 服务化场景下一个用户把整个服务带下去 |
⭐ 而且官方自己给的示例里没有包 try/except ——
照着示例抄一遍跑得通,上线就不成立。这一条必须自己补。
5.5 三件事串起来的最短代码骨架
try:
# ① 检索时:取几条、卡不卡阈值
r = Retriever(vector_store=vector_store, document_store=chunk_store,
embed_func=emb.embed_documents, k=10, score_threshold=0.3)
# ② 检索后:精排
reranker = LocalReranker.create(model_path="/path/to/bge-reranker-large", dev_id=0, k=5)
# ③ 接进 Chain 才生效(不传 reranker 就等于没加)
rag = SingleText2TextChain(retriever=r, llm=llm, reranker=reranker)
response = rag.query("你的问题")
print(response) # response["source_documents"] 就是验收证据
except Exception as e:
print(f"RAG 调用失败:{e}") # 官方要求:异常在这里接住,别让进程退出
⚠️ 诚实标注:
k=10、score_threshold=0.3、k=5是本课为演示填的示例值, 不是官方推荐值;LocalReranker.create的model_path需替换为你的实际模型目录。
第六段 判据 / 验收
本段的硬要求:看返回的内容,不看报错。
| # | 判据 | 怎么验 | 不过说明 |
|---|---|---|---|
| ① | 检索器参数是显式写的 | 代码里 k / score_threshold 都能看见,不是吃默认 |
还在用 k=1 —— 这是最常见的一条 |
| ② | 检索单独跑得通 | 探针脚本能打印出非空的文档列表 | 库的问题(回 G3),不是参数问题 |
| ③ | topk 里确实有对的 | 20 个标准问题,看检索结果里有没有那段原文 | 没有 → 调 k / 加查询改写 / 加关键词路 |
| ④ | 答案完整 | 命中的问题里,材料是不是完整的 | 不完整 → 回 G4(切分),不是检索的问题 |
| ⑤ | 答案不跑偏 | 返回的文档里相关内容的占比 | 偏低 → 上 score_threshold |
| ⑥ | 精排接上了 | SingleText2TextChain 里传了 reranker= |
没传 → 默认 None,精排等于没做 |
| ⑦ | source_documents 非空 |
打印 response["source_documents"] |
空 → 检索没给到;回答流畅也不代表查到了 |
| ⑧ | 参数定档并记录 | 有一份定档表(见下) | 不定档 = 换人接手要重来一遍 |
⭐ 判据 ⑥ 是本课最容易被骗过的一条:
代码里写了 LocalReranker.create(...),不等于精排生效了 ——
它必须在 Chain 的构造参数里出现。
定档记录表(我会留这份):
| 项 | 内容 |
|---|---|
| 检索方式 | 纯向量 / 查询改写 / 关键词 / 混合 |
k |
定版值(以及为什么是这个数) |
score_threshold |
定版值(未使用就写 None) |
| 精排 | 用了哪个类、哪个模型、k 多少;没用就写「无」 |
| embedding 模型 + 维度 | 例:bge-large-zh-v1.5/1024 |
| 测试问题数 / 命中数 | 例:20 个 / 17 个 |
| 未命中的那几个 | 是什么问题、为什么(这一栏最值钱) |
⭐ 为什么「未命中的那几个」最值钱:它划出了这套参数的边界 —— 下次遇到同类问题,你就知道该往「检索前」还是「检索时」调,而不是从头试。
第七段 出问题怎么查
排查顺序:先把「检索单独跑一遍」,再判是三个位置里的哪一个,最后才怀疑大模型。
| 你看到的现象 | 先归到哪个位置 | 具体动作 |
|---|---|---|
| 回答不完整、只说了一半 | 检索时 | 查 k —— 是不是还在默认的 1 |
| 回答里混了不相关内容、答偏 | 检索时 | score_threshold 还是 None?从 0.2 起往上试 |
k 调大后反而更差 |
检索时 | 只调了 k 没配阈值,噪声一起进来了 |
| 换一种问法就查不到 | 检索前 | 上 MultiQueryRetriever;或改 prompt 让它出多个角度 |
| 问编号 / 型号 / 错误码查不到 | 检索前 | 上 BMRetriever / FullTextRetriever(关键词那条路) |
| 检索结果里有对的那条,但排得很靠后 | 检索后 | 上 reranker;reranker 参数有没有真传进 Chain |
| 加了 reranker 但效果没变 | 检索后 | 三件事:① 传进 Chain 了吗 ② k 是不是小于待排序的条数 ③ 模型加载在哪张卡(dev_id) |
| 混合检索的两路分数没法比 | 检索后 | 用 MixRetrieveReranker;确认 Document.metadata 里有 score 和 retrieval_type |
| 换了 embedding 模型后整体变差 | 向量化 | MindFAISS 的 x_dim 跟着改了吗?整库重做了吗? |
| 多线程跑检索偶发失败 | 向量化 | TextEmbedding 的 lock 没传 —— 官方:不传锁即不支持并发 |
| 多模态检索报 500 | 向量化 | CLIPEmbedding.embed_images 的 batch_size 调小(官方明说) |
| 检索时进程直接退出(不是报错返回) | 规范 | 没包 try/except —— 官方硬规范 |
FullTextRetriever 一跑就参数报错 |
前提 | 关系库不是 MilvusDocstore / OpenGaussDocstore(当前只支持这两种) |
rerank_top_k 结果条数不对 |
精排 | 它按 Reranker(k) 里的 k 返回,不是按传进来的列表长度 |
第八段 常见报错清单
⚠️ 官方的 RAG SDK 文档没有单独的「报错码表」 —— 本表按现象组织。查其他报错用官方案例库,按稳定特征词检索 (去掉路径、pid、时间戳,只留
Acl open device、libdcmi.so这类):https://www.hiascend.com/document/caselibrary
| 现象 | 先查什么 |
|---|---|
| 检索返回空列表 | 库是不是空的(回 G3);关系库与向量库是否一一对应 |
检索返回的条数比 k 少 |
score_threshold 卡掉了;阈值越大越严格(官方) |
k 传 0 或超过 10000 |
官方取值范围 [1, 10000] |
score_threshold 传了负值或大于 1 |
官方取值范围 [0, 1](None 表示不使能过滤) |
filter_dict 报错 |
当前只支持 document_id 过滤,且 id 列表长度不超过 1000*1000 |
MultiQueryRetriever 改写出的问题语言不对 |
prompt 和 question 语言不一致(官方明说会影响效果) |
MultiQueryRetriever 报 input_variables 相关错 |
prompt.input_variables 必须包含 question;且 question 字符串不能改 |
BMRetriever 的 docs 报长度错 |
docs 列表长度取值 [0, 1000](官方) |
FullTextRetriever 传 SQLiteDocstore 报错 |
官方:当前只支持 MilvusDocstore 和 OpenGaussDocstore |
Reranker(...) 报「抽象类不能实例化」 |
Reranker 是抽象基类,要用 LocalReranker/TEIReranker/MixRetrieveReranker |
LocalReranker.create 抛 KeyError |
官方:必选参数必须传入,否则抛 KeyError |
| 模型路径被拒 | 路径长度不能超过 1024、不能是软链接和相对路径;不能在 /etc、/dev、/tmp 等目录下 |
| 加载模型报权重格式相关告警 | 官方 NOTE:非 safetensors 权重请先转换,避免 ckpt/bin 引入安全问题 |
rerank 的 batch_size 超范围 |
官方 [1, 1024],默认 32;且可配置值由设备显存决定 |
| 精排结果没排序效果 | k(Reranker 构造里的)小于 2 就等于没排序 |
MixRetrieveReranker 的权重算出来不在 [0,1] |
官方要求确保所有权重计算结果取值为 [0, 1](公式见官方原文图片) |
| 进程在检索/精排时直接退出 | 接口没包在 try/except 里(官方硬规范) |
用 TEIReranker / TEIEmbedding 连不上 |
TEI 服务不支持 https,官方建议前挂 nginx;url 长度 [1, 128],rerank 支持 /rerank、/v1/rerank |
多模态 embed_images 报 500 |
batch_size 太大,官方明说调小 |
第九段 小结 + 钩子 + 自测
三句话记住本课
- 检索有三个可以分别下手的位置 —— 检索前改问题(查询改写)· 检索时改取法(近似检索 / 关键词)· 检索后改排序(reranker)。 效果不好先定位位置,别笼统说「检索不行」。
- 官方默认值在三个位置上都不站在你这一边 ——
k默认 1 ·score_threshold默认None·Chain的reranker默认None; 官方示例能跑通,只说明链路通,不代表效果调好了。 - 检索的上限是
topk,不是「库里有」 —— 文档在库里但没进 topk,对大模型就等于不存在; 而topk之外,后面怎么排都救不回来。
自测(不看上文)
Retriever的k和score_threshold官方默认值分别是什么?各自会造成「答不全」还是「答偏」?- 查询改写检索(
MultiQueryRetriever)拿到大模型的 3 个问题之后,对 n 个问题×topk 个文档做了什么处理? BMRetriever和FullTextRetriever的区别是什么?后者对关系库有什么限制?Reranker.rerank和Reranker.rerank_top_k的返回值分别是什么?- 为什么说「
LocalReranker.create(...)写了不等于精排生效了」? - 换了 embedding 模型,为什么整库必须重做?还有哪个参数必须跟着改?
- 官方那条「必须在
try/except块内调用」的规范,不遵守时你看到的不是报错,而是什么?
钩子:下一课
检索和精排都调好了,但整条链路还差最后一段没接上:
检索结果怎么拼成 prompt?多轮对话的上下文怎么带?开了缓存之后为什么有的问题秒回、有的不秒回? 而且官方有一条很硬的警告 —— 缓存数据库不做加密存储,某些字段不许往里面放。
G6 会把问答编排(Chain / 缓存 / Prompt 压缩)这一层拆开讲,
那时候我们回到同一个 SingleText2TextChain,把这条链路补完。
附录 A 官方出处
| # | 内容 | 官方出处 |
|---|---|---|
| 1 | 三个检索位置:「初始化检索方式,用户可以定义近似检索、查询改写检索等方式……对检索到的上下文 context 通过 reranker 进行精排(可选),提高检索质量」 | MindSDK 26.1.0《RAG SDK · 开发流程》→ zh/mindsdk/2610/rag/ragug/docs/zh/user_guide.md |
| 2 | Retriever 机制:问题向量化后使用近似算法在向量数据库中检索相似的 topk 个向量 ID,通过向量 ID 获取关系数据库中 topk 个相关文档;继承 langchain_core.retrievers.BaseRetriever;问题长度不超过 100 万 |
MindSDK 26.1.0《RAG SDK · 检索 · 接口参考》→ …/docs/zh/api/retrieval.md |
| 3 | Retriever(vector_store, document_store, embed_func, k, score_threshold):所有参数需通过关键字参数传递;k 取值范围 [1, 10000],默认 1;score_threshold 默认 None(为 None 则不使能阈值过滤)、取值范围 [0,1]、越大越严格;filter_dict 默认 {}、只支持 document_id、id 列表长度不超过 1000*1000 |
同上 |
| 4 | set_filter(filter_dict) 官方原型与过滤示例 {"document_id": [1, 2, 4]} |
同上 |
| 5 | MultiQueryRetriever 功能:将输入的 query 发送给大模型进行问题改写,再根据每个问题检索 topk,对 n 个问题*topk 个文档去重和按文本长度排序;继承 mx_rag.retrievers.Retriever |
同上 |
| 6 | MultiQueryRetriever(llm, prompt, parser, llm_config):prompt 默认值为「从不同角度改写生成 3 个问题」的模板;question 字符串固定不能更改;input_variables 必须包含 question;template 长度 (0, 1*1024*1024];prompt 和 question 语言类型最好保持一致,否则会影响大模型回答效果;parser 默认 DefaultOutputParser,通过数字编号拆分 |
同上 |
| 7 | BMRetriever 功能:query 通过大模型提取关键词,再使用 BM25 进行 topk 检索;docs 必选、列表长度 [0, 1000];k [1,10000] 默认 1;prompt 默认「关键词不超过 10 个……尽量切分为动词、名词、或形容词等单独的词,不要长词组」;preprocess_func 默认逗号切分 |
同上 |
| 8 | FullTextRetriever 功能:使用 BM25 对 query 做 topk 检索;document_store 当前只支持 MilvusDocstore 和 OpenGaussDocstore;官方示例切分参数为 chunk_size=750, chunk_overlap=100 |
同上 |
| 9 | Reranker 抽象基类:Reranker(k),k 必选(返回精排后最相关的 k 个结果);rerank(query, texts, batch_size) 为抽象方法,batch_size 默认 32、可配置值由设备显存决定;rerank_top_k(objs, scores) 返回 k 个得分最高对象;objs 长度 [1,1000*1000]、元素长度 [1, 128*1024*1024];scores 长度 [1,1000*1000] |
MindSDK 26.1.0《RAG SDK · 排序 · 接口参考》→ …/docs/zh/api/reranker.md |
| 10 | LocalReranker(model_path, dev_id, k, use_fp16):本地 transformers;当前支持模型 bge-reranker-large、bge-reranker-base;dev_id [0,63] 默认 0;k [1,10000] 默认 1;use_fp16 默认 True;NOT NOTE「非 safetensors 权重请先转换」;model_path 路径约束(≤1024、非软链接/相对路径、单文件 ≤10GB、深度 ≤64、文件数 ≤512、禁用路径列表) |
同上 |
| 11 | rerank 返回 numpy.array(与 texts 长度一致,保存每个 text 和 query 的相关性得分);query 长度 [1, 1024*1024];texts 列表长度 [1,1000*1000]、元素长度 [1,1024*1024];batch_size [1,1024] 默认 32;create(**kwargs) 为静态方法,必选参数不传将抛 KeyError |
同上 |
| 12 | TEIReranker(url, k, client_param):连接 TEI 服务;url 长度 [1,128],支持 /rerank、/v1/rerank;NOTE:基于 TEI 框架创建的 rerank 服务不支持 https 协议,可通过搭建 nginx 服务,客户端以 https 访问 nginx、nginx 转发到 rerank 服务 |
同上 |
| 13 | RerankerFactory:_NPU_SUPPORT_RERANKER = {"local_reranker": LocalReranker.create, "tei_reranker": TEIReranker.create};create_reranker(similarity_type=..., **kwargs),similarity_type 必选,可取 local_reranker / tei_reranker |
同上 |
| 14 | MixRetrieveReranker(k, baseline, amplitude, slope, midpoint):提供 BM25 和稠密向量混合检索结果排序功能;k 默认 100、baseline 默认 0.4、amplitude 默认 0.3、slope 默认 1、midpoint 默认 6(函数值达到基础值和最大值中间点时的 query 长度);权重计算公式在官方文档中为图片,官方要求确保计算结果取值为 [0,1];rerank 的 texts 为 list[Document],返回 list[Document];官方注明 batch_size 「该变量暂未使用」 |
同上 |
| 15 | MixRetrieveReranker 官方调用示例:Document.metadata 中携带 {"score": 1.0, "retrieval_type": "dense"} 与 {"score": 2.0, "retrieval_type": "sparse"} |
同上 |
| 16 | TextEmbedding(model_path, dev_id, use_fp16, pooling_method, lock):当前支持模型 BAAI/bge-large-zh-v1.5、aspire/acge_text_embedding;pooling_method 取值 ['cls','mean','max','lasttoken'] 默认 'cls';lock 为 None 时该接口不支持并发,multiprocessing.Lock() 支持多进程、threading.Lock() 支持多线程;dev_id [0,63] 默认卡 0(通过 npu-smi info 查询可用 ID) |
MindSDK 26.1.0《RAG SDK · 向量化 · 接口参考》→ …/docs/zh/api/embedding.md |
| 17 | embed_documents(texts, batch_size) 返回 List[List[float]](示例:4 条文本 + 1024 维 → (4,1024));embed_query(text) 返回 List[float];batch_size [1,1024] 默认 32 |
同上 |
| 18 | SparseEmbedding(model_path, dev_id, use_fp16):当前支持模型 BAAI/bge-m3;embed_documents 返回 List[Dict[int, float]](key 为 token_id、value 为 token_weights);embed_query 返回 Dict[int, float] |
同上 |
| 19 | TEIEmbedding(url, client_param, embed_mode):支持 /v1/embed、/v1/embeddings、/embed_sparse;TEI embed 服务不支持 https(nginx 同 12);embed_mode 默认 "dense",该参数当前已弃用 |
同上 |
| 20 | CLIPEmbedding.embed_images:batch_size「如果太大,可能导致服务器返回 500 错误,此时需要调小 batch_size」 |
同上 |
| 21 | 向量化推理加速(官方示例):os.environ["ENABLE_BOOST"] = "True" + from mx_rag.transformer_adapter.modeling_bert_adapter import enable_bert_speed + torch_npu.npu.set_device(f"npu:{device_id}") |
同上 |
| 22 | SingleText2TextChain(llm, retriever, reranker, prompt, sys_messages, source, user_content_builder):reranker 可选、默认为 None;source 默认为 True,返回字典 key 为 source_documents;返回形如 {"query":…, "result":…, "source_documents":[…]};官方「基本对话功能」示例中未传 reranker |
MindSDK 26.1.0《RAG SDK · 大模型Chain · 接口参考》→ …/docs/zh/api/llm_chains.md |
| 23 | ParallelText2TextChain(检索推理并行):同样有可选 reranker 参数,「节省检索时延」 |
同上 |
| 24 | ⭐ 官方硬规范:「RAG SDK 接口遵循异常处理机制,故用户必须在 try/except 语句块内进行调用以及异常处理,防止在使用的过程中出现异常抛出导致程序退出的情况。」 |
MindSDK 26.1.0《RAG SDK · 接口参考 · 使用说明》→ …/docs/zh/api/README.md |
| 25 | 镜像与样例路径:镜像 Tag 格式 {version}-{chip}-{os}-{python};容器内示例代码位于 /workspace/RAGSDK_Samples;问答样例目录 rag_with_api;样例命令 python3 rag_demo_query.py --embedding_url … --llm_url … --model_name Qwen3-4B --query "…";成功判据「输出包含检索到的文档内容和生成的回答」;示例 url 需换成用户本地实际配置 |
MindSDK 26.1.0《RAG SDK · 开发流程》→ …/docs/zh/user_guide.md |
| 26 | 官方案例库入口(查报错用) | https://www.hiascend.com/document/caselibrary |
⚠️ 属于本文「归纳/实践」而非官方原文的部分,已明确标注:
- 第三段 3.3「三个默认值叠加」的表述与本表(这是把官方若干条参数默认值并列起来看的结果, 官方没有一段文字同时讲这三件事);
- 第四段 4.0 的八步执行顺序、4.1 的摸底做法、4.2 的「探针脚本 + 存基线」(官方未给此工作方法);
- 4.3 的「k 调到 10~20」「阈值从 0.2 起试」(官方未给任何推荐值,只是示例值);
- 4.5「专有名词/编号/错误码走向量反而容易找不准」的适用场景判断(官方未给适用场景说明);
- 4.6「选择判据」那张表与 5.3 的两条判断线(官方未给选型建议,是由各类型的官方功能描述归纳);
- 5.3「
midpoint想表达短问题更信关键词、长问题更信语义」(官方只给了公式图片,未给文字解释); - 5.5 的代码骨架(把官方接口按顺序串起来,示例值非官方推荐值);
- 第六段判据表、第七段排查表、第八段报错清单(官方 RAG SDK 无独立报错码表,均为现象归纳);
retrieve_probe.py这个文件名是自取的,代码来自官方《检索 · 调用示例》。
⚠️ 官方未给出、因此本课没有写的内容(需要时按实际环境确认):
k取多少、score_threshold取多少 —— 官方只给了取值范围和「越大越严格」的方向,没有任何推荐值;- reranker 该选本地还是服务 —— 官方列了三个实现,未给选型建议;
MixRetrieveReranker的权重计算公式 —— 官方文档中为图片,本文未复现,使用时请对照官方原文;- 任何性能/精度数字(检索耗时、reranker 提升幅度)—— 官方未给出;
- 检索质量的官方评估方法 —— 官方有独立模块(
evaluation_module),属 G7 内容,本课未展开; MultiQueryRetriever参数表与调用示例不一致(参数表 4 个、示例传 7 个)的原因 —— 官方只写了「该类继承mx_rag.retrievers.Retriever」,未逐条说明父类参数的传递要求;LocalReranker/TextEmbedding所用模型的具体下载地址 —— 官方只给了模型名与部分 ModelScope 链接,未给出 dump 到本地的完整步骤。
附录 B 命令详解
G3/G4 已解释过的命令(
docker exec、cd、python3、ls等)此处不重复;下文只列出本课新增或新用法的。
命令 npu-smi info
含义:查昇腾设备信息,本课用它拿「可用的 NPU ID」 去填
dev_id拆解:npu-smi(昇腾的设备管理工具)+info(子命令:显示设备信息) 用法:直接执行;官方《向量化》原文即写「模型运行 NPU ID,通过npu-smi info查询可用 ID」 期望:一张表,列出每张卡的NPU ID/Chip Count/Chip ID/Product Type等 不过会怎样:命令不存在 → 驱动没装(回 A1); 有输出但 ID 不是 0 → 不要照抄示例里的dev_id=0, 容器/租用环境常只透传部分卡(实测见过 ID 为 5)
命令 docker exec -it ragsdk_demo bash
含义:进入 G3 里起的 RAG SDK 容器(官方样例代码在容器内的
/workspace/RAGSDK_Samples) 拆解:docker(容器工具)+exec(在运行中的容器里执行命令)+-it(交互式并分配终端)ragsdk_demo(容器名)+bash(进去后运行的 shell) 用法:docker exec -it <你的容器名> bash期望:提示符切到容器内,pwd返回容器内路径 不过会怎样:No such container→ 容器名错或已停(先docker ps -a); 报权限错 → 当前用户不在 docker 组
命令 cd /workspace/RAGSDK_Samples/rag_with_api
含义:切到官方问答样例目录 —— 后面的
rag_demo_query.py必须在这里跑 拆解:cd(change directory,切换目录)+ 官方给出的样例路径 用法:cd /workspace/RAGSDK_Samples/rag_with_api期望:切换成功(pwd打印该路径) 不过会怎样:No such file or directory→ 镜像版本与文档不一致, 不要猜目录名,用find /workspace -name "rag_demo_*"找
命令 python3 rag_demo_query.py --embedding_url http://127.0.0.1:8080/v1/embeddings --llm_url http://127.0.0.1:1025/v1/chat/completions --model_name Qwen3-4B --query "请描述2024年高考作文题目"
含义:跑官方问答样例,一次走完「向量化 → 检索 → 组装 prompt → 大模型回答」 拆解:
rag_demo_query.py(官方样例脚本,位于rag_with_api目录)--embedding_url(向量化服务地址,示例为/v1/embeddings)--llm_url(大模型 chat 接口地址,示例为/v1/chat/completions)--model_name(大模型名,官方示例Qwen3-4B)+--query(问题) 用法:三个 url 换成你自己部署的地址(官方注明示例 url 需按本地实际配置修改) 期望:官方判据「若输出包含检索到的文档内容和生成的回答,表示问答流程运行正常」, 形如{'query': '...', 'result': '...', 'source_documents': [...]}不过会怎样:连接被拒 → 向量化或大模型服务没起(回 D2);result有内容但source_documents为空 → 检索没给到东西,别被流畅的回答骗过
命令 python3 retrieve_probe.py
含义:只做检索、不调大模型的探针脚本 —— 用来单独评估检索质量 拆解:
python3(解释器)+retrieve_probe.py(文件名自取, 代码来自官方《检索 · 调用示例》,示例里已建好库与检索器,末尾print(res)) 用法:python3 retrieve_probe.py > probe_基线.txt(先存基线,改参数前后对比) 期望:打印检索到的文档列表(page_content+metadata); 重点看:① 返回几条 ② 其中几条真正相关 不过会怎样:抛异常 → 先看有没有包try/except(官方硬规范); 返回空列表 → 回 G3 查库(空库 / 双库不对应)
命令 grep -rn "reranker" /workspace/RAGSDK_Samples
含义:在官方样例代码里搜
reranker的实际用法 —— 比只看文档更可靠 拆解:grep(在文本里找含关键词的行)+-r(递归子目录)+-n(显示行号)"reranker"(要找的关键词)+ 路径(官方样例目录) 用法:grep -rn "reranker" /workspace/RAGSDK_Samples期望:能看到官方样例里reranker是怎么构造、怎么传进 Chain 的 不过会怎样:输出为空 → 该版本样例里没用到精排(说明这条路要你自己按接口参考写); ⚠️ 本命令为通用 Linux 命令,非昇腾专用;官方未给出「在样例里找参数」这条做法
⚠️ 最后的提醒:本课里的每一条接口名、参数名、取值范围、默认值、返回值, 均取自官方《RAG SDK · 接口参考》对应模块; 凡是官方没有给出的(推荐 k 值、推荐阈值、选型建议、性能数字、权重公式的文字形式), 本文均已明写「官方未给出」,请勿把示例值当成推荐值使用。