37 KiB
37 KiB
AIGC 架构深度分析与改造方案
文档版本: 1.0.0
更新日期: 2024-12-09
状态: 待实施
1. 当前架构概览
1.1 系统组成
┌─────────────────────────────────────────────────────────────────────────────┐
│ 前端 (Vue/React) │
│ - 用户交互界面 │
│ - WebSocket 接收进度推送 │
│ - HTTP API 调用 │
└─────────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ Java 后端 (Spring Boot) │
│ - 用户认证与权限 │
│ - 数据库 CRUD (MySQL) │
│ - 消息队列调度 (RabbitMQ) │
│ - WebSocket 推送 │
│ - API 次数管理 │
│ - 任务状态管理 │
└─────────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ Python 后端 (FastAPI) │
│ - AI/LLM 调用 │
│ - Prompt 管理与渲染 │
│ - 海报图片生成 │
│ - 内容生成逻辑 │
└─────────────────────────────────────────────────────────────────────────────┘
1.2 核心业务流程
NoteCreator (笔记生成) 完整流程
用户点击"生成笔记"
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ 1. NoteCreatorController (Java) │
│ - 接收请求: userId, packageIds, styleIds, audienceIds, dates, numTopics │
│ - 创建 NoteCreatorTask 记录 (状态: PENDING) │
│ - 发送消息到 RabbitMQ (NOTE_CREATOR_QUEUE_HIGH/NORMAL) │
│ - 立即返回 taskId 给前端 │
└─────────────────────────────────────────────────────────────────────────────┘
│
│ RabbitMQ 异步消费
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ 2. NoteCreatorQueueConsumer (Java) │
│ - 更新任务状态: PROCESSING │
│ - 推送 WebSocket: 任务开始 (1%) │
│ - 调用 NoteCreatorGenerateService.executeFullNoteCreator() │
│ - 接收进度回调,推送 WebSocket (5% → 20% → 80% → 90% → 100%) │
│ - 更新任务状态: SUCCESS/FAILED │
│ - ACK 消息 │
└─────────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ 3. NoteCreatorGenerateServiceImpl (Java) │
│ │
│ 步骤 1: 生成选题 (5% → 20%) │
│ ├── 将 packageIds 转换为 productIds + scenicSpotIds │
│ ├── 调用 TopicGenerateService.generateAndSaveTopic() │
│ └── 推送进度: 20% │
│ │
│ 步骤 2: 预扣除 API 次数 │
│ │
│ 步骤 3: 生成内容 (20% → 90%) │
│ ├── 遍历每个选题 │
│ ├── 调用 ContentGenerateService.generateAndSaveContents() │
│ ├── 每完成一篇,推送进度 + 新结果 (流式推送) │
│ └── 保存到数据库 │
│ │
│ 步骤 4: 处理失败退款 │
│ │
│ 步骤 5: 返回结果 (90% → 100%) │
└─────────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ 4. TopicGenerateServiceImpl (Java) │
│ │
│ 当前实现 (有问题): │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ Map<String, Object> requestBody = new HashMap<>(); │ │
│ │ requestBody.put("dates", datesStr); │ │
│ │ requestBody.put("numTopics", request.getNumTopics()); │ │
│ │ requestBody.put("styleIds", request.getStyleIds()); // ⚠️ ID │ │
│ │ requestBody.put("audienceIds", request.getAudienceIds()); // ⚠️ ID │ │
│ │ requestBody.put("scenicSpotIds", ...); // ⚠️ ID │ │
│ │ requestBody.put("productIds", ...); // ⚠️ ID │ │
│ │ │ │
│ │ // 调用旧接口 │ │
│ │ externalServiceClient.post("content-generate", "topics", ...); │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────────┘
│
│ HTTP 同步调用
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ 5. Python FastAPI │
│ │
│ 旧接口 (已废弃): │
│ POST /api/v1/tweet/topics │
│ - 接收 ID 列表 │
│ - 查询数据库获取完整信息 ← ⚠️ Python 访问数据库 │
│ - 构建 Prompt │
│ - 调用 LLM │
│ - 返回选题列表 │
│ │
│ 新接口 (V2): │
│ POST /api/v2/aigc/execute │
│ - 接收完整对象 │
│ - 直接使用 PromptRegistry 渲染 │
│ - 调用 LLM │
│ - 返回结果 │
└─────────────────────────────────────────────────────────────────────────────┘
2. 问题分析
2.1 数据库双端访问问题
现状:
Java 端:
- 存储 景区(ScenicSpot)、产品(Product)、风格(Style)、人群(Audience)
- 存储 选题(Topic)、内容(Content)、任务(Task)
Python 端:
- 也需要查询 景区、产品、风格、人群 信息来构建 Prompt
- 导致两端都需要数据库连接
问题:
- 数据一致性风险
- 连接池资源浪费
- 部署复杂度增加
- Python 端需要维护 ORM 模型
2.2 ID vs 完整对象
现状:
// Java 端传递 ID
requestBody.put("scenicSpotIds", Arrays.asList("1", "2", "3"));
# Python 端需要查数据库
scenic_spots = db.query(ScenicSpot).filter(ScenicSpot.id.in_(ids)).all()
问题:
- 额外的数据库查询
- ID 可能无效或已删除
- 数据版本不一致
2.3 Prompt 管理分散
现状:
Python 端:
prompts/
├── topic_generate/v1.0.0.yaml
├── content_generate/v1.0.0.yaml
├── style/gonglue/v1.0.0.yaml
└── audience/qinzi/v1.0.0.yaml
Java 端:
- 需要知道有哪些风格/人群可选
- 需要展示风格/人群的名称和描述
- 但这些信息在 Python 端的 YAML 文件中
问题:
- Java 端无法动态获取可用的风格/人群列表
- 前端下拉框的选项需要硬编码或单独维护
- 新增风格/人群需要两端同步修改
3. 目标架构 (方案 A: Python 作为纯计算服务)
3.1 职责划分
┌─────────────────────────────────────────────────────────────────────────────┐
│ Java 后端 │
│ │
│ 职责: │
│ ✅ 用户认证与权限管理 │
│ ✅ 所有数据库 CRUD 操作 │
│ ✅ 消息队列调度 (RabbitMQ) │
│ ✅ WebSocket 进度推送 │
│ ✅ 任务状态管理 │
│ ✅ API 次数管理 │
│ ✅ 查询并组装完整数据对象 │
│ ✅ 提供风格/人群配置 API (从 Python 获取或本地缓存) │
│ │
│ 不做: │
│ ❌ Prompt 模板管理 │
│ ❌ LLM 调用 │
│ ❌ 图片处理 │
└─────────────────────────────────────────────────────────────────────────────┘
│
│ HTTP (同步调用,传完整对象)
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ Python 后端 │
│ │
│ 职责: │
│ ✅ Prompt 模板管理 (PromptRegistry) │
│ ✅ Prompt 渲染 (Jinja2) │
│ ✅ LLM 调用 │
│ ✅ 海报图片生成 │
│ ✅ 提供风格/人群配置查询 API │
│ │
│ 不做: │
│ ❌ 数据库访问 │
│ ❌ 用户认证 │
│ ❌ 任务状态管理 │
│ ❌ 消息队列 │
└─────────────────────────────────────────────────────────────────────────────┘
3.2 新的调用流程
┌─────────────────────────────────────────────────────────────────────────────┐
│ Java: TopicGenerateServiceImpl │
│ │
│ // 1. 从数据库查询完整对象 │
│ ScenicSpot scenicSpot = scenicSpotService.getById(scenicSpotId); │
│ Product product = productService.getById(productId); │
│ Style style = styleService.getById(styleId); │
│ Audience audience = audienceService.getById(audienceId); │
│ │
│ // 2. 构建请求体 (完整对象) │
│ Map<String, Object> request = Map.of( │
│ "engine", "topic_generate", │
│ "params", Map.of( │
│ "month", "2025-01", │
│ "num_topics", 5, │
│ "scenic_spot", Map.of( │
│ "id", scenicSpot.getId(), │
│ "name", scenicSpot.getName(), │
│ "description", scenicSpot.getDescription(), │
│ "address", scenicSpot.getAddress(), │
│ "highlights", scenicSpot.getHighlights() │
│ ), │
│ "product", Map.of( │
│ "id", product.getId(), │
│ "name", product.getName(), │
│ "price", product.getPrice(), │
│ "description", product.getDescription() │
│ ), │
│ "style", Map.of( │
│ "id", style.getId(), │
│ "name", style.getName() │
│ ), │
│ "audience", Map.of( │
│ "id", audience.getId(), │
│ "name", audience.getName() │
│ ) │
│ ) │
│ ); │
│ │
│ // 3. 调用 Python V2 接口 │
│ Response response = externalServiceClient.post( │
│ "content-generate", │
│ "/api/v2/aigc/execute", │
│ request, │
│ TopicGenerateResponse.class │
│ ); │
└─────────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ Python: /api/v2/aigc/execute │
│ │
│ // 1. 解析请求 │
│ engine_id = request.engine # "topic_generate" │
│ params = request.params # 包含完整对象 │
│ │
│ // 2. 获取引擎并执行 │
│ engine = registry.get(engine_id) │
│ result = await engine.execute(params) │
│ │
│ // 3. 引擎内部 │
│ // - 使用 PromptRegistry 渲染 Prompt │
│ // - 调用 LLM │
│ // - 返回结果 │
└─────────────────────────────────────────────────────────────────────────────┘
4. Prompt 与配置管理方案
4.1 风格/人群配置的双端访问
问题:Java 端需要展示风格/人群列表供用户选择,但配置在 Python 端。
方案 1: Python 提供查询 API (推荐)
Python 端提供 API:
GET /api/v2/aigc/prompts/list
返回:
{
"prompts": [
"topic_generate",
"content_generate",
"style/gonglue",
"style/tuijian",
"audience/qinzi",
"audience/zhoubianyou",
"audience/gaoshe"
]
}
GET /api/v2/aigc/prompts/styles
返回:
{
"styles": [
{
"id": "gonglue",
"name": "攻略风",
"description": "以实用信息为主,包含详细的游玩路线..."
},
{
"id": "tuijian",
"name": "极力推荐风",
"description": "热情推荐,强调产品亮点..."
}
]
}
GET /api/v2/aigc/prompts/audiences
返回:
{
"audiences": [
{
"id": "qinzi",
"name": "亲子向",
"description": "家庭出游,有小孩同行..."
},
...
]
}
Java 端使用:
// 启动时或定时刷新,缓存到本地
@Scheduled(fixedRate = 3600000) // 每小时刷新
public void refreshStylesAndAudiences() {
StylesResponse styles = pythonClient.get("/api/v2/aigc/prompts/styles");
AudiencesResponse audiences = pythonClient.get("/api/v2/aigc/prompts/audiences");
// 缓存到 Redis 或内存
cache.put("styles", styles.getStyles());
cache.put("audiences", audiences.getAudiences());
}
// 前端请求时返回缓存
@GetMapping("/styles")
public List<StyleVO> getStyles() {
return cache.get("styles");
}
方案 2: 配置同步到数据库
Python 端:
- 仍然是 Prompt 的权威来源
- 提供导出 API
Java 端:
- 定时从 Python 同步配置到数据库
- 前端从 Java 数据库读取
问题:
- 数据可能不一致
- 需要同步机制
推荐方案 1,因为:
- Python 是 Prompt 的唯一权威来源
- 无数据一致性问题
- Java 只做缓存,不存储
4.2 Prompt YAML 结构规范
# prompts/style/gonglue/v1.0.0.yaml
meta:
name: style_gonglue
version: "1.0.0"
description: "攻略风文案风格"
author: "team"
created_at: "2024-12-08"
# 用于 Java 端展示的元信息
style_id: "gonglue" # 唯一标识
style_name: "攻略风" # 显示名称
style_description: "以实用信息为主,包含详细的游玩路线、时间安排、费用预算等"
style_icon: "📝" # 可选,前端图标
style_order: 1 # 排序权重
# 风格提示词内容 (用于 Prompt 渲染)
content: |
你是景区小红书爆款文案策划...
# prompts/audience/qinzi/v1.0.0.yaml
meta:
name: audience_qinzi
version: "1.0.0"
description: "亲子向用户画像"
# 用于 Java 端展示的元信息
audience_id: "qinzi"
audience_name: "亲子向"
audience_description: "家庭出游,有小孩同行,关注安全性和趣味性"
audience_icon: "👨👩👧"
audience_order: 1
# 人群提示词内容
content: |
用户画像:亲子家庭
- 年龄构成:父母25-45岁,孩子3-12岁
- 出游特点:注重安全、趣味、教育意义
...
5. 接口规范
5.1 Python V2 API
5.1.1 执行引擎
POST /api/v2/aigc/execute
请求体:
{
"engine": "topic_generate",
"params": {
"month": "2025-01",
"num_topics": 5,
"scenic_spot": {
"id": 1,
"name": "天津冒险湾",
"description": "天津最大的水上乐园...",
"address": "天津市滨海新区...",
"highlights": ["水上过山车", "儿童戏水区"]
},
"product": {
"id": 10,
"name": "家庭套票",
"price": 299,
"original_price": 399,
"description": "含2大1小门票..."
},
"style": {
"id": "gonglue",
"name": "攻略风"
},
"audience": {
"id": "qinzi",
"name": "亲子向"
}
}
}
响应体:
{
"success": true,
"data": {
"topics": [
{
"index": 1,
"date": "2025-01-15",
"title": "寒假遛娃好去处",
"logic": "寒假期间家庭出游需求旺盛..."
},
...
]
},
"execution_time": 12.5,
"metadata": {
"model": "gpt-4",
"prompt_version": "v1.0.0",
"tokens_used": 1500
}
}
5.1.2 查询风格列表
GET /api/v2/aigc/config/styles
响应体:
{
"styles": [
{
"id": "gonglue",
"name": "攻略风",
"description": "以实用信息为主...",
"icon": "📝",
"order": 1
},
{
"id": "tuijian",
"name": "极力推荐风",
"description": "热情推荐,强调亮点...",
"icon": "🔥",
"order": 2
}
],
"count": 2
}
5.1.3 查询人群列表
GET /api/v2/aigc/config/audiences
响应体:
{
"audiences": [
{
"id": "qinzi",
"name": "亲子向",
"description": "家庭出游...",
"icon": "👨👩👧",
"order": 1
},
...
],
"count": 3
}
5.2 Java 端改造清单
5.2.1 TopicGenerateServiceImpl 改造
// 改造前
private TopicGenerateResponse callAIService(TopicGenerateRequest request) {
Map<String, Object> requestBody = new HashMap<>();
requestBody.put("dates", datesStr);
requestBody.put("styleIds", request.getStyleIds()); // ❌ 传 ID
requestBody.put("audienceIds", request.getAudienceIds()); // ❌ 传 ID
requestBody.put("scenicSpotIds", request.getScenicSpotIds());
requestBody.put("productIds", request.getProductIds());
return externalServiceClient.post(SERVICE_NAME, "topics", requestBody, ...);
}
// 改造后
private TopicGenerateResponse callAIService(TopicGenerateRequest request) {
// 1. 查询完整对象
List<ScenicSpot> scenicSpots = scenicSpotService.listByIds(request.getScenicSpotIds());
List<Product> products = productService.listByIds(request.getProductIds());
Style style = styleConfigService.getById(request.getStyleIds().get(0));
Audience audience = audienceConfigService.getById(request.getAudienceIds().get(0));
// 2. 构建 V2 请求
Map<String, Object> params = new HashMap<>();
params.put("month", datesStr);
params.put("num_topics", request.getNumTopics());
params.put("scenic_spot", convertToMap(scenicSpots.get(0)));
params.put("product", convertToMap(products.get(0)));
params.put("style", Map.of("id", style.getId(), "name", style.getName()));
params.put("audience", Map.of("id", audience.getId(), "name", audience.getName()));
Map<String, Object> requestBody = Map.of(
"engine", "topic_generate",
"params", params
);
// 3. 调用 V2 接口
return externalServiceClient.post(SERVICE_NAME, "/api/v2/aigc/execute", requestBody, ...);
}
private Map<String, Object> convertToMap(ScenicSpot spot) {
Map<String, Object> map = new HashMap<>();
map.put("id", spot.getId());
map.put("name", spot.getName());
map.put("description", spot.getDescription());
map.put("address", spot.getAddress());
map.put("traffic_info", spot.getTrafficInfo());
map.put("highlights", spot.getHighlights());
map.put("opening_hours", spot.getOpeningHours());
return map;
}
5.2.2 ContentGenerateServiceImpl 改造
// 改造后
private ContentGenerateResponse callAIService(ContentGenerateRequest.ContentsInfo request) {
// 1. 查询完整对象
ScenicSpot scenicSpot = scenicSpotService.getById(request.getScenicSpotIds().get(0));
Product product = productService.getById(request.getProductIds().get(0));
Style style = styleConfigService.getById(request.getStyleIds().get(0));
Audience audience = audienceConfigService.getById(request.getAudienceIds().get(0));
// 2. 构建 V2 请求
Map<String, Object> params = new HashMap<>();
params.put("topic", request.getTopic());
params.put("scenic_spot", convertToMap(scenicSpot));
params.put("product", convertToMap(product));
params.put("style", Map.of("id", style.getId(), "name", style.getName()));
params.put("audience", Map.of("id", audience.getId(), "name", audience.getName()));
params.put("enable_judge", true);
Map<String, Object> requestBody = Map.of(
"engine", "content_generate",
"params", params
);
return externalServiceClient.post(SERVICE_NAME, "/api/v2/aigc/execute", requestBody, ...);
}
5.2.3 ExternalServicesConfig 改造
# application.yml
external-services:
content-generate:
enabled: true
base-url: http://localhost:8000
connect-timeout: 30
read-timeout: 120
endpoints:
# 旧接口 (待废弃)
topics: /api/v1/tweet/topics
content: /api/v1/tweet/content
# 新接口 (V2)
execute: /api/v2/aigc/execute
styles: /api/v2/aigc/config/styles
audiences: /api/v2/aigc/config/audiences
engines: /api/v2/aigc/engines
5.2.4 新增 StyleConfigService
@Service
public class StyleConfigService {
@Autowired
private ExternalServiceClient pythonClient;
@Autowired
private RedisTemplate<String, Object> redisTemplate;
private static final String CACHE_KEY_STYLES = "aigc:config:styles";
private static final String CACHE_KEY_AUDIENCES = "aigc:config:audiences";
/**
* 获取所有风格配置
*/
public List<StyleConfig> getAllStyles() {
// 1. 先查缓存
List<StyleConfig> cached = (List<StyleConfig>) redisTemplate.opsForValue().get(CACHE_KEY_STYLES);
if (cached != null) {
return cached;
}
// 2. 从 Python 获取
StylesResponse response = pythonClient.get("content-generate", "styles", StylesResponse.class);
List<StyleConfig> styles = response.getStyles();
// 3. 缓存 1 小时
redisTemplate.opsForValue().set(CACHE_KEY_STYLES, styles, 1, TimeUnit.HOURS);
return styles;
}
/**
* 根据 ID 获取风格
*/
public StyleConfig getById(String styleId) {
return getAllStyles().stream()
.filter(s -> s.getId().equals(styleId))
.findFirst()
.orElseThrow(() -> new BusinessException(ErrorCode.NOT_FOUND, "风格不存在: " + styleId));
}
/**
* 刷新缓存
*/
@Scheduled(fixedRate = 3600000)
public void refreshCache() {
try {
redisTemplate.delete(CACHE_KEY_STYLES);
redisTemplate.delete(CACHE_KEY_AUDIENCES);
getAllStyles();
getAllAudiences();
log.info("风格/人群配置缓存已刷新");
} catch (Exception e) {
log.error("刷新配置缓存失败", e);
}
}
}
6. 迁移计划
6.1 阶段划分
阶段 1: Python 端准备 (已完成 ✅)
├── [x] 实现 PromptRegistry
├── [x] 迁移所有 Prompt 到 YAML
├── [x] 实现 V2 引擎 (topic_generate, content_generate, poster_generate)
├── [x] 实现 /api/v2/aigc/execute 接口
└── [x] 删除旧的数据库访问代码
阶段 2: Python 端补充 (待实施)
├── [ ] 实现 /api/v2/aigc/config/styles 接口
├── [ ] 实现 /api/v2/aigc/config/audiences 接口
├── [ ] 完善 Prompt YAML 的 meta 信息
└── [ ] 添加接口文档
阶段 3: Java 端改造 (待实施)
├── [ ] 新增 StyleConfigService
├── [ ] 新增 AudienceConfigService
├── [ ] 改造 TopicGenerateServiceImpl
├── [ ] 改造 ContentGenerateServiceImpl
├── [ ] 改造 PosterGenerateServiceImpl
├── [ ] 更新 ExternalServicesConfig
└── [ ] 添加配置缓存机制
阶段 4: 联调测试 (待实施)
├── [ ] 单元测试
├── [ ] 集成测试
├── [ ] 性能测试
└── [ ] 回归测试
阶段 5: 上线切换 (待实施)
├── [ ] 灰度发布
├── [ ] 监控告警
├── [ ] 旧接口废弃
└── [ ] 文档更新
6.2 兼容性策略
过渡期间:
1. Python 端同时保留 V1 和 V2 接口
2. Java 端逐步切换到 V2 接口
3. 通过配置开关控制使用哪个版本
4. 完全切换后删除 V1 接口
配置示例:
external-services:
content-generate:
use-v2-api: true # 开关
7. 风险评估
| 风险 | 等级 | 影响 | 缓解措施 |
|---|---|---|---|
| Python 服务不可用 | 🔴 高 | 所有 AIGC 功能不可用 | 健康检查、自动重启、降级提示 |
| 配置缓存过期 | 🟡 中 | 风格/人群列表可能不一致 | 定时刷新、手动刷新接口 |
| 接口响应超时 | 🟡 中 | 用户体验差 | 合理超时设置、进度推送 |
| Prompt 渲染错误 | 🟡 中 | 生成内容质量差 | 变量验证、默认值、错误提示 |
| 数据对象字段缺失 | 🟢 低 | Prompt 渲染不完整 | 字段校验、默认值填充 |
8. 附录
8.1 数据对象字段规范
ScenicSpot (景区)
{
"id": 1,
"name": "天津冒险湾",
"description": "天津最大的水上乐园,拥有多种刺激水上项目和亲子设施",
"address": "天津市滨海新区海滨大道",
"location": "天津市",
"traffic_info": "地铁9号线直达,自驾可走津滨高速",
"highlights": ["水上过山车", "儿童戏水区", "漂流河"],
"opening_hours": "09:00-18:00",
"ticket_info": "成人票 199 元,儿童票 99 元",
"tips": "建议自带泳衣,园区内也有售卖"
}
Product (产品)
{
"id": 10,
"name": "家庭套票",
"price": 299,
"original_price": 399,
"description": "含2大1小门票,赠送储物柜",
"includes": ["2张成人票", "1张儿童票", "储物柜1个"],
"valid_period": "2025-01-01 至 2025-03-31",
"usage_rules": "需提前1天预约,入园当日有效"
}
Style (风格)
{
"id": "gonglue",
"name": "攻略风"
}
Audience (人群)
{
"id": "qinzi",
"name": "亲子向"
}
Topic (选题)
{
"index": 1,
"date": "2025-01-15",
"title": "寒假遛娃好去处",
"object": "天津冒险湾",
"product": "家庭套票",
"style": "攻略风",
"targetAudience": "亲子向",
"logic": "寒假期间家庭出游需求旺盛,水上乐园是热门选择"
}
8.2 错误码规范
| 错误码 | 说明 | HTTP 状态码 |
|---|---|---|
| ENGINE_NOT_FOUND | 引擎不存在 | 404 |
| INVALID_PARAMS | 参数校验失败 | 400 |
| PROMPT_NOT_FOUND | Prompt 不存在 | 404 |
| PROMPT_RENDER_ERROR | Prompt 渲染失败 | 500 |
| LLM_ERROR | LLM 调用失败 | 500 |
| TIMEOUT | 执行超时 | 504 |
9. 变更记录
| 版本 | 日期 | 作者 | 变更内容 |
|---|---|---|---|
| 1.0.0 | 2024-12-09 | Team | 初始版本 |