Answer API 技术设计
# Answer API 技术设计
修订记录
| 版本 | 日期 | 修订说明 |
|---|---|---|
| v0.1 | 2026-05-01 | 建立当前设计基线;延续 kunora-wiki 作为 llm-wiki 方案的既有产品封板和工程设计,不推倒重来。 |
1. 摘要
Answer API 是 kunora-wiki 对用户和系统提供标准问答能力的自研入口。它接收 AnswerRequest,校验 caller、scope 和 dataset 权限,调用 RAGFlow 或索引查询能力获取候选上下文,把外部结果转换为标准 AnswerResult、Citation、SuggestedAction 和审计记录。
Answer API 不实现第二套 RAG,不直接修改知识库内容,不在无证据或索引不可用时编造答案。知识库无法回答时,它返回 answer.no_answer、原因和反馈/改进动作,而不是伪造低质量答案。
2. 模块目标
- 提供稳定
AnswerRequest/AnswerResultPublic Contract。 - 校验请求 schema、caller、scope、dataset 和 session 权限。
- 查询 RAGFlow 或标准搜索索引,并标准化 citation。
- 在
requireCitations=true时保证答案有可回跳证据。 - 对无答案、低置信度、索引不可用提供可操作 actions。
- 产生 request-level audit,便于追踪调用来源、scope 和结果。
3. 非目标
- 不直接写
publish/**或创建 PR。 - 不直接调用 AgentBridge 自动修文档。
- 不绕过 Agent Access API 创建反馈或改进任务;只返回建议动作或调用受控入口。
- 不把 RAGFlow chunk id 作为主引用。
- 不返回未授权 scope 中的内容。
- 不把 RAGFlow 私有响应结构暴露给客户端。
4. 上下文边界
Answer API 位于 L3 Access 层。它可以依赖 ConfigManager、manifest reader、RagflowClient、SearchIndexClient,但不能依赖 AgentBridge。
5. 输入与输出
5.1 输入
| 输入 | 来源 | 说明 |
|---|---|---|
AnswerRequest | 前端、系统、Agent Access API | 标准问答请求。 |
ConfigBundle / ModelPolicy | ConfigManager | dataset、模型策略、scope 策略。 |
PageManifest | WorkspaceStore / Display Adapter | 引用回跳、页面可见性。 |
IndexManifest | Index Adapter | 可用索引目标和滞后状态。 |
| RAGFlow answer/search result | RagflowClient | 外部 RAG 结果。 |
| SearchResult | SearchIndexClient | 检索结果。 |
5.2 输出
| 输出 | 消费者 | 说明 |
|---|---|---|
AnswerResult | 前端、系统、Agent Access API | 标准答案或无答案结果。 |
Citation[] | 客户端、审计、反馈 | 可回跳引用。 |
SuggestedAction[] | 前端、Agent Access API | create_feedback、create_improvement_task 等建议。 |
AuditEvent / AuditRef | 审计系统、日志 | 调用记录。 |
ErrorObject[] | 客户端、日志 | 标准错误。 |
6. 依赖的 common 契约
| 契约 | 用途 |
|---|---|
Caller | 调用者身份。 |
Scope | 请求范围和版本。 |
AnswerRequest | API 输入。 |
AnswerResult | API 输出。 |
Citation | 引用结构。 |
SearchResult | 索引检索结果。 |
PageManifest | citation URL 和授权过滤。 |
IndexManifest | 索引可用性判断。 |
FeedbackRequest / ImprovementTaskRequest | SuggestedAction payload 参考。 |
AuditEvent / AuditRef | 审计。 |
ErrorObject | 错误输出。 |
7. 核心流程
流程要求:
- 请求进入时必须生成或接受可信
requestId。 - caller 声明的 scope 只是请求,实际 scope 必须由服务端 policy 收敛。
- 检索结果必须经过 PageManifest 过滤,排除不可见或越权页面。
requireCitations=true且无法生成引用时,不返回确定答案。- RAGFlow 不可用时返回错误或降级结果,不编造答案。
8. 权限与 scope
| 校验 | 规则 |
|---|---|
| caller | 必须可识别;匿名 caller 只能访问公开 scope。 |
| paths | 结果 path 必须落在 effective scope 内。 |
| datasets | 请求 dataset 必须属于 policy 允许集合。 |
| version | MVP 默认只允许 main;working 需要显式授权。 |
| includeWorkingDocs | 默认 false,true 时必须由 policy 允许。 |
| sessions | session scope 不能扩大首次请求 scope。 |
拒绝时返回 answer.forbidden_scope、answer.dataset_not_allowed 或 answer.session_forbidden。
9. 答案生成与 citation 规 则
Answer API 不直接信任外部 RAG 的引用,需要标准化为 Citation:
- citation 必须包含
path。 - 推荐包含
documentId和url。 url来自 PageManifest,不从外部 RAG 私有字段直接透传。externalChunkId可保存,但不能作为唯一引用。- 引用页面必须满足 effective scope 和 qaVisible。
- citation 去重按 documentId + path + anchor + externalChunkId。
置信度规则:
| 条件 | confidence |
|---|---|
| 有足够 citation,答案覆盖问题 | high 或 medium。 |
| 检索结果弱、引用少或答案部分覆盖 | low。 |
| 无可用 citation 且 requireCitations=true | 不返回确定答案,使用 noAnswerReason。 |
10. 无答案与建议动作
answer.no_answer 是有效业务结果,通常 HTTP 200。
| 场景 | noAnswerReason | SuggestedAction |
|---|---|---|
| 检索无结果 | search_no_result | create_feedback、create_improvement_task。 |
| citation 不足 | citation_missing | create_feedback。 |
| 索引不可用 | index_unavailable | retry_later、create_feedback。 |
| scope 过窄 | scope_too_narrow | 提示扩大 scope,但不自动扩大。 |
| 低置信度 | low_confidence | create_feedback。 |
SuggestedAction 只表达可执行建议;真正写入反馈或任务必须走 Agent Access API 或受控 backend。
11. API 语义
| 接口 | 输入 | 输出 | 说明 |
|---|---|---|---|
answer | AnswerRequest | AnswerResult | 标准问答入口。 |
validateAnswerRequest | raw request | validation result | schema 和基础字段校验。 |
resolveAnswerScope | caller、scope | effective scope | 服务端授权后 scope。 |
normalizeCitations | external result、PageManifest | Citation[] | 引用标准化。 |
buildNoAnswerResult | reason、context | AnswerResult | 无答案标准响应。 |
HTTP 映射:
| 场景 | HTTP |
|---|---|
| 正常答案 | 200 |
| 无答案 | 200 |
| partial result | 200 + status=partial 或 confidence low |
| schema 错误 | 400 |
| unauthorized | 401 |
| forbidden scope/dataset | 403 |
| RAGFlow/索引不可用且无降级 | 503 |
12. 状态与持久化
Answer API 默认无长期业务状态。
| 数据 | 是否持久化 | 说明 |
|---|---|---|
| request/session audit | 是 | 用于追踪调用和拒绝。 |
| AnswerResult | 可选 | 可由调用方保存,不作为事实源。 |
| session state | 可选 | 仅保存 scope、history 摘要和过期时间。 |
| feedback/task | 否 | 由 Agent Access API 或 IssueTracker 创建。 |
13. 错误处理
| 错误码 | retryable | 场景 | 处理 |
|---|---|---|---|
answer.invalid_request | false | schema 或问题为空 | HTTP 400。 |
answer.forbidden_scope | false | path/version 越权 | HTTP 403。 |
answer.dataset_not_allowed | false | dataset 越权 | HTTP 403。 |
answer.ragflow_unavailable | true | RAGFlow 不可用 | 不生成虚假答案。 |
answer.no_answer | false | 知识库无法回答 | HTTP 200,带 noAnswerReason。 |
answer.citation_missing | false | requireCitations 但无引用 | 返回无答案或低置信。 |
answer.session_forbidden | false | session 扩大 scope | HTTP 403。 |
answer.session_expired | false | session 过期 | 要求新建 session。 |
14. 安全与审计
以下事件必须审计:
- 所有 answer 请求。
- scope/dataset/session 拒绝。
- 返回无答案和低置信度。
- RAGFlow 或索引不可用。
- citation 被过滤或删除。
审计记录不得包含 token、完整私有配置或未授权文档全文。
15. 测试要求
| 测试 | Fixture | 预期 |
|---|---|---|
| no answer | fixtures/common/answer/no-answer.json | 返回 answer.no_answer,HTTP 200。 |
| citation path anchor | fixtures/common/answer/citation-path-anchor.json | citation 可回跳到展示页面。 |
| search citation | fixtures/common/index/search-result-citation.json | SearchResult 转 Citation。 |
| forbidden scope | fixtures/common/access/forbidden-scope.json | 返回 forbidden,不调用下游。 |
| index partial | fixtures/common/manifest/index-manifest.partial.json | 标记降级或低置信。 |
| RAGFlow unavailable | future answer ragflow unavailable fixture | 不生成虚假答案。 |
模块验收标准:
AnswerRequest和AnswerResult有 schema contract test。requireCitations=true时无 citation 不返回确定答案。- 越权 path/dataset 不出现在答案或 citation 中。
- RAGFlow 私有结构不进入 API response。
- no-answer actions 可被 Agent Access API 消费。
16. 设计决策
| 决策 | 说明 | 取舍 |
|---|---|---|
| 无答案返回 HTTP 200 | 无答案是有效业务结果,不是传输错误。 | 客户端必须读取 noAnswerReason。 |
| Answer API 不直接创建任务 | 写入动作统一走 Agent Access API。 | 前端需要二次调用或后端受控转发。 |
| Citation 必须标准化 | 保证引用可回跳和可审计。 | 需要维护 PageManifest 映射。 |
| 不依赖 RAGFlow 私有 ID | 保持跨索引目标稳定。 | 需要额外 documentId/path 映射。 |
17. 待确认问题
- 多轮 session 的历史是否纳入 AnswerResult audit,还是只保存摘要。
partial result是否需要单独状态字段,还是用 confidence/errors 表达。- Answer API 是否允许直接调用 create_feedback,还是严格只返回 SuggestedAction。
- working version 问答是否进入 MVP。