# DemandAgent 给下游的迭代需求

## 1. 结论先行

新版 ContentFindAgent 不能再依赖旧 MySQL Pattern 反查机制来恢复 Pattern、Case 和分类树血缘。

旧 MySQL `topic_pattern_*` 链路已删除弃用，不进入新版 `evidence_pack`，不作为下游回溯依据。旧字段只允许作为迁移前后的字段对照出现，用来说明它们在 PG Pattern V2 中被哪些字段替换。

新版 DemandAgent 的唯一正式 Pattern 证据源是 PG `open_aigc.public` Pattern V2 主事实表。DemandAgent 输出的 `pattern_source_system` 唯一合法值是 `pg_pattern_v2`。

为了新版能从需求出发稳定跑通数据源、Query、判断、游走、资产沉淀和策略学习，DemandAgent 或上游证据层需要把生成需求时已经知道的证据一起传给下游。

更准确地说：DemandAgent 补 `demand_content.ext_data.evidence_pack` 是 Exact Mode 的必要条件，但不是充分条件。ContentFindAgent 还必须在领取需求、生成发现内容、判断筛选、最终入库时读取、继承并沉淀结构化 `source_evidence`，最终结果才能从 `post_id/platform_content_id` 回到具体 Pattern、itemset 和分类树节点。

下游必须新增或扩展的核心字段：

| 字段 | 作用 |
| --- | --- |
| `pattern_source_system` | DemandAgent 输出中固定且唯一合法值为 `pg_pattern_v2`，标记 Pattern 证据来自 PG Pattern V2 主事实 |
| `pattern_execution_id` | 标记需求来自哪次 PG `pattern_mining_execution` |
| `mining_config_id` | 标记来源 Pattern 使用的具体挖掘配置 |
| `source_kind` | 标记需求来源是聚类结果、Pattern 频繁项集、直接 Case，还是其他来源 |
| `case_id_type` | 标准化 `caseid` 的语义，例如本链路中应明确为 `post_id` |
| `source_post_id` | 标记本条需求证据中的原始支撑帖子 |
| `category_bindings` | 绑定分类节点，例如分类 ID、路径、层级、来源类型、点类型和维度 |
| `element_bindings` | 绑定具体元素，例如元素名、元素类型、点类型、所属 post |
| `itemset_ids` | 绑定 Pattern 频繁项集 |
| `itemset_items[]` | 绑定 itemset 内每个 item 对应的分类节点、路径、点类型和维度 |
| `support` / `absolute_support` | 记录 Pattern 支持度，判断它是不是稳定组合 |
| `matched_post_ids` | 记录支撑 Pattern 的原始帖子或视频 |
| `video_ids` / `case_ids` | 记录可作为 Case seed 的素材 ID；Pattern 来源下二者都是 `post_id` 语义 |
| `decode_case_ids` | PG-only 当前固定为空数组的兼容字段，不参与 Pattern exact 闭合 |
| `seed_terms` | 记录真正给 Query 使用的下层特征或元素词 |
| `source_evidence` | ContentFindAgent 从 `evidence_pack` 继承并追加运行态字段后形成的下游结果证据，不由 DemandAgent 直接输出 |
| `source_certainty` / `validation_status` | 标记证据是否已经 DB 强校验通过 |
| `run_id` / `demand_content_id` / `demand_task_id` | `run_id` 是 CFA 本次运行 ID；`demand_content_id` 是 DemandAgent 需求主键；`demand_task_id` 在云端单表模式下可以为空，只作为上游任务线索 |

V1 不一定马上改复杂 DB schema。可以先在 `demand_content.ext_data` 里增加一个结构化 `evidence_pack`，先把证据传下来。

MVP 边界：DemandAgent 只输出 PG `pattern_itemset.scope='topic'` 的分类 Pattern 证据。`topic_element`、script、paragraph、group scope 暂不输出，因为它们不能保证每条证据都有 `category_id/category_path` 回到分类树节点。

## 2. 新版下游到底需要什么

新版 ContentFindAgent 不是只拿一个需求词去搜内容。它需要知道这个需求从哪里来、为什么成立、应该怎么生成 Query、判断结果应该绑定回哪棵分类树，以及最终资产入库前是否可追溯。

下游需要的对象主要有五类。

