# Prompt & Skill 重构：从"规则复读机"到"综合决策者"

## Context

**2026-04-22 深度复盘发现的架构问题**：

在验证"为什么37个ROI<关停线的广告未被pause"时，发现系统架构的根本性矛盾：

1. **规则层已做判断**：`ad_decision.py:424-428` 已检查 `ROI < P50×0.75` → 输出 `roi_low=True`
2. **Skill层重复要求**：`action_playbook.md:31,61,81` 又要求LLM检查 `动态ROI < 关停线（渠道P50×0.75）`
3. **结果**：LLM成了"规则复读机"，只是把规则层的判断用中文复述一遍

**正确的分工**（用户确认）：
- **规则 = 体检仪器**：测出"roi_low=True"（数值检测）
- **LLM = 医生**：综合全局信息判断是否真的应该pause（综合判断）
- LLM **不应该**重复检查"ROI是否<0.75"（这是规则的职责）

**技术数据**：
- 硬编码阈值重复：`0.75`在7个地方出现，`300元`在8个地方出现
- 规则与LLM边界模糊：同一个检查逻辑在规则、skill、护栏三层重复
- 缺失决策权衡原则：只有if-then决策树，没有"如何权衡多因素冲突"的原则

---

## 改动目标

**不改规则层代码**（`ad_decision.py`、`guardrails.py` 均不动），只改 prompt 和 skill：

1. **Skill 从 8 个精简到 5 个**：删除冗余、合并混淆、拆清边界
2. **移除硬编码阈值**：Skill中不再出现`0.75/0.90/1.05/300/500`等具体数值
3. **改为候选标记语义**：从"检查ROI是否<0.75"改为"理解roi_low=True的含义"
4. **补充多因素权衡**：异常识别、组合位置、调整效果评估等规则无法覆盖的判断
5. **清理 system.prompt**：移除与 skill 重复的硬编码内容，更新 skill 索引

---

## 新 Skill 架构（5 个）

| # | Skill 名称 | 文件名 | 内容定位 | 来源 |
|---|-----------|--------|---------|------|
| 1 | **ad-domain** | `ad_domain.md` | 我们的业务模型（裂变模型、R值、ROI公式、字段定义） | 改写自旧 ad-domain（去掉腾讯API参数） |
| 2 | **platform-rules** | `platform_rules.md` | 腾讯广告平台硬约束（oCPM学习期、调价上限、数据口径、API限制） | 改写自旧 tencent-ad-playbook（去掉我们的业务判断） |
| 3 | **decision-framework** | `decision_framework.md` | 角色定义 + 对比标准 + 候选标记含义 + 年龄策略 | 新建：整合旧 roi-baseline + age-protection + 新增角色定义 |
| 4 | **action-playbook** | `action_playbook.md` | 7种action说明 + 多因素权衡原则 + 异常识别 | 改写自旧 action-playbook（去硬编码阈值，加权衡原则） |
| 5 | **posterior-wisdom** | `posterior_wisdom.md` | 后验经验（学习中断、降价恢复、创意冷启动、置信度分级） | **不动** |

**删除 7 个旧 skill 文件**：
- `roi_strategy.md` — 纯索引，已无意义
- `roi_baseline.md` — 内容合并到 decision-framework
- 旧 `action_playbook.md` — 被新版替换
- `age_protection.md` — 内容合并到 decision-framework
- `guardrail_rules.md` — 用户明确不需要护栏 skill
- 旧 `ad_domain.md` — 被新版替换
- `tencent_ad_playbook.md` — 被 platform-rules 替换

---

## 改动清单

### 改动 1：新建 `skills/ad_domain.md`（改写）

**文件**：`examples/auto_put_ad_mini/skills/ad_domain.md`

**改动要点**：
- **保留**：裂变模型（L15-39）、核心字段定义（L41-66）、ROI公式（L68-88）、R值含义（L90-137）
- **删除 L9-13**：腾讯API参数（`marketing_carrier_type`、`bid_mode`、`optimization_goal`），移到 platform-rules
- **微调**：开头 description 改为"我们的业务模型与核心指标"，不再提"渠道"

---

### 改动 2：新建 `skills/platform_rules.md`（改写）

**文件**：`examples/auto_put_ad_mini/skills/platform_rules.md`

