Skip to content

Latest commit

 

History

History
113 lines (89 loc) · 15.4 KB

File metadata and controls

113 lines (89 loc) · 15.4 KB

raguide 完善清单(TODO)

来源:2026-07-17 全项目审计(基线 07b17de,6 路子代理 + 全量测试 + 人工复核)。 标注:✅已亲验 = 审计时逐条读码/跑代码实锤;◇待复核 = 子代理报告(证据具体但动手前先核对现场)。 规矩提醒:凡改检索/评测逻辑的项(标 🚪)必须过 gold-set 门禁;改后端代码后需手动重启后端(宿主进程无 --reload)。


批次 1 · 高价值 bug 修复(小 diff,先做)

  • 1.1 [P1]✅ intent token 双计(2026-07-18 修复) — intent/retrieval 节点返回整 state,api 层对 usage 键 SUMMED → intent tokens 计两遍,月成本虚增、熔断提前。改 agent/intent.py / agent/retrieval.py(及 modular_pipeline 出口)只返回 delta;验收:一次 recommend 查询的 done.usage 应等于 Langfuse 各 LLM 子 span usage 之和。
  • 1.2 [P1]✅ Web:登录管理员被误要求输 ADMIN_TOKEN(2026-07-18 修复) — 7 个 admin 对话框 useState(() => isAdmin() || …) 在 /me hydrate 前一次性求值(AppSidebar 页面加载即挂载)。改为渲染期订阅 auth store 派生。文件:LlmSettingsDialog/OpsDashboardDialog/EvalCandidatesDialog/GoldSetDialog/KbManagerDialog/EvalDashboardDialog/ProfileSettingsDialog。验收:清 localStorage 旧 admin token → admin 登录 → 刷新 → 打开模型设置不再见令牌闸门。
  • 1.3 [P2]✅ Web:404 幽灵会话(2026-07-18 修复) — page.tsx onSelectfetchFull 返回 null(会话已被删)照常绑定 → 后续对话全部静默不落库。null 时应回落 newChat()(与 catch 分支同)。
  • 1.4 [P2]◇ iOS:.onChange(of: auth.user) 全字段比较(2026-07-18 修复,含空会话回收) — 改昵称/换头像即断流清屏;登录用户冷启动「默认展示上次对话」失效且每次启动累积空会话。只比较 user id;账号 sync 完成后重发 adoptLatestIfIdle 信号。ChatView.swift:87-90 + ConversationStore.initialSyncDone
  • 1.5 [P2]◇ iOS:图库图不降采样(2026-07-18 修复) — 相机路径有 downscaled(maxDimension:1600),图库路径漏用 → 大图超 5MB 被后端拒。ChatView.swift:76-84

批次 2 · 检索 + 评测(🚪同一次 gold-set 门禁,需 Docker 栈)

  • 2.1 [P1]✅🚪 Pre-Retrieval 路由字段漂移pre_retrieval/router.pyproducts(真名 mentioned_products)、lookup(真名 spec_lookup)、不存在的 ambiguouscompare 的 Decompose 与 spec_lookup 的 HyDE/Multi-Query 从未运行。修字段名 + 补一个「router 字段与 IntentSlots 对账」单测防再漂移。
  • 2.2 [P2]✅🚪 评测误判连字符词agent_evaluator.py _ID_RE 把 type-c/wi-fi 当 product_id,task_completion 1.0→0.75(实测)。收紧判定(如仅匹配 known ids 形状/词表),分数口径会变。
  • 2.3 [P2]◇🚪 case 异常 ≠ 安全违规 — case 抛异常(超时)时 5 维全 0 含 safety=0,GATE 失败理由误导为"安全违规"(6-11 污染事件同模式)。异常 case 单独记 error,不落 safety 地板。run_gold_set.py + ci_gate.py
  • 2.4 [P3]✅ baseline 刷新_baseline.json case_count=71,现 gold-set 75。2.1-2.3 修完跑全量,GATE PASSED 后一并把 baseline 刷到 75 例口径。
  • 2.5 [P2]◇ BM25 独有命中 snippet 恒空 — 注释承诺的 payload cache 回填从未实现,空文本进精排被压底。tantivy_client.py + rrf.py(修复本身也属检索逻辑,并入本批门禁)。
  • 2.6 [P2]◇ advisor 工具循环第 2 轮起丢多轮历史_build_followup_messages 不拼 history,跨轮指代在首个工具调用后消失。agent/advisor.py:203-205(并入本批门禁)。