| 对象 | 下游含义 | 为什么需要 |
| --- | --- | --- |
| Pattern | 分类或元素的稳定组合 | 用来判断需求是不是有结构支撑，而不是单条素材偶然出现 |
| Case | 支撑 Pattern 或需求的原始素材 | 用来查看素材原文、解构点、平台调性和后续判断证据 |
| 分类 / 元素绑定 | 需求对应分类树的哪个父节点或子节点 | 所有游走、判断和入库结果都要能绑定回分类树 |
| 支撑素材 | `matched_post_ids`、`video_ids`、Case ID 等 | 用来做 Query 输入、Case 回扣、判断规则证据和策略学习 |
| run_context | 一路记录从需求到结果的路径 | 策略学习、失败复盘、入库追溯都需要它 |

三类“有需求”的数据源都应该作为 DemandAgent 下游。它们不能只给一个自然语言需求名，还要给来源证据。不然后续即使找到内容，也说不清这个内容为什么服务于当初那个需求。

所有资产入库前至少要保留：

| 必留信息 | 用途 |
| --- | --- |
| 来源路径 | 证明资产从哪个需求、Pattern、Case 或平台线索来 |
| 判断结果 | 证明为什么继续、入池、观察、淘汰 |
| 分类或元素绑定 | 证明资产属于分类树中的哪个节点 |
| 平台调性说明 | 证明资产适合当前平台，不是跨平台硬套 |
| run_context | 支持策略学习和后续复盘 |

## 3. DemandAgent 当前给了什么

### 3.1 DemandItem

DemandAgent 当前生成的 `DemandItem` 是 LLM / tool 产生的备选业务需求，不是最终给下游消费的强校验证据。

代码证据：

- `/Users/samlee/Documents/works/DemandAgentNew/examples/demand/demand_build_agent_tools.py:37`
- `/Users/samlee/Documents/works/DemandAgentNew/examples/demand/demand_build_agent_tools.py:113`

当前保留字段：

| 字段 | 当前含义 |
| --- | --- |
| `element_names` | 需求名称来源，后续会拼成 `demand_content.name` |
| `reason` | 生成需求的理由 |
| `desc` | 需求描述，后续写入 `suggestion` |
| `type` | 来源类型，例如元素、关系、分类 |
| `evidence_refs` | LLM 声明的证据引用发现内容，只能作为 DB 强校验输入，不能直接给下游当真实证据 |

`evidence_refs` 里即使出现 `itemset_ids/source_post_id/seed_terms`，也只是声明。DemandAgent 必须用 PG DB 重新读取和校验，再升级成 `demand_content.ext_data.evidence_pack`。任一最终字段来自旧 MySQL `topic_pattern_*` 时，该 DemandItem 必须 rejected。

### 3.2 demand_content

新版 DemandAgent V1 同时保留两种受控输出模式：

- `local_json`：本地回归 / fixture 模式，只写本地 `demand_content.json` 等 JSON 文件，不作为 CFA 生产读取来源。
- `mysql_demand_content`：云端测试服模式，只写 MySQL `content-deconstruction-supply.demand_content` 单表。

两种模式给下游的正式证据载体都必须是 `demand_content.ext_data.evidence_pack`。云端单表模式不新建 `demand_task`，因此 `demand_task_id` 可以为空；CFA 不能把它当作必填主键。P0F 以后，CFA 正式需求读取应使用 MySQL `demand_content`，本地 JSON 只保留为回归 fixture。

代码证据：

- `/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/mysql_demand_content_sink.py`

当前本地 `demand_content.json` 字段：

| `demand_content` 字段 | 来源 |
| --- | --- |
| `merge_leve2` | 当前执行品类 |
| `name` | `element_names` 逗号拼接 |
| `reason` | DemandItem.reason |
| `suggestion` | DemandItem.desc |
| `score` | 按 `name` 拆分后查权重并求平均 |
| `ext_data` | JSON 对象，包含旧业务字段 `reason/desc/type/video_ids`，以及新版强校验字段 `evidence_pack` |
| `dt` | 当天日期 |

注意：这里的字段名是历史真实表字段 `merge_leve2`，不是 `merge_level2`。CLI 或函数参数可以使用 `merge_level2` 作为变量名，但落到 `demand_content`、本地 JSON、下游读取契约时必须保持 `merge_leve2`。

`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`。这就是本次需求要补齐的输出契约。

### 3.3 dwd_multi_demand_pool_di

新版 local MVP 不写 Hive，只生成本地 `dwd_multi_demand_pool_di.json` 镜像。这个文件不是给 ContentFindAgent 做 exact 回溯的主输入。

代码证据：

- `/Users/samlee/Documents/works/DemandAgentNew/examples/demand/data_query_tools.py:128`
- `/Users/samlee/Documents/works/DemandAgentNew/examples/demand/data_query_tools.py:194`
- `/Users/samlee/Documents/works/DemandAgentNew/examples/demand/data_query_tools.py:227`

