Files
PlantAI-rag-new/docs/PRD.md
T
jerryandClaude Fable 5 bbd5db2315 feat(capabilities): S6 Superpowers+S7 终验(文档/humanizer CJK 修复/验收脚本)
- prompts/superpowers_{review,answer_quality,minimal_code}.md + prompt_pack.py
- agentic_controller/answer_composer Superpowers 注入点(env 总闸,关态逐字节一致)
- compile_qa.sh: prompts/ 目录自动拷贝
- humanizer: CJK 逗号规则 + 引用保护收窄(只护标记本身,带引用句可润色)
- docs: README 能力矩阵+env 表 / ARCHITECTURE Gateway 章 / API §6 / PRD:17 /
  TEST_CASES:126 多轮语义 / CHANGELOG
- tooling/cap/final_acceptance.sh 终验矩阵
- 终验: 金标 16/20 regressions=0, 多轮指代 PASS, 热加载 PID 不变 PASS,
  Humanizer 开态「此外」消除且 22 引用保留, 五上游全绿, 7913 已释放

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-09-02 18:27:41 +08:00

29 KiB
Raw Blame History

PRD.md —— PlantAI-rag-new 产品需求文档

版本 1.0 | 作者 PM | 本文件由 PM 独占写入,所有开发/测试 agent 只读

本文件是全项目需求的唯一来源。 开发 agent 按此实现,测试 agent 按此写用例。 每个功能点有唯一编号 FR-<模块>-<序号>,测试用例必须在追溯矩阵中与之一一对应。 需求有歧义时,向 PM 提出,不要自行解释。


0. 产品定位

面向植物生物信息学研究者的文献知识问答工作台。用户提出关于植物基因家族的科学问题,系统从已构建的文献知识库(约 100 篇论文、44,595 条关系断言)中检索证据,生成有引用锚定的答案,并展示完整的检索过程、证据来源与知识图谱。同时提供论文抽取任务的管理入口。

使用场景:桌面深度研究为主,手机端随时查询为重要补充(实验室、会议、田间)。

不做什么:默认支持同会话上下文记忆(可在设置中关闭)(上游 max_rounds:1,每次提问独立检索);不做文献全文阅读器;不做基因家族分析流程执行(那是 PlantAI-dev 的职责)。


1. 术语表

术语 含义
会话 Session 一组问答的容器,有标题、状态、时间。注意:会话是组织单位,不是上下文单位——同一会话内的多次提问互相独立
消息 Message 会话内的一条记录,role 为 user 或 assistant
块 Block 助手消息的内容单元,判别式联合类型(text/table/code/stream/pipeline/tool/sources/graph)
来源 Source 一条支撑答案的文献证据,含标题、片段、分数、PMID/DOI 等
证据链 Chain 知识图谱上的一条多跳推理路径,由若干 hop 组成
阶段 Stage 上游 QA 服务推送的细粒度检索步骤(十余个)
相位 Phase 前端展示用的五阶段归并(规划/检索/证据/生成/完成)
上游 Upstream 现有的三个后端服务:QA(7920)、抽取(8000/7900)、Neo4j
BFF 本项目的适配层后端,前端唯一直连对象

2. 全局约定

2.1 状态枚举

会话状态 idle | running | done | error

  • idle 排队中/新建未提问 —— 空心点,ink-subtle
  • running 有进行中的问答 —— 青色 #00D4FF 脉冲点
  • done 最近一次问答成功 —— success #2ED3A0 实心点
  • error 最近一次问答失败或中断 —— error #FF5C7A 实心点

消息状态 streaming | done | error

相位状态 waiting | running | done(对应字形 ◌ / ● / ✓)

2.2 错误处理原则

  • BFF 一切错误返回统一信封 {"ok":false,"error":{"code","message","degraded"}},HTTP 状态码语义正确。
  • 前端不显示原始异常堆栈,显示 error.message 的中文可读文案。
  • degraded:true 表示「上游不可用」而非「请求有误」,UI 用降级提示(横幅/离线态)而非错误弹窗。
  • 失败必须可见:任何静默吞掉错误的实现视为缺陷。