批次 3 · 安全(后端)

  • 3.1 [P1]✅ X-Owner-Id 冒领账号身份 — 无 JWT 请求带 X-Owner-Id: u_acct_<id> 可读/改/删该账号会话+画像;反馈可冒名(运营面板显示受害者名)。治本:游客 id 强制 u_web_/u_ios_ 形状(或加 guest: 前缀),effective_owner_id/require_owner_id 拒绝无 JWT 却带 u_acct_* 的头。api/auth.py:128-157。注意三端游客零回归。
  • 3.2 [P2]◇ 会话 messages 无大小上限ConversationUpdate.messages 无 max_length、无全局请求体上限 → DB/内存膨胀 DoS。加 Pydantic max_length + uvicorn 层 body 上限。
  • 3.3 [P3]◇ SSE error 帧回传内部异常原文api/agent.py:415-425 str(e)[:200] 可能泄内部细节;INTERNAL_ERROR 固定文案,细节只进日志/trace。
  • 3.4 [P3]◇ 登录无限流POST /v1/auth/login 加简单限流(如 Redis 计数)。
  • 3.5 [P3]◇ JWT 无吊销 — role 嵌 token 30 天有效,降权不生效;短 access + refresh 或 jti 黑名单(工作量大,可挂 backlog)。
  • 3.6 [P3]◇ admin 探测 SSRFprobe_endpoint base_url 无网段限制;至少拒 169.254.0.0/16 与私网段(或白名单 scheme+host)。
  • 3.7 [P3]◇ admin 商品图上传无校验 — 复用 files.py 的 size+PIL verify 校验矩阵。admin_kb.py:276-286

批次 4 · iOS 会话同步契约(三条同根,一起修)

  • 4.1 [P2]◇ decodeMessages 丢 data-done — 服务端拉回只取 text parts;iOS 改个名就把 web 会话全部完成标记剥掉(web 端全显示「已停止」)。decode 时解析 data-done(含 trace_id)回填 StoredMessage。ConversationStore.swift:270-280
  • 4.2 [P2]◇ restore 丢 stopped/error 再保存伪造 done=true — StoredMessage↔ChatMessage 双向保真(restore 用 done 推导 stopped)。ChatViewModel.swift:52-64
  • 4.3 [P1]◇ syncFromServer server-wins 覆盖本地新消息 — 断网时 pushToServer try? 静默失败,下次同步旧服务端版本覆盖落盘 → 永久丢一轮对话。加脏标记/updatedAt 比较,未推送成功的会话跳过覆盖。ConversationStore.swift:184-241
  • 4.4 [P1]◇ finalizeTurn 无任务身份校验 — 生成中「编辑重发」旧任务晚到把新流状态机踩掉(停止按钮消失、句柄丢失)。finalizeTurn guard 自己仍是当前 streamTask。ChatViewModel.swift:213-219,267
  • 4.5 [P2]◇ 下拉刷新串台 — refreshFromServer await 后不校验会话已切换,把 A 会话尾部 append 进 B。append 前 guard id == activeConversationIdChatViewModel.swift:124-131
  • 4.6 [P2]◇ 清空所有会话后孤儿会话 — 清空后当前会话 id 悬空,后续消息静默不持久化。清空后重建活跃会话。MenuSheets.swift:395-409
  • 4.7 [P2]◇ 刷新合并按 count 对齐会吞消息 — 改为按消息 id 前缀对齐。ChatViewModel.swift:124-131
  • 4.8 [P3]◇ 其余 — 撤回生成中回合不停流(cancelStreamIfTargeted 查 idx+1);reachableURL 重写所有外链 host(仅回环地址才重写);AuthTokenStore.session 数据竞争(加锁);SSE resource timeout 300s 掐长流;rename 只 PUT title 不全量 messages;iOS 反馈已评态持久化(对齐 web 05c2f6d)。