**改动要点**：
- **保留**：旧 tencent-ad-playbook 的 §1-§3（oCPM学习期、调价幅度上限、少广告多素材）、§5-§7（小程序场景、数据口径、执行层硬约束）
- **删除或移走旧 §4（素材疲劳）中属于我们业务判断的内容**：
  - "CTR+CVR 同时下跌>25% → 素材疲劳"这类带具体数值的判断 → 改为原则性描述
  - "首选 creative_adjust 而非 pause" → 这是 action 选择原则，移到 action-playbook
- **从旧 ad-domain 搬入**：L9-13 的平台参数（`marketing_carrier_type`、`bid_mode`、`optimization_goal`）
- **开头定位**：明确"这是腾讯广告 3.0 平台的投放规则，优先于任何业务决策"

---

### 改动 3：新建 `skills/decision_framework.md`（新建）

**文件**：`examples/auto_put_ad_mini/skills/decision_framework.md`

**核心内容**（整合 roi-baseline + age-protection + 新增角色定义）：

#### 第一章：你的角色 — 从规则复读机到综合决策者

```
规则层（体检仪器）     →  候选标记（体检报告）  →  你（医生）         →  护栏（药剂安全审查）
ad_decision.py 计算       roi_low=True 等         综合全局信息判断       guardrails.py 拦截矛盾
具体数值检测               传递给你                 是否真的要执行action    你不需要管
```

- ✅ **你的职责**：理解候选标记的业务含义，综合多因素做最终判断
- ❌ **不是你的职责**：重复检查具体数值（如"ROI是否<2.80"）

#### 第二章：对比标准（来自旧 roi-baseline）

| 维度 | 对比基准 | 数据字段 | 业务含义 |
|------|---------|---------|---------|
| 动态 ROI | **渠道P50** | `channel_roi_p50` | 全体广告"动态ROI_7日均值"的中位数 |
| 裂变率 | **同类均值** | `tier_fission_mean` | 同人群包 R 值的裂变水位 |
| CTR | **同类均值** | 同类 | 同人群的曝光质量 |

- ROI 必须看渠道（跨人群共享预算，低于P50=跑不出渠道平均效率）
- 裂变率必须看同类（不同R值人群裂变天然不同，跨人群比=比苹果和橘子）

#### 第三章：候选标记含义

**规则层已完成的工作**（不要重复检查）：
- `roi_low=True`：动态ROI 明显低于渠道P50（具体阈值由规则控制，你不需要知道数值）
- `bid_up_candidate=True`：ROI 明显优于渠道，且满足提价的年龄/消耗等前提
- `bid_down_candidate=True`：ROI 略低于渠道，消耗足够，近期无调价
- `scale_up_candidate=True`：成熟稳定 + 高消耗 + ROI 达标

**阈值参考**（仅理解规则逻辑用，不在reason中引用具体数值）：
- 关停线 ≈ 渠道P50 × 0.75
- 降价线 ≈ 渠道P50 × 0.90
- 提价线 ≈ 渠道P50 × 1.05
（以上数值可能调整，以规则输出的候选标记为准）

#### 第四章：年龄策略（来自旧 age-protection，去掉代码细节）

| 年龄段 | 天数 | 允许操作 | 禁止操作 | 原因 |
|--------|------|---------|---------|------|
| 冷启动期 | ≤3天 | 你不会看到这类广告（规则已排除） | — | 系统刚开始学习 |
| 早期成长期 | 4-7天 | bid_up / observe / creative_adjust | bid_down / pause | 降价会打断学习 |
| 成熟期 | >7天 | 全部action | bid_up（改走scale_up） | 稳定期不调出价 |

（注：年龄保护由规则层+护栏层双重实现，你不太可能收到违反年龄保护的广告）

---

### 改动 4：改写 `skills/action_playbook.md`

**文件**：`examples/auto_put_ad_mini/skills/action_playbook.md`

**整体结构**（4章）：

#### 第一章：候选标记 → action 映射（取代旧决策树）

不再是硬编码 if-then 决策树，改为候选标记驱动：

```
收到候选广告
  │
  ├─ bid_up_candidate=True → 评估是否 bid_up（第二章 §3）
  ├─ bid_down_candidate=True → 评估是否 bid_down（第二章 §2）
  ├─ roi_low=True → 评估是否 pause（第二章 §1）
  ├─ scale_up_candidate=True → 评估是否 scale_up（第二章 §4）
  └─ 以上都不满足 → hold 或 observe
```

#### 第二章：7种action说明（去硬编码阈值）

每种 action 结构统一为：
- **触发前提**：候选标记 + 你需要综合权衡的要点
- **pct 要求**：幅度范围
- **禁用于**：候选标记冲突场景（如 `bid_up_candidate=True` 时不能 bid_down）

