PROJECT_STRUCTURE — 腾讯广告实时调控模块
目录:examples/tencent_realtime_control/
定位:独立管理实时投放指标采集、CPM 状态判断和腾讯广告调控,不依赖广告创建或历史调价分析流程。
本目录实际承载 4 个相对独立的子系统,共用同一套基础设施(MySQL / ODPS / 腾讯 API / 飞书):
- 实时 CPM 调控(核心)— 按当天整体小时 CPM 阈值,自动提价/恢复/延后自动化广告
- 飞书运营命令控制 — 运营人员在指定飞书群 @机器人,用自然语言暂停/恢复/停止/查询广告
- 实时收入预测 — 预测当天最终收入,计算建议总成本(只读,不写腾讯接口)
- 日级 ROI 逐行审批(消费方)— 代码位于
examples/auto_put_ad_mini/roi_control/,本目录只启动轮询服务
一、子系统总览
┌────────────────────────────────────────────────────────────────┐
│ run_control_service.py │
│ (组合根 / Docker ad-control-service) │
│ │
│ ┌─────────────┐ ┌───────────────┐ ┌──────────────────────┐ │
│ │ FeishuCommand│ │RoiSheetApproval│ │ revenue_forecast_service││
│ │ Service │ │ Service │ │ (收入预测后台线程) │ │
│ └──────┬──────┘ └──────┬────────┘ └──────────┬───────────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ run_scheduler.py (10分钟调度循环) │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ run_once.py::run_cycle() │ │
│ │ CPM 读取 → 决策 → 执行 → 通知 │ │
│ └────────────────────────────────────────────────────────┘ │
└────────────────────────────────────────────────────────────────┘
▲ ▲ ▲
│ │ │
ODPS 小时CPM信号 腾讯 Marketing API MySQL 状态/审计
二、文件清单与职责
1. 入口 / 服务装配
| 文件 |
行数 |
职责 |
run_control_service.py |
85 |
生产常驻服务入口。初始化 schema 后并行启动:飞书命令 WebSocket、ROI 表格审批轮询、收入预测后台线程、CPM 调度循环 run_forever()。写操作受 RTC_APPLY_ENABLED / --apply 控制 |
run_scheduler.py |
112 |
CPM 调控的常驻调度循环。默认 12:00–21:00 每 600s 触发一次 run_cycle(),非投放时段休眠到次日 RTC_START_HOUR |
run_once.py |
798 |
单次幂等 CPM 调控周期(也是调度循环的核心逻辑所在)。包含决策状态机、执行、写后回读、报告落盘。支持 --apply/--at/--cpm-override/--force-refresh/--test-notification |
run_revenue_forecast.py |
41 |
单次收入预测执行入口,默认受运行时间窗约束,--ignore-runtime-window 可越过 |
init_db.py |
18 |
初始化数据库 schema(读取 schema.sql + 运行迁移) |
2. 实时 CPM 调控子系统
| 文件 |
行数 |
职责 |
realtime_config.py |
61 |
调控参数:投放时段、CPM 高低阈值、提价比例、分区延迟上限、DB 锁名等(全部可环境变量覆盖) |
odps_source.py |
74 |
CPM 信号源。从 loghubods.advertiser_data_da_hour 读当天整体小时 真实cpm_总,返回最新分区 |
tencent_client.py |
629 |
腾讯广告 API 读写封装。写后回读校验(默认 3 次×1s),读回不一致抛 PostWriteVerificationError。区分"未发出/被拒/结果未知"三类写失败 |
storage.py |
1312 |
MySQL 状态与审计存储(全模块最大)。ad 状态、账户范围、每日状态、操作日志、运营命令、暂停状态、收入预测等全部落库逻辑 |
feishu_notifier.py |
607 |
飞书在线表格通知。真实调价/延后/状态变更的窗口生成 xlsx + 发群;dry-run 与无动作不通知 |
fetch_daily_hourly_cpm.py |
60 |
数据检查工具:查看指定日期分时 CPM,落 CSV 并打印 |
决策逻辑(在 run_once.py):
decide(cpm, low, high):
cpm > high(250) → BOOST # 基础出价 ×1.05 上调,每天至多一次
low(190) ≤ cpm ≤ high → RESTORE # 恢复基础出价 + 恢复策略暂停的广告
cpm < low(190) → PAUSE # 恢复基础价,begin_date 延后到次日(不 SUSPEND)
3. 飞书运营命令子系统
| 文件 |
行数 |
职责 |
feishu_command_service.py |
395 |
飞书 WebSocket 入口。校验群/发送人/@机器人后串行处理消息;多轮补问草稿、命令预览、确认/取消 |
operator_commands.py |
198 |
确定性命令解析。ParsedCommand / CommandIntent 数据类,暂停/停止/恢复/状态/今日消耗等动作的规则解析 |
command_intent_parser.py |
218 |
受限 NLU。标准命令走确定性解析;RTC_NL_COMMAND_ENABLED=1 时模型只返回动作+范围 JSON,不可读库/调接口 |
operator_control.py |
899 |
命令预览与执行。预览冻结广告快照 + 冲突检测;确认后按账户/广告执行暂停/恢复/停止,含写后回读、状态机流转 |
account_status_query.py |
- |
从 ODPS 账号表读取全部当前账号,校验 token 后按投放起止日期和广告开关判断广告投放状态,生成飞书三 Sheet 报表与按钮卡片 |
today_spend_query.py |
79 |
只读的今日消耗汇总查询(全部/自动化/指定账户),逐账户调腾讯报表聚合 |
命令生命周期:解析 → 预览(冻结明细) → 10分钟内确认 → 执行 → 回读校验 → 审计落库
4. 实时收入预测子系统
| 文件 |
行数 |
职责 |
revenue_forecast.py |
57 |
领域数据类:RevenueObservation、RevenueTrendWindow、RevenueForecast |
revenue_forecast_config.py |
115 |
预测配置:运行时段、15分钟窗口数、目标成本比例、参数版本、DB 锁名 |
revenue_forecast_source.py |
250 |
ODPS 取数:ads_ad_own_package_detail_15min 15分钟收入序列、opengid_base_data 渠道成本、当日快照 |
revenue_speed_forecast.py |
243 |
加权速度预测算法。build_speed_samples → aggregate_speed_parameters(发布 P10/P50/P90)→ calculate_speed_forecast |
revenue_forecast_repository.py |
370 |
预测结果/观测/速度样本/已发布参数的 MySQL 持久化;参数版本发布后不可覆盖 |
revenue_forecast_job.py |
212 |
单轮预测周期:取数 → 质量校验(VALID/STALE/CORRECTED) → 载入参数 → 计算 → 落库 |
revenue_forecast_service.py |
77 |
后台调度线程(默认关闭,REVENUE_FORECAST_ENABLED=1 启用) |
build_revenue_speed_parameters.py |
118 |
从完整历史日构建并发布速度参数版本(--start-date/--end-date/--parameter-version) |
backtest_revenue_speed_forecast.py |
284 |
严格走步回测:每个预测日只用此前日期训练,只读 ODPS,不写 MySQL |
5. 实验 / 测试 / 配置
| 文件 |
行数 |
职责 |
adjust_bid_experiment_20260729.py |
284 |
一次性八广告分组调价实验(2026-07-29),默认只预览,带 bid_hold 释放与账户范围注册 |
test_feishu_natural_commands.py |
439 |
飞书命令链路单测:确定性解析、NLU 兜底、预览、调度器唤醒、暂停执行 |
test_revenue_forecast.py |
158 |
收入预测算法单测:速度样本构建、参数聚合、预测计算、异常分支 |
schema.sql |
420 |
全部表结构(见下) |
requirements.txt |
7 |
pandas / openpyxl / pyodps / pymysql / python-dotenv / requests |
.env.example |
76 |
环境变量样例(本地开发兼容;生产以仓库根 runtime.env.example 为准) |
__init__.py |
1 |
模块标记 |
6. 外部依赖(不在本目录)
| 路径 |
用途 |
examples/auto_put_ad_mini/roi_control/ |
日级 ROI 指标计算与审批表发布,run_control_service.py 启动其 RoiSheetApprovalService |
agent.tools.builtin.feishu.feishu_client |
框架内置飞书客户端(WebSocket / 发消息) |
三、数据库表(schema.sql)
| 表 |
用途 |
realtime_control_daily_state |
每日 CPM 调控状态(最后分区/决策/刷新时间) |
realtime_control_ad_state |
广告基准与状态:base_bid_fen、boosted_date、bid_hold、paused_by_strategy、operatorpause* |
realtime_control_account_scope |
实时调控显式账户范围(control_mode:FULL / PAUSE_ONLY) |
realtime_control_action_log |
每次真实动作的审计日志 |
operator_command / operator_command_item / operator_command_draft |
飞书运营命令、冻结明细、多轮草稿 |
roi_metric_run / roi_fission_parameter_* / roi_entity_snapshot / roi_action_item / roi_agency_delivery |
日级 ROI 指标运行与审批动作(ROI 子系统表,由 auto_put_ad_mini 写入) |
revenue_forecast_observation / result / speed_sample / speed_parameter |
收入预测的原始快照、版本化结果、历史速度样本、已发布参数 |
storage.py::initialize_schema() 会在建表后额外执行 realtime_control_ad_state 的增量列迁移。
四、关键数据流
CPM 调控(每 10 分钟)
ODPS 小时CPM (odps_source)
│ fetch_latest_cpm()
▼
run_cycle() ── 校验分区延迟 ≤2h / 时段 12–21 点
│ decide() → BOOST / RESTORE / PAUSE / CUTOFF / WAIT_DATA / OFF_HOURS
▼
execute_inventory_action()
├─ load_ad_states() 取每账户广告状态(MySQL)
├─ tencent.get_ads() 拉实时广告
├─ target_for_ad() 计算目标出价/状态/begin_date
└─ tencent.update_ad()/update_ad_begin_dates() 写腾讯(含回读校验)
▼
feishu_notifier.send_action_notification() ── 真实变更才发飞书在线表格
▼
upsert_ad_state() / insert_action_log() ── 状态与审计落库
飞书命令(消息触发)
飞书群 @机器人
▼ FeishuCommandService._authorized() 校验群/人/@
▼ understand():确定性解析 → (可选)LLM 兜底
▼ preview_write_command():冻结广告快照 + 冲突检测 → 回复预览
▼ 用户「确认 cmd_xxx」(10分钟内)
▼ execute_confirmed_command():锁内执行 → 写后回读 → 审计
五、配置要点(.env.example / realtime_config.py)
| 变量 |
默认 |
含义 |
RTC_START_HOUR / RTC_STOP_HOUR |
12 / 21 |
CPM 调控投放时段 |
RTC_POLL_SECONDS |
600 |
调控轮询间隔 |
RTC_HIGH_CPM / RTC_LOW_CPM |
250 / 190 |
提价 / 延后阈值 |
RTC_BID_UP_RATIO |
1.05 |
提价比例 |
RTC_APPLY_ENABLED |
0 |
总闸:所有入口默认 dry-run,为 1 才写腾讯 |
RTC_COMMAND_ENABLED / RTC_COMMAND_CHAT_ID / RTC_COMMAND_ALLOWED_OPEN_IDS |
- |
飞书命令开关与白名单 |
RTC_NL_COMMAND_ENABLED |
0 |
启用 LLM 兜底解析 |
REVENUE_FORECAST_ENABLED |
0 |
收入预测后台服务开关 |
REVENUE_SPEED_PARAMETER_VERSION |
revenue_speed_params_v1 |
已发布速度参数版本(只读) |
⚠️ 所有执行入口默认 dry-run,只有 --apply 或 RTC_APPLY_ENABLED=1 才调用腾讯写接口;--at / --cpm-override 仅限 dry-run(run_once.py 会校验)。
六、常用运行命令
# 初始化数据库
.venv/bin/python examples/tencent_realtime_control/init_db.py
# 单次 CPM 调控(dry-run)
.venv/bin/python examples/tencent_realtime_control/run_once.py
# 验证指定 CPM 分支
.venv/bin/python examples/tencent_realtime_control/run_once.py --at 2026-07-24T15:00:00 --cpm-override 260
# 真实执行
.venv/bin/python examples/tencent_realtime_control/run_once.py --apply
# 生产常驻服务(含飞书命令 + ROI 审批 + 收入预测 + CPM 循环)
RTC_APPLY_ENABLED=0 .venv/bin/python examples/tencent_realtime_control/run_control_service.py
# 收入预测:发布参数 / 单次执行 / 走步回测
.venv/bin/python examples/tencent_realtime_control/build_revenue_speed_parameters.py --start-date 20260727 --end-date 20260805 --parameter-version revenue_speed_params_v1
.venv/bin/python examples/tencent_realtime_control/run_revenue_forecast.py
.venv/bin/python examples/tencent_realtime_control/backtest_revenue_speed_forecast.py --history-start 20260727 --start-date 20260728 --end-date 20260805
# 查看当天分时 CPM
.venv/bin/python examples/tencent_realtime_control/fetch_daily_hourly_cpm.py
七、扩展指引
- 调整 CPM 阈值/时段 → 改
realtime_config.py 或环境变量,无需动业务代码
- 新增决策分支 → 在
run_once.py::decide() 与 target_for_ad() 中扩展,并补充 feishu_notifier._action_text() 的动作文案
- 新增飞书命令 →
operator_commands.py 定义动作常量与解析 → operator_control.py 实现预览/执行 → feishu_command_service.py 接入消息分发
- 训练新预测参数 → 用
build_revenue_speed_parameters.py 发布新版本号(发布后不可覆盖)
- 任何涉及腾讯写操作的新功能 → 复用
tencent_client.py 的写后回读校验与失败分类,不要裸调 API