2.3 文案约定

用户可见文案统一走 src/i18n/labels.js。例外:后端返回的 error.message 直接展示(后端已中文化)。

2.4 数据不伪造原则

UI 只展示后端真实返回的数据。禁止:占位假数据流入生产路径、把空结果渲染成看起来有内容的样子、用动画暗示实际不存在的流式过程(客户端揭示动画是明示的视觉设计,允许,但不得声称是 token 流)。


3. 模块与编号

模块 前缀 范围
应用外壳 FR-SHELL 三栏布局、顶栏、状态栏、折叠、背景
主题与无障碍 FR-THEME 深浅主题、动效降级、焦点、对比度
会话管理 FR-SESSION 列表、分组、增删改查、搜索
对话与问答 FR-CHAT 消息渲染、作曲器、流式、流水线、持久化
检索过程 FR-RETRIEVAL 工作台 Tab1
文献来源 FR-SOURCE 工作台 Tab2
提取任务 FR-EXTRACT 工作台 Tab3
知识图谱 FR-KG 工作台 Tab4
响应式 FR-RESP 四档断点与移动端专项
健康与降级 FR-HEALTH 上游探活与降级行为

4. FR-SHELL 应用外壳

编号 功能点 业务逻辑与边界 验收要点
FR-SHELL-001 桌面三栏网格 grid-template-columns: 260px minmax(0,1fr) 380px;grid-template-rows: 48px minmax(0,1fr) 28px;区域 "top top top" / "side chat bench" / "status status status"。页面本身不滚动(body{overflow:hidden}),滚动发生在各栏内部 1440×900 下三栏宽度精确;缩放窗口不出现横向滚动条
FR-SHELL-002 顶栏 高 48px。左:9px 渐变发光圆点 + 「海古纪 PlantAI」渐变文字(background-clip:text)。中:当前会话标题(超长省略)+ 状态徽章。右:主题切换按钮。背景 color-mix(in srgb, var(--pa-canvas) 88%, transparent) + backdrop-filter: blur(14px),底部 1px hairline 无会话时中部显示「就绪」徽章;标题超长省略而非换行
FR-SHELL-003 底部状态栏 高 28px。左:4 个 7px agent 状态点(规划/检索/证据/生成),与流水线相位联动。右:PlantAI RAG v0.1 + mono 的 QA 版本号 + 会话数 + 上游健康标记 问答进行中四点按相位依次点亮;QA 版本号来自 /api/qa/info
FR-SHELL-004 左栏折叠 折叠后宽 64px 图标轨,显示 3 个 34×34 图标按钮(会话/图谱/设置),当前项左侧 2px 渐变竖条。折叠状态写入 localStorage pa-side-collapsed 折叠/展开过渡 300ms ease-out;刷新后保持
FR-SHELL-005 右栏折叠 折叠后保留 28px 手柄条(折叠 ≠ 隐藏),点击手柄重新展开。状态写入 localStorage pa-bench-collapsed 折叠后手柄可见可点;刷新后保持
FR-SHELL-006 Aurora 背景 固定层,z-index:0,pointer-events:none。两个 560/620px 渐变光斑,blur(120px),aurora-drift 16s 往复;叠加 48px 点阵,顶部渐隐遮罩。浅色主题下 --pa-aurora-opacity:.08 不遮挡任何交互;浅色下明显衰减
FR-SHELL-007 首屏初始化 顺序:读 localStorage 主题并写 documentElement.dataset.theme(必须在挂载前,避免闪白)→ 挂载应用 → 并行请求会话列表与 /api/health、/api/qa/info → 无会话则显示欢迎空态 深色主题下刷新无白屏闪烁;接口失败不阻塞渲染

5. FR-THEME 主题与无障碍

