sino-bc-cli 1.0.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +256 -0
- package/dist/affordance/auth.md +31 -0
- package/dist/affordance/bill.md +48 -0
- package/dist/affordance/biz-line-ai-strategy.md +35 -0
- package/dist/affordance/biz-line-metrics.md +47 -0
- package/dist/affordance/biz-line.md +84 -0
- package/dist/affordance/common-file.md +25 -0
- package/dist/affordance/dashboard.md +75 -0
- package/dist/affordance/dict.md +28 -0
- package/dist/affordance/document.md +67 -0
- package/dist/affordance/im.md +91 -0
- package/dist/affordance/invoice.md +49 -0
- package/dist/affordance/media.md +17 -0
- package/dist/affordance/organization.md +47 -0
- package/dist/affordance/project-analysis.md +95 -0
- package/dist/affordance/project.md +321 -0
- package/dist/affordance/quota.md +19 -0
- package/dist/affordance/reconciliation.md +41 -0
- package/dist/affordance/report.md +75 -0
- package/dist/affordance/sso-team-group.md +30 -0
- package/dist/affordance/task.md +148 -0
- package/dist/affordance/tenant.md +17 -0
- package/dist/affordance/user.md +41 -0
- package/dist/affordance/wallet.md +100 -0
- package/dist/api-doc/README.md +67 -0
- package/dist/api-doc/custom/template.md +0 -0
- package/dist/api-doc/oapi/auth.md +61 -0
- package/dist/api-doc/oapi/bill.md +130 -0
- package/dist/api-doc/oapi/biz-line-ai-strategy.md +119 -0
- package/dist/api-doc/oapi/biz-line-metrics.md +419 -0
- package/dist/api-doc/oapi/biz-line.md +382 -0
- package/dist/api-doc/oapi/common-file.md +50 -0
- package/dist/api-doc/oapi/dashboard.md +218 -0
- package/dist/api-doc/oapi/dict.md +49 -0
- package/dist/api-doc/oapi/document.md +182 -0
- package/dist/api-doc/oapi/im.md +278 -0
- package/dist/api-doc/oapi/invoice.md +129 -0
- package/dist/api-doc/oapi/media.md +17 -0
- package/dist/api-doc/oapi/organization.md +94 -0
- package/dist/api-doc/oapi/project-analysis.md +364 -0
- package/dist/api-doc/oapi/project.md +1114 -0
- package/dist/api-doc/oapi/quota.md +21 -0
- package/dist/api-doc/oapi/reconciliation.md +98 -0
- package/dist/api-doc/oapi/report.md +254 -0
- package/dist/api-doc/oapi/sso-team-group.md +54 -0
- package/dist/api-doc/oapi/task.md +528 -0
- package/dist/api-doc/oapi/tenant.md +17 -0
- package/dist/api-doc/oapi/user.md +98 -0
- package/dist/api-doc/oapi/wallet.md +275 -0
- package/dist/generated/api-catalog.json +39681 -0
- package/dist/generated/api-directory-index.json +1509 -0
- package/dist/index.js +2 -0
- package/dist/skill-manifest.json +336 -0
- package/dist/skills/biz-line-strategy-generate/SKILL.md +122 -0
- package/dist/skills/biz-line-strategy-generate/references/ai-strategy-prompt.md +50 -0
- package/dist/skills/biz-line-strategy-generate/references/api-flow.md +155 -0
- package/dist/skills/biz-line-strategy-generate/references/four-strategies.md +58 -0
- package/dist/skills/biz-line-strategy-generate/references/metrics.md +119 -0
- package/dist/skills/biz-line-strategy-generate/references/output-excel.md +63 -0
- package/dist/skills/biz-line-strategy-generate/references/runtime.md +127 -0
- package/dist/skills/biz-line-strategy-generate/references/spec.md +500 -0
- package/dist/skills/biz-line-strategy-generate/scripts/ai_strategy.py +89 -0
- package/dist/skills/biz-line-strategy-generate/scripts/build_report.py +629 -0
- package/dist/skills/biz-line-strategy-generate/scripts/cleanup.py +87 -0
- package/dist/skills/biz-line-strategy-generate/scripts/cli_json.py +705 -0
- package/dist/skills/biz-line-strategy-generate/scripts/fetch_data.py +449 -0
- package/dist/skills/biz-line-strategy-generate/scripts/run_workflow.py +402 -0
- package/dist/skills/biz-line-strategy-generate/scripts/strategy_output.py +556 -0
- package/dist/skills/biz-line-strategy-generate/scripts/submit_tags.py +32 -0
- package/dist/skills/biz-line-strategy-generate/scripts/summarize.py +932 -0
- package/dist/skills/biz-line-strategy-generate/scripts/test_ai_strategy.py +235 -0
- package/dist/skills/biz-line-strategy-generate/scripts/test_cli_json.py +97 -0
- package/dist/skills/biz-line-strategy-generate/scripts/test_database_output.py +904 -0
- package/dist/skills/biz-line-strategy-generate/scripts/test_pipeline.py +253 -0
- package/dist/skills/biz-line-strategy-generate/scripts/test_strategy_rules.py +224 -0
- package/dist/skills/biz-line-strategy-generate/scripts/test_tag_submission.py +238 -0
- package/dist/skills/biz-line-strategy-generate/scripts/test_workflow.py +1233 -0
- package/dist/skills/sino-bc-cli/SKILL.md +62 -0
- package/dist/skills/sino-bc-cli/domains/sino-bc-auth/SKILL.md +36 -0
- package/dist/skills/sino-bc-cli/domains/sino-bc-bill/SKILL.md +48 -0
- package/dist/skills/sino-bc-cli/domains/sino-bc-biz-line/SKILL.md +58 -0
- package/dist/skills/sino-bc-cli/domains/sino-bc-biz-line/references/common-mistakes.md +7 -0
- package/dist/skills/sino-bc-cli/domains/sino-bc-biz-line/references/enums.md +13 -0
- package/dist/skills/sino-bc-cli/domains/sino-bc-biz-line-ai-strategy/SKILL.md +46 -0
- package/dist/skills/sino-bc-cli/domains/sino-bc-biz-line-metrics/SKILL.md +46 -0
- package/dist/skills/sino-bc-cli/domains/sino-bc-common-file/SKILL.md +44 -0
- package/dist/skills/sino-bc-cli/domains/sino-bc-dashboard/SKILL.md +50 -0
- package/dist/skills/sino-bc-cli/domains/sino-bc-dict/SKILL.md +48 -0
- package/dist/skills/sino-bc-cli/domains/sino-bc-document/SKILL.md +53 -0
- package/dist/skills/sino-bc-cli/domains/sino-bc-im/SKILL.md +62 -0
- package/dist/skills/sino-bc-cli/domains/sino-bc-invoice/SKILL.md +48 -0
- package/dist/skills/sino-bc-cli/domains/sino-bc-media/SKILL.md +40 -0
- package/dist/skills/sino-bc-cli/domains/sino-bc-organization/SKILL.md +46 -0
- package/dist/skills/sino-bc-cli/domains/sino-bc-project/SKILL.md +112 -0
- package/dist/skills/sino-bc-cli/domains/sino-bc-project-analysis/SKILL.md +61 -0
- package/dist/skills/sino-bc-cli/domains/sino-bc-project-analysis/references/analysis-workflow.md +21 -0
- package/dist/skills/sino-bc-cli/domains/sino-bc-project-analysis/references/filters-and-metrics.md +30 -0
- package/dist/skills/sino-bc-cli/domains/sino-bc-quota/SKILL.md +44 -0
- package/dist/skills/sino-bc-cli/domains/sino-bc-reconciliation/SKILL.md +47 -0
- package/dist/skills/sino-bc-cli/domains/sino-bc-report/SKILL.md +53 -0
- package/dist/skills/sino-bc-cli/domains/sino-bc-sso-team-group/SKILL.md +45 -0
- package/dist/skills/sino-bc-cli/domains/sino-bc-task/SKILL.md +73 -0
- package/dist/skills/sino-bc-cli/domains/sino-bc-task/references/state-machine.md +18 -0
- package/dist/skills/sino-bc-cli/domains/sino-bc-tenant/SKILL.md +34 -0
- package/dist/skills/sino-bc-cli/domains/sino-bc-user/SKILL.md +57 -0
- package/dist/skills/sino-bc-cli/domains/sino-bc-wallet/SKILL.md +55 -0
- package/dist/skills/sino-bc-cli/references/domain-index/module-8534789.md +53 -0
- package/dist/skills/sino-bc-cli/references/domain-index/module-8551546.md +70 -0
- package/dist/skills/sino-bc-cli/references/domain-index/module-8562638.md +13 -0
- package/dist/skills/sino-bc-cli/references/domain-index/module-8566367.md +13 -0
- package/dist/skills/sino-bc-cli/references/domain-index/module-8581524.md +17 -0
- package/dist/skills/sino-bc-cli/references/domain-index/module-8601540.md +13 -0
- package/dist/skills/sino-bc-cli/references/domain-index/module-8614891.md +33 -0
- package/dist/skills/sino-bc-cli/references/domain-index/module-8621792.md +17 -0
- package/dist/skills/sino-bc-shared/SKILL.md +31 -0
- package/dist/skills/sino-bc-shared/references/auth-recovery.md +36 -0
- package/dist/skills/sino-bc-shared/references/config-and-env.md +60 -0
- package/dist/skills/sino-bc-shared/references/output-contract.md +86 -0
- package/dist/skills/sino-bc-shared/references/skill-lifecycle.md +17 -0
- package/dist/skills/sino-bc-shared/references/tenant-context.md +21 -0
- package/dist/skills/sino-bc-shared/references/write-approval.md +16 -0
- package/package.json +70 -0
- package/scripts/postinstall.cjs +36 -0
|
@@ -0,0 +1,500 @@
|
|
|
1
|
+
# 业务线策略生成
|
|
2
|
+
|
|
3
|
+
## Purpose
|
|
4
|
+
|
|
5
|
+
为业务线策略生成技能规定可复用的分析、Excel 导出与批量执行行为,保证多条业务线运行时有明确的并发上限、独立结果和失败信息,并在每条任务结束后仅保留验证通过的最终文件,避免临时数据持续堆积或误删其他任务产物。
|
|
6
|
+
|
|
7
|
+
## Requirements
|
|
8
|
+
|
|
9
|
+
### Requirement: 统一生成入口与业务线隔离
|
|
10
|
+
|
|
11
|
+
技能 MUST 提供覆盖查询、拉数、分析、校验、导出和清理的统一入口。单业务线与多业务线 MUST 使用相同分析规则。输入 MUST 支持名称查找和显式业务线 ID 列表;批量候选 MUST 按 ID 去重。名称匹配不唯一时 MUST 明确报告歧义而非自动取第一条。业务请求 MUST 复用现有 CLI,MUST NOT 手写网关 HTTP 或绕过身份约束。
|
|
12
|
+
|
|
13
|
+
#### Scenario: 批量重复 ID 不重复生成
|
|
14
|
+
- **GIVEN** 输入列表包含相同业务线 ID 两次
|
|
15
|
+
- **WHEN** 执行统一入口
|
|
16
|
+
- **THEN** 该业务线只执行一次,拥有独立工作目录和唯一最终 Excel
|
|
17
|
+
|
|
18
|
+
#### Scenario: 名称存在歧义
|
|
19
|
+
- **GIVEN** 名称查询返回多条候选
|
|
20
|
+
- **WHEN** 解析单业务线目标
|
|
21
|
+
- **THEN** 返回候选与歧义错误,不启动这些候选的投放拉数任务
|
|
22
|
+
|
|
23
|
+
### Requirement: 拉数和AI阶段逐条滑动补位
|
|
24
|
+
|
|
25
|
+
工作流MUST默认拉数(含业务预检、分页及固定分析)最多3条,标签/AI至导出/入库/清理最多3条,总在途(含等待)最多6条。--concurrency仅接受1/2/3,作为每阶段上限,总在途最多为两倍。初始MUST仅按拉数名额启动任务;任意一条准备好转入AI阶段时MUST立即归还拉数名额,调度器在本次循环补拉下一条,MUST NOT等待另外两条同时转阶段。AI已满时允许本条在总上限内持有独立数据等待,不另建无界审核队列;每条内部CLI请求及分页仍串行,MUST NOT简单将拉数并发改成6。
|
|
26
|
+
|
|
27
|
+
只有取得AI名额后MUST创建审核请求并启动7/15分钟阶段计时;交接等待MUST独立计入timings.wait_ai_slot。单条MUST保留原有try/finally生命周期,正常、失败或取消均在清理结束后释放持有名额及总在途名额;阶段等待取消MUST不发审核请求。目录、身份、候选编号及结果独立,其他条目正常推进。Python线程池不保证宿主模型真正并行,MUST NOT宣称已恢复子Agent或实测提速。
|
|
28
|
+
|
|
29
|
+
#### Scenario: 单条转阶段立即补拉
|
|
30
|
+
- **GIVEN** A/B/C正在拉数,B/C仍未完成
|
|
31
|
+
- **WHEN** A完成固定分析并进入标签/AI阶段
|
|
32
|
+
- **THEN** A仍未交付时D已开始拉数,MUST NOT等待B/C完成
|
|
33
|
+
|
|
34
|
+
#### Scenario: 两个阶段与全局上限
|
|
35
|
+
- **GIVEN** 三条业务线占用AI阶段,另三条已预取并等待
|
|
36
|
+
- **WHEN** 尚有后续业务线
|
|
37
|
+
- **THEN** 不启动第七条,不提前为等待者创建审核请求;AI名额释放后继续滑动处理
|
|
38
|
+
|
|
39
|
+
#### Scenario: 缩小并发与取消等待
|
|
40
|
+
- **WHEN** concurrency为1或2
|
|
41
|
+
- **THEN** 两阶段分别至多1或2,总在途至多2或4
|
|
42
|
+
- **WHEN** 用户取消等待AI名额的业务线
|
|
43
|
+
- **THEN** 不发该条标签/AI请求,清理自己的目录,已有条目按原规则收尾
|
|
44
|
+
|
|
45
|
+
#### Scenario: 非法并发参数不发起请求
|
|
46
|
+
- **WHEN** concurrency为0或大于3
|
|
47
|
+
- **THEN** 启动业务任务前拒绝,不创建业务请求
|
|
48
|
+
|
|
49
|
+
### Requirement: 分页与失败回包必须完整校验
|
|
50
|
+
|
|
51
|
+
维度与成效请求 MUST 使用 `size=1000`,最多获取 200 页;仍未取全时 MUST 明确失败,不能生成不完整结果。
|
|
52
|
+
|
|
53
|
+
每页 CLI 回包 MUST 直写 `<stem>.pN.out.json` 并检查退出码、信封和分页总数。拉数成功后 MUST 写 `<stem>.pages.json`(含 `total`、`pages`、每页 `counts`)。拉数过程 MUST 只在内存保留当前页与行数累计,MUST NOT 将各页累积为全表 list,MUST NOT 再写一份全表 `merged.json`。汇总 MUST 按 `pages.json` 顺序逐页 yield 行;`pages.json` 缺失但存在 `p2` 及之后页文件时 MUST 失败,不得只读第一页。`share_map` / `metric_value` / 覆盖日期 / 出价快照 MUST 一次扫描完成,MUST NOT 为占比或比率把全表物化成 list。learning 的新增对象识别只保留新增行参与判断;导出明细 MUST 覆盖持续对象,并按维度、渠道、ID 聚合指标,不能逐页原样复制数据行。开始分析前的清单校验 MUST 只核对该索引与 manifest 的 `total`/`counts`,MUST NOT 为校验整表加载。广告/广告组名称片段分布 MUST 只用原始展示名,MUST NOT 把空名回退成 ID 再拆词。异常、解析失败、未到总数即遇空页、达到分页上限仍未取全,MUST 阻止该业务线生成成功报告,且 MUST NOT 写下完整 `pages.json`。CLI stderr 错误 MUST 保留到本次任务结果摘要,而非当作无数据。其他业务线 MUST 可以继续执行。
|
|
54
|
+
|
|
55
|
+
#### Scenario: 后续页失败不导出部分结果
|
|
56
|
+
- **GIVEN** 首页成功且声明仍有下一页
|
|
57
|
+
- **WHEN** 后续页调用失败或返回空页但累计数量不足
|
|
58
|
+
- **THEN** 该业务线失败,不将不完整数据生成最终 Excel,不留下完整 `pages.json`,其他业务线继续执行
|
|
59
|
+
|
|
60
|
+
#### Scenario: 多页成功只落分页文件
|
|
61
|
+
- **GIVEN** 某 stem 两页合计 3 行且 `data.total` 为 3
|
|
62
|
+
- **WHEN** 拉数成功
|
|
63
|
+
- **THEN** 目录中有 `stem.p1.out.json`、`stem.p2.out.json` 与 `stem.pages.json`(`total=3`、`counts=[2,1]` 或等价分页)
|
|
64
|
+
- **AND** 不存在 `stem.merged.json`
|
|
65
|
+
- **AND** 汇总能从页文件读出这 3 行
|
|
66
|
+
- **AND** `share_map` / `metric_value` 对一次性迭代器也能得到与 list 相同的占比和比率
|
|
67
|
+
|
|
68
|
+
### Requirement: 指标与周期口径固定
|
|
69
|
+
|
|
70
|
+
统一入口 MUST 在批次开始时按执行机器当地日期解析默认周期:本期为上周一至周日,上期为上上周一至周日。MUST NOT 使用业务线返回的周期。用户指定日期 MUST 按期成对覆盖,未指定的期保持其自然周默认值;不合法日期 MUST 报错而非静默回退。查询、Excel 及数据库本期字段 MUST 使用同一解析结果。
|
|
71
|
+
|
|
72
|
+
#### Scenario: 自然周默认与业务线周期不同
|
|
73
|
+
- **GIVEN** 执行日期为 2026-09-22,业务线返回本期 2026-09-07~2026-09-13
|
|
74
|
+
- **WHEN** 用户没有指定日期
|
|
75
|
+
- **THEN** 使用本期 2026-09-14~2026-09-20、上期 2026-09-07~2026-09-13,保存本期字段与此一致
|
|
76
|
+
|
|
77
|
+
#### Scenario: 用户只覆盖本期
|
|
78
|
+
- **GIVEN** 用户提供完整本期起止日期但未提供上期
|
|
79
|
+
- **WHEN** 解析周期
|
|
80
|
+
- **THEN** 本期使用用户日期,上期仍为执行日期的上上周一至周日
|
|
81
|
+
|
|
82
|
+
分析 MUST 只支持飞书「指标」sheet 的 29 项指标:三渠道成效接口 12 个基础指标与按该 sheet 公式计算的 17 个衍生指标;等价别名或等价公式不算新指标。基础值求和后再计算比率;表外指标即使能推导,也 MUST 判“核心指标不支持”,不能用默认 CPI 替代。learning 样本门槛只要求本期消耗大于0美元;MUST NOT 限制最低投放天数或最低安装量。指标本身缺失或分母为零时仍待观察。
|
|
83
|
+
|
|
84
|
+
有实际上期记录且核心指标可比时 MUST 仅按改善幅度判断:达到2%(包含边界)有效,未达到2%改善无效,与是否满足阈值无关。全部请求渠道的上期成效均无记录时 MUST 按附带阈值判断,达标为有效、未达标为无效,无阈值则待观察。上期有记录但指标缺失或为0 MUST 待观察,不冒充无上期。固定说明、指标方向、币种与解析约束见 metrics.md。
|
|
85
|
+
|
|
86
|
+
请求周期与实际返回的数据覆盖范围 MUST 分别展示。数据未覆盖完整请求周期时 MUST 提示不完整,MUST NOT 将较短周期消耗下降直接解释为主动减预算。新增部分成效 MUST 单独聚合,MUST NOT 将业务线整体环比宣称为单一动作的因果效果。
|
|
87
|
+
|
|
88
|
+
#### Scenario: 人民币 CPA 与美元安装数据不可直接对标
|
|
89
|
+
- **GIVEN** 客户目标是人民币 CPA 与次日留存,接口返回美元消耗和平台安装量
|
|
90
|
+
- **WHEN** 缺少汇率、CPA 定义或留存数据
|
|
91
|
+
- **THEN** 仅计算已支持的观察指标,明确客户 KPI 暂不可判定,不生成 CPM 默认达标结论
|
|
92
|
+
|
|
93
|
+
#### Scenario: 本期六天与上期七天
|
|
94
|
+
- **GIVEN** 请求两个七天周期,但本期只返回六个日期
|
|
95
|
+
- **WHEN** 生成策略及 learning
|
|
96
|
+
- **THEN** 展示请求日期和实际覆盖日期,并提示消耗总额比较存在周期差异
|
|
97
|
+
|
|
98
|
+
### Requirement: 对象与明细按稳定标识统计
|
|
99
|
+
|
|
100
|
+
广告和广告组 MUST 按渠道及 ID 判断新增、暂停、持续,MUST NOT 仅按名称去重。完整明细 MUST 保留同名不同 ID 的记录,所有维度枚举包含可计算的本期与上期指标。两期集合差异 MUST NOT 被描述为已确认的创建或暂停操作。出价变化 MUST 按广告组日快照计算,并区分上调、下调、期内变化但首末持平;无值 MUST NOT 默认为零。国家全量与新增成效 MUST 可在明细追溯。
|
|
101
|
+
|
|
102
|
+
#### Scenario: 同名广告不可合并
|
|
103
|
+
- **GIVEN** 两个不同广告 ID 使用同一名称
|
|
104
|
+
- **WHEN** 统计新增广告并导出明细
|
|
105
|
+
- **THEN** 分别计数并输出 ID,不因名称相同而丢失其中一条
|
|
106
|
+
|
|
107
|
+
#### Scenario: 期内调价后恢复原价
|
|
108
|
+
- **GIVEN** 一个广告组期内出价变化但首末有效快照一致
|
|
109
|
+
- **WHEN** 生成出价摘要
|
|
110
|
+
- **THEN** 计为首末持平的期内变化,不归类为下调
|
|
111
|
+
|
|
112
|
+
### Requirement: 每条业务线只交付一份校验通过的最终 Excel
|
|
113
|
+
|
|
114
|
+
Excel 写入与逐单元格回读校验 MUST 使用同一文本清洗口径:剔除 XML 1.0 不可写的控制字符和孤立代理项,保留制表、换行、回车及其他正常字符;不能让单条广告名称中的非法字符导致整条业务线的文件解析失败。
|
|
115
|
+
|
|
116
|
+
每条可生成的业务线 MUST 独立产出一份包含固定 16 列策略摘要及 35 列维度明细的 Excel。明细列依次为明细数据、动作、渠道、id、名称、指标 sheet 的 29 个指标、补充。首列只允许维度名,不得加入周期覆盖、项目、完整说明或“新增成效/”“/分布”等类型;非出价动作只允许新增、暂停、持续。每个指标按本期值、可计算上期值格式输出,缺本期显示 `-`;出价补充列只写调价字段的起始与末值,其余留空。明细不得把 `[续 …]` 拼进动作。预算、广告产品、受众正文前各增加实时字典匹配的名称列,素材无标签。前两张表的分析与排版 MUST 由固定脚本完成;正常流程 MUST 一次生成固定样式,MUST NOT 依赖 Agent 临时生成修订脚本或二次导入重排。双表草稿校验后,MUST 从同一明细生成只含 `明细` sheet 的 AI 输入工作簿,Agent 只依据该表与独立提示词撰写 AI 复盘。第三张表 MUST 以表头加单行八列保存一页速览、从第一张表复制的预算/广告产品/受众标签及四类策略全文;每个标签紧挨对应策略正文左侧,空标签保留空值,素材/创意无标签,Learning 留在策略正文内。文件发布前 MUST 检查 Excel 容器、三张表、列名、记录及 AI 文本和标签完整性。本地模式最终路径 MUST 位于待清理工作目录之外,名称 MUST 能区分业务线与请求,MUST NOT 覆盖已存在的其他文件。
|
|
117
|
+
|
|
118
|
+
#### Scenario: 并发生成不覆盖结果
|
|
119
|
+
- **GIVEN** 两条业务线在同一秒完成导出
|
|
120
|
+
- **WHEN** 发布最终文件
|
|
121
|
+
- **THEN** 获得两个不同且可读取的文件路径,各自包含对应业务线数据
|
|
122
|
+
|
|
123
|
+
#### Scenario: 校验失败不发布损坏文件
|
|
124
|
+
- **GIVEN** Excel 缺少明细表或明细行数不一致
|
|
125
|
+
- **WHEN** 执行发布前校验
|
|
126
|
+
- **THEN** 该任务失败,不对外声明最终 Excel 已生成
|
|
127
|
+
|
|
128
|
+
### Requirement: 任务结束后按归属清理全部临时产物
|
|
129
|
+
|
|
130
|
+
每条业务线任务完成后,MUST 清理本次任务创建的全部非最终产物,包括但不限于 JSON、请求/响应、日志副本、预览图片、临时脚本、临时 Excel、检查文件及运行时缓存。本地成功时 MUST 先确认最终文件已发布且验证通过,再清理;数据库模式 MUST 在临时 Excel 校验并上传成功后删除该文件,再携带 storageKey 保存策略;失败时 MUST 先保存可返回的错误摘要到内存/输出,再清理其临时和不完整产物。所有任务结束后 MUST 清理本次批次共享临时目录。MUST NOT 保留额外磁盘分析报告或将已删除目录作为交付物。
|
|
131
|
+
|
|
132
|
+
清理 MUST 以本次创建的独立目录及登记文件为边界,校验规范化绝对路径及所有权,MUST NOT 按扩展名或桌面 glob 广泛扫描。MUST NOT 删除历史请求、其他并行业务线、仓库源码、技能目录、平台凭证或 CLI 全局审计日志。符号链接、Windows junction/reparse point MUST NOT 被递归跟随到边界外。存在清理失败时 MUST 明确报告残留路径和原因,不宣称已完全清理。
|
|
133
|
+
|
|
134
|
+
#### Scenario: 成功后只保留最终文件
|
|
135
|
+
- **GIVEN** 本次业务线目录中存在 JSON、PNG、TXT、无扩展名文件和临时子目录
|
|
136
|
+
- **WHEN** 最终 Excel 发布并校验成功
|
|
137
|
+
- **THEN** 上述临时产物及业务线临时目录均被清理,最终 Excel 仍可读取
|
|
138
|
+
|
|
139
|
+
#### Scenario: 失败任务不残留临时文件
|
|
140
|
+
- **GIVEN** 拉数或分析失败且已创建部分回包和临时输出
|
|
141
|
+
- **WHEN** 该业务线任务结束
|
|
142
|
+
- **THEN** 返回业务线 ID、失败阶段和错误摘要,清理其拥有的临时产物,继续处理其他任务
|
|
143
|
+
|
|
144
|
+
#### Scenario: 清理链接时保护外部目录
|
|
145
|
+
- **GIVEN** 本次临时目录中有链接指向另一任务或用户目录
|
|
146
|
+
- **WHEN** 执行清理
|
|
147
|
+
- **THEN** 不遍历或删除链接目标,外部文件及其他任务目录保持不变
|
|
148
|
+
|
|
149
|
+
#### Scenario: 文件占用导致清理失败
|
|
150
|
+
- **GIVEN** 最终 Excel 已验证,但一个临时文件被占用且删除失败
|
|
151
|
+
- **WHEN** 工作流结束清理
|
|
152
|
+
- **THEN** 返回最终文件路径及清理失败状态和残留路径,批次以非成功状态结束
|
|
153
|
+
|
|
154
|
+
### Requirement: 批次结果可观察且失败互不掩盖
|
|
155
|
+
|
|
156
|
+
工作流 MUST 按业务线返回阶段状态、本地最终 Excel 路径或数据库 aiStrategyId/storageKey,以及未生成或失败原因,并提供阶段耗时和批次成功/失败数量。结果 MUST 区分生成失败、导出失败、清理失败;重试结束后任一业务线最终失败时批次 MUST 非零退出,同时保留其他任务的成功文件。耗时结果 MUST 通过输出或最终 Excel 内已有适当区域提供,MUST NOT 为此保留额外临时报告。用户可处理的中断 MUST 停止启动新任务并等待/终止子进程后执行边界内清理;进程被强制杀死或断电的情形不得宣称已完成清理。
|
|
157
|
+
|
|
158
|
+
#### Scenario: 混合结果完整汇报
|
|
159
|
+
- **GIVEN** 三条业务线分别成功、拉数失败、清理失败
|
|
160
|
+
- **WHEN** 批次收尾
|
|
161
|
+
- **THEN** 输出三条各自结果与阶段耗时,保留成功的最终 Excel,批次非零退出
|
|
162
|
+
|
|
163
|
+
### Requirement: 用户显式选择数据库输出
|
|
164
|
+
|
|
165
|
+
技能 MUST 默认仅交付本地 Excel,沿用桌面及显式目录选择。仅用户明确要求数据库输出时 MUST 上传 Excel 并保存 AI 策略;此模式 MUST NOT 在桌面发布文件。所有业务请求 MUST 走已有 CLI。
|
|
166
|
+
|
|
167
|
+
#### Scenario: 默认本地交付
|
|
168
|
+
- **GIVEN** 用户没有要求入库
|
|
169
|
+
- **WHEN** 完成策略生成
|
|
170
|
+
- **THEN** 返回可读取的最终 Excel 路径,不调用上传或 AI 保存接口
|
|
171
|
+
|
|
172
|
+
#### Scenario: 数据库交付
|
|
173
|
+
- **GIVEN** 用户明确要求入库且可生成策略
|
|
174
|
+
- **WHEN** 上传与保存均返回成功
|
|
175
|
+
- **THEN** 返回 AI 策略 ID、storageKey 与清理结果,不返回已删除的本地 Excel 链接
|
|
176
|
+
|
|
177
|
+
### Requirement: 缺行业配置是一次性生成失败
|
|
178
|
+
|
|
179
|
+
唯一查出的业务线若adCategoryIndustryIds缺失、为空或首项非正整数,MUST只取首项判配置失败,不用其他行业。数据库模式在真实业务线ID和合法可保存周期上下文下MUST保存一次GENERATION_FAILED及remark,并标记不可整条重试;本地模式MUST只报告,不写库。MUST在项目预检/成效请求前停止。接口查询失败、空字典和行业配置缺失MUST区分;未知业务线/非法周期不得伪造入库,保存结果未知仍不重放。
|
|
180
|
+
|
|
181
|
+
#### Scenario: 配置失败与其他业务线隔离
|
|
182
|
+
- **WHEN** A缺行业ID而B配置合法
|
|
183
|
+
- **THEN** A最多保存一次失败且不拉项目成效,B继续正常流程;A不进入后续整条重试轮
|
|
184
|
+
|
|
185
|
+
### Requirement: 临时数据使用持久任务根
|
|
186
|
+
|
|
187
|
+
所有临时数据MUST位于工作根的strategy_task/YYYY-MM-DD/tmp/随机批次内。工作根默认启动cwd,可用--task-root覆盖;相对路径按启动cwd解析,批次启动日期固定,跨午夜/重试不改变。空值、不可写或规范化后位于本专家Skill树内(含junction重定向)MUST失败,不回退系统TEMP。清理MUST复用原所有权边界,只清理本次随机批次/业务线,不扫历史或其他任务。
|
|
188
|
+
|
|
189
|
+
#### Scenario: 重试与历史目录隔离
|
|
190
|
+
- **WHEN** 本次任务跨午夜后重试,工作根内另有历史批次
|
|
191
|
+
- **THEN** 沿用启动日路径,仅清理本次目录,历史批次保留
|
|
192
|
+
|
|
193
|
+
### Requirement: 提示词格式与事件准备
|
|
194
|
+
|
|
195
|
+
AI提示词MUST以模板的“策略总结:”“关键数据:”“调整方向:”“Learning(最终单一标签):”表示小节,四个策略大标题仍用【】独立成行,一页速览非空且最多2行。Agent可在fetch期间预读当前提示词、准备现有提交入口与明细解析;MUST不编造未返回数据、不使用其他业务线结果作为事实。多事件到达时MUST分别及时处理,按本批有效请求身份去重,不扫历史tmp、不逐条新写提交脚本、不另建无界审核队列。等待时间MUST区分事件接手/分析/发布,不能全部视作模型推理时长;不强制子Agent架构。Python只机械校验与导出,不实现营销判断。
|
|
196
|
+
|
|
197
|
+
#### Scenario: 按模板输出
|
|
198
|
+
- **WHEN** Agent生成本条AI策略
|
|
199
|
+
- **THEN** 四段使用正确大标题和冒号小节,返回前自检数字依据、唯一末段Learning与非空正文,不套用示例数字
|
|
200
|
+
|
|
201
|
+
### Requirement: 动态标签与 Excel 展示一致
|
|
202
|
+
|
|
203
|
+
两种输出 MUST 通过 `biz-line +categories` 分别查询 BUDGET_STRATEGY、MEDIA_STRATEGY、AUDIENCE_STRATEGY,MUST 先查询业务线并取 adCategoryIndustryIds 第一个行业 ID,以其字符串值作为 filterCondition;缺失或首项非法 MUST 失败,不改取后续项。三类标签 MUST 在项目预检和广告数据查询前加载。同批次 MUST 按行业 ID 缓存完整三类成功字典;错误仅在当前轮缓存,重试轮开始清除错误,同行业同轮并发只加载一次,不同行业分别查询,MUST NOT 跨批次缓存或硬编码行业 ID,并保留 ID/name 对应。正常审核 MUST 由 Agent 逐类分析实际策略正文、结构化事实与本行业本场景全部候选标签,按含义选择最适合者;MUST NOT 仅因同名或固定动作词匹配失败而选其他,只有具体标签均不合适时选择本场景“其他”;两次审核被拒或超时后的自动兜底见下述标签交接要求。MUST NOT 跨场景兜底或编造 ID。字典获取失败或空列表 MUST 明确报告;审核穷尽后缺少唯一“其他”的场景标签为空并报告,不使其他策略或该策略正文失败。Excel MUST 在上述三类正文前分别增加标签名称列,主表合计 16 列,素材策略不增加标签。入库 MUST 传对应 ID 数组,符合 schema 的大小限制。
|
|
204
|
+
|
|
205
|
+
#### Scenario: 未匹配使用其他
|
|
206
|
+
- **GIVEN** 预算策略没有可靠匹配且预算字典返回“其他”
|
|
207
|
+
- **WHEN** 导出或入库
|
|
208
|
+
- **THEN** Excel 展示该名称,入库 budgetStrategyTags 使用同一个字典 ID
|
|
209
|
+
|
|
210
|
+
#### Scenario: 字典不可用
|
|
211
|
+
- **GIVEN** 业务线首个行业 ID 无效、接口失败或返回空列表
|
|
212
|
+
- **WHEN** 处理标签
|
|
213
|
+
- **THEN** 报告具体原因,不把空结果当作已成功匹配,不保存 READY
|
|
214
|
+
|
|
215
|
+
#### Scenario: 多业务线行业重复
|
|
216
|
+
- **GIVEN** 三条业务线的 adCategoryIndustryIds 分别为 [11,22]、[11]、[22]
|
|
217
|
+
- **WHEN** 在同一批次并发生成
|
|
218
|
+
- **THEN** 第一条仅使用行业 11,前两条共享行业 11 的三类字典,第三条使用行业 22;合计六次字典查询,不串用标签
|
|
219
|
+
|
|
220
|
+
### Requirement: 四类效果独立保存
|
|
221
|
+
|
|
222
|
+
READY MUST 包含四类策略正文、四类 learning、四类 effect、三类标签 ID 数组及 fileStorageKey。effect MUST 从最终 AI sheet 的末段 Learning 标签使用整数 1=有效、2=无效、3=待观察。固定分析的有上期环比/无上期阈值分支仅用于第一张策略表,不覆盖 AI 结论。
|
|
223
|
+
|
|
224
|
+
#### Scenario: 数据不足待观察
|
|
225
|
+
- **GIVEN** AI sheet 某类 Learning 标签为待观察
|
|
226
|
+
- **WHEN** 保存该类效果
|
|
227
|
+
- **THEN** 对应 StrategyEffect 为 3,保留其独立正文和 learning
|
|
228
|
+
|
|
229
|
+
### Requirement: 工作流保存真实生成结果
|
|
230
|
+
|
|
231
|
+
数据库模式 MUST 按真实结果保存 READY、NO_PROJECT、UNSUPPORTED_CHANNEL、NO_AD_ACCOUNT、NO_DELIVERY_DATA 或 GENERATION_FAILED;非 READY MUST 提供 remark。MUST NOT 保存 PERIOD_NOT_FINISHED、BEFORE_SUPPORTED_PERIOD、GENERATING,MUST NOT 把查询异常当作空业务数据。MUST 先取得真实业务线及合法周期;无法确定时仅报告错误而不伪造写入。不支持或未知渠道 MUST NOT 被静默丢弃后宣称成功。
|
|
232
|
+
|
|
233
|
+
#### Scenario: 未关联项目
|
|
234
|
+
- **GIVEN** 项目查询成功返回空且业务线与可保存周期已确定
|
|
235
|
+
- **WHEN** 结束数据库模式生成
|
|
236
|
+
- **THEN** 保存 NO_PROJECT 和原因,不制造空策略或 Excel
|
|
237
|
+
|
|
238
|
+
#### Scenario: 请求异常
|
|
239
|
+
- **GIVEN** 已确定可保存的业务线和周期,但投放请求失败
|
|
240
|
+
- **WHEN** 收尾
|
|
241
|
+
- **THEN** 尝试保存 GENERATION_FAILED 及原因,并分别报告生成和状态保存结果
|
|
242
|
+
|
|
243
|
+
### Requirement: 用全部关联项目上周消耗预检
|
|
244
|
+
|
|
245
|
+
数据库模式 MUST 分页获取该业务线全部关联项目并与业务线 projectIds 核对覆盖;缺少项目时 MUST 失败,不按部分项目判断全零。使用项目列表 lastWeekSpend 判断上周消耗,MUST NOT 使用 isLast7DSpend 或近七天状态,也 MUST NOT 使用该接口的 channelIdList 判断业务线渠道。无项目时保存 NO_PROJECT;存在项目且全部 lastWeekSpend 明确为 0 时 MUST 立即保存 NO_DELIVERY_DATA 与原因,不继续广告数据查询、策略生成或上传。至少一个项目大于 0 时才继续关联账号渠道及账号校验,再按目标周期取数。缺失、非法值和查询失败 MUST NOT 当成 0;无法证实全零或存在正消耗时 MUST 报告失败。
|
|
246
|
+
|
|
247
|
+
#### Scenario: 全部项目上周为零
|
|
248
|
+
- **GIVEN** 所有页读取成功且每个关联项目 lastWeekSpend 都为 0
|
|
249
|
+
- **WHEN** 执行生成前检查
|
|
250
|
+
- **THEN** 直接保存 NO_DELIVERY_DATA,不查询广告维度及成效,也不生成空 Excel
|
|
251
|
+
|
|
252
|
+
#### Scenario: 后续页存在正消耗
|
|
253
|
+
- **GIVEN** 第一页项目消耗为 0,后续页至少一个项目 lastWeekSpend 大于 0
|
|
254
|
+
- **WHEN** 完成分页预检
|
|
255
|
+
- **THEN** 继续从关联项目与账号接口检查全部广告账号渠道,不提前保存 NO_DELIVERY_DATA
|
|
256
|
+
|
|
257
|
+
#### Scenario: 消耗缺失不能冒充零
|
|
258
|
+
- **GIVEN** 项目列表无正消耗但存在 lastWeekSpend 缺失
|
|
259
|
+
- **WHEN** 执行预检
|
|
260
|
+
- **THEN** 报告无法判断并保存 GENERATION_FAILED,不保存 NO_DELIVERY_DATA
|
|
261
|
+
|
|
262
|
+
#### Scenario: 服务默认筛选遗漏关联项目
|
|
263
|
+
- **GIVEN** 分页 total 已取全,但返回 ID 未覆盖业务线 projectIds
|
|
264
|
+
- **WHEN** 尝试判断上周消耗
|
|
265
|
+
- **THEN** 报告项目覆盖不完整,不保存 NO_PROJECT 或 NO_DELIVERY_DATA
|
|
266
|
+
|
|
267
|
+
### Requirement: 业务线渠道只依据关联广告账号
|
|
268
|
+
|
|
269
|
+
本地和数据库模式 MUST 从 biz-line +project-list(/biz-line/project-list)全量项目的 adAccounts 判断渠道,只允许 Facebook/Meta、Google、TikTok 中一个或多个,不使用项目分页的 channelIdList。账号有 channelId 时 MUST 用 media +channels 解析且以 ID 为准,channelName 为空不得丢弃账号;缺 ID 才用账号名称识别。其他或未知渠道 MUST 为 UNSUPPORTED_CHANNEL,不静默过滤。显式分析账号覆盖或跳过消耗预检 MUST NOT 绕过关联账号渠道校验。全部无账号沿用 NO_AD_ACCOUNT;格式错误或查询失败 MUST 为技术失败,不冒充无账号。数据库原全零消耗预检优先级不变。
|
|
270
|
+
|
|
271
|
+
#### Scenario: 项目渠道与账号渠道不同
|
|
272
|
+
- **GIVEN** 项目分页的渠道缺失或属于其他平台,关联账号接口中的全部账号只属于 Google 和 TikTok
|
|
273
|
+
- **WHEN** 项目消耗预检放行并读取关联账号
|
|
274
|
+
- **THEN** 继续生成,仅按去重后的 Google 和 TikTok 账号拉取维度与成效
|
|
275
|
+
|
|
276
|
+
#### Scenario: 支持账号中混入其他渠道
|
|
277
|
+
- **GIVEN** 某个关联项目有 Facebook 账号,另一个项目有其他或未知渠道账号
|
|
278
|
+
- **WHEN** 校验所有关联账号,即使用户另指定 Facebook 分析账号或跳过消耗预检
|
|
279
|
+
- **THEN** 数据库保存 UNSUPPORTED_CHANNEL 及原因,本地报告不可生成,不查询广告成效或导出部分报告
|
|
280
|
+
|
|
281
|
+
#### Scenario: 账号名称为空但渠道ID可识别
|
|
282
|
+
- **GIVEN** 账号 channelName 为空或过时,channelId 可在渠道字典中解析为支持渠道
|
|
283
|
+
- **WHEN** 校验账号渠道
|
|
284
|
+
- **THEN** 按 ID 对应的真实渠道去重并取数;未知 ID 不得凭支持渠道名称放行
|
|
285
|
+
|
|
286
|
+
### Requirement: 上传校验清理与保存顺序可追溯
|
|
287
|
+
|
|
288
|
+
数据库模式 MUST 先生成并完整校验 Excel,再调用 `common-file +upload`,serviceName MUST 为 sino-opti-hive。MUST 验证非空 storageKey,删除本次临时 Excel,并在 `biz-line-ai-strategy +ai-strategy-save` 的 fileStorageKey 传原值。保存结果未知 MUST NOT 自动重试或追加失败状态覆盖;上传或保存失败 MUST 报告阶段与已有 key。清理 MUST 仅针对本次拥有的文件,失败 MUST 报告残留,MUST NOT 宣称完全成功。
|
|
289
|
+
|
|
290
|
+
#### Scenario: 上传成功后保存失败
|
|
291
|
+
- **GIVEN** 已取得 storageKey 并删除临时 Excel
|
|
292
|
+
- **WHEN** AI 策略保存失败或超时
|
|
293
|
+
- **THEN** 返回 key、保存失败或结果未知,不重新上传、不自动重试、不用 GENERATION_FAILED 覆盖潜在成功记录
|
|
294
|
+
|
|
295
|
+
#### Scenario: 清理失败
|
|
296
|
+
- **GIVEN** 本次文件被占用无法删除
|
|
297
|
+
- **WHEN** 任务收尾
|
|
298
|
+
- **THEN** 返回确切残留路径和清理错误,数据库保存结果独立展示
|
|
299
|
+
|
|
300
|
+
### Requirement: 批量执行保持隔离
|
|
301
|
+
|
|
302
|
+
工作流 MUST 保持拉数/AI各最多三条、总在途最多六条滑动处理及同批次 ID 去重、每条内部串行请求与分页处理。各业务线结果、上传 key、状态写入及清理 MUST 独立,失败 MUST NOT 阻塞其他业务线或掩盖其结果。
|
|
303
|
+
|
|
304
|
+
#### Scenario: 混合生成结果
|
|
305
|
+
- **GIVEN** 同批业务线分别生成成功、无账号、保存失败
|
|
306
|
+
- **WHEN** 批次结束
|
|
307
|
+
- **THEN** 分别返回三条完整结果,保存失败令批次非成功且不影响其他记录
|
|
308
|
+
|
|
309
|
+
### Requirement: 显式跳过项目消耗预检
|
|
310
|
+
|
|
311
|
+
仅用户明确要求跳过项目上周消耗判断时传 `--skip-project-spend-check`,默认不启用。该参数只跳过 `lastWeekSpend` 的全零或无正消耗门槛;仍校验项目分页完整性、关联项目、渠道、账号、指定周期真实投放数据及标签。不得因用户指定了历史周期就自动跳过。
|
|
312
|
+
|
|
313
|
+
### Requirement: 主表汇总与简洁 learning
|
|
314
|
+
|
|
315
|
+
原始 KPI MUST NOT 进入任何 sheet 或入库正文。策略 MUST 显示合计与分类分布,并在各维度新增/暂停各自数量为1~5时列全名称;超过5个收起该动作名单,广告组/广告用分布替代。全量对象、逐条调价值及成效仍保留在明细。所有展示的消耗占比 MUST 有对应金额,金额及合计消耗 MUST 有环比,零基数明确不可计算。广告组和广告 MUST 按五个阈值展示完整名称或名称片段分布与数量;调价仅保留非零动作数量,不猜代码含义、不用 ID 代替名称。对外文案 MUST 使用新增、暂停、分布在。learning MUST 只有结论与说明两部分,分支规则与固定文案见 metrics.md,未知数据为待观察。策略汇总 MUST 完整展示,不能静默截断尾部类别。
|
|
316
|
+
|
|
317
|
+
#### Scenario: 未达标但改善
|
|
318
|
+
- **GIVEN** 同口径 KPI 未达标但较上期改善达到2%,样本足够
|
|
319
|
+
- **WHEN** 输出 learning
|
|
320
|
+
- **THEN** 仅显示“结论:有效”和“说明:策略有效”,效果码为 1
|
|
321
|
+
|
|
322
|
+
#### Scenario: 汇总变长
|
|
323
|
+
- **GIVEN** 策略同时显示金额、占比、分布,超过原 18 行限制
|
|
324
|
+
- **WHEN** 导出 Excel
|
|
325
|
+
- **THEN** 自适应列宽完整展示各类别;超过 Excel 可显示范围则失败,不截掉末段或留下半句话
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
### Requirement: 批次失败按轮重跑
|
|
329
|
+
|
|
330
|
+
工作流 MUST 首轮执行全部去重业务线,整轮结束后才重跑可重试的失败条目,每条含首次最多 3 次;成功条目 MUST NOT 重跑。每轮拉数/AI分别上限3、总在途上限6,周期与用户参数保持不变,每次使用独立临时目录。行业字典成功缓存 MUST 跨轮复用,失败缓存 MUST 在下一轮开始前清除。
|
|
331
|
+
|
|
332
|
+
#### Scenario: 部分失败后恢复
|
|
333
|
+
- **WHEN** 首轮 A、B 失败、C 成功,第二轮 A 失败、B 成功
|
|
334
|
+
- **THEN** 顺序为全首轮结束后执行 A/B,再仅执行 A 第三次;最终仅返回三条业务线结果,C 执行一次、B 两次、A 三次,各自包含 attempts 与 attempt_history
|
|
335
|
+
|
|
336
|
+
#### Scenario: 保存未知及取消
|
|
337
|
+
- **WHEN** READY 或失败状态保存请求报错/结果未知,或条目有已交付文件/清理失败/输出残留,或 worker 外层异常使副作用无法确定
|
|
338
|
+
- **THEN** MUST 保留错误及已有 key,不自动整条重跑,避免重复保存或交付
|
|
339
|
+
- **WHEN** 用户取消
|
|
340
|
+
- **THEN** MUST 停止启动新任务与重试,等待在途清理;未启动条目也出现在最终结果中
|
|
341
|
+
|
|
342
|
+
#### Scenario: 业务结果与技术错误
|
|
343
|
+
- **WHEN** 无项目等不可生成业务状态已保存成功
|
|
344
|
+
- **THEN** 视为已处理结果,不重跑
|
|
345
|
+
- **WHEN** 技术错误且 GENERATION_FAILED 已保存成功
|
|
346
|
+
- **THEN** 可进入下一轮;第三次仍失败即停止,按最终结果统计失败,不将历次尝试累加成业务线数量
|
|
347
|
+
|
|
348
|
+
|
|
349
|
+
### Requirement: 核心指标配置失败说明
|
|
350
|
+
四类 learning MUST 区分核心指标为空与无法识别,结论均为待观察、效果均为 3。未填写或纯空白时说明 MUST 为“核心指标为空”;指标不在接口指标及受支持衍生指标范围时 MUST 说明“核心指标不支持”;已认出指标但阈值/币种/表达无法解析时 MUST 说明“核心指标无法识别”。此原因优先于样本不足或缺数据。只有核心指标可识别但数据不足时使用“数据不足,暂无法判断”。MUST 保持结论与说明格式,不回显 KPI 原文。
|
|
351
|
+
|
|
352
|
+
### Requirement: 标签内容分析交接
|
|
353
|
+
|
|
354
|
+
标签选择MUST在导出/上传/保存前通过tag_review_required交接,绑定bizLineId、业务线attempt及本次reviewId,保留三类完整正文、事实和全部行业候选。请求MUST声明choice-key-v1、有效expiresAt,并为各候选提供绑定本次审核/策略类别/真实ID的choiceKey。Agent MUST在每次提交前重读对应请求,仅返回三类候选编号与理由,经submit_tags.py映射真实ID并自动组装身份;MUST NOT手写ID或将其他请求编号复制过来。编号错误、身份错配、过期、关闭、被下一轮替代、重复响应及非法选择MUST被拒绝,不覆盖、不部分发布、不重建已清理目录。消费端MUST再次验证编号到ID的映射,Excel与数据库复用同一组真实ID。
|
|
355
|
+
|
|
356
|
+
拒绝或超时MUST只重试标签选择,不重新拉数与分析。含首次最多2次、每次7分钟,旧请求结束时关闭;每次路径和reviewId独立。两次失败才逐场景使用真实唯一“其他”,没有唯一“其他”的场景标签为空、READY标签字段为[],正文和learning继续交付。原因、缺失场景及waitSeconds/阶段timings可见,MUST NOT称兜底为人工审核通过。取消、字典故障或提交IO故障不得自动归为内容不匹配。MUST保持拉数3/AI3/总6滑动补位和逐条清理,不另建无界队列。
|
|
357
|
+
|
|
358
|
+
#### Scenario: 同行业相同ID仍不能串线
|
|
359
|
+
- **GIVEN** A/B业务线共享行业候选ID
|
|
360
|
+
- **WHEN** 将A的choiceKey写入B或把预算编号用于受众
|
|
361
|
+
- **THEN** 提交失败且B无新响应,不接受只因真实ID合法而跨请求选择
|
|
362
|
+
|
|
363
|
+
#### Scenario: 重读与独占发布
|
|
364
|
+
- **WHEN** 请求在映射期间被修改、超时、关闭或被替代,或另一个提交已写入响应
|
|
365
|
+
- **THEN** 拒绝提交,不覆盖、不留下半写JSON,不创建已清理目录
|
|
366
|
+
|
|
367
|
+
#### Scenario: 两次审核失败兜底
|
|
368
|
+
- **WHEN** 两次回包均无效或各等待7分钟仍无响应
|
|
369
|
+
- **THEN** 不重新拉数;逐类使用唯一真实“其他”,没有的标签为空且保留正文/learning,失败原因写入最终结果
|
|
370
|
+
|
|
371
|
+
#### Scenario: 直接ID响应不能绕过编号检查
|
|
372
|
+
- **WHEN** 直接写入缺少本次choiceKey或编号与ID不符的响应
|
|
373
|
+
- **THEN** 消费端拒绝,进入原标签阶段剩余次数,而非保存READY
|
|
374
|
+
|
|
375
|
+
#### Scenario: 提交输入与最终响应字段诊断
|
|
376
|
+
- **GIVEN** AI应仅提交choiceKey/reason,最终id及身份由submit_tags.py生成
|
|
377
|
+
- **WHEN** 提交输入或被手写的响应缺少choiceKey/reason,或响应缺少整数id
|
|
378
|
+
- **THEN** 返回具体类别、选择下标、字段名和submit_tags.py修正指引,不只返回KeyError字段原文;原合法性、身份和重试规则不变
|
|
379
|
+
- **AND** 提交脚本预检失败不发布响应,同一请求可在原期限内修正后重交,不重置7分钟计时
|
|
380
|
+
|
|
381
|
+
### Requirement: 完整指标查询与 learning 分支
|
|
382
|
+
fetch MUST 请求三渠道当前共同支持的12个基础 indicators,MUST NOT 把衍生指标传给接口。服务返回 conflictField 时 MUST 保留于本次分页索引;核心指标所依赖字段被任一请求渠道明确拒绝时,MUST 判核心指标不支持而非使用部分渠道结果。缺失值不补零。
|
|
383
|
+
|
|
384
|
+
#### Scenario: 无上期阈值及样本门槛
|
|
385
|
+
- **GIVEN** 上期实际成效无记录、本期样本充分,核心指标为安装量>=100
|
|
386
|
+
- **WHEN** 本期安装量为100/99
|
|
387
|
+
- **THEN** 分别输出有效/核心指标达标、无效/核心指标未达标
|
|
388
|
+
- **WHEN** 核心指标仅为安装量,无附带阈值,或本期样本未达门槛
|
|
389
|
+
- **THEN** 输出待观察/数据不足,暂无法判断
|
|
390
|
+
|
|
391
|
+
#### Scenario: 2%边界与无可比值
|
|
392
|
+
- **GIVEN** 样本充分,上期CPI=2,本期CPI=1.96
|
|
393
|
+
- **THEN** 改善恰好2%,输出有效,即使核心指标阈值为CPI<=1
|
|
394
|
+
- **WHEN** CPI改善不足2%、持平或变差
|
|
395
|
+
- **THEN** 输出无效
|
|
396
|
+
- **WHEN** 上期有记录但核心指标为0或缺失
|
|
397
|
+
- **THEN** 输出待观察,不改走无上期阈值分支
|
|
398
|
+
|
|
399
|
+
|
|
400
|
+
### Requirement: 小集合名称展开
|
|
401
|
+
各维度新增与暂停 MUST 分别计数和判断阈值:0个隐藏该动作,新增与暂停均为0则显示未出现变化,1~5个列出全部完整名称,超过5个不列该动作全部名称。国家/词包/年龄等按已有合并集合口径判断;金额占比类别按原渠道维度补充新增/暂停名称,不受前三类金额占比摘要限制。广告组/广告按各动作跨渠道总数判断,超过5个改为渠道名称片段分布,不超过5个逐渠道列全名称。同名不同ID仍分别计数,不截断名称。调价广告组名称、分布及逐条出价值只放明细。明细sheet继续保留全部记录,learning格式不变。
|
|
402
|
+
|
|
403
|
+
#### Scenario: 新增与暂停独立边界
|
|
404
|
+
- **WHEN** 新增5个国家、暂停2个国家
|
|
405
|
+
- **THEN** 策略列出5个新增国家及2个暂停国家全部名称
|
|
406
|
+
- **WHEN** 新增6个广告、暂停2个广告
|
|
407
|
+
- **THEN** 新增只展示数量和分布,暂停列出2个广告的名称;完整名单保留在明细
|
|
408
|
+
|
|
409
|
+
关键词维度为名称展开规则的例外:策略正文无论新增/暂停数量多少(包括1~5个),始终只展示数量,不展示关键词名称或片段;完整关键词仍保留在明细 sheet。其他维度的五个阈值规则不变。
|
|
410
|
+
|
|
411
|
+
|
|
412
|
+
### Requirement: 非预算 learning 限定新增枚举范围
|
|
413
|
+
预算 learning MUST 保持业务线总体口径。广告产品/受众/素材 MUST 使用 four-strategies.md 对应维度中本期新增枚举的成效,MUST NOT 复用预算结论或纳入持续、暂停对象。新增 MUST 按渠道内两期集合差识别,广告/广告组使用稳定ID。同一维度跨渠道的全部新增枚举 MUST 先合计基础指标再计算一次核心指标;样本门槛 MUST 只检查该维度新增合计消耗大于0美元。维度成效请求 MUST 附加 calendar_date,总体账户请求保持原样。维度新增合计的本期指标 MUST 与业务线上期全部请求渠道的账户总体同一指标比较,不要求上期有同值枚举。仅上期账户总体没有记录时 MUST 使用阈值分支;有记录但核心指标缺失或为0 MUST 待观察。核心字段冲突 MUST 检查维度及上期账户总体分页元数据。
|
|
414
|
+
|
|
415
|
+
各有新增的维度 MUST 独立评估;有效维度的新增消耗/全部有新增维度的新增消耗 MUST 严格超过70%才判整类有效(说明策略有效),恰好70%不算有效。待观察和无效维度的消耗 MUST 留在分母,不得剔除。跨维度权重可能重叠,MUST NOT 宣称为去重业务总消耗。未超过70%且存在待观察维度则待观察;全部维度可判定但未超过70%则无效(说明需关停)。核心指标配置问题优先;缺消耗、零总消耗、全部无新增均待观察。输出 MUST 仍为结论和说明两部分,effect 与对应结论一致。
|
|
416
|
+
|
|
417
|
+
#### Scenario: 总体改善不替代新增值表现
|
|
418
|
+
- **GIVEN** 总体 CPI 改善至少2%,新增广告 CPI 相比上期业务线总体未改善至少2%且样本充分
|
|
419
|
+
- **THEN** 预算有效;仅该广告维度新增的素材策略无效
|
|
420
|
+
- **WHEN** 广告产品所有维度无新增
|
|
421
|
+
- **THEN** 广告产品待观察,不复制预算结论
|
|
422
|
+
- **WHEN** 新增广告仅投放一天、本期正消耗,且核心指标可计算
|
|
423
|
+
- **THEN** 素材仍按该广告自身指标判定,不因投放天数不足而待观察
|
|
424
|
+
|
|
425
|
+
#### Scenario: 有效维度消耗占比边界
|
|
426
|
+
- **GIVEN** 有效新增维度消耗710,无效维度消耗290
|
|
427
|
+
- **THEN** 总体有效,无需所有枚举有效
|
|
428
|
+
- **WHEN** 有效消耗700、无效消耗300
|
|
429
|
+
- **THEN** 总体无效,恰好70%不算超过
|
|
430
|
+
- **WHEN** 有效消耗700、待观察消耗300
|
|
431
|
+
- **THEN** 待观察消耗仍计入分母,总体待观察
|
|
432
|
+
|
|
433
|
+
|
|
434
|
+
#### Scenario: 新增国家对比上期总体
|
|
435
|
+
- **GIVEN** 上期业务线总体 CPI=2,本期新增美国 CPI=1.96,样本充分,目标阈值CPI<=1
|
|
436
|
+
- **THEN** 美国枚举改善2%判有效,不因无上期美国数据改走阈值;其消耗计入有效权重
|
|
437
|
+
- **WHEN** 上期有总体记录但总体CPI缺失或为0
|
|
438
|
+
- **THEN** 美国枚举待观察,不回退阈值判断
|
|
439
|
+
- **WHEN** 上期账户总体没有任何记录
|
|
440
|
+
- **THEN** 美国枚举沿用无上期阈值判断
|
|
441
|
+
|
|
442
|
+
|
|
443
|
+
### Requirement: 按业务线覆盖核心指标及 learning 数值说明
|
|
444
|
+
显式用户覆盖 MUST 以真实业务线ID绑定,仅本次分析有效,优先于业务线coreIndex;未覆盖则使用业务线字段。重复覆盖和本批之外ID MUST 拒绝,不得跨业务线串用,不得修改服务端业务线配置。无法解析的覆盖 MUST 保留对应待观察原因,不回退默认指标。
|
|
445
|
+
|
|
446
|
+
learning MUST 保持结论与说明两部分。预算说明 MUST 展示核心指标本期/上期总体值及环比;非预算说明 MUST 按有新增的维度展示用于实际判定的新增合计本期值、上期总体值与环比,每个维度的 KPI 明细 MUST 另起一行。衍生指标 MUST 先求和同维度新增枚举的基础值再计算。可识别阈值 MUST 展示标准化目标及比较方向;缺失值与零分母 MUST 明确不可计算。有效/待观察/无效分别附建议继续执行/建议再观察一周/建议关停。MUST NOT 回显原始KPI长文本、逐枚举明细或执行关停操作。
|
|
447
|
+
|
|
448
|
+
|
|
449
|
+
### Requirement: 样例总结、逐行排版与入库说明
|
|
450
|
+
四大策略 MUST 分别按样例预算/广告产品/受众/素材总结结构撰写,并放在各自正文最上方;不得复制样例数字或套用同一总结句。维度标题及行首三渠道名 MUST 在Excel原生加粗。金额后 MUST 紧跟环比,100%→100%占比 MUST 隐藏;枚举及其数据 MUST 单独换行。新增/暂停都无值显示未出现变化,单动作0以及上调/下调0项 MUST 省略。预算调价正文 MUST NOT 展示广告组名称或名称分布,明细保留。
|
|
451
|
+
|
|
452
|
+
受众新增广告组 MUST 展示本期合计消耗及该渠道本期总消耗占比;暂停 MUST 使用上期同口径。不补零或使用错误周期分母。Excel MUST 一业务线一行,超长策略仍保存在原单元格,不生成策略续行,不截断正文;原有学习结论与说明保持完整。
|
|
453
|
+
|
|
454
|
+
READY 四个 Learning 字段 MUST 取最终 AI sheet 对应策略末段 Learning 冒号后的完整正文,剥离标题和括号效果;effect MUST 按该括号标签编码,策略正文 MUST 排除末段 Learning。MUST NOT 改写 Excel 原始正文或回退第一张表结论。缺失、重复或不合法 Learning MUST 仅重试 AI,含首次最多三次;穷尽时有合法上下文 MUST 记录 GENERATION_FAILED,不上传或保存 READY。
|
|
455
|
+
|
|
456
|
+
策略展示统一规则:占比差值仍按本期占比减上期占比计算,显示为带符号的百分数(例如 -1.7%),不写“个百分点”。四类策略及总结仅展示本次实际广告账号所属渠道(用户指定账号时以覆盖后的账号为准);无账号渠道不展示,有账号但零消耗的渠道不得因此隐藏。learning 的说明中,动作/原因与后续 KPI 数据之间换行;第一张表保留结论与说明;数据库仅保存 AI sheet 末段 Learning 冒号后的正文并保留内部换行。
|
|
457
|
+
|
|
458
|
+
Excel 主表在项目名称后增加广告账号列(共16列)。列出业务线关联项目的全部广告账号,按 Meta、Google、TikTok 分组去重;渠道名原生加粗、单独一行,其下每个账号 ID 一行,下一个渠道另起行。无账号渠道省略;账号列表完整保留在同一单元格,不因用户覆盖分析账号而缩减。此字段仅供 Excel,不增加数据库入参。
|
|
459
|
+
|
|
460
|
+
|
|
461
|
+
### Requirement: READY 内容来自 AI策略 sheet
|
|
462
|
+
|
|
463
|
+
数据库模式 MUST 在上传前回读并校验最终 Excel 的 `AI策略` sheet,以本业务线唯一数据行的四类策略单元格作为正文与 Learning 来源。每格末尾的独立 Learning 段 MUST 被剥离;括号中的有效、无效、待观察 MUST 分别映射为接口 Effect 的 1、2、3,冒号后非空全文 MUST 写入对应 Learning,保留内部换行,不保存标题和效果标签。末段 MUST 可明确识别为 `Learning(有效/无效/待观察):说明`,兼容英文大小写、半角括号/冒号及单独的 `【Learning】` 小节标题;正文和说明均不能为空。入库 MUST NOT 回退到第一张表的固定正文、效果或 learning。
|
|
464
|
+
|
|
465
|
+
三类标签 MUST 取同一行对应标签列,严格核对本业务线已审核的名称/ID 绑定后传原 ID 数组,不重新匹配或编造 ID。第一张表标签为空且已满足缺少其他的兜底条件时,AI sheet 空标签 MUST 保存为 `[]`。创意不传标签。业务线和周期仍取当前合法上下文,fileStorageKey 仍取上传结果;保存成功、未知结果停止重放及逐条清理 MUST 沿用原规则。
|
|
466
|
+
|
|
467
|
+
#### Scenario: AI 与固定策略结论不同
|
|
468
|
+
|
|
469
|
+
- **GIVEN** 第一张表固定结论为待观察,AI预算单元格末段为 `Learning(有效):点击成本下降。`
|
|
470
|
+
- **WHEN** 数据库模式保存 READY
|
|
471
|
+
- **THEN** budgetStrategyEffect 为 1,budgetStrategyLearning 为 `点击成本下降。`,budgetStrategySupplement 仅含末段之前的 AI 正文
|
|
472
|
+
|
|
473
|
+
#### Scenario: 空标签按已核对兜底保存
|
|
474
|
+
|
|
475
|
+
- **GIVEN** 本业务线某场景无唯一其他且审核兜底确认标签为空,AI sheet 对应列也是空
|
|
476
|
+
- **WHEN** 组装 READY
|
|
477
|
+
- **THEN** 对应 StrategyTags 为 `[]`,其 AI 正文、效果和 Learning 正常保存
|
|
478
|
+
|
|
479
|
+
#### Scenario: 标签错配拒绝上传
|
|
480
|
+
|
|
481
|
+
- **GIVEN** AI sheet 标签名称与本业务线已审核的名称/ID 绑定不一致
|
|
482
|
+
- **WHEN** 上传前校验
|
|
483
|
+
- **THEN** 该业务线失败,不上传或保存 READY,不以其他业务线标签补齐
|
|
484
|
+
|
|
485
|
+
|
|
486
|
+
### Requirement: AI 策略横向单行展示
|
|
487
|
+
|
|
488
|
+
最终工作簿 MUST 依次包含 `策略`、`明细`、`AI策略`。最后一张表 MUST 依次有「一页速览」「预算策略标签」「预算策略」「广告产品策略标签」「广告产品策略」「受众策略标签」「受众策略」「创意策略」八列。三类标签 MUST 直接复制第一张表同业务线的对应标签值,空值也保持一致;素材/创意策略无标签。表头下一行分别保留速览、标签和四段策略全文,Learning 包含在对应策略段内;单条业务线不得按篇幅拆成多行。正文换行和允许的加粗 MUST 保留,前两张表内容 MUST 不变。AI 表单元格 MUST 与前两张表统一引用共享字符串,MUST NOT 使用 inlineStr,以兼容内嵌预览器。本地与数据库模式 MUST 交付相同的三表结构;数据库接口字段名称 MUST 不变,READY 内容 MUST 按本规格从 AI sheet 拆分获取。
|
|
489
|
+
|
|
490
|
+
#### Scenario: 五段正文及三类标签齐全
|
|
491
|
+
|
|
492
|
+
- **GIVEN** AI 返回一页速览和按顺序排列的四类策略
|
|
493
|
+
- **WHEN** 导出最终 Excel
|
|
494
|
+
- **THEN** 第三张表的第二行保存速览、从第一张表复制的三类标签及四段全文,第一行是八列标题
|
|
495
|
+
|
|
496
|
+
#### Scenario: 内嵌预览器读取完整正文
|
|
497
|
+
|
|
498
|
+
- **GIVEN** 最终工作簿含带换行和加粗的 AI 策略正文
|
|
499
|
+
- **WHEN** 读取 AI sheet 单元格的共享字符串索引
|
|
500
|
+
- **THEN** 八列表头与唯一数据行全部可从同一字符串池回读,加粗和换行保留,不存在 inlineStr 单元格
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"""把已生成的 Excel 明细交给执行技能的 Agent 撰写 AI 策略,不在脚本中分析投放。"""
|
|
2
|
+
from datetime import datetime, timezone
|
|
3
|
+
import json
|
|
4
|
+
import time
|
|
5
|
+
from uuid import uuid4
|
|
6
|
+
|
|
7
|
+
from build_report import prepare_ai_sections
|
|
8
|
+
from strategy_output import split_ai_learning
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class AiStrategyExhausted(RuntimeError):
|
|
12
|
+
"""AI 文案三次均未取得有效回包;批次不得再重跑整条业务线。"""
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def review_ai_strategy(root, workbook, prompt_path, cancel, progress, *,
|
|
16
|
+
biz_line_id, attempt, wait_seconds=900, require_learning=False):
|
|
17
|
+
"""只等待本业务线绑定的 Agent 回包;失败只重发 AI 请求。"""
|
|
18
|
+
if type(biz_line_id) is not int or biz_line_id <= 0 or type(attempt) is not int or attempt <= 0:
|
|
19
|
+
raise ValueError('AI 策略请求缺少有效业务线 ID 或轮次')
|
|
20
|
+
if wait_seconds <= 0:
|
|
21
|
+
raise ValueError('AI 策略等待上限必须大于 0')
|
|
22
|
+
if not workbook.is_file():
|
|
23
|
+
raise ValueError('AI 策略请求缺少已校验的工作簿')
|
|
24
|
+
|
|
25
|
+
failures = []
|
|
26
|
+
for review_attempt in range(1, 4):
|
|
27
|
+
if cancel.is_set():
|
|
28
|
+
raise InterruptedError('任务已取消')
|
|
29
|
+
prompt = prompt_path.read_text(encoding='utf-8')
|
|
30
|
+
if not prompt.strip():
|
|
31
|
+
raise ValueError('AI 策略提示词为空')
|
|
32
|
+
# 每次请求都使用独立文件和随机 ID,迟到回包不能被后续尝试误收。
|
|
33
|
+
request_path = root / f'ai-strategy.{review_attempt}.request.json'
|
|
34
|
+
response_path = root / f'ai-strategy.{review_attempt}.response.json'
|
|
35
|
+
request_id = uuid4().hex
|
|
36
|
+
request = {
|
|
37
|
+
'bizLineId': biz_line_id, 'attempt': attempt, 'requestId': request_id,
|
|
38
|
+
'prompt': prompt, 'promptPath': str(prompt_path),
|
|
39
|
+
'workbookPath': str(workbook), 'worksheetName': '明细',
|
|
40
|
+
}
|
|
41
|
+
if require_learning:
|
|
42
|
+
# 机械入库格式与独立分析提示词分开,不引入固定策略或额外投放数据。
|
|
43
|
+
request['outputContract'] = (
|
|
44
|
+
'四段策略各以独立末段 Learning(有效/无效/待观察):说明 结束;'
|
|
45
|
+
'每段只能有一个 Learning,正文和冒号后的说明均非空,可保留换行。')
|
|
46
|
+
request_path.write_text(json.dumps(request, ensure_ascii=False), encoding='utf-8')
|
|
47
|
+
issued_at = datetime.now(timezone.utc).isoformat(timespec='milliseconds').replace('+00:00', 'Z')
|
|
48
|
+
started = time.monotonic()
|
|
49
|
+
progress({'event': 'ai_strategy_required', 'bizLineId': biz_line_id, 'attempt': attempt,
|
|
50
|
+
'reviewAttempt': review_attempt, 'requestId': request_id, 'issuedAt': issued_at,
|
|
51
|
+
'request_path': str(request_path), 'response_path': str(response_path)})
|
|
52
|
+
deadline = started + wait_seconds
|
|
53
|
+
while not cancel.is_set():
|
|
54
|
+
if time.monotonic() >= deadline:
|
|
55
|
+
reason = '等待 AI 策略回包超时'
|
|
56
|
+
break
|
|
57
|
+
if response_path.exists():
|
|
58
|
+
try:
|
|
59
|
+
reply = json.loads(response_path.read_text(encoding='utf-8-sig'))
|
|
60
|
+
if not isinstance(reply, dict) or set(reply) != {'bizLineId', 'attempt', 'requestId', 'text'}:
|
|
61
|
+
raise ValueError('AI 策略回包结构无效')
|
|
62
|
+
# 先严格绑定业务线、轮次与本次请求,再接收自然语言正文。
|
|
63
|
+
if type(reply['bizLineId']) is not int or reply['bizLineId'] != biz_line_id or \
|
|
64
|
+
type(reply['attempt']) is not int or reply['attempt'] != attempt or \
|
|
65
|
+
not isinstance(reply['requestId'], str) or reply['requestId'] != request_id:
|
|
66
|
+
raise ValueError('AI 策略回包身份与当前业务线不一致')
|
|
67
|
+
value = reply['text']
|
|
68
|
+
if not isinstance(value, str) or not value.strip():
|
|
69
|
+
raise ValueError('AI 策略正文为空')
|
|
70
|
+
# 同导出器共用机械分段校验,拒绝错列或超长回包后只重试 AI 阶段。
|
|
71
|
+
sections = prepare_ai_sections(value)
|
|
72
|
+
if require_learning:
|
|
73
|
+
for plain, _parts in sections[1:]:
|
|
74
|
+
split_ai_learning(plain)
|
|
75
|
+
except (ValueError, UnicodeError) as exc:
|
|
76
|
+
reason = str(exc)
|
|
77
|
+
break
|
|
78
|
+
progress({'event': 'ai_strategy_accepted', 'bizLineId': biz_line_id,
|
|
79
|
+
'attempt': attempt, 'reviewAttempt': review_attempt,
|
|
80
|
+
'requestId': request_id, 'waitSeconds': round(time.monotonic() - started, 3)})
|
|
81
|
+
return value
|
|
82
|
+
cancel.wait(min(0.2, max(0, deadline - time.monotonic())))
|
|
83
|
+
if cancel.is_set():
|
|
84
|
+
raise InterruptedError('任务已取消')
|
|
85
|
+
failures.append({'reviewAttempt': review_attempt, 'reason': reason})
|
|
86
|
+
progress({'event': 'ai_strategy_rejected', 'bizLineId': biz_line_id,
|
|
87
|
+
'attempt': attempt, 'reviewAttempt': review_attempt,
|
|
88
|
+
'requestId': request_id, 'reason': reason})
|
|
89
|
+
raise AiStrategyExhausted('AI 策略生成三次失败:' + ';'.join(item['reason'] for item in failures))
|