20 KiB
20 KiB
05 AI 对话与知识库问答 — 跨项目完整能力分析
项目角色分类:主链路(iOS、主 API、DeepSeek 模型服务)、上游支撑(Python RAG Worker,仅为知识库内容供给,不参与对话上下文加载)、运维可观测(Admin)。 Qdrant 不参与对话上下文加载——所有 5 种 Scope 的上下文均来自 PostgreSQL KnowledgeItem 表。 Heavy Runtime 不直接参与基础 AI 对话——它负责异步 AI 分析任务(学习状态分析、测验生成等),对话链路走 AiGateway 直达模型。 Rust Document Runtime 不参与 AI 对话链路。
1. 能力目标
用户可以通过自然语言与 AI 进行学习相关的对话。对话可以限定在特定知识库、资料或知识点的范围内,AI 基于范围内知识内容回答问题,并提供来源引用。支持流式回复、思考过程展示和多会话管理。
2. C 端入口
| 入口页面 | 对话范围 | 触发方式 |
|---|---|---|
| AI 反馈页 | 全局 | "深入提问"按钮 |
| 知识库详情页 | 知识库 | 底部 AI 对话按钮 |
| 资料阅读页 | 资料 | 工具栏 AI 按钮 |
| 知识点详情页 | 知识点 | 工具栏菜单(如有) |
| AI 反馈页 → AIChatPage | 全局 | "深入提问" → AIChatPage |
| (废弃)AI 首页 | 全局 | 底部输入栏(页面无入口) |
3. 对话范围
3.1 全局对话(scopeType: global)
- 上下文来源: 无知识库上下文。AI 仅基于通用知识回答。
- RAG 查询范围: 不进行任何检索。
- 会话识别: 创建 session 时 scopeType=global 且 scopeId 为空。
- 切换处理: 用户从范围对话点击"新建对话"可创建全局对话。
3.2 知识库范围(scopeType: knowledge_base)
- 上下文来源: 从 KnowledgeItem 表查询该知识库下的知识点(最多 30 条,每条截取前 500 字符,总计最多 4000 字符)。
- RAG 查询范围: 上下文直接从 PostgreSQL 的 KnowledgeItem 表加载。所有 5 种 Scope 均不调用 Qdrant——
loadContextByScope在代码中完全不涉及向量搜索。 - 会话识别: 创建 session 时 scopeType=knowledge_base,scopeId=。相同知识库范围的会话通过 "open-or-create" 模式复用(同一用户同一知识库只有一个活跃对话会话)。
- 切换处理: 用户切换到另一个知识库的对话时,创建新会话或恢复已有会话。
3.3 资料范围(scopeType: material)
- 上下文来源: 按 sourceRef 匹配该资料关联的知识点。与知识库范围相同,上下文直接从 PostgreSQL 的 KnowledgeItem 表加载。Qdrant 不参与对话上下文加载。
- 会话识别: session 的 scopeType=material,scopeId=。
- 切换处理: 用户离开资料阅读页后,对话会话保留。下次进入同一资料时恢复。
3.4 知识点范围(scopeType: knowledge_item)
- 上下文来源: 单个知识点的完整内容。
- RAG 查询范围: 单个知识点本身,无需检索。
- 会话识别: session 的 scopeType=knowledge_item,scopeId=。
- 切换处理: 每个知识点有独立会话。
3.5 范围切换机制
- 用户在不同入口进入 AI 对话时,系统根据当前上下文自动确定对话范围。
- 每个范围维护独立的 ChatSession。
- 会话列表 Sheet 可按范围过滤显示。
- ScopeSnapshot 保存在每条消息中,确保历史消息知道其产生时的范围上下文。
4. 用户主流程
用户进入对话(从知识库详情页/资料阅读页/AI 反馈页等入口)
→ iOS 调用 API 创建或恢复会话(open-or-create,相同范围复用会话)
→ 用户输入消息
→ iOS 调用流式发送 API(POST /rag-chat/sessions/:id/stream)
→ API 校验会话所有权
→ API 内容安全检查(敏感词匹配)
→ API 保存用户消息(含 scopeSnapshot)
→ API 自动生成会话标题(首次消息时,截取前 40 字符)
→ API 根据 scopeType 加载上下文:
- global:空上下文
- knowledge_base:从 KnowledgeItem 表查询最多 30 条(每条约 500 字符)
- material/folder:按相应过滤条件查询
- knowledge_item:查询单个知识点
→ API 将上下文注入系统提示模板
→ API 调用 AiGateway → 路由到 DeepSeek Provider → deepseek-v4-pro
→ DeepSeek 流式返回(content 块 + thinking 块)
→ API 通过 SSE 逐块转发给 iOS
→ iOS 实时展示 AI 回复(含思考过程可折叠动画)
→ 流式完成后 API 保存 AI 消息(含 token 计数)
→ API 保存引用(前 5 个上下文项作为 ChatCitation)
→ iOS 展示引用信息
→ 用户可复制回复、重新生成、或发送新消息
5. 项目职责
iOS — 主链路参与者
- AI 对话界面(消息气泡、思考过程展示、引用展示)
- 流式接收与实时渲染(SSE 解析)
- 输入栏(文字输入、语音图标占位、发送按钮)
- 会话列表 Sheet(搜索、切换、删除、归档、置顶)
- 新建对话
- 范围标签展示(当前对话限定范围)
- 复制回复、重新生成
主 API — 主链路参与者
- 会话 CRUD(open-or-create、列表、更新、软删除)
- 会话所有权校验
- 消息发送(同步 + 流式)
- 内容安全检查(输入消息和 AI 输出)
- 上下文加载(按 scopeType 从 KnowledgeItem 表查询)
- 系统提示构建(上下文注入)
- AiGateway 路由(模型选择、回退、重试)
- SSE 流式转发
- 引用保存(ChatCitation)
- Token 使用记录(ModelInvocationLog)
- 自动标题生成
DeepSeek 模型服务 — 主链路参与者
- 接收系统提示 + 用户消息 + 上下文
- 流式生成回复(content + reasoning_content)
- 模型:deepseek-v4-pro(primary tier),deepseek-v4-flash(cheap tier)
- 通过 AiGateway 统一管理 API 密钥和路由
Python RAG Worker — 上游支撑(间接参与)
- 不直接参与对话流程。负责文档导入后的处理(解析→分块→嵌入→索引),为知识库提供结构化的知识点内容。
- RAG 处理结果(KnowledgeItem、KnowledgeChunk)是对话上下文的间接来源——KnowledgeItem 表中的内容可能来自 RAG 生成的候选知识点。
- 注意:知识库范围对话的上下文来自 KnowledgeItem 表(PostgreSQL),不依赖 Qdrant 向量搜索,也不依赖 RAG 的实时处理状态。
Qdrant — 不参与对话上下文加载
- 存储文档块的向量索引,用于文档导入后的语义检索(Admin RAG 调试页使用)。
- 不参与 AI 对话的上下文加载——
loadContextByScope完全不调用 Qdrant,所有 5 种 Scope 的上下文均来自 PostgreSQL。
Admin — 运维与可观测
- 会话日志查看(Admin 聊天日志页,查看所有会话和消息)
- AI 网关管理(路由规则、提供商管理、回退日志)
- AI 使用统计(调用次数、延迟、失败率、成本,按提供商和模型)
- AI 成本管理(费用记录、按用户统计、导出)
- 模型配置(temperature、max_tokens 等参数)
- 内容安全审核(敏感词库、审核记录、举报管理、违规处罚)
Heavy Runtime — 不直接参与
Heavy Runtime 负责异步 AI 分析任务(学习状态分析、薄弱点识别、测验生成、闪卡生成),通过独立的作业排队机制运作。基础 AI 对话不经过 Heavy Runtime,而是通过 AiGateway 直接调用 DeepSeek。
6. 会话管理
6.1 创建
- 方式: open-or-create 模式。用户从入口进入对话时,iOS 调用 POST /rag-chat/sessions。
- 复用逻辑: 相同 scopeType + scopeId + userId 下存在未归档未删除的会话时,返回已有会话(HTTP 200)。否则创建新会话(HTTP 201)。
- 这意味着: 每个用户在每个知识库范围内只有一个活跃对话会话。
6.2 切换
- 方式: 用户在会话列表 Sheet 中点击历史会话 → iOS 调用 API 加载该会话的消息历史。
- 效果: 当前对话界面切换到所选会话,范围标签更新。
6.3 搜索
- 方式: 在会话列表 Sheet 中输入搜索词 → 本地过滤或 API 搜索。
- 范围: 当前范围内的会话。
6.4 归档
- 方式: 会话列表 Sheet 中滑动 → "归档"。
- 效果: API 更新会话 isArchived=true。已归档会话不在默认列表中显示。
- 恢复: 可通过更新 isArchived=false 取消归档。
6.5 删除
- 方式: 会话列表 Sheet 中滑动 → "删除"。
- 效果: API 软删除会话(isDeleted=true)。消息保留在数据库中但不再对用户可见。
6.6 置顶
- 方式: 会话列表 Sheet 中左滑 → "置顶"/"取消置顶"。
- 效果: API 更新会话 isPinned 状态。置顶会话排在最前。
6.7 Scope(对话范围)
- 每个会话有 scopeType 和 scopeId,确定上下文来源。
- 新建对话时,如果用户从范围入口(知识库/资料)进入,新会话继承该范围。
- 用户也可以在对话中切换到全局模式创建新会话。
6.8 Scope Snapshot(范围快照)
- 每条消息保存一个 scopeSnapshot 对象:{ scopeType, scopeId, parentKnowledgeBaseId }。
- 作用:将消息冻结到发送时的范围上下文。即使后续范围发生变化,历史消息仍知道自己引用了哪个范围的上下文。
6.9 引用(Citation)
- AI 回复后,系统从上下文项中提取前 5 个创建 ChatCitation。
- 每个引用包含:chunkId(知识点 ID)、sourceTitle(标题)、excerptText(内容前 500 字符)。
- iOS 在消息气泡中展示引用信息。
6.10 历史消息
- iOS 进入会话时调用 GET /rag-chat/sessions/:id/messages 加载历史。
- 消息按时间排序,含角色(user/assistant)、内容、token 数和引用。
7. 核心业务数据
7.1 对话会话(ChatSession)
- 谁创建: API 在 iOS 调用 open-or-create 时创建(或返回已有)。
- 谁更新: API 在每次消息发送时更新 lastMessageAt;iOS 操作更新 isPinned/isArchived/isDeleted/title/modelMode/modelId。
- 谁查询: iOS 获取会话列表和消息历史;Admin 在聊天日志页查看。
- 用途: 对话的组织单元,承载范围信息和消息列表。
7.2 对话范围(ChatScope)
- 概念性对象(非独立数据库表),由 ChatSession 的 scopeType + scopeId 定义。
- 取值: global、knowledge_base、folder、material、knowledge_item。
- 用途: 确定上下文加载策略和会话唯一性。
7.3 消息(ChatMessage)
- 谁创建: API 在发送流程中创建用户消息和 AI 消息。
- 谁更新: 创建后不可修改。
- 谁查询: iOS 加载会话消息历史;Admin 在聊天日志详情中查看。
- 用途: 对话的完整记录,含角色、内容、token 数、scopeSnapshot。
7.4 引用(ChatCitation)
- 谁创建: API 在 AI 回复保存后自动创建(从前 5 个上下文项提取)。
- 谁更新: 创建后不可修改。
- 谁查询: iOS 在消息详情中展示;消息列表查询时惰性加载。
- 用途: 为 AI 回复提供可追溯的来源引用。
7.5 范围快照(ScopeSnapshot)
- 概念性对象(嵌入在 ChatMessage 中),包含 { scopeType, scopeId, parentKnowledgeBaseId }。
- 用途: 冻结每条消息产生时的对话范围。
7.6 知识分块(KnowledgeChunk)
- 谁创建: Python RAG Worker 在文档处理时创建。
- 谁更新: 不更新(软删除通过 Qdrant 实现)。
- 谁查询: Admin 在分块管理页查看;Qdrant 向量搜索(当前仅 Admin RAG 调试页使用,不用于对话上下文加载)。
- 用途: 文档的语义检索向量索引。当前不参与 AI 对话上下文构建。
7.7 模型配置(Model Configuration)
- 谁管理: Admin 通过 AI 网关管理页配置路由规则和提供商。
- 谁使用: AiGateway 在每次对话请求时根据 tier(primary/cheap/strong)和 taskType 选择模型。
- 当前配置: primary tier → deepseek-v4-pro;cheap tier → deepseek-v4-flash。
8. 异常与降级
8.1 RAG 尚未处理完成
- 场景: 资料已上传但 Python RAG Worker 尚未完成向量索引。
- 影响: 知识库范围对话的上下文来自 KnowledgeItem 表——不受 RAG 处理状态影响。所有 Scope 的上下文加载均不依赖 Qdrant,RAG 未完成不影响对话功能。
8.2 检索无结果
- 场景: 知识库为空或范围内无匹配知识点。
- API 处理: loadContextByScope 返回 isEmpty=true。系统提示注入"当前知识库中暂无相关内容"。
- 模型行为: AI 基于通用知识回答,可能告知用户知识库内容不足。
8.3 模型调用失败
- 场景: DeepSeek API 返回错误(超时、限流、服务异常)。
- API 处理: AiGateway 自动回退(fallback 到同 tier 的备用模型/提供商),最多重试 3 次。
- 用户感知: 如果所有重试均失败,返回错误提示。Admin 可在回退日志中查看详情。
8.4 流式响应中断
- 场景: SSE 连接在网络问题或客户端断开时中断。
- API 处理: 检测 res.destroyed,优雅停止流式输出。已生成的部分内容可能不保存为完整消息(取决于中断时机)。
- iOS 处理: 显示连接中断提示。用户可重新发送消息。
8.5 用户取消生成
- 场景: 用户在 AI 生成过程中取消(iOS 断开 SSE 连接或发送取消请求)。
- API 处理: 检测连接断开,停止流式输出。
- 影响: 部分生成的内容不保存。用户可重新发送。
8.6 会话被删除
- 场景: 用户或 Admin 删除会话。
- API 处理: 软删除(isDeleted=true)。消息保留但不可见。
- 用户感知: 会话从列表中消失。已删除会话不可恢复(当前无回收站功能)。
8.7 资料被删除
- 场景: 对话引用的知识库/资料/知识点被删除。
- API 处理: 上下文加载时自动过滤已删除项。历史消息的 scopeSnapshot 仍保留原范围信息,但该范围可能不再可访问。
- 用户感知: 新对话中该范围无上下文可用。历史消息仍可查看但引用可能失效。
8.8 无权限
- 场景: 用户尝试访问其他用户的会话。
- API 处理: 会话所有权校验失败,返回 403/404。
- 用户感知: 无法查看或操作非自己的会话。
8.9 Token 超限
- 场景: 上下文 + 对话历史超过模型上下文窗口。
- API 处理: 上下文加载有 4000 字符硬限制。长对话历史可能需要截断(具体策略待确认)。
- 用户感知: 较早的对话内容可能不被模型考虑。
8.10 模型 API Key 无效
- 场景: 平台 DeepSeek API Key 过期或余额不足。
- API 处理: AiGateway 调用失败。如果用户配置了自己的 API Key,可回退到用户 Key。
- Admin 处理: Admin 在密钥管理页更新或轮换 Key。
- 用户感知: 对话报错。用户可在 AI 设置中提供自己的 DeepSeek Key。
8.11 DeepSeek 服务不可用
- 场景: DeepSeek API 全面不可用。
- API 处理: AiGateway 尝试所有提供商后失败。
- 用户感知: 对话完全不可用,显示服务异常提示。
- Admin 处理: Admin 在 AI 网关管理页监控提供商状态,配置备用提供商。
9. 查询与管理入口
用户查询
- 会话列表: iOS 对话页工具栏 → 会话列表 Sheet(搜索、筛选)。
- 消息历史: iOS 对话页加载历史消息。
- 引用信息: iOS 消息气泡中展示。
- AI 使用统计: iOS 端当前未展示(无用户可见的 token 用量或成本页面)。
Admin 查询
- 会话日志: Admin 聊天日志页 → 查看所有会话(含用户 ID、知识库 ID、消息数)。
- 消息详情: Admin 聊天日志页 → 点击会话查看全部消息(角色、内容预览、token 数、时间)。
- AI 网关管理: Admin AI 网关页(路由规则 CRUD、提供商启用/禁用、回退日志)。
- AI 使用统计: Admin 指标页(按提供商/模型的调用次数、延迟、失败率、成本)。
- AI 成本管理: Admin 计费页(费用记录 CRUD、按用户统计、导出 CSV)。
- 内容安全审核: Admin 内容安全页(敏感词库、审核记录、举报管理、违规处罚)。
系统内部查询与管理
- AiGateway 路由: 每次对话请求时自动查询路由规则和提供商配置。
- Token 使用记录: AiGateway 自动记录每次调用的 inputTokens/outputTokens/延迟/成本到 ModelInvocationLog。
- 每日使用聚合: 系统自动聚合用户和平台的每日 AI 使用量(UserAiUsageDaily、PlatformAiBudgetDaily)。
- 配额检查: 发送消息前检查用户每日配额和平台预算。
10. 当前完成状态
| 组件 | 状态 | 说明 |
|---|---|---|
| iOS 流式对话界面 | 已完成 | SSE 解析 + 思考过程展示 + 引用展示 |
| iOS 消息气泡渲染 | 已完成 | 用户消息紫色渐变 + AI 消息含思考折叠 |
| iOS 复制/重新生成 | 已完成 | 复制到剪贴板 + 重新发送 |
| iOS 会话列表 Sheet | 已完成 | 搜索、切换、删除、归档、置顶 |
| iOS 新建对话 | 已完成 | 强制创建新会话 |
| iOS 范围标签展示 | 已完成 | 对话顶部显示当前范围 |
| iOS 全局对话 | 已完成 | 无上下文对话 |
| iOS 知识库范围对话 | 已完成 | 从知识库详情页底部按钮进入 |
| iOS 资料范围对话 | 已完成 | 从资料阅读页工具栏 AI 按钮进入 |
| iOS 知识点范围对话 | 暂未确认 | API scopeType=knowledge_item 已定义;iOS 知识点详情页工具栏菜单未发现直接 AI 对话入口,可能需从知识点详情页手动跳转 |
| API open-or-create 会话 | 已完成 | 相同范围复用已有会话 |
| API 内容安全检查 | 已完成 | 输入消息 + AI 输出敏感词匹配 |
| API 上下文加载(KnowledgeItem 表) | 已完成 | 按 scopeType 查询最多 30 条 |
| API 系统提示构建 | 已完成 | 上下文注入到提示模板 |
| API AiGateway 路由 | 已完成 | tier 路由 + 回退 + 重试 |
| API SSE 流式转发 | 已完成 | Content-Type: text/event-stream |
| API 引用保存 | 已完成 | 前 5 个上下文项 → ChatCitation |
| API 自动标题生成 | 已完成 | 首次消息截取前 40 字符 |
| API Token 使用记录 | 已完成 | ModelInvocationLog |
| DeepSeek 模型调用 | 已完成 | deepseek-v4-pro(primary)、deepseek-v4-flash(cheap) |
| Qdrant 参与对话上下文加载 | 未完成 | loadContextByScope 完全不调用 Qdrant;所有 5 种 Scope 上下文均来自 PostgreSQL KnowledgeItem 表 |
| 联网搜索 | 暂未确认 | 未发现联网搜索功能实现 |
| 深度思考 | 已完成 | DeepSeek reasoning_content → SSE thinking 块 → iOS 思考过程展示 |
| 文件附件 | 暂未确认 | 未发现对话中上传文件功能 |
| 导图 | 暂未确认 | 未发现 AI 生成导图功能 |
| 分享 | 暂未确认 | 未发现对话分享功能 |
| 生成笔记 | 暂未确认 | 未发现从对话生成笔记功能 |
| Admin 会话日志查看 | 已完成 | 聊天日志页 |
| Admin AI 网关管理 | 已完成 | 路由规则 + 提供商 + 回退日志 |
| Admin AI 使用统计 | 已完成 | 按提供商/模型的调用统计 |
| Admin AI 成本管理 | 已完成 | 费用记录 + 按用户统计 + 导出 |
| Admin 内容安全审核 | 已完成 | 敏感词库 + 审核记录 + 举报 + 违规 |
| 用户 AI 用量展示 | 未完成 | iOS 端无 token 用量或配额展示 |
| 用户自定义 API Key | 已完成 | iOS 设置页 → AI 设置 → 输入自己的 DeepSeek Key |
| 平台预算回退 | 已完成 | 平台预算不足时自动回退到用户 Key |