# Prompt Store 设计稿

## 目标

- 提示词使用独立的 prompt Supabase 存储，不复用当前业务主库的 SUPABASE_URL。
- 当前业务数据、任务状态、1688 账号、搜索结果仍然保留在现有主库。
- 提示词远程化只接管自然语言指令本身，不接管代码里的字段序列化、截图读取、消息拼装等运行逻辑。
- 首期支持版本化、环境隔离、模型范围匹配、本地缓存和回退到代码默认值。

## 环境变量约定

- PROMPT_SUPABASE_URL: 独立 prompt Supabase 项目地址。
- PROMPT_SUPABASE_SERVICE_ROLE_KEY: 仅服务端使用的 prompt Supabase service role key。
- PROMPT_ENV: 提示词目标环境，建议默认使用 prod。
- PROMPT_CACHE_TTL_MS: 本地缓存毫秒数，建议默认 300000。

说明：不要把现有 .env 里的 SUPABASE_URL 改成 prompt Supabase。当前主库仍应指向 xkxsqucfblmcsneiuezg，对应的 prompt 库单独走 PROMPT_SUPABASE_URL。

## 核心表设计

首期只需要两张核心表。

### prompt_templates

用途：保存稳定的 prompt 标识和元信息。

关键字段：

- prompt_key: 全局唯一键，代码侧只认这个值。
- module: 所属模块，例如 automation.search、chatbot.intent。
- scene: 业务场景，例如 page_review、round_3。
- content_format: 内容结构，决定 payload_json 的解析方式。
- description: 人类可读说明。
- is_enabled: 是否启用该模板。

### prompt_versions

用途：保存版本化的真实 prompt 内容。

关键字段：

- template_id: 关联 prompt_templates。
- target_env: 运行环境，建议 prod、staging、dev。
- provider_scope: 适配的模型供应商，默认使用 *。
- model_scope: 适配的模型名，默认使用 *。
- version: 模板版本号，按模板维度自增。
- status: draft、active、archived。
- payload_json: 真正的提示词内容，统一存 object。
- variables_json: 变量说明，统一存 array。
- checksum: 内容摘要，便于审计和排查。

## 查询匹配规则

服务端加载 prompt 时建议按以下优先级匹配 active 版本：

1. prompt_key + target_env + provider_scope 精确匹配 + model_scope 精确匹配。
2. prompt_key + target_env + provider_scope 精确匹配 + model_scope 为 *。
3. prompt_key + target_env + provider_scope 为 * + model_scope 为 *。
4. 若未命中，则回退到代码中的默认 prompt。

同一组 template_id + target_env + provider_scope + model_scope 只能有一条 active 版本。

## content_format 约定

建议首期只使用以下几种格式：

- text: payload_json 结构为 { "content": "..." }。
- text_template: payload_json 结构为 { "template": "...{{var}}..." }。
- chat_bundle: payload_json 结构为 { "system": "...", "user_template": "..." }。
- multimodal_bundle: payload_json 结构为 { "system": "...", "user_template": "...", "image_slots": ["..."] }。
- round_map: payload_json 结构为 { "rounds": { ... }, "generic_round": { ... } }。

说明：即使是单条文本，也建议统一放进 payload_json，而不是单独开 content 列。这样后续扩展字段不会改表。

## 当前 prompt key 清单

下面是首期应纳入独立 prompt Supabase 的 key 清单。