当前映射字段：

| 字段 | 当前含义 |
| --- | --- |
| `strategy` | 策略名 |
| `demand_id` | 派生 ID |
| `demand_name` | 需求名 |
| `weight` | 分数 |
| `type` | 从 `ext_data.type` 解析 |
| `video_count` | `video_ids` 数量 |
| `video_list` | `video_ids` |
| `extend` | 当前主要保留品类 |
| `dt` | 分区日期 |

这一层不增加 `evidence_pack`，不承载 Pattern exact evidence。ContentFindAgent 的主输入只能是 `demand_content.json` 或未来 DB `demand_content.ext_data.evidence_pack`。

## 4. 旧 MySQL Pattern 链路为什么删除弃用

旧版 ContentFindAgent 的 Case 反查工具是 `get_goodcase_topic_point`。

代码证据：

- `/Users/samlee/Documents/works/ContentFindAgent/examples/content_finder/tools/get_goodcase_topic_point.py:91`
- `/Users/samlee/Documents/works/ContentFindAgent/examples/content_finder/tools/get_goodcase_topic_point.py:96`
- `/Users/samlee/Documents/works/ContentFindAgent/examples/content_finder/tools/get_goodcase_topic_point.py:144`

旧链路曾经是：

```text
features
-> topic_pattern_element.name = feature
-> post_id 交集
-> workflow_decode_task_result.channel_content_id
-> purpose_points / key_points / inspiration_points
```

这条链路已删除弃用，原因如下。

| 问题 | 说明 |
| --- | --- |
| 不带 `execution_id` | 同一个词可能出现在多个 Pattern execution，不能证明来自当前需求那次执行 |
| 只查元素名 | DemandAgent 当前有些需求名其实是分类节点，旧 CFA 只查 `topic_pattern_element.name` 会漏掉 |
| 不查 itemset | 无法恢复 `itemset_id`、support、absolute support、matched posts |

更关键的是，新版 DemandAgent 已切换为 PG Pattern V2 主事实。旧 MySQL `topic_pattern_element` 即使能查到 post，也不是新版 `evidence_pack` 的合法来源。

因此旧链路不能作为任何兜底链路写入新版主血缘。它只保留在本文档中作为“删除弃用字段如何被 PG 字段替换”的迁移说明。

## 5. 旧 MySQL 字段删除弃用与 PG 替换关系

| 旧 MySQL 表/字段 | 新状态 | 新 PG 替换来源 |
| --- | --- | --- |
| `topic_pattern_execution.id` | 删除弃用 | `pattern_mining_execution.id`，即新版 `pattern_execution_id` |
| `topic_pattern_execution.status` | 删除弃用 | `pattern_mining_execution.status` |
| `topic_pattern_execution.cluster_name/merge_leve2/platform/account_name/post_limit/min_absolute_support/mining_configs` | 删除弃用为 Pattern 证据字段 | PG execution 是全局 Pattern 快照；业务侧 `merge_leve2/platform` 只保留在 Demand 输出上下文，不作为 Pattern 主事实 |
| `topic_pattern_mining_config.id` | 删除弃用 | `pattern_mining_config.id`，即 `mining_config_id` |
| `topic_pattern_mining_config.dimension_mode/target_depth` | 删除弃用 | 从 `pattern_mining_config.params` 解析或派生 |
| `topic_pattern_category.id` | 删除弃用 | `pattern_mining_category.id` |
| `topic_pattern_category.path` | 删除弃用 | `pattern_mining_category.path` |
| `topic_pattern_category.category_nature` | 删除弃用 | `pattern_mining_category.category_nature` 和 `pattern_mining_category.classified_as` |
| `topic_pattern_element.id/post_id/point_type/point_text/element_type/name/description/category_id/category_path` | 删除弃用 | `pattern_mining_element.id/post_id/point_type/point_text/element_type/name/description/category_id/category_path` |
| `topic_pattern_itemset.id` | 删除弃用 | `pattern_itemset.id` |
| `topic_pattern_itemset.mining_config_id` | 删除弃用 | `pattern_itemset.mining_config_id` |
| `topic_pattern_itemset.support/absolute_support` | 删除弃用 | `pattern_itemset.support/absolute_support` |
| `topic_pattern_itemset.matched_post_ids` | 删除弃用 | 从 `pattern_itemset_post` 按 `execution_id + itemset_id` 聚合生成 `matched_post_ids` |
| `topic_pattern_itemset_item.id/itemset_id/point_type/dimension/category_id/category_path/element_name` | 删除弃用 | `pattern_itemset_item.id/itemset_id/point_type/dimension/category_id/category_path/element_name`，并可补充 PG 新字段 `layer/element_id/post_count` |

