# Claude 开发指南

## 项目概述

这是一个基于 Reson Agent 框架的业务开发项目。项目包含：
- **Agent 框架源码**（只读，不可修改）
- **业务开发区域**（可自由开发）
- **基础设施服务**（按需使用）

## 🚨 重要约束

### Git 操作规范

**🚨 硬性规则：没有用户明确指令，绝对不执行 git commit / git push。**

**默认行为：**
- ❌ **不自动提交（commit）** — 必须等待用户明确说"提交"或"commit"才能执行
- ❌ **不自动推送（push）** — 必须等待用户明确说"推送"或"push"才能执行
- ❌ **不主动提议提交** — 完成代码修改后，汇报改动内容即可，不要主动问"要不要提交"
- ❌ **禁止以任何形式暗示/诱导提交** — 以下句式全部禁用：
  - "要不要我帮你提交/推送？"
  - "需要我现在提交推送吗？"
  - "是否需要提交这些修改？"
  - "改完后要不要一起提交？"
  - "现在可以推送了吗？"
  - 任何结尾带"提交/推送"问号的句子都是违规
- ✅ 改完代码只做两件事：(1) 汇报改了什么；(2) 停下，等用户指令
- ✅ 可以创建分支、查看状态、查看 diff
- ✅ 提交前必须向用户展示改动内容并等待确认

**正确流程：**
1. 完成代码修改
2. 展示改动摘要给用户
3. **等待用户主动说"提交"或"commit"**（不要主动询问）
4. 执行 `git add` + `git commit`
5. **等待用户主动说"推送"或"push"**（不要主动询问）
6. 执行 `git push`

**Commit message 格式规范（2026-06-08 用户确认）：**
- ❌ **不加** `Co-Authored-By: Claude ...` 行
- ❌ **不加** `🤖 Generated with [Claude Code](...)` 行
- ✅ 标题一行，模仿项目历史风格（`feat(xxx): ...` / `fix(xxx): ...`）
- ✅ 正文最多 3-5 行，只写"为什么/做了什么"的本质，不堆改动清单
- ✅ 信息越短越好，能一行说清就一行

### 禁止修改的目录（框架源码）

以下目录是 Agent 框架的核心源码，**在任何情况下都不得修改**：

```
agent/                  # Agent 框架核心代码
├── core/              # 核心运行逻辑
├── tools/             # 内置工具系统
├── llm/               # LLM 调用封装
├── trace/             # 轨迹追踪
├── skill/             # Skill 系统
├── cli/               # 命令行工具
├── utils/             # 工具函数
└── docs/              # 框架文档
```

**如果需要扩展功能，应该：**
- ✅ 在 `examples/[your_project]/tools/` 创建自定义工具
- ✅ 在 `examples/[your_project]/skills/` 创建自定义 Skill
- ✅ 通过配置文件调整框架行为
- ❌ 不要修改 `agent/` 目录下的任何文件

### 可以修改的目录（业务开发区域）

```
examples/              # 业务开发主目录
├── my_business/       # 你的业务项目
│   ├── config.py      # 业务配置
│   ├── run.py         # 运行入口
│   ├── task.prompt    # 任务描述
│   ├── tools/         # 自定义工具（可选）
│   ├── skills/        # 自定义 Skill（可选）
│   └── outputs/       # 输出目录
└── [other_examples]/  # 其他业务项目
```

### 基础设施目录（按需使用）

```
frontend/              # 前端可视化界面
gateway/               # API 网关
im-server/             # IM 服务器
im-client/             # IM 客户端
knowhub/               # 知识库服务
config/                # 全局配置
```

这些目录提供基础设施支持，通常不需要修改。如需调整配置，优先在业务项目的 `config.py` 中覆盖。

## 当前修改说明

### 已修改文件

1. **frontend/react-template/package-lock.json**
   - 升级 Semi UI 组件库：`2.56.0` → `2.92.2`
   - 目的：使用最新的 UI 组件特性
   - 影响范围：前端可视化界面

