# 2026-07-24 问题总结：当前代码与 PRD 的匹配度

## 1. 结论

当前代码已从“分类树 + 需求词热度”明显推进到“每日供给流水线 + 分级 Agent + 视频点位扩展 + 可视化下钻”的阶段。

尤其已经落地了：

- 每日串行流水线；
- 需求分级统筹与并发执行；
- 需求自身来源内归一评分；
- 分类树全局与局部热度查询；
- S/A 级需求的视频点位扩展；
- 分级需求在树上的多分类展示；
- 调度任务执行记录；
- 分级需求、视频和点位的前端下钻。

但它尚未实现 PRD 定义的完整 Harness。当前的核心问题不是“缺少一个 Agent”，而是**需求对象、评分对象、内容对象、每日快照和策略对象还没有统一成同一条可追溯闭环**。

现阶段更准确的定位是：

> 已实现“每日需求词分级与视频点位拓展”的业务原型；尚未实现“证据—平台需求—供给分配—内容归因—后验反馈—策略协作”的完整系统。

## 2. 本次核对范围

- 核对基线：`prd/` 下已确认的业务 PRD。
- 代码状态：`feature/zhangbo` 当前 `d2154ed`。
- 重点审阅：新增 `demand_grade_agent`、`demand_grade_orchestrator_agent`、`demand_video_expand_agent`、调度流水线、数据模型、API 和 Vue 页面。
- 本文结论基于代码静态阅读和构建级检查；没有以线上数据库结果替代代码事实。

## 3. PRD 五个模块的匹配度

| PRD 模块 | 当前匹配度 | 已实现部分 | 主要缺口 |
|---|---|---|---|
| 证据收集 Harness | 部分匹配 | ODPS→MySQL 同步、四项先验、真实 ROV/VOV、视频点位 | 没有不可变证据包、来源/事件版本、冲突和迟到数据机制 |
| 需求认知与智能汇总 Harness | 初步匹配 | 需求词归类、需求词↔池行关系、分级需求可挂多个分类 | 没有“原始表达→标准需求词→平台需求”三层对象；无合并拆分和关系语义账本 |
| 需求评估与供给分配 Harness | 部分匹配 | S/A/B/C/D 分级、来源内归一分、局部热度、ROV 后验 | 没有“成立度 + 局部供给优先级”双结果、行动层、探索配额和跨日稳定规则 |
| 发布、可视化与反馈入口 Harness | 初步匹配 | 热力图、分级列表、多挂靠点击、视频/点位下钻 | 没有标准需求任务包、两个下游视图、反馈入口、完整评分解释和日期一致性保证 |
| 业务协作与策略控制 Harness | 基本未实现 | 调度执行记录、Agent 运行日志 | 没有数据问答、自动分析、负向决策、定义管理、影响预览和策略版本 |

## 4. 已实现能力与 PRD 的正向对应

### 4.1 每日自动运行已有主干

`run_supply_pipeline` 已按“全局树同步 → 需求池同步 → 分级 → 视频点位拓展”执行，调度器每天 12:00 触发。

对应 PRD：每日自动运行、需求分级、内容证据扩展。

相关代码：

- `supply_infra/scheduler/app.py`
- `supply_infra/scheduler/jobs/run_supply_pipeline.py`

### 4.2 需求自身先验分已避免直接混加不同来源

`demand_priority.py` 先在每个 strategy 内对原始 `weight` 排名归一，再对已有来源取均值；缺失来源不补零。

对应 PRD：先验维度保持正交、缺失不当成零。

相关代码：

- `agents/demand_grade_agent/tools/demand_priority.py`

### 4.3 后验已进入分级 Agent 的判断提示

分级 Agent 同时读取分类树热度、需求自身来源分、真实 ROV/VOV、样本数、父节点和全部兄弟节点；提示明确“无后验不等于零”。

对应 PRD：局部冷热、后验和样本量参与判断。

相关代码：

- `agents/demand_grade_agent/prompt/system_prompt.md`
- `agents/demand_grade_agent/tools/query_category_local_heat.py`
- `agents/demand_grade_agent/tools/query_demand_popularity_by_word.py`

### 4.4 分级结果已经支持多分类展示