编号 功能点 业务逻辑与边界 验收要点
FR-THEME-001 双主题等价 深色为默认。浅色不是降级稿,是同一套语义的另一组令牌值。所有组件必须在两套主题下都正确 逐组件走查两套主题无失色、无对比度不足
FR-THEME-002 切换与持久化 顶栏按钮切换,写 localStorage['pa-theme'],同步 documentElement.dataset.theme。图标日/月互换并 rotate 180°(400ms) 切换即时生效;刷新保持
FR-THEME-003 浅色 glow 衰减 浅色下所有辉光乘 --pa-glow-opacity:.35——浅底上不衰减会糊 浅色下按钮悬停辉光明显弱于深色
FR-THEME-004 动效降级 @media (prefers-reduced-motion: reduce) 下关闭全部 animation/transition;状态改由静态符号表达(实心/空心/✓/✕),不依赖运动传达信息 开启系统「减少动态效果」后无任何动画,且状态仍可辨认
FR-THEME-005 焦点与键盘 :focus-visible 输出 2px rgba(94,106,210,.5) 焦点环,offset 1px。所有交互元素键盘可达,Tab 顺序符合视觉顺序 纯键盘可完成:新建会话→输入→发送→切换 tab
FR-THEME-006 对比度 深色 ink/canvas ≈15:1,ink-muted/canvas ≥4.5:1;浅色同标准 抽检主要文本对比度达标

6. FR-SESSION 会话管理

编号 功能点 业务逻辑与边界 验收要点
FR-SESSION-001 列表与分组 按 updated_at 倒序,分「今天 / 昨天 / 更早」三组,组标签 11px/500/字距0.6px。空列表显示引导文案 跨零点后分组正确迁移
FR-SESSION-002 状态点四态 见 §2.1。running 脉冲动画,其余静态 四种状态视觉可区分,且不仅靠颜色(形状:空心/实心 + 动/静)
FR-SESSION-003 新建会话 顶部渐变按钮(40px 高)。行为:调 POST /api/sessions 创建 → 切为活动会话 → 对话区显示欢迎空态。不预先落一条空消息 连点两次产生两个独立会话,不重复
FR-SESSION-004 选择与加载 点击会话 → GET /api/sessions/{id} 拉取消息 → 渲染历史。加载中显示骨架屏。切换会话时若有进行中的流,中断该流并把原会话置 error(标注「已中断」) 历史消息含表格/图谱块能正确重渲染
FR-SESSION-005 搜索过滤 搜索框对 title 做不区分大小写的子串匹配,实时过滤(前端过滤,不发请求)。无匹配显示「无匹配会话」 输入中文/英文均可过滤;清空恢复全量
FR-SESSION-006 重命名 双击标题或右键菜单进入编辑,回车提交 PATCH /api/sessions/{id},Esc 取消。空标题不允许提交 重命名后列表与顶栏标题同步更新
FR-SESSION-007 删除 需二次确认。确认后 DELETE /api/sessions/{id}(级联删消息)。若删的是当前会话,切到列表中最新一个;列表空则显示欢迎空态 删除后刷新不再出现;消息一并清除
FR-SESSION-008 标题自动生成 新会话首次提问后,用问题前 30 字符(超出加省略号)作为标题,调 PATCH 落库。用户手动改过标题的会话(meta.title_manual=true)不再自动覆盖 首问后标题自动变化;手动改名后再提问不被覆盖
FR-SESSION-009 活动态高亮 左侧 2px 渐变竖条 + color-mix(in srgb, var(--pa-g-to) 8%, transparent) 底 + 22% 内描边 活动项一眼可辨,与悬停态区分

7. FR-CHAT 对话与问答(核心模块)

7.1 基础渲染

