소스 검색

docs: update demand output v1 rollout checklist

SamLee 3 주 전
부모
커밋
1fe3ccc7f6
2개의 변경된 파일188개의 추가작업 그리고 26개의 파일을 삭제
  1. 129 13
      demand_output_improve_plan.md
  2. 59 13
      demandagent给下游的迭代需求.md

+ 129 - 13
demand_output_improve_plan.md

@@ -2,7 +2,7 @@
 
 ## Summary
 
-这次不是“DemandAgent 对接 ContentFindingAgent”,而是 **DemandAgent 自身输出结构升级**:在不改真实 DB schema、不真实写 DB 的前提下,核心只调整普通需求池 `demand_content.ext_data`,增加结构化 `evidence_pack`。原本会写入 `dwd_multi_demand_pool_di`、`feature_point_data`、`demand_task` 的数据,MVP 阶段只做本地 JSON 镜像和回归检查,不改它们的业务字段结构。
+这次不是“DemandAgent 对接 ContentFindingAgent”,而是 **DemandAgent 自身输出结构升级**:在不改真实 DB schema 的前提下,核心只调整普通需求池 `demand_content.ext_data`,增加结构化 `evidence_pack`。V1 同时保留两种受控输出模式:`local_json` 用于本地回归,只写本地 JSON;`mysql_demand_content` 用于云端测试服,只写 MySQL `demand_content` 单表。原本会写入 `dwd_multi_demand_pool_di`、`feature_point_data`、`demand_task` 的数据,V1 阶段不真实写入这些表,也不改它们的业务字段结构。
 
 本次 DemandAgent 侧补齐的是上游 exact evidence 基础:它能让需求单携带真实 DB 校验过的 Pattern/itemset/category 证据,但最终链路还要求 ContentFindAgent 读取、继承并沉淀结构化 `source_evidence`,否则最终结果仍无法从 `post_id/aweme_id` exact 回到 Pattern 和分类树节点。
 
@@ -39,6 +39,86 @@ PG Pattern V2 替换更新:正式证据源已经切到 PG `open_aigc.public` 
 
 `demand_task` 是任务台账,不算业务结果输出表。本地模式只模拟它的创建和完成状态,方便串起 `demand_task_id`,不改变业务输出结构。
 
