# SupplyAgent 代码仓库结构总结 ## 1. 阅读基线 本文档完全基于当前代码仓库重新阅读后形成,不继承此前对项目的业务推演或可视化设计理解。 代码快照: - 分支:`feature/zhangbo` - 阅读时提交:`2ab77ce` - Python 要求:`>= 3.11` - 后端:FastAPI + SQLAlchemy 2.x + PyMySQL - Agent:OpenRouter/OpenAI 兼容 API + 自研 Tool/Skill/ReAct 框架 - 数据源:ODPS(MaxCompute) - 数据库:MySQL - 对象存储:阿里云 OSS - 前端:Vue 3 + TypeScript + Vite `.env` 已被 `.gitignore` 忽略。本文不会记录其中的密码、密钥、数据库地址或 Token。 --- ## 2. 当前项目的实际定位 当前 SupplyAgent 由两部分组成: 1. 一套通用 AI Agent 运行框架; 2. 一套围绕“需求词、全局分类树、热度、视频和需求生成”的业务系统。 业务系统当前主要完成: - 从 ODPS 同步全局分类树和树下元素; - 从 ODPS 同步多策略需求池; - 将需求词挂到分类树节点; - 汇总四项先验热度和真实 ROV/VOV; - 把词级热度沿分类树向上聚合; - 按单一热度维度生成并保存平台需求; - 把需求词连接到真实视频和视频最终选题; - 通过 API 和 Vue 页面展示分类树、热力图和下钻证据; - 记录 Agent 完整执行过程,生成 HTML,上传 OSS 并在 MySQL 留档。 当前系统的核心业务链路是: ```text ODPS 全局分类与元素 ↓ MySQL 全局分类树 ↑ 需求池词语 → 归类 Agent → 需求词挂靠 ↓ 四项先验 + 真实 ROV/VOV ↓ 词级统计 → 分类树节点聚合 → 四维全局排名 ↓ 需求生成 Agent → generated_demand ↓ FastAPI → Vue 分类树/热力图/证据下钻 ``` --- ## 3. 仓库分层 ```text SupplyAgent/ ├── supply_agent/ 通用 Agent 框架 ├── agents/ 业务 Agent 和专属工具 ├── supply_infra/ MySQL、ODPS、OSS、定时任务 ├── api/ FastAPI 查询接口和静态前端托管 ├── web/ Vue 3 业务前端 ├── scripts/ 部署、日志上传、日志可视化脚本 ├── visualization/ 早期/独立的业务设计可视化材料 ├── Dockerfile 前端构建 + Python 运行镜像 ├── pyproject.toml Python 包、依赖和命令入口 └── requirements.txt 另一份运行依赖清单 ``` 任务 CLI 已并入 `supply_infra/scheduler/jobs/`(`python -m ...`)。 模块之间的依赖方向: ```text web ↓ HTTP api ↓ supply_infra.db.repositories ↓ MySQL agents ↓ supply_agent(Agent 框架) ↓ supply_infra(数据库/ODPS/OSS) jobs / scheduler ↓ supply_infra.scheduler.jobs ↓ ODPS + MySQL + 业务 Agent ``` --- ## 4. 通用 Agent 框架:`supply_agent/` ### 4.1 `supply_agent/config.py` 负责 Agent 侧配置: - OpenRouter API Key、模型和 Base URL; - Agent 最大迭代次数和温度; - Skills 目录; - 日志目录和日志开关。 配置来自环境变量或项目根目录 `.env`,相对路径会解析到项目根目录。 ### 4.2 `supply_agent/llm/client.py` 基于 OpenAI Python SDK 连接 OpenRouter,提供: - 同步对话 `chat`; - 异步对话 `achat`; - 同步文本流 `stream`; - 异步文本流 `astream`; - Tool Calling; - OpenRouter reasoning effort; - LLM 输入和输出日志。 模型可以在运行时切换。 ### 4.3 `supply_agent/tools/` `base.py` 提供: - `@tool` 装饰器; - 从 Python 函数签名生成 JSON Schema; - Optional 和基础类型转换; - 同步/异步工具执行; - 异常转为 JSON 错误结果。 `registry.py` 提供: - 工具注册、删除和查询; - OpenAI ToolDefinition 列表; - 根据模型返回的工具名执行工具; - 同步和异步执行; - 批量注册被 `@tool` 装饰的函数。 ### 4.4 `supply_agent/skills/` Skill 机制读取指定目录下的 `SKILL.md`: - 支持 YAML frontmatter 的名称和描述; - 启动时把 Skill 目录作为目录索引加入系统提示词; - Agent 通过内置 `load_skill` 工具按需加载全文; - Skill 加载后会重建系统消息并注入当前上下文。 当前仓库根目录的 `skills/` 被 `.gitignore` 忽略,因此代码支持 Skill,但仓库没有可随代码分发的业务 Skill 内容。 ### 4.5 `supply_agent/agent/` `core.py` 的 `Agent` 负责组装: - LLMClient; - ToolRegistry; - SkillRegistry; - AgentLoop; - AgentLogger。 对外提供: - `run`; - `arun`; - `stream`; - `astream`。 `loop.py` 实现标准 ReAct/Tool Calling 循环: ```text 系统消息 + 对话历史 ↓ 调用 LLM ↓ 有工具调用?──否──→ 返回最终结果 │是 ↓ 执行工具并写入 Tool Message ↓ 下一轮 LLM ``` 达到最大迭代次数时,同步和普通异步运行会追加一条用户消息,要求模型给出当前最佳答案;流式路径则直接发出 Max iterations reached。 ### 4.6 `supply_agent/logging/` 每次 Agent 运行生成: - 人类可读 `.log`; - 结构化 `.jsonl`。 日志记录: - run_start; - 完整 LLM 输入; - 模型输出和 reasoning; - 工具调用参数和结果; - Skill 加载; - run_end。 运行结束后: 1. 将日志渲染成 HTML; 2. 上传 `.log`、`.jsonl`、`.html` 到 OSS; 3. 把 HTML 公网地址写入 `oss_logs`; 4. 上传失败只记录错误,不影响 Agent 主结果。 --- ## 5. 三个业务 Agent ## 5.1 `demand_belong_category_agent` 目标:把需求词挂到真实存在的全局分类树节点。 工具: - `query_global_tree_category`:读取整棵树或指定子树; - `batch_insert_demand_belong_category`:批量写入需求词、分类 ID 和原因。 业务流程: 1. 查看顶层分类; 2. 选择最相关分支; 3. 逐层下钻; 4. 不确定时停在更可靠的上层节点; 5. 将结果写入 `demand_belong_category`。 系统提示允许一个词选择一个或多个高置信节点,但当前数据库和写入工具以 `name` 唯一: - `demand_belong_category.name` 有唯一约束; - 同一次请求也按 name 去重; - 因此当前实现实际上只能保存“一词一个分类节点”; - 多挂靠尚未在当前表结构中实现。 定时任务会把新需求词按 100 个一批交给该 Agent。 ## 5.2 `generate_demand_agent` 目标:从分类树局部热度和已挂靠需求词中,按单一维度生成平台需求结果。 支持的来源维度只有四项先验: - `ext_pop`:外部热度; - `plat_sust_pop`:平台持续热度; - `plat_ly_pop`:平台去年同期热度; - `recent_pop`:近期热度。 一次运行只允许处理一个维度。 工具: - `query_latest_biz_dt`:取两张统计表都有数据的最新日期; - `query_category_tree_by_dim`:查看指定维度有数据的树; - `query_category_leaves_by_dim`:定位有数据的叶子节点; - `query_demand_words_by_category`:查询节点或子树下的真实需求词; - `query_category_path`:补充根到节点的路径; - `batch_save_generated_demands`:写入 `generated_demand`。 输出结构固定为: ```text source_dim └── overall_direction └── summary_event └── demand_name ``` 重要约束: - `demand_name` 必须原样来自 `demand_belong_category.name`; - Agent 不能新造需求词; - `summary_event` 尽量对应一个需求,最多轻量合并 2~3 个强相关需求; - 写入时保存类目、路径、维度 avg/count 快照、reason、业务日和 run_id; - 同一次工具调用按 `(source_dim, demand_name)` 去重; - 当前 `generated_demand` 没有数据库唯一约束,不同 run 可以重复生成相同需求。 真实 ROV/VOV 当前不属于该 Agent 的 `source_dim`,也没有参与其单维生成工具链。 ## 5.3 `find_agent` 目标:根据需求词、参考视频标题和相关点,寻找老年受众更可能观看和分享的抖音视频。 当前注册的业务工具包括: - `batch_search_and_record`:批量执行多个关键词和分页搜索,每页创建独立搜索及候选记录; - `douyin_search`:调用外部抖音关键词搜索服务并返回数据库记录 ID; - `douyin_search_tikhub`:调用 TikHub 搜索,保存分页状态并返回数据库记录 ID; - `douyin_user_videos`:按作者 sec_uid、排序和游标扩展历史作品并返回数据库记录 ID; - `douyin_detail`:按 content_id 获取视频详情和可播放地址; - `get_content_fans_portrait`:获取视频点赞用户画像; - `get_account_fans_portrait`:获取作者粉丝画像; - `batch_fetch_portraits`:批量获取视频画像,并可同时获取作者画像; - `normalize_age_portraits`:标准化 `50-` 等年龄桶及双侧证据; - `create_video_discovery_run`:创建可追踪的找视频运行; - `batch_update_video_discovery_candidates`:按 candidate_id 更新证据、评分和最终分池; - `update_video_discovery_run_status`:独立更新找视频运行状态; - `query_video_discovery_state`:查询搜索树和候选分池。 搜索和详情接口有约 10 秒的请求间隔限制。 Agent 以需求相关性、老年受众倾向和分享价值的联合目标做判断。系统提示明确区分 “分享量高”和“受众偏老”两类证据,使用视频点赞画像作为内容侧证据、作者粉丝画像 作为账号先验,并对画像缺失或冲突降低置信度。搜索词由 Agent 根据需求、参考标题、 相关点和途中发现的有效标签自主决定;支持多关键词、游标翻页和标签扩展。与需求无关 但老年倾向、分享价值双高的视频保存在人工备选池。 搜索过程持久化到: - `video_discovery_run`:任务输入、意图、状态与计数; - `video_discovery_search`:逐关键词、逐游标页的搜索轨迹; - `video_discovery_candidate`:视频详情、双侧画像、标签、评分、分池与人工审核状态。 --- ## 6. 基础设施:`supply_infra/` ### 6.1 配置 `supply_infra/config.py` 管理: - MySQL; - ODPS; - APScheduler; - 阿里云 OSS; - Agent 日志上传开关。 配置文件固定从项目根目录 `.env` 读取,不依赖当前工作目录。 ### 6.2 数据库会话 `supply_infra/db/session.py`: - 懒加载全局 SQLAlchemy Engine; - 使用连接池和 `pool_pre_ping`; - `get_session()` 自动提交; - 异常时自动回滚; - `init_db()` 通过 ORM metadata 创建缺失表。 ### 6.3 Repository 规则 业务 Agent、API 和定时任务原则上不直接执行 MySQL SQL,而是通过 Repository: - 基础 CRUD; - 批量插入; - insert ignore; - upsert; - 条件查询; - 批量更新。 ODPS 查询仍在 `supply_infra/odps/client.py` 内直接组织 SQL。 ### 6.4 ODPS 客户端 当前读取的主要 ODPS 数据: - `public_pattern_mining_category`:全局分类; - `pattern_mining_element`:树下元素; - `dwd_multi_demand_pool_di`:多策略需求池; - `dwd_topic_decode_result_di`:视频解析和最终选题; - `dwd_video_produce_plan_stat_hour`:真实 ROV/VOV。 ### 6.5 OSS 客户端 负责: - 生成对象路径; - 上传本地文件; - 返回 CDN 公网地址。 --- ## 7. MySQL 数据模型 当前 ORM 定义 10 张表。 | 表 | 作用 | 关键唯一性/关联 | |---|---|---| | `global_tree_category` | 全局分类树节点 | `source_id` 唯一;`parent_id` 形成树 | | `global_tree_element` | ODPS 元素与分类挂靠 | `(name, category_id)` 唯一 | | `multi_demand_pool_di` | 按日同步的策略需求池 | 代码按 `(strategy, demand_id, biz_dt)` 管理差异 | | `demand_belong_category` | 需求词归属分类 | `name` 唯一;当前一词只能保存一个分类 | | `demand_belong_pool_rel` | 需求词与需求池行的匹配边 | `(demand_belong_category_id, multi_demand_pool_di_id)` 唯一 | | `demand_popularity_stats` | 词级六维 avg/count | `(demand_category_id, biz_dt)` 唯一 | | `category_tree_weight` | 分类树节点六维聚合和四维排名分 | `(category_id, biz_dt)` 唯一 | | `multi_demand_video_detail` | 视频标题与最终选题 JSON | `vid` 唯一 | | `generated_demand` | 需求生成 Agent 输出 | 按 run_id 记录,无数据库唯一约束 | | `oss_logs` | Agent 日志 HTML 的 OSS 地址 | 按 agent_name 查询 | ### 7.1 关键关系 ```text global_tree_category.id ├── global_tree_category.parent_id ├── global_tree_element.category_id ├── demand_belong_category.category_id ├── category_tree_weight.category_id └── generated_demand.category_id demand_belong_category.id ├── demand_popularity_stats.demand_category_id ├── demand_belong_pool_rel.demand_belong_category_id └── generated_demand.demand_belong_id multi_demand_pool_di.id └── demand_belong_pool_rel.multi_demand_pool_di_id ``` 这些关联在 ORM 中主要以整数 ID 表达,没有使用 SQLAlchemy relationship,也没有显式数据库 ForeignKey。 --- ## 8. 热度数据的真实代码口径 ### 8.1 策略到四项先验的映射 代码把需求池策略映射为: | ODPS strategy | 统计字段 | 页面含义 | |---|---|---| | `新热事件` | `ext_pop` | 外部热度 | | `逐月` | `plat_sust_pop` | 平台持续热度 | | `去年同期阳历` | `plat_ly_pop` | 去年同期热度 | | `去年同期阴历` | `plat_ly_pop` | 去年同期热度 | | `当下供需gap` | `recent_pop` | 近期热度 | ### 8.2 真实 ROV/VOV 从近 7 日 `dwd_video_produce_plan_stat_hour` 获取人工 AGC 和自动 AGC 数据: - ROV = 回流 UV / 分发曝光 PV; - VOV = 拉回曝光 PV / 分发曝光 PV; - 同一特征值存在多行时,优先保留 `rov_diff`、`vov_diff` 较高的一行; - 按特征值与 `demand_name` 精确匹配,回填 `multi_demand_pool_di`。 ### 8.3 词级统计 对每个 `demand_belong_category.name`: 1. 在当日 `multi_demand_pool_di.demand_name` 中执行子串 LIKE 匹配; 2. 按策略收集非零 weight; 3. 分别计算四项先验的 avg/count; 4. 汇总匹配行的真实 ROV/VOV avg/count; 5. 写入 `demand_popularity_stats`。 因此当前词与需求池的匹配核心是字符串包含关系,不是分词索引、向量匹配或显式语义关系。 ### 8.4 分类树节点聚合 分类节点聚合六个独立维度: - 外部热度; - 平台持续热度; - 去年同期热度; - 近期热度; - 真实 ROV; - 真实 VOV。 每个节点统计其整个子树内有需求词挂靠的节点: ```text 节点维度 avg = Σ(挂靠点 avg × count) / Σ(count) 节点维度 count = Σ(count) ``` 结果写入 `category_tree_weight`。 ### 8.5 四维排名分和全局热度 `demand_pool/tree_weight.py` 在写入权重后会对四项先验排名: - 各维只让 `count > 0` 的节点参与; - 按 avg 降序排名; - 同分取平均名次; - 映射到 `(0, 1]`; - 无数据节点为 0; - `total_score` 是四个排名分直接相加,范围 `[0, 4]`。 真实 ROV/VOV 会被聚合并通过 API 返回,但当前不进入 `total_score`。 前端显示“全局热度”时再使用 `total_score / 4` 映射为 `0~1` 色阶。 单一维度热度则由前端根据该维所有有数据节点的 avg 做百分位色阶,不直接使用数据库中的四维 rank score 字段。 --- ## 9. 定时任务和数据流水线 ### 9.1 已注册的定时任务 `supply_infra/scheduler/app.py` 当前只注册一条任务: 1. 每天 `15:00`(`SCHEDULER_TIMEZONE`):串行执行全链路 `run_supply_pipeline`(全局树 → 需求池 → 分级 → 拓展 → 找视频 → AIGC 发布)。 ### 9.2 全局树同步 `sync_global_tree_odps_to_mysql`: 1. 拉取有效元素; 2. 拉取全部分类; 3. 从元素命中的分类向上补齐祖先; 4. 按 ODPS source_id 去重; 5. 已有分类保持不变,只插入新分类; 6. 给新分类分配 MySQL ID 并转换 parent_id; 7. 写入元素及其 MySQL category_id。 该任务是增量插入,不会根据 ODPS 当前状态自动删除或更新历史分类。 ### 9.3 策略需求池完整流水线 `supply_infra.scheduler.jobs.demand_pool`(`sync_multi_demand_pool_odps_to_mysql`)实际执行顺序: 1. 比较 ODPS 与 MySQL 当日去重行数; 2. 行数不同时执行差异同步; 3. 对当日所有 demand_name 按空格拆词; 4. 调用归类 Agent 处理未出现过的新词; 5. 建立需求词与需求池的子串匹配边,并回填词级 video_list; 6. 获取并回填近 7 日真实 ROV/VOV; 7. 计算词级六维 avg/count; 8. 计算整棵分类树六维聚合; 9. 计算四项先验全局排名分和 total_score; 10. 同步全部待处理视频的标题和最终选题。 当前有一个同步判断风险:只要 ODPS 和 MySQL 行数相同,就跳过需求池差异拉取;如果内容发生变化但总行数不变,该轮不会发现这些变化。 ### 9.4 手动任务入口 用 `python -m` 调用(与定时流水线同源): - `python -m supply_infra.db`:初始化数据库; - `python -m supply_infra.scheduler.jobs.run_supply_pipeline`:全链路; - `python -m supply_infra.scheduler.jobs.demand_pool`:需求池同步(含内部阶段); - `python -m supply_infra.scheduler.jobs.grade_demand_pool`:分级(可加 `--retry-failed`); - 以及 global_tree / expand / discover / publish 各步骤模块。 也可通过 API `POST /api/scheduler/jobs/{job_id}/run` 手动触发。 --- ## 10. FastAPI:`api/` 服务端口:`8080`。 | 接口 | 作用 | |---|---| | `GET /health` | 健康检查 | | `GET /api/category-tree?biz_dt=YYYYMMDD` | 返回嵌套分类树、六维 avg/count、total_score 和挂靠词数 | | `GET /api/demand-belong-category` | 返回所有有效需求词挂靠 | | `GET /api/demand-belong-category/{id}/videos` | 返回需求词关联的视频标题和最终选题 JSON | | `GET /api/demand-belong-oss-logs` | 返回归类 Agent 的 OSS 日志列表 | 如果 `web/dist` 存在,FastAPI 会把它挂到 `/`,同一个 8080 服务同时提供 API 和生产前端。 API 当前是同步 SQLAlchemy 查询,没有分页、鉴权或缓存。 --- ## 11. Vue 前端:`web/` ### 11.1 路由 | 路由 | 页面 | |---|---| | `/` | 平台全局需求地图 | | `/demand-tree` | 传统横向分类树 | | `/demand-process` | 需求归类 Agent 日志 | | `/demand-map` | 重定向到 `/` | 当前顶部导航只显示“平台全局需求地图”,另外两个页面有路由但没有导航入口。 ### 11.2 平台全局需求地图 `GlobalDemandMapView.vue` 并行读取: - 完整分类树和热度; - 全部需求词挂靠。 `IcicleHeatTree.vue` 使用 Canvas 绘制从左到右的冰柱树: - 每层固定 `200px` 宽; - 全局状态适配视口高度; - 选择层级或聚焦节点后按可读高度纵向扩展; - 最大逻辑画布高度 `24000px`; - 实际 Canvas 始终只有视口大小,只绘制可见区域; - 普通滚轮滚动; - 拖拽平移; - `Ctrl/Command + 滚轮` 缩放; - 点击节点聚焦子树; - 支持层级起点和祖先面包屑。 热力标签: - 全局树结构; - 全局热度 `total_score`; - 外部热度; - 平台持续热度; - 去年同期热度; - 近期热度。 API 虽然返回真实 ROV/VOV,但当前冰柱图标签没有提供真实 ROV/VOV 的独立切换入口。 ### 11.3 节点证据下钻 分类节点存在需求词时显示搜索标识。点击后通过 `DemandPathPanel.vue` 展开: ```text 当前分类节点 → 细节元素/需求词 → 真实视频实例 → 最终选题 JSON ``` 这里展示的是 `demand_belong_category` 需求词,不是 `generated_demand` 中由生成 Agent 产出的四层平台需求。 当前前端没有读取或展示 `generated_demand` 的 API。 ### 11.4 传统分类树页面 `CategoryTree.vue` 使用 Vue DOM 递归组件展示: - 默认展开 3 层; - 支持选择展开深度; - 支持手动展开和收起; - 支持按维度过滤有数据的节点; - 支持拖动画布; - 支持导出包含数据的独立 HTML; - 同样可以下钻需求词、视频和最终选题。 ### 11.5 需求归类过程页面 读取 `demand_belong_category_agent` 的 `oss_logs`,按时间倒序显示,点击打开 Agent 运行过程 HTML。 --- ## 12. 部署和运行 ### 12.1 Python 命令入口 `pyproject.toml` 注册: - `supply-api`; - `supply-visualize`。 ### 12.2 本地开发 后端: ```bash python -m api ``` 前端: ```bash cd web npm install npm run dev ``` Vite 在 `5173`,将 `/api` 代理到 `127.0.0.1:8080`。 ### 12.3 Docker Docker 使用两阶段构建: 1. Node 20 构建 Vue; 2. Python 3.11 安装项目和 ODPS 可选依赖; 3. 把 `web/dist` 放入 Python 镜像; 4. 通过 `python -m api` 启动 8080。 `scripts/docker-deploy.sh` 可以构建并向指定镜像仓库推送时间戳标签和 `latest`。 --- ## 13. 当前代码已经实现的能力 - 通用同步/异步 Agent 和 Tool Calling; - 动态 Skill 加载机制; - 三个业务 Agent; - 全量 Agent 日志和 OSS 发布; - ODPS 到 MySQL 的全局树同步; - 多策略需求池增量同步; - 新词自动归类; - 需求词与需求池匹配边; - 真实 ROV/VOV 回填; - 词级六维统计; - 分类树六维向上聚合; - 四项先验排名和 total_score; - 单维度平台需求生成与落库; - 视频标题和最终选题同步; - FastAPI 查询接口; - Vue 全局冰柱热力图; - 分类节点到需求词、视频和最终选题的下钻; - Docker 构建和部署脚本。 --- ## 14. 当前代码未完成或存在偏差的部分 ### 14.1 需求多挂靠尚未实现 `demand_belong_category.name` 唯一,当前一个需求词只能保存一个 category_id。系统提示中的“一词多个节点”无法真实落库。 ### 14.2 `generated_demand` 未进入产品展示 需求生成 Agent 已能写 `generated_demand`,但: - 没有对应 API; - 前端没有需求清单; - 没有与内容、反馈的展示闭环; - 当前全局图下钻的是需求词,不是最终生成需求。 ### 14.3 后验没有进入全局综合分 真实 ROV/VOV 已采集、聚合并由 API 返回,但: - 不进入 `total_score`; - 不进入 generate_demand_agent 的 source_dim; - 当前主热力图没有 ROV/VOV 标签; - 尚未形成“后验反向调整最终需求排序”的完整实现。 ### 14.4 `find_agent` 的外部证据仍可增强 当前已持久化搜索轨迹、正式推荐和人工备选,但画像接口提供的是点赞用户而非真实转发 用户。后续若能补充转发用户画像、分年龄观看留存、相似视频和批量搜索接口,可进一步 提高老年分享判断的直接性与多词多页探索效率。 ### 14.5 关系语义较弱 当前主要关系是: - 树父子; - 需求词到单一分类; - 需求词和需求池的字符串子串匹配; - 需求词到视频列表。 尚没有独立的语义关系表、关系类型、关系 reason、置信度和人工审核状态。 ### 14.6 同步完整性风险 需求池同步先比较总行数。总行数相同但内容变化时,会跳过 ODPS 明细同步。 ### 14.7 测试体系缺失 当前仓库没有 `tests/`,并且 `.gitignore` 直接忽略 `tests/`,会阻止正常提交测试目录。 ### 14.8 文档已滞后 现有 `README.md`、`ARCHITECTURE.md` 和 `agents/README.md` 包含已经不存在或未实现的结构,例如: - `video_content` 模型/Repository; - find_agent 的保存和历史查询工具; - 旧的 Agent 数量和数据流。 后续应以本文和源码为准,并更新旧文档。 --- ## 15. 当前本地运行环境与数据库状态 ### 15.1 本地 Python 环境不匹配 当前机器默认环境: - Python `3.10.19`; - SQLAlchemy `1.4.51`; - 项目根目录没有 `.venv`。 源码要求: - Python `>=3.11`; - SQLAlchemy `>=2.0`。 因此直接使用当前默认 `python3` 导入数据库层会在 `DeclarativeBase` 处失败。应建立 Python 3.11+ 虚拟环境后安装项目依赖。 ### 15.2 `.env` 的 MySQL 配置问题 只读连接检查发现: 1. `MYSQL_HOST` 的值开头多了一个 `=`,会导致主机名解析失败; 2. 临时去掉该字符后可以到达 MySQL 服务,但返回错误 `1045 Access denied`; 3. 需要核对用户名/密码、RDS 白名单或该用户允许连接的 Host 范围。 由于未通过鉴权,本次无法确认数据库真实表数量、行数和最新业务日。本文的数据结构来自当前 ORM 和 Repository 源码,不冒充线上运行态数据。 ### 15.3 前端依赖未安装 当前没有 `web/node_modules`。Node `20.11.1`、npm `10.2.4` 已存在,执行前需要先在 `web/` 运行 `npm install` 或 `npm ci`。 --- ## 16. 建议的后续阅读顺序 如果继续开发,建议按以下顺序进入代码: 1. `supply_infra/scheduler/jobs/demand_pool/`:理解需求池同步主业务; 2. `supply_infra/db/models/`:理解真实数据对象; 3. `supply_infra/scheduler/jobs/demand_pool/tree_weight.py`:理解树上热度; 4. `agents/demand_belong_category_agent/`:理解需求词挂树; 5. `agents/generate_demand_agent/`:理解平台需求生成; 6. `api/services/category_tree.py`:理解后端对前端的数据形态; 7. `web/src/components/IcicleHeatTree.vue`:理解全局热力图; 8. `web/src/components/DemandPathPanel.vue`:理解节点证据下钻; 9. `supply_agent/agent/`:理解底层 Agent 执行机制; 10. `supply_agent/logging/`:理解可追溯运行日志。 --- ## 17. 一句话总结 当前 SupplyAgent 是一套以 ODPS 和 MySQL 为数据底座、以全局分类树为组织骨架、以自研 Agent 框架完成需求词归类和单维需求生成、并通过 FastAPI/Vue 展示分类热度与视频证据的业务系统;核心数据流水线已经形成,但多挂靠、最终需求产品化、后验反馈进入综合决策、语义关系图和自动化测试仍未完成。