外观
RAG 检索模式篇
目标:让集成方用
POST /v1/rag/retrieve按查询文本召回当前用户有权访问的内容片段(chunk),理解返回的回链坐标(sourceDocId/sourceVersion/span)与相关性分语义,按容器缩窄检索范围,规避授权与时效相关的常见坑,进而在自己的应用里组装 RAG(检索增强生成)流程;并在需要为合规 / 审计留痕时,改用审计型签发接口组(/v1/rag/sign/verify/issuances)让「AI 消费了哪些内容」可事后追溯。不在本篇范围:关键词全文搜索(按文档为粒度返回命中,见全文搜索模式篇);认证形态与委派头(见认证与身份双通道);错误码完整码表(见错误码参考)。
全文搜索回答「哪些文档与关键词相关」,RAG 检索回答「哪些内容片段与这句话语义相关」——后者返回带定位坐标的正文片段,专为「检索增强生成」类应用设计:把召回的片段作为上下文喂给大模型,并凭坐标回链原文出处。两者独立授权、互不替代。
关键事实
- 端点:
POST /v1/rag/retrieve,所需 scope:client:rag:retrieve——与全文搜索(client:search:read)独立授权,默认不预授任何客户端,需在开通时显式授予。 - ⚠️ 必须代表用户调用(强通道或弱通道),不支持 APP_ONLY。无用户身份的请求返回 HTTP 403。片段级权限过滤按当前用户执行:结果只含该用户有权读取的内容,集成方无需再做权限裁剪。
- 检索语料来自已发布版本:文档发布后,其内容片段经异步处理就绪方可被召回(最终一致);未发布 / 草稿内容不会出现在结果中。
query必填;topK默认 10、取值范围 [1, 100],超出范围直接拒绝(不静默截断);containerId可选,传入则只在该容器范围内召回。- 结果按相关性降序排列;
score仅用于本次结果内的相对比较,不同查询之间不可比,也不建议设固定阈值过滤。 - ⚠️ 检索能力受部署授权档位门控:基础档位不含检索能力,调用本端点(含
/v1/rag/sign等签发接口组)返回 HTTP 403 与错误码 178008;需部署授权档位含检索能力(进阶 / 完整档)方可调用。这是部署级能力边界、非请求参数问题,重试无效。
一、最小调用
bash
curl -X POST 'https://atkonbase.example.com/api/v1/rag/retrieve' \
-H 'Authorization: Bearer ${accessToken}' \
-H 'X-Atk-User-Token: ${userToken}' \
-H 'Content-Type: application/json' \
-d '{
"query": "合同到期后多久内可以续签",
"topK": 5
}'期望响应(关键字段)
json
{
"code": 0,
"data": [
{
"chunkId": "CH1000042",
"sourceDocId": "D1000001",
"sourceVersion": "V1000003",
"span": "{\"unit\":\"char\",\"start\":1200,\"end\":1456}",
"text": "……合同期满前 30 日内,乙方可书面提出续签申请……",
"score": 0.87
}
]
}| 字段 | 含义 |
|---|---|
chunkId | 命中片段的业务键 |
sourceDocId | 源文档 ID——V1 文档端点直接可用,凭此回链原文 |
sourceVersion | 命中时锚定的源版本 ID(= 该文档当前已发布版本);引用展示时建议带上,避免文档再发版后出处错位 |
span | 定位坐标,JSON 字符串:unit 标识坐标体系,start / end 给出片段在源内容中的区间(按源内容格式可能附带页码等扩展键)。用于在原文中精确定位高亮 |
text | 片段正文——直接作为 RAG 上下文喂给生成模型 |
score | 相关性分,越大越相关;仅供本次结果内排序参考 |
二、按容器缩窄范围
知识库类场景常按业务域分容器存放内容,检索时传 containerId 限定范围:
bash
curl -X POST 'https://atkonbase.example.com/api/v1/rag/retrieve' \
-H 'Authorization: Bearer ${accessToken}' \
-H 'X-Atk-User-Token: ${userToken}' \
-H 'Content-Type: application/json' \
-d '{
"query": "报销单据需要哪些附件",
"topK": 10,
"containerId": "${financeKbContainerId}"
}'范围参数只接受 containerId(闭集),不提供开放的过滤表达式;需要按字段值精确筛选文档时用元数据筛选,两者解决不同问题。
三、组装 RAG 流程(建议形态)
- 召回:以最终用户身份调用
/v1/rag/retrieve(强通道带X-Atk-User-Token,或弱通道 act-as),拿 topK 片段。 - 拼上下文:将
text拼入提示词;保留每条的sourceDocId/sourceVersion/span作为引用元信息。 - 生成与引用:生成模型答复后,按引用元信息渲染「出处」链接——跳转你应用内该文档的详情 / 预览页,凭
span高亮原文位置。 - 空结果处理:召回为空时(无相关内容或用户无权访问任何相关内容),提示词侧应明确「未检索到资料」,避免模型凭空作答。
四、审计型签发(让「AI 消费了哪些内容」可追溯)
/v1/rag/retrieve 是不留档的轻量召回。当你需要为合规 / 审计留下「谁、何时、基于什么查询、拿到了哪些内容」的凭据时,改用审计型签发:在召回的同一次调用里额外拿到一份回执,系统同时为本次签发留存一条只增不改的审计记录。三个接口分工如下,各自用独立 scope 授予。
4.1 签发:POST /v1/rag/sign
召回口径与 /v1/rag/retrieve 完全一致(同一套按用户的强一致权限过滤、同样的 chunks 结构与回链坐标、同样的 topK 规则),额外返回一份回执:能力 token(capabilityToken)、签发标识(issuanceId)与有效期(expiresAt)。所需 scope:client:rag:sign;与 /v1/rag/retrieve 一样必须代表用户调用,不支持 APP_ONLY。
bash
curl -X POST 'https://atkonbase.example.com/api/v1/rag/sign' \
-H 'Authorization: Bearer ${accessToken}' \
-H 'X-Atk-User-Token: ${userToken}' \
-H 'Content-Type: application/json' \
-d '{
"query": "合同到期后多久内可以续签",
"topK": 5
}'期望响应(关键字段):
json
{
"code": 0,
"data": {
"issuanceId": "IS1000007",
"capabilityToken": "${capabilityToken}",
"expiresAt": "2026-06-16T12:30:00Z",
"chunks": [
{
"chunkId": "CH1000042",
"sourceDocId": "D1000001",
"sourceVersion": "V1000003",
"span": "{\"unit\":\"char\",\"start\":1200,\"end\":1456}",
"text": "……合同期满前 30 日内,乙方可书面提出续签申请……",
"score": 0.87
}
]
}
}| 字段 | 含义 |
|---|---|
chunks | 本次召回的片段数组,结构与 /v1/rag/retrieve 完全一致(直接作为 RAG 上下文与回链) |
issuanceId | 本次签发的标识;审计正查时据此定位记录 |
capabilityToken | 能力 token——交给出站闸口 / 合规系统,凭它回查本次签发事实 |
expiresAt | 回执有效期(ISO-8601);过期后仍可验证到「确实签发过」并提示已过期 |
4.2 验证:POST /v1/rag/verify
持签发时拿到的 capabilityToken 回查签发事实——是否为本系统签发、是否仍在有效期、签发给哪个用户、当时交付了哪些内容标识(仅返回标识、不回正文)。持 token 即可验证,无需代表具体用户、也不限定由签发它的同一客户端调用;适合出站闸口 / 合规系统在喂给 AI 前或事后核对。所需 scope:client:rag:verify。
bash
curl -X POST 'https://atkonbase.example.com/api/v1/rag/verify' \
-H 'Authorization: Bearer ${accessToken}' \
-H 'Content-Type: application/json' \
-d '{ "capabilityToken": "${capabilityToken}" }'json
{
"code": 0,
"data": {
"valid": true,
"notExpired": true,
"subject": "${subjectUserId}",
"chunkIds": ["CH1000042", "CH1000058"]
}
}| 字段 | 含义 |
|---|---|
valid | 是否为本系统签发的有效回执 |
notExpired | 是否仍在有效期内(已过期的回执 valid 仍可为 true、notExpired 为 false,表示「确实签发过、但已过期」) |
subject | 当时签发给哪个用户主体 |
chunkIds | 当时交付的内容片段标识(不含正文) |
4.3 审计正查:POST /v1/rag/issuances
按用户主体 + 时间范围分页正查本租户的签发记录,适合合规 / 审计场景按主体追溯「某用户的 AI 消费历史」。仅返回本租户数据。因可枚举消费历史、敏感度较高,使用独立于验证的 scope:client:rag:issuance。
bash
curl -X POST 'https://atkonbase.example.com/api/v1/rag/issuances' \
-H 'Authorization: Bearer ${accessToken}' \
-H 'Content-Type: application/json' \
-d '{
"subjectUserId": "${subjectUserId}",
"issuedFrom": "2026-06-01T00:00:00Z",
"issuedTo": "2026-06-30T23:59:59Z",
"pageNumber": 1,
"pageSize": 20
}'返回分页的签发记录,每条含 issuanceId / subject(签发给谁)/ clientId(经哪个客户端签发)/ queryText(当时的查询)/ chunkIds / issuedAt / expiresAt(均不回正文)。
三个 scope 各自独立授予——
client:rag:sign(签发)、client:rag:verify(验证)、client:rag:issuance(审计正查)——与client:rag:retrieve互不替代,按需在开通时申请。
常见坑
- ⚠️ 拿 APP_ONLY 身份调用:
/v1/rag/retrieve与/v1/rag/sign均返回 HTTP 403。RAG 召回与签发的权限过滤以用户为单位,服务端到服务端的批处理场景也必须以弱通道(act-as)指明代表的用户。 - ⚠️ scope 漏授权:
client:rag:retrieve默认不预授,未授权时返回 Scope 不足错误码(102002)。开通时与client:search:read分别申请。 - ⚠️ 刚发布就检索:片段处理是发布后异步进行的,立即检索可能召不回新内容。批量灌库后建议留出处理时间,再做验证性检索。
- ⚠️ 跨查询比较
score或设固定阈值:相关性分只在单次结果内有序,不同查询、不同时期的分值不可比;按名次(topK)截取,不要按分值硬过滤。 - ⚠️ 用户搜不到「自己刚上传」的内容:先确认文档已发布(草稿不入语料),再确认该用户对文档有读权限。
- ⚠️ 把
topK传大于 100:直接报错拒绝,不会静默截断到 100。 - ⚠️ 签发时代表一个无效用户:以代授权代表的用户在有效化后无有效身份(例如该用户已被禁用)时,
/v1/rag/sign返回176018——签发须落定主体并据此留档,无有效主体则拒绝(不会发出主体为空的回执)。确保代表一个有效且启用的用户调用。
下一步
- 按关键词搜文档(文档粒度、带高亮) → 全文搜索模式篇
- 强通道 / 弱通道怎么选 → 认证与身份双通道
- 给用户授予内容读权限 → ACL 与继承模式篇