+## V1 阶段开发清单
+
+本清单用于承接“待决策事项”与当前开发执行状态。当前 checkout 中未找到独立的 `待决策事项.md` 文件,因此本节只吸收已经在本方案、`demandagent给下游的迭代需求.md`、真实代码和已拍板沟通中能被证实的事项;未找到原文依据的内容统一放入“待补充”,不擅自替用户补决策。
+
+### 1. 已拍板并进入 V1 的事项
+
+| 事项 | V1 处理方式 | 真实依据 |
+| --- | --- | --- |
+| Pattern 证据源 | 只使用 PG Pattern V2,`pattern_source_system` 唯一合法值为 `pg_pattern_v2` | `pg_pattern_repository.py` 只读 PG `pattern_mining_*` / `pattern_itemset*`;`evidence_pack_builder.py` 固定 `PATTERN_SOURCE_SYSTEM = "pg_pattern_v2"` |
+| Pattern scope | V1 只输出 `pattern_itemset.scope='topic'` | `evidence_pack_builder.py` 校验 `PATTERN_ITEMSET_SCOPE = "topic"`;`pg_pattern_repository.py` 定义 `TOPIC_SCOPE = "topic"` |
+| 旧 MySQL Pattern | 删除弃用,不作为任何新版 evidence 来源 | `demandagent给下游的迭代需求.md` 已明确旧 `topic_pattern_*` 链路删除弃用;当前 PG repository 不读取旧 `topic_pattern_*` |
+| 下游主载体 | `demand_content.ext_data.evidence_pack` 是给下游的主证据包 | `run.py` 构造 `ext_data.evidence_pack`;`mysql_demand_content_sink.py` 入库前强校验该字段 |
+| LLM 与证据真实性边界 | LLM 只产出候选 `evidence_refs`;最终 `evidence_pack` 必须由代码 DB 强校验补齐 | `run.py` 读取候选 `evidence_refs` 后调用 `build_evidence_pack()`;`evidence_pack_builder.py` 失败返回 reject |
+| 云端 V1 输出 | 开发/测试服可以真实写云端 MySQL 单表 `demand_content`,但只写这一张表 | `run_existing_execution_mysql.py` 注释和入口约束;`mysql_demand_content_sink.py` 只执行 `INSERT/UPDATE demand_content` |
+| 本地 V1 输出 | local 回归仍保留 `local_json`,产物写入 `examples/demand/test_output_data/{run_id}` | `run_existing_execution_local.py` 与 `local_output_sink.py` |
+| Agent 框架边界 | 不改 `agent/` 通用框架;只改 `examples/demand` 业务域 | 本方案“改动归属”已定义;代码改动集中在 `examples/demand` |
+| 下游消费口径 | 当前验收按本输出契约,不按尚未适配完成的 ContentFindAgent 旧 scheduler 代码验收 | 已拍板:下游代码未完成最新结构适配,本轮按 `demand_output_improve_plan.md` 验收 |
+
+### 2. 需按默认值推进的事项
+
+这些不是新决策,而是当前代码已经存在的默认值或运行约束;V1 执行时按代码默认推进,后续如产品要改,需要单独决策。
+
+| 事项 | 默认值 / 默认行为 | 代码位置与含义 |
+| --- | --- | --- |
+| PG execution 入参 | CLI 必须显式传已有 `pattern_mining_execution.id`;测试默认样本使用已验证的 `581` | `run_existing_execution_mysql.py` / `run_existing_execution_local.py` 都要求 `--execution-id` |
+| execution 状态 | 只允许 `status='success'` | `run_existing_execution_mysql.py` 启动前调用 `query_execution_for_evidence()` 校验 |
+| MySQL 写入模式 | `DEMAND_OUTPUT_MODE=mysql_demand_content` 只能通过 `examples.demand.run_existing_execution_mysql` 入口设置 | `run.py` 的 `_require_mysql_entrypoint()` |
+| 本地 JSON 模式 | `DEMAND_OUTPUT_MODE=local_json` 只能通过 `examples.demand.run_existing_execution_local` 入口设置 | `run.py` 的 `_require_local_entrypoint()` |
+| ID 语义 | `case_id_type` 固定为 `post_id` | `evidence_pack_builder.py` 构造 `case_id_type="post_id"` |
+| Pattern case 列表 | `video_ids` 与 `case_ids` 默认等于 DB 校验后的 `matched_post_ids` | `evidence_pack_builder.py` 构造两者;`mysql_demand_content_sink.py` 入库前校验相等 |
+| decode 兼容字段 | `decode_case_ids` 在 PG-only V1 中默认可为空数组,不参与 Pattern exact 闭合 | `evidence_pack_builder.py` 单独查询并写入;未命中不影响 Pattern itemset 通过 |
+| 证据状态 | accepted demand 固定为 `source_certainty=db_validated`、`validation_status=passed` | `evidence_pack_builder.py` 构造固定状态;MySQL sink 入库前复验 |
+| MySQL 单表去重 | 同一 `run_label + name + evidence_pack.source_post_id` 已存在时跳过 | `mysql_demand_content_sink.py` 的 `_row_exists_for_run()` |
+| MySQL 入库回填 | 插入后用真实自增 `id` 回填 `ext_data.evidence_pack.demand_content_id` | `mysql_demand_content_sink.py` 插入后 update 同一行 |
+| 单表模式任务 ID | 不建 `demand_task` 时,`demand_task_id` 不能伪装成真实 DB ID;可为 `null` 或运行侧模拟值,语义必须在 run manifest / 日志中说明 | 当前 `run_existing_execution_mysql.py` 调用 `main(..., task_id=None)` |
+| MySQL entrypoint 工具白名单 | 只开放 `get_frequent_itemsets/get_itemset_detail/create_demand_item/create_demand_items` | `run.py` 的 `_enabled_tools_for_run()` |
+| 工具返回压缩 | `DEMAND_ITEMSET_DETAIL_MAX_IDS=12`、`DEMAND_ITEMSET_DETAIL_MAX_POST_IDS=20` | `run_existing_execution_mysql.py` 设置默认环境变量 |
+| LLM 模型解析 | 优先读 `DEMAND_LLM_MODEL`,再读 `ARK_MODEL` / OpenRouter 相关变量 | `run.py` 的 `resolve_model()` |
+| PG 连接配置 | 优先读 `DEMAND_PATTERN_PG_DSN`,再读 `PGVECTOR_DSN` | `pg_pattern_repository.py` 的 `_resolve_dsn()` |
+| MySQL 连接配置 | 优先读 `DEMAND_CONTENT_MYSQL_DSN`,否则读 `DEMAND_CONTENT_MYSQL_*`,再 fallback 到 `CONTENT_SUPPLY_DB_*` | `mysql_demand_content_sink.py` 的 `_resolve_mysql_config()` |
+
+### 3. 待补充但不能阻塞 V1 单表验证的事项
+
+这些事项尚未形成可执行决策,或当前真实代码/文档还没有完全闭合。V1 可以继续推进 100 条测试,但必须在交付说明中标明边界。
+
+| 待补充事项 | 当前缺口 | V1 临时处理 |
+| --- | --- | --- |
+| 原始 `待决策事项.md` | 当前仓库及 `/Users/samlee/Documents/works` 三层内未找到该文件,无法逐条引用原文 | 本节先按已拍板沟通和现有两份文档吸收;若用户提供文件,需要再做一次逐条 diff |
+| ContentFindAgent 最新适配 | 下游新版代码尚未完成,不按旧 scheduler 验收 | 只按本契约校验 `demand_content.ext_data.evidence_pack`;CFA 后续需继承并沉淀 `source_evidence` |
+| 100 条正式批次完成报告 | 代码和云端链路已能写 MySQL,但最终批次需要以云端 SQL 统计为准 | 以 `run_label` 前缀查询数量和逐条 evidence 校验,不用本地 JSON 数量替代 |
+| 生产任务闭环 | 单表 `demand_content` 不能支撑旧调度、去重、结果回写 | V1 只验收 FH/CFA 可读取需求结构;不验收旧 `server.py` 自动调度 |
+| 独立 evidence 表 | 当前只写 `ext_data.evidence_pack`,未拆关系表 | V1 不拆表;如 `ext_data` 变大或下游要 SQL join,再进入 V1.1 |
+| `topic_element` exact 方案 | 真实 PG 样本中存在分类路径缺失,不能保证 exact 回分类树 | V1 不输出;后续必须先补齐分类树节点或定义降级语义 |
+| PG Pattern V2 页面主事实链接 | 当前 evidence 能回 PG 表,但未定义前端页面 URL 或跨系统跳转 ID | V1 只保证表级 exact;页面级跳转另列需求 |
+
+### 4. V1 明确不处理的事项
+
+| 不处理事项 | 原因 |
+| --- | --- |
+| 不恢复旧 MySQL `topic_pattern_*` evidence | 已删除弃用,任何最终证据来自旧 MySQL 都必须 rejected |
+| 不输出 `topic_element`、script、paragraph、group scope | 不能保证每条证据都有 `category_id/category_path` 回到分类树节点 |
+| 不改 PG Pattern V2 数据库 schema | DemandAgent 是下游消费方,只读 PG 主事实 |
+| 不改 `agent/` runner / tool registry / trace store / LLM 框架 | 本次是 Demand 业务域输出协议升级 |
+| 不写 `demand_task`、Hive/ODPS、旧 Pattern 中间表 | V1 云端只写 MySQL `demand_content` 单表;本地模式只写 JSON |
+| 不保证旧 ContentFindAgent scheduler 自动闭环 | 旧 scheduler 还需要 `demand_find_task` 和结果表,已超出单表 V1 范围 |
+| 不把 rejected DemandItem 下发给下游 | rejected 只用于 DemandAgent 排查,不能作为可消费需求 |
+
+### 5. V1 验收清单
+
+| 验收项 | 必须满足 |
+| --- | --- |
+| 证据真实性 | 每条 accepted row 的 `evidence_pack.source_certainty='db_validated'` 且 `validation_status='passed'` |
+| PG-only | `evidence_pack.pattern_source_system='pg_pattern_v2'`,不得出现 `mysql_topic_pattern` 或旧 `topic_pattern_*` 来源 |
+| itemset 闭合 | `pattern_execution_id/mining_config_id/itemset_ids/itemset_items/support/absolute_support` 均来自同一 PG execution 且 scope 为 `topic` |
+| post 闭合 | `matched_post_ids` 来自 `pattern_itemset_post`,`source_post_id in matched_post_ids`,`video_ids == case_ids == matched_post_ids` |
+| 分类树闭合 | `itemset_items[]` 与 `category_bindings[]` 均有 `category_id/category_path` |
+| 元素证据闭合 | `element_bindings[]` 非空,且来自 PG `pattern_mining_element` |
+| 写库范围 | 云端 V1 只能写 MySQL `demand_content`;不能写 `demand_task`、Hive、PG Pattern 或旧 MySQL Pattern |
+| 下游契约 | 给 FH/CFA 的主输入是 MySQL `demand_content` 行或其导出的 `demand_content.json`,不是 `demand_items` 或 `rejected_demand_items` |
+
 ## 改动归属:Agent 框架 vs examples/demand 业务域
 
 ### 1. 不涉及 Agent 通用框架的改动