**重点改写**：
- `pause`：原来是"ROI < P50×0.75 且 消耗≥300"，改为"roi_low=True + 综合权衡5要点（裂变对比、调整历史、tier组合、数据质量、异常识别）"
- `bid_down`：原来是"ROI在[0.75, 0.90)区间"，改为"bid_down_candidate=True + 权衡（是否近期调过价、是否换过创意、消耗稳定性）"
- `bid_up`：原来是两条硬编码分支A/B，改为"bid_up_candidate=True + 权衡（CTR是否正常、裂变是否真的强）"

#### 第三章：多因素权衡原则（全新内容）

这是规则无法覆盖的决策维度：

1. **裂变 vs ROI 双低**：ROI低 + 裂变低于同类50% = 真正的低效，强pause信号
2. **调整效果评估**：7天内已调过价但无改善 → observe等效果；连续3次调价无效 → pause
3. **tier组合位置**：该tier只剩这条跑量广告 → 谨慎pause，reason中建议"需配合新广告"
4. **异常识别模式**：
   - CTR正常但ROI低 → 可能是后端转化问题（非广告素材问题）
   - ROI突降（7日均值vs昨日相差>30%）→ 可能是数据异常
   - 高消耗+高ROI突然变低 → 可能是竞争加剧，非广告本身问题
5. **不确定时的默认策略**：observe > hold > bid_down > pause（保守优先）

#### 第四章：action优先级（简化版）

```
pause（明确低效）> bid_down（有改善空间）> creative_adjust > observe > hold
bid_up（冷启动期优质）> scale_up（成熟期优质）
```

---

### 改动 5：更新 `prompts/system.prompt`

**文件**：`examples/auto_put_ad_mini/prompts/system.prompt`

#### 5.1 自检表 B 改写（L177-185）

**当前**：硬编码 ROI 水位（`渠道P50 × 1.05`、`渠道P50 × 0.50`）
**改为**：候选标记一致性检查

```markdown
### B. action 与候选标记的一致性

| 候选标记 | 允许的 action | 禁止的 action | 原因 |
|---|---|---|---|
| `bid_up_candidate=True` | `bid_up`/`hold`/`observe` | ❌ `bid_down`/`pause` | 规则标记为"优质"，不应降价或关停 |
| `roi_low=True` | `pause`/`observe`/`hold` | ❌ `bid_up`/`scale_up` | 规则标记为"ROI严重偏低"，不应加码 |
| `bid_down_candidate=True` | `bid_down`/`hold`/`observe` | ❌ `bid_up` | 规则标记为"需降价"，不应提价 |

**你不需要重复检查具体ROI数值，规则已完成筛选。重点是综合其他因素做最终判断。**
```

#### 5.2 第六部分 reason 维度扩展（L204-211）

**当前**：6个维度
**改为**：8个维度（追加2个）

```markdown
7. **组合位置** — 该tier总消耗、广告数、本广告占比（tier唯一跑量广告需谨慎关停）
8. **异常识别** — CTR正常但ROI低？ROI突降>30%？（可能是后端问题或数据异常）
```

#### 5.3 第七部分 Skill 索引重写（L221-251）

**当前**：8个skill + 冲突优先级
**改为**：5个skill 简洁索引

```markdown
# 第七部分：投放经验知识库（Skills）

你有 5 份 skill 可以依据（由框架自动注入）：

| skill | 何时查阅 | 核心内容 |
|-------|---------|---------|
| **ad-domain** | 需要理解业务模型时 | 裂变模型、R值含义、ROI公式、核心字段定义 |
| **platform-rules** | **决策前先过一遍** | 腾讯oCPM学习期、调价上限、数据口径（平台硬约束 > 业务决策） |
| **decision-framework** ⭐ | **每次决策必读** | 你的角色定义、对比标准、候选标记含义、年龄策略 |
| **action-playbook** ⭐ | **选 action 前** | 7种action说明 + 多因素权衡原则 |
| **posterior-wisdom** | reason要解释"为什么观察"时 | 学习中断/降价恢复/创意冷启动/置信度分级 |

**冲突优先级**：platform-rules > decision-framework > action-playbook > posterior-wisdom > ad-domain
```

#### 5.4 清理"方向型反馈"硬编码（L283附近）

**当前**：`临时上下调全局阈值 10-20%`
**改为**：`根据反馈方向适度调整决策的保守/激进程度`（不写具体幅度）

---

