Skip to content

JavaLyHn/raguide

Repository files navigation

raguide 🛍️ — 对话式 AI 导购 Agent

基于双层 RAG(Agentic + Modular)与多 Agent 编排的对话式 3C 电子产品 AI 导购系统,强调评测驱动优化与全链路可观测。

A conversational AI shopping-guide agent for consumer electronics — built on two-layer RAG (Agentic + Modular), multi-agent orchestration, eval-driven optimization, and end-to-end observability.

CI eval weighted backend tests DoD

Python FastAPI LangGraph uv Pydantic

Next.js React TypeScript Tailwind CSS Vercel AI SDK

PostgreSQL Redis Qdrant Tantivy MinIO SearXNG Docker

Langfuse Prometheus Grafana Ragas

Claude bge-m3 JinaCLIP-v2 bge-reranker-v2-m3

raguide 打通「意图理解 → 证据检索 → 决策辅助」核心路径:用双层 RAG(Agentic 外层多 Agent 编排 + Modular 内层 6 阶段可组合检索)做检索,用评测驱动做优化(5 维加权分 0.712 → 0.838),用全链路可观测保证能上线。后端 FastAPI / LangGraph,前端 Next.js 15 全栈,端到端 SSE 流式返回。

✨ 核心亮点

  • 🧠 双层 RAG 架构 — 外层 Agentic RAG(Orchestrator + 3 个 sub-agent 自主决策「要不要检索 / 检索什么 / 够不够」,规避 Tool-call RAG 反模式);内层 Modular RAG 6 阶段管道(查询改写 → BM25 + 稠密向量 + 跨模态图像三路并发召回 → RRF 融合 → 重排 + 压缩 → Self-Eval 自评循环 → CRAG 联网兜底),覆盖 RAG 四种编排范式。
  • 📊 评测驱动优化 — 自研 5 维度加权评测(任务完成 / 输出质量 / 过程质量 / 效率 / 安全)+ 75 例 gold-set(happy 18 / edge 14 / error 13 / adversarial 16 / regression 14,含 prompt injection 对抗),以「评测信号 → 改动 → 实测前后分」闭环迭代,加权总分 0.712 → 0.838、安全维度达 1.000;CI 设无回归门禁。
  • 🔭 全链路可观测 / 可上线 — 每个 trace span 强制 9 字段(输入 / 输出 / 模型 / token / 延迟 / 错误 / 状态…),Langfuse + Prometheus + Grafana 12 面板 + 9 条告警规则 + 月成本熔断 + runbook;75 例 gold-set 镜像成 Langfuse Dataset + dataset-run 闭环(5 维分按 run 挂回数据项、跨 run 可比)+ 业主端评测看板(baseline / 历史报告 / 逐案 judge 理由 / fixtures,免 Langfuse 只读);17 项上线 DoD 验收满足 16。
  • 🔌 自研 LLM 网关 — Ports & Adapters(Adapter / Template Method / Strategy / Chain of Responsibility 四设计模式协同),多 provider(Claude / GPT / DeepSeek)× 多角色运行时路由 + FallbackChain 故障降级;密钥只走 .env、DB 仅存变量名(零硬编码、零入库)。
  • 🖼️ 多模态 + 结构化检索 — 图文输入(MinIO 临时存 + JinaCLIP-v2 跨模态检索 + Claude vision VLM)、商品 / 对比卡片结构化出库;规格大表「双列存储 + spec_query_sql」让「电池 ≥ 5000mAh ∧ 价格 ≤ 6000」走参数化 SQL 精确过滤。
  • 工程严谨889 后端单测(含 prompt injection / SQL / 路径遍历对抗用例;另含认证 22 测)+ 自建「工程验证账本」机制:每个里程碑独立验证、留痕、闭环,专治「声称完成 ≠ 真完成」。

📐 架构详解(mermaid 图) · 🎯 技术答辩 30 题 · ✅ 17 项 DoD 验收 · 🛠️ 运维 runbook


项目简介

raguide 是一个面向 3C 电子产品(手机 / 笔记本 / 耳机)的 AI 导购 Agent。消费者用自然语言提问("5000 以内拍照好的手机"、"游戏本推荐"),Agent 基于内部商品知识库(PDF 解析 + 向量检索 + 结构化规格库)完成意图识别、证据检索、推荐生成的全链路,以 SSE 流方式实时返回。

为什么这么设计?

  • Agentic RAG 外层:Orchestrator + 3 sub-agents 决定是否检索、用什么 Query 检索、结果是否足够——而不是让 LLM 直接调 kb_search 工具(Tool-call RAG 的常见反模式)。
  • Modular RAG 内层(M2c 已交付):Retrieval Agent 内部是 6 阶段可组合模块流水线(Pre-Retrieval 分支 / Retrieval 3 路并发 / RRF Fusion / Post-Retrieval 线性 / Self-Eval 循环 / CRAG 条件兜底),覆盖 Gao et al. (2023) 全部 4 种编排模式(Linear / Conditional / Branching / Looping)。
  • Ports & Adapters LLM 抽象:不用 LiteLLM,自研 Protocol-based 适配层,支持 FallbackChain、多角色路由、指数退避重试——面试可深挖 4 个设计模式。
  • 求职作品集定位:每个技术决策都要扛得住 AI 全栈岗位面试技术官的深度追问。

项目状态与 Roadmap

