# 测试环境 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": " 图片地址>", "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/ ``` 真实样例: ```text https://weknora-api-test.dobot.cn/i/02e269e8-c4f0-4b3f-a41e-82f5b222a31f ``` 前端直接将稳定地址作为图片地址: ```html 知识图片 ``` 图片访问不需要Bearer Key: ```text 浏览器GET /i/ → Adapter查询有效映射 → HTTP 302 → 私有OSS 10分钟签名URL → 图片HTTP 200 ``` 注意: - 保存和渲染稳定`/i/`地址; - 不保存、不打印、不缓存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/` | | 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和独立知识库白名单。