@@ -73,7 +153,7 @@ PG Pattern V2 替换更新:正式证据源已经切到 PG `open_aigc.public` 
 
 本次实际改动都落在 `examples/demand`,属于 DemandAgent 示例业务域,也就是当前 Demand 生成链路的业务实现层。
 
-当前改动已经完成业务入口、DB 强校验和本地 sink 的 MVP 闭环:`demand_build_agent_tools.py` 产出候选 `evidence_refs`,`evidence_pack_builder.py` 用真实 DB 只读校验并补齐 `evidence_pack`,`run.py` 只把 passed rows 写入本地 `demand_content.json`,失败项写入 `rejected_demand_items.json`。
+当前改动已经完成业务入口、DB 强校验和受控 sink 的 V1 闭环:`demand_build_agent_tools.py` 产出候选 `evidence_refs`,`evidence_pack_builder.py` 用真实 DB 只读校验并补齐 `evidence_pack`。`local_json` 模式只把 passed rows 写入本地 `demand_content.json`,失败项写入 `rejected_demand_items.json`;`mysql_demand_content` 模式只把 passed rows 写入测试服 MySQL `demand_content` 单表,失败项只记日志,不进入下游需求池
 
 具体包括:
 
@@ -89,8 +169,8 @@ PG Pattern V2 替换更新:正式证据源已经切到 PG `open_aigc.public` 
 
 - `examples/demand/run.py`
   - 调整结果写出路径。