编号 功能点 业务逻辑与边界 验收要点
FR-CHAT-001 欢迎空态 消息为空时显示:46px 渐变菱形(✧)+ 渐变标题「海古纪 PlantAI 知识工作台」+ 副标题 + 3 张建议卡(示例问题)。点击建议卡直接以该文本提问 卡片悬停上浮 2px + 青色微光;点击即发起真实提问
FR-CHAT-002 用户消息 右对齐,最大宽 70%,渐变底(深色 135deg,#2A2A3E,#1C1C2A;浅色 #E8ECFF,#F4FBFF)+ hairline-strong 边,r12,padding 10/15px 长文本正确换行不溢出
FR-CHAT-003 助手消息 无底色全文(Linear 式),左缘 2px 透明竖线悬停变渐变。头部:24px 渐变头像(✦)+ 「PlantAI 智能体」+ 时间。内容按块联合顺序渲染 多块混排顺序正确
FR-CHAT-004 Markdown 渲染 markdown-it 解析 → DOMPurify 消毒 → v-html。表格加 md-table 类:thead 用 2px 渐变下边框,数据格 mono(表头为「说明」的列除外,保持比例字体);代码块 code-bg + hairline + mono 12.5px LLM 输出的表格/列表/加粗正确渲染;注入脚本被消毒
FR-CHAT-014 自动滚动 新消息或流式更新时滚到底。例外:用户手动向上滚动后暂停自动滚动,并显示「回到最新」按钮;点击或用户滚回底部后恢复 阅读历史时不被强制拽到底
FR-CHAT-015 内联引用 答案文本中的引用标记渲染为可点 chip,点击滚动定位到工作台「文献来源」中对应条目并高亮 2s 引用 chip 与来源列表编号一致

7.2 作曲器

编号 功能点 业务逻辑与边界 验收要点
FR-CHAT-005 输入框 r16 surface-1 卡片,:focus-within 渐变描边 + 青色辉光。textarea 无边框透明,14px/1.6,min-height 46px,max-height 160px 后内部滚动。占位符提示示例问题 多行输入自动增高至上限后滚动
FR-CHAT-006 三种模式 pill 切换,参数集定义在 config/modes.js:
问答 {use_llm:true} → /api/qa/chat/stream
方案 {use_llm:true, native_chain_enabled:true, native_chain_max_hops:3, native_chain_top_k:5} → 同上,深证据链
检索 {use_llm:false} → /api/qa/search,只出来源不出答案
激活态渐变底 + 白字 + 青光
三种模式发出的请求体字段正确;检索模式不产生答案块
FR-CHAT-007 发送与快捷键 Enter 换行,⌘/Ctrl+Enter 发送。发送按钮渐变 pill,空输入或忙碌时 disabled(opacity .45)。底部提示文案说明快捷键 快捷键在中英文输入法下均生效;空输入不可发送
FR-CHAT-011 停止/中断 流式进行中,发送按钮变为「停止」。点击 → AbortController.abort() → 关闭 SSE → 当前消息置 error 并标注「已停止」→ 已收到的块保留不丢 停止后 BFF 侧上游连接也关闭(不留悬挂请求)

7.3 流式问答(最复杂的部分,详细说明)

FR-CHAT-008 流式问答主流程

业务逻辑,按时序:

  1. 用户发送 → 前端立即在界面追加用户消息气泡 → POST /api/sessions/{id}/messages 落库(role:user)
  2. 会话状态置 running,左栏状态点开始脉冲,底栏 agent 点复位
  3. 前端追加一条助手消息骨架(status:streaming),内含一个 pipeline 块,五相位全为 waiting
  4. fetch + ReadableStream 打开 POST /api/qa/chat/stream(不能用 EventSource——请求是带 JSON body 的 POST)
  5. 逐帧消费:
    • event: progress → 取 phase 字段(BFF 已计算好,前端不解析上游 stage 名)→ 更新 pipeline 块对应相位为 running,此前相位置 done;同时把该事件的 details 追加为工作台「检索过程」的一张阶段卡
    • event: complete → payload 即完整归一化响应 → 用 answer 生成 text 块(走揭示动画)、sources 生成 sources 块、图谱数据生成 graph 块;pipeline 全部置 done
    • event: error → 消息置 error,展示 error.message,保留已收到的块
    • event: timeout → 同 error,文案为「检索超时」
    • event: raw → 记入 raw,不渲染
    • : 注释帧(keepalive)→ 忽略
  6. 每 ~3s 调 PATCH /api/sessions/{id}/messages/{mid} 做检查点持久化
  7. 终态:消息置 done/error 落库,会话状态同步,底栏 agent 点定格

边界与异常:

  • 上游最长 240s:期间必须持续有视觉反馈(相位卡 + shimmer + 已耗时计数),不得让用户面对静止界面
  • 网络中断(移动端切网常见):fetch reject → 置 error,文案「连接中断」,提供「重试」按钮。不自动重连——每次 LLM 调用昂贵,自动重试会放大成本
  • 页面刷新中途:重载后显示最后检查点内容 + 「已中断」标注,会话状态 error
  • 同一会话并发提问:忙碌时发送按钮 disabled,从交互上杜绝

FR-CHAT-009 五阶段流水线卡

相位 颜色令牌 上游 stage(由 BFF 归并)
规划 --pa-t-planning #C0A8DD understanding_started、entities_identified、related_search_started
检索 --pa-t-execution #9FBBE0 concepts_found、subquestion_retrieved、agent_review_started、subquestion_retry_started
证据 --pa-t-knowledge #9FC9A2 evidence_accepted、evidence_review_completed
生成 --pa-t-validation #DFA88F answer_generation_started
完成 --pa-t-done #C08532 completed

渲染:纵向时间线,每相位 = 16px 状态点(✓ done / ● running / ◌ waiting)+ 2px 连接线 + 相位名 + 描述(取自最近一次该相位事件的摘要)+ 右侧状态文字;running 相位额外显示 11px 旋转 spinner。卡片头部「⚙ 检索流水线」+ 整体状态徽章(语义色)。

关键约束:相位色只回答「哪一步在做什么」,语义色只回答「整体成败」,两者不得混用。

FR-CHAT-010 答案揭示动画

上游不做 token 级流式,完整答案在 complete 一次到达。前端以 30ms/字符的速度揭示,尾部显示 8×15px 青色闪烁光标(blink 1s),下方显示 3px shimmer 进度线。揭示期间用户可点击「跳过」立即显示全文。揭示结束替换为最终 text 块。

边界:答案超过 2000 字符时,揭示速度自动加快(总时长上限 8s),避免长答案等待过久。

FR-CHAT-012 错误与重试

  • 上游返回 HTTP≥400 且 detail.error_code == "invalid_llm_citation":BFF 已自动重试一次;若仍失败,前端展示「引用校验失败,请重试」并提供重试按钮
  • 其他错误:展示 error.message,提供重试按钮
  • 重试 = 用相同问题与模式重新发起,在同一条助手消息位置替换,不新增用户消息

FR-CHAT-013 消息持久化与恢复

  • 块联合完整落库(stream 块为瞬态,不落库,落库时已转为 text)
  • raw 字段保存完整归一化响应,供排查与重渲染
  • 刷新后从 GET /api/sessions/{id} 恢复全部块,包括表格、来源、图谱

8. FR-RETRIEVAL 检索过程(工作台 Tab1)

编号 功能点 业务逻辑与边界 验收要点
FR-RETRIEVAL-001 阶段卡列表 每个 SSE progress 事件生成一张卡,沿用原型「工具调用卡」视觉:折叠头(相位色图标 + 阶段中文名 + 状态点 + 耗时 mono)+ 展开体(details 以 mono 参数块呈现 + 摘要行) 一次问答后卡片数量与收到的 progress 事件数一致
FR-RETRIEVAL-002 相位筛选 chip:全部/规划/检索/证据/生成。激活态实心 #5E6AD2 底 + 白字 筛选后仅显示对应相位卡片
FR-RETRIEVAL-003 展开折叠 点击头部切换,chevron 旋转 90°,展开体 fade-slide 200ms。运行中的卡默认展开,完成后自动折叠 展开状态互相独立
FR-RETRIEVAL-004 运行中效果 运行中卡片头部 shimmer 扫光 1.8s 循环 + 状态点脉冲 完成后动效停止
FR-RETRIEVAL-005 检索计划 若响应含 retrieval_plan,在列表顶部以只读信息块展示;另展示 /api/qa/info 的 12 段 pipeline 描述作为静态说明 无 plan 时该区域不显示(不留空框)
FR-RETRIEVAL-006 空态 未提问时显示「发起提问后,这里会实时展示检索过程」 空态不显示假卡片

9. FR-SOURCE 文献来源(工作台 Tab2)

编号 功能点 业务逻辑与边界 验收要点
FR-SOURCE-001 来源列表 沿用原型「产物文件」的 mono 列表视觉。每条:序号 + 标题(超长省略)+ mono 元信息行(PMID:xxx / DOI:xxx / 分数)+ 证据片段(默认 2 行截断,点击展开) 条目数与 source_count 一致
FR-SOURCE-002 字段展示 展示归一化后的 title / snippet / score / pmid / pmcid / doi / section / support_count。缺失字段不显示占位符,不显示 undefined/null 各字段缺失组合下渲染正常
FR-SOURCE-003 外链跳转 链接优先级:url > doi(拼 https://doi.org/{doi})> pmid(拼 PubMed)> pmcid(拼 PMC)。均无则不显示链接图标。新标签页打开,带 rel="noopener" 点击真实跳转到正确文献页
FR-SOURCE-004 证据链 chains 按 chain_id 分组,每组可展开为逐跳列表:源实体 —[关系]→ 目标实体,每跳附 paper_id/PMID。跳数以徽章显示 多跳链条展开顺序正确
FR-SOURCE-005 会话级聚合 顶部切换「本次回答 / 本会话全部」。后者调 GET /api/sessions/{id}/sources,按 paper_id 去重并累计出现次数 去重正确,计数准确
FR-SOURCE-006 空态 无来源时显示「本次检索未命中文献」,不显示空列表框 空结果不误导为加载中

10. FR-EXTRACT 提取任务(工作台 Tab3)

编号 功能点 业务逻辑与边界 验收要点
FR-EXTRACT-001 任务列表 GET /api/extraction/jobs。每条沿用原型进度条视觉:任务名 + mono 百分比 + 6px 轨道 + 渐变填充 + sweep 扫光;100% 转为纯 success 色且停止扫光。上游无 progress 数值,百分比由 BFF 按 stage 派生(queued=5 / mineru=35 / llm=75 / completed=100,failed 显示失败态不显示进度条) 列表与上游一致;派生数值正确;failed 任务呈现为错误态
FR-EXTRACT-002 任务详情 点击展开 GET /api/extraction/jobs/{id},展示状态、message(中文进度描述)、统计字段(stage/species/figure_table 计数)、plan(仅 completed 有,未完成置 null 不显示) 详情字段与上游一致;未完成任务不显示 plan 且不报错
FR-EXTRACT-003 运行日志 GET /api/extraction/run-log,mono 等宽展示,最大高度内滚动,自动贴底 长日志不撑破布局
FR-EXTRACT-004 论文上传 作曲器区域附件按钮 → 选 PDF → POST /api/extraction/upload(multipart)→ 显示上传进度 → 成功返回 job_id 并刷新列表。限制:仅 PDF,单文件 ≤50MB。上游当前环境 MinerU 二进制路径缺失会导致新任务 failed(历史 27 个 failed 任务同因)——若发生,展示上游 message 的明确错误文案 非 PDF 被拒;超限被拒;错误文案可读
FR-EXTRACT-005 轮询刷新 存在 running 状态任务时每 5s 轮询列表;全部终态则停止轮询。切到其他 tab 时暂停轮询 无进行中任务时不空转
FR-EXTRACT-006 离线降级 抽取上游不可用时显示离线提示与重试按钮,不影响其他 tab 8000/7900 全停时该 tab 优雅降级

11. FR-KG 知识图谱(工作台 Tab4)

双数据源策略(重要):

  • 答案图谱:来自当前消息的 graph 块(由 QA 响应的 knowledge_graph/native_graph_chains 归一化而来)。永远可用,Neo4j 挂了也不受影响。
  • 自由浏览:来自 GET /api/kg/*,BFF 用 Bolt 直连 Neo4j。上游 /api/v1/kg/* 已损坏(指向未运行的 7687),不可依赖。
编号 功能点 业务逻辑与边界 验收要点
FR-KG-001 答案图谱渲染 手写 SVG 力导向布局。节点圆点 + 标签,边为渐变线(#5E6AD2→#00D4FF)带关系名。节点数 >50 时自动降级为列表视图并提示 图谱与答案引用的实体一致
FR-KG-002 节点着色与图例 按实体 type 着色,用品牌色 + 辅助紫 + 五相位色构成调色板,底部图例。同一 type 在会话内颜色稳定 图例与节点颜色对应
FR-KG-003 节点详情 点击节点 → 侧滑详情面板,展示实体属性;若 Neo4j 可用,额外调 GET /api/kg/entities/{name} 拉全量属性 Neo4j 不可用时仍能显示消息内已有属性
FR-KG-004 实体搜索 搜索框 → GET /api/kg/entities?q= → 按 name_norm 精确/前缀匹配(走 name_norm 索引,0.1s 内返回)→ 选中渲染其邻域。注意上游无全文索引,搜索是精确/前缀匹配,非模糊全文检索 中英文实体名(精确或前缀)均可搜到;响应 <1s
FR-KG-005 邻域展开 GET /api/kg/entities/{name}/neighborhood?depth=&limit=。深度选择 1/2,默认 1(两跳实测约 13s,需提示较慢)。节点上限 200,每跳按 paper_count/support_count 降序截断防 hub 吃满预算 深度切换生效;超限有提示不卡死
FR-KG-006 缩放与平移 滚轮/双指缩放(0.3×–3×),拖拽平移,双击复位。触摸端必须支持双指缩放与单指拖拽 手机上可流畅缩放平移
FR-KG-007 离线降级 Neo4j 不可用时:搜索与邻域功能禁用并提示离线;答案图谱照常渲染(这是双数据源的意义) 断开 Neo4j 后 tab 不白屏
FR-KG-008 空态 本次回答无图谱数据时提示「本次检索未产生图谱关系」,并引导使用实体搜索 空态不显示空画布

12. FR-RESP 响应式(手机为一等公民)

12.1 断点

编号 档位 宽度 布局规则
FR-RESP-001 Desktop ≥1280px 完整三栏 260/1fr/380
FR-RESP-002 Laptop 1024–1279px 三栏保留;左栏自动折叠为 64px 轨;右栏收窄至 340px
FR-RESP-003 Tablet 768–1023px 对话单栏铺满;左栏改左抽屉(scrim 遮罩 + 滑入),顶栏加汉堡按钮;右栏改右抽屉,顶栏加工作台按钮并显示来源数角标
FR-RESP-004 Mobile <768px 单栏;顶栏 = 汉堡 + 标题 + 工作台按钮;对话铺满;作曲器吸底;工作台为全屏覆盖层 + 顶部 tab 条;底部状态栏隐藏,四个 agent 点合并为顶栏一枚聚合状态点

抽屉与覆盖层动效沿用 ease-out 300ms;打开时 scrim 淡入,点击 scrim 或按 Esc 关闭。

12.2 移动端专项

编号 功能点 业务逻辑与边界 验收要点
FR-RESP-005 viewport 与安全区 <meta viewport ... viewport-fit=cover>;作曲器 padding-bottom: env(safe-area-inset-bottom);顶栏 env(safe-area-inset-top) iPhone 刘海/Home 条不遮挡内容
FR-RESP-006 iOS 输入放大规避 <768px 时 textarea font-size:16px(低于 16px 必触发 iOS 自动缩放)。禁止用 maximum-scale=1 规避——伤害无障碍 iPhone Safari 聚焦输入框页面不放大
FR-RESP-007 悬停态触摸等价 所有 hover 样式包在 @media (hover: hover) 内。触摸设备下:来源外链图标常驻可见、助手消息左缘线常驻、会话条目去掉悬停底色改用点击反馈 手机上无「需要悬停才出现」的功能
FR-RESP-008 触控目标 <768px 下会话条目、bench tab、模式 pill、图标按钮 min-height:44px(iOS HIG 标准,高于 DESIGN.md 的 36px) 手机上不误触
FR-RESP-009 视口高度 用 100dvh,保留 100vh 回退,规避移动浏览器地址栏伸缩导致的高度跳变 滚动时布局不跳动
FR-RESP-010 虚拟键盘 监听 visualViewport 的 resize:键盘弹出时压缩消息区高度并保持贴底,作曲器始终可见 键盘弹出不遮挡输入框
FR-RESP-011 表格横向滚动 <768px 下答案内 md-table 包一层横向滚动容器,右侧加渐隐提示。不压缩字号(可读性优先) 宽表格可横滑查看完整内容
FR-RESP-012 移动端性能降级 <768px 下 aurora 模糊半径降低或 --pa-aurora-opacity:0;图谱节点数上限降至 30 中端手机滚动流畅无卡顿
FR-RESP-013 手势(可选) 左缘右滑开会话抽屉,右滑关工作台覆盖层。不作为验收门槛 实现则可用,不实现不算缺陷

13. FR-HEALTH 健康与降级

编号 功能点 业务逻辑与边界 验收要点
FR-HEALTH-001 健康轮询 挂载后请求 GET /api/health,此后每 30s 一次。结果写入 store,驱动状态栏标记与各降级态。轮询失败不弹窗,仅标记 上游恢复后 30s 内自动解禁
FR-HEALTH-002 QA 不可用 /api/qa/* 返 503 degraded:作曲器禁用并显示「知识问答服务当前不可用」,历史会话仍可浏览 停掉 7920 后 UI 明确提示而非静默失败
FR-HEALTH-003 Neo4j 不可用 图谱 tab 搜索/邻域禁用并提示离线;答案图谱不受影响 见 FR-KG-007
FR-HEALTH-004 抽取不可用 见 FR-EXTRACT-006 仅该 tab 降级
FR-HEALTH-005 网络中断 流式中断时提示「连接中断」+ 重试按钮;不自动重连(避免重复触发昂贵 LLM 调用) 手机切换网络后有明确提示

14. 非功能要求

项 要求
首屏可交互 桌面 <2s(本地网络),手机 <3s
长任务反馈 QA 最长 240s,期间必须持续有视觉反馈,无静止超过 5s 的状态
数据安全 Neo4j 凭据只存在于 BFF 配置,绝不下发到浏览器;LLM 输出必须经 DOMPurify 消毒后才 v-html
离线容忍 前端零外网请求(无 Google Fonts、无 CDN),符合 DESIGN.md 禁令
浏览器支持 Safari 16+(iOS)、Chrome 110+、Firefox 110+

15. FR 索引(供追溯矩阵使用)

SHELL: 001–007(7)|THEME: 001–006(6)|SESSION: 001–009(9)|CHAT: 001–015(15)|RETRIEVAL: 001–006(6)|SOURCE: 001–006(6)|EXTRACT: 001–006(6)|KG: 001–008(8)|RESP: 001–013(13)|HEALTH: 001–005(5)

合计 81 个功能点。 测试用例追溯矩阵必须覆盖全部 81 项(FR-RESP-013 标注为可选,仍需有用例但允许标记为 N/A)。