2. **examples/my_business/** (新增)
   - 业务开发示例项目
   - 包含：配置、运行脚本、任务描述
   - 当前任务：分析 `agent/core` 目录结构

3. **examples/auto_ad_placement/** (新增)
   - 腾讯广告自动化投放 Agent 系统
   - 基于腾讯广告 Marketing API v3.0
   - 包含：7个 Agent（main/audience/creative/budget/system_ops/monitor/data_analyst）
   - 工具：ad_api.py（API封装）、data_query.py（数据查询）、budget_calc.py（预算计算）等
   - Skills：ad_domain、budget_strategy、audience_strategy、creative_strategy、monitor_rules

4. **examples/auto_put_ad_mini/** (新增 — 当前活跃开发)
   - 小程序投流场景 — 面向 ROI 的广告调控 Agent
   - 定位：自动化系统的**最小业务单元**，专注"数据驱动的广告粒度决策"
   - 后续将作为模块接入 `auto_put_ad` 完整体系（无人工干预 → 自主决策 → 自学习反馈）

## 🎯 auto_put_ad_mini：当前阶段目标与领域知识

> **工作目录**: `examples/auto_put_ad_mini/`
> **业务场景**: 微信小程序投流（`MARKETING_CARRIER_TYPE_MINI_PROGRAM_WECHAT`）
> **核心目标**: 基于 ROI + 跑量（消耗）双维度，自动给出广告粒度的操作决策

### 阶段定位

本项目是整个自动化投放系统的**第一个业务单元**：

```
终极形态（auto_put_ad）          当前阶段（auto_put_ad_mini）
┌──────────────────────┐        ┌───────────────────────┐
│ 受众策略 Agent        │        │                       │
│ 创意策略 Agent        │        │  数据拉取 → ROI 计算  │
│ 预算策略 Agent        │        │       ↓               │
│ ★ 监控调控 Agent ◄───┼────────│  决策引擎（规则+策略） │
│ 数据分析 Agent        │        │       ↓               │
│ 系统运维 Agent        │        │  操作执行（API 调用）  │
│ 自学习/反馈环        │        │                       │
└──────────────────────┘        └───────────────────────┘
```

### 当前阶段决策范围（仅限以下操作）

| 决策类型 | 操作 | API 端点 | 触发条件 |
|---------|------|---------|---------|
| **调整出价** | 修改广告 bid_amount | `/v3.0/adgroups/update` | ROI 偏离目标、跑量不足/过快 |
| **暂停广告** | 修改 configured_status → DELETED/SUSPEND | `/v3.0/adgroups/update` | ROI 过低、长期无消耗、当日预算耗尽 |

> ⚠️ 当前阶段**不包含**：创建广告、修改定向、修改创意、调整预算分配。这些属于后续扩展。

### 数据维度与决策依据

Agent 需要拉取并分析以下三个时间粒度的数据：

| 时间粒度 | 用途 | 关键指标 |
|---------|------|---------|
| **小时级** | 实时监控，快速止损 | 最近 1-3 小时消耗速率、转化成本突变 |
| **日级** | 当天表现评估，出价微调 | 当日 ROI、当日消耗进度、当日转化量 |
| **周级** | 趋势判断，策略调整 | 7 日 ROI 均值、消耗趋势、转化成本波动 |

### 核心决策双维度

```
                    ROI 高
                      │
         ┌────────────┼────────────┐
         │  高ROI低量  │  高ROI高量  │
         │  → 提价放量  │  → 维持/微调 │
消耗少 ──┼────────────┼────────────┤── 消耗多
         │  低ROI低量  │  低ROI高量  │
         │  → 暂停观察  │  → 降价/暂停 │
         └────────────┼────────────┘
                      │
                    ROI 低
```

**决策逻辑（7 种 action，详见 config.py 和 skills/）**：
1. **pause** — 规则标记 roi_low + LLM综合判断（裂变/历史/tier组合/数据质量）→ 暂停
2. **bid_down** — 规则标记 bid_down_candidate + LLM权衡 → 降价 3%-5%
3. **bid_up** — 规则标记 bid_up_candidate（仅4-7天冷启动期）→ 提价 5%-10%
4. **scale_up** — 成熟+稳定+高消耗+ROI达标 → 建议扩量
5. **creative_adjust** — ROI达标但素材吸引力不足 → 建议换素材
6. **observe** — 数据不充分 / 刚调整过 → 观察等待
7. **hold** — 无异常信号 → 保持不变

### 先验策略规则

- **ROI 目标**：业务配置，通常 >= 1.0（每投入 1 元至少回收 1 元）
- **阈值基准**：ROI 基于渠道P50（全体 `channel_roi_p50`，即"动态ROI 7日均值"的中位数），裂变率基于同类人群包均值
- **出价调整步长**：提价 5%-10%，降价 3%-5%（提降分离，降价更保守）
- **冷启动保护**：<=3天极度保护，4-7天仅允许提价
- **最低消耗门槛**：日消耗 < 100 元的广告数据不具统计意义；降价需>=500元/天
- **出价边界**：下限 0.05 元，上限 1.00 元
- **关停线**：`ROI_LOW_FACTOR=0.75`，**提价线**：`BID_UP_ROI_FACTOR=1.05`，**降价线**：`BID_DOWN_ROI_FACTOR=0.90`
- **暂停后复活**：本阶段不处理，留给后续扩展

### ROI 计算公式

#### 简单 ROI（直接收益率）
```
ROI = 收入（GMV / 转化价值） ÷ 广告消耗（cost）

# 分时间粒度
hourly_roi = sum(hourly_revenue) / sum(hourly_cost)
daily_roi  = daily_revenue / daily_cost
weekly_roi = sum(7d_revenue) / sum(7d_cost)
```

#### 动态 ROI (7日均值)（考虑裂变效率稳定性的动态 ROI）

**⚠️ 重要：决策参考使用 动态 ROI (7日均值) 均值，而非单日值**

**公式定义**：
```
对每一天（需日消耗 ≥ 100 元才参与计算）：
  T0裂变系数 = T0裂变数（fission0_count） / 首层打开数（open_count）
  arpu       = 总收入 / 总回流人数

  当日裂变收益率 = T0裂变数 × arpu / cost
  当日回流倍数   = 总回流人数 / 首层打开数

7日滚动均值（min_periods=3，至少3天合格数据即可计算）：
  回流倍数_7日均值     = mean(当日回流倍数) over 7天
  T0裂变系数_7日均值   = mean(T0裂变系数) over 7天
  裂变效率稳定因子     = 回流倍数_7日均值 / T0裂变系数_7日均值

动态 ROI (7日均值) = 当日裂变收益率 × 裂变效率稳定因子
```

**变量含义说明**：
- **当日裂变收益率**：当天每投入 1 元，通过 T0 层裂变带来的直接收益
- **当日回流倍数**：当天每个首层用户平均带来多少总回流用户（含裂变）
- **裂变效率稳定因子**：7 日裂变效率的稳定性调整系数，反映长期裂变能力
- **动态 ROI (7日均值)**：综合考虑当日收益和 7 日裂变稳定性的动态 ROI

**两个关键指标**：
1. **动态 ROI (7日均值)**（单日值）：某一天的 动态 ROI (7日均值)，如 20260412 = 1.2071
2. **动态 ROI (7日均值) 均值**（多日均值）：最近 N 天每天的 动态 ROI (7日均值) 求平均，如 7 天均值 = 1.7295

**决策使用规则**：
- **广告级决策**：使用单个广告的 动态 ROI (7日均值)（需连续 7 天日消耗 ≥ 100 元）
- **人群包评估**：使用人群包整体的 动态 ROI (7日均值) 均值（用于整体质量评估）
- **关停阈值**：动态 ROI (7日均值) < 渠道P50 × ROI_LOW_FACTOR（详见 config.py）→ 关停

**计算层级差异**：
- **广告级 ROI**：先按广告聚合，再计算 ROI（用于单个广告决策）
- **人群包级 ROI**：先汇总所有广告数据，再计算 ROI（用于整体评估）
- 两者数值可能不同，用途不同，不能直接对比

### 关键数据字段映射（腾讯广告 Reporting API）

| 业务含义 | API 字段 | 说明 |
|---------|---------|------|
| 广告消耗 | `cost` | 单位：分 |
| 曝光量 | `view_count` | |
| 点击量 | `valid_click_count` | |
| 转化量 | `conversions_count` | 取决于 optimization_goal |
| 转化成本 | `cost_per_conversion` | cost / conversions_count |
| 千次曝光成本 | `thousand_display_price` | |
| 点击率 | `ctr` | |
| 当前出价 | `bid_amount`（广告属性） | 单位：分 |
| 广告状态 | `configured_status` / `system_status` | |

### 项目结构规划

```
examples/auto_put_ad_mini/
├── run.py                    # 运行入口
├── config.py                 # 业务配置（ROI 阈值、出价边界等）
├── presets.json              # 预设参数
├── prompts/
│   └── system.prompt         # Agent 系统 Prompt
├── tools/
│   ├── ad_api.py             # 腾讯广告 API 封装（拉数据 + 操作）
│   └── roi_calculator.py     # ROI 计算与决策建议生成
├── skills/
│   ├── ad_domain.md          # 业务模型：裂变模型、R值、ROI公式
│   ├── platform_rules.md     # 平台硬约束：oCPM学习期、调价上限
│   ├── decision_framework.md # 决策框架：角色 + 候选标记 + 年龄策略
│   ├── action_playbook.md    # 动作手册：7种action + 权衡原则
│   └── posterior_wisdom.md   # 后验经验：学习中断/置信度分级
└── outputs/                  # 运行输出
```

### 与 auto_put_ad 的关系

- `auto_put_ad_mini` 是 `auto_put_ad` 终极体系中 **Monitor/调控 Agent** 的前身
- 当前阶段独立运行，只做"数据→决策→执行"单向链路
- 后续接入完整体系后，将增加：反馈环（执行结果回馈策略）、跨 Agent 协作、自学习机制
- 工具层（`tools/ad_api.py`）设计时应考虑复用性，便于后续迁移

## 腾讯广告 3.0 关键 API 知识

**⚠️ 重要：本项目使用腾讯广告 Marketing API v3.0，与旧版(2.0)有根本性区别！**

### 层级结构（3.0 简化为 2 层）

| 旧版（2.0，已废弃） | 新版（3.0，当前使用） |
|---------------------|----------------------|
| 推广计划（Campaign） | ❌ 已移除 |
| 广告组（AdGroup） | ❌ 业务概念已被"广告"取代 |
| 广告（Ad）| ✅ **广告** — 3.0 顶层单位 |
| 广告创意 | ✅ **动态创意（Dynamic Creative）** |

### API 端点与业务概念的映射（避免混淆）

| 业务概念 | API 端点 | 返回字段 | 说明 |
|---------|---------|---------|------|
| **广告**（3.0 顶层） | `/v3.0/adgroups/add` | `adgroup_id` | 技术保留旧名，但业务是"广告" |
| **创意** | `/v3.0/dynamic_creatives/add` | `dynamic_creative_id` | 组件化创意 |

### 广告创建关键参数（`/v3.0/adgroups/add`）

本业务固定参数：
- `marketing_goal = MARKETING_GOAL_USER_GROWTH`（用户增长）
- `marketing_carrier_type`：`MARKETING_CARRIER_TYPE_MINI_PROGRAM_WECHAT` 或 `MARKETING_CARRIER_TYPE_WECHAT_OFFICIAL_ACCOUNT`
- `bid_mode = BID_MODE_OCPM`（oCPM 出价，固定）
- `optimization_goal`：`OPTIMIZATIONGOAL_PAGE_VIEW` 或 `OPTIMIZATIONGOAL_CLICK`
- `targeting.custom_audience`：自有人群包 ID 数组
- `targeting.age`：年龄区间数组，如 `[{"min": 25, "max": 35}]`
- `time_series`：336 位字符串（48段×7天，每段30分钟，"1"=投放）

### 3.0 核心策略变化

- 旧策略：堆砌大量"广告+创意"组合（拼基建）
- 新策略：**少广告、多素材**，同一广告下创建多个创意，系统自动优选（拼素材）
- 数据聚合在同一营销目标下，缩短冷启动周期

### API 限制

- 单账户 QPS 限制 10
- 批量操作单次最多 50 条
- 出价和预算单位：分（1元 = 100分）
- 审核时间：普通素材 2-4 小时，节假日可能延长至 24 小时
- 数据延迟：实时数据 15-30 分钟，转化数据 1-2 小时

## 开发规范

### 0. Python 环境规范

**每次执行 Python 脚本前，必须确保使用虚拟环境：**

```bash
# 检查虚拟环境是否存在
if [ ! -d ".venv" ]; then
    python3 -m venv .venv
fi

# 激活虚拟环境
source .venv/bin/activate

# 安装依赖（如需要）
pip3 install -r requirements.txt
```

- 使用 `pip3` 而非 `pip` 安装依赖
- 虚拟环境路径：`.venv/`
- 执行脚本统一使用：`.venv/bin/python3`

### 1. 创建新业务项目

```bash
# 在 examples/ 下创建新项目
mkdir -p examples/your_project/{tools,skills,outputs}
cd examples/your_project

# 复制模板文件
cp ../my_business/config.py .
cp ../my_business/run.py .
cp ../my_business/task.prompt .
```

### 2. 自定义工具开发

在业务项目下创建 `tools/` 目录：

```python
# examples/your_project/tools/my_tool.py
from agent.tools import tool, ToolResult

@tool(description="我的自定义工具")
async def my_custom_tool(param: str) -> ToolResult:
    """工具功能描述

    Args:
        param: 参数说明
    """
    # 实现逻辑
    return ToolResult(output="结果")
```

在 `run.py` 中导入：

```python
from tools.my_tool import my_custom_tool
```

### 3. 自定义 Skill 开发

在业务项目下创建 `skills/` 目录：

```markdown
<!-- examples/your_project/skills/my_skill.md -->
---
name: my-skill
description: 我的领域知识
category: custom
---

## 使用场景
- 场景描述

## 指导原则
- 原则说明
```

### 4. 配置管理

业务配置集中在 `config.py`：

```python
from agent.core.runner import RunConfig, KnowledgeConfig

RUN_CONFIG = RunConfig(
    model="qwen/qwen3.5-plus-02-15",
    temperature=0.3,
    max_iterations=50,
    tools=["read_file", "write_file", "your_custom_tool"],  # 工具白名单
    knowledge=KnowledgeConfig(
        enable_injection=False,
        enable_completion_extraction=False,
    )
)
```

## 协作约定

### Claude 助手行为准则

当协助开发时，Claude 应该：

1. **严格遵守目录约束**
   - 永远不修改 `agent/` 目录下的文件
   - 所有业务代码放在 `examples/[project]/` 下
   - 如需扩展功能，通过自定义工具/Skill 实现

2. **优先使用框架能力**
   - 查阅 `agent/README.md` 了解框架功能
   - 使用内置工具而非重复实现
   - 通过配置调整行为而非修改源码

3. **保持项目结构清晰**
   - 每个业务项目独立目录
   - 配置、代码、输出分离
   - 遵循框架推荐的目录结构

4. **提供清晰的说明**
   - 修改文件时说明原因和影响范围
   - 新增功能时提供使用示例
   - 配置变更时解释参数含义

### 开发者行为准则

1. **不要直接修改框架源码**
   - 如发现框架 bug，记录并反馈给框架维护者
   - 通过扩展机制实现自定义功能

2. **保持业务代码独立**
   - 每个业务项目独立目录
   - 避免跨项目依赖
   - 共享代码可提取到独立模块

3. **合理使用版本控制**
   - 框架源码变更通过 git submodule 或上游同步
   - 业务代码正常提交
   - 配置文件注意敏感信息

## 常见问题

### Q: 如何扩展框架功能？

A: 通过以下方式扩展，而不是修改源码：
- 自定义工具：`examples/[project]/tools/`
- 自定义 Skill：`examples/[project]/skills/`
- 配置覆盖：`config.py` 中的 `RunConfig`

### Q: 如何调试框架行为？

A: 使用框架提供的调试功能：
- 日志级别：`setup_logging(level="DEBUG")`
- 轨迹追踪：查看 `.trace/` 目录
- 前端可视化：启动 `frontend/react-template`

### Q: 如何更新框架版本？

A:
```bash
# 如果是 git submodule
git submodule update --remote agent

# 如果是直接克隆
cd agent && git pull origin main
```

## 🚨 开发注意事项和常见陷阱（auto_put_ad_mini）

### ⚠️ 关键问题1：决策CSV缺失字段（已反复出现多次！）

**问题描述**：
生成的决策报告（Excel/飞书表格）只显示7列基本字段（ad_id、action、dimension、reason、recommended_change_pct、current_bid、recommended_bid），缺少关键业务字段如：
- ad_name（广告名称）
- ad_age_days（投放天数）
- cost_7d_avg（7日均消耗）
- audience_tier（人群包）
- 动态ROI
- 等约13个字段

**根本原因**：
在 `tools/ad_decision.py` 的 `apply_decisions()` 函数中，决策DataFrame是直接从LLM输出字典构建的：
```python
df_out = pd.DataFrame(all_decisions)  # 只包含决策字段
```
LLM输出的字典只包含决策相关字段（action、reason等），不包含metrics CSV中的业务字段。如果不合并metrics CSV，输出的Excel/飞书表格就会缺失这些关键信息。

**历史记录**：
- 从初始commit（10b0b28）就存在这个bug，从未有合并逻辑
- 在开发过程中反复出现此问题多次
- 每次修改其他功能后，这个问题会再次显现

**正确解决方案**：
在 `apply_decisions()` 函数中，DataFrame创建后**立即合并**metrics CSV字段：

```python
# ===== 关键修复：合并 metrics CSV 中的字段 =====
try:
    df_metrics_full = pd.read_csv(metrics_csv)

    # 定义需要合并的字段
    merge_cols = [
        "ad_id", "account_id", "ad_name", "audience_tier", "create_time", "ad_age_days",
        "bid_amount", "yesterday_cost", "yesterday_revenue", "yesterday_roi",
        "cost_7d_total", "cost_7d_avg", "revenue_7d_total",
        "动态ROI", "动态ROI_7日均值", "cost_30d_total", "cost_30d_avg",
        "stable_spend_days_30d", "creative_count", "roi_valid_days"
    ]

    # 仅保留实际存在的列
    merge_cols = [c for c in merge_cols if c in df_metrics_full.columns]
    df_metrics_merge = df_metrics_full[merge_cols]

    # 左连接：保留所有决策，添加metrics字段
    df_out = df_out.merge(df_metrics_merge, on="ad_id", how="left", suffixes=("", "_metrics"))

    logger.info(f"已从 metrics CSV 合并 {len(merge_cols)} 个字段")
except Exception as e:
    logger.warning(f"合并 metrics 字段失败: {e}")
```

**关键位置**：
- 文件：`examples/auto_put_ad_mini/tools/ad_decision.py`
- 函数：`apply_decisions()`（约1324-1345行）
- 必须在 `df_out = pd.DataFrame(all_decisions)` **之后立即执行**

**预防措施**：
1. **在测试时验证列完整性**：每次测试后检查生成的Excel文件，确认所有OUTPUT_COLUMNS都存在
2. **不要删除关键字段**：避免使用 `df_out.drop(columns=["cost_7d_avg"])` 等操作删除业务字段
3. **代码审查检查点**：任何修改 `apply_decisions` 函数的变更，都必须验证字段合并逻辑是否完整
4. **端到端测试**：修改决策逻辑后，必须执行完整流程并检查飞书表格的列是否正确

---

### ⚠️ 关键问题2：年龄保护逻辑不完整

**问题描述**：
早期成长期（4-7天）的广告收到了LLM的降价（bid_down）或关停（pause）建议，触发兜底检查告警。这些广告应该只允许提价（bid_up）决策。

**根本原因**：
在 `get_ads_for_review()` 函数的年龄保护逻辑中，只检查了"是否有提价候选"，但没有检查"是否有其他类型的候选"：

```python
# ❌ 错误逻辑（不完整）
if not (bid_up_candidate or scale_up_candidate):
    # 没有提价候选就跳过，但没检查是否有其他候选
    normal_ads_count += 1
    continue
```

这导致如果广告同时满足 `roi_low=True` 和 `bid_up_candidate=False`，就会进入LLM评估，LLM可能建议降价或关停。

**正确解决方案**：
检查是否存在**任何非提价类型的候选**，如果有则排除：

```python
# ✅ 完整逻辑
elif ad_age <= EARLY_GROWTH_DAYS:  # 4-7天
    if not (bid_up_candidate or scale_up_candidate):
        # 检查是否有其他候选标记
        has_any_candidate = roi_low or decay_signal or bid_down_candidate
        if has_any_candidate:
            normal_ads_count += 1
            logger.debug(
                f"广告 {row['ad_id']} 处于早期成长期（{ad_age}天），"
                f"年龄保护：仅允许提价/扩量，其他候选已排除"
                f"（roi_low={roi_low}, decay={decay_signal}, bid_down={bid_down_candidate}）"
            )
            age_protected_skip = True
```

**关键位置**：
- 文件：`examples/auto_put_ad_mini/tools/ad_decision.py`
- 函数：`get_ads_for_review()`（约996-1020行）
- 在候选标记判断之后，LLM评估之前

**设计原则**：
- **三层架构**：年龄保护（硬约束） → 业务逻辑（LLM评估） → 兜底检查
- **5种候选标记**：roi_low、decay_signal、bid_up_candidate、bid_down_candidate、scale_up_candidate
- **规则+LLM协作**：规则确定**是否**评估，LLM确定**如何**操作

**验证方法**：
```bash
# 运行后检查兜底检查触发次数
grep "兜底检查触发" outputs/decision_log_*.log | wc -l
# 应该输出 0
```

---

### ⚠️ 关键问题3：硬编码日期问题

**问题描述**：
代码或测试中使用硬编码的日期参数（如 `--date 20260415`），导致无法使用最新数据。

**解决方案**：
1. 默认使用"昨天"日期：
```python
from datetime import datetime, timedelta
default_date = (datetime.now() - timedelta(days=1)).strftime("%Y%m%d")
```

2. 移除测试代码中的硬编码日期
3. 在CLAUDE记忆中清除特定日期的上下文

**预防措施**：
- 在代码审查时搜索硬编码日期：`grep -r "20260[0-9]" --include="*.py"`
- 配置文件中使用相对日期表达式

---

### 💡 调试技巧

**验证决策流程完整性**：
```bash
# 1. 检查metrics CSV列
head -1 outputs/metrics_*.csv | tr ',' '\n' | nl

# 2. 检查决策CSV列（应包含所有metrics字段）
head -1 outputs/reports/decisions_*.csv | tr ',' '\n' | nl

# 3. 对比OUTPUT_COLUMNS定义
grep "OUTPUT_COLUMNS = " tools/report_generator.py -A 20

# 4. 检查Excel文件实际列数
python3 -c "import pandas as pd; print(pd.read_excel('outputs/reports/approval_table_*.xlsx').columns.tolist())"
```

**验证年龄保护逻辑**：
```bash
# 检查兜底检查触发情况
grep "兜底检查触发" outputs/decision_log_*.log

# 应该输出空（0个触发）
```

---

### 📋 修改清单模板

每次修改决策相关代码后，执行以下检查：

- [ ] 运行完整流程：`cd examples/auto_put_ad_mini && .venv/bin/python3 execute_once.py`
- [ ] 验证metrics CSV包含所有字段：`head -1 outputs/metrics_*.csv`
- [ ] 验证决策CSV包含所有字段：`head -1 outputs/reports/decisions_*.csv`
- [ ] 打开Excel文件检查列是否完整（至少20列）
- [ ] 检查飞书消息格式是否正确（包含统计信息和表格）
- [ ] 验证年龄保护：`grep "兜底检查触发" outputs/decision_log_*.log` 应为空
- [ ] 检查无硬编码日期：`grep -r "20260[0-9]" --include="*.py" | grep -v ".venv"`

---

**文档更新**：2026-04-20
**记录原因**：这些问题已反复出现多次，必须明确文档化以防止再次发生

## 项目依赖

### 环境要求

- Python 3.10+
- Node.js 16+ (前端可视化)
- 必需的 API Key：
  - `QWEN_API_KEY` (通义千问)
  - `OPEN_ROUTER_API_KEY` (OpenRouter，可选)
  - `GEMINI_API_KEY` (Gemini，可选)

### 安装依赖

```bash
# Python 依赖
pip install -r requirements.txt

# 前端依赖（可选）
cd frontend/react-template
npm install
```

## 参考资源

- 框架文档：`agent/README.md`
- 示例项目：`examples/*/`
- API 文档：`agent/docs/`
- 前端界面：http://localhost:3000 (启动后)

---

**最后更新**: 2026-04-09
**维护者**: liulidong