-  - 增加 `local_json` 本地输出模式。
-  - 避免 MVP 测试时真实写 `demand_task` / `demand_content`
+  - 增加 `local_json` 本地回归模式和 `mysql_demand_content` 测试服单表写入模式。
+  - 避免 V1 测试时真实写 `demand_task` / Hive / PG Pattern / 旧 MySQL Pattern
   - 这是 DemandAgent 业务 orchestration 改动。
 
 - `examples/demand/data_query_tools.py`
@@ -114,6 +194,16 @@ PG Pattern V2 替换更新:正式证据源已经切到 PG `open_aigc.public` 
   - 只允许传已有 PG `pattern_mining_execution.id`。
   - 禁止调用 `run_mining`,避免写 Pattern 中间表。
 
+- `examples/demand/run_existing_execution_mysql.py`
+  - 新增云端测试服单表写入入口。
+  - 只允许传已有 PG `pattern_mining_execution.id`。
+  - 强制 `DEMAND_OUTPUT_MODE=mysql_demand_content`,只写 MySQL `demand_content`。
+
+- `examples/demand/mysql_demand_content_sink.py`
+  - 新增测试服 MySQL 单表 sink。
+  - 入库前强校验 `ext_data.evidence_pack`,插入后回填真实 `demand_content_id`。
+  - 不创建或写入 `demand_task`、Hive、PG Pattern、旧 MySQL Pattern。
+
 ## Key Changes
 
 1. DemandItem 输出结构增强