新版 `evidence_pack` 中不允许出现旧 MySQL 专属来源。字段名可以保留通用业务含义，例如 `itemset_ids`、`matched_post_ids`、`category_bindings`，但它们的值必须来自 PG Pattern V2。

## 6. 必须补给下游的字段清单

| 字段 | 字段意义 | 下游用途 | 为什么不能靠 CFA 自己补 | 缺失风险 |
| --- | --- | --- | --- | --- |
| `pattern_source_system` | Pattern 证据来源系统，DemandAgent 输出中唯一合法值为 `pg_pattern_v2` | 判断反查目标是 PG Pattern V2 主事实 | CFA 只看需求单无法知道证据来自哪套 Pattern 表 | 把旧 MySQL 删除弃用链路误当 PG 主事实 |
| `pattern_execution_id` | 当前需求来源的 Pattern 执行 ID | 数据源详情、Pattern 回查、策略学习 | CFA 只能按词反查，无法知道当时 execution | 同名词跨 execution 混淆 |
| `mining_config_id` | 当前 itemset 所属挖掘配置 ID | 区分同一 execution 下不同 Pattern 配置 | CFA 事后只靠 post 反查会得到多个配置下的 itemset | 无法确定具体 Pattern 配置 |
| `source_kind` | 来源类型：聚类结果、Pattern 频繁项集、直接 Case 等 | 决定后续流程：是否进 Query，是否先游走或先判断 | 只看 `type` 不够，不能区分真实来源路径 | 不同来源走错流程 |
| `case_id_type` | `caseid` 的 ID 语义，Pattern case 链路中应明确为 `post_id` | 稳定对齐 `post_id/channel_content_id/platform_content_id` | CFA 只能猜这个 ID 是结果表 id、decode id 还是 post id | join 语义混乱 |
| `source_post_id` | 本条证据里的原始支撑帖子 ID | 从最终 case 回到上游 matched post | 单个 post 可能支撑很多 itemset，CFA 不能知道哪条是来源 post | 只能得到多条可能路径，不能 exact |
| `category_bindings` | 分类节点绑定，当前包含 `itemset_id/itemset_item_id/category_id/category_name/category_path/category_full_path/category_source_type/category_level/point_type/dimension/element_name` | 所有结果绑定回分类树节点 | CFA 按元素名查不到分类节点，且同名分类可能多处存在 | 入库后无法解释属于哪个分类 |
| `element_bindings` | 元素绑定，当前包含 `itemset_id/itemset_item_id/category_id/point_type/dimension/element_name/matched_element_count/matched_post_count/matched_post_ids/sample_elements` | 作为 Query 输入素材、判断回扣证据 | CFA 可以按词查元素，但不知道哪个是 DemandAgent 采用的 | Query seed 可能跑偏 |
| `itemset_ids` | Pattern 频繁项集 ID | 回查 Pattern 组合和稳定性 | CFA 旧链路不查 itemset | 不能证明 Pattern 是组合，不是散词 |
| `itemset_items[]` | itemset 内每个 item 对应的 `category_id/category_path/point_type/dimension/element_name` | 直接还原 Pattern chip 到分类树节点 | CFA 只靠 `itemset_id` 还要二次猜 item 和节点 | 不能稳定解释具体命中的分类树节点 |
| `support` | 相对支持度 | 判断 Pattern 是否稳定 | 需求池当前没有保存 | 无法按稳定性排序或过滤 |
| `absolute_support` | 绝对支撑素材数 | 判断有多少素材支撑 | 需求池当前没有保存 | 不能区分单例和稳定模式 |
| `matched_post_ids` | 支撑 itemset 的帖子 ID 列表 | 找 Case、看原始素材、做回扣判断 | `video_ids` 不等价于 itemset 的 matched posts | Case 来源不准，支撑证据不准 |
| `video_ids` / `case_ids` | 可直接作为 Case seed 的素材 ID；Pattern 来源下固定是 `post_id` 语义 | 数据源 Case、Query 输入、判断证据 | CFA 可偶尔从 decode 表命中，但不稳定 | 如果语义不清，容易把 post_id 和 decode row id 混用 |
| `decode_case_ids` | PG-only 当前固定为空数组的兼容字段 | 明确 decode row ID 不参与本次 Pattern exact 闭合 | 本次主链路不读旧 decode-case 表 | 不能把 decode 缺失误判成 Pattern 证据失败 |
| `seed_terms` | 真正用于 Query 的下层特征或元素词 | Query 输入素材 | `name` 可能是分类、关系或宽泛表达，不一定适合作 Query | Query 输入不稳定 |
| `source_evidence` | 下游最终结果继承的结构化证据，不是 DemandAgent 输出字段 | 写入 `demand_find_content_result` 或 source edge artifact | DemandAgent 只能给 `evidence_pack`，无法替下游结果落库 | 最终结果又断在 `process_trace` 文本 |
| `source_certainty` | 证据可信度，进入下游时必须为 `db_validated` | 下游判断是否能 exact 回溯 | CFA 无法判断 LLM 声明是否已被 DB 校验 | 把备选证据误当真实证据 |
| `validation_status` | DemandAgent 证据校验状态，进入需求池时必须为 `passed` | 下游只消费通过校验的任务 | CFA 事后补查无法恢复生成时的拒绝原因 | 失败证据流入下游 |
| `run_id` | 贯穿下游任务的 run_context | 策略学习、失败复盘 | CFA 可创建自己的 run_context，但不能补上游生成过程 | 上下游链路断开 |
| `demand_task_id` | DemandAgent 侧任务 ID | 回查生成日志和任务状态 | CFA 无法凭需求名可靠找到唯一任务 | 无法定位上游运行 |
| `demand_content_id` | 下游领取的需求 ID | CFA 主任务绑定 | 这个字段 CFA 已能拿到，但应进入统一证据包 | run_context 不统一 |