`demand_grade_category_rel` 允许一条 `demand_grade` 映射多个分类，前端可从需求卡片直接选择分类。

对应 PRD：需求可以有多个挂靠点。

注意：这只是分级结果层的多分类展示，不等于原始需求认知层已具备可解释的多挂靠能力，详见问题 P1-3。

### 4.5 视频点位扩展已提供内容证据雏形

对 S/A 级需求，系统读取已关联视频的目的点、关键点和灵感点，再由 Agent 筛选可扩展的需求文本和 reason，并展示到前端。

对应 PRD：需求向内容、语言证据下钻。

相关代码：

- `supply_infra/scheduler/jobs/expand_demand_from_video_points.py`
- `agents/demand_video_expand_agent/`
- `api/services/demand_grade_videos.py`

## 5. P0：会导致每日结果不完整、失真或不可安全发布的问题

### P0-1：需求池以“总行数相同”跳过同步，不能保证每日输入快照正确

**现状**

`_sync_pool_rows` 先比较 ODPS 和 MySQL 总行数；相同就跳过明细同步。两边行数相同、但同一条需求的权重、视频、名称或其他内容已经变化时，当日输入会保持旧值。

**与 PRD 的差距**

PRD 要求每天以变化的上游数据形成完整证据包。行数相同不是“数据未变化”的充分条件。

**风险**

- 当日热度、分级和后续视频扩展可能基于过期数据；
- 历史上无法说明当日实际使用了哪个上游版本；
- 结果看起来“每日运行成功”，但业务含义已失真。

**代码证据**

- `supply_infra/scheduler/jobs/sync_multi_demand_pool_odps_to_mysql.py`：`_sync_pool_rows`。

### P0-2：分级组全部失败时，计划仍可能被判定为“执行完成”

**现状**

`DemandGradePlanRepository.get_execution_snapshot` 只把 `pending + running` 视为未完成，不把 `failed` 计入未完成。因此所有组都失败、但没有 pending/running 时，`execution_complete` 仍为真。

`grade_demand_pool` 又直接把这个字段作为 `success`，使外层流水线有可能继续执行 S/A 视频拓展，并把当日流水线标为成功。

**与 PRD 的差距**

PRD 明确要求：模块整体失败或结果不完整时，不得静默发布；必须说明缺失模块、影响范围和最后稳定版本。

**风险**

- 空的或不完整的分级结果会被视为正式当日结果；
- 视频拓展只基于残缺 S/A 集合；
- 前端和下游无法区分“真实无需求”与“分级执行失败”。

**代码证据**

- `supply_infra/db/repositories/demand_grade_plan_repo.py`：`get_execution_snapshot`。
- `supply_infra/scheduler/jobs/grade_demand_pool.py`：以 `execution_complete` 作为成功判断。
- `supply_infra/scheduler/jobs/run_supply_pipeline.py`：失败步骤后仍继续后续步骤。

### P0-3：前端可能将不同业务日的树热度和需求分级拼接在同一张图中

**现状**

`GlobalDemandMapView` 和 `CategoryTreeView` 并行调用：

- `/api/category-tree`：默认取 `category_tree_weight` 最新日期；
- `/api/demand-grade`：默认取 `demand_grade` 最新日期。

两个“最新日期”没有被同一 `biz_dt` 约束，也没有 API 返回一致性状态。

**与 PRD 的差距**

PRD 要求每日全量业务结果是一个可追溯快照，树热度、需求、评分、内容和行动应属于同一运行批次。

**风险**

- 用户可能在 7 月 24 日树热度上看到 7 月 23 日分级需求；
- 局部冷热、等级和 reason 无法解释；
- 页面视觉上正确，业务上却不是同一日结果。

**代码证据**

- `web/src/views/GlobalDemandMapView.vue`
- `web/src/views/CategoryTreeView.vue`
- `api/services/category_tree.py`
- `api/services/demand_grade.py`

### P0-4：数据库仅使用 `create_all`，没有迁移机制，现网结构升级不可控

**现状**

应用启动时调用 `Base.metadata.create_all()`。该操作可以创建缺失表，但不会为既有表安全地新增字段、修改约束或迁移历史数据。