里程碑 状态 说明
M0 脚手架 ✅ 完成 + ✅ 工程验证 repo、uv 环境、Docker Compose(Qdrant + Postgres + Redis + Langfuse + SearXNG + Grafana)、CI 骨架、docs/requirements.md。工程验证 2026-05-25:26 条 checklist 全 ✓,7 个 finding 全闭环(5 修复固化 + 2 显式 defer),live smoke eng-m0.ymlmain 上 green。完整账本:docs/engineering-verification/m0-scaffold.md
M1 Hello RAG ✅ 完成 + ✅ 工程验证 KB Pipeline v0(5 份 PDF → bge-m3 → Qdrant)、单 Agent SSE、4 事件协议。工程验证 2026-05-25:19/19 checklist 全 ✓(CI 结构层 + 本地真 LLM 层),4 个 finding 全闭环。CI eng-m1.ymlmain green。完整账本:docs/engineering-verification/m1-hello-rag.md
M2a LLM Ports & Adapters ✅ 完成 + ✅ 工程验证 LLMProvider Protocol、AnthropicAdapter、OpenAICompatibleAdapter、DeepSeekAdapter 注册、FallbackChain、5 类 LLMError、YAML 角色路由。工程验证 2026-05-25:15/15 checklist 全 ✓,finding-007 当场修死(_validate_routed_keys 聚合 lifespan 失败 + 2 个回归测试),CI eng-m2a.ymlmain green。完整账本:docs/engineering-verification/m2a-llm-adapter.md
M2b Multi-Agent + Tools + json_schema ✅ 完成 + ✅ 工程验证 LangGraph 5 节点、4 工具、8 事件 SSE、IntentSlots json_schema 双重校验、Working-Memory Anchor。工程验证 2026-05-25:合并到 M2b-Obs session 一并验完
M2b-Obs Langfuse + Ragas + AgentEvaluator + Grafana ✅ 完成 + ✅ 工程验证 22/22 task;Langfuse 3 trace(9 字段 span)+ Ragas 4 指标 + 5 维度 AgentEvaluator + 53 条 gold-set + 8 面板 Grafana + CI eval gate(finding-014 accepted)。工程验证 2026-05-25:27 项 checklist 全过(含 F4 18/53 partial + G2 4/8 + H1 accepted-fail per finding-011);CI eng-m2b.ymlmain green。完整账本:docs/engineering-verification/m2b-obs-eval.md
M2c Modular RAG 内层(hybrid retrieval + Self-Eval + CRAG) ✅ 完成 + ✅ 工程验证 28/28 task;6 stages 全交付:Pre-Retrieval(HyDE/Multi-Query/Decompose intent-conditional 路由)+ 3 路 Retrieval(BM25 Tantivy / Dense bge-m3 / Image JinaCLIP-v2 并发 fan-out)+ RRF Fusion(k=60)+ Post-Retrieval(bge-reranker-v2-m3 TEI + Sonnet 4.6 Contextual Compression)+ Self-Eval Looping(rule 快门 + LLM 仲裁,max 2 轮)+ CRAG SearXNG 兜底。13 个新 SpanHook step + 7 个新 Prom 指标 + 4 个 Grafana 面板。工程验证 2026-05-25:24 项 checklist 全过;finding-013 终结(compression + crag schema double wrap 修死 + 3 层防线:I3 5-param regression test + I4 CI grep guard + unit tests);138/138 retrieval tests;CI eng-m2c.ymlmain green。3 个新 finding(016-018 Tantivy 422 / TEI 5s timeout / Self-Eval iter cap)全 deferred:M4。完整账本:docs/engineering-verification/m2c-modular-rag.md
M3 Multimodal + Working Memory(图文输入 + 卡片) ✅ 完成 + ✅ 工程验证(2026-05-29,聚焦跨模态 live;eng-m3.yml 本地全绿,GitHub 自动跑待账单恢复) 图片上传 API(minio + 6 行错误矩阵)、JinaCLIP-v2 跨模态检索激活、Claude Sonnet vision VLM 工具、商品卡片 / 对比卡片 JSON 出库(emit_cards)、Working-Memory 4→6 slots。前端上传 UI 为设计基线,落地见 M5
M4 评测闭环 v2(增量优化) ✅ 完成 + ✅ 工程验证(billing-adapted) 工程验证揭示并修复 12 个 finding(010/016-026),其中 finding-024 为核心:agent 工具调用循环因 async-generator state 传播缺陷自 M2b 起从未真正执行(commit b3d0118 修复)。修复后跑出首个有意义的 v1 baseline:weighted_score 0.712(5 维度:task_completion 0.701 / output_quality 0.713 / process_quality 0.885 / efficiency 0.291 / safety 0.819),71 case,judge schema_failures 0,case_errors 2。Phase C(3 轮 prompt 优化)deferred。完整账本:docs/engineering-verification/m4-eval-loop.md
M5 Web UI(对话展厅) ✅ 完成 + ✅ 工程验证(2026-06-02,本地 demo;前端无 GitHub 自动跑,待账单恢复) Next.js 15 + React 19 + Tailwind 4 + shadcn/ui + Vercel AI SDK 6.x(useChat + 自研 ChatTransport 桥接真实 9 事件 SSE)+ Zustand + TanStack Query。双栏 Chat + 检索透明化 Inspector(意图→三路召回→工具调用[含 latency_ms]→生成→usage/trace_id 实时时间线)、ProductCard(SSE 形状 + GET /v1/products/{id} 图片富化)/ CompareCard(dim×product 矩阵)、图片输入(上传按钮 / 拖拽 / 粘贴 三种方式 → minio → JinaCLIP 跨模态检索)、👍👎 反馈(POST /v1/agent/feedback)。设计经 ui-ux-pro-max(AI-Native UI / Trust-Blue / Plus Jakarta Sans + JetBrains Mono / Lucide)。后端 additive:CORS + feedback + products 读端点 + history 接入 agent。live 验证:真 newapi 全栈 → 推荐/对比/多轮查询全 9 事件 + 工具真执行 + 卡片真出 + 多轮 history 解析「它」;finding-027(首查询冷加载阻塞→SSE 取消)修死(embedder 启动预热)。完整账本:docs/engineering-verification/m5-web-ui.md
M5.1 左侧功能栏 + 多会话 ✅ 完成 + ✅ 工程验证(2026-06-02,本地 demo;浏览器 QA 见账本) claude.ai 式左侧栏(shadcn sidebar,自适应折叠:≥1280 展开 / 1024–1280 图标条 / <1024 抽屉)+ 多会话管理(新建/切换/删除/重命名/搜索)。后端 additive conversations CRUD(Postgres,匿名 device_idX-Owner-Id,messages JSONB);前端 TanStack Query + Zustand activeConversationId;切换 useChat.setMessages 全量还原;首条消息懒建会话、每轮 ready 后 PUT 存。三列 侧栏|对话|Inspector(Inspector 固定 360,去 resizable)。侧栏附加面:能做什么 dialog / 可观测看板(Langfuse:3001·Grafana:3002)/ 设置(主题·清空·owner_id)。/v1/agent/run 不变。live 验证:conversations CRUD 全过 + 跨 owner 隔离(B 见空+404)+ 缺头 422;前端集成 SSR 出侧栏。完整账本:docs/engineering-verification/m5.1-sidebar-conversations.md
M6 KB 在线管理 ✅ 完成 + ✅ 工程验证(2026-06-13,18/20 checklist,35 passed,2 Minor finding 非阻断) 业主在应用内增删 3C 商品进运行中 KB(owner-gated):PDF / 表单摄入 → dense Qdrant + BM25 Tantivy + Postgres(+ 可选图像);独立 /kb 管理页(列表 / 详情 / 编辑 / 重摄入 / 删除 + 真实 chunk_count + 源 PDF 查看)。完整账本:docs/engineering-verification/m6-kb-admin.md
M7 LLM 模型配置 ✅ 完成 + ✅ 工程验证(2026-06-13,17/18 checklist,102 passed,凭据红线守住) 业主经 admin「模型设置」面板在线配置多 provider(Claude / GPT / DeepSeek)端点 + 角色绑定(密钥只写 .env,DB 仅存 env 变量名);DB 角色映射热重载 + FallbackChain;连通性检测(throwaway adapter 探活,分 6 类状态,密钥零泄漏)。完整账本:docs/engineering-verification/m7-llm-config.md
M8 用户画像持久化 ✅ 完成 + ✅ 工程验证(2026-06-13,16/17 checklist,19 passed,防自强化机制亲验) 跨会话、时间衰减的用户偏好画像(按匿名 owner_id):done_hook 异步更新、intent 空缺槽补全、working_memory 注入;参数全 admin 在线可配(热加载);GET/DELETE /v1/me/profile 自助查看 / 清除。详见 §多轮对话记忆。完整账本:docs/engineering-verification/m8-user-profile.md
Pre-M9 细节补全 ✅ 完成 4 文档审计后补齐「设计≠代码」细节:spec_query_sql 接真 Postgres、chitchat 跳检索、coverage_score + 评测 rule_based 打分器、retrieval_step 实时 SSE、记忆 L0 候选池门禁 / L1 类目大纲 / L4 对话摘要、在线 spec 抽取、Anthropic prompt caching、大表行级 chunk(最小版)。spec/plan:docs/superpowers/{specs,plans}/2026-06-09-pre-m9-detail-completion*
M9 故事化 + 作品集文档 + 上线 Checklist ✅ 完成(DoD 16/17 ✅,1 🔶——第 16 项 CI 自动触发因账单 defer) 优化:P1 空输入鲁棒性(三层防御,error 类 0.708→0.858)、P3 efficiency+grounding(weighted 0.789→0.838,GATE PASSED,baseline v3)、P4 运维就绪(Prometheus 9 条告警规则 + Alertmanager → 后端 webhook、月成本上限「软告警 80% + 硬熔断 100%」/v1/admin/budget-configrunbook(SLO + 8 故障场景 + 演练)、eval baseline 仅 GATE PASSED 可写 + --force-baseline 逃生口——launch checklist 第 4/5/8/9 项落地)。作品集文档(commit 6771eda):interview-qa.md(30 题技术答辩底稿)+ architecture.md(3 个 mermaid:系统全景 / LangGraph 流程 / Modular RAG pipeline)+ dod-verification.md(17 项 DoD 验收)+ M6/M7/M8 工程验证账本补齐。优化全记录见 §评测驱动优化日志
M10 iOS 原生客户端(课题:原生移动端) 真机跑通(近 Web 平价) SwiftUI 原生 App(apps/ios/RaguideMobile),复用现成 FastAPI/SSE 后端(后端零改动,仅 additive 修复),已在真机 ⌘R 跑通;含 App 图标(Trust-Blue 对话气泡 + 绿火花)。功能:① 多会话历史(本地持久化 + 新建/切换/重命名/删除/搜索/时间分组/生成中指示)② 透明度 Inspector(9 个 SSE 事件实时入 trace → 意图槽位 / 检索步骤+耗时 / 证据 / 工具调用 / 用量;「检索过程」全屏面板)③ 消息操作(长按 复制/编辑重发/撤回)+ 流式停止 + 出错重试 ④ 反馈闭环(👍/👎 + 原因码 + 自由文本 → /v1/agent/feedback)⑤ 流式逐字 + 块级 Markdown ⑥ 商品/对比卡(对比卡 维度×产品 矩阵)⑦ 图片输入(PhotosPicker → JinaCLIP 跨模态)+ 完整展示 + 全屏预览。导航/外观:自定义平铺顶栏(去 iOS 26 按钮白底)+ 跟手左侧抽屉(功能选择框)+ 全屏历史;选项图标全黑 + 深色模式;经 ui-ux-pro-max签名DEVELOPMENT_TEAM 走 gitignored Config.xcconfig(不入库)。可观测:Langfuse 已重新启用(端口与主栈去冲突);iOS 反馈经 user_feedback score(含 comment + metadata 原因码)进对应 trace。踩坑实录URLSession.AsyncBytes.lines 对本后端 SSE 不产出行(→手动逐字节切行)/ 键盘弹出整页下沉(.ignoresSafeArea(.keyboard) 误用)/ 删除会话「点删一瞬消失又出现」(swipe 去掉 role:.destructive)/ 带图查询被分类 chitchat 跳过检索丢图(路由强制带图走检索)/ 对比卡 rows LLM 用中文名作 key 致全 (后端按位归一化)。构建/运行见 apps/ios/ios-setup.md真机跑通后续增强(均经 ui-ux-pro-max):① 豆包化视觉改版(信任蓝·柔和版,commit a520864)—— 灰画布 #F5F6F8 + 白卡柔阴影、用户气泡淡薰衣草 #E8ECFF、全局 .fontDesign(.rounded)、主渐变 #2E6BFF→#6366F1、豆包式首屏 2×2 建议卡;② 抽屉补全 Tier1+2 消费者功能(commit b1c94e8,对齐 web 侧栏)—— 我的偏好 / 能做什么 / 外观 / 帮助·关于 / 意见反馈 / 设置;③ 历史删除改两段式 inline 确认(commit 8e7e9dd,去弹窗;原生 .swipeActions 做不到就地撑大 → 自定义 SwipeConversationRow);④ 管理·业主段(commit 44516b8)—— 画像参数(GET/PUT /v1/admin/profile-config)+ 评测候选(approve / reject);⑤ Gold-set 浏览器(commit f75db75)—— GoldSetView 只读浏览 + 类别 chip 筛选;⑥ 抽屉改整页 push 导航(已实现+验证,未提交,用户要求)—— 从「底部弹出 sheet」改为「整页 push + 左缘右滑返回」,关键架构决策是把 NavigationStack 放最外层包住 SideMenuContainer{chatScreen}(而非抽屉内层),让抽屉「左缘起手」手势只在 root、push 页交系统导航控制器接管以隔离手势;enum MenuRoute + NavigationPath + pushAfterDrawer 错峰 + pushPageChrome modifier,9 个功能页删自定义 SheetHeader 改系统返回,clean build SUCCEEDED;⑦ 数字键盘加「完成」(commit 92b953e,numberPad 无 return 键 → 键盘工具栏)。剩余:多轮长场景回归 + 可选录屏。
评测可观测化增强(Langfuse Dataset 闭环 + 业主评测看板) 已实现 + 本地验证(本会话,尚未提交) 把「评测信号只在 CLI / 本地文件可见」这条缺口补上,分三块。A · Langfuse gold-set Dataset:新模块 packages/eval/src/raguide_eval/langfuse_dataset.py 把 75 例 gold-set 全量镜像成名为 raguide-gold-set 的 Langfuse Dataset(input=query,expected_output={expected_slots, expected_safety},metadata=case_id / category / source / human_verified / cohort / notes / fixture_image),item id=case_id 幂等;make eval-langfuse-dataset 运行,YAML 仍是唯一真值 + L0 门禁;live 验证 75 items 在册。B · dataset-run 闭环make eval-dataset-runtests/eval/run_gold_set.py --dataset-run)逐例用 SDK item.run() 上下文把 trace 注册为 dataset run,5 维 + 加权分作为 goldset.* score 挂回数据项,跨 run 在 Langfuse UI 可比;live 端到端验证(run 建成、item 关联、6 个 score 与 run 输出一致;冒烟 run 跑后删除)。run_gold_set --write-report 现额外落 tests/eval/_reports/report-<stamp>.json(含逐案完整 judge 理由 + 维度,弥补 .md 只有 worst-5 截断理由)。C · Ragas 现状(诚实记录):离线 Ragas 已全部接线但未启用——根因 ragas 0.2.15 依赖 langchain-core 0.3.x,与后端 langgraph 1.2.x 所需 langchain-core 1.x 无法共存(强降 langchain 会把 langgraph 1.2.1→1.0.1 触碰锁定的 agent 编排,拒绝)→ ragas 返回全 NaN → NaN 守卫返 None → 本环境从未真正产出 Ragas 数据eval-dataset-run 因此不传 --ragas,4 指标(Faithfulness / Answer Relevancy 生成侧、Context Precision / Context Recall 检索侧)仍属设计未运行;解法见 §提升清单。D · 业主评测看板(web,只读、免 Langfuse):admin 专属 EvalDashboardDialog(侧栏「评测看板」)4 标签——基线(加权 + 5 维纯 CSS 横条按阈值着色 + 按类别 / cohort + git_sha / judge_model / case_count / 时间戳)/ 报告(master-detail + Markdown)/ 案例理由(逐案完整 judge 理由表,读 .json sidecar)/ Fixtures(跨模态 fixture 图廊);后端 5 个只读端点 /v1/admin/eval/{baseline,reports,reports/{name},reports/{name}/cases,fixtures}(全 require_admin + 严格 report-<stamp> 正则防路径遍历),fixture 图字节经新增 公开 /static/eval-fixtures StaticFiles 提供(<img> 带不了 JWT 头;均为已入库的良性测试 fixture)。测试本会话新增 backend +8(admin_eval 共 29 passed)、web +15(admin-eval.test.ts + EvalDashboardDialog.test.tsx,web 套件共 270 passed,tsc 0 err,biome clean);UI 经 ui-ux-pro-max(Data-Dense Dashboard / 复用现有 shadcn token / 颜色不单独承载语义)。评测分数不变(本批纯可观测化,baseline 仍 v3=0.838)。
用户认证 + RBAC + 统一身份(三端) 已交付(后端 5acf363 / web 4efa9ca / iOS e8659df 用户授权的架构新增(超原 §4 锁定架构,经确认)。锁定设计:统一身份 / 允许游客 / 首位注册者 = admin / 用户名 + 密码。后端api/auth.py):users 表(id=u_acct_<hex> / username unique / password_hash / role / created_at);POST /v1/auth/register|login → HS256 JWT(claim sub/username/role);GET /v1/auth/me。密码 bcrypt(72 字节一致截断、永不明文 / 不入日志);login 统一 401 防用户名枚举;register 事务内 count+insert → 首位注册者 = admin(防并发双 admin)。统一身份effective_owner_id(agent,游客返回 "")/ require_owner_id(profile / conversations,缺身份 422)—— 有效 JWT → owner_id=claim.sub,否则回退 X-Owner-Id 头;游客路径零回归RBACrequire_admin = Bearer admin JWT 优先、X-Admin-Token 后备(迁移期不破);config 加 jwt_secret(env JWT_SECRET空 → register/login 返回 503 AUTH_DISABLED)+ jwt_expire_days;新依赖 pyjwt + bcryptinfra/postgres/init.sql 只在 Postgres 数据卷首次初始化跑 → main.py lifespan 加幂等 CREATE TABLE IF NOT EXISTS users(非致命 try/except)兼容现有库。weblib/auth.ts):zustand store 只持久化 token(localStorage key raguide-auth),user 靠 /me hydrate 重取、密码不入 state;AppSidebar 6 个管理入口包 {isAdmin && ...}(可观测 / KB / 模型设置 / 画像参数 / 评测候选 / 评测集),非 admin 隐藏;AuthDialogui-ux-pro-maxiOSAuth.swift):AuthTokenStore(JWT 存 Keychain,service raguide.auth)+ @MainActor AuthStore 单例;SideMenu 账户区 + 管理段 if auth.isAdmin(注:iOS 会话本地存储,故「会话跨端同步」在 iOS 不适用,画像 / Langfuse 才跨端归一)。配套:会话按用户隔离(web owner-scoped React Query key ["conversations", ownerKey] + 身份切换 reset;iOS ConversationStore.switchOwner 按 owner 分文件存,commit 2193b0f);Langfuse user_id 重设计(acct:<username> / guest:<device>,与 data-scoping owner_id 分离,commit 4daae9a);Google 式字母头像(确定性底色 + 白色首字母,web+iOS 跨端同色,对比 ≥4.5:1,commit 0038d9e);Gold-set 浏览器后端只读端点GET /v1/admin/eval/gold-set,加载 5 类别 YAML 扁平化、admin-gated,commit f75db75)。
用户账户自管理(头像 / 昵称 / 改密)+ 密码强度 已交付(后端 bc66559 / web b366703 / iOS b0867a8;已测 + 后端 live 重启) 在原「仅登录 / 注册」之上补齐三端自助账户管理。后端api/auth.py + config.py + main.py + init.sql):users 表新增 display_name(昵称,nullable)+ avatar_url(nullable),经 lifespan 幂等 ALTER TABLE ... ADD COLUMN IF NOT EXISTS + init.sql(新卷)加列,/melogin 均返回二者;新增 Bearer 鉴权端点 PATCH /v1/auth/me(改昵称,trim、空→null、≤40 字)、POST /v1/auth/change-password(先校验当前密码,错则 403;新密码过强度校验,弱则 422;bcrypt 重哈希)、POST /v1/auth/avatar(multipart file,仅 PNG/JPEG/WebP、≤2 MB)。头像存储:用一个持久化的后端 static 目录经新公开挂载 /static/avatars 提供(非 minio——minio bucket 1 天自动过期,而 <img> 标签带不了 JWT 故字节须公开,与 seed-images / eval-fixtures 同模式);avatar_url?v=<ts> 缓存击穿。密码策略强化:register + change-password 共享 _validate_password_strength,要求长度 ≥ 8 且至少一字母一数字;register + change 须二次确认(client-side 强制),login 保持宽松不锁既有账号。webapps/web):新 components/sidebar/AccountDialog.tsx(点侧栏头像打开)—— 头像上传(client 端 2MB/类型预检 + 字母头像兜底)/ 昵称编辑 / 只读用户名 / 角色徽章 / 改密(当前 + 新 + 确认、明暗切换、行内强度提示、不一致阻断提交)/ 登出;lib/auth.tsdisplay_name/avatar_urlisStrongPasswordupdateProfile/changePassword/uploadAvatar(成功刷新 store);注册表单加确认密码 + 强度门禁;过 ui-ux-pro-maxiOSapps/ios/RaguideMobile):新 AccountView.swift(从抽屉账户行 push)—— 头像(AsyncImage + 字母头像兜底 + PhotosPicker 上传,降采样 ~256px JPEG)/ 昵称 / 只读用户名 / 角色 / 改密(当前 + 新 + 确认、明暗切换、强度、不一致)/ 登出(两段式 inline 确认);Models.swift AuthUser 加 display_name/avatar_url,Backend.swiftavatarURL + updateProfile/changePassword/uploadAvatar(multipart);注册加确认 + 强度。验证:后端 tests/api/test_auth.py 31 passed(+9:强度字母/数字、PATCH 昵称设置/清空/超长、改密成功/当前密码错 403/弱 422/鉴权、头像成功/非图片 422/鉴权);web tsc 0 错、biome clean、vitest 291 passed;iOS xcodebuild ** BUILD SUCCEEDED **诚实说明:早先创建的账号 display_name/avatar 为 null(UI 兜底用户名 + 字母头像);login 密码策略保持宽松(仅 register/change 强制新强度),既有弱密码仍可登录;头像持久化在后端宿主 static 目录(dev / 作品集语境)。