## 7. 检查过程与证据

### 7.1 DemandAgent 文档审计

`/Users/samlee/Documents/works/DemandAgent工程文档集/demand-agent-analysis.md:432` 已写明 DemandItem 到 `demand_content` 的映射：

| 目标字段 | 来源 |
| --- | --- |
| `merge_leve2` | 当前执行品类 |
| `name` | `element_names` 拼接 |
| `reason` | DemandItem.reason |
| `suggestion` | DemandItem.desc |
| `score` | 权重 JSON 查分求平均 |
| `ext_data` | `reason/desc/type/video_ids` |
| `dt` | 当天日期 |

历史文档曾把 `workflow_decode_task_result` 作为辅助回填逻辑；PG-only MVP 不再依赖它闭合 Pattern 证据。Agent 输出主要靠 Prompt 约束，最终是否进入需求池由 DemandAgent 代码按 PG DB 强校验决定。

### 7.2 DemandAgent 代码审计

DemandAgent 新版代码里直接读取 PG Pattern V2 的分类、元素、itemset 和支撑帖子字段。

代码证据：

- PG repository：`/Users/samlee/Documents/works/DemandAgentNew/examples/demand/pg_pattern_repository.py`
- PG tool adapter：`/Users/samlee/Documents/works/DemandAgentNew/examples/demand/pattern_builds/pg_pattern_service.py`
- Evidence 强校验：`/Users/samlee/Documents/works/DemandAgentNew/examples/demand/evidence_pack_builder.py`

关键字段包括：

| 表 | 关键字段 |
| --- | --- |
| `pattern_mining_execution` | `id`, `status`, `topic_itemset_count`, `post_count`, `category_count`, `element_count` |
| `pattern_mining_config` | `id`, `execution_id`, `algorithm`, `scope`, `name`, `params` |
| `pattern_itemset` | `id`, `execution_id`, `mining_config_id`, `scope`, `support`, `absolute_support`, `dimensions` |
| `pattern_itemset_post` | `execution_id`, `itemset_id`, `post_id` |
| `pattern_itemset_item` | `itemset_id`, `point_type`, `dimension`, `category_id`, `category_path`, `element_name` |
| `pattern_mining_category` | `id`, `execution_id`, `source_type`, `path`, `level`, `parent_id`, `classified_as` |
| `pattern_mining_element` | `execution_id`, `post_id`, `source_table`, `point_type`, `element_type`, `name`, `category_id`, `category_path` |

也就是说，PG 主事实表已经具备 DemandAgent 输出下游证据链所需字段。新版问题不是“上游没有”，而是 DemandAgent 必须把这些字段校验后写进 `demand_content.ext_data.evidence_pack`，并要求下游继续继承。

### 7.3 旧 ContentFindAgent 代码审计

旧 CFA 的 `get_goodcase_topic_point` 只按 `topic_pattern_element.name` 精确匹配。

关键 SQL：