@@ -175,8 +265,32 @@ record = {
       "source_kind": "pattern_itemset",
       "case_id_type": "post_id",
       "source_post_id": "02454b8dab4c13c9fa21042bdc92d122",
-      "category_bindings": [],
-      "element_bindings": [],
+      "category_bindings": [
+        {
+          "itemset_id": 1607313,
+          "itemset_item_id": 6051234,
+          "category_id": 123456,
+          "category_name": "示例分类",
+          "category_path": "/形式/...",
+          "category_full_path": "/形式/...",
+          "point_type": "关键点",
+          "dimension": "形式",
+          "element_name": null
+        }
+      ],
+      "element_bindings": [
+        {
+          "itemset_id": 1607313,
+          "itemset_item_id": 6051234,
+          "category_id": 123456,
+          "point_type": "关键点",
+          "dimension": "形式",
+          "element_name": "示例元素",
+          "matched_element_count": 1,
+          "matched_post_count": 1,
+          "matched_post_ids": ["02454b8dab4c13c9fa21042bdc92d122"]
+        }
+      ],
       "itemset_ids": [1607313],
       "itemset_items": [
         {
@@ -195,7 +309,7 @@ record = {
       "decode_case_ids": [],
       "seed_terms": ["权钱交易", "利益输送"],
       "trace_id": "...",
-      "demand_task_id": 1,
+      "demand_task_id": null,
       "demand_content_id": 1,
       "source_certainty": "db_validated",
       "validation_status": "passed"
@@ -207,7 +321,7 @@ record = {
 
 3. `dwd_multi_demand_pool_di` / `feature_point_data` 不改业务结构,仅做本地镜像
 
-本地目录仍保留多文件,目的是完整复刻本次 run 的所有输出,便于回归验证“不真实写 DB / Hive”
+本地目录仍保留多文件,目的是完整复刻本次 run 的所有输出,便于回归验证 `local_json` 模式不真实写 DB / Hive
 
 ```text
 test_output_data/{run_id}/
@@ -259,9 +373,10 @@ test_output_data/{run_id}/
 | `seed_terms` | LLM 候选 + 代码校验后的 element/category/itemset 反推 | 最终输出必须能被已校验证据覆盖;否则拒绝该需求 | 候选阶段受影响,最终输出必须被证据覆盖 |
 | `source_kind` | LLM 候选明确声明;若缺失但已有 `itemset_ids` 或 `source_tool=get_itemset_detail`,DemandAgent 内部可安全补齐为 `pattern_itemset` | MVP 只支持 `pattern_itemset`;补齐后仍必须走 DB 强校验,不是 Pattern itemset 则拒绝 | 候选阶段受影响,最终输出必须 DB 校验通过 |
 | `trace_id` | 现有 Agent runner / trace store | 框架事实 | 否 |
-| `demand_content_id` | 生产写库后为真实 `demand_content.id`;MVP 本地为模拟 ID | 生产真实,MVP 测试模拟 | 否 |
+| `demand_task_id` | 本地回归可为模拟任务 ID;云端单表模式因不建 `demand_task` 可为 `null` | 不能伪装成真实 DB task id | 否 |
+| `demand_content_id` | 云端单表写库后为真实 `demand_content.id`;本地回归为模拟 ID | 云端测试服真实,本地回归模拟 | 否 |
 
-因此最终进入 `demand_content` 的 `evidence_pack` 只能出现
+因此最终进入 `demand_content` 的 `evidence_pack` 必须包含完整证据字段;其中状态字段的取值只能是
 
 ```json
 {
@@ -318,8 +433,9 @@ local 模式只能通过 `examples.demand.run_existing_execution_local` 进入
 
 ## Test Plan
 
-- 写库屏障测试:本地模式下 monkeypatch `mysql_db.insert/update/insert_many`、`execute_odps_sql` 和 PG DML/DDL,若被调用则测试失败;PG repository 只允许 `SELECT/SHOW/EXPLAIN`。
-- 输出结构测试:校验本地 JSON 文件存在;重点校验 `demand_content.ext_data.evidence_pack`,同时确认 `dwd_multi_demand_pool_di.json` / `feature_point_data.json` 没有新增业务字段。
+- 写库屏障测试:`local_json` 模式下 monkeypatch `mysql_db.insert/update/insert_many`、`execute_odps_sql` 和 PG DML/DDL,若被调用则测试失败;PG repository 只允许 `SELECT/SHOW/EXPLAIN`。
+- 云端单表写库测试:`mysql_demand_content` 模式下只允许 MySQL `demand_content` 的 `INSERT/UPDATE`;不得调用 `_create_demand_task/_finish_demand_task`、Hive/ODPS 写入、PG DML/DDL 或旧 MySQL Pattern 写入。
+- 输出结构测试:本地回归校验 JSON 文件存在;云端测试服按 `run_label` 查询 MySQL `demand_content` 行。两种模式都重点校验 `demand_content.ext_data.evidence_pack`,同时确认 `dwd_multi_demand_pool_di` / `feature_point_data` 不新增业务字段。
 - evidence 测试:校验所有进入 `demand_content` 的 `evidence_pack.pattern_execution_id/source_kind/seed_terms/trace_id/source_certainty/validation_status` 必填,`validation_status` 必须为 `passed`,`source_certainty` 必须为 `db_validated`。
 - Pattern itemset evidence 测试:当 `source_kind=pattern_itemset` 时,`pattern_source_system/case_id_type/source_post_id/mining_config_id/itemset_ids/itemset_items/matched_post_ids/support/absolute_support` 必填,且 `source_post_id` 必须在 `matched_post_ids` 中,`len(matched_post_ids)` 必须等于 `absolute_support`。
 - 严格拒绝测试:构造 LLM 声明错误 itemset、跨 execution itemset、缺少 `matched_post_ids/source_post_id/itemset_items/mining_config_id`、DB 校验失败等样本,验证这些 DemandItem 不进入 `demand_content`,只进入 `rejected_demand_items.json`。
@@ -328,7 +444,7 @@ local 模式只能通过 `examples.demand.run_existing_execution_local` 进入
 
 ## Assumptions
 
-- MVP 不做真实 DB 写入,也不做 DB schema migration
+- V1 不做 DB schema migration;本地回归模式不写 DB,云端测试服模式只写 MySQL `demand_content` 单表
 - 本次只调整 DemandAgent 输出,不改 `agent/` 通用框架。
 - 本次下游证据链只以 `demand_content.ext_data.evidence_pack` 为载体;`dwd_multi_demand_pool_di` 和 `feature_point_data` 不承载 evidence_pack。
 - DemandAgent 当前正式证据源是 PG `open_aigc.public` Pattern V2 主事实;旧 MySQL Pattern 兼容层只作为历史背景,不再作为 evidence 来源。

+ 59 - 13
demandagent给下游的迭代需求.md

@@ -33,7 +33,7 @@
 | `seed_terms` | 记录真正给 Query 使用的下层特征或元素词 |
 | `source_evidence` | ContentFindAgent 从 `evidence_pack` 继承并追加运行态字段后形成的下游结果证据,不由 DemandAgent 直接输出 |
 | `source_certainty` / `validation_status` | 标记证据是否已经 DB 强校验通过 |
-| `trace_id` / `demand_task_id` / `demand_content_id` | 串起需求生成、内容寻找、判断、沉淀和策略学习 |
+| `trace_id` / `demand_content_id` / `demand_task_id` | 串起需求生成、内容寻找、判断、沉淀和策略学习;其中 V1 云端单表模式不建 `demand_task`,`demand_task_id` 可为空 |
 
 V1 不一定马上改复杂 DB schema。可以先在 `demand_content.ext_data` 里增加一个结构化 `evidence_pack`,先把证据传下来。
 
@@ -90,15 +90,17 @@ DemandAgent 当前生成的 `DemandItem` 是 LLM / tool 产生的候选业务需
 
 ### 3.2 demand_content
 
-新版 local MVP 中,DemandAgent 不真实写 `demand_content` DB,而是写本地 `demand_content.json`。未来恢复生产写库时,正式给下游的载体仍是 `demand_content.ext_data.evidence_pack`。
+新版 V1 有两种受控输出模式:`local_json` 用于本地回归,只写本地 `demand_content.json`;`mysql_demand_content` 用于云端测试服,只写 MySQL `demand_content` 单表。两种模式下,正式给下游的证据载体都是 `demand_content.ext_data.evidence_pack`。
 
 代码证据:
 
 - `/Users/samlee/Documents/works/DemandAgentNew/examples/demand/run.py`
 - `/Users/samlee/Documents/works/DemandAgentNew/examples/demand/evidence_pack_builder.py`
 - `/Users/samlee/Documents/works/DemandAgentNew/examples/demand/local_output_sink.py`
+- `/Users/samlee/Documents/works/DemandAgentNew/examples/demand/run_existing_execution_mysql.py`
+- `/Users/samlee/Documents/works/DemandAgentNew/examples/demand/mysql_demand_content_sink.py`
 
-当前本地 `demand_content.json` 字段:
+当前 `demand_content` 字段:
 
 | `demand_content` 字段 | 来源 |
 | --- | --- |
@@ -114,11 +116,11 @@ DemandAgent 当前生成的 `DemandItem` 是 LLM / tool 产生的候选业务需
 
 `video_ids` 在新版 PG-only 链路中来自 DB 校验后的 `evidence_pack.video_ids/matched_post_ids`。`pattern_execution_id` 指 PG `pattern_mining_execution.id`,不是旧 MySQL execution,也不是 DemandAgent 本地 run id。
 
-真实 DB 中 `demand_content.ext_data` 是 MySQL JSON 字段,可以承载完整 `evidence_pack`;但当前生产样例仍多为 `reason/desc/type/video_ids`,还没有稳定落下新版 PG `evidence_pack`。这就是本次需求要补齐的输出契约。
+真实 DB 中 `demand_content.ext_data` 是 MySQL JSON 字段,可以承载完整 `evidence_pack`。V1 云端测试服单表模式会插入 `demand_content` 后回填真实 `demand_content.id` 到 `ext_data.evidence_pack.demand_content_id`;不建 `demand_task` 时,`demand_task_id` 不得伪装成真实 DB ID,可为空或使用明确标注的模拟/运行 ID。当前生产样例仍多为 `reason/desc/type/video_ids`,还没有稳定落下新版 PG `evidence_pack`。这就是本次需求要补齐的输出契约。
 
 ### 3.3 dwd_multi_demand_pool_di
 
-新版 local MVP 不写 Hive,只生成本地 `dwd_multi_demand_pool_di.json` 镜像。这个文件不是给 ContentFindAgent 做 exact 回溯的主输入。
+`local_json` 回归模式不写 Hive,只生成本地 `dwd_multi_demand_pool_di.json` 镜像。这个文件不是给 ContentFindAgent 做 exact 回溯的主输入。
 
 代码证据:
 
@@ -219,7 +221,7 @@ features
 | `source_certainty` | 证据可信度,进入下游时必须为 `db_validated` | 下游判断是否能 exact 回溯 | CFA 无法判断 LLM 声明是否已被 DB 校验 | 把候选证据误当真实证据 |
 | `validation_status` | DemandAgent 证据校验状态,进入需求池时必须为 `passed` | 下游只消费通过校验的任务 | CFA 事后补查无法恢复生成时的拒绝原因 | 失败证据流入下游 |
 | `trace_id` | 贯穿下游任务的 trace | 策略学习、失败复盘 | CFA 可创建自己的 trace,但不能补上游生成过程 | 上下游链路断开 |
-| `demand_task_id` | DemandAgent 侧任务 ID | 回查生成日志和任务状态 | CFA 无法凭需求名可靠找到唯一任务 | 无法定位上游运行 |
+| `demand_task_id` | DemandAgent 侧任务 ID;V1 云端单表模式不建 `demand_task` 时可为空 | 本地回归可回查模拟任务;云端单表模式主要依赖 `trace_id/run_label/demand_content_id` | CFA 无法凭需求名可靠找到唯一任务 | 若产品要求任务台账,需要另建真实任务表;单表 V1 不伪装真实 task |
 | `demand_content_id` | 下游领取的需求 ID | CFA 主任务绑定 | 这个字段 CFA 已能拿到,但应进入统一证据包 | Trace 不统一 |
 
 ## 7. 检查过程与证据
@@ -345,8 +347,32 @@ V1 建议先不要大改表结构,先扩展 `demand_content.ext_data`。
         "element_name": null
       }
     ],
-    "category_bindings": [],
-    "element_bindings": [],
+    "category_bindings": [
+      {
+        "itemset_id": 1607313,
+        "itemset_item_id": 6051234,
+        "category_id": 123456,
+        "category_name": "示例分类",
+        "category_path": "/形式/...",
+        "category_full_path": "/形式/...",
+        "point_type": "关键点",
+        "dimension": "形式",
+        "element_name": null
+      }
+    ],
+    "element_bindings": [
+      {
+        "itemset_id": 1607313,
+        "itemset_item_id": 6051234,
+        "category_id": 123456,
+        "point_type": "关键点",
+        "dimension": "形式",
+        "element_name": "示例元素",
+        "matched_element_count": 1,
+        "matched_post_count": 1,
+        "matched_post_ids": ["02454b8dab4c13c9fa21042bdc92d122"]
+      }
+    ],
     "support": 0.000075,
     "absolute_support": 1,
     "matched_post_ids": ["02454b8dab4c13c9fa21042bdc92d122"],
@@ -355,7 +381,7 @@ V1 建议先不要大改表结构,先扩展 `demand_content.ext_data`。
     "decode_case_ids": [],
     "seed_terms": ["从 PG itemset item / category path 推导的真实词"],
     "trace_id": "...",
-    "demand_task_id": 123,
+    "demand_task_id": null,
     "demand_content_id": 456,
     "source_certainty": "db_validated",
     "validation_status": "passed"
@@ -367,7 +393,7 @@ V1 建议先不要大改表结构,先扩展 `demand_content.ext_data`。
 
 | 阶段 | 建议 |
 | --- | --- |
-| V1 必须 | `pattern_source_system`, `source_kind`, `case_id_type`, `source_post_id`, `pattern_execution_id`, `mining_config_id`, `itemset_ids`, `itemset_items[]`, `category_bindings`, `element_bindings`, `support`, `absolute_support`, `matched_post_ids`, `video_ids/case_ids`, `seed_terms`, `trace_id`, `source_certainty`, `validation_status` |
+| V1 必须 | `pattern_source_system`, `source_kind`, `case_id_type`, `source_post_id`, `pattern_execution_id`, `mining_config_id`, `itemset_ids`, `itemset_items[]`, `category_bindings`, `element_bindings`, `support`, `absolute_support`, `matched_post_ids`, `video_ids/case_ids`, `seed_terms`, `trace_id`, `source_certainty`, `validation_status`;accepted demand 中 `category_bindings` / `element_bindings` 必须非空 |
 | V1 兼容字段 | `decode_case_ids`,PG-only 当前固定为空数组;如后续重新引入 decode row ID,需要另做下游契约 |
 | V1.1 增强 | 独立证据表、下游完整判断日志、topic_element 后续分类树补齐方案 |
 | 后续再拆表 | 如果 `evidence_pack` 变大,再考虑独立证据表或关系表 |
@@ -411,15 +437,17 @@ DemandAgent 代码必须按真实 DB 校验并补齐 `evidence_pack`。对于 `s
 | `element_bindings` | 必须能用 `execution_id + source_post_id + category_id + point_type + dimension/element_type + element_name(如有)` 精确绑定到 PG `pattern_mining_element`,且限定 `source_table='post_decode_topic_point_element'` |
 | `source_certainty` / `validation_status` | 进入 `demand_content` 时只能是 `db_validated` / `passed` |
 
-在当前官方 `local_json` MVP 路径中,任一必需字段查不到、跨 execution、post 不在 matched posts、category 不在当前 execution、source post 精确 element binding 不成立,当前 DemandItem 都失败,不写入本地 `demand_content.json`。失败项只进入本地 `rejected_demand_items.json`,Agent 继续生成下一条需求。
+在当前官方 V1 路径中,任一必需字段查不到、跨 execution、post 不在 matched posts、category 不在当前 execution、source post 精确 element binding 不成立,当前 DemandItem 都失败。`local_json` 模式不写入本地 `demand_content.json`,失败项进入本地 `rejected_demand_items.json`;`mysql_demand_content` 模式不写入 MySQL `demand_content`,失败项只进入运行日志 / rejected 统计。Agent 继续生成下一条需求。
 
 任一最终证据字段来自旧 MySQL `topic_pattern_*` 时,同样必须 rejected。新版 exact evidence 不允许 MySQL 兜底。
 
 对 `source_kind=pattern_itemset` 的需求,`case_ids` 按 `post_id` 语义直接等于已校验的 `matched_post_ids`,因为 PG Pattern V2 的主支撑关系来自 `pattern_itemset_post`;兼容字段 `decode_case_ids` 当前固定为空数组。`source_post_id/itemset_ids/itemset_items/mining_config_id/matched_post_ids/support/absolute_support` 不可为空且必须 DB 校验通过。
 
-### 8.2 本地 MVP 输出方式
+### 8.2 V1 输出方式
+
+V1 有两条受控输出路径。
 
-本次 MVP 不真实写 `demand_task`、`demand_content`、Hive、PG 或 MySQL,只通过 `examples.demand.run_existing_execution_local` 读取已有 PG `pattern_mining_execution.id` 并把输出写到本地:
+本地回归模式通过 `examples.demand.run_existing_execution_local` 读取已有 PG `pattern_mining_execution.id` 并把输出写到本地:
 
 ```text
 examples/demand/test_output_data/{run_id}/
@@ -438,6 +466,24 @@ examples/demand/test_output_data/{run_id}/
 
 其中只有 `demand_content.json[].ext_data.evidence_pack` 是给下游 exact evidence 的新增载体;`dwd_multi_demand_pool_di.json` 和 `feature_point_data.json` 只做原业务字段镜像,不增加 `evidence_pack`。
 
+云端测试服模式通过 `examples.demand.run_existing_execution_mysql` 读取已有 PG `pattern_mining_execution.id`,真实调用 LLM 和 PG 只读工具,最终只写 MySQL `demand_content` 单表:
+
+```text
+content-deconstruction-supply.demand_content
+  id
+  merge_leve2
+  name
+  reason
+  suggestion
+  ext_data.evidence_pack
+  score
+  dt
+  create_time
+  update_time
+```
+
+该模式不写 `demand_task`、Hive/ODPS、PG Pattern、旧 MySQL Pattern、`dwd_multi_demand_pool_di` 或 `feature_point_data`。下游 FH / ContentFindAgent 后续读取的是 `demand_content` 行及其中的 `ext_data.evidence_pack`,不是 `demand_items` 或 rejected 清单。
+
 ### 8.3 ContentFindAgent 接到需求后必须做什么
 
 ContentFindAgent 后续领取 `demand_content` 时,不能只取 `id/name/suggestion/score/merge_leve2/dt`,还必须解析 `ext_data.evidence_pack`。