693cd952cd
仓库首次入库(此前仅存在于本地工作区与测试服构建产物中,未上传)。 改动(src/knowledge_adapter/asset_content_processor.py): - 新增 _TRUNCATED_TRAILING_MARKDOWN_RESOURCE_IMAGE 规则,清除 chunk 末尾被截断的  - 回归测试 tests/test_asset_content_processor.py:: test_truncated_trailing_markdown_resource_image_is_removed 验证证据: - 测试服 120.76.217.51,镜像 knowledge-adapter-service:reviewed-test-aeab4b5fca2d (release aeab4b5fca2d8661):KB d015d05c-25c8-4d63-b2ab-e8590d3c2dfb 5 个查询全部 http=200、records=5、残留 resource:// = 0;KB b9dacd62 无退化;容器日志无 error/exception - 本地:pytest 141 项全通过、ruff 全通过 - 该文件与 258c31e0fe07fd08 源码的差异经逐文件 md5 比对,为唯一变更文件
357 lines
8.9 KiB
Markdown
357 lines
8.9 KiB
Markdown
# 测试环境 WeKnora 检索 API 调用说明
|
||
|
||
## 1. 当前状态
|
||
|
||
公网HTTPS链路已经通过真实验收:
|
||
|
||
```text
|
||
Dify/业务后端
|
||
→ https://weknora-api-test.dobot.cn/retrieval
|
||
→ 公网测试入口
|
||
→ 测试ECS Nginx:80
|
||
→ Knowledge Adapter:18080
|
||
→ WeKnora knowledge-search
|
||
```
|
||
|
||
真实验收结果:
|
||
|
||
```text
|
||
检索:HTTP 200
|
||
records:5
|
||
稳定图片UUID:15
|
||
图片:稳定UUID 302 → 私有OSS签名取图 HTTP 200
|
||
```
|
||
|
||
完整且已脱敏的真实请求与响应:
|
||
|
||
```text
|
||
docs/test-api-request-response.txt
|
||
```
|
||
|
||
## 2. 接口地址与安全边界
|
||
|
||
### 检索地址
|
||
|
||
```http
|
||
POST https://weknora-api-test.dobot.cn/retrieval
|
||
```
|
||
|
||
这是服务端到服务端接口:
|
||
|
||
```text
|
||
Dify可以直接调用
|
||
业务后端/BFF可以直接调用
|
||
浏览器前端不能携带Adapter API Key直接调用
|
||
```
|
||
|
||
浏览器推荐链路:
|
||
|
||
```text
|
||
浏览器前端
|
||
→ 业务后端/BFF
|
||
→ Adapter
|
||
→ WeKnora
|
||
```
|
||
|
||
禁止把真实API Key写入:
|
||
|
||
- 前端JavaScript或打包产物;
|
||
- Git仓库;
|
||
- URL查询参数;
|
||
- LocalStorage或SessionStorage;
|
||
- 普通日志、埋点或错误上报。
|
||
|
||
## 3. 请求方法
|
||
|
||
### Headers
|
||
|
||
```http
|
||
Authorization: Bearer [TEST_DIFY_KEY]
|
||
Content-Type: application/json
|
||
Accept: application/json
|
||
X-Request-ID: <可选,建议使用UUID>
|
||
```
|
||
|
||
对外调用使用的是Dify Bearer Key。WeKnora API Key和OSS凭据只由Adapter内部使用,不能提供给Dify或浏览器。
|
||
|
||
### Body
|
||
|
||
```json
|
||
{
|
||
"knowledge_id": "b9dacd62-87eb-4b38-a6b6-85f68e144796",
|
||
"query": "接线",
|
||
"retrieval_setting": {
|
||
"top_k": 5,
|
||
"score_threshold": 0.2
|
||
}
|
||
}
|
||
```
|
||
|
||
### 字段说明
|
||
|
||
| 字段 | 类型 | 必填 | 说明 |
|
||
|---|---:|---:|---|
|
||
| `knowledge_id` | UUID字符串 | 是 | 测试环境“对外知识库”固定为 `b9dacd62-87eb-4b38-a6b6-85f68e144796` |
|
||
| `query` | 字符串 | 是 | 用户问题;去除首尾空格后不能为空,最多2000字符 |
|
||
| `retrieval_setting.top_k` | 整数 | 是 | 至少为1,当前上限为5 |
|
||
| `retrieval_setting.score_threshold` | 浮点数 | 是 | 范围0至1;业务建议初始使用0.2,排查召回问题时可临时使用0 |
|
||
| `metadata_condition` | 对象 | 否 | 当前不支持非空过滤条件,调用方应省略 |
|
||
|
||
`knowledge_id`应由Dify或业务后端固定,不能接受浏览器任意指定。
|
||
|
||
## 4. 应答格式
|
||
|
||
成功响应:
|
||
|
||
```json
|
||
{
|
||
"records": [
|
||
{
|
||
"content": "Markdown格式的知识片段",
|
||
"score": 0.82,
|
||
"title": "文档标题",
|
||
"metadata": {
|
||
"knowledge_base_id": "知识库UUID",
|
||
"knowledge_id": "文档UUID",
|
||
"chunk_id": "Chunk UUID",
|
||
"chunk_index": 1,
|
||
"chunk_type": "text"
|
||
}
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
真实公网响应节选(`content`为缩写,完整正文见TXT样本):
|
||
|
||
```json
|
||
{
|
||
"records": [
|
||
{
|
||
"content": "<Markdown知识片段,包含稳定的 /i/<UUID> 图片地址>",
|
||
"score": 0.5314404987902756,
|
||
"title": "Dobot Magician Go用户手册V1.1_20240624_cn.pdf",
|
||
"metadata": {
|
||
"knowledge_base_id": "b9dacd62-87eb-4b38-a6b6-85f68e144796",
|
||
"knowledge_id": "3c878f4e-bfea-4c5c-b122-b63ba9db4e34",
|
||
"chunk_id": "d674ba02-7769-4e9a-8596-961cb50e1f75",
|
||
"chunk_index": 53,
|
||
"chunk_type": "text"
|
||
}
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
字段说明:
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
|---|---:|---|
|
||
| `records` | 数组 | 检索结果;没有命中时为空数组 |
|
||
| `records[].content` | 字符串 | Markdown知识片段,不是大模型生成的最终答案 |
|
||
| `records[].score` | 浮点数 | 当前检索相关度分数;不要跨模型或跨版本硬编码绝对含义 |
|
||
| `records[].title` | 字符串 | 来源文档标题 |
|
||
| `records[].metadata` | 对象 | 知识库、文档和Chunk审计标识 |
|
||
|
||
该接口只负责检索。Dify拿到`records`后,再将知识片段交给大模型生成最终回答。
|
||
|
||
## 5. curl调用示例
|
||
|
||
真实Key应由运行环境或密钥系统注入,不要直接写进脚本:
|
||
|
||
```bash
|
||
curl --request POST \
|
||
'https://weknora-api-test.dobot.cn/retrieval' \
|
||
--header "Authorization: Bearer ${WEKNORA_ADAPTER_API_KEY}" \
|
||
--header 'Content-Type: application/json' \
|
||
--header 'Accept: application/json' \
|
||
--header "X-Request-ID: $(python3 -c 'import uuid; print(uuid.uuid4())')" \
|
||
--data '{
|
||
"knowledge_id": "b9dacd62-87eb-4b38-a6b6-85f68e144796",
|
||
"query": "接线",
|
||
"retrieval_setting": {
|
||
"top_k": 5,
|
||
"score_threshold": 0.2
|
||
}
|
||
}'
|
||
```
|
||
|
||
## 6. Node.js服务端调用示例
|
||
|
||
下面代码只能运行在Node.js服务端或BFF,不能放入浏览器包:
|
||
|
||
```js
|
||
import { randomUUID } from "node:crypto";
|
||
|
||
const ADAPTER_URL = "https://weknora-api-test.dobot.cn/retrieval";
|
||
const KNOWLEDGE_ID = "b9dacd62-87eb-4b38-a6b6-85f68e144796";
|
||
|
||
export async function retrieveKnowledge(query) {
|
||
const apiKey = process.env.WEKNORA_ADAPTER_API_KEY;
|
||
if (!apiKey) {
|
||
throw new Error("WEKNORA_ADAPTER_API_KEY is not configured");
|
||
}
|
||
|
||
const response = await fetch(ADAPTER_URL, {
|
||
method: "POST",
|
||
headers: {
|
||
Authorization: `Bearer ${apiKey}`,
|
||
"Content-Type": "application/json",
|
||
Accept: "application/json",
|
||
"X-Request-ID": randomUUID(),
|
||
},
|
||
body: JSON.stringify({
|
||
knowledge_id: KNOWLEDGE_ID,
|
||
query,
|
||
retrieval_setting: {
|
||
top_k: 5,
|
||
score_threshold: 0.2,
|
||
},
|
||
}),
|
||
signal: AbortSignal.timeout(25000),
|
||
});
|
||
|
||
if (!response.ok) {
|
||
throw new Error(`Knowledge retrieval failed: HTTP ${response.status}`);
|
||
}
|
||
|
||
const body = await response.json();
|
||
if (!body || !Array.isArray(body.records)) {
|
||
throw new Error("Invalid knowledge retrieval response");
|
||
}
|
||
return body.records;
|
||
}
|
||
```
|
||
|
||
日志中只建议记录:
|
||
|
||
```text
|
||
X-Request-ID、HTTP状态、耗时、records数量
|
||
```
|
||
|
||
不要记录:
|
||
|
||
```text
|
||
Authorization、API Key、完整问题、完整知识正文、图片302 Location
|
||
```
|
||
|
||
## 7. 浏览器调用BFF示例
|
||
|
||
浏览器只调用业务后端,不携带Adapter API Key:
|
||
|
||
```js
|
||
const response = await fetch("/api/knowledge/retrieve", {
|
||
method: "POST",
|
||
headers: { "Content-Type": "application/json" },
|
||
body: JSON.stringify({ query: userInput }),
|
||
});
|
||
|
||
if (!response.ok) {
|
||
throw new Error(`检索失败:HTTP ${response.status}`);
|
||
}
|
||
|
||
const { records } = await response.json();
|
||
```
|
||
|
||
业务后端负责补充:
|
||
|
||
```text
|
||
Authorization
|
||
knowledge_id
|
||
retrieval_setting
|
||
X-Request-ID
|
||
```
|
||
|
||
## 8. Dify配置
|
||
|
||
在Dify外部知识库API中填写:
|
||
|
||
```text
|
||
Endpoint:
|
||
https://weknora-api-test.dobot.cn/retrieval
|
||
|
||
API Key:
|
||
测试环境Adapter原始Key
|
||
|
||
External Knowledge ID:
|
||
b9dacd62-87eb-4b38-a6b6-85f68e144796
|
||
```
|
||
|
||
不要把Dify直接指向WeKnora原生`/api/v1/knowledge-search`。协议转换、知识库白名单、响应裁剪和图片稳定URL都由Adapter负责。
|
||
|
||
## 9. 图片调用方法
|
||
|
||
检索结果中的图片使用稳定地址:
|
||
|
||
```text
|
||
https://weknora-api-test.dobot.cn/i/<UUID>
|
||
```
|
||
|
||
真实样例:
|
||
|
||
```text
|
||
https://weknora-api-test.dobot.cn/i/02e269e8-c4f0-4b3f-a41e-82f5b222a31f
|
||
```
|
||
|
||
前端直接将稳定地址作为图片地址:
|
||
|
||
```html
|
||
<img src="https://weknora-api-test.dobot.cn/i/<UUID>" alt="知识图片">
|
||
```
|
||
|
||
图片访问不需要Bearer Key:
|
||
|
||
```text
|
||
浏览器GET /i/<UUID>
|
||
→ Adapter查询有效映射
|
||
→ HTTP 302
|
||
→ 私有OSS 10分钟签名URL
|
||
→ 图片HTTP 200
|
||
```
|
||
|
||
注意:
|
||
|
||
- 保存和渲染稳定`/i/<UUID>`地址;
|
||
- 不保存、不打印、不缓存302后的OSS签名地址;
|
||
- 10分钟过期的是OSS签名地址,不是稳定UUID地址;
|
||
- 稳定UUID属于能力链接,不应进入无关日志或公开页面;
|
||
- OSS Bucket继续保持Private。
|
||
|
||
真实图片验收:
|
||
|
||
```text
|
||
稳定UUID:HTTP 302
|
||
Cache-Control:no-store
|
||
Referrer-Policy:no-referrer
|
||
私有OSS匿名访问:HTTP 403
|
||
短期签名取图:HTTP 200
|
||
类型:image/jpeg
|
||
大小:56,025 bytes
|
||
JPEG结构:有效
|
||
```
|
||
|
||
## 10. 错误码
|
||
|
||
| HTTP状态 | 含义 | 调用方处理 |
|
||
|---:|---|---|
|
||
| 200 | 成功 | 读取`records`,允许空数组 |
|
||
| 400 | 请求格式错误或知识库未授权 | 不重试;检查请求字段和固定`knowledge_id` |
|
||
| 401 | API Key缺失或错误 | 不重试;检查服务端Secret配置 |
|
||
| 403 | 请求方法被Nginx拒绝 | 不重试;确认使用`POST /retrieval`或`GET /i/<UUID>` |
|
||
| 404 | 路径或图片UUID不存在 | 不重试;检查地址 |
|
||
| 502 | WeKnora响应异常或内容处理失败 | 记录Request ID,有限重试并告警 |
|
||
| 503 | WeKnora超时、暂时不可用或图片签名失败 | 建议退避重试1至2次,仍失败则降级 |
|
||
|
||
不要自动重试400、401、403和404。
|
||
|
||
## 11. 联调检查表
|
||
|
||
- [x] 公网HTTPS回源测试ECS Nginx 80;
|
||
- [x] 保留`Host`、`Authorization`、`Content-Type`和`X-Request-ID`;
|
||
- [x] 无Key请求返回401;
|
||
- [x] 正确Key请求返回HTTP 200和`records`;
|
||
- [x] 有图结果返回稳定UUID,图片302和最终下载通过;
|
||
- [ ] 前端构建产物中确认不存在Adapter API Key;
|
||
- [ ] 业务日志中确认没有Authorization、完整正文和OSS签名URL;
|
||
- [ ] 生产环境使用独立域名、独立Key和独立知识库白名单。
|