Files
meida/docs/技术架构文档.md
T
2026-08-13 23:10:49 +08:00

65 KiB
Raw Blame History

「美搭」技术架构文档

版本:v1.0 | 更新日期:2026-08-13 | 状态:待技术评审

本文的定位:把产品需求翻译成可直接拆解为开发任务的技术方案。读完这份文档,应该能回答三个问题——系统由哪些部分组成、数据长什么样、每条关键链路怎么跑通。

前置阅读:《技术选型与调研报告》(所有选型结论与理由,本文只引用编号 TD-xx,不重复论证) 配套阅读:《需求规格说明》(需求编号 FR-xx/NFR-xx)、《合规与安全方案》、《开发任务拆解》


1. 架构目标与约束

1.1 这个系统真正难的地方

在动手设计之前先明确难点,否则很容易把它当成一个「CRUD + 调几个 AI 接口」的普通应用,那会在三个月后付出代价:

  1. 它是一个「长耗时任务为主」的系统,不是请求-响应系统。报告生成、换装出图都在数十秒量级。这意味着任务中心、状态机、幂等、进度反馈、失败退款、断线恢复不是附加功能,而是主干链路。
  2. AI 输出必须被约束,而不是被信任。报告结论与搭配建议要可解释、可审计、不能违反禁忌规则。因此架构上必须有「检索 → 规则约束 → 生成 → 生成后校验」的闭环,而不是把用户问题直接丢给大模型。
  3. 它处理的是敏感个人信息(人脸),且产出的全部是 AI 生成内容。合规不是上线前补的文档,而是架构约束:原图不落盘、生成物统一打标识、输入输出双向审核。
  4. 成本随活跃度线性增长。GPU 出图与大模型调用都是按量付费。如果没有从第一天就把成本埋进链路并可归因到功能和用户,用户量上来后无法优化,只能凭感觉砍功能。
  5. 知识库是持续演进的资产,它的更新频率远高于代码。所以规则、色板、单品必须是数据而不是代码,且有配套的运营入口与回归测试。

1.2 质量属性优先级

按项目当前阶段(V1 单端、效果优先、团队 4~6 人)排序:

优先级 质量属性 具体要求
1 正确性与可解释性 建议不违反硬性禁忌;每条结论可追溯到规则或知识条目
2 合规性 人脸处理、AI 标识、内容审核、备案登记均满足现行要求
3 可演进性 域边界清晰,V2 拆服务/换模型/多端时不需要重写
4 可观测性 业务漏斗、AI 成本、任务健康三张看板齐备
5 性能 见 NFR 指标;报告与出图允许秒级到分钟级,但等待体验必须做好
6 极致成本优化 V1 只要求「可归因、可预警」,不要求「最省」

1.3 架构约束(不可协商)

约束 来源
客户端为鸿蒙原生 ArkTS,服务端保持端无关 TD-01
服务端全 Python(FastAPI) 项目决策
基础设施以腾讯云为主,服务器部署在中国大陆 项目决策 + TD-15 手机号获取要求
人脸原图不进入持久化存储 TD-20
所有对外生成物必须经过统一合规出口 TD-21
V1 不接入任何支付能力,配额为唯一成本控制手段 TD-28
V2 起虚拟商品支付必须走华为 IAP TD-16
V1 不上微服务、不上 K8s、不上专用向量库与图数据库 TD-08/TD-09,团队规模

2. 系统上下文

                                  ┌──────────────────────┐
                                  │   鸿蒙客户端 (ArkTS)  │
                                  └──────────┬───────────┘
                                             │ HTTPS / SSE
                                             ▼
┌──────────────────────────────────────────────────────────────────────────┐
│                        美搭服务端 (Python / 腾讯云)                        │
│                                                                          │
│   API 层 ──▶ 业务域模块 ──▶ AI 能力层 ──▶ 数据层                          │
│                    │                                                     │
│                    └──▶ 任务队列 ──▶ Worker                              │
└───┬──────────┬──────────┬──────────┬──────────┬──────────┬───────────────┘
    │          │          │          │          │          │
    ▼          ▼          ▼          ▼          ▼          ▼
┌────────┐┌────────┐┌────────┐┌────────┐┌────────┐┌──────────────┐
│华为服务 ││大模型   ││腾讯云AI ││自有换装 ││腾讯云   ││腾讯云基础设施 │
│账号/推送││DeepSeek││人脸识别 ││发型服务 ││天御审核 ││COS/CDN/PG/  │
│Push    ││智谱GLM ││        ││(GPU)   ││        ││Redis/CLS     │
└────────┘└────────┘└────────┘└────────┘└────────┘└──────────────┘

外部依赖及其失效影响(每一个都要有降级方案,见 §13.4):

外部系统 用途 失效影响 降级策略
华为 Account Kit 登录 新用户无法注册 游客模式可继续体验非付费功能
华为 IAP 支付(V2 起) 无法购买 提示稍后再试,不影响已有权益。V1 不依赖此项
华为 Push Kit 任务完成通知 通知不到 应用内任务中心轮询兜底
DeepSeek / GLM 文案生成、对话 报告与对话不可用 双供应商自动切换;均失败时报告排队重试,对话返回兜底话术
腾讯云人脸识别 面部分析 报告无法生成面部维度 报告降级为「体型+色彩」子集,标注待补全
自有换装服务 出图 换装不可用 任务转排队,不扣配额,超时退还
腾讯云天御 内容审核 不可降级 审核失败一律按「拦截」处理(fail-close),宁可少发不可漏审

3. 总体架构

3.1 分层视图

┌───────────────────────────────────────────────────────────────────────┐
│ L1 客户端层                                                            │
│  鸿蒙 ArkTS:页面 / 状态管理 / 端侧缓存 / 图片压缩 / SSE流式渲染          │
└───────────────────────────────────────────────────────────────────────┘
                                  ▼
┌───────────────────────────────────────────────────────────────────────┐
│ L2 接入层                                                              │
│  CLB + Nginx:TLS / 限流 / 防刷 / 请求日志 / 静态与图片走 CDN            │
└───────────────────────────────────────────────────────────────────────┘
                                  ▼
┌───────────────────────────────────────────────────────────────────────┐
│ L3 API 层(FastAPI,面向端的编排层)                                     │
│  认证鉴权 · 参数校验 · 幂等 · 配额校验与预扣 · 统一响应 · OpenAPI          │
└───────────────────────────────────────────────────────────────────────┘
                                  ▼
┌───────────────────────────────────────────────────────────────────────┐
│ L4 业务域层(模块化单体:包内隔离,禁止跨域直接访问对方数据表)             │
│ ┌────────┬────────┬────────┬────────┬────────┬────────┬────────┐      │
│ │identity│profile │ report │ agent  │ tryon  │   kb   │billing │      │
│ │账号会话│画像记忆│美学报告│对话Agent│换装发型│ 知识库 │配额计量│      │
│ ├────────┼────────┼────────┼────────┼────────┴────────┴────────┤      │
│ │  task  │wardrobe│compliance│ notify │                        │      │
│ │任务中心│ 衣橱V2 │合规出口 │ 通知   │                        │      │
│ └────────┴────────┴─────────┴────────┴────────────────────────┘      │
└───────────────────────────────────────────────────────────────────────┘
                                  ▼