### 改动 6：更新 `config.py` 的 skills 列表

**文件**：`examples/auto_put_ad_mini/config.py`（L53-62）

```python
skills=[
    "ad-domain",
    "platform-rules",        # 改名：tencent-ad-playbook → platform-rules
    "decision-framework",    # 新增：角色 + 标准 + 候选标记 + 年龄策略
    "action-playbook",       # 改写：去硬编码阈值 + 加权衡原则
    "posterior-wisdom",      # 不变
],
```

---

### 改动 7：更新 `CLAUDE.md` 过时信息

**文件**：`/Users/liulidong/project/agent/Agent/CLAUDE.md`

| 位置 | 当前说法 | 修正为 |
|------|---------|--------|
| "阈值基准" | "ROI 基于渠道均值（全体 `roi_mean`）" | "ROI 基于渠道P50（全体 `channel_roi_p50`，即中位数）" |
| "ROI计算公式" | "min_periods=7" | "min_periods=3" |
| "决策逻辑优先级" | 5种action（止损/预算/清理/降价/放量） | 更新为7种action |
| "先验策略规则" | 硬编码全部数值 | 添加"详见 config.py，此处仅概念说明" |

同步更新 `examples/auto_put_ad_mini/CLAUDE.md`：
| 位置 | 修正 |
|------|------|
| "决策逻辑（6种action）" | 更新为7种action（加 creative_adjust） |
| "阈值基准" | roi_mean → channel_roi_p50 |
| skills 列表 | 更新为5个新skill |

---

### 改动 8：删除旧 skill 文件

删除以下文件（内容已合并到新skill中）：
- `skills/roi_strategy.md`（纯索引，无独立价值）
- `skills/roi_baseline.md`（合并到 decision-framework）
- `skills/age_protection.md`（合并到 decision-framework）
- `skills/guardrail_rules.md`（用户明确不需要）
- `skills/tencent_ad_playbook.md`（被 platform-rules 替换）

---

## 不做的事

- ❌ 不改规则层代码（`ad_decision.py`）
- ❌ 不改护栏代码（`guardrails.py`）
- ❌ 不改数据注入（本次不补充预算/竞争等上下文数据）
- ❌ 不改 `agent/` 框架目录
- ❌ 不新建护栏skill（用户明确排除）

---

## 执行顺序

1. 新建 `skills/decision_framework.md`（全新文件）
2. 新建 `skills/platform_rules.md`（改写自 tencent-ad-playbook）
3. 改写 `skills/ad_domain.md`（去掉平台参数）
4. 改写 `skills/action_playbook.md`（去硬编码 + 加权衡原则）
5. 更新 `prompts/system.prompt`（自检表B + reason维度 + skill索引）
6. 更新 `config.py`（skills列表）
7. 更新两份 `CLAUDE.md`
8. 删除 5 个旧 skill 文件

---

## 验证

### 1. 静态检查（硬编码阈值是否移除）

```bash
cd examples/auto_put_ad_mini

# skill中不应有硬编码数值（仅decision-framework的"阈值参考"段允许带≈说明）
grep -n "0\.75\|0\.90\|1\.05" skills/*.md

# 不应有硬编码消耗门槛
grep -n "300元\|500元\|1000元" skills/action_playbook.md prompts/system.prompt
```

### 2. 端到端测试

```bash
cd examples/auto_put_ad_mini && .venv/bin/python3 execute_once.py
```

**对比指标**：
| 指标 | 改动前 | 期望 |
|------|--------|------|
| pause reason 包含裂变对比 | ~43% | ≥95% |
| observe reason 提及调整历史 | ~30% | ≥70% |
| reason 出现硬编码数值 | 多处 | 0处 |
| 兜底检查触发次数 | 0-2 | 0 |

### 3. Skill 文件数量检查

```bash
ls -la skills/*.md | wc -l
# 期望：5 个文件（ad_domain / platform_rules / decision_framework / action_playbook / posterior_wisdom）
```

---

## 回滚策略

```bash
cd examples/auto_put_ad_mini
git checkout HEAD -- \
  skills/ \
  prompts/system.prompt \
  config.py
# CLAUDE.md 更新无需回滚（修正过时信息）
```

---

## 后续扩展方向（本次不做）

1. **数据层补充全局上下文**：预算剩余、tier总消耗/广告数、市场环境
2. **Skill层补充**：预算约束下的优先级分配、时间节点策略
3. **验证层增强**：ReasonQualityGuardrail（检查reason是否包含必要元素）