本轮代码已新增多张表，并改动既有表使用方式；没有看到迁移目录或迁移脚本。

**与 PRD 的差距**

PRD 依赖历史版本、日快照、关系和运行账本。数据结构升级必须可控，不能依赖开发环境首次建表。

**风险**

- 已部署数据库可能缺列、缺索引或约束不一致；
- 代码升级后在运行期才报 SQL 错误；
- 无法可靠回滚或核对一次结构变更影响的历史数据。

**代码证据**

- `supply_infra/db/session.py`：`init_db`。
- 仓库未发现迁移文件或迁移工具目录。

## 6. P1：关键业务闭环尚未形成的问题

### P1-1：没有 PRD 所需的三层标准需求对象，`demand_grade` 仍是需求池词的每日评级

**现状**

`demand_grade` 的唯一键是 `(biz_dt, demand_name)`，`demand_name` 直接来自 `multi_demand_pool_di`。它保存的是需求词某日的 S/A/B/C/D 评级，而不是独立、稳定、可跨日演进的平台需求。

原有 `generated_demand` 仍存在，但当前新增 API、前端、分级流水线和视频扩展均不消费它。

**与 PRD 的差距**

PRD 要求：

```text
原始需求表达 → 标准需求词 → 平台需求 → 每日需求任务包
```

当前将“原始词/需求词”和“最终平台需求”合并为同一个 `demand_name`，无法稳定表达别名、合并、拆分、层级和生命周期。

**风险**

- 同义词或相近词可能每天各自评级，或被模型临时合并但没有正式主从关系；
- 无法可靠回答“这条平台需求由哪些原始表达组成”；
- 下游只能收到词级结果，而不是业务意图明确的需求任务。

**代码证据**

- `supply_infra/db/models/demand_grade.py`
- `supply_infra/db/models/generated_demand.py`
- `api/services/demand_grade.py`

### P1-2：评分口径与 PRD 不一致，且没有“成立度 + 局部供给优先级”双结果

**现状**

- 分类树 `total_score` 是四项排名分的和，范围约为 `0～4`；
- `demand_grade.score` 是来源内排名均值，范围为 `0～100`；
- S/A/B/C/D 是 Agent 基于提示自行判定的单一等级；
- `DemandGrade` 只持久化 `posterior_rov_avg`，没有持久化 VOV、归因结果或独立的局部优先级。

**与 PRD 的差距**

PRD 要求对人展示的分数统一为 `0～1`，并分别输出：

1. 需求成立度；
2. 局部供给优先级；
3. 置信度和行动层。

**风险**

- 前端、Agent 和业务人员会把不同量纲的分数误作同一分数；
- “高可信但当前无需供给”和“证据少但值得探索”无法区分；
- 真实 VOV、内容归因和风险抑制无法进入统一决策。

**代码证据**

- `supply_infra/scheduler/jobs/update_category_tree_rank_scores.py`
- `agents/demand_grade_agent/tools/demand_priority.py`
- `supply_infra/db/models/demand_grade.py`

### P1-3：多挂靠只在分级结果层存在，缺少原始认知层的关系语义与 reason

**现状**

`demand_grade_category_rel` 支持一个分级结果挂多个分类；但基础表 `demand_belong_category` 仍以 `name` 唯一且只有一个 `category_id`。

更关键的是，需求词和池行、需求和分类的关联大量来自名称包含匹配；关系表不保存关系类型、来源、reason、置信度、审核状态或有效期。

**与 PRD 的差距**

PRD 要求树是稳定骨架，需求为独立图节点；所有跨树关系都要可解释，模型推断关系需标记。

**风险**

- 多挂靠可能是字符串匹配副产物，而不是业务上确认的关联；
- 无法区分“上游关联”“模型推断”“人工确认”；
- 用户点击路径时不能解释为什么挂到该节点。

**代码证据**

- `supply_infra/db/models/demand_belong_category.py`
- `supply_infra/db/models/demand_grade_category_rel.py`
- `supply_infra/scheduler/jobs/sync_demand_belong_pool_rel.py`

### P1-4：名称包含匹配会制造错误关联，且关系没有业务日期

**现状**

