TravelContentCreator/docs/ARCHITECTURE_ANALYSIS.md

37 KiB
Raw Blame History

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
  - 导致两端都需要数据库连接

问题

  1. 数据一致性风险
  2. 连接池资源浪费
  3. 部署复杂度增加
  4. 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()

问题

  1. 额外的数据库查询
  2. ID 可能无效或已删除
  3. 数据版本不一致

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 文件中

问题

  1. Java 端无法动态获取可用的风格/人群列表
  2. 前端下拉框的选项需要硬编码或单独维护
  3. 新增风格/人群需要两端同步修改

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 初始版本