Files
smart-project-pricing/瑞小美AI接入规范1月17日.md
2026-01-31 21:33:06 +08:00

494 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 瑞小美 AI 接入规范
> 适用于瑞小美全团队所有 AI 相关项目
> **最后更新**2026-01-17
---
## 核心原则
| 原则 | 要求 |
|------|------|
| **服务商策略** | **首选 4sapi.com → 备选 OpenRouter.ai**(自动降级) |
| **统一配置** | 从**门户系统**统一获取 Key各模块**禁止独立配置** |
| **统一服务** | 通过 `shared_backend.AIService` 调用,禁止直接请求 API |
### 瑞小美 SCRM 配置入口
- **配置管理**https://scrm.ireborn.com.cn → AI 配置
- **调用统计**:查看各模块 Token 使用量、成本、服务商分布
- **调用日志**:按模块、服务商、状态筛选历史调用
---
## 服务商配置
### 降级策略(强制)
```
请求流程4sapi.com → (失败) → OpenRouter.ai
```
| 优先级 | 服务商 | API 地址 | 说明 |
|--------|--------|----------|------|
| **1首选** | 4sapi.com | `https://4sapi.com/v1/chat/completions` | 国内优化,延迟低 |
| **2备选** | OpenRouter.ai | `https://openrouter.ai/api/v1/chat/completions` | 模型全,稳定性好 |
**降级触发条件**(宽松策略,首选失败就尝试备选):
- 连接超时(默认 30s
- 服务端错误5xx
- 客户端错误4xx余额不足、Key 无效、模型不存在等
- 网络异常
> ✅ **说明**:只要首选服务商调用失败,就会自动尝试备选服务商
### 4sapi.com 配置
**API 端点**
```
https://4sapi.com/v1/chat/completions
```
**测试阶段 Key**(仅限开发环境):
```
sk-9yMCXjRGANbacz20kJY8doSNy6Rf446aYwmgGIuIXQ7DAyBw
```
**官方文档**
- [图片生成](https://4sapi.apifox.cn/359535008e0)
- [图片修改](https://4sapi.apifox.cn/359535009e0)
- [音频理解](https://4sapi.apifox.cn/359535011e0)
- [视频理解](https://4sapi.apifox.cn/359535012e0)
- [文档理解](https://4sapi.apifox.cn/359535013e0)
- [TTS 语音合成](https://4sapi.apifox.cn/382937873e0)
- [语音转文字](https://4sapi.apifox.cn/382936341e0)
- [Embeddings](https://4sapi.apifox.cn/359535014e0)
### OpenRouter.ai 配置(备选)
**API 端点**
```
https://openrouter.ai/api/v1/chat/completions
```
**测试阶段 Key**(仅限开发环境):
```
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
```
**官方文档**[Images](https://openrouter.ai/docs/guides/overview/multimodal/images) | [PDFs](https://openrouter.ai/docs/guides/overview/multimodal/pdfs) | [Audio](https://openrouter.ai/docs/guides/overview/multimodal/audio) | [Videos](https://openrouter.ai/docs/guides/overview/multimodal/videos)
---
## Key 管理规范
### ⚠️ 强制要求
1. **禁止**在代码中硬编码 API Key
2. **必须**从门户系统统一获取配置
3. **必须**同时配置两个服务商的 Key支持降级
> 测试阶段 Key 见上方「服务商配置」章节
### 配置架构(瑞小美 SCRM
```
┌───────────────────────────────────────────────────────────────┐
│ 门户系统 (scrm.ireborn.com.cn) │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ AI 配置页面(仅超管可访问) │ │
│ │ - 首选服务商4sapi.comAPI Key + Base URL │ │
│ │ - 备选服务商OpenRouterAPI Key + Base URL │ │
│ │ - 默认模型 │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ GET /api/ai/internal/config (内部 API无需鉴权
└──────────────────────────────┬────────────────────────────────┘
┌───────────────────────┼───────────────────────────────┐
│ │ │
▼ ▼ ▼
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ 会话存档 │ │ 智能回复 │ │ 撩回搭子 │
│ AIService │ │ AIService │ │ AIService │
└─────────────┘ └─────────────┘ └─────────────┘
```
### 配置 API门户系统已实现
**端点**`GET http://portal-backend:8000/api/ai/internal/config`
**返回格式**
```json
{
"code": 0,
"data": {
"primary": {
"provider": "4sapi",
"api_key": "sk-xxx...",
"base_url": "https://4sapi.com/v1"
},
"fallback": {
"provider": "openrouter",
"api_key": "sk-or-v1-xxx...",
"base_url": "https://openrouter.ai/api/v1"
},
"default_model": "gemini-3-flash-preview"
}
}
```
**说明**
- 各模块通过 Docker 内网访问 `portal-backend:8000`
- 配置有 60 秒缓存,避免频繁调用
- 如需自定义端点,设置环境变量:`PORTAL_CONFIG_API=http://...`
---
## 支持的能力
| 能力 | 方法 | 说明 |
|------|------|------|
| 文本聊天 | `chat()` | 基础对话,支持多轮 |
| 图片理解 | `vision()` | PNG/JPEG/WebP/GIF |
| PDF 分析 | `analyze_pdf()` | 文档理解、OCR |
| 音频分析 | `analyze_audio()` | 语音转文字 |
| 视频分析 | `analyze_video()` | 视频内容理解 |
| 图像生成 | `generate_image()` | 文生图 |
| 流式输出 | `chat_stream()` | 逐字返回 |
> 官方文档见上方「服务商配置」章节
---
## 推荐模型
### 模型命名对照表
> ⚠️ **注意**:两个服务商的模型命名规则不同,`AIService` 会自动转换
| 用途 | 4sapi.com首选 | OpenRouter备选 |
|------|-------------------|---------------------|
| **测试** | `gemini-3-flash-preview` ✅ | `google/gemini-3-flash-preview` |
| **分析** | `claude-opus-4-5-20251101-thinking` ✅ | `anthropic/claude-opus-4.5` |
| **创意** | `gemini-3-pro-preview` ✅ | `google/gemini-3-pro-preview` |
| **生图** | `gemini-2.5-flash-image-preview` ✅ | `google/gemini-2.0-flash-exp:free` |
> ✅ 已验证可用2026-01-17
### 代码中使用
```python
from shared_backend.services.ai_service import (
DEFAULT_MODEL, # 测试:自动映射到当前服务商
MODEL_ANALYSIS, # 分析
MODEL_CREATIVE, # 创意
MODEL_IMAGE_GEN, # 生图
)
# AIService 内部自动处理模型名转换,开发者无需关心
```
---
## 调用示例
### 基础用法
```python
from shared_backend.services.ai_service import AIService
# module_code 标识你的模块,用于统计
ai = AIService(module_code="your_module", db_session=db)
# Key 自动从系统后台获取,无需手动指定
response = await ai.chat(
messages=[
{"role": "system", "content": "你是助手"},
{"role": "user", "content": "你好"}
],
prompt_name="greeting" # 必填,用于调用统计
)
print(response.content)
```
### 图片理解
```python
response = await ai.vision(
prompt="描述这张图片",
images=["https://example.com/image.jpg"], # URL / base64 / bytes
prompt_name="image_analysis"
)
```
### PDF 分析
```python
response = await ai.analyze_pdf(
prompt="总结要点",
pdf="https://example.com/doc.pdf",
pdf_engine="pdf-text", # 免费 | "mistral-ocr" 收费
prompt_name="pdf_summary"
)
```
### 音频/视频
```python
# 音频
response = await ai.analyze_audio(
prompt="转录并总结", audio=audio_bytes, mime_type="audio/mp3"
)
# 视频
response = await ai.analyze_video(
prompt="描述内容", video="https://example.com/video.mp4"
)
```
### 图像生成
```python
response = await ai.generate_image(
prompt="一只橘猫",
model=MODEL_IMAGE_GEN,
prompt_name="cat_gen"
)
for img in response.images:
print(img)
```
### 流式输出
```python
async for chunk in ai.chat_stream(messages, prompt_name="stream_test"):
print(chunk, end="", flush=True)
```
---
## 多模态消息格式
```python
# 图片
{"type": "image_url", "image_url": {"url": "https://..." or "data:image/jpeg;base64,..."}}
# PDF
{"type": "file", "file": {"filename": "doc.pdf", "file_data": "..."}}
# 音频
{"type": "input_audio", "input_audio": {"url": "..."}}
# 视频
{"type": "input_video", "input_video": {"url": "..."}}
```
---
## 工具函数
```python
from shared_backend.services.ai_service import (
file_to_base64, # 文件转 base64
make_data_url, # 构建 data URL
get_mime_type, # 获取 MIME 类型
)
```
---
## 返回结构
所有调用返回 `AIResponse` 对象(对服务商原始响应的统一封装):
```python
@dataclass
class AIResponse:
content: str # ← choices[0].message.content
model: str # ← model
provider: str # ← 实际使用的服务商4sapi / openrouter
input_tokens: int # ← usage.prompt_tokens
output_tokens: int # ← usage.completion_tokens
total_tokens: int # ← 计算值
cost: float # ← usage.total_cost如有
latency_ms: int # ← 本地计算
raw_response: dict # ← 完整原始响应
images: List[str] # ← 图像生成结果
annotations: dict # ← PDF 解析注释
```
**使用示例**
```python
response = await ai.chat(messages, prompt_name="test")
print(response.content) # AI 回复
print(response.provider) # 实际服务商4sapi / openrouter
print(response.total_tokens) # 消耗 token
print(response.cost) # 费用(美元)
print(response.latency_ms) # 延迟(毫秒)
# 需要原始响应时
print(response.raw_response) # 服务商完整返回
```
---
## 提示词规范
### 文件位置(强制)
```
{模块}/后端服务/prompts/{功能名}_prompts.py
```
### 文件结构(强制)
```python
"""功能描述"""
PROMPT_META = {
"name": "policy_analysis", # 唯一标识,用于统计
"display_name": "政策解读", # 后台显示名称
"description": "解析政策文档", # 功能描述
"module": "your_module", # 所属模块
"variables": ["content"], # 变量列表
}
SYSTEM_PROMPT = """你是专业分析师..."""
USER_PROMPT = """请分析:{content}"""
```
### 元数据自动注册(可视化)
`PROMPT_META` 会**自动注册到数据库**,实现后台可视化管理:
```python
# 模块启动时扫描并注册
from shared_backend.services.ai_service import scan_and_register_prompts
scan_and_register_prompts(
module_path="/path/to/your_module",
module_code="your_module"
)
```
**注册流程**
```
prompts/*_prompts.py → PROMPT_META → ai_prompts 表 → 后台可视化
```
**后台功能**
- 查看所有已注册的提示词
- 按模块筛选
- 查看变量定义
- 点击"同步"手动刷新
> 提示词**内容**由开发维护Git 版本控制),后台**仅展示元数据**,不支持在线编辑
---
## 调用日志与统计
### ⚠️ 强制要求
**必须传入 `db_session`** 才能记录调用日志到 `ai_call_logs` 表:
```python
# ❌ 错误:无法记录日志,统计页面无数据
ai = AIService(module_code="my_module")
# ✅ 正确:日志会写入数据库
ai = AIService(module_code="my_module", db_session=db)
```
### 独立模块配置
如果模块运行在独立容器中,无法直接获取数据库会话,需配置环境变量:
```bash
# docker-compose.yml
environment:
- DATABASE_URL=mysql+pymysql://user:pass@scrm-mysql:3306/scrm_content?charset=utf8mb4
```
然后在代码中自动创建会话:
```python
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
import os
def get_db_session():
database_url = os.getenv("DATABASE_URL")
if not database_url:
return None
engine = create_engine(database_url, pool_pre_ping=True)
Session = sessionmaker(bind=engine)
return Session()
# 使用
db = get_db_session()
ai = AIService(module_code="my_module", db_session=db)
```
### 查看统计
**入口**https://scrm.ireborn.com.cn → AI 配置 → 调用统计
**统计维度**
- 按模块各模块调用次数、Token 消耗、成本
- 按服务商4sapi / OpenRouter 使用分布(观察降级频率)
- 按日期:调用趋势图
**自动记录字段**`ai_call_logs` 表):
| 字段 | 说明 |
|------|------|
| `module_code` | 模块标识 |
| `prompt_name` | 提示词名称 |
| `provider` | **实际使用的服务商**4sapi / openrouter |
| `model` | 使用的模型 |
| `input_tokens` / `output_tokens` | Token 消耗 |
| `cost` | 费用(美元) |
| `latency_ms` | 响应延迟 |
| `status` | 调用状态success / error |
| `error_message` | 错误信息(失败时) |
| `created_at` | 调用时间 |
**降级监控**:通过 `provider` 字段筛选,可观察降级发生频率,评估首选服务商稳定性
---
## 检查清单
### 配置检查(门户系统)
- [ ] 在门户 AI 配置页面配置 **4sapi.com API Key**
- [ ] 在门户 AI 配置页面配置 **OpenRouter API Key**(备选)
- [ ] 确认两个 Key 都有效(门户页面显示"已配置"
### 代码检查(各模块)
- [ ] 使用 `shared_backend.AIService`,未直接调用 API
- [ ] 未硬编码 API Key
- [ ] 创建 `prompts/{功能}_prompts.py`
- [ ] 包含 `PROMPT_META`name, display_name, module, variables
- [ ] 调用时传入 `prompt_name`(用于统计)
- [ ] 初始化时传入 `db_session`(记录日志)
### 验证
```bash
# 检查门户配置 API 是否可访问
curl http://portal-backend:8000/api/ai/internal/config
# 检查 AI 调用日志是否记录
SELECT * FROM ai_call_logs ORDER BY created_at DESC LIMIT 10;
```
---
*瑞小美 AI 团队 · 2026-01-17*