批次 5 · Web 体验与健壮性

  • 5.1 [P2]◇ 恢复窗口内发送被吞 — 刷新后 restore 完成前发送,send() 静默 return 但 draft/图已清空。send 失败时不清 draft(或 restore 完成前禁用发送)。chat-manager.ts:176-178 + page.tsx:85-94
  • 5.2 [P2]◇ 切回刚完成的后台会话再提问会覆盖掉答案 — PUT 全量覆盖 last-writer-wins 窗口。select 时若 manager 内存快照比 GET 新则用内存版;长期可给 PUT 加版本号。chat-manager.ts:132-147
  • 5.3 [P2]◇ ["my-profile"] 查询键不按身份分桶 — 切号短暂看到上一身份画像。key 加 user?.id ?? "guest",identity change 时 removeQueries。SettingsDialog.tsx + page.tsx:174
  • 5.4 [P3]◇ 快速切换会话「后返回者赢」 — onSelect 加序号守护。page.tsx:99-116
  • 5.5 [P3]◇ 登出不 abort 在跑的流chatManager.reset() 对各 entry 调 stop()。chat-manager.ts:246-254
  • 5.6 [P3]◇ Safari 日期解析 NaN — 后端 updated_at 非 ISO8601(空格+微秒),web 直接 new Date();先规范化(iOS 已踩过同坑,有现成写法)。group-conversations.ts:22
  • 5.7 [P3]◇ 服务端断流被误标「已停止」 — 断流无 error 事件时给用户中性文案+重试入口;parseFrame 对损坏 done 帧至少记日志。message-actions.ts + sse.ts
  • 5.8 [P3]◇ window.confirm 残留 5 处统一居中模态 — 清空所有会话(AppSidebar:116)/清除画像(SettingsDialog:116)/删除端点(LlmSettingsDialog:191)/拒绝候选(EvalCandidatesDialog:353)/删除产品(KbProductList:44),复用 DeleteConfirmDialog。
  • 5.9 [P3]◇ 聊天区无自动滚动跟随 — 流式生成长出视口不跟随;接近底部时自动滚动。MessageList.tsx
  • 5.10 [P3]◇ 401 过期无再登录引导 — transport 401 时触发登录弹窗而非泛化报错。