┌───────────────────────────────────────────────────────────────────────┐
│ L5 AI 能力层(可独立部署与扩容,对上以内部 API 暴露)                     │
│ ┌──────────────┬──────────────┬──────────────┬──────────────┐        │
│ │ llm-gateway  │  vision-svc  │retrieval-svc │ rules-engine │        │
│ │多模型路由    │分割/关键点/  │混合检索+重排 │决策表求值+   │        │
│ │Prompt版本    │色值采样/体型 │              │可解释路径    │        │
│ ├──────────────┼──────────────┼──────────────┴──────────────┤        │
│ │ matting-svc  │  tryon-svc   │                             │        │
│ │批量抠图      │换装/发型(GPU)│                             │        │
│ └──────────────┴──────────────┴─────────────────────────────┘        │
└───────────────────────────────────────────────────────────────────────┘
                                  ▼
┌───────────────────────────────────────────────────────────────────────┐
│ L6 数据层                                                              │
│  PostgreSQL + pgvector(业务/知识库/向量/事件)· Redis(缓存/队列/限流) │
│  COS 四桶(临时/用户内容/知识素材/报告产物)· CLS(日志与审计)           │
└───────────────────────────────────────────────────────────────────────┘

                      ┌──────────────────────────────┐
       横向贯穿:      │ Celery Workers(gpu/cpu/io/beat)│
                      │ 可观测性(OTel/Prom/Grafana)    │
                      │ 配置与密钥(SSM/KMS)            │
                      └──────────────────────────────┘

3.2 为什么是「模块化单体 + 独立 AI 服务」

这是本架构最关键的一个取舍,理由:

业务域做单体:identity/profile/report/agent/billing 之间事务关联紧密(一次报告生成要扣配额、写画像、写记忆、记成本)。拆成微服务后这些操作就需要分布式事务或最终一致性补偿,对 4~6 人团队是净损失。单进程内一个数据库事务就解决了。

AI 能力做独立服务:它们的资源画像与业务代码完全不同——GPU 依赖、模型文件体积、推理并发模型、扩缩容节奏都不一样。混在一个进程里会导致「换装排队把 API 拖慢」。独立部署后可以单独限流、单独扩容、单独重启。

但单体不等于混乱。硬性规则:

  1. 每个域是一个 Python 包,只能通过对方暴露的 service 接口调用,禁止直接查对方的表。
  2. 领域逻辑放在 packages/domain,不依赖 FastAPI、不依赖数据库会话,可纯单元测试。
  3. 跨域的写操作通过域内事件(进程内事件总线 + 持久化 outbox)解耦,例如「报告完成」事件被 profile(写画像)、memory(写记忆)、notify(推送)、billing(结算成本)分别消费。
  4. 数据库虽是单库,但表按域前缀命名,为将来拆库预留边界。

演进触发条件:当某个域的写入 QPS 或数据量成为瓶颈,或需要独立发布节奏时,按 §19 的路径拆出。不要提前拆。


4. 模块职责与依赖

4.1 业务域模块清单

模块 职责 关键对外能力 不负责
identity 账号、登录、会话、设备、游客迁移、同意授权记录 login() get_current_user() merge_guest() record_consent() 权益判定(归 billing)
profile 用户画像(诊断结论)+ 分层记忆系统 get_profile() get_memory_snapshot() write_memory() resolve_conflict() 报告生成流程
report 报告触发判定、生成编排、版本管理、分享 can_trigger() create_report() get_report() create_share() 具体的视觉分析与文案生成(调 AI 层)
agent 会话管理、意图识别、上下文组装、生成编排 chat_stream() extract_preference() 知识检索实现(调 retrieval)
tryon 换装/发型的业务编排、素材校验、结果管理 create_tryon_task() get_result() GPU 推理(调 tryon-svc)
kb 知识实体/关系/规则/素材的读写与发布 query_entities() get_rules() publish() 检索算法(调 retrieval)
billing V1:配额账本、流水、周期重置、任务奖励发放。V2 增:会员、订单、IAP 校验 check_quota() reserve() commit() refund() grant() 定价策略配置(配置化);V1 无支付相关职责
task 统一任务中心:创建、状态机、进度、查询、取消 submit() get_status() list_user_tasks() 具体任务实现(Worker)
compliance 统一合规出口:审核、水印、元数据标识、内容编号登记、审计 moderate() publish_asset() register_content() 业务判断
notify 推送、应用内消息、Token 管理 push() notify_task_done() —
wardrobe 我的衣橱(V2) — —

4.2 依赖规则

identity ← 所有模块(读当前用户)
billing  ← report / tryon / agent(消耗资源前预扣)
task     ← report / tryon(长耗时任务统一走它)
compliance ← report / tryon / agent / kb(所有产物出口)
profile  ← report(写入)/ agent(读取+写入)
kb       ← agent / report(读取)

禁止的依赖:compliance 不得反向依赖任何业务域(它必须能被任何模块安全调用);identity 不得依赖其他业务域(避免登录链路被业务拖累)。

4.3 AI 能力层服务

服务 形态 内容 资源
llm-gateway 进程内包(V1)→ 独立服务(V2) 多供应商路由、Prompt 版本、结构化输出约束、流式、缓存前缀优化、成本计量、限流降级 IO 密集
vision-svc 独立服务 人像分割(云)、人体关键点(ONNX 自建)、色值采样、体型测算、人脸属性与关键点(云) CPU(含 ONNX)
retrieval-svc 进程内包 混合检索:硬过滤 → 规则命中 → 向量召回 → BM25 → 重排 → 解释路径 CPU + PG
rules-engine 进程内包 决策表求值、硬约束校验、命中链输出 CPU
matting-svc 离线批处理 BiRefNet 抠图 + 白底标准化 + 规格校验 GPU(按需)
tryon-svc 独立服务(现有服务改造) 换装三工作流、发型更换/发色 GPU(常驻或按需)

llm-gateway 为何 V1 先做进程内包:它没有独立的资源诉求(纯 IO),拆成服务只增加一跳网络。但它的接口必须按远程调用来设计(无共享内存假设、明确超时、可序列化的入参出参),这样 V2 拆出去时零成本。

4.4 现有换装服务的改造要求

既然服务自有可控(TD-00 前提),必须做以下改造,否则它会成为整个系统的不稳定源:

改造项 现状问题 要求
鉴权 可能是开放接口 改为内部服务,仅允许内网/网关调用,带服务间令牌
调用模式 同步长连接 改为提交任务 + 回调通知(或提供任务查询接口),避免长连接占用
幂等 无 接受 idempotency_key,重复提交返回同一结果
并发控制 无 明确最大并发数并对外暴露,让上游队列按容量限流
成本埋点 无 每次推理返回 gpu_seconds 与模型版本,供成本归因
结果存储 直传阿里云 OSS 改为写入腾讯云 COS(统一存储与生命周期治理);历史数据做迁移或双读
输入校验 未知 前置校验图片规格、人脸存在性、单品白底图规格,尽早失败
版本管理 未知 模型/工作流版本号随结果返回,便于回溯效果变化

5. 技术栈总览

层次 选型 决策依据
客户端 HarmonyOS ArkTS + ArkUI TD-01
端侧能力 Account Kit / Push Kit(V1);IAP Kit / Core Speech Kit(V2) TD-15~TD-17、TD-14、TD-28
接入 腾讯云 CLB + Nginx + CDN TD-03
服务端 Python 3.12 + FastAPI + Uvicorn/Gunicorn TD-02
ORM/迁移 SQLAlchemy 2.0 (async) + Alembic TD-02
校验 Pydantic v2(同时用于 LLM 结构化输出约束) TD-02
任务 Celery + Redis(gpu/cpu/io/beat 四队列) TD-11
数据库 PostgreSQL 16 + pgvector TD-08
缓存 Redis 7 —
存储 腾讯云 COS(4 桶)+ CDN TD-03
大模型 DeepSeek(主)+ 智谱 GLM(备/视觉) TD-04
Embedding BGE-M3(自建 ONNX) TD-22
视觉 腾讯云人脸识别 + RTMPose(ONNX) + BiRefNet TD-05~TD-07
审核 腾讯云天御 IMS/TMS TD-13
渲染 Playwright + Chromium(服务端长图/PDF) TD-12
可观测 OpenTelemetry + Prometheus + Grafana + CLS TD-24
部署 Docker + Docker Compose(V1)→ TKE(V2) TD-03
CI/CD GitHub Actions 或腾讯云 CODING;ruff + mypy + pytest 卡关 TD-02

6. 数据模型

6.1 设计原则

  1. 单库多域,表名以域前缀区分(id_/pf_/rp_/kb_/ag_/tr_/bl_/tk_/cp_)。
  2. 主键统一用雪花 ID(bigint),不用自增(避免枚举攻击与将来分库冲突),不用 UUID 作主键(索引局部性差)。对外暴露的 ID 做混淆编码。
  3. 不存人脸原图,不存可反推生物特征的数据。诊断结果只存分类标签与色值等派生量(TD-20)。
  4. 所有涉及配额/金额的表都有幂等键与流水,任何余额变更必须有对应流水记录,余额可由流水重算校验。V1 虽不涉及金钱,此原则同等适用 —— 用户对"次数被白扣"的敏感度不比扣钱低。
  5. 软删除 + 硬删除双轨:常规软删除;账号注销走硬删除任务(合规要求,见《合规与安全方案》)。
  6. JSONB 用于「结构会演进但不需要索引全部字段」的场景(诊断结论、规则条件、检索轨迹);需要过滤的字段一律提升为列。

6.2 核心表清单

identity 域

表 关键字段 说明
id_user user_id PK, status, nickname, avatar_key, register_source, created_at, last_active_at, deleted_at 内部主键,与外部身份解耦
id_user_identity user_id, provider('huawei'), union_id, open_id, UNIQUE(provider,union_id) 一个用户可有多个外部身份
id_guest guest_id, device_fp, merged_to_user_id, created_at 游客数据,登录后合并
id_device device_id, user_id, push_token, os_version, last_seen_at 推送 Token 管理
id_consent consent_id, user_id, consent_type('terms'/'privacy'/'face'/'minor'), doc_version, granted_at, revoked_at, client_ip, ua 合规留证:人脸的单独同意必须独立成行
id_session session_id, user_id, refresh_token_hash, expire_at, revoked 刷新令牌服务端可撤销

profile 域(画像与记忆)

表 关键字段 说明
pf_profile profile_id, user_id, label, is_default 预留多档案(帮家人诊断的场景),V1 只创建默认档案
pf_diagnosis diagnosis_id, profile_id, source_report_id, dimensions JSONB, version, overall_confidence, created_at 34 个诊断维度的结构化结论;按版本追加,不覆盖
pf_memory memory_id, user_id, layer(L0~L5), mem_key, mem_value JSONB, confidence numeric, status('active'/'pending_confirm'/'archived'/'rejected'), source('explicit'/'implicit'/'report'/'behavior'), evidence_ref, valid_from, last_reinforced_at, decay_after, created_at 记忆项主表;索引 (user_id,layer,status)
pf_memory_event event_id, memory_id, action('create'/'reinforce'/'decay'/'conflict'/'user_edit'/'delete'), detail JSONB, created_at 记忆变更审计,支撑「我的记忆」页面的可解释性
pf_memory_snapshot user_id, snapshot JSONB, token_count, content_hash, built_at, expire_at 注入 LLM 的画像摘要缓存,避免每轮重算

report 域

表 关键字段 说明
rp_report report_id, user_id, profile_id, tier('basic'/'full'), status, version, result JSONB, model_info JSONB, content_code, rendered_asset_key, cost_cents, created_at, completed_at content_code 为 AI 标识内容编号(TD-21)
rp_input input_id, report_id, questionnaire JSONB, photo_meta JSONB, derived_features JSONB 只存派生特征与图片元信息,不存原图
rp_share share_id, report_id, share_token, expire_at, view_count, revoked 分享链接可失效、可撤回

kb 域(知识库)

表 关键字段 说明
kb_entity entity_id, entity_type(12 类), name, attrs JSONB, status('draft'/'reviewing'/'published'/'archived'), version, source, license, updated_by 12 类实体统一表 + attrs 差异化
kb_relation from_id, rel_type, to_id, weight, confidence, evidence 邻接表,递归 CTE 做多跳(TD-09)
kb_rule rule_id, version, status, priority, conditions JSONB, effects JSONB, is_hard, evidence, author, reviewer, published_at 决策表(TD-10)
kb_chunk chunk_id, entity_id, chunk_type, text, embedding vector(1024), embedding_model, embedding_version, tsv tsvector 向量 + 全文双索引,支撑混合检索
kb_asset asset_id, entity_id, asset_type, cos_key, spec_check JSONB, tryon_ready bool, review_status, license tryon_ready 是换装闭环的关键标志位
kb_color color_id, season_code, role('base'/'accent'/'avoid'), lab_l,lab_a,lab_b, hex, name_cn 自建色板(TD-18)
kb_gap gap_id, query_text, filter_ctx JSONB, hit_count, first_seen_at 知识缺口埋点:无检索结果的查询,驱动内容生产

agent 域

表 关键字段 说明
ag_conversation conv_id, user_id, title, rolling_summary, status, msg_count, created_at 长会话滚动摘要存这里(L4 记忆)
ag_message msg_id, conv_id, role, content, intent, retrieval_trace JSONB, rule_hits JSONB, model, tokens_in/out/cached, cost_cents, moderation JSONB, created_at retrieval_trace + rule_hits 让每个回答可复盘
ag_feedback feedback_id, msg_id, rating, reason, created_at 驱动隐式偏好推断与质量评估

tryon 域

表 关键字段 说明
tr_task task_id, user_id, workflow_type, input_refs JSONB, result_asset_key, gpu_seconds, model_version, content_code, cost_cents 与统一任务中心 tk_task 一对一关联
tr_favorite fav_id, user_id, asset_key, tags, created_at 用户收藏的效果图

task 域(统一任务中心)

表 关键字段 说明
tk_task task_id, user_id, task_type('report'/'tryon'/'hairstyle'/'matting'/'render'), status, progress, stage_text, idempotency_key UNIQUE, payload JSONB, error_code, retry_count, points_reserved, submitted_at, started_at, finished_at, eta_seconds 全系统唯一的长耗时任务视图,前端任务中心直接读它

billing 域(V1 为配额与计量,无支付)

V1 不接支付(TD-28)。本域在 V1 的职责是配额限制与计量。关键设计:表结构一次做到位,V2 上支付时不需要迁移。

表 关键字段 V1 说明
bl_wallet user_id PK, balance, version(乐观锁) ✅ V1 存「可用额度」,V2 语义扩展为点数余额。同一张表,不改结构
bl_ledger tx_id, user_id, delta, tx_type, reason, ref_type, ref_id, balance_after, idempotency_key UNIQUE, created_at ✅ 流水是真相,余额是缓存。tx_type V1 只用 system_grant/consume/refund,V2 增加 purchase/gift —— 这是 V1→V2 免迁移的关键
bl_quota user_id, quota_key, period_key, used, limit_value ✅ 周期配额计量(日/月/终身),按 period_key 自然重置,无需定时任务清零
bl_quota_rule quota_key, period_type, base_limit, task_bonus_max, hard_cap ✅ 配额规则配置化(FR-BILL-04),改配置不发版
bl_membership user_id, level, valid_from, valid_to, source_order_id, auto_renew ❌ V2 会员
bl_order order_id, user_id, product_id, product_type, price_cents, platform('huawei_iap'), purchase_token UNIQUE, status, verified_at, raw_receipt JSONB ❌ V2 purchase_token 唯一约束防重复发货(TD-16)

原 bl_point_tx 改名为 bl_ledger:V1 阶段它记录的是配额流水而非点数流水,用 point 命名会在 V1 造成误解。改用中性名称,同时新增 tx_type 字段承载两个阶段的语义差异。

compliance 域

表 关键字段 说明
cp_content_registry content_code PK(27 位), content_type, ref_type, ref_id, provider_code, model_info JSONB, generated_at AI 生成内容编号登记(TD-21)
cp_moderation_log log_id, target_type, target_id, provider, suggestion, labels JSONB, action, created_at 审核留证
cp_audit_log audit_id, actor_type, actor_id, action, target, before JSONB, after JSONB, ip, created_at 后台操作审计,知识库改动必须留痕
cp_data_request request_id, user_id, type('export'/'delete'), status, completed_at 个人信息导出/删除请求(法定权利)

观测与成本

表 关键字段 说明
ob_ai_call call_id, user_id, scene, provider, model, tokens_in/out/cached, latency_ms, cost_cents, success, error_code, ref_type, ref_id, created_at 成本归因的唯一数据源,按月分区
ob_event event_id, user_id, event_name, props JSONB, client_ts, server_ts 埋点事件,按月分区(TD-23)

6.3 诊断维度的存储形态

34 个诊断维度用 pf_diagnosis.dimensions JSONB 存储,但每个维度都是结构化三元组,不是自由文本:

{
  "color_season": {
    "value": "浅暖柔和型",
    "confidence": 0.82,
    "evidence": ["skin_lab:[68.2,12.4,18.7]", "hair_lab:[24.1,6.2,9.8]", "contrast:low"],
    "source": "vision+rule",
    "rule_hits": ["R-COLOR-0021", "R-COLOR-0034"]
  },
  "body_shape": {
    "value": "X型",
    "confidence": 0.76,
    "evidence": ["shoulder_hip_ratio:1.02", "waist_hip_ratio:0.71"],
    "source": "vision+rule",
    "rule_hits": ["R-BODY-0007"]
  }
}

为什么必须带 confidence 和 evidence:低置信度维度要在报告中降级表述(「你的体型偏向 X 型」而不是断言),并且要能在用户质疑时说明依据。这也是记忆系统冲突消解的输入——用户显式反馈会覆盖低置信度的机器推断。


7. 关键链路设计

7.1 美学报告生成(最复杂的链路)

客户端                    API              task/Worker           AI 能力层
  │                        │                    │                    │
  │ 1.POST /reports        │                    │                    │
  │   (idempotency_key)    │                    │                    │
  ├───────────────────────▶│                    │                    │
  │                        │ 2.触发资格校验      │                    │
  │                        │  (已有报告?配额?)   │                    │
  │                        │ 3.配额预扣(reserve) │                    │
  │                        │ 4.创建 tk_task     │                    │
  │◀── task_id ────────────┤                    │                    │
  │                        │ 5.入队(cpu队列)     │                    │
  │                        ├───────────────────▶│                    │
  │ 6.订阅进度(轮询/Push)   │                    │ 7.拉取临时区原图     │
  │                        │                    ├───────────────────▶│
  │                        │                    │ 8.内容审核(图片)     │
  │                        │                    │ 9.人像分割           │
  │                        │                    │ 10.人体关键点(ONNX) │
  │                        │                    │ 11.人脸关键点+属性   │
  │                        │                    │ 12.色值采样(Lab)     │
  │                        │                    │ 13.体型/季型/脸型测算│
  │                        │                    │◀── 结构化诊断 ──────┤
  │                        │                    │ 14.**立即删除原图**  │
  │                        │                    │ 15.规则引擎求值      │
  │                        │                    │   (建议/禁忌/依据)   │
  │                        │                    │ 16.知识库检索        │
  │                        │                    │   (配色/单品/发型)   │
  │                        │                    │ 17.LLM 生成文案      │
  │                        │                    │   (结构化输出约束)   │
  │                        │                    │ 18.生成后校验        │
  │                        │                    │   (禁忌违反=0?色值在板内?)│
  │                        │                    │ 19.文本审核          │
  │                        │                    │ 20.渲染长图(Playwright)│
  │                        │                    │ 21.合规出口:         │
  │                        │                    │   水印+元数据+编号登记│
  │                        │                    │ 22.写画像/记忆/成本   │
  │                        │                    │ 23.配额 commit      │
  │                        │                    │ 24.Push 通知        │
  │◀──── 报告就绪 ─────────┴────────────────────┤                    │

关键工程要求:

要求 做法
原图生命周期 上传直传 COS 临时桶(预签名 URL,不经过应用服务器);Worker 拉取后处理,第 14 步显式删除;桶级 2 小时生命周期作为兜底
失败即退款 任何步骤失败,tk_task 转 failed 并触发 refund();用户看到明确原因与「重试」入口
分步可恢复 第 7~13 步的视觉分析结果落库为中间态,LLM 或渲染失败时不需要重跑视觉分析(也就不需要用户重新上传)
生成后校验不可跳过 校验失败最多重试 2 次(提高约束强度),仍失败则降级为「规则直出模板文案」,绝不放行违规内容
等待体验 阶段文案随进度更新;预估时间基于历史 p50;超过阈值转为「后台生成 + 完成推送」,允许用户离开页面
幂等 相同 idempotency_key 重复提交返回同一 task_id,不重复扣点

7.2 Agent 对话(含检索与画像注入)

用户提问
   │
   ▼
① 输入审核(TMS + 备案关键词库)───拦截──▶ 返回安全提示,记录日志
   │ 通过
   ▼
② 意图识别(轻量模型 / 规则前置)
   ├─ 场景咨询 / 单品搭配 / 风格建议 / 闲聊 / 越界(医疗、身材评判等)
   ▼
③ 上下文组装(token 预算严格分配)
   ├─ 系统提示词(固定前缀,放最前以命中缓存)
   ├─ 画像摘要(L0/L1/L2,来自 pf_memory_snapshot)
   ├─ 会话滚动摘要(L4)
   └─ 检索结果(见 ④)
   ▼
④ 混合检索(retrieval-svc)
   ├─ a. 硬过滤:SQL WHERE(季型/体型禁忌/场合/季节)
   ├─ b. 规则命中:rules-engine 求值,取建议与禁忌
   ├─ c. 向量召回:pgvector 相似度 Top-K
   ├─ d. 关键词召回:tsvector BM25
   ├─ e. 融合重排:RRF + 规则权重 + 新鲜度
   └─ f. 输出:知识片段 + 命中规则 ID + 图谱路径(供解释链)
   ▼
⑤ LLM 生成(llm-gateway,流式 SSE)
   └─ 约束:只能使用检索到的知识;硬禁忌不得出现;输出结构化搭配卡片
   ▼
⑥ 生成后校验:禁忌违反检查 + 色值在色板内检查
   ▼
⑦ 输出审核(TMS)───拦截──▶ 重新生成或返回兜底
   ▼
⑧ 落库:message + retrieval_trace + rule_hits + 成本
   ▼
⑨ 异步:偏好抽取 → 写入 L2 记忆(显式)/ 生成待确认候选(隐式)

Token 预算分配(必须硬性限制,否则成本会失控):

部分 预算 说明
系统提示词 ≤ 800 固定不变,放在最前以最大化缓存命中
画像摘要 ≤ 500 从记忆快照裁剪,按置信度与相关性排序
会话摘要 ≤ 400 滚动压缩
检索知识 ≤ 1500 重排后取前 N 条,超出则截断而非全塞
用户当前输入 ≤ 500 超长提示精简
输入合计 ≤ 3700
输出 ≤ 800 超长回答不利于阅读,也贵

缓存前缀纪律:系统提示词与稳定知识片段必须放在 prompt 头部且不含时间戳、随机 ID、用户昵称等变量,否则缓存永远不命中,输入成本翻数倍(TD-04)。

7.3 换装任务

① 前置校验:单品是否 tryon_ready?用户照片是否合规且质量达标?
② 配额:check_quota → reserve
③ 创建 tk_task(type=tryon) → 入 gpu 队列
④ Worker:调 tryon-svc(带 idempotency_key),拿到 gpu_seconds
⑤ 结果图审核(IMS)
⑥ 合规出口:水印「AI 生成」+ 写入元数据与内容编号 → 存 COS 用户内容桶
⑦ commit 配额、记录成本、Push 通知
⑧ 失败:区分可重试(网络/排队超时)与不可重试(输入非法/审核拒绝),后者立即退点

队列即容量:gpu 队列的并发上限直接由 GPU 容量决定,并把「当前排队位次 + 预估等待」返回给用户。不要让请求无限积压——超过阈值直接拒绝新任务并提示稍后再试,这比让用户等 10 分钟体验更好。

7.4 配额消耗(V1)与 IAP 支付(V2)

V1:配额三段式

校验:GET 配额 → 判定 bl_quota.used < limit_value + task_bonus
        ↓ (服务端硬校验,客户端提示仅为体验,FR-BILL-06)
预扣:reserve  → bl_ledger 写 delta=-N, tx_type=consume, status=reserved
        ↓
任务执行(Celery,长耗时)
        ↓
成功:commit  → 确认扣除,status=committed
失败:refund  → 写反向流水 delta=+N, tx_type=refund(带 idempotency_key)

发放:任务奖励 → bl_ledger 写 delta=+N, tx_type=system_grant
        ↓ (同一任务同一周期幂等,FR-BILL-03)

为什么预扣而不是直接扣:长耗时任务可能失败,直接扣会产生「扣了额度没拿到结果」的客诉。先冻结再确认,失败自动释放。V1 虽然不涉及金钱,这个问题依然存在 —— 用户对"次数被白扣"的敏感度不比扣钱低,而且 V1 没有客服退款兜底手段,只能靠机制保证。

对账:所有变更都写流水,余额可由流水重算校验(每日定时,不一致则告警)。V1 就要做,否则 V2 上支付时对账逻辑得从零开发且无历史数据验证。

V2:IAP 支付(V1 不实现)

购买:客户端 IAP 下单 → 支付成功拿 purchase_token
        ↓
     POST /orders/verify (purchase_token)
        ↓
     服务端调华为 IAP 校验接口(**必须服务端校验**,不可信客户端结果)
        ↓
     UNIQUE(purchase_token) 保证只发货一次
        ↓
     发放点数/会员 → 写 bl_ledger(tx_type=purchase,带 idempotency_key)

V1→V2 的衔接成本被刻意压到最低:消耗侧逻辑(reserve/commit/refund)完全复用,只需新增「购买」这一条发放路径。这是 §6.2 中坚持让 V1 与 V2 共用 bl_wallet / bl_ledger 的收益。

7.5 统一合规出口

所有对外生成物必须经过 compliance.publish_asset(),没有例外。

async def publish_asset(
    raw: bytes | str,
    content_type: Literal["image", "text", "pdf"],
    ref: ContentRef,
    model_info: ModelInfo,
) -> PublishedAsset:
    # 1. 内容审核(fail-close:审核服务不可用则拒绝发布)
    # 2. 生成 27 位内容编号并登记 cp_content_registry
    # 3. 显式标识:图片加可见「AI 生成」水印;文本加提示语
    # 4. 隐式标识:写入文件元数据(属性信息 + 服务提供者编码 + 内容编号)
    # 5. 上传目标 COS 桶,返回带签名的访问地址

必须专门测试的点:图片经过 CDN、缩略图处理、客户端保存与再次分享后,元数据是否仍然存在。很多图片处理链路会剥离 EXIF/XMP,一旦剥离就等于没做隐式标识(TD-21)。


8. AI 能力层设计

8.1 LLM 网关

class LLMGateway:
    async def complete(
        self,
        scene: Scene,                  # 场景决定模型档位、超时、预算
        messages: list[Message],
        schema: type[BaseModel] | None, # 需要结构化输出时传 Pydantic 模型
        stream: bool = False,
        user_id: int | None = None,
    ) -> Completion | AsyncIterator[Chunk]:
        ...

内置能力:

能力 实现要点
场景化路由 scene → (provider, model, temperature, max_tokens, timeout) 全部配置化,改模型不改代码
故障转移 主供应商超时/5xx/限流 → 自动切备用;连续失败触发熔断,冷却后半开探测
结构化输出 传入 Pydantic Schema,网关负责 JSON Schema 约束 + 解析失败重试 + 校验
Prompt 版本 Prompt 存文件(随代码版本化)+ 场景绑定版本号;A/B 时按用户哈希分流
成本计量 每次调用写 ob_ai_call,含缓存命中 token 数
预算保护 场景级日预算 + 用户级频控;超限降级到轻量模型或拒绝
审核联动 输入输出审核在网关内统一完成,业务方无需关心
可复现 记录 prompt 版本 + 模型版本 + 参数,便于回溯「为什么当时这么答」

8.2 视觉服务

POST /internal/vision/analyze
  ├─ segment_portrait  → 腾讯云 SegmentPortraitPic → 前景掩膜
  ├─ body_keypoints    → RTMPose ONNX → 关键点(肩/髋/踝定高)
  ├─ face_landmarks    → 腾讯云 AnalyzeFace(90点) / AnalyzeDenseLandmarks(888点,仅全面报告)
  ├─ face_attributes   → 腾讯云 DetectFaceAttributes(Skin/Hair/Shape/Eye/...)
  ├─ color_sampling    → 自研:按关键点定位采样区,转 Lab,稳健统计(去高光/阴影)
  └─ body_measure      → 自研:掩膜宽度剖面法(TD-06)
返回:结构化特征 + 每项置信度 + 质量问题标记(模糊/遮挡/多人/姿态异常)

质量门禁前置:图片质量不达标(多人、遮挡、侧脸过大、光线过暗)应在分析前就返回明确的重拍指引,而不是硬算出一个低置信度结果。用户宁愿重拍一次,也不愿收到一份错的报告。

8.3 混合检索的实现

核心是一条 SQL 完成硬过滤 + 向量召回(这正是选 pgvector 的收益):

WITH filtered AS (
  SELECT c.chunk_id, c.entity_id, c.text, c.embedding, e.attrs
  FROM kb_chunk c
  JOIN kb_entity e ON e.entity_id = c.entity_id
  WHERE e.status = 'published'
    AND e.entity_type = ANY(:entity_types)
    AND (:occasion IS NULL OR e.attrs->'occasions' ? :occasion)
    AND NOT (e.attrs->'avoid_body_shapes' ? :body_shape)   -- 硬禁忌直接排除
),
vec AS (
  SELECT chunk_id, 1 - (embedding <=> :query_vec) AS vec_score
  FROM filtered ORDER BY embedding <=> :query_vec LIMIT 50
),
kw AS (
  SELECT chunk_id, ts_rank(tsv, plainto_tsquery('simple', :query_text)) AS kw_score
  FROM kb_chunk WHERE tsv @@ plainto_tsquery('simple', :query_text) LIMIT 50
)
SELECT ... -- RRF 融合,再叠加规则权重与新鲜度

重排权重(可配置,需用黄金集调参):最终分 = 0.45×向量 + 0.2×关键词 + 0.25×规则权重 + 0.1×新鲜度。规则命中的条目要有明显加权——专业规则的可信度高于语义相似度,这是自建知识库的意义所在。

8.4 记忆系统的读写

读(注入):

get_memory_snapshot(user_id, budget_tokens)
  → 优先级排序:L0 身份 > L1 画像 > L2 显式偏好 > L5 衣橱 > L3 事件
  → 过滤:status='active' AND confidence >= 阈值
  → 裁剪到预算内 → 缓存(hash 变更才重建)

写:

显式(用户明确说的)  → confidence=0.95,立即生效,回执告知用户「已记住」
报告产出(机器诊断)  → confidence=诊断置信度,写 L1
行为推断(隐式)      → 累积证据,达阈值生成 status='pending_confirm'
                        → 在合适时机征询确认,确认后才转 active

衰减与冲突:定时任务按 decay_after 降低未被强化的记忆置信度;同 key 冲突时显式 > 报告 > 隐式,时间新 > 时间旧,并写 pf_memory_event 留痕。用户在「我的记忆」页面的编辑拥有最高优先级且不可被自动覆盖。


9. API 设计规范

9.1 基本约定

项 约定
基础路径 /api/v1,大版本进路径
风格 面向资源的 REST;流式对话用 SSE(text/event-stream)
认证 Authorization: Bearer <access_token>(JWT,15 分钟)+ 刷新令牌(服务端可撤销)
幂等 写操作支持 Idempotency-Key 头,服务端 24 小时内保证同键同结果
分页 游标分页(cursor + limit),不用 offset
时间 全部 ISO 8601 UTC,客户端负责本地化
文档 FastAPI 自动生成 OpenAPI,契约先行:先定 schema 再写实现

9.2 统一响应

{ "code": 0, "message": "ok", "data": { }, "request_id": "..." }
{ "code": 40301, "message": "今日额度已用完", "data": { "required": 1, "remaining": 0, "reset_at": "..." },
  "request_id": "...", "hint": "明天恢复,或完成任务多换 3 次" }

错误码分段:4xxxx 客户端错误、5xxxx 服务端错误、6xxxx 外部依赖错误(便于监控区分「我们的问题」和「厂商的问题」)。每个错误码都要有用户可读的 message 和可选的 hint(告诉用户怎么办)——AI 产品的失败场景多,错误文案是体验的一部分。

9.3 主要接口清单

域 方法与路径 说明
认证 POST /auth/huawei POST /auth/refresh POST /auth/guest POST /auth/merge 登录、刷新、游客、游客合并
用户 GET/PATCH /me POST /me/consents DELETE /me(注销) 含同意记录与注销
上传 POST /uploads/presign 返回 COS 临时桶预签名 URL,图片不经应用服务器
报告 POST /reports GET /reports/{id} GET /reports POST /reports/{id}/share POST /reports/{id}/regenerate
画像 GET /profile GET /profile/memories PATCH /profile/memories/{id} DELETE /profile/memories/{id} 「我的记忆」可见可控
Agent POST /agent/conversations POST /agent/conversations/{id}/messages(SSE) POST /agent/messages/{id}/feedback
换装 POST /tryon/tasks GET /tryon/tasks/{id} POST /tryon/results/{id}/favorite
发型 GET /hairstyles POST /hairstyles/tasks
任务 GET /tasks GET /tasks/{id} POST /tasks/{id}/cancel 任务中心
知识 GET /kb/items GET /kb/items/{id} 只读对外
配额 GET /quota GET /quota/ledger POST /quota/tasks/{task_key}/claim V1;hint 文案不得含价格字样(FR-BILL-07)
支付 GET /products POST /orders/verify V2 起
埋点 POST /events/batch 客户端批量上报

10. 缓存策略

数据 位置 TTL 失效方式
记忆快照 Redis 1 小时 记忆写入时按 user_id 主动失效
知识检索结果 Redis 10 分钟 键含 query hash + 过滤条件 + 知识库版本号
规则集(已发布) 进程内 + Redis 5 分钟 发布时广播失效
色板 进程内 长期 版本号变更时重载
报告长图 COS + CDN 长期 报告版本变更生成新对象(不覆盖,便于回溯)
LLM 结果 不缓存业务层 — 依赖供应商 prompt 缓存降本,不做业务层结果缓存(个性化内容缓存意义不大)
用户配额 Redis 计数器 + PG 落账 周期 周期切换重置

知识库版本号是关键设计:所有检索缓存键都带上全局 kb_version,知识库发布时版本号 +1,所有旧缓存自然失效,不需要精确追踪哪些缓存受影响。


11. 安全设计

11.1 认证与授权

  • JWT 短期 access token(15 分钟)+ 服务端可撤销的 refresh token;登出/注销时撤销全部会话。
  • 所有资源访问必须校验归属(report.user_id == current_user.id),不能只靠 ID 不可猜。越权是这类应用最常见的漏洞。
  • 后台采用独立账号体系与独立域名/网段,不与用户端共用鉴权。

11.2 数据安全

数据 措施
人脸原图 临时桶、服务端加密、2 小时生命周期、处理后立即删除、访问全程走预签名 URL
诊断结论 属敏感个人信息衍生数据,数据库加密存储敏感字段,日志中禁止打印
结果图 私有桶 + CDN 签名 URL(短期有效)+ 防盗链,禁止公开可读
密钥 全部走 SSM/KMS,禁止进代码、镜像、环境变量明文
日志 脱敏中间件:手机号、UnionID、图片 URL、诊断结论一律脱敏或不记录
备份 PG 自动备份 + 定期恢复演练(没演练过的备份等于没有备份)

11.3 防刷与滥用

风险 措施
免费额度被批量刷取 设备指纹 + 华为账号绑定;同设备多账号限制;异常注册风控
换装接口被外部盗用 内网隔离 + 服务间令牌;对外接口强制登录 + 配额消耗
恶意图片攻击 上传前校验类型/尺寸/像素上限;解码走安全库;审核前置
Prompt 注入 用户输入与系统提示词严格分区;输出侧校验;禁止用户内容影响工具调用决策
爬取知识库 对外接口只暴露必要字段,加频控与签名

