完整设计真相见
superpowers/specs/2026-05-20-raguide-system-architecture.md;面试技术追问的深答见interview-qa.md;运维故障处置见runbook.md。
3C 电子产品 AI 导购 Agent:Agentic RAG(外层)+ Modular RAG(内层),Orchestrator 调度 3 个 sub-agents(Intent / Retrieval / Advisor)。默认 Claude 模型族驱动;v1.1 起业主可经「模型设置」面板把任一角色路由到 Claude / GPT / DeepSeek(密钥只走 .env,DB 仅存 env 变量名)。
flowchart TD
Web["Web 客户端<br/>Next.js 15 + React 19 + AI SDK 6.x"]
BE["FastAPI + LangGraph<br/>(宿主 uvicorn :8000,非容器)"]
Web -- "SSE 9 事件<br/>(Bearer JWT / X-Owner-Id)" --> BE
subgraph Auth["认证 / RBAC / 统一身份"]
AU["/v1/auth register·login·me<br/>HS256 JWT + bcrypt"]
ID["effective_owner_id<br/>JWT.sub 优先,回退 X-Owner-Id"]
AD0["require_admin<br/>Bearer admin JWT + X-Admin-Token 后备"]
end
BE --> Auth
subgraph Agents["Orchestrator + 3 sub-agents"]
IA["IntentAgent<br/>意图槽位 json_schema"]
RA["RetrievalAgent<br/>Modular RAG 内层"]
AD["AdvisorAgent<br/>5 工具 + emit_cards"]
end
BE --> Agents
subgraph Stores["存储 / 检索(全自托管)"]
QD["Qdrant<br/>text + image 双 collection"]
TA["Tantivy<br/>BM25 稀疏"]
PG["PostgreSQL 16<br/>specs / gold-set / feedback / 配置"]
RD["Redis 7<br/>缓存 + 月成本累计"]
SX["SearXNG<br/>CRAG 兜底"]
MN["minio<br/>用户上传图"]
end
RA --> QD & TA & SX
AD --> PG
BE --> RD & MN
subgraph Models["模型服务(自托管)"]
BGE["bge-m3 嵌入"]
JC["JinaCLIP-v2 图像"]
RR["bge-reranker-v2-m3"]
end
RA --> BGE & JC & RR
subgraph Obs["可观测 / 评测"]
LF["Langfuse 3<br/>9 字段 span trace"]
PR["Prometheus + Alertmanager<br/>9 条告警规则"]
GF["Grafana 5 看板 32 panel"]
end
BE -. "trace / metrics" .-> Obs
PR -- "webhook" --> BE
flowchart LR
O["orchestrator<br/>状态初始化<br/>(无 LLM)"]
O -->|空/空白输入| C["clarify<br/>固定澄清话术<br/>(零 LLM)"]
O -->|正常| I["intent"]
I --> R["retrieval<br/>Modular RAG"]
R --> A["advisor"]
A -->|工具调用| T["tool_dispatch"]
T -->|证据增广回写| A
A -->|done| E["END + done_hook<br/>(LLM-judge 评分 + 画像更新)"]
C --> E
条件边由 _route_after_orchestrator 决定;advisor⇄tool_dispatch 是工具循环(SAME_TOOL_CAP=3 / MAX_ITER=5 安全帽);成功的 get_product_details/spec_query_sql 结果回写 evidence channel,统一 emit_cards / 评测 F5 / LLM-judge 的 grounding 口径(P3)。
flowchart TD
Q["query + slots"] --> PRE
subgraph PRE["Pre-Retrieval(intent 条件路由 / 分支)"]
HY["HyDE"]
MQ["Multi-Query"]
DC["Decompose"]
end
PRE --> FAN
subgraph FAN["三路检索(并发 fan-out / 分支)"]
BM["BM25 (Tantivy)"]
DE["Dense (bge-m3)"]
IM["Image (JinaCLIP-v2)"]
end
FAN --> RRF["RRF Fusion (k=60)"]
RRF --> POST
subgraph POST["Post-Retrieval(线性)"]
RK["Reranker (TEI)"]
CP["Contextual Compression"]
end
POST --> SE{"Self-Eval<br/>(max 2 轮)"}
SE -->|不足| PRE
SE -->|够| OUT["evidence"]
SE -->|检索质量差| CRAG["CRAG SearXNG 兜底"]
CRAG --> OUT
任一路 fan-out 失败不阻塞其余路(容错降级);TEI rerank 超时回退 RRF top-5(finding-017)。
- KB Ingestion — 离线 job,文档(Docling 主路;MinerU/VLM 表格兜底为 descope 项未实现)→ bge-m3 → Qdrant + Tantivy + Postgres
- RAG + Agent Backend — 在线服务(本图主体)
- LLM Gateway — 自研 Ports & Adapters(不用 LiteLLM),内嵌在 ②;DB 角色映射热重载 + FallbackChain
- Evaluation & Feedback — 评测闭环(75 例 gold-set + AgentEvaluator + LLM-judge + CI gate)
- Web Client — Next.js(对话展厅 + 检索透明化 Inspector + 在线 KB/模型/预算管理)
跨三端(后端 / web / iOS)的统一身份与权限层,在不破坏游客匿名访问的前提下叠加可选登录与业主权限分级。
- 认证:
POST /v1/auth/register|login签发 HS256 JWT(claimsub/username/role),GET /v1/auth/me凭 token 回取身份。口令经 bcrypt(72 字节截断,不存明文、不入日志);login失败统一 401 防用户名枚举;register在单事务内count + insert—— 首位注册用户即 admin。 - 用户表:
users(id = u_acct_<hex>/usernameunique /password_hash/role/created_at)。 - 统一身份(关键设计):
effective_owner_id(agent 路径):有效 JWT →owner_id = claim.sub;否则回退X-Owner-Id请求头;游客返回空串""(游客零回归)。require_owner_id(profile / conversations 路径):缺身份时返回 422。- 即「登录用户用稳定
u_acct_<hex>、游客用 device id」做 data-scoping,登录态与匿名态走同一套下游逻辑。
- RBAC:
require_admin= Bearer admin JWT 优先 +X-Admin-Token后备(保留旧接入方式)。前端按角色隐藏管理入口:web{isAdmin && ...}(6 个管理入口),iOSif auth.isAdmin(管理段)。 - token 存储:web 存
localStorage(只持久化 token,user靠/mehydrate,密码不入 state);iOS 存 Keychain(serviceraguide.auth)。 - 配置 / 依赖:
config新增jwt_secret(envJWT_SECRET)+jwt_expire_days;新依赖pyjwt+bcrypt。JWT_SECRET留空时 register/login 返回 503AUTH_DISABLED,游客功能不受影响(运维细节见 runbook)。 - Langfuse 身份分离:trace
user_id=acct:<username>/guest:<device>(人读视角),与 data-scoping 用的owner_id(稳定u_acct_<hex>/ device id)分离;session_id按会话。
done_hook 把低分候选挖入池时一并存 signals(intent_type / 抽取槽位 / 工具);admin approve 时读 signals 富化 gold-set expected_slots(category / intent_type / preferences / mentioned_products / budget,空值丢弃)+ 富 notes 后,写入 human_verified gold-set。expected_safety 不捏造;pre-fix 阶段 signals = NULL 的存量候选降级为空槽。对应 L0 写入门禁(Action-Verified Only)。
- 全 LLM 输出强制
json_schema/ function calling,严禁正则解析自由文本 - Trace span 必含 9 字段(step / input / output / model / tool_name / tokens_in / tokens_out / latency_ms / error / status)
- 评估 5 维度加权(task_completion 30% + output_quality 30% + process_quality 20% + efficiency 10% + safety 10%)
- 测试集 5 类别覆盖(happy / edge / error / adversarial 必含 prompt injection / regression)
- System prompt 6 要素框架(身份 / 能力 / 工作流程 / 输出格式 / 质量标准 / 安全红线)
- 工具 metadata 含
trigger_conditions+exclusion_conditions - Distributed Prompt Storage:Orchestrator 极简(纯状态节点,无 prompt);领域 SOP 落
docs/sops/*.md,Advisor 用read_sop(name)按需加载 - 凭据只走
.env,永不硬编码、永不进 git
| Q | A(一句话) |
|---|---|
| 为什么 LangGraph 不 LangChain | graph-native,状态机 + 条件边 + checkpoint 能讲清编排 |
| 为什么 Qdrant 不 Pinecone | 成本可控 + 自托管可演示 + 数据主权 |
| 为什么 bge-m3 不 OpenAI Embedding | 数据主权 + 成本 + 稠密/稀疏/ColBERT 三合一 |
| 为什么 Intent 默认用 Haiku 角色 | 结构化抽取任务 + 低延迟 + 便宜(provider 可经面板换) |
| 为什么 Agent 不 RAG-only | 工具调用让「5000 以内电池 5000+」这类结构化查询走 SQL(双列存储) |
| 为什么自研 LLM 抽象不 LiteLLM | Ports & Adapters 可讲;Protocol + Template Method + Registry + Chain of Responsibility 四模式协同 |
| 为什么评测规则 + LLM-judge 混合 | 确定性维度(efficiency/process/task/safety)规则打分稳定可复现,主观维度(output_quality)交 judge |
Langfuse 3 自托管(9 字段 span)+ 自研 AgentEvaluator 5 维度加权 + 75 例 gold-set(5 类别)+ LLM-as-Judge + 双门禁 CI gate(no-regression 0.03 + safety floor 0.5)+ Grafana 5 看板 32 panel + Prometheus 9 条告警规则 + Alertmanager → 后端 webhook。Ragas 4 指标已接线但 DEFERRED(ragas 0.2.x 与 langgraph 1.2.x 争 langchain-core,本环境未产出数据)。当前 baseline weighted 0.838(v3)。映射到 17 项 DoD —— 逐项验收见 dod-verification.md。