批次 6 · LLM 网关多 provider 真兼容(Rule#10 兑现)

  • 6.1 [P2]◇ FallbackChain 换 provider 不换 model — 兜底端点收到 primary 的 model 名必 4xx(newapi 按 key 隔离)。绑定链上每跳自己的 model。llm/registry.py:106-121
  • 6.2 [P2]◇ openai_compat 不兼容三件套 — content blocks(tool_use/tool_result/image)未转 OpenAI 格式、工具 schema 用 input_schema、response_format 非 json_schema.json_schema(DeepSeek 仅 json_object)→ 绑 GPT/DeepSeek 后工具循环/多模态/结构化全废。做消息/schema 双向转换层 + 真端点验证。
  • 6.3 [P2]◇ openai_compat usage 恒 0 + 无 record_llm_call — 加 stream_options.include_usage + 接 record_llm_call(成本/观测断档)。
  • 6.4 [P3]◇ llm.yaml 回退路径相对 CWDregistry.py:328_PROJECT_ROOT 定位。
  • 6.5 [P3]◇ DeepSeek 加入 fallback_chain(llm.yaml 尾注承诺未兑现,依赖 6.2)。

批次 7 · 后端稳健性

  • 7.1 [P2]◇ 同步 IO 阻塞事件循环 — minio get/stat(modular_pipeline.py:172,252)、Qdrant scroll(kb/products.py:65)走 asyncio.to_thread;依赖抖动时所有并发 SSE 冻结。
  • 7.2 [P2]◇ KB 重摄入先删后写无回滚 — 失败即商品从检索库消失;改为新写成功后再删旧(或影子集合切换)。kb/ingest.py:331-355
  • 7.3 [P3]◇ CRAG 拒答语义反转_RewriteOutput.web_query min_length=1 把「拒答空串」变 ValidationError → 回退原句照搜。允许空串并显式处理。crag/fallback.py
  • 7.4 [P3]◇ spec_query_sql 吞 infra 错误 — DB 挂了伪装成"没有符合条件的商品";infra 错应 propagate。tools/spec_query_sql.py:133-138
  • 7.5 [P2]◇ lifespan 幂等 DDL 补全 — 现仅兜底 3 处;conversations/llm_endpoints(+种子)/user_profiles/profile_config/budget_config/eval_candidate_cases 本体在绕过 dev.sh 启动的老卷上会 500。把 init.sql 关键对象全量搬进 lifespan(或启动时执行 init.sql)。main.py:59-107
  • 7.6 [P3]◇ HTTP/DB 客户端复用 — httpx.AsyncClient/QdrantClient 每次调用新建;lifespan 单例。

批次 8 · infra / CI / 评测基建

  • 8.1 [P2]◇ CI 收集范围缺 eval/kb 包 — GitHub CI 只跑 apps/backend;ci_gate/gold-set schema 测试在 CI 盲区。ci.yml 加根目录 job(等额度恢复一并开自动触发)。
  • 8.2 [P3]✅ 监控栈 Linux 可移植host.docker.internal 硬编码 + compose 无 extra_hosts: host-gateway
  • 8.3 [P3]◇ compose 加固 — prometheus/alertmanager/grafana 加 healthcheck + restart: unless-stopped(防睡眠恢复后监控栈死);:latest 镜像钉版本。
  • 8.4 [P3]◇ HighRetrievalP95 全池化 — 按 step 分组或只算端到端 step,排除 error 样本。rules.yml:24-26
  • 8.5 [P3]◇ eval.yml 清死步骤 — PR comment/auto baseline 两步在仅 workflow_dispatch 下永不执行;Update baseline 还会全量重跑第二遍。
  • 8.6 [P3]◇ up.sh init.sql 失败不可见 — 真错误与 NOTICE 区分,失败要红字。scripts/dev/up.sh:38
  • 8.7 [P3]◇ 杂项_MAX_ITER/_SAME_TOOL_CAP 镜像常数改 import 或对账测试;CostBudget80/Exhausted 加 inhibit;gold_set_writer 与 _schema.py 双 schema 收敛;--force-baseline help 文案对齐;kb-ingestion cli category 硬编码 "phone"。

批次 9 · 文档纠偏(纯文档,零风险,伤面试可信度的优先)

  • 9.1 ✅ interview-qa Q5 改口径(2026-07-18 完成) — MinerU/VLM 表格兜底/MultiVectorRetriever 均无实现(descoped),照稿答辩会被打穿。改为「设计目标 + 当前最小实现 + descope 理由」。
  • 9.2 ✅ 测试数全文统一(2026-07-18 完成:922/351/57/45/106、75 例、21 题、5 工具、5 看板 32 panel、9 场景) — 徽章 889→实测 921;web 254/270/291→348;gold-set 50/53/71→75;interview-qa「30 题」→21;工具 4→5;Grafana 面板数按实际(5 看板 32 panel);runbook 8 场景→9。历史数字加「当时」限定。
  • 9.3 ✅ License 节(2026-07-18 完成) — README L939 "WIP 未正式发布" → GPL-3.0 + 链 LICENSE。
  • 9.4 ✅ 死链修复(2026-07-18 完成:提升.md→inline 解法;gold_set.yaml→目录;runbook 假路由→侧栏对话框) — 提升.md(Ragas 解法唯一指向,需补写或改指向)、tests/gold_set.yaml→目录、runbook /admin/llm-config→侧栏对话框。
  • 9.5 ◇ 互相矛盾处(2026-07-18 完成:SSE 9 类+retrieval_step 行;architecture Ragas 改 DEFERRED;compose 清单;「尚未提交」清除;结构树补 ios/eval;eval.yml 注释 75;CLAUDE.md §9) — SSE 协议表补 retrieval_step(8→9);architecture.md「Ragas 已实现✅」改 DEFERRED;compose 服务清单(无 Langfuse,实际 10 服务);两处「尚未提交」删掉;结构树补 apps/ios、packages/eval;「apps/web 功能 minimal」删。
  • 9.6 ◇ Quick Start 改 ./dev.sh 一键(2026-07-18 完成;手动步骤保留为等价拆解)。
  • 9.7 ◇ README 补 demo 展示(⏸ 待用户提供素材:web 录屏/截图 + iOS 真机截图,不能代做) — 顶部 1 张 web 双栏 Inspector 动图 + 1 张 iOS 真机截图 + 架构 mermaid;顺带完成 M10 的「真机录屏」遗留。
  • 9.8 ◇ Roadmap 巨型单元格瘦身(2026-07-18 已纠错内部过时措辞;大规模删减涉信息丢失,待用户批准再做) — 每行一句结论 + 链接账本;补 2026-06-14 后交付(运营面板/CRAG rerank/iOS 服务端同步/记住我/GPL/dev.sh),其中 iOS 服务端同步同时推翻「iOS 会话本地存储」旧表述。
  • 9.9 ◇ requirements.md 加「达成状态」(2026-07-18 完成:成功标准达成注 + 30 SKU 现状注) — 「尚未开始」「≥30 SKU」(实际 5-7 款)等过时状态注。

批次 10 · Backlog(择机/外部条件)

  • CI 自动触发恢复(GitHub 账单)——当前 push 实际零门禁,bug 就是这么漏进 main 的
  • Ragas 4 指标(langchain-core 依赖冲突;解法:独立 venv 跑 ragas 或等版本兼容)+ 补写「提升清单」文档
  • judge 可见性盲区 3 例(tool-evidence snippet 嵌规格摘要)
  • 断流重连(reconnectToStream,需后端配端点)
  • KB 数据底盘扩到 ≥30 SKU(requirements 承诺)
  • feedback-store 按身份分桶 + 容量清理;composer 模型药丸随角色绑定动态化;session_id per-conversation
  • 大表行级 chunk 摄入接线 / MultiVector(或正式 descope 并改文档)

建议执行顺序

1 → 9(文档零风险可穿插)→ 2(一次门禁打包)→ 3 → 4 → 5 → 6/7 → 8 → 10。 每批完成后:跑对应测试套件 + 亲验 + commit/push;批次 2 必须 Docker 栈起 + GATE PASSED 才准动 baseline。