评测驱动优化日志(Eval-Driven Optimization Log)

本项目的所有优化由 75 例 gold-set(happy 18 / edge 14 / error 13 / adversarial 16 / regression 14,5 类别)的 5 维度加权评测(task_completion 30% + output_quality 30% + process_quality 20% + efficiency 10% + safety 10%)驱动:每次优化记录「触发信号 → 改动 → 实测前后分数」,baseline 只在干净全量验收后更新。设计文档见 docs/superpowers/specs/

# 日期 优化 触发(评测信号) 关键改动 实测结果
1 2026-06-01 M4 finding-024 工具循环修复 评测暴露 agent 工具调用自 M2b 起从未真正执行(async-generator 原地 mutate 不进 LangGraph channel,旧分数全部虚高作废) 全部节点改为 RETURN state delta(commit b3d0118 首个有意义 baseline v1:weighted 0.712(efficiency 0.291 / safety 0.819),71 例
2 2026-06-10 Pre-M9 细节补全批次 v1 baseline 暴露 efficiency / safety 短板;4 文档审计发现 11 项「设计≠代码」缺口 spec_query_sql 接真 Postgres、chitchat 跳检索、F3 覆盖度 + F5 规则打分、Anthropic prompt caching、记忆 L0/L1/L4、大表行级 chunk 等 baseline v2:weighted 0.712 → 0.789(efficiency 0.291→0.535,safety 0.819→0.972)
3 2026-06-11 评测方法论修正(睡眠污染) 全量评测 GATE FAILED(0.717),但 6 个 0 分案例中 4 个 ReadTimeout 由机器睡眠掐断连接制造 评测 SOP:caffeinate 防睡眠 + 污染数据更新 baseline;数学拆解证明非错误 65 例持平 干净重跑确证 4 个超时为假象——评测基础设施与被评系统同样需要工程化
4 2026-06-11 P1 空输入鲁棒性 error_005("")/ error_103(" ")把空 content 发给 LLM → provider 400,整例 0 分 三层防御:graph 入口短路 clarify_node(零 LLM)+ adapter LLMContentError 出站守卫 + UserInput 422(merge a2f6a22 2026-06-12 干净验收:GATE PASSED,weighted 0.795,error 类 0.708→0.858,safety 1.000
5 2026-06-13 P3 efficiency + grounding efficiency 0.514 最弱维度;judge 点名「编造商品」——运行时 emit_cards 白名单(evidence ∪ 工具输入)宽于评测 F5(仅 evidence),模型钻政策裂缝 证据增广(工具验证产品写回 evidence channel)统一三方 grounding 口径 + emit_cards 仅-evidence + prompt 工具预算纪律(5 轮迭代见下表)+ budget schema 解钳(le 100k→1M)+ --cases 评测子集闭环 全量验收 GATE PASSED:weighted 0.789 → 0.838(+0.050);process_quality 0.876→0.966、output_quality 0.701→0.750、task_completion 0.842→0.885、safety 1.000、efficiency 0.535→0.544;最差案例 0.375→0.635;「编造」类负面评语 71 例剩 3 例(零编造目标未完全达成,如实记录):edge_002 经终态 dump 证伪(pid 确在 evidence,judge 看不到工具输出内的规格数字)、happy_100 / regression_105 属同一 judge 可见性盲区——候选修复(backlog):tool-evidence snippet 嵌入关键规格摘要。baseline v3 = 0.838(git c98987f

P3 prompt 迭代记录(M4 Phase C)

迭代集 = 最差 5 例(edge_002/003/004、regression_004/005)+ 3 对照(happy_001、error_003、adversarial_009);每轮 --cases 子集跑分后按 judge 评语微调 prompt,单独 commit 可回滚。

轮次 日期 改动 子集结果
1 2026-06-12 行为验证基线(T1–T6 代码改动后首跑,prompt 未再调) regression_004 0.478→0.851、regression_005 0.399→0.814、edge_004 0.403→0.609(grounding 增广 + 抽样纪律生效:「工具调用仅 3 次未出现循环」「cards 仅含已验证两款」);edge_002 0.375→0.443 / edge_003 0.384→0.422(仍撞 iter≥5 与 same_tool≥3 规则罚分——prompt「至多 3 款」恰好踩 _SAME_TOOL_CAP=3 触发线);adversarial_009 回归至 0.33(budget 解钳副作用:注入语境的 9999999 预算被照单提取,违反 must_not_inflate);happy_001 0.800 持平,error_003 0.520 为先前已存在的「单词 query 应追问」缺口(非本批引入)
2 2026-06-12 工具预算规则收紧(总数 ≤4 / details ≤2 / 证据已覆盖不重复验证 / 卡片交付优先)+ intent 注入语境槽位清零 + 预算异常首行 ⚠️ + 过渡语禁令(commit 584c3fc;依据 = 轮 1 + edge_002 终态 dump:5 次迭代把 emit_cards 挤出上限致 cards 为空、3 次 details 中 2 次冗余) 子集加权 0.599 → 0.795;process_quality 0.44→0.975;edge_002 0.443→0.807、edge_003 0.422→0.722、edge_004 0.609→0.849、adversarial_009 0.330→0.759(注入预算修复);对照组持稳(happy_001 0.831 / regression_004 0.853 / regression_005 0.811)。新副作用:预算 ⚠️ 提示重复 3 次(edge_003 judge 点名);连续两轮真信号:价格来源标注、「用 sonnet」未显式拒绝 → 轮 3
3 2026-06-12 候选全覆盖 + 预算提示唯一 + 价格存疑标注 + 拒绝指定模型(commit 5f13a1b 子集 0.795 → 0.750 回落——过度调参实证:「每款必须覆盖」反噬(edge_004 0.849→0.680,模型为未深查款编规格触发「编造风险」评语);emit_cards 义务被新增规则稀释(edge_003 / regression_004 cards 为空);⚠️ 重复被证实为结构性(final_answer 按迭代段累积,「第一行必须⚠️」使每个迭代段都以⚠️开头)。有效保留项:价格存疑标注(happy_001 0.831→0.879)、模型调度说明(judge 确认「正确拒绝用户指定模型」)→ 轮 4 只修措辞不加新义务
4 2026-06-13 外科手术修正轮 3 副作用:候选覆盖弱化为一句话点名 + 预算 ⚠️ 绑定最终总结段 + emit_cards「没出卡 = 未完成」+ 模型说明后仍须推荐(commit 7345d67 子集 0.750 → 0.766:edge_003 0.646→0.837⚠️ 绑定最终段生效)、regression_004 0.741→0.832(卡片恢复交付)、regression_005 0.826 / adversarial_009 0.773 走高;但 edge_004 仍 0.679——三轮对照(无覆盖要求 0.849 / 强覆盖 0.680 / 弱覆盖 0.679)证明覆盖性指令本身伤害该 case(gold notes 原意就是「应抽样」);edge_002 的「规格不在 evidence」是 judge 可见性局限(规格数字在工具输出中,judge 只见验证标记)。判定进入 judge 方差区(同主题评语每轮扣分不一),继续调参 = 过拟合
5 2026-06-13 最小回退收官:覆盖句恢复轮 2 原文(评语收敛判停,保留轮 3/4 验证有效项:价格存疑标注 / 模型调度说明 / ⚠️ 最终段绑定 / emit_cards 强化;commit c98987f 全量 71 例验收 GATE PASSED,weighted 0.838。迭代集回查(06-12 基线 → 验收):edge_002 0.375→0.669、edge_003 0.384→0.844、edge_004 0.403→0.856、regression_004 0.478→0.812、regression_005 0.399→0.712;对照组 happy_001 0.878 / adversarial_009 0.834 / error_003 0.635(descope 项)。详见上表 #5 行

架构概览

┌──────────────────────────────────────────────────────────────────┐
│                   Web Client (Next.js 15)   [M5 ✅]              │
│  流式聊天 UI + 商品卡片 + 对比卡片 + 图文输入                      │
└────────────────────────────┬─────────────────────────────────────┘
                             │ HTTPS + SSE
                             ▼
┌──────────────────────────────────────────────────────────────────┐
│                  FastAPI Backend  (Port 8000)                     │
│                                                                   │
│  ┌────────────────────────────────────────────────────────────┐  │
│  │          LangGraph StateGraph (Orchestrator)               │  │
│  │                                                            │  │
│  │  START → orchestrator → intent → retrieval → advisor       │  │
│  │                                     ↑            ↓        │  │
│  │                                     └─ tool_dispatch ←──┘  │  │
│  │                                                    ↓       │  │
│  │                                                   END      │  │
│  └────────────────────────────────────────────────────────────┘  │
│                           │                                       │
│         ┌─────────────────┼──────────────────┐                   │
│         ▼                 ▼                  ▼                   │
│  ┌─────────────┐  ┌────────────────────┐  ┌──────────────────┐  │
│  │ LLM Gateway │  │ Retrieval          │  │  Tools Layer     │  │
│  │ Ports &     │  │ (M2c Modular RAG   │  │  4 tools wired   │  │
│  │ Adapters    │  │  6-stage pipeline) │  │  (see §工具)      │  │
│  └──────┬──────┘  └──────┬─────────────┘  └──────────────────┘  │
└─────────┼────────────────┼──────────────────────────────────────┘
          │                │
  ┌───────┴───────┐        ▼
  ▼               ▼  ┌─────────────────────────────────┐
 newapi proxy  DeepSeek│  Qdrant 1.13                  │
 (sonnet/opus) (扩展点)│  ├─ products_text (bge-m3 1024d)│
                      │  └─ products_image (JinaCLIP    │
                      │       1024d, 跨模态)            │
                      │  Tantivy svc :7700 (BM25)       │
                      │  TEI svc :7997 (bge-reranker)   │
                      │  SearXNG :8080 (CRAG fallback)  │
                      │  PostgreSQL 16 / Redis 7        │
                      └─────────────────────────────────┘
                                 ↑
                      ┌──────────────────────┐
                      │  KB Ingestion (离线) │
                      │  M2c demo seed_kb +  │
                      │  M3 真 Docling 管道  │
                      └──────────────────────┘

* M2b 已交付:5 LangGraph nodes, 4 tools, 8 SSE events
* M2b-Obs 已交付:Langfuse 3 trace + 5 维度 AgentEvaluator + Ragas + 50 gold-set + CI eval gate + 8 面板 Grafana
* M2c 已交付:Modular RAG 6 阶段(Pre-Retrieval / 3-way Retrieval / RRF / Reranker+Compression / Self-Eval Loop / CRAG),+13 SpanHook steps,+7 Prom metrics,+4 Grafana panels
* 当前 **后端 889 passed(含认证 22 测;CI 默认 = 不含 integration/e2e);eval 包 51 + kb-ingestion 包 45;前端 web 254 vitest**(M2c close 396 → M6-M10 + 认证增量)
* M6 KB 在线管理 / M7 LLM 模型配置 / M8 用户画像持久化 / Pre-M9 细节补全 / M10 iOS 客户端 / 用户认证 + RBAC + 统一身份 均已交付(见 Roadmap)

技术栈

选型 版本 / 说明
后端语言 Python 3.12 + uv uv 包管理,比 pip/poetry 快 10-100×
Web 框架 FastAPI 0.115+,异步原生,原生 SSE 支持
Agent 编排 LangGraph 0.2+,StateGraph + 条件边;当前未启用 Checkpointer——多轮记忆走「客户端持有历史 + Working-Memory 锚点」,详见 §多轮对话记忆
LLM(Advisor / Intent) Claude Sonnet 4.6 via newapi proxy(SONNET_API_KEY)
LLM(Judge) Claude Sonnet 4.6 via newapi proxy(SONNET_API_KEY);T17.5 起从 Opus 4.7 切换 — newapi 对 Opus 4-系列强制 temperature=1.0 破坏判定稳定性,详见 llm.yamlanthropic_opus provider 仍注册可未来切回
LLM 抽象 自研 Ports & Adapters 非 LiteLLM;Protocol-based + Adapter + FallbackChain
向量库 Qdrant 1.13+ 自托管 Docker;双 collection — products_text (bge-m3 1024d) + products_image (JinaCLIP 1024d);M2c 后均已激活
关系库 PostgreSQL 16 + asyncpg 商品元数据 + 结构化规格双列
Embedding bge-m3 自托管,1024d,多语言,稠密+稀疏+ColBERT 三合一
Reranker bge-reranker-v2-m3 M2c 已交付;HF Text Embeddings Inference (TEI) Docker 服务(host port 7997);top-20 → top-5 cross-encoder
BM25 Tantivy M2c 已交付 docker 服务(host port 7700);FastAPI+tantivy-py wrap;jieba 中文分词(client side)
跨模态 Embedding JinaCLIP-v2 M2c 已交付;865M 模型 in-process 单例(双 check lock);文本/图像共享 1024d 空间
缓存 Redis 7 LLM 响应缓存
Web 搜索 SearXNG 自托管;M2c 已激活作为 CRAG fallback(rewrite → /search → top-3 → Evidence(source="web"))
可观测 Langfuse 3.x 自托管 + Prometheus + Grafana M2b-Obs 已交付;9 字段 SpanFields;prometheus-fastapi-instrumentator
评估 Ragas 0.2+ + 自研 AgentEvaluator 5 维度 M2b-Obs 已交付;CI eval gate + 50 case gold-set
前端(M5 已交付) Next.js 15 / React 19 / Vercel AI SDK 6.x / shadcn-style(base-ui) / Tailwind 4 TypeScript 5.5+

跨平台支持

raguide 在 macOS / Linux / Windows 上都能跑。所有路径用 pathlib、配置只读 .env(不依赖 .zshrc / .bash_profile / PowerShell $PROFILE)。

Windows 提示:推荐使用 WSL2,所有命令和 Mac/Linux 完全一致。如果坚持原生 PowerShell,下面各节给出对应命令。


前置依赖

工具 用途 macOS Linux Windows
Python ≥ 3.12 后端 + 摄入 CLI brew install python@3.12 apt install python3.12 https://python.org/downloads
uv Python 包管理 curl -LsSf https://astral.sh/uv/install.sh | sh 同 macOS powershell -c "irm https://astral.sh/uv/install.ps1 | iex"
Docker Desktop 容器编排 https://docker.com/products/docker-desktop https://docs.docker.com/engine/install/ https://docker.com/products/docker-desktop
Node.js ≥ 20 Web 前端(M5) brew install node@20 nvm install 20 https://nodejs.org/en/download
Git 版本控制 brew install git apt install git https://git-scm.com/download/win

Quick Start(4 步起服务)

步骤 0 · Clone + 进目录

git clone git@github.com:JavaLyHn/raguide.git
cd raguide

步骤 1 · 配置 .env(所有平台必须)

# macOS / Linux / WSL
cp .env.example .env

# Windows PowerShell
Copy-Item .env.example .env

然后编辑 .env 填入 LLM 凭据。详见下面「LLM 配置」小节。

步骤 2 · 启动 Docker 依赖

docker compose -f infra/docker-compose.yml up -d

第一次会拉镜像(~6 GB),耐心等。

步骤 3 · 启动后端

# macOS / Linux / WSL
cd apps/backend
uv run uvicorn raguide_backend.main:app --reload --port 8000

# Windows PowerShell
cd apps\backend
uv run uvicorn raguide_backend.main:app --reload --port 8000

如果 .env 缺少必要的 API key,uvicorn 会在启动时立刻抛 RuntimeError(含可点击的 .env 路径),不会等到请求时才报错——这是设计意图。

步骤 4 · 启动前端(M5 完成后有效;另开窗口)

cd apps/web
npm install
npm run dev

浏览器打开 http://localhost:3000


LLM 配置

raguide 使用 Anthropic SDK,通过 config/llm.yaml 做角色路由。当前默认走 newapi 代理,使用两个独立 API key(newapi 按 key 做模型隔离)。

选项 A · newapi 代理(当前默认)

编辑 .env

SONNET_API_KEY=<newapi 给的 sonnet key>
OPUS_API_KEY=<newapi 给的 opus key>
ANTHROPIC_BASE_URL=https://newapi.elevatesphere.com

ANTHROPIC_BASE_URL 不要带 /v1 后缀。Anthropic SDK 自己会追加 /v1/messages。如果写成 .../v1,SDK 会拼成 /v1/v1/messages → 404。raguide 启动时会自动检测并剥掉错误的 /v1,但建议写对。

选项 B · 官方 Anthropic API(单 key)

如果用官方 API(无代理),.env 改为:

ANTHROPIC_API_KEY=sk-ant-api03-...
ANTHROPIC_BASE_URL=

同时修改 apps/backend/config/llm.yaml,将 anthropic_sonnetanthropic_opus 两个 provider 都改用 api_key_env: ANTHROPIC_API_KEY

选项 C · OS 环境变量覆盖(CI / 生产)

pydantic-settings 优先级:OS env > .env > 默认值。

# macOS / Linux / WSL
export SONNET_API_KEY=...
export OPUS_API_KEY=...
export ANTHROPIC_BASE_URL=https://newapi.elevatesphere.com

# Windows PowerShell(当前 session)
$env:SONNET_API_KEY = "..."
$env:OPUS_API_KEY = "..."

# Windows PowerShell(持久化)
[Environment]::SetEnvironmentVariable("SONNET_API_KEY", "...", "User")

Run M1 Demo(单 Agent RAG 验证)

M1 已完成,演示 RAG 全链路:PDF 摄入 → 向量检索 → 流式生成。

macOS / Linux / WSL

# 1. 确保 Qdrant + Postgres 在跑
docker compose -f infra/docker-compose.yml up -d qdrant postgres

# 2. 摄入 5 份 3C 商品 PDF(首次会下载 bge-m3 约 2GB,5-10 分钟)
uv run raguide-ingest --src data/m1/

# 3. 起后端
cd apps/backend
uv run uvicorn raguide_backend.main:app --port 8000 &

# 4. 发送问题
curl -N -X POST http://localhost:8000/v1/agent/run \
  -H "Content-Type: application/json" \
  -d '{"session_id":"demo","user_input":{"text":"小米 17 Pro Max 电池多大"}}'

Windows PowerShell

# 1. 起 Docker
docker compose -f infra\docker-compose.yml up -d qdrant postgres

# 2. 摄入
uv run raguide-ingest --src data\m1\

# 3. 起后端
cd apps\backend
Start-Process -NoNewWindow uv -ArgumentList "run", "uvicorn", "raguide_backend.main:app", "--port", "8000"
cd ..\..

# 4. 发送(PowerShell 内建,SSE 流不显示;建议用 curl)
Invoke-RestMethod -Method Post -Uri "http://localhost:8000/v1/agent/run" `
  -ContentType "application/json" `
  -Body '{"session_id":"demo","user_input":{"text":"小米 17 Pro Max 电池多大"}}'

Windows + SSEInvoke-RestMethod 不支持 SSE 流式显示。推荐安装 curl:winget install curl,然后使用 macOS 命令。

预期 SSE 输出(M1 路径,4 事件)

event: intent_done
data: {"slots":{"category":"phone","budget":null,"preferences":["battery"],"mentioned_products":["小米 17 Pro Max"],"intent_type":"spec_lookup","complexity":"simple"}}

event: retrieval_done
data: {"evidence":[{"product_id":"xiaomi-17-pro-max","score":0.747,"snippet":"...7500mAh..."},...]}

event: token
data: {"delta":"小米 17 Pro Max 搭载 **7500mAh** 大"}

event: token
data: {"delta":"电池,支持 **100W 有线快充 + 50W 无线快充**,是该系列容量最大的版本。\n\n—— 来自 xiaomi-17-pro-max.pdf p.1"}

event: done
data: {"usage":{"tokens_in":2551,"tokens_out":90,"cost_cny":0.063},"trace_id":"trc_..."}

Run M2b Demo(Multi-Agent 推荐路径)

M2b 完成后,完整的 5 节点 LangGraph 流水线已上线。

curl -N -X POST http://localhost:8000/v1/agent/run \
  -H "Content-Type: application/json" \
  -d '{"session_id":"demo","user_input":{"text":"5000 以内拍照好的手机"}}'

预期 SSE 事件序列

最简路径(Advisor 认为检索结果已足够,无工具调用):

event: intent_done
data: {"slots":{"category":"phone","budget":5000,"preferences":["camera"],"mentioned_products":[],"intent_type":"recommend","complexity":"deep"}}

event: retrieval_done
data: {"evidence":[{"product_id":"vivo-x300-ultra","score":0.62,...},{"product_id":"xiaomi-17-pro-max","score":0.60,...},...]}

event: token
data: {"delta":"根据您的预算和拍照需求,为您推荐以下几款..."}

...(更多 token)...

event: done
data: {"usage":{...},"trace_id":"trc_..."}

含工具调用路径(Advisor 主动查详情或对比):

event: intent_done
data: {...}

event: retrieval_done
data: {...}

event: tool_call_started
data: {"tool_name":"compare_products","args":{"product_ids":["vivo-x300-ultra","xiaomi-17-pro-max"]}}

event: tool_call_done
data: {"tool_name":"compare_products","result":{...}}

event: card
data: {"kind":"compare","products":[...],"dimensions":[...]}

event: token
data: {"delta":"综合以上对比..."}

event: done
data: {...}

所有 4 个工具均已接入:get_product_details(Postgres + Qdrant 真实数据)、compare_products(真实,组合调用 get_product_details)、spec_query_sql真实,Pre-M9 起查 Postgres product_specs 双列做数值硬约束过滤)、read_sop(真实,读取 docs/sops/*.md)。


SSE 事件协议(8 类)

事件名 Payload 结构 何时发出 起始里程碑
intent_done {"slots": IntentSlots} IntentAgent 完成 json_schema 解析 M2b
retrieval_done {"evidence": [Evidence, ...]} RetrievalAgent 完成检索 M1
tool_call_started {"tool_name": str, "args": dict} AdvisorAgent 发起工具调用 M2b
tool_call_done {"tool_name": str, "result": Any} 工具执行返回 M2b
card {"kind": "product"|"compare", ...} compare_products 或 Advisor 生成卡片 M2b
token {"delta": str} AdvisorAgent 流式吐字(每个 token chunk) M1
done {"usage": {...}, "trace_id": str} 单轮对话结束 M1
error {"code": str, "message": str, "recoverable": bool} 任意节点异常 M1

IntentSlots 结构

{
  "category": "phone|laptop|earphone|null",
  "budget": 5000,
  "preferences": ["camera", "battery"],
  "mentioned_products": ["iPhone 16"],
  "intent_type": "recommend|compare|spec_lookup|faq|unknown",
  "complexity": "simple|deep"
}

Multi-Agent 架构详解(M2b)

5 个 LangGraph 节点

节点 职责 读取 State 字段 写入 State 字段
orchestrator 路由入口,初始化 trace_id,校验输入 user_query trace_id, started_at
intent 用 Claude Sonnet json_schema 解析用户意图,提取 6 维 IntentSlots;双重校验(Anthropic server + Pydantic client) user_query, history slots
retrieval M2c Modular RAG 6 阶段管道(详见 §Modular RAG 内层管道);签名保持 async def retrieval_node(state) -> state 不变;body 委托给 modular_pipeline.run();emit retrieval_done SSE slots, user_image_url? evidence, compressed_evidence, web_results, self_eval_*, crag_triggered, ...
advisor Claude Sonnet 生成推荐,可在 tool-use loop 内多次调用工具(max 5 轮,同一工具 max 3 次);流式 emit token + card slots, evidence, history response, tool_calls, cards
tool_dispatch 执行单次工具调用,刷新 Working-Memory Anchor;根据结果决定回到 advisor 还是结束 tool_calls[-1] tool_calls[-1].result, working_memory

4 个工具(含 trigger / exclusion 元数据)

工具 类型 Trigger 条件 Exclusion 条件
get_product_details 真实(Postgres + Qdrant) 已知 product_id,需完整规格 product_id 未知时
compare_products 真实(组合调用) 用户要求对比 2-3 款 仅 1 个候选时
spec_query_sql 真实(Postgres product_specs 双列) 硬约束过滤(电池≥5000mAh、价格≤6000 等数值约束,参数化 SQL 取交集) 语义模糊查询
read_sop 真实(读 docs/sops/) 需要领域 SOP(话术/口径/对比规则) 常识性回答

Working-Memory Anchor(每次工具返回自动注入)

<working_memory>
当前用户意图: recommend / phone
对比中商品: vivo-x300-ultra | xiaomi-17-pro-max
已收集证据: 8 段检索 + 2 次工具
用户上传图摘要: (未上传)
图像证据命中数: 0
用户偏好痕迹: camera · 预算 ≤5000元
</working_memory>

设计意图:多轮对话中 LLM 容易忘记早期偏好。Working-Memory Anchor 不依赖完整 history,通过每次工具返回末尾(注入到最后一条 tool_result)刷新焦点状态来缓解遗忘(借鉴 GenericAgent 设计 ②)。这 6 块固定字段由 agent/working_memory.py 组装,完整机制见 §多轮对话记忆

安全防护

  • MAX_TOOL_ITERATIONS = 5:防止 Advisor 无限工具调用循环
  • SAME_TOOL_CAP = 3:同一工具最多调用 3 次(防重复)
  • json_schema 双重校验:Anthropic server 强制 schema + Pydantic client 二次校验,prompt injection 在 IntentAgent 层直接被过滤为 null 字段
  • 业务异常 vs 基础设施异常分离ToolError(可重试)vs InfraError(直接 error 事件)

多轮对话记忆(短期 / 长期 / 锚点)

raguide 当前采用 「客户端持有历史 + 无状态后端 + Working-Memory 锚点」 的记忆架构,未启用 LangGraph Checkpointer。分三层:

① 短期记忆(单会话内多轮)— 客户端驱动

  • 前端 useChat(Vercel AI SDK 6.x)维护 messages 数组(apps/web/app/page.tsx)。
  • 自研 RaguideChatTransport 每轮把「最新 user 文本 + 完整历史 history[]」一起 POST 到 /v1/agent/runapps/web/lib/transport.ts)。
  • 后端 Advisor 每轮重建消息列表,最多取最近 20 轮,无摘要agent/advisor.pyhistory[-20:])。
  • session_id(前端 UUID)仅用于日志 / 反馈追踪,不用于状态恢复
  • → 后端完全无状态;"记忆"实体在前端,逐轮整体重发。

② Working-Memory 锚点注入(借鉴 GenericAgent 设计 ②)

工具循环(Self-Eval loop,最多 2 轮)中,每次工具返回后把 <working_memory> 块注入到最后一条 tool_result 消息(agent/working_memory.py + agent/advisor.py)。固定 6 块:当前意图 / 对比中商品 / 已收集证据 / 用户上传图摘要 / 图像命中数 / 偏好痕迹·预算。让 LLM 在每次工具返回后重读累积焦点,缓解长上下文遗忘。格式见上文 §Working-Memory Anchor

③ 长期记忆(跨会话)— 会话存取 + 用户画像学习

  • conversations 表(PostgreSQL,messages JSONB,匿名 owner_id)保存 / 恢复整段对话(api/conversations.py,M5.1 交付)。

  • 切换会话时 GET /v1/conversations/{id}setMessages 全量还原。

  • 用户画像(跨会话偏好学习,已实现):按 owner_id 持久化时间衰减的偏好画像(user_profiles 表 + agent/user_profile.py)。done_hook 每轮异步把 slots 合并进画像(指数半衰期计数);intent_node 用画像补全空缺槽位(本轮明说优先),working_memory 注入「历史画像」块。参数(半衰期 / Top-N / 守卫阈值 / 品牌白名单)经 admin「画像参数」面板在线可调(profile_config 表 + 热加载)。用户可在「设置」查看 / 清除自己的画像(GET/DELETE /v1/me/profile)。设计见 docs/superpowers/specs/2026-06-09-user-profile-persistence-design.md

  • 5 层记忆(L0–L4)已基本落地(Pre-M9 批次):L0 失败 case 候选池 + 人工确认门禁(done_hook 低分入池 → admin「评测候选」面板 approve → 写 human_verified gold-set);L1 商品类目大纲常驻注入(kb/catalog_outline.py,热加载);L2 Working-Memory 锚点 + 用户画像;L3 Modular RAG 向量召回;L4 对话摘要压缩(超 12 轮即时摘要,替代硬截断)。

⚠️ 已设计但尚未实现(面试需诚实区分"现状 vs 目标")

设计(CLAUDE.md §5 / umbrella spec) 现状
统一「5 层」记忆抽象 L0–L4 各层均已落地(见上),但仍是离散实现,无单一 MemoryManager 抽象层(YAGNI,可不做)
LangGraph Checkpointer(thread_id 恢复) 不采用(有意做无状态后端)
完整大表父子检索(MultiVectorRetriever) 仅最小版(表格行级 chunk + 模板前缀 capability 已建+测);MultiVectorRetriever + LLM Contextual 前缀 + 摄入路径接线待续

设计取舍:无状态后端便于水平扩展(无 session 亲和性要求),历史真值在前端、跨会话持久化交给 conversations 表 + user_profiles 画像表。L0–L4 五层记忆已落地(L4 用即时摘要替代了原 20 轮硬截断);仅「统一抽象层」与 checkpointer 是有意未做的取舍——面试时主动说清这条"现状 vs 设计"边界。


Modular RAG 内层管道(M2c)

RetrievalAgent 内部 6 阶段流水线 — Pre-Retrieval → 3-way Retrieval → RRF Fusion → Post-Retrieval → Self-Eval Loop → CRAG fallback:

用户问题
   ↓
┌─ 1. Pre-Retrieval (Branching, intent-conditional) ──────────┐
│   IntentSlots → router → 选一支:                            │
│     • HyDE          (短/模糊 query, Sonnet 4.6 → 假设性回答) │
│     • Multi-Query   (长 query 多面, Sonnet 4.6 → 3 个变体)   │
│     • Decompose     (compare ≥2 产品, 纯 Python 拆分)        │
│     • passthrough   (chitchat / unknown)                     │
└────────────────────────────────────────────────────────────┘
   ↓ asyncio.gather (per-path 2s timeout, 失败不阻塞)
┌─ 2. Retrieval (Branching, 3-way concurrent) ────────────────┐
│   • BM25     :7700  (Tantivy + jieba 中文分词)               │
│   • Dense   Qdrant  (bge-m3 1024d, products_text)            │
│   • Image   Qdrant  (JinaCLIP-v2 1024d, products_image,      │
│                       activate when state.user_image_url ≠ "")│
└────────────────────────────────────────────────────────────┘
   ↓
3. Fusion (RRF k=60) — chunk_id dedup, max-score keep, top-20
   ↓
┌─ 4. Post-Retrieval (Linear) ───────────────────────────────┐
│   4.1 Reranker (TEI :7997, bge-reranker-v2-m3) → top-5     │
│   4.2 Compression (Sonnet 4.6 json_schema, ≤200 字符/chunk,  │
│       reject hallucinated chunk_id)                          │
└────────────────────────────────────────────────────────────┘
   ↓
┌─ 5. Self-Eval Loop (Looping, max 2 轮) ─────────────────────┐
│   5.1 rule  (top≥0.7 ∧ count≥3 → 1.0)                       │
│   5.2 llm   (rule 没过 → Sonnet 4.6 仲裁                     │
│              {enough, has_clues, missing_aspects})           │
│   verdict 路由:                                             │
│     • enough=True                → finish (score=1.0)        │
│     • !enough,  has_clues, iter<2 → retry_with_focus (0.0)   │
│     • !enough,  has_clues, iter=2 → finish_degraded (0.4)    │
│     • !enough, !has_clues         → CRAG ↓                   │
└────────────────────────────────────────────────────────────┘
   ↓
┌─ 6. CRAG Fallback (Conditional) ───────────────────────────┐
│   Sonnet 4.6 rewrite (json_schema, ≤100 char web query)      │
│       → SearXNG :8080 /search → top-3                        │
│       → Evidence(source="web", chunk_id="web_0..2")          │
│   Advisor system prompt 末追加 §7 网络检索补充规则           │
│       (强制 "经查询 [年月]" 引用前缀)                       │
└────────────────────────────────────────────────────────────┘
   ↓
state["evidence"] = state["compressed_evidence"] (或 web_results 若 CRAG)
→ AdvisorAgent

M2c 设计决策(spec §1.2 brainstorm 锁定)

# 决策 选择
Q1 scope 一锅端 28 task / 单 milestone
Q2 KB 数据 M2c 内嵌 demo seed(5 产品 × 6-10 chunk + 5 图),M3 真 Docling 替换
Q3 BM25 实现 Tantivy 独立 docker service(非 Qdrant 原生 sparse),严格按 spec
Q4 JinaCLIP 进 scope + 5 CC0 placeholder 图
Q5 Self-Eval Hybrid 规则粗筛 + LLM 细筛(非纯 LLM 也非纯规则)
Q6 Pre-Retrieval 3 个分支全上 + intent-conditional 路由(非并跑所有)
Q7 CRAG 最小可行闭环(rewrite → SearXNG → 3 results;无 full-page scrape;无 DuckDuckGo Plan B)
Q8 Reranker 部署 TEI Docker(非 in-process)

M2c 观测面板(4 个新 Grafana panel id 9-12)

  • Panel 9 Retrieval pipeline latency p95 by step(13 个 step 标签:pre_retrieval.hyde / retrieval.bm25 / fusion.rrf / post.rerank / self_eval.llm / crag.search …)
  • Panel 10 Self-Eval verdict distribution(finish / finish_degraded / retry_with_focus / crag stacked)
  • Panel 11 CRAG fallback frequency(rate stat, 阈值 green/yellow/red @ 0.01/0.05)
  • Panel 12 Recall@5 trend(gold-set 跑 eval 写入的 gauge)

新加 7 个 Prom 指标:raguide_retrieval_latency_seconds(Histogram by step+status)、raguide_retrieval_recall_at_5(Gauge)、raguide_self_eval_decisions_total(Counter by verdict)、raguide_self_eval_iterations_total(Counter by iter)、raguide_crag_fallback_total(Counter)、raguide_fusion_dedup_ratio(Gauge)、raguide_rerank_score_delta(Histogram, buckets 0/1/2/3/5/10/20)。

M2c 新 Langfuse score(与 5 维 AgentEvaluator 解耦)

agent.self_eval — done_hook 在 state.self_eval_score 非空时通过 langfuse_client.create_score() 推送。进 5 维 AgentEvaluator 加权(CLAUDE.md Rule #3 LOCKED:task_completion 30% + output_quality 30% + process_quality 20% + efficiency 10% + safety 10% 不变)。


LLM Ports & Adapters 设计(M2a)

LLMProvider (Protocol, PEP 544)
    ├── stream_chat(messages, tools, system_prompt, ...) -> AsyncIterator[StreamEvent]
    ├── supports(feature: str) -> bool
    └── estimate_cost(tokens_in, tokens_out) -> float

        ↓ implements
AnthropicAdapter          ← v1 唯一路由(via SONNET/OPUS key + newapi proxy)
OpenAICompatibleAdapter   ← Template Method base(骨架:build_payload + parse_stream)
    └── DeepSeekAdapter   ← 已注册(ProviderRegistry),不路由(扩展点演示)

ProviderRegistry (Factory)  ← 从 llm.yaml 加载,启动时验证所有 role→provider 映射
FallbackChain (CoR)         ← [anthropic_sonnet → anthropic_opus],指数退避 1s/2s/4s

4 个设计模式协同

模式 体现
Adapter 各家 SDK → 统一 LLMProvider Protocol 接口
Template Method OpenAICompatibleAdapter 定义流式归一化骨架;子类只填 base_url / model_id
Strategy YAML 配置 roles.advisor.provider: anthropic_sonnet 做运行时路由
Chain of Responsibility FallbackChain(primary, *fallbacks) 主路失败自动降级,无需调用方感知

5 类 LLMError 树

LLMError (base)
├── TransientLLMError      ← 网络抖动,FallbackChain 自动重试
├── RateLimitLLMError      ← 429,指数退避后重试
├── AuthLLMError           ← 401/403,启动时 fail-fast,不重试
├── SchemaValidationError  ← json_schema 不合 schema,记 trace span error
└── UpstreamLLMError       ← 500/502,对外 error 事件

测试

# 单元测试(CI 默认 = 不含 integration/e2e,889 个后端单测;前端另有 254 web vitest)
uv run pytest -m "not integration and not e2e"

# 集成测试(需要 Docker 起 Postgres + Qdrant,约 10 秒)
uv run pytest -m integration

# E2E 测试(需要 .env 真实 API key,约 40 秒,消耗约 ¥0.05)
uv run pytest -m e2e

测试覆盖分布(下表为 M2c 收尾时的 396 单测分布;M6-M10 + 认证增量后后端共 889 单测(含认证 22 测)、前端 254 web vitest、eval 包 51 + kb-ingestion 包 45):

来源里程碑 测试数 说明
LLM + Agent 单元 M1/M2a/M2b ~191 json_schema 校验、Tool dispatch cap、Working-Memory、Adversarial (prompt injection / SQL / 路径遍历)
Observability 单元 M2b-Obs + M2c ~35 LangfuseSpanHook 18 step 注册(5 M2b + 13 M2c)、tokens_capture per-trace counter、Prom metrics 13 个指标
Eval pipeline 单元 M2b-Obs ~30 AgentEvaluator 5 维度、Judge JSON schema、Ragas runner、ci_gate 双门禁、gold-set GoldCase schema
Modular RAG 单元 M2c ~125 Pre-Retrieval(HyDE/Multi-Query/Decompose/router 24)+ 3 路 Retrieval(Tantivy/dense/image/fanout 16)+ RRF(7)+ Post(reranker/compression 11)+ Self-Eval(rule/llm/loop 19)+ CRAG(fallback/searxng 9)+ Integration(pipeline 5)+ Obs(m2c_obs 5)+ Seed(kb/images 9)
Workflow YAML lint M2b-Obs 2 .github/workflows/*.yml 顶层 key 防漂移
集成 M1/M2b 3 KB fetchers + lifespan boot
E2E M1/M2b 3 M2b recommend + M2b compare + M1 regression(真 API)

**M2c 新增的 Modular RAG 测试(~125 个)**包括:HyDE/Multi-Query json_schema + 6 元素 prompt + 拒幻觉 chunk_id(compression Q3)+ 3 路 retrieval graceful degradation + RRF k=60 + dedup 比 + reranker rank-delta + Self-Eval rule fast-path + LLM verdict 矩阵 + CRAG rewrite/<script> 过滤 + 4 verdict 路由(finish/retry/finish_degraded/crag)+ retrieval_node 签名保持。3 类新 adversarial:Pre-Retrieval 注入 / 图片隐藏文本 / CRAG web 污染。


已交付命令(make targets)

命令 来源里程碑 用途
make langfuse-up M2b-Obs 启动 Langfuse 自托管 docker-compose(ClickHouse + Postgres + MinIO + Worker + Web,6 容器,Web UI 默认 http://localhost:3001)
make langfuse-down M2b-Obs 停止 Langfuse 全部容器
make langfuse-logs M2b-Obs 跟踪 Langfuse Web/Worker 日志
make langfuse-status M2b-Obs Langfuse 各容器健康状态
make eval-gold M2b-Obs 跑 50 条 gold-set → Ragas 4 指标 + 5 维度 AgentEvaluator + 双门禁;本地需先 make eval-infra 起 pg/qdrant/redis
make eval-baseline M2b-Obs 重置 tests/gold_set/_baseline.json(intentional 行为变更后用)
make eval-infra M2b-Obs 起本地 eval 三件套(pg + qdrant + redis)
make eval-infra-down M2b-Obs 关本地 eval 服务
make ci-check M2b-Obs 本地复现 CI sweep(ruff + pytest)
make m2c-infra-up M2c 起 Modular RAG 全栈(qdrant + postgres + redis + searxng + tantivy-server :7700 + tei-reranker :7997
make m2c-infra-down M2c 仅停 M2c 新增的 tantivy + tei(共享 infra 不动)
make m2c-seed M2c scripts/seed_kb_demo.py:5 产品 × 6-10 chunk + 5 图 → Qdrant text/image + Tantivy + Postgres
make eval-langfuse-dataset 评测可观测化 把 75 例 gold-set YAML 镜像成 Langfuse Dataset raguide-gold-set(仅 items,item id=case_id 幂等;YAML 仍是唯一真值)
make eval-dataset-run 评测可观测化 跑 gold-set 并用 item.run() 把每例结果注册为 Langfuse dataset run + 挂回 5 维 / 加权 goldset.* score(跨 run 可比;不传 --ragas,Ragas 因依赖冲突 deferred)

CI Eval Gate.github/workflows/eval.yml)当前为 manual workflow_dispatch trigger(per Run #8 secret-config issue resolved by switching trigger)— 想跑就到 Actions 页面手动点 Run workflow

依据 spec:


环境变量参考

Observability + Eval environment variables (M2b-Obs)

Variable Required for Default Notes
LANGFUSE_HOST trace http://localhost:3001 UI host port from infra/docker-compose.langfuse.yml
LANGFUSE_PUBLIC_KEY trace unset → no-op Created in Langfuse UI; pk-lf-...
LANGFUSE_SECRET_KEY trace unset → no-op Created in Langfuse UI; sk-lf-...
EVAL_ENABLED prod async eval true Set false in CI/e2e to avoid duplicate judge spend
EVAL_SAMPLE_RATE prod async eval 1.0 Float 0..1; production sampling

When the Langfuse keys are absent the LangfuseClient.get() returns None and all hooks no-op — backend stays fully functional without observability.

CI eval gate secrets

.github/workflows/eval.yml runs all 50 gold-set cases on every PR (gate enforcement) and on every push to main (baseline auto-update on PASS). It requires the following repo secrets:

  • SONNET_API_KEY — required (judge LLM is Sonnet 4.6 since T17.5; see CLAUDE.md §4)
  • OPUS_API_KEY — required only for Ragas runner (LangchainLLMWrapper currently points at Opus)
  • ANTHROPIC_API_KEY — fallback / unified key when not using the newapi proxy
  • ANTHROPIC_BASE_URL — required when proxying through newapi

PR runs evaluate against the current main baseline. Main pushes update the baseline on PASS (auto-commit by github-actions[bot]).

Each run executes 50 cases × 1 judge call = ~50 Sonnet 4.6 invocations. Typical cost: $0.10–$0.30/run. Set EVAL_SAMPLE_RATE to throttle in dev.

(EVAL_SAMPLE_RATE is the production-eval sampling knob in the backend; it does not affect CI eval, which always runs all 50. The note is informational only.)


常见问题(Troubleshooting)

Q1. 后端启动报 RuntimeError: ANTHROPIC_API_KEY is not set

.env 还是占位符(或缺少 SONNET_API_KEY)。打开错误消息里的绝对路径,填入真实 key。详见「LLM 配置」。

Q2. 代理报 404 Not Found 或日志出现 /v1/v1/messages

ANTHROPIC_BASE_URL 带了 /v1 后缀。改为不带 /v1 的根 URL(如 https://newapi.elevatesphere.com)。

Q3. uv run raguide-ingest 报 "bge-m3 download failed"

sentence-transformers 缓存目录权限或网络问题。

  • macOS / Linux:检查 ~/.cache/huggingface/hub/ 可写
  • Windows:检查 %USERPROFILE%\.cache\huggingface\hub\ 可写
  • 中国大陆:可设 HF_ENDPOINT=https://hf-mirror.com 走镜像

Q4. Windows 上 docker compose 报错

Docker Desktop 必须在前台启动(鲸鱼图标 menubar 显示绿色)。首次在 WSL2 下需手动启用 integration。

Q5. PowerShell 启动 uvicorn 后无法关闭

Start-Process 后用 Get-Process uv | Stop-Process,或直接关 PowerShell 窗口。

Q6. macOS 上 docker compose up ClickHouse healthcheck 失败

已知问题:ClickHouse healthcheck 用 localhost 会解析到 IPv6。raguide M0 的 docker-compose.yml 已修复(用 127.0.0.1)。更新到 main 最新即可。

Q7. 文档里出现 haiku-4-5,但实际运行是 sonnet-4-6

这是正确的。newapi 代理当前只暴露 sonnet-4-6opus-4-7haiku-4-5 不可用。因此 intent 和 advisor 两个角色都路由到 claude-sonnet-4-6(见 config/llm.yaml)。当 newapi 暴露 haiku 或切换到官方 Anthropic key 时,intent 角色可降级到 haiku 以节省约 10× 成本——只需改 llm.yaml,代码零改动。

Q8. 什么时候能在 Langfuse 看到 trace?

M2b-Obs 已交付。 起本地 Langfuse 即可:

make langfuse-up
# 等 60 秒让 ClickHouse + Postgres 初始化
open http://localhost:3001          # 创建 org/project + 拿 pk-lf-... / sk-lf-... key
# 把两个 key 写进 .env 后重启后端

X-Trace-ID HTTP 响应头会带 32 char OTel hex trace_id,直接到 Langfuse UI 搜该 id 看完整 span 树(含 9 字段 metadata + LLM-as-Judge 5 维度 score + Ragas 4 指标 score)。


项目结构

raguide/
├── apps/
│   ├── backend/                         # FastAPI + LangGraph
│   │   ├── src/raguide_backend/
│   │   │   ├── agent/                   # 5 LangGraph nodes + tools + prompts
│   │   │   │   ├── orchestrator.py      # 路由入口,trace_id 初始化
│   │   │   │   ├── intent.py            # IntentAgent + json_schema 双重校验
│   │   │   │   ├── retrieval.py         # RetrievalAgent(M1 dense;M2c 扩展)
│   │   │   │   ├── advisor.py           # AdvisorAgent + tool-use loop
│   │   │   │   ├── tool_dispatch.py     # 执行工具 + Working-Memory 刷新 + 安全 cap
│   │   │   │   ├── working_memory.py    # Working-Memory Anchor 构建
│   │   │   │   ├── graph.py             # StateGraph 组装 + 条件边
│   │   │   │   ├── state.py             # AgentState 10 字段 TypedDict
│   │   │   │   ├── prompts/             # intent.md, advisor.md(6 要素框架)
│   │   │   │   └── tools/               # 4 工具实现(含 trigger/exclusion 元数据)
│   │   │   │       ├── base.py          # Tool ABC + ToolRegistry
│   │   │   │       ├── get_product_details.py
│   │   │   │       ├── compare_products.py
│   │   │   │       ├── spec_query_sql.py
│   │   │   │       └── read_sop.py
│   │   │   ├── llm/                     # Ports & Adapters
│   │   │   │   ├── ports.py             # LLMProvider Protocol + 5 类 LLMError
│   │   │   │   ├── registry.py          # ProviderRegistry + YAML loader + 启动校验
│   │   │   │   ├── fallback.py          # FallbackChain(Chain of Responsibility)
│   │   │   │   ├── retry.py             # 指数退避(1s/2s/4s)
│   │   │   │   └── adapters/
│   │   │   │       ├── anthropic.py     # AnthropicAdapter(v1 唯一路由)
│   │   │   │       ├── openai_compat.py # OpenAICompatibleAdapter(Template Method)
│   │   │   │       └── deepseek.py      # DeepSeekAdapter(已注册,不路由)
│   │   │   ├── kb/
│   │   │   │   └── products.py          # asyncpg pool + Postgres/Qdrant fetchers
│   │   │   ├── retrieval/               # M1 dense retrieval(M2c 将扩展)
│   │   │   ├── api/                     # FastAPI routes + 8-event SSE handler
│   │   │   └── main.py                  # Lifespan: settings + registry + pool + tools
│   │   ├── config/
│   │   │   └── llm.yaml                 # Role → provider + model 路由配置
│   │   └── tests/                       # 889 unit(CI 默认,含认证 22)+ integration/e2e(需 Docker)
│   └── web/                             # Next.js 15(M5 — 已脚手架,功能 minimal)
├── packages/
│   └── kb-ingestion/                    # KB 摄入 CLI(Python,离线 job)
├── docs/
│   ├── requirements.md                  # M0 交付物(Step 1 七问)
│   ├── architecture.md                  # 高层架构概览
│   ├── archive/                         # 历史版本文档存档
│   ├── superpowers/
│   │   ├── specs/                       # Umbrella spec + 各 milestone spec
│   │   └── plans/                       # 实施计划 + 完成报告
│   └── sops/                            # 5 份领域 SOP(read_sop 工具读取)
│       ├── phone_recommendation.md
│       ├── comparison_protocol.md
│       ├── budget_constraints.md
│       ├── camera_advice.md
│       └── gaming_recommendation.md
├── infra/
│   └── docker-compose.yml               # Qdrant + Postgres + Redis + Langfuse + SearXNG + Grafana
├── data/
│   └── m1/                              # 5 份 3C 商品 PDF(M1 demo 数据)
├── tests/
│   └── gold_set.yaml                    # 评测金标集(M4 扩展至 50 条 5 类别)
├── 07-Phase7-实战篇-从零到生产.md        # 强制标准 #1(10 步工作流 + 10 项 launch checklist)
├── 08-可观测与可评估Agent深度设计.md     # 强制标准 #2(17 项 DoD)
├── CLAUDE.md                            # AI 工作规则(所有 AI 工具自动加载)
├── pyproject.toml                       # uv 项目配置
├── .env.example                         # 凭据模板(无真实 key,可进 git)
└── .gitignore                           # 屏蔽 .env / __pycache__ / .venv / *.pyc

文档索引

文件 用途
CLAUDE.md AI 工作规则(所有 AI 工具自动加载)
docs/requirements.md 需求文档(M0 Step 1 交付物)
docs/architecture.md 架构概览 — 3 个 mermaid(系统全景 / LangGraph 流程 / Modular RAG pipeline)
docs/interview-qa.md 30 题技术答辩底稿(架构决策 / 工程深度 / 实战教训 / 安全与对抗 + 电梯陈述)
docs/dod-verification.md 17 项 DoD 验收(16 ✅ / 1 🔶 CI 自动触发因账单 defer)
docs/runbook.md 运维手册 — SLO + 9 告警速查 + 8 故障场景 + 演练命令
docs/engineering-verification/ 逐里程碑工程验证账本(M0–M8,每本:checklist + finding + 闭环 + 亲跑测试结果)
docs/PROJECT_CHECKLIST.md M0-M6 完整验收清单(注:勾选状态偏旧,以工程验证账本为准)
docs/superpowers/specs/ Umbrella spec + 各 milestone 设计 spec(M2b-Obs ✅ / M2c ✅ 完成报告)
docs/superpowers/plans/ 实施计划 + 完成报告(M2b-Obs 22 task ✅ + M2c 28 task ✅;DoD 验收见 dod-verification.md 16/17 ✅)
docs/sops/ 5 份领域 SOP(由 read_sop 工具按需加载)
docs/standards/INDEX.md 强制开发标准索引
07-Phase7-实战篇-从零到生产.md 强制标准 #1 — 10 步工作流
08-可观测与可评估Agent深度设计.md 强制标准 #2 — 17 项 DoD

最近活动

完整 commit 流可看 git log --oneline。已交付里程碑(最新在前):

  • 评测可观测化增强(本会话已实现 + 本地验证,尚未提交):75 例 gold-set 镜像成 Langfuse Dataset raguide-gold-setmake eval-langfuse-dataset,新模块 packages/eval/src/raguide_eval/langfuse_dataset.py,live 验 75 items)+ dataset-run 闭环(make eval-dataset-run,每例 item.run() 挂回 5 维 / 加权 goldset.* score,跨 run 可比,live 端到端验过冒烟 run)+ run_gold_set --write-report 额外落 report-<stamp>.json 逐案完整 judge 理由;业主端只读评测看板EvalDashboardDialog + 5 个 admin-gated 只读端点 /v1/admin/eval/{baseline,reports,…,fixtures} + 公开 /static/eval-fixtures 服 fixture 图,免 Langfuse 看 baseline / 历史报告 / 逐案理由 / fixtures);UI 经 ui-ux-pro-max诚实更正:离线 Ragas 已全部接线但未启用——ragas 0.2.15 与后端 langgraph 1.2.x 的 langchain-core 版本冲突无法共存,本环境从未真正产出 Ragas 数据(4 指标设计未运行,解法见 提升.md)。测试:backend +8(admin_eval 29 passed)/ web +15(共 270 passed);eval 套件 163 passed;评测分数不变(纯可观测化,baseline 仍 0.838)。
  • 用户认证 + RBAC + 统一身份(三端)(后端 5acf363 / web 4efa9ca / iOS e8659df):用户名 + 密码注册登录(HS256 JWT / bcrypt / 首位注册者 = admin)、effective_owner_id 统一身份(有效 JWT → owner_id=sub,否则回退 X-Owner-Id游客零回归)、RBAC(Bearer admin JWT 优先 + X-Admin-Token 后备)。配套:会话按用户隔离(2193b0f)、Langfuse user_id 重设计(acct:/guest:4daae9a)、Google 式字母头像(0038d9e)、Gold-set 浏览器(后端只读 GET /v1/admin/eval/gold-set + web/iOS 业主视图,f75db75)。
  • M10 iOS 后续增强:豆包化视觉改版(信任蓝·柔和版,a520864)、抽屉补全 Tier1+2 消费者功能(b1c94e8)、历史删除两段式 inline 确认(8e7e9dd,自定义 SwipeConversationRow)、管理·业主段(画像参数 + 评测候选 approve/reject,44516b8)、数字键盘加「完成」(92b953e);未提交但已实现+验证:评测候选「查看完整内容」详情视图(web master-detail / iOS 整页,修「卡片只截断 2 行、整卡不可点」bug,+2 web vitest)、抽屉改整页 push 导航(NavigationStack 移至最外层隔离手势,clean build SUCCEEDED)、Gold-set L0 富化(贯通 4 层修复采纳入库候选数据稀疏:eval_candidate_casessignals JSONB → done_hook 存 signals → admin approve 构建 expected_slots + 富 notes → append_failed_case 写入;旧候选 signals=NULL 优雅降级,+1 backend 测试)。
  • M9 作品集文档 + 工程验证账本补齐(commit 6771eda):interview-qa.md(30 题技术答辩)+ architecture.md(3 mermaid)+ dod-verification.md(17 项 DoD,16✅1🔶)+ M6/M7/M8 工程验证账本(35 / 102 / 19 passed 亲跑复核)。此前 M9 优化(P1 空输入鲁棒 / P3 grounding 0.789→0.838 / P4 运维就绪)见上方 Roadmap 与评测日志。
  • M8 用户画像持久化:跨会话时间衰减偏好画像(owner_id keyed)+ admin 在线可配参数(热加载)+ 自助查看 / 清除。14 任务 Subagent-Driven + opus 最终评审(修复「偏好自强化循环」)。
  • M7 LLM 模型配置:业主在线配置多 provider 端点 + 角色绑定(密钥只进 .env)+ 热重载 + 连通性检测。
  • M6 KB 在线管理:业主应用内增删商品进运行中 KB + 独立 /kb 管理页(详情 / 编辑 / 重摄入 / 源 PDF)。
  • M5 / M5.1 Web UI:对话展厅(AI SDK 6.x,双栏 Chat + Inspector)+ claude.ai 式左侧栏多会话。
  • M2b-Obs / M2c:Langfuse + Ragas + 5 维 AgentEvaluator + Grafana;Modular RAG 6 阶段检索 pipeline。
  • Pre-M9 细节补全:4 文档审计 → 补齐 11 项「设计≠代码」细节(spec_query_sql 真查 / chitchat 跳检索 / coverage_score + 评测 rule_based 打分 / retrieval_step 实时 SSE / 记忆 L0 候选池门禁 / L1 类目大纲 / L4 对话摘要 / 在线 spec 抽取 / prompt caching / 大表行级 chunk 最小版)。Subagent-Driven 15 任务 + 安全评审(T1 spec_query_sql、T10 L0 gate)。
  • 测试:后端 889 passed(含认证 22 测;CI 默认 = 不含 integration/e2e),eval 包 51 + kb-ingestion 包 45,前端 web 254 vitest。CIci.yml(backend + web jobs)绿;eval.yml 为 manual workflow_dispatch
  • Pre-M9 遗留(已记 spec):eval baseline 需 make eval-baseline 重置(F5 改了打分);大表行级 chunk 的摄入路径接线(capability 已建未接 live);descope 项见 spec。

License

(WIP — 项目作品集用途,未正式发布)

About

对话式 3C 电子产品 AI 导购 Agent · 双层 RAG(Agentic 外层多 Agent 编排 + Modular 内层 6 阶段可组合检索)+ 评测驱动优化(5 维加权)+ 全链路可观测 · FastAPI/LangGraph + Next.js 15 + SwiftUI 三端全栈

Topics

Resources

License

Stars

2 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors