Files
color_full/docs/adr/0002-ai-api-strategy.md

267 lines
11 KiB
Markdown
Raw Normal View History

# ADR-0002: AI 能力通过外部 API 调用实现
> **状态**: 已决议
> **日期**: 2026-05-20
> **父决策**: ADR-0001整体技术栈
> **决策者**: 架构评审
---
## 上下文
平台需要 AI 能力支撑四大核心模块配方指标预测、NL 搜索、配方生成/推演、颜色推荐。考虑两种实现路径:
- **方案 A**:自建 Python AI 微服务FastAPI + 自训练模型)
- **方案 B**:通过外部 AI API 调用实现LLM API + Prompt Engineering
---
## 决策
**选择方案 B**:所有 AI 能力通过调用外部 LLM API 实现。
---
## 理由
### 方案 B 优势
| 维度 | 方案 A自建 | 方案 B外部 API |
| :--- | :--- | :--- |
| **开发成本** | 需要 ML 工程师训练模型;数据清洗和标注投入大 | Prompt Engineering 即可;无需 ML 专业背景 |
| **运维成本** | GPU 服务器(至少 1 台 A100+ 模型部署和监控 | 零运维,按调用量付费 |
| **迭代速度** | 重新训练需数天到数周 | 调整 Prompt 即时生效 |
| **模型能力** | 受限于自有数据量和训练资源 | 持续获得最新大模型能力升级 |
| **部署复杂度** | 增加 1 个微服务 + GPU 依赖 + gRPC | 仅 BFF 层 HTTP 调用 |
| **冷启动** | 模型加载需数分钟 | 即用即走 |
### 化妆品配方场景的特殊适配
配方研发的 AI 需求特点:
1. **推理为主,非训练密集型**:预测肤感/稳定性本质是"基于成分知识的推理"LLM 的常识推理 + few-shot learning 可以胜任
2. **数据量小**:企业内部配方数据通常是千到万级,不足以训练专用深度学习模型
3. **领域知识密集**LLM 已具备化学/化妆品基础知识,通过 Prompt 注入成分数据库即可精准推理
4. **需求多变**配方推演的约束条件千变万化API 调用的灵活性远胜固定模型
---
## BFF 层 AI 调用架构
```
┌─────────────────────────────────────────────────────────┐
│ Fastify BFF │
│ │
│ ┌────────────────────────────────────────────────────┐ │
│ │ AI Service Module │ │
│ │ │ │
│ │ ┌──────────┐ ┌──────────┐ ┌───────────────┐ │ │
│ │ │ Cache │ │ Rate │ │ Fallback │ │ │
│ │ │ Layer │ │ Limiter │ │ Handler │ │ │
│ │ └──────────┘ └──────────┘ └───────────────┘ │ │
│ │ │ │
│ │ ┌────────────────────────────────────────────┐ │ │
│ │ │ Prompt Templates (per capability) │ │ │
│ │ │ - predictFormulaMetrics │ │ │
│ │ │ - parseNLQuery │ │ │
│ │ │ - generateFormulaOptions │ │ │
│ │ │ - recommendColorants │ │ │
│ │ │ - extractFormulaStructure │ │ │
│ │ └────────────────────────────────────────────┘ │ │
│ │ │ │
│ │ ┌────────────────────────────────────────────┐ │ │
│ │ │ AI API Client │ │ │
│ │ │ - streaming (SSE proxy) │ │ │
│ │ │ - retry with backoff │ │ │
│ │ │ - timeout (30s default, 120s streaming) │ │ │
│ │ └────────────────────────────────────────────┘ │ │
│ └────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
```
### 核心模块
| 模块 | 职责 |
| :--- | :--- |
| **Prompt Templates** | 每种 AI 能力对应独立的 Prompt 模板,包含 system prompt + 结构化输出指令 |
| **Cache Layer** | LRU 缓存相同/相似查询的 AI 响应(基于 query hashTTL 5min~1h |
| **Rate Limiter** | 令牌桶 + 并发控制,保护 API 配额 |
| **Fallback Handler** | API 不可用时返回缓存结果或友好降级提示 |
| **AI API Client** | 统一的 HTTP 客户端,处理 streaming、重试、超时 |
---
## 各 AI 能力的 API 调用策略
### 1. 配方指标预测
```
POST /api/ai/predict
BFF 流程:
1. 从 PostgreSQL 检索该成分组合的历史相似配方pgvector 向量搜索)
2. 构建 Prompt
- System: 化妆品配方专家角色 + 指标定义
- Context: 历史相似配方的指标数据few-shot examples
- User: 当前配方的成分列表和比例
3. 调用 AI API非 streaming预期 < 5s
4. 缓存结果key: 成分+比例 hash
```
### 2. NL 搜索解析
```
POST /api/formulas/search?q=不含酒精的高保湿精华
BFF 流程:
1. 调用 AI API 将 NL 转为结构化查询:
{
"filters": { "exclude_ingredients": ["alcohol", "ethanol"], "category": "精华液" },
"vector_query": "高保湿、补水、滋润配方",
"sort": "保湿指数 DESC"
}
2. filters → PostgreSQL WHERE 子句
3. vector_query → pgvector embedding → HNSW 相似搜索
4. 合并结果返回
```
### 3. 配方推演
```
POST /api/ai/explore
BFF 流程:
1. 用户设置约束(目标成本、保留成分、禁止成分、目标指标)
2. 检索当前配方 + 相关历史配方作为 context
3. 构建 Prompt → 调用 AI APIstreaming 模式)
4. BFF 转发 SSE 流到前端,逐步展示生成的候选方案
5. 每个候选方案附带置信度和变更说明
```
### 4. 颜色推荐
```
POST /api/color/recommend
BFF 流程:
1. 前端传入目标颜色 Lab 值
2. 在 PostgreSQL 中检索 ΔE < 3.0 的历史颜色配方pgvector
3. 将目标色 + 最近匹配配方作为 context调用 AI API 推荐色浆组合
4. 返回推荐色浆 + 预测比例 + 预测 ΔE
```
### 5. 配方结构化提取
```
POST /api/formulas/extract
BFF 流程:
1. 用户粘贴配方文本(或上传 Excel
2. 调用 AI API with function calling / structured output
3. 提取:成分 INCI 名、中文名、比例、所属相、工艺备注
4. 与成分目录ingredients 表)模糊匹配校验
5. 返回结构化 JSON前端展示确认
```
---
## AI API 选型
### 主选
| API | 优势 | 适用场景 |
| :--- | :--- | :--- |
| **OpenAI GPT-4o / GPT-4.1** | 推理能力最强structured output 原生streaming 稳定 | 配方推演、NL 解析、结构化提取 |
| **Anthropic Claude 4** | 长上下文200K化工领域知识强 | 配方生成(需大量 context、复杂推理 |
| **DeepSeek V3** | 性价比高;中文能力强 | 指标预测(高频调用)、批量处理 |
### 推荐策略
| 场景 | 模型 | 理由 |
| :--- | :--- | :--- |
| 配方推演(流式,低频,高质量) | GPT-4o | streaming 体验最好,推理质量最高 |
| 指标预测(非流式,高频,需快) | DeepSeek V3 | 便宜、快、中文好 |
| NL 搜索解析(高频,需结构化输出) | GPT-4o-mini / DeepSeek V3 | 便宜 + function calling |
| 配方结构化提取(批量,需准确) | GPT-4o | structured output 精度最高 |
| 颜色推荐(低频,需领域知识) | GPT-4o | 需要强推理 |
### API 配置抽象
```typescript
// BFF 层多 provider 抽象
interface AIProvider {
chat(messages: Message[], options: ChatOptions): Promise<ChatResponse>;
chatStream(messages: Message[], options: ChatOptions): AsyncIterable<ChatChunk>;
}
const providers: Record<string, AIProvider> = {
openai: new OpenAIProvider({ apiKey: env.OPENAI_API_KEY }),
deepseek: new DeepSeekProvider({ apiKey: env.DEEPSEEK_API_KEY }),
// 预留其他 provider
};
```
所有 AI 调用通过统一的 `AIService` 模块,根据场景路由到对应 provider上层业务不感知具体模型。
---
## 降级策略
| 场景 | 降级行为 |
| :--- | :--- |
| AI API 超时5s | 指标预测:返回"无法预测,请手动评估"NL 搜索:降级为基础关键词搜索 |
| AI API 不可用(连续失败) | 全部能力降级为提示模式,告知用户"AI 服务暂不可用" |
| 配额耗尽 | 限流 + 排队;高频能力(指标预测)优先缓存命中 |
---
## 缓存策略
| 缓存内容 | TTL | Key |
| :--- | :--- | :--- |
| 指标预测结果 | 1 小时 | 成分列表 + 比例的 hash |
| NL 搜索解析 | 5 分钟 | 原始查询文本 hash |
| 颜色推荐 | 30 分钟 | 目标 Lab 值 + 允许 ΔE |
| 成分结构化提取 | 永久(除非成分库更新) | 原料名称 hash |
使用 Redis 存储。BFF 启动时无需依赖 Redis降级为内存 LRU 缓存。
---
## 安全考虑
- **API Key 管理**:环境变量注入(非代码硬编码),支持 vault/secret manager
- **数据脱敏**:发送给 AI API 的 prompt 不包含公司敏感配方全量数据,仅发送 necesary context
- **Prompt 注入防护**用户输入NL 搜索词)经过清洗后嵌入 prompt 模板
- **审计日志**:所有 AI 调用记录请求摘要、token 消耗、耗时)存储到 PostgreSQL audit 表
---
## 后果
### 正向
- 零 ML 基础设施投入,开发周期缩短 50%+
- 部署仅需 4 个服务,运维复杂度极低
- 模型能力随 API 升级自动提升,无迁移成本
- 成本可控:按调用量付费,低用量时几乎为零
- BFF 层可独立开发和测试mock AI 响应)
### 风险和缓解
| 风险 | 缓解 |
| :--- | :--- |
| API 延迟影响用户体验 | 缓存 + streaming + 降级;预测 API 设置 5s 超时 |
| 外部 API 数据隐私 | Prompt 中不发送完整配方;仅发送必要上下文 |
| 供应商锁定 | 多 provider 抽象层;标准化 prompt 模板可跨模型复用 |
| LLM 幻觉(生成不合理配方) | 结果后处理校验(比例总和 100%、成分存在性检查) |
---
## 参考
- ADR-0001: 整体技术栈选型
- PRD: `.scratch/formula-rd-platform/PRD.md`
- OpenAI Structured Outputs: https://platform.openai.com/docs/guides/structured-outputs
- pgvector: https://github.com/pgvector/pgvector