```sql
SELECT DISTINCT post_id
FROM topic_pattern_element
WHERE name = %s
```

这个 SQL 不带 `execution_id`、`category_id`、`itemset_id`，也不查分类树节点。更重要的是，它读取的是已删除弃用的旧 MySQL `topic_pattern_element`，不能进入新版 PG `evidence_pack`。

### 7.4 真实 DB 只读抽样

本轮只做了只读查询，没有写 DB，也没有输出 secret。

PG Pattern V2 主事实表只读校对结论：

| PG 表 | 行数 | 字段结论 |
| --- | --- |
| `pattern_mining_execution` | 7 | 有 `id/status/snapshot_date/is_current/is_retired/post_filter/post_count/classify_execution_id/category_count/element_count/topic_itemset_count/topic_element_itemset_count` |
| `pattern_mining_config` | 45 | 有 `id/execution_id/algorithm/scope/name/params/transaction_count/result_count/input_bucket_key` |
| `pattern_mining_category` | 25816 | 有 `id/execution_id/source_stable_id/source_type/name/description/path/level/parent_id/category_nature/classified_as` |
| `pattern_mining_element` | 1950755 | 有 `id/execution_id/post_id/source_table/source_element_id/element_type/name/category_id/category_path/point_type/point_text/topic_point_id` |
| `pattern_itemset` | 449216 | 有 `id/execution_id/mining_config_id/scope/support/absolute_support/dimensions/is_cross_point/is_cross_layer`，没有 `matched_post_ids` 列 |
| `pattern_itemset_item` | 1808629 | 有 `id/itemset_id/layer/point_type/dimension/category_id/category_path/element_name/element_id/post_count` |
| `pattern_itemset_post` | 3910262 | 有 `itemset_id/post_id/execution_id`，是新版 `matched_post_ids` 的唯一来源 |

需求池真实表只读校对结论：

| 表 | 行数 | 字段 |
| --- | --- | --- |
| `demand_content` | 29888 | `id/merge_leve2/name/reason/suggestion/ext_data/score/dt/create_time/update_time` |
| `demand_task` | 1987 | `id/execution_id/name/platform/status/log/create_time/update_time` |

`demand_content.ext_data` 是 JSON 字段，可以承载完整 `evidence_pack`。当前生产样例仍主要是 `desc/reason/type/video_ids`，没有稳定出现新版 `pg_pattern_v2` 的 `evidence_pack`，所以这仍是待补齐的输出契约。

### 7.5 subagent 交叉验证

本轮拆了三个 subagent 交叉验证。

| subagent | 验证范围 | 结论 |
| --- | --- | --- |
| PG/MySQL DB 字段侧 | PG Pattern V2、旧 MySQL `topic_pattern_*`、需求池表字段 | PG V2 能支撑新版证据链；旧 MySQL 字段必须删除弃用，只作为迁移对照 |
| DemandAgent 代码侧 | PG repository、tool adapter、`evidence_pack_builder`、local output | 当前主路径读取 PG Pattern V2 并写本地 JSON，`evidence_pack.pattern_source_system` 为 `pg_pattern_v2` |
| ContentFindAgentNew 下游侧 | `source_context.ext_data.evidence_pack`、`source_evidence`、校验器 | 下游需要继承 DemandAgent 的 PG `evidence_pack`，再追加运行态 `source_evidence` 字段 |

三个方向结论一致。

## 8. 建议的交付方式

V1 建议先不要大改表结构，先扩展 `demand_content.ext_data`。

推荐结构：

```json
{
  "reason": "...",
  "desc": "...",
  "type": "...",
  "video_ids": ["51978710"],
  "evidence_pack": {
    "pattern_source_system": "pg_pattern_v2",
    "source_kind": "pattern_itemset",
    "case_id_type": "post_id",
    "source_post_id": "51978710",
    "pattern_execution_id": 581,
    "mining_config_id": 2082,
    "itemset_ids": [1608352],
    "itemset_items": [
      {
        "itemset_id": 1608352,
        "category_id": 76006,
        "category_path": "/理念/观念/个人观念/情感认同/国家民族认同/爱国情感",
        "point_type": null,
        "dimension": "需求",
        "element_name": null
      }
    ],
    "category_bindings": [],
    "element_bindings": [],
    "support": 0.0045734552921411235,
    "absolute_support": 49,
    "matched_post_ids": ["51978710"],
    "video_ids": ["51978710"],
    "case_ids": ["51978710"],
    "decode_case_ids": [],
    "seed_terms": ["爱国情感", "人物故事"],
    "run_id": "...",
    "demand_task_id": 123,
    "demand_content_id": 456,
    "source_certainty": "db_validated",
    "validation_status": "passed"
  }
}
```