11.4 降级与熔断

每个外部依赖都要有明确的降级行为(见 §2 表格)。唯一不允许降级的是内容审核:审核服务不可用时按拦截处理(fail-close)。其他能力遵循 fail-soft,保证核心体验可用。


12. 性能与容量

12.1 性能目标(NFR)

链路 指标 目标
普通 API p95 响应 < 300ms
Agent 首字 p95 < 2s
Agent 整轮 p95 < 8s
初级报告生成 p50 / p95 < 45s / < 90s
全面报告生成 p95 < 180s(允许后台生成 + 推送)
换装出图 p95 < 40s(受 GPU 容量约束,排队时间单独统计)
知识检索 p95 < 200ms
长图渲染 p95 < 8s
可用性 月度 ≥ 99.5%(V1)

排队时间与执行时间必须分开统计。混在一起看会得出错误结论:明明是 GPU 容量不足(该扩容),却被误判为推理慢(去优化模型)。

12.2 容量假设与压力点

以 1 万 DAU 为规划基线(V1 实际远低于此,用于确认架构不会在早期就撞墙):

资源 估算 压力点
API QPS 峰值约 100~200 单机 FastAPI 多 worker 足够
报告生成 首日集中,后续每日新增用户量级 CPU 队列 + 视觉分析,可水平扩 worker
换装出图 最大瓶颈 GPU 数量决定吞吐,靠队列削峰 + 配额限制需求
PG 连接 需连接池(asyncpg pool + 上限保护) 长事务与 Worker 争用,必须分离读写池
向量检索 十万级向量 pgvector HNSW 足够,索引重建走低峰

13. 成本模型

架构上的硬性要求:每一次付费调用都必须落 ob_ai_call,并可归因到用户与功能。 没有这张表,成本优化只能靠猜。

⚠️ V1 不收费让这张表的地位更高,不是更低(TD-28)。V1 没有收入,因此成本是唯一的财务变量;同时 ob_ai_call 是 V2 定价的唯一数据来源 —— 单次真实成本与人均使用频次都从这里出。埋点缺失的功能,在 V2 定价时就是一个必须靠猜的空洞。这一项不允许"先上线后补埋点"。

V1 的成本上限是可以事前算准的确定值(这是不收费换来的好处):

月度 AI 成本上限 = MAU × Σ(各功能日配额上限 × 单次成本 × 30)

因为配额是服务端硬限制(FR-BILL-06),不存在超额路径,所以这是上限而非估计值。按 MAU 15 万、免费用户月成本上限 ¥8 计算,月度上限约 ¥12 万(产品方案 §5.3.1)。

单位成本核算公式(数值需在 Phase 0 验证任务中实测填入,此处为建模框架):

功能 成本构成 建模公式
初级报告 人脸 API + 分割 API + 自建推理 + LLM + 审核 + 渲染 ≈ C_face + C_seg + C_llm(in≈8k, out≈3k) + C_mod×n + C_render
全面报告 初级 + 稠密关键点 + 更长文案 ≈ 初级 × 3~4
Agent 单轮 LLM(缓存命中后输入成本大幅下降)+ 检索 + 双向审核 ≈ C_llm(in≈3.7k 多数缓存, out≈0.8k) + C_mod×2
换装单次 GPU 秒数 + 审核 + 存储 + CDN ≈ gpu_seconds × 单价 + C_mod + C_storage
抠图单件 GPU 秒数(离线批量摊薄) 批量跑,按批次成本 / 件数

必须设置的三道成本闸门:

  1. 场景级日预算:某功能超预算自动降级(切轻量模型/暂停非核心功能),并告警。
  2. 用户级频控:配额硬上限(服务端校验,FR-BILL-06),防单用户异常消耗。
  3. 日成本预警:日成本环比突增超过阈值立即告警——通常意味着有 bug(重试风暴、缓存失效)或被刷。

14. 部署架构

14.1 V1 部署(单可用区,Docker Compose)

腾讯云 VPC
├─ CLB(公网入口,TLS 终止)
├─ CVM-app(2~4 核)
│   ├─ nginx
│   ├─ api        (FastAPI × N workers)
│   ├─ admin      (极简运营后台)
│   ├─ worker-cpu (Celery: cpu 队列)
│   ├─ worker-io  (Celery: io 队列)
│   ├─ beat       (定时任务,单实例)
│   └─ vision-svc (ONNX 推理)
├─ CVM-gpu(按需启停)
│   ├─ tryon-svc  (换装/发型推理)
│   ├─ worker-gpu (Celery: gpu 队列)
│   └─ matting    (批量抠图,仅素材生产期运行)
├─ 云数据库 PostgreSQL(含 pgvector)
├─ 云数据库 Redis
├─ COS × 4 桶 + CDN
└─ CLS / 监控告警

GPU 实例按需启停是 V1 最有效的成本手段:换装量小的时候没必要 7×24 常驻。实现方式是队列有积压时拉起、空闲一段时间后释放(配合任务中心的排队体验,用户可接受冷启动的额外等待)。

14.2 环境

环境 用途 数据
local 本地开发 Docker Compose 起 PG/Redis/COS 模拟;AI 能力走 mock 或少量真实调用
dev 联调 独立库;外部 API 用测试账号与低配额
staging 预发/验收 结构与生产一致,保留可供监管抽查的测试通道与虚拟测试账号(备案已完成,但变更备案与日常抽查仍需,TD-19)
prod 生产 —

14.3 发布

  • 容器镜像 + 标签化版本;数据库迁移在发布流程中作为独立步骤执行(先迁移后发布,保证向后兼容)。
  • 迁移必须向后兼容(加列不删列、先双写后切读),避免回滚时数据不兼容。
  • 灰度:按用户哈希分流;报告与 Agent 这类核心链路的 Prompt/规则变更必须先灰度 + 看黄金集回归。

15. 可观测性

类型 工具 关键内容
链路追踪 OpenTelemetry 一次报告生成的完整 span 树(含各外部调用耗时),排障必需
指标 Prometheus + Grafana 三张看板:业务漏斗、AI 成本、任务健康(TD-24)
日志 CLS 结构化 JSON,带 request_id/user_id/task_id 贯穿
审计 cp_audit_log 后台操作、知识库变更、权限变更
告警 云监控 + 企业微信/飞书 分级:P0(服务不可用/审核失效)、P1(任务失败率超阈值/成本突增)、P2(延迟劣化)

必须能一键回答的三个问题(这是可观测性的验收标准):

  1. 「某用户说他的报告生成失败了」→ 用 user_id 找到 task,看到失败在哪一步、错误码、是否已退点。
  2. 「昨天成本涨了 3 倍」→ 按功能/模型分组的成本对比,定位到具体场景。
  3. 「换装最近变慢了」→ 区分是排队变长(扩容)还是推理变慢(模型/资源)。

16. 工程规范

16.1 仓库结构