| Prompt Key | 当前来源 | 格式 | 首期范围 | 说明 |
| --- | --- | --- | --- | --- |
| automation.standardization.combined.system | automation/standardization/combined-standardization-contract.ts | text | P0 | 标准化和 1688 可搜索性联合判断的 system prompt。 |
| automation.standardization.keyword_semantic.system | automation/standardization/standardization-llm.ts | text | P0 | 关键词语义分析的 system prompt。 |
| automation.document_extraction.materials.system | automation/standardization/document-extraction-contract.ts | text | P0 | 从 GLM 原始文件输入中提取采购物料的 system prompt。 |
| automation.search.keyword_fusion.bundle | automation/keywords/keyword-selection.ts | multimodal_bundle | P0 | 图搜关键词融合，包含 system、步骤化 user template、两张图片槽位。 |
| automation.search.semantic_title_validation.bundle | automation/playwright/search-plan.js | chat_bundle | P0 | 标题语义校验，判断搜索词干扰项。 |
| automation.search.keyword_regeneration.bundle | automation/playwright/search-plan.js | chat_bundle | P0 | 搜索失败后的关键词重写。 |
| automation.search.hit_rate_fallback.bundle | automation/playwright/search-hit-rate-fallback.js | chat_bundle | P0 | 命中率语义复核，search-plan.js 和 search-table.js 都会复用。 |
| automation.search.page_review.bundle | automation/playwright/search-plan.js | multimodal_bundle | P0 | 搜索结果页视觉有效性判定，包含截图槽位。 |
| automation.search.candidate_filter.bundle | automation/playwright/search-plan.js | chat_bundle | P0 | 候选商品与 ai_keyword_analysis 对齐过滤。 |
| automation.search.best_image_selection.bundle | automation/playwright/search-plan.js | multimodal_bundle | P0 | 从候选图中挑选最佳图搜参考图。 |
| chatbot.intent.round_1.system | chatbot/src/llm-intent.js | text | P1 | 询问是否有现货。 |
| chatbot.intent.round_2.system | chatbot/src/llm-intent.js | text | P1 | 询问是否支持规格与起订量。 |
| chatbot.intent.round_3.system | chatbot/src/llm-intent.js | text | P1 | 提取价格与交期。 |
| chatbot.intent.round_4.system | chatbot/src/llm-intent.js | text | P1 | 判断国标与专票。 |
| chatbot.intent.generic_round.system | chatbot/src/llm-intent.js | text_template | P1 | 自定义漏斗轮次的通用 system prompt。 |

## 当前不建议单独入库的内容

以下内容首期建议仍保留在代码中，不单独作为 prompt 表记录：

- buildCombinedStandardizationUserMessageFromRaw 和 buildCombinedStandardizationUserMessageFromSource。
- analyzeProductForKeyword 里按字段逐行拼接 user message 的逻辑。
- chatbot/src/llm-intent.js 里 analyzeReply 的 user message 上下文拼接。
- search-plan.js 和 keyword-selection.ts 里与截图、候选列表、标题统计结果相关的数据准备逻辑。

原因：这些部分本质上是结构化数据序列化，而不是稳定的业务提示词文本。

## 当前重复或特殊项处理建议

- automation/playwright/search-table.js 与 automation/playwright/search-plan.js 存在大量重复 prompt。首期只以 search-plan.js 为主入口设计 key，search-table.js 后续复用同一 key。
- automation/standardization/human-fix-hint.ts 中的 HUMAN_FIX_HINT_PROMPT_REQUIREMENTS 和 HUMAN_FIX_HINT_PROMPT_EXAMPLE 当前被嵌入两个 system prompt。首期不单独拆成 fragment，直接并入两个 active version 即可。
- keyword-selection.ts 中的步骤 1、步骤 2、步骤 3 提示词建议作为一个 multimodal_bundle 的不同字段存入同一个 payload_json，而不是拆成多条模板。

## 推荐的 payload_json 形态

### text

```json
{
  "content": "你是一个建筑工程资深采购员..."
}
```

### chat_bundle

```json
{
  "system": "你是 1688 搜索结果命中率审核器，只返回 JSON。",
  "user_template": "你在做 1688 搜索结果命中率复核。\n目标搜索词: {{keyword}}\n抽样商品数: {{sample_count}}\n{{sample_text}}"
}
```

### multimodal_bundle

```json
{
  "system": "你是一个电商商品识别与命名专家。",
  "user_template": "请根据以下步骤完成判断，并仅输出要求的 JSON：\n{{step1}}\n\n{{step2}}\n\n{{step3}}",
  "image_slots": ["source_image", "search_result_screenshot"]
}
```

### text_template

```json
{
  "template": "你是一个采购助手 AI。当前是第 {{current_round}} 轮询问。\n本轮名称：{{round_name}}\n本轮发送话术：{{template_text}}\n{{pass_condition_line}}"
}
```

## 实施顺序建议

1. 先在独立 prompt Supabase 执行 supabase/sql/prompt-store-schema.sql。
2. 先只填充 prompt_templates 元数据，不急着一次性录入全部 prompt_versions。
3. 优先迁移 P0 范围：standardization、document extraction、keyword fusion、search-plan。
4. 迁移时按任务预取 prompt bundle，并把 prompt_key、version、checksum 记录到主业务库的任务结果里。
5. chatbot 提示词放到第二阶段。

## 首期边界

- 首期不在 prompt Supabase 中额外新增 runtime snapshot 表。
- 首期不做前端直接管理 prompt 的页面，因为当前登录态和 prompt 库不是同一个 Supabase 项目。
- 首期不修改现有主库的 llm_config 读写逻辑，prompt store 与 llm_config 并行存在。