字段可以分批补齐：

| 阶段 | 建议 |
| --- | --- |
| 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`, `run_id`, `source_certainty`, `validation_status` |
| V1 兼容字段 | `decode_case_ids`，PG-only 当前固定为空数组；如后续重新引入 decode row ID，需要另做下游契约 |
| V1.1 增强 | 独立证据表、下游完整判断日志、topic_element 后续分类树补齐方案 |
| 后续再拆表 | 如果 `evidence_pack` 变大，再考虑独立证据表或关系表 |

注意：本次 MVP 只下发 `source_kind=pattern_itemset` 且 PG `scope='topic'` 的需求；如果来源不是该类 Pattern 频繁项集，暂不进入 exact 输出。

### 8.1 DemandAgent 必须保证的真实性边界

给下游 ContentFindAgent 的任务证据链必须真实。LLM 只能在 `evidence_refs` 里声明引用，不能直接决定最终证据。

当前 MVP 中，LLM 生成需求时仍只写 `evidence_refs` 引用声明；DemandAgent 代码会基于 PG DB 只读校验并升级为 `evidence_pack`。推荐 `evidence_refs` 形态如下：

```json
{
  "source_kind": "pattern_itemset",
  "source_tool": "get_itemset_detail",
  "itemset_ids": [1608352],
  "category_ids": [76006, 76848],
  "source_post_id": "51978710",
  "case_ids": {
    "pattern_itemset": ["51978710"]
  },
  "seed_terms": ["爱国情感", "人物故事"]
}
```

LLM 最好显式声明 `source_kind=pattern_itemset`；如果漏填但已经给出 `itemset_ids` 或 `source_tool=get_itemset_detail`，DemandAgent 内部可以安全补齐为 `pattern_itemset`，然后继续真实 DB 强校验。`source_post_id` 必须来自 `get_itemset_detail` 的 `post_ids/matched_post_ids` 或已查询过的 `get_post_elements` 结果。`case_ids` 在待复看阶段可以按 `source_kind` 分组；最终 `evidence_pack.case_ids` 对 Pattern 来源固定为 post_id 列表，decode 表行 ID 另放 `decode_case_ids`。

DemandAgent 代码必须按真实 DB 校验并补齐 `evidence_pack`。对于 `source_kind=pattern_itemset` 的需求，必须确认：

| 校验项 | 必须满足 |
| --- | --- |
| `pattern_execution_id` | PG `pattern_mining_execution.id` 必须存在且 `status='success'` |
| `source_kind` | 最终 `evidence_pack` 必须是 `pattern_itemset`；LLM 漏填时可由 `itemset_ids/source_tool` 安全推断，不是 Pattern itemset 则拒绝 |
| `itemset_ids` | 每个 itemset 都属于当前 PG execution，且 `pattern_itemset.scope='topic'`，能查到 `mining_config_id/support/absolute_support/matched_post_ids` |
| `mining_config_id` | 必须来自 PG `pattern_itemset.mining_config_id`，并能 join 到同一 execution 且 `scope='topic'` 的 `pattern_mining_config` |
| `source_post_id` | 必须在对应 itemset 的 `pattern_itemset_post.post_id` 聚合结果中 |
| `matched_post_ids` | 必须由 PG `pattern_itemset_post` 聚合得到，非空，`COUNT(DISTINCT post_id)` 必须等于 `absolute_support` |
| `itemset_items[]` | 必须能从 PG `pattern_itemset_item` 查到，并能 join 到当前 execution 的 `pattern_mining_category` |
| `category_bindings` | `category_id` 必须属于当前 `pattern_execution_id`，不能跨 execution 借节点 |
| `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` 和 `mysql_demand_content` 两种路径中，任一必需字段查不到、跨 execution、post 不在 matched posts、category 不在当前 execution、source post 精确 element binding 不成立，当前 DemandItem 都失败，不写入下游可消费的 `demand_content`。本地模式失败项进入 `rejected_demand_items.json`；云端单表模式不写入 `demand_content` 成功记录。

任一最终证据字段来自旧 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 V1 双输出方式

V1 有两种受控输出方式：

- `local_json`：通过 `examples.demand.run_existing_execution_local` 读取已有 PG `pattern_mining_execution.id`，把输出写到本地，只作为回归 fixture。
- `mysql_demand_content`：通过 `examples.demand.run_existing_execution_mysql` 读取已有 PG `pattern_mining_execution.id`，只写 MySQL `demand_content` 单表，不写 `demand_task`、Hive、PG 或其他 MySQL 表。

本地输出目录：

```text
examples/demand/test_output_data/{run_id}/
  run_manifest.json
  demand_task.json
  demand_items.json
  rejected_demand_items.json
  demand_content.json
  dwd_multi_demand_pool_di.json
  feature_point_data.json
  intermediate/result/
  intermediate/data/
  .run_context/
  output/