meida/
├─ apps/
│  ├─ api/                 # FastAPI 应用(路由、依赖注入、中间件)
│  ├─ worker/              # Celery 任务定义
│  └─ admin/               # 极简运营后台
├─ services/
│  ├─ vision/              # 视觉推理服务
│  ├─ matting/             # 抠图批处理
│  └─ tryon/               # 换装服务(改造纳管)
├─ packages/
│  ├─ domain/              # 领域模型与业务规则(纯逻辑,无 IO,可纯单测)
│  ├─ llm/                 # LLM 网关
│  ├─ retrieval/           # 混合检索
│  ├─ rules/               # 规则引擎
│  ├─ memory/              # 记忆系统
│  ├─ compliance/          # 审核 / 水印 / 元数据标识
│  └─ shared/              # 配置、日志、错误、DB、COS、可观测
├─ prompts/                # Prompt 模板(版本化,随代码走)
├─ migrations/             # Alembic
├─ tests/
│  ├─ unit/                # 领域逻辑
│  ├─ integration/         # 带 DB/Redis(testcontainers)
│  └─ golden/              # 黄金集回归(检索/规则/报告)
├─ deploy/                 # Dockerfile / compose / CI 配置
├─ docs/                   # 本文档集
└─ client-harmony/         # 鸿蒙 ArkTS 工程

16.2 AI 辅助开发下的质量防线

既然主要由 AI 编码,人工 review 的带宽会成为瓶颈,因此必须把规范变成机器可执行的检查:

防线 内容 卡关方式
契约先行 接口先写 Pydantic schema 与 OpenAPI,再写实现 客户端类型由 OpenAPI 生成,schema 变更即可见
静态检查 ruff(lint+format)+ mypy strict(覆盖 packages/domain、packages/llm) CI 失败即阻断合并
分层依赖检查 用 import-linter 之类的工具声明层间依赖规则 跨域直接访问对方表 → CI 报错
黄金集回归 检索准确率、规则命中正确性、报告结构完整性、禁忌违反数=0 每次 PR 跑,指标退化即阻断
迁移检查 Alembic 迁移必须可逆或明确标注不可逆 Review 检查清单
敏感信息扫描 密钥/Token 扫描 pre-commit + CI

黄金集是最重要的一道:AI 改代码时最容易破坏的是那些「没有断言保护的隐性行为」。检索链路和规则引擎必须有一套固定输入 → 期望输出的样本集,这既是质量防线,也是《美学知识库-建设方案》中质量保障章节的落地形式。


17. 架构演进路线

阶段 架构形态 触发条件
V1 模块化单体 + 独立 AI 服务;单机 Compose;PG 单库 —
V1.5 读写分离;Redis 集群;GPU 自动伸缩 报告/换装量上升,PG 读压力显现
V2 拆出 llm-gateway、retrieval-svc 为独立服务;引入 TKE 需要独立发布节奏或独立扩容
V2 多端(iOS/Android)→ 重新评估跨端框架 明确的多端商业需求(TD-01)
V3 向量迁 Qdrant/Milvus;事件流引入消息队列;数仓引入 ClickHouse 向量 > 500 万 / 跨域事件复杂度上升 / 需要即席分析

演进纪律:每一次架构升级都必须先出现可测量的瓶颈,再动手。提前架构化是这个阶段最大的浪费。


18. 架构决策记录(ADR 索引)

ADR 决策 详见
ADR-01 客户端用鸿蒙原生 ArkTS,不用跨端框架 TD-01
ADR-02 业务域用模块化单体,AI 能力独立服务 §3.2
ADR-03 向量检索用 pgvector,不引入专用向量库 TD-08
ADR-04 图谱用 PG 邻接表 + 递归 CTE TD-09
ADR-05 规则引擎自研数据驱动决策表 TD-10
ADR-06 人体关键点自建(腾讯云已下线) TD-05
ADR-07 体型测算用掩膜宽度剖面法 TD-06
ADR-08 抠图用 BiRefNet,禁用 RMBG-2.0 TD-07
ADR-09 自建 LLM 网关,双供应商路由 TD-04
ADR-10 人脸原图不落盘,只存派生特征 TD-20
ADR-11 统一合规出口,所有生成物必经 TD-21
ADR-12 报告长图服务端渲染 TD-12
ADR-13 配额预扣-确认-退还三段式;V1 与 V2 共用账本表 §7.4、TD-28
ADR-14 统一任务中心承载全部长耗时任务 §7

19. 技术风险登记

风险 影响 概率 应对
备案登记周期拖延上线 最高 已消除 ✅ 备案已完成,此风险关闭(TD-19)
备案范围与实际调用的模型不一致 高:超范围提供服务 中 核实备案覆盖的模型清单;LLM 网关已做多路由抽象,必要时 V1 先单路由(TD-19 残留项)
素材自采产能不足 高:tryon_ready < 300 件则「建议→试穿」闭环不成立 中高 备案解除后这是最长工序(TD-26)。按周产能倒排,未达标则功能降级为「加入搭配」
���职顾问到岗延迟 中:规则库启动即延后,M2 顺延 中 Phase 0 最早启动招聘(TD-27、T-P0-20)
团队缺乏 ArkTS 经验 前端进度不确定 中 第一个任务就打通端到端骨架,尽早暴露问题
体型测算准确率不达标 报告核心结论不可信 中 Phase 0 验证任务(≥80% 一致率);不达标则降级表述 + 引入人工校准
换装成功率依赖白底图素材 核心闭环卡住 高 素材生产列为 Phase 1 前置任务,先小批量走通再规模化
GPU 成本随活跃度线性增长 单位经济恶化 低(V1) V1 不收费,配额为硬上限,月度成本上限 = MAU × 单用户配额成本,可事前算准。V2 引入付费后此风险重新升级
大模型调价或能力变动 成本与质量波动 中 网关抽象 + 双供应商 + 场景配置化
云 API 下线(已发生一次) 能力缺口 中 核心能力(关键点、抠图)自建;对云能力保留替换预案
AI 标识元数据在链路中被剥离 合规不达标 中 专项测试覆盖 CDN/压缩/客户端保存全路径
知识库内容生产跟不上 建议质量低、可解释性弱 高 知识缺口埋点驱动优先级;顾问资源尽早接洽(TD-27)

20. 与需求文档的映射

本文章节 对应需求文档
§7.1 报告生成链路 《美学报告-需求文档》§6 生成流程
§7.2 Agent 链路、§8.3 混合检索 《穿搭Agent-需求文档》§3.4、《美学知识库-建设方案》§6
§6.2 profile 域、§8.4 记忆读写 《用户系统与记忆系统-需求文档》§3
§6.2 kb 域、§8.3 《美学知识库-建设方案》§2~§6
§7.4 配额与支付 《用户系统与记忆系统-需求文档》§2.4/2.5、《需求规格说明》§2.9
§7.5、§11 《合规与安全方案》全文
§13 成本模型 《产品方案》§5.2 成本结构

相关文档


变更记录

日期 版本 变更
2026-08-13 v1.1 按业务决策收口调整。billing 域降级为「配额与计量」:V1 移除支付、订单、会员、IAP;bl_point_tx 改名 bl_ledger 并新增 tx_type 字段,使 V1 配额账本与 V2 点数账本共用同一张表(V2 免数据迁移);新增 bl_quota_rule 配额规则表。§7.4 拆为「V1 配额三段式」与「V2 IAP 支付」。§13 成本模型补充「V1 成本上限可事前算准」的公式,并强调 ob_ai_call 是 V2 定价的唯一数据来源、不允许后补。§19 风险登记:备案风险关闭,新增备案范围一致性、素材自采产能、顾问到岗三项风险
2026-08-13 v1.0 首次输出。确立「模块化单体 + 独立 AI 服务」架构、十个业务域数据模型、五条关键链路、统一合规出口、V1 单机 Docker Compose 部署与成本模型