`sync_demand_belong_pool_rel` 用 `name in demand_name` 生成关系，并读取全表需求池，不限定 `biz_dt`。这使一个历史词与历史/当前不同日期的池行都可能形成永久关系。

**与 PRD 的差距**

PRD 要求每条关系有来源、时间、reason 和可追溯性。

**风险**

- 短词、重名词和包含词容易误匹配；
- 历史关系污染当日分级归属；
- 需求与视频的证据链无法证明是哪个日期、哪条上游事实形成的。

**代码证据**

- `supply_infra/scheduler/jobs/sync_demand_belong_pool_rel.py`
- `supply_infra/db/repositories/multi_demand_pool_di_repo.py`：`list_id_name_video_lists`。

### P1-5：视频点位扩展不是“需求—内容—表现归因”关系

**现状**

视频拓展只对 S/A 级需求执行，并把视频点位中的文本保存为 `expanded_text`。它没有记录：

- 内容主承接哪个需求；
- 辅助承接哪些需求；
- 覆盖程度；
- 内容质量、分发条件和样本状态；
- ROV/VOV 中多少可归因给某个需求；
- 归因结果如何改变次日分级。

**与 PRD 的差距**

PRD 的核心闭环是“需求→内容→表现→归因→次日需求”，而不是“高等级需求从视频点位生成一些扩展词”。

**风险**

- 后验仍只是词或分类节点上的指标，不能证明某项内容验证了某个需求；
- 低等级和冷区需求没有获得通过内容验证的机会；
- 扩展词可能不断增加，却不形成正式需求生命周期。

**代码证据**

- `supply_infra/db/models/demand_video_expansion.py`
- `supply_infra/scheduler/jobs/expand_demand_from_video_points.py`
- `api/services/demand_grade_videos.py`

### P1-6：寻找 Agent 没有接入标准任务包，且自身提示与工具不一致

**现状**

`find_agent` 仍是交互式搜索/分析 Agent；它没有从 `demand_grade` 或任何标准任务包读取当日任务，也没有将找到内容写回需求—内容关系。

其提示要求调用 `save_video_content`、`query_video_content`，但注册工具中不存在这两个能力。

**与 PRD 的差距**

PRD 要求寻找 Agent 与人消费同一任务包，并把发现作为可追溯证据回流。

**风险**

- “自动寻找内容”无法成为每日闭环的一部分；
- Agent 的结果没有业务 ID、主辅需求或覆盖度；
- 提示与实际工具不一致时，执行会产生无效调用。

**代码证据**

- `agents/find_agent/agent.py`
- `agents/find_agent/tools/__init__.py`

### P1-7：没有人的反馈入口，也没有“为什么不是需求”的负向决策账本

**现状**

当前 API 和 Vue 页面只提供树、分级需求和视频点位查询。没有创建反馈、纠错、合并拆分建议、管理指令或负向候选查询接口。

数据模型中也没有候选拒绝、证据不足、重复合并、人工复核等对象。

**与 PRD 的差距**

PRD 要求人可以补充需求和证据，系统能回答“为什么 XX 是需求”和“为什么 XX 不是需求”。

**风险**

- 人无法通过产品参与定义和数据纠错；
- 只能解释已被评级的词，无法解释未生成/被拒绝的候选；
- 业务判断不能沉淀为下一日证据。

**代码证据**

- `api/app.py`
- `web/src/`
- `supply_infra/db/models/`

### P1-8：策略中心、对话式分析和定义版本管理未实现

**现状**

评分规则主要分散在 Agent prompt、Python 常量和调度流程中。没有策略版本实体、定义草案、影响模拟、确认操作或面向业务人员的数据问答服务。

**与 PRD 的差距**

PRD 要求你可以在对话中查看定义、查询数据、要求分析、提出修改，并在影响预览后确认生效。

**风险**

- 同一条需求的结论难以追溯使用了哪版规则；
- 修改 prompt 或阈值会悄悄改变结果；
- 不能把你的业务判断转成受控、可审计的系统策略。

**代码证据**

- `agents/demand_grade_agent/prompt/system_prompt.md`
- `agents/demand_grade_orchestrator_agent/prompt/system_prompt.md`
- `api/app.py`