```

其中只有 `demand_content.json[].ext_data.evidence_pack` 是给下游 exact evidence 的新增载体；`dwd_multi_demand_pool_di.json` 和 `feature_point_data.json` 只做原业务字段镜像，不增加 `evidence_pack`。

云端测试服输出只看 `content-deconstruction-supply.demand_content.ext_data.evidence_pack`。CFA 领取真实需求池时，应优先从该 MySQL 单表解析证据包。

### 8.3 ContentFindAgent 接到需求后必须做什么

ContentFindAgent 后续领取 `demand_content` 时，不能只取 `id/name/suggestion/score/merge_leve2/dt`，还必须解析 `ext_data.evidence_pack`。

它需要把 `source_kind/source_post_id/pattern_execution_id/mining_config_id/itemset_ids/itemset_items/category_bindings/matched_post_ids/source_certainty` 注入数据源、Query、判断、游走、入库上下文。最终结果必须保存结构化 `source_evidence` 到 `demand_find_content_result` 或 sidecar/source edge artifact。

ContentFindAgentNew 生成 `source_evidence` 时，需要继承 DemandAgent 的 `evidence_pack`，并追加运行态字段：`discovery_start_source/previous_discovery_step/origin_path_id/search_query_id/query/search_query_generation_method/discovered_platform_content_id/discovery_relation/source_path_record_ids`。这些字段不由 DemandAgent 预写完整。当前 CFA validator 已强校验 `discovery_start_source/previous_discovery_step/origin_path_id/discovered_platform_content_id`，并校验 `source_evidence` 与 `evidence_pack` 的 `pattern_source_system/pattern_execution_id/source_post_id/case_id_type/mining_config_id/source_certainty/validation_status/itemset_ids/itemset_items/matched_post_ids/seed_terms` 保持一致；`search_query_id/query/search_query_generation_method/discovery_relation/source_path_record_ids` 当前由生成逻辑追加，后续如要作为硬门槛，需要在 CFA validator 中继续加严。

如果新找到的 `platform_content_id/post_id` 不在 DemandAgent 的 `source_post_id/matched_post_ids` 中，只能标记为 `derived` 或 `discovered_content_item`，不能声称它 exact 属于某个 Pattern 节点。除非下游额外完成新 post 的解构和分类绑定，否则 DemandAgent 的证据只能证明“这个需求来源于某 Pattern”，不能证明“这个新 post 属于这个 Pattern”。

## 9. 下游使用方式

| 下游阶段 | 怎么使用这些字段 |
| --- | --- |
| 数据源 | 展示 Pattern、Case、分类/元素绑定和原始支撑素材 |
| Query | 使用 `seed_terms` 作为 Query 输入素材，不直接把宽泛 `name` 当 Query |
| Platform | 根据来源平台和 seed 生成平台适配 Query |
| 判断 | 用分类/元素绑定、Case 原文和 support 做回扣判断 |
| 游走 | 每次游走结果绑定回分类或元素节点，避免无限漂移 |
| 资产清洗沉淀 | 入库前保留来源路径、判断结果、分类或元素绑定、平台调性说明、run_context 和结构化 `source_evidence` |
| 策略学习 | 用 run_context 回看哪类来源、哪类 seed、哪类规则包有效 |

## 10. 最终判断

旧版 ContentFindAgent 的 MySQL Pattern 反查已删除弃用，不能承担新版主血缘，也不能作为新版 `evidence_pack` 的兜底来源。

如果新版要求精准找到 Pattern、Case、分类或元素绑定，并让所有入库资产可追溯，DemandAgent 必须把生成需求时已经知道的证据一并传给下游。

最小可行做法是：先在 `demand_content.ext_data` 中增加 `evidence_pack`。这样 V1 可以先让需求单携带真实上游证据，不需要马上重构 DB schema，也能避免下游继续靠猜。

但这只是 Exact Mode 的上游基础。最终 `demand_find_content_result` 能不能从 `platform_content_id/post_id` 回到具体 Pattern 和分类树节点，还取决于 ContentFindAgent 是否读取、继承并沉淀结构化 `source_evidence`。
