核验日期:2026-05-29
代码范围:/Users/samlee/Documents/works/image_article_comprehension
文档/Excel范围:/Users/samlee/Documents/works/image_article_comprehension_structure源码分析、/Users/samlee/Documents/works/数据工程
结论来源:当前 checkout 代码行号、三个已完成 subagent 只读复核、PostgreSQL open_aigc.public 只读查询、Excel 只读检查。Excel 未被修改。
本报告不复写源码中的数据库密码、API key、token、AK/SK。MySQL
open_aigc_pattern的 RDS 域名 Fake-IP 路径本轮连接失败,但改用真实内网地址192.168.202.204:3306后只读复核成功;本文只写脱敏后的连接事实和统计结果。
data_clustering_statistic.xlsx 里的 00-08 链路是真实存在的“聚类辅助分类/embedding 分类工程链路”:三张源元素表进入 9 组 source_type + source_table,经过 element_dedup_group、本地 source embedding cache、dist_rows 距离矩阵、DBSCAN 候选簇、cluster batch,再进入分类 agent 或 EmbeddingClassifier,最终沉淀 global_category/global_element/element_classification_mapping。
但这条 Excel 链路不是 run_classify.py 的硬前置链路。run_classify.py 的主路径直接从源表 SQL 聚合未分类元素,按 (name, type) 去重后交给 ClassifyAgent;它不导入 dedup matrix、embedding cache、距离矩阵或 DBSCAN。代码证据是 run_classify.py 和 data_operation.py。
当前事实应写成“双入口/双口径”:
| 入口 | 是否需要 dedup/embedding/DBSCAN | 作用 |
|---|---|---|
run_classify.py |
不需要 element_dedup_group、source embedding cache、距离矩阵、DBSCAN |
主分类入口:SQL 聚合未分类元素,Agent 写 global 三表 |
run_classify_embedding.py |
需要待分类元素 embedding 和 global vector search,不需要 DBSCAN | embedding + LLM 批量分类入口,写 global element/mapping/embedding |
cluster_on_demand.py / run_classify_clustering.py |
DBSCAN 需要预构建距离矩阵;聚类到分类的桥接当前仍有 TODO | 聚类辅助入口:找相似候选簇,辅助人工/agent 批处理 |
global_category/global_element/element_classification_mapping 的口径要按“广义/狭义”拆开:如果把整个 pattern_global_v2 服务都口头叫 Pattern V2,那么其中的分类库/分类执行阶段会写这三张 global 表;如果按本文更精确的“狭义 Pattern V2 = daily snapshot/mining/API 子域”,它不生成这三张 global 表,只读取它们。三张 global 表的核心写入点包括 classify_agent_tools.py、data_operation.py、data_operation.py、data_operation.py。
Pattern V2 的真实角色是下游快照和挖掘:读取 element_classification_mapping、活跃 global_category、三张源元素表和可选 global_element_semantic_map/cluster,写 pattern_mining_* 快照和 pattern_itemset*、pattern_script_sequence*、pattern_group_itemset* 结果。代码证据是 run_daily.py、snapshot_builder.py、snapshot_builder.py。
global_element_semantic_cluster/map 当前库中有数据,但当前仓库内只找到 Pattern V2 对它的消费和快照写入,没有找到生成 global_element_semantic_cluster/map 的脚本或 agent 主路径。只能确认:Pattern V2 消费它,并把命中的 semantic cluster 写成 pattern_mining_element_semantic_map。
pattern_global_v2 的主链不是一个简单线性全自动链路,而是一条主链加多个可选/维护入口:数据导入、分类库冷启动、run_classify/embedding classify、聚类辅助、向量同步、classification status、Pattern V2 快照挖掘、API/可视化。check/optimize/refactor/distribute/promote/cleanup/backfill 是维护或质量治理链路,会影响 future snapshot 的 global 资产或发布状态,但不是每次 Pattern V2 挖掘的硬前置。
MySQL open_aigc_pattern 读通后不改变上述主链路结论。它证明 8012 Topic/Script Build 工作台和旧 topic_pattern_* 兼容层是活跃数据域,但没有发现它参与 run_classify.py、global 三表生成,或替代 PostgreSQL open_aigc 的 Pattern V2 主事实。
实线表示硬依赖;虚线表示辅助、可选、半自动或维护链路。
flowchart TD
A["上游 decode / data_io / API / ODPS / JSON"] --> B["post / post_decode_* / post_script_* 源表"]
B --> C["run_classify.py SQL 未分类元素聚合"]
C --> D["ClassifyAgent 工具"]
D --> E["global_category"]
D --> F["global_element"]
D --> G["element_classification_mapping"]
D --> H["post_classification_status"]
B -. "Excel 聚类工程链路" .-> I["element_dedup_group: 9 组 source_type + source_table"]
I -.-> J["source embedding cache: embeddings_{source_table}.*"]
J -.-> K["dist_rows 距离矩阵: source_type__source_table"]
K -.-> L["DBSCAN 候选簇"]
L -.-> M["cluster batch"]
M -. "run_classify_clustering 当前 TODO" .-> D
B -. "embedding 分类入口" .-> N["run_classify_embedding.py"]
N -.-> O["EmbeddingClassifier: embedding/search/LLM/write"]
O --> F
O --> G
O --> P["global_element_embedding"]
E --> Q["Pattern V2 snapshot_builder"]
F -. "经 mapping / semantic map 间接参与" .-> Q
G --> Q
B --> Q
R["global_element_semantic_cluster/map"] -. "可选消费;当前仓库未找到生成器" .-> Q
H --> S["classify_post_buckets"]
S --> T["pattern_mining_post_bucket"]
Q --> U["pattern_mining_execution"]
Q --> V["pattern_mining_category"]
Q --> W["pattern_mining_element"]
Q --> X["pattern_mining_element_semantic_map"]
V --> Y["FP-Growth / PrefixSpan / group mining"]
W --> Y
T --> Y
Y --> Z1["pattern_itemset / item / post"]
Y --> Z2["pattern_script_sequence / item / post"]
Y --> Z3["pattern_group_itemset / item / member"]
Z1 --> API["pattern_global_v2 API / debug tools / visualization"]
Z2 --> API
Z3 --> API
API --> BUILD["patter_from_global_and_build: Topic/Script Build Agent"]
BUILD --> OUT["open_aigc_pattern topic_build_* / script_build_*"]
MAINT["check / optimize / refactor / distribute / sync_vectors / promote / cleanup / backfill"] -. "维护 global 资产或 pattern execution 状态" .-> E
MAINT -.-> F
MAINT -.-> G
MAINT -.-> U
data_clustering_statistic.xlsx 有 9 个 sheet:00_聚类总览 到 08_global_mapping。只读检查显示,它描述的是“聚类/embedding 辅助分类”工程链路,不是 run_classify.py 唯一执行链路。
| Excel 阶段 | 当前代码事实 | 代码证据 | 需要纠偏的口径 |
|---|---|---|---|
| 00/01 原始元素表 | 三张源元素表:post_decode_topic_point_element、post_script_element、post_script_paragraph_field_element |
models.py、models.py、models.py | 不是全库聚类,是 3 张表里的指定业务维度 |
02 element_dedup_group |
一张表承载 9 组处理组合,按规范化元素名聚合 | sync_all_dedup_groups.py、dedup_manager.py、dedup_manager.py、models.py | 不是 9 张去重表 |
| 03 source embedding cache | 本地 cache/embeddings_{source_table}.ids.npy/.vecs.npy;可复用已分类的 global_element_embedding |
embedding_cache.py、distance_matrix_manager.py | source embedding cache 不是独立 DB 表 |
04 dist_rows 距离矩阵 |
本地行存储,文件名按 source_type__source_table |
build_all_matrices.py、distance_matrix_manager.py | 距离矩阵不是 PostgreSQL 表 |
| 05 DBSCAN | cluster_on_demand.py 要求矩阵已存在,DBSCAN 用 precomputed distance |
cluster_on_demand.py、cluster_on_demand.py、cluster_on_demand.py | DBSCAN 是聚类入口硬前置,不是 run_classify.py 硬前置 |
| 06 cluster batch | 旧 ClusterBatchPreparer 可从 JSON 展开未分类 batch |
cluster_batch_prepare.py、cluster_batch_prepare.py、cluster_batch_prepare.py | 当前实现有方法名/key 漂移风险,不能写成稳定全自动主链 |
| 07 classify agent | ClassifyAgent 或 EmbeddingClassifier 写 global element/mapping/embedding | run_classify.py、run_classify_embedding.py、EmbeddingClassifier.py | 分类 agent 不是 DBSCAN;DBSCAN 只是帮助组织候选 batch |
| 08 global mapping | 最终主事实是 global 三表及 embedding/status 辅助表 | models.py、models.py、models.py | Pattern V2 下游读取这些资产,不生成这些资产 |
Excel 本身的问题不是“链路错”,而是容易被读成“所有分类都必须先跑 DBSCAN”。更准确的说法是:Excel 描述的是聚类辅助分类/embedding 分类工程路径;run_classify.py 还有一条不依赖 DBSCAN 的主分类路径。
run_classify 的真实前置run_classify.py 的硬前置是:
element_classification_mapping 可用于排除已分类 source element。global_category 写入工具。run_classify.py 不强制需要:
element_dedup_groupdist_rows 距离矩阵global_clusters_*.json代码上它直接调用 data_operation.get_unclassified_elements() 或脚本侧未分类查询,再创建 batch 并调用 agent.run_classify_batch():run_classify.py、run_classify.py、run_classify.py。SQL 去重在 data_operation.py 到 data_operation.py,是 GROUP BY name/type,不是读 element_dedup_group。
相反,cluster_on_demand.py 的硬前置才是距离矩阵:矩阵不存在会直接抛错并提示先跑 build_all_matrices.py,见 cluster_on_demand.py 到 cluster_on_demand.py。
Global 三表的生成和维护来自分类库链路,不来自 Pattern V2。
| 表 | 主要写入路径 | 代码证据 |
|---|---|---|
global_category |
create_category、update_category、create_and_classify、冷启动、优化/重构维护 |
classify_agent_tools.py、data_operation.py、data_operation.py、data_operation.py |
global_element |
ClassifyAgent 的 find_or_create_element;EmbeddingClassifier 的 batch_find_or_create_elements |
classify_agent_tools.py、data_operation.py、data_operation.py、EmbeddingClassifier.py |
element_classification_mapping |
classify_elements 单条写;EmbeddingClassifier 批量写;auto-link/backfill 回填 |
classify_agent_tools.py、data_operation.py、data_operation.py、data_operation.py、data_operation.py |
分类资产的业务关系是:
原始源表一行
-> element_classification_mapping.source_table + source_element_id
-> global_element.id
-> global_element.belong_category_stable_id
-> global_category.stable_id / path
global_category 和 global_element 都有 retired_at_execution_id 当前有效口径;global_category.stable_id 是逻辑分类 ID,id 是行版本 ID。
Pattern V2 的起点不是 raw 解构或 DBSCAN,而是已经存在的 global 分类资产和源表事实。
| 输入 | 作用 | 代码证据 |
|---|---|---|
| post ids / post filter | 决定本次 execution 的帖子范围 | run_daily.py |
element_classification_mapping |
把源元素连接到 global category/element | snapshot_builder.py |
global_category 活跃树 |
回填当前可信 path 和祖先链,构建 pattern 快照树 | snapshot_builder.py |
| 三张源元素表 | 生成 execution 内元素快照 | snapshot_builder.py |
global_element_semantic_map/cluster |
可选语义归一,用簇代表覆盖 name/description/category | snapshot_builder.py |
post_classification_status / mapping 完成度 |
分桶,决定哪些帖子进入不同算法 | run_daily.py |
一个需要单独标注的事实:build_snapshot() 接收 classify_execution_id,但当前映射读取是按 post_ids 全量读 element_classification_mapping,没有按 classify_execution_id 过滤 mapping;classify_execution_id 主要用于收集 category 版本视图。这可能带来时间一致性风险,证据见 snapshot_builder.py 到 snapshot_builder.py。
| 输出表 | 作用 | 代码证据 |
|---|---|---|
pattern_mining_execution |
一次挖掘执行记录、post 范围、状态、统计 | models.py |
pattern_mining_category |
execution 内剪枝后的分类树快照 | models.py、snapshot_builder.py |
pattern_mining_element |
execution 内源元素到 pattern category 的冻结事实 | models.py、snapshot_builder.py |
pattern_mining_element_semantic_map |
本次快照中 semantic cluster 的归一记录 | snapshot_builder.py |
pattern_mining_post_bucket |
topic/fully 等分类完成度桶 | run_daily.py |
| 算法 | transaction | 结果表 | 代码证据 |
|---|---|---|---|
| Topic / topic_element / cross / paragraph FP-Growth | 帖子、段落或选题点 group | pattern_itemset、pattern_itemset_item、pattern_itemset_post |
run_daily.py、itemset_writer.py |
| Script PrefixSpan | 帖子内段落顺序序列 | pattern_script_sequence、pattern_script_sequence_item、pattern_script_sequence_post |
run_daily.py、script_sequence_writer.py |
| Point group mining | 帖子内子分组单元 | pattern_group_itemset、pattern_group_itemset_item、pattern_group_itemset_member |
models.py、group_itemset_writer.py |
run_daily_main.py 当前硬编码默认只启用 ENABLE_TOPIC_ELEMENT=True,其他开关 false,见 run_daily_main.py。run_daily.py 函数本身支持更宽的可配置能力,所以报告里应区分“函数能力”和“当前默认入口”。
Pattern V2 成功后不自动发布为 is_current;需要单独 promote,见 run_daily.py 和 promote_current.py。
| 能力 | 是否并入主链 | 说明 |
|---|---|---|
data_io 导入 |
是 | 把上游 decode/API/ODPS/JSON 结果写入 post_decode_* / post_script_*,是源表入口 |
| 分类树 cold start | 是 | 首次或空树场景创建 global_category 初始分类体系 |
run_classify.py |
是 | 主分类入口,直接写 global 三表 |
run_classify_embedding.py / EmbeddingClassifier |
是,可选替代分类入口 | embedding + vector search + LLM,写 global element/mapping/embedding |
| dedup/embedding/距离矩阵/DBSCAN | 是,但属于聚类辅助路径 | Excel 描述的工程链路,辅助构造分类 batch,不是 Pattern V2 或 run_classify 的硬前置 |
global_*_embedding / vector search |
是 | 分类复用、相似搜索、embedding 分类依赖 |
post_classification_status / Pattern buckets |
是 | 决定 Pattern V2 算法输入桶 |
global_element_semantic_cluster/map |
是,作为 Pattern snapshot 可选输入 | 当前仓库只能证明被消费,不能证明由 Pattern V2 生成 |
这些链路不应写成 Pattern V2 的硬前置,但会改变后续快照看到的 global 资产或 execution 状态:
| 链路 | 作用 | 对主链影响 |
|---|---|---|
| check / optimize / refactor | 检查分类树结构、离群元素、重复节点,提出或执行分类树调整 | 调整后影响未来 global_category/global_element/mapping |
| distribute | 分类或聚类后的分发/批处理辅助 | 属于分类库维护工具,不是 pattern mining 必经步骤 |
sync_vectors.py / generate_missing_embeddings.py |
同步或补齐 global_category_embedding/global_element_embedding |
提升相似搜索、embedding 分类和工具检索质量 |
| promote current | 切换 pattern_mining_execution.is_current |
影响线上 API 默认读取哪个 execution |
| cleanup / backfill / clone snapshot | 删除、修复、复制或补回 pattern 快照/结果 | 维护历史 execution,不生成 global 三表 |
open_aigc.public本轮 PostgreSQL 只读连接成功。关键计数如下:
| 数据域 | 表 | 行数 |
|---|---|---|
| 源表 | post |
66,974 |
| 源表 | post_decode_topic_point_element |
1,308,993 |
| 源表 | post_script_element |
47,951 |
| 源表 | post_script_paragraph_field_element |
177,856 |
| 去重 | element_dedup_group |
262,326 |
| global | global_category |
4,944 |
| global | global_element |
290,864 |
| global | element_classification_mapping |
1,123,373 |
| embedding | global_element_embedding |
455,269 |
| embedding | global_category_embedding |
8,860 |
| semantic | global_element_semantic_cluster |
5,585 |
| semantic | global_element_semantic_map |
18,248 |
| pattern snapshot | pattern_mining_execution |
7 |
| pattern snapshot | pattern_mining_category |
25,816 |
| pattern snapshot | pattern_mining_element |
1,950,755 |
| pattern result | pattern_itemset |
449,216 |
| pattern result | pattern_script_sequence |
2,753 |
| pattern result | pattern_group_itemset |
2,997 |
element_classification_mapping 当前分布:
| source_table | element_type | rows | posts | global_elements |
|---|---|---|---|---|
post_decode_topic_point_element |
实质 | 518,403 | 52,529 | 125,586 |
post_decode_topic_point_element |
形式 | 421,692 | 52,395 | 46,994 |
post_decode_topic_point_element |
意图 | 12,050 | 11,954 | 230 |
post_script_element |
实质 | 23,069 | 1,933 | 9,941 |
post_script_element |
形式 | 13,103 | 1,949 | 7,022 |
post_script_paragraph_field_element |
作用 | 25,298 | 1,907 | 4,751 |
post_script_paragraph_field_element |
实质 | 74,238 | 1,933 | 26,449 |
post_script_paragraph_field_element |
形式 | 35,520 | 1,932 | 8,112 |
element_dedup_group 当前 9 组分布:
| source_table | source_type | groups | occurrence_sum |
|---|---|---|---|
post_decode_topic_point_element |
实质 | 140,069 | 537,822 |
post_decode_topic_point_element |
形式 | 49,402 | 423,987 |
post_decode_topic_point_element |
意图 | 643 | 40,732 |
post_script_element |
实质 | 12,562 | 31,872 |
post_script_element |
形式 | 9,053 | 16,079 |
post_script_paragraph_field_element |
作用 | 8,422 | 28,895 |
post_script_paragraph_field_element |
实质 | 30,830 | 81,906 |
post_script_paragraph_field_element |
形式 | 9,151 | 38,519 |
post_script_paragraph_field_element |
感受 | 2,194 | 28,536 |
Pattern execution 状态:
| id | snapshot_date | status | is_current | post_count | category_count | element_count | topic_itemset_count | topic_element_itemset_count | script_sequence_count |
|---|---|---|---|---|---|---|---|---|---|
| 581 | 2026-05-09 | success | false | 13,265 | 1,932 | 290,467 | 35,406 | 18,491 | |
| 541 | 2026-04-27 | running | false | 12,448 | 3,992 | 315,389 | 38,418 | ||
| 501 | 2026-04-27 | success | false | 12,448 | 3,992 | 315,389 | 26,070 | ||
| 421 | 2026-04-24 | success | false | 12,448 | 3,995 | 315,389 | 26,849 | 8,932 | |
| 401 | 2026-04-23 | failed | true | 12,448 | 3,995 | 315,389 | 1,197 | ||
| 301 | 2026-04-21 | success | false | 11,760 | 3,955 | 199,366 | 928 | 388 | |
| 281 | 2026-04-16 | success | true | 11,760 | 3,955 | 199,366 | 76,835 | 17,153 | 1,030 |
这里有一个上线口径风险:当前 DB 中 is_current=true 同时出现 #401 failed 和 #281 success。最新成功是 #581,但它不是 current。API 默认读取 current 时需要同时防守 status='success'。
open_aigc_pattern本轮复核发现:当前代码里的 MySQL 连接配置目标是 open_aigc_pattern,但 RDS 域名 rm-bp1k5853td1r25g3n690.mysql.rds.aliyuncs.com 在当前网络环境下解析到 Fake-IP 198.18.0.59。该路径 TCP 端口可连,但收不到 MySQL greeting,PyMySQL 报 OperationalError: (2013, 'Lost connection to MySQL server during query')。改用真实内网地址 192.168.202.204:3306 后,只读查询成功。
当前只读复核结果:
| 项 | 结果 |
|---|---|
| 数据库 | open_aigc_pattern |
| MySQL 版本 | 5.7.30-log |
| 表数 | 35 |
| 字段数 | 332 |
关键表规模:
| 表 | 行数 | 角色 |
|---|---|---|
topic_build_record |
1,093 | 选题构建执行记录 |
topic_build_topic |
1,264 | 选题候选/结果 |
topic_build_point |
7,369 | 选题点 |
topic_build_composition_item |
22,579 | 选题组成元素 |
topic_build_item_relation |
19,055 | 构成元素关系 |
topic_build_item_source |
23,504 | 元素证据来源 |
topic_build_item_exploration_trace |
15,466 | item 探索轨迹 |
topic_build_log |
1,086 | 选题构建日志 |
script_build_record |
269 | 脚本构建执行记录 |
script_build_paragraph |
945 | 脚本段落 |
script_build_element |
2,459 | 脚本元素 |
script_build_paragraph_element |
4,447 | 段落和元素关联 |
script_build_decision_trace |
649 | 脚本构建决策 trace |
script_build_log |
264 | 脚本构建日志 |
external_search_case_log |
12,043 | 外部搜索 case 缓存 |
prompt / prompt_version |
9 / 125 | prompt 当前版本和历史版本 |
build_strategy / build_strategy_version |
56 / 242 | 构建策略当前版本和历史版本 |
topic_pattern_execution |
58 | 旧 topic pattern 本地执行 |
topic_pattern_category |
29,363 | 旧 topic pattern 分类镜像 |
topic_pattern_element |
565,571 | 旧 topic pattern 元素镜像 |
topic_pattern_itemset |
655,513 | 旧 topic pattern 本地 itemset |
topic_pattern_itemset_item |
3,007,048 | 旧 topic pattern item |
因此,代码层事实需要写得更精确:patter_from_global_and_build 的 pattern_server.py 提供 topic/script build API,并通过 MySQL ORM 模型写 topic_build_*、script_build_*、prompt、strategy、external search 等应用表;topic_pattern_* 是旧本地 mining / 兼容 / 展示兜底层。它不是 global 三表生成器,也不替代 PostgreSQL open_aigc 里的 Pattern V2 快照和挖掘结果。
这份报告不把服务边界作为主分析框架,但按 Docker 部署看,有两个主要后台服务:
| Docker | 端口 | 大概职责 | 代码证据 |
|---|---|---|---|
docker/Dockerfile.pattern_global_v2 |
8001 | 数据底座、分类库、global 表、dedup/embedding/聚类辅助、Pattern V2、API/debug/可视化 | Dockerfile.pattern_global_v2、Dockerfile.pattern_global_v2、visualization_server.py |
docker/Dockerfile.patter_from_global_and_build |
8012 | Topic/Script Build Agent、构建工作台、prompt/strategy、外部搜索和构建记录,消费 8001/open_aigc 数据/API | Dockerfile.patter_from_global_and_build、Dockerfile.patter_from_global_and_build、pattern_server.py、pattern_server.py |
pattern_server.py 文件头仍写 8002,但 Docker 暴露的是 8012,应以 Docker 和启动参数为准。
run_classify_clustering.py 准备好 cluster batch 后仍打印 TODO,未真实调用 agent.run_classify_batch():run_classify_clustering.py。ClusterBatchPreparer.cluster_all_elements() 同步矩阵时带 source_type + source_table,但加载矩阵用 load_or_create(source_type),和新矩阵 key source_type__source_table 有漂移风险:cluster_batch_prepare.py、cluster_batch_prepare.py。ClusterBatchPreparer.get_unclassified_from_cluster() 调用 expand_dedup_groups,当前 DedupManager 中可靠方法名是 expand_members,存在旧方法名漂移风险:cluster_batch_prepare.py、dedup_manager.py。感受 + post_decode_topic_point_element 有原始数据,但不在 dedup/matrix 9 组目标里;Pattern/global 当前 mapping 也没有感受映射行。这会造成“源表有感受、当前 global/mapping 没感受”的口径差异。classify_execution_id 没有过滤 mapping,只影响 category 版本收集,可能造成 execution 时间一致性偏差。global_element_semantic_cluster/map 当前 DB 有数据,但当前仓库未找到生成链路,只能确认 Pattern V2 消费它。open_aigc_pattern 的标准 RDS 域名当前仍会走 Fake-IP 路径并导致 MySQL 握手失败;真实内网地址 192.168.202.204:3306 可只读复核成功。后续若要服务运行稳定,应修复域名解析/代理规则,或让配置支持可控的内网地址覆盖。去重 + embedding + 聚类 + 分类 agent + Pattern V2 都属于广义 pattern_global_v2 数据底座能力,但不是一条单一强制全自动链。Excel 描述的是聚类辅助分类工程链路;run_classify.py 可以绕过 DBSCAN 直接分类;global 三表由分类库链路写入;Pattern V2 在下游读取这些 global 资产和源表事实,生成 pattern_mining_* 快照和 pattern 结果,再供 API/debug tools 和 Topic/Script Build Agent 消费。