## 7. P2：历史、可观测性和工程质量问题

### P2-1：运行记录是作业日志，不是需求级业务决策账本

**现状**

`scheduler_job_execution` 能记录流水线开始/结束、结果摘要和错误；分级计划也能记录组和组内项状态。

但它们不能把某条需求的原始证据、认知版本、评分输入、模型解释、策略版本、发布任务、内容归因和人工操作串成一条可查询的历史链路。

### P2-2：同一日重复运行会覆盖分级结果，缺少修订版本

`demand_grade` 按 `(biz_dt, demand_name)` upsert；`demand_grade_category_rel` 会先删除再重写。若同一天重跑或人工纠正，旧等级、旧 reason 和旧挂靠将被覆盖。

这不满足 PRD 对迟到数据、更正批次和历史版本的要求。

### P2-3：跨日稳定、探索配额和行动层没有持久化

当前 S/A/B/C/D 是单日等级，不等于 PRD 的“保供、优先、定向验证、探索、抑制”。没有主题配额、冷区分层随机保留、升级/降级滞后和历史衰减记录。

### P2-4：全局树总热度仍只由四项先验构成

`CategoryTreeWeight.total_score` 只累计外部、持续、去年同期和近期四项排名分。真实 ROV/VOV 可被查询，但没有进入树的全局综合热度，也没有形成单独的后验校正结果。

这使“后验反馈反向影响需求强度”只在 Agent prompt 层存在，未成为可复算的业务结果。

### P2-5：没有自动化测试，且本次代码差异存在格式问题

- 仓库未发现受版本管理的 Python、TypeScript 或 Vue 测试文件；
- 前端依赖未安装，本次无法执行真实前端构建；
- `git diff --check afa8a6d..HEAD` 报告 `web/src/components/DemandGradeListPanel.vue` 末尾多一个空白行。

这不直接改变业务语义，但会降低上述复杂调度、分级和关系逻辑的回归保障。

## 8. 建议的处理顺序

### 第一优先级：先保证每日结果可信

1. 用内容级指纹或更新时间替代“总行数相同即跳过同步”。
2. 修正分级失败状态：任何 failed 组都不能被视为执行完成；失败时禁止发布为完整当日结果。
3. 以单一 `biz_dt + run_id` 对齐树、分级、视频扩展和前端查询。
4. 引入数据库迁移，禁止仅依赖 `create_all` 升级现网结构。

### 第二优先级：建立 PRD 的核心对象和评分结果

1. 建立“原始表达、标准需求词、平台需求、每日任务包”四层对象。
2. 把当前 `demand_grade` 明确定位为词级证据/评估，或升级为平台需求评估；不要同时承担两种含义。
3. 持久化 `需求成立度(0～1)`、`局部供给优先级(0～1)`、置信度、行动层、各维贡献和风险抑制。
4. 将真实 ROV 和真实 VOV 经过归因后进入可复算的后验结果。

### 第三优先级：补齐关系、内容和反馈闭环

1. 用显式关系表替代字符串包含作为最终关系依据；保存关系类型、来源、reason、置信度、审核状态和有效期。
2. 建立需求—内容多对多映射，记录主/辅助需求、覆盖度、内容质量、分发和样本状态。
3. 将寻找 Agent 改为消费任务包、返回结构化发现并写入证据。
4. 增加人的反馈、候选拒绝/未决、人工复核和管理指令。

### 第四优先级：完成业务协作能力

1. 建立策略版本、定义草案、影响模拟和确认流程。
2. 建立可查询的业务决策账本。
3. 支持“为什么是需求/为什么不是需求/为什么今天变化”的数据驱动问答和自动分析。

## 9. 本次验证记录

- 已完成：全部受 Git 管理 Python 文件的 `py_compile` 语法检查。
- 已完成：当前提交相对 PRD 基线的差异检查和主要数据/调度/API/前端链路阅读。
- 未发现：受版本管理的自动化测试文件。
- 未执行：前端构建；原因是 `web/node_modules` 不存在，未在本次分析任务中安装依赖。
- 发现：`git diff --check afa8a6d..HEAD` 报告 `DemandGradeListPanel.vue` 末尾空白行。

