Files
prop-ai-hr/docs/20260718/问师傅多轮会话与原始资料交付设计.md
T

6.9 KiB

问师傅多轮会话与原始资料交付设计

状态:实施基线,尚未代表代码完成、生产发布或业务验收。

目标:让“问·数字师傅”能理解本次连续对话中的指代,并在当前授权范围内交付命中的原文件或操作视频。

1. 当前事实与问题

mobile-uni/src/pages/user/sop/index.vue 会在页面内展示消息列表,但每次文字查询只向 POST /api/knowledge/query 发送当前 queryText;附件查询同样只向 POST /api/knowledge/query-media 发送当前问题和本次附件。页面刷新、重新进入或服务端生成答案时都没有可用的对话上下文。

因此当前能力是“微信式界面 + 单轮无状态 RAG”,不是多轮智能会话。典型失败包括:

  • 用户先问“自动扶梯困人怎么办”,再说“把这个 SOP 原文件给我”,第二句无法确定“这个”指什么;
  • 用户说“有没有操作视频”,系统仍按普通知识问答检索,可能返回另一份语义相近但无关的 SOP;
  • 命中文档后只有引用片段,缺少经过再次授权校验的原文件或视频入口。

2. 第一版目标与非目标

第一版完成:

  1. 内部登录用户拥有 30 分钟不活跃过期的短期会话;页面可显式“新对话”。
  2. 使用现有 chat 模型把追问改写为可独立检索的问题,并输出 QA、FILE、VIDEO、DATA_TOOL 四类意图。
  3. 改写后的问题继续走现有租户、调用应用、主体授权交集和 RAG 链路。
  4. 文件/视频只从当前命中且仍有权限的知识附件中返回;下载时再次校验权限。
  5. 模型、会话表或附件不可用时明确降级,不编造上下文、链接或文件。

第一版不做:

  • 跨天长期记忆、用户画像记忆或对话向量库;
  • 对外 API_TOKEN 调用端的有状态会话;
  • 自动执行任意数据库查询、自然语言转 SQL;
  • 把用户上传的本次图片/视频自动写入共享知识库;
  • 仅凭语义相似度把未命中的文件伪装成“原文件”。

3. 会话数据

新增单表 aihr_knowledge_conversation,只保存一个会话的压缩 JSON,不拆消息表:

字段 作用
tenant_id、app_id、user_id 会话隔离键,全部由服务端身份解析
conversation_id 客户端持有的随机会话 ID
version 乐观并发版本
context_json 最近最多 6 轮的脱敏问题、截断答案、引用标题/文档 ID
expires_time 30 分钟不活跃过期时间
create_time、update_time 审计时间

约束:单个用户问题最多 600 字、单个答案最多 800 字、送入模型的会话上下文最多 6000 字;过期记录惰性清理。唯一键为 tenant_id + app_id + user_id + conversation_id。客户端不能传租户、应用或用户身份。

4. 查询契约

内部 POST /api/knowledge/query 和 POST /api/knowledge/query-media 增加可选字段:

{
  "conversationId": "01J...",
  "contextVersion": 3
}

响应在现有字段上增加:

{
  "conversationId": "01J...",
  "contextVersion": 4,
  "intent": "FILE",
  "rewrittenQuery": "自动扶梯困人应急操作 SOP 原文件",
  "resources": [
    {
      "attachmentId": 123,
      "title": "自动扶梯困人应急操作 SOP.pdf",
      "type": "FILE",
      "contentUrl": "/api/knowledge/resources/123/content"
    }
  ]
}

旧客户端不传会话字段时继续按无状态查询处理。外部 POST /api/open/knowledge/query 保持无状态,并忽略或拒绝会话字段。

5. 处理流程

内部登录与应用解析
  → 计算租户 + 应用 + 主体的有效知识空间
  → 读取本人未过期会话并校验 contextVersion
  → 现有 chat 模型 temperature=0 输出 rewrittenQuery + intent
  → QA/FILE/VIDEO:在有效空间内执行现有混合检索
  → DATA_TOOL:只执行既有白名单工具及角色/项目范围校验
  → FILE/VIDEO:把命中 docId 映射为当前空间的附件资源
  → 返回答案、引用、资源和新 contextVersion
  → 脱敏截断后更新最近 6 轮会话

模型输出必须使用固定 JSON 契约。JSON 解析失败或模型不可用时,以原问题检索,并用关键词规则只做保守意图判断;不能从历史上下文猜测缺失主体。

6. 原文件和视频安全

新增认证接口 GET /api/knowledge/resources/{attachmentId}/content。每次下载必须重新计算当前租户、调用应用、用户/角色与知识空间授权,并确认附件仍属于有效空间,然后才通过现有 OSS 服务流式返回内容。

响应只暴露业务附件 ID、标题、类型和受控接口地址,不暴露 ossId、对象存储 key、原始 OSS URL 或服务器路径。权限被撤销、文件被解绑或附件不存在时立即拒绝;对话中曾经命中过不能覆盖下载时的实时授权。

视频意图只返回视频类型附件;没有视频时明确回答“当前授权资料中未找到相关视频”,不把 PDF、图片或用户本次上传的视频替代成知识库操作视频。

7. 并发与降级

  • 客户端提交旧 contextVersion 时返回冲突,避免两个请求互相覆盖上下文。
  • 会话不存在或过期时,从空上下文继续当前问题,并返回新的版本。
  • 会话持久化失败时保留当前单轮 RAG 能力,同时不声称已理解前文。
  • RAG 无证据时沿用 noEvidence=true;文件/视频意图无附件时返回空 resources 和明确说明。
  • 原始资料接口失败不回退到公开 URL、跨空间附件或模型生成链接。

8. 移动端交互

问师傅页维护当前 conversationId/contextVersion,消息仍只作当前页面展示。顶部提供“新对话”,清空页面消息和会话标识。答案卡增加原文件/视频资源卡,点击时复用现有鉴权文件下载能力;页面卸载或资源替换时释放本地 blob URL。

需要验证文字和语音追问、模型失败、会话过期、并发冲突、无文件、无视频、授权撤销、重新登录和超大字号。微信式外观不再作为“有记忆”的完成证据。

9. 验收用例

最小连续对话:

  1. “自动扶梯困人怎么办?”返回有依据的 SOP 答案和引用。
  2. “把这个 SOP 原文件给我。”rewrittenQuery 指向同一主题,只返回当前授权附件。
  3. “有操作视频吗?”只返回同一主题的视频;不存在时明确无视频。
  4. 点击资料可下载;撤销空间授权后,同一链接立即拒绝。

安全与回归还需覆盖:跨用户/跨租户会话不可读、旧版本冲突、30 分钟过期、模型关闭、OSS 缺失、视频类型过滤、外部 API 保持无状态、旧客户端单轮查询不回退。

完成结论分为:代码实现、自动化测试、本地 HTTP、移动端视觉与交互、生产部署、生产真实多轮、正式业务验收;这些层级不得互相替代。