跳转至

整体架构

xgb_wiki 是一个单机数据处理 + 本地 Web 展示系统:从内网 MySQL 抽取选股宝脱水研报,整理为题材本体(SQLite),再经 Flask 渲染为可浏览的 Wiki,并导出 Ontology-Playground 兼容的本体 schema。 设计动机与模型取舍见 设计方案;字段级定义见 数据模型。

1. 系统上下文

🖼 交互版大图:xgb_wiki 系统上下文(architecture)——可搜索、聚焦链路(主数据链 / 可选旁路 / 发布链)、明暗主题。规格源 diagrams/xgb-context.architecture.json。

flowchart LR
    subgraph 外部依赖
        MYSQL[("内网 MySQL\nxuangubao\n(只读)")]
        LLM["Ark API\n(链映射/观点提取/问答,可选\n配置页 /settings/llm 可调)"]
        LAS["LAS 图片解析\n(限流 1 QPM,计费)"]
        IMG["image.xuangubao.cn\n研报配图"]
        WEKNORA["WeKnora v0.8.2\n后台核心知识库\n(已实施:文档推送+检索)"]
        TOS[("火山 TOS 上海桶\n三库备份 xgb-wiki/backup/*\nlatest.json 指向最新")]
    end

    subgraph xgb_wiki
        ETL["数据同步\nscripts/sync/sync_data.py\n(sync.py 编排 + etl.py 搬运\n含 report_tag 栏目重建)"]
        DB[("SQLite\ndata/xgb_wiki.db\n本体实例数据 + report_tag")]
        WEB["Flask Web\napp.py → src/web :5010\n(含 /reports 栏目页\n与 /settings/llm)"]
        RDF["RDF 导出\nsrc/kg/rdf_export.py"]
    end

    subgraph 展示层
        BROWSER["浏览器\n14+ Wiki 页面\n(栏目/简报/配置页)"]
        PG["Ontology-Playground\n本地镜像 / fork Pages"]
        SITE["Cloudflare Pages 静态研报站\nxgb-wiki-site.pages.dev\n(GitHub Actions CI 构建)"]
    end

    MYSQL -->|"SELECT 脱水研报\n(按同步进度标记增量)"| ETL
    LLM -.->|"可选:链映射"| ETL
    ETL --> DB
    DB --> WEB
    LAS -.->|"按需解析"| WEB
    IMG -.->|"缩略图直链"| WEB
    WEB --> BROWSER
    DB --> RDF
    RDF --> PG
    DB -->|"build_static_site.py\npush master 触发 CI"| SITE
    DB -->|"push_to_weknora.py\n篇级 MD+月份标签\n(推送进度标记幂等)"| WEKNORA
    DB -.->|"backup_tos.py(工作机侧)\n三库快照+.env 滚动6份"| TOS
    TOS -.->|"tos_preflight.py(多机预检)\n云端新则恢复三库"| DB

关键边界:

  • MySQL 只读且仅内网可达——所有写入一律落 SQLite;同步默认增量(同步进度标记驱动,秒级), 失败自动回退,全量重建(--full)幂等可随时执行
  • LLM 与 LAS 均为可选旁路:观点提取有规则引擎降级(无 key 可用),图片不解析不影响主流程
  • 外网图片域名直链展示;若后续公网部署需考虑图片代理/本地化
  • WeKnora 语义层(双核演进中):结构化事实口径(热度/时间窗/证据)永远以本库为准;语义侧(全文检索/RAG(检索增强生成)问答/图谱浏览)按 融合方案 v0.2 逐步移交 WeKnora——文档推送已实施(4844 篇,数据至 2026-09-30),问答迁离(S1)与图谱接管(S2)执行前,本页路由表仍为现状
  • 数据分发双通道:git(代码 + db 快照随仓库走)与火山 TOS(backup_tos.py 三库备份 / tos_preflight.py 按需恢复,多机协作主通道)并行;MySQL/xgb-wiki/TOS/WeKnora 四系统角色与全部流程见 四系统总览

2. 数据流水线

🖼 交互版大图:增量同步流水线(workflow)——主链 / 校验与回退 / 合并新增三个视角。规格源 diagrams/xgb-sync-pipeline.workflow.json。

flowchart TB
    subgraph 抽取层 extractors.py
        A1["大涨题材段\nN、个股:X(1)大涨题材:Y"]
        A2["研报来源块\n券商,分析师,S编号,标题,日期"]
        A3["正文图片\n<img src> + 前后100字上下文"]
        A4["plates 字段\nID,名称;…(仅 live)"]
    end

    subgraph 编排层 sync.py + etl.py
        B0["环境检查 → 备份 → 临时库\n校验 → 原子替换/回退 → sync_log"]
        B1["建库/重建 schema"]
        B2["逐篇处理 live+digest\n(全量/增量共用,进度标记驱动)"]
        B2T["栏目 tag 重建\nreport_tag 全量映射\n(一篇可多栏目,/reports 依据)"]
        B3["聚合统计\n出现次数/衰减热度/时间窗\n(cnt_5d..30d + theme_daily)"]
        B4["载入 chain_map.json\n(19链/173环节)"]
    end

    subgraph 观点层 viewpoint.py
        C1["信号句定位 evidenceQuote"]
        C2["催化类型分类 reasonType\n(8类关键词字典)"]
    end

    A1 --> B2
    A4 --> B2
    A2 --> B2
    A3 --> B2
    B0 --> B1 --> B2 --> B2T --> B3 --> B4
    B2 --> C1 --> C2

日常增量同步(python scripts/sync/sync_data.py,默认)约 5~20 秒:按同步进度标记拉新增研报、 剔除源端删除行、全量重建 report_tag 栏目映射、聚合全量重算,全程经环境检查/ 数据校验/失败回退(详见 数据同步指南)。全量重建加 --full 约 1 分钟。 两种模式均在 etl_meta 表记录 built_at / ref_date(数据基准时间)与同步进度标记 wm_live_id / wm_digest_id。

3. 模块划分

2026-09 分层重构后的结构(重构过程与决策见 refactoring.md;放置规则见仓库根 AGENTS.md 末节)。

src/                     # 核心库(一律绝对导入 from src.<pkg>.<module>,无 path hack)
├── config.py            # 唯一配置入口:DB/LLM/LAS、衰减参数、栏目字典(LIVE/DIGEST_TAG_COLUMNS + REPORT_NAV)、路径
│                        #   (load_dotenv(override=True);llm_settings() 调用时叠加 data/llm_config.json 覆盖)
├── web/                 # Flask 应用层(app.py 仅 7 行入口)
│   ├── __init__.py      #   create_app 工厂 + get_db/close_db + 5 过滤器与 10 蓝图注册;ROOT 锚定仓库根
│   ├── helpers.py       #   模板过滤器 days_ago/heat/seg_label/event_badge/dt_short(注册名不变)
│   ├── api.py           #   /api/nlq、/api/ask 蓝图
│   └── views/           #   9 页面蓝图:chains(/ /chain) themes(/theme /timeline /mindmap) stocks(/stock)
│                        #   daily(/daily) reports(/reports /report /ratings) brokers ontology(含 Playground
│                        #   镜像与 /ontology.rdf) settings(/settings/llm 图片解析 LLM测试) graph(/graph + 5 API)
├── kg/                  # 知识图谱与本体域
│   ├── ontology.py      #   本体 schema 单一事实源:build_schema() 供 /ontology 页、RDF 导出
│   │                    #   与 Playground 镜像 catalogue 三方共用;实体/关系显示名为中文
│   ├── rdf_export.py    #   Playground 兼容 RDF/XML + metadata.json 导出
│   ├── kg_schema.py     #   图谱存储层(graph.db 三元组+mention+90天半衰期;移植 2_xuangubao v0.5.0)
│   ├── kg_query.py      #   图谱查询层(主题群/行业子图/公司反查/搜索;时间窗权重)
│   ├── kg_cluster.py    #   Louvain 主题群聚类(networkx;cluster 表缓存)
│   └── kg_extractor.py  #   图谱 LLM 抽取(三元组+防幻觉校验;LLM 不可用规则降级)
├── llm/                 # LLM 与问答域
│   ├── llm_chain.py     #   LLM 客户端:call_llm 调用时读 llm_settings()(.env < data/llm_config.json 覆盖),链映射/问答/观点升级共用
│   ├── qa.py            #   NL2Data 问答(LLM 版):链内/全局上下文构建 → LLM → 实体链接
│   ├── nlq.py           #   规则式自然语言查询(无 LLM):时间窗/活跃天数/链/题材/日期意图解析
│   └── viewpoint.py     #   推荐观点规则引擎(信号句+关键词字典);LLM 版见 scripts/kg
├── pipeline/            # 数据管道域(MySQL→SQLite)
│   ├── sync.py          #   同步编排:环境检查/备份/临时库/数据校验/回退/sync_log(详见 docs/sync.md)
│   ├── etl.py           #   MySQL→SQLite 搬运:全量/增量共用逐行提取与聚合(编排见 sync.py)
│   ├── extractors.py    #   纯函数正则提取器(大涨题材段/研报来源块/图片),可单测
│   └── image_parser.py  #   LAS 解析:单张异步 + 批量队列(65s/张节流)+ 结果缓存 + 题材回填
└── content/             # 内容生成域(纯 SQLite)
    ├── trends.py        #   时间窗统计与查询辅助:cnt_5d..30d / theme_daily / 活跃天数
    │                    #   (active_themes/chain_active)/ 活跃个股(active_stocks,题材∩窗口活跃)
    │                    #   / 题材↔个股关联图(stock_theme_graph)/ 推荐概述(reco_overview)
    └── daily.py         #   每日简报与当日脑图载荷(观点单元卡流数据源)

scripts/                 # 命令行入口(thin wrapper 五分类;新环境先 pip install -e .)
├── sync/                #   sync_data(增量/全量入口,--check/--log)· build_wiki(全量别名)
│                        #   · refresh_trends(时间窗重算,无需 MySQL)· refresh_daily(观点单元回填)
│                        #   · parse_queue(图片批量解析队列,默认 400 张)
├── build/               #   build_static_site(静态站 → data/output/site/,含栏目 hub + 15 子页)
│                        #   · build_playground_catalogue(镜像 catalogue 重建)· localize_playground(汉化+问答补丁)
├── kg/                  #   build_graph(图谱构建 --stats/--since/--force)· kg_recluster(重算主题群)
│                        #   · gen_chain_map(链映射 --min-count/--batch)· export_ontology · extract_viewpoints_llm
├── deploy/              #   deploy_site(本地手动发布 Cloudflare Pages;线上默认走 GitHub Actions)
└── ops/                 #   run_tests(242 项全功能测试)· mcp_server(MCP stdio 4 工具 + --cli)
                         #   · install_skill(skills → ~/.zcode/skills 绝对路径版)· git_slim_db(db 入库瘦身 filter)

app.py                   # Flask 入口(7 行):from src.web import create_app → 127.0.0.1:5010
templates/ static/       # Jinja2 模板(Bootstrap 5 + Cytoscape 本地 vendor)+ 自定义样式
skills/                  # 对外 skill 定义(xgb-wiki / xgb-sync,查询语法/口径/红线)
.github/workflows/       # deploy-site.yml:push master → 测试+构建+Cloudflare Pages 部署
data/                    # SQLite 库 + 三个开放字典 + chain_map + 导出产物(playground/;site/ 为构建产物不入库)

依赖方向:scripts → src,app.py → src.web;包间 web → {kg,llm,content} → {pipeline, config};config 不依赖任何模块。extractors.py 不依赖数据库(纯函数),ontology.py 只读字典 JSON——保证 schema 可脱离数据库渲染。

4. Web 路由一览

路由 模板 职责
/ index.html 产业链总览矩阵(19链 + 未定位题材)
/daily daily.html 每日简报:当日观点单元卡流(聚合篇分组+默认展开),?day= 选日;过滤(类型/题材/仅核心)与关注列表/已读标记由 static/js/daily.js 前端执行(URL 持久化;静态站同款 JS 渲染)
/timeline timeline.html 每日题材:页面级时间周期(1/3/5/10/20日,未选隐藏活跃统计)+ 推荐概述 + 日期热力条 + 单日明细(活跃天数列)+ 题材↔个股关联图(Cytoscape,题材节点唯一)+ 活跃题材/产业链侧栏;?day= 选日、?sw= 选周期
/chain/<id> chain.html 图形视图(Cytoscape:链→环节→题材→核心个股四层,热度着色,PNG导出)+ 卡片视图 + 链内 AI 问答框
/theme/<pid> theme.html 题材核心页:链位置 + 时间窗徽标(5/10/20/30日 + 近5日活跃)+ 个股热度表 + 推荐时间线 + 图片证据(LAS 解析)
/stock/<code> stock.html 个股:题材 + 推荐时间线 + 评级事件
/ratings ratings.html 评级事件列表(eventType 筛选)
/graph graph.html 知识图谱(移植 2_xuangubao v0.5.0):主题群→行业→环节群→公司三级钻取(ECharts),data/graph.db 独立库
/graph/api/* — clusters/cluster/industry/company/search(页面内部接口;静态站 KG_EMBED 内嵌路由)
/reports reports.html 研报栏目(2026-09 吸收自 2_xuangubao):3 组 15 栏目导航,tag 经 report_tag 全量映射
/reports/<live\|digest>/<tag_id> report_list.html 栏目列表:日期范围筛选 + 已读 localStorage + 只看未读
/brokers、/broker/<bid> brokers/broker.html 券商被引用与评级事件(导航已移除,保留深链)
/report/<live\|digest>/<id> report.html 原文渲染 + 实体标注 + 配图(可触发 AI 解析)
/settings/llm settings_llm.html LLM 配置页(本地 Flask 专用):生效配置展示/覆盖保存(data/llm_config.json)/连通测试
/ontology ontology.html schema 展示 + embed widget(RDF 走 /ontology.rdf 同源加载)
/Ontology-Playground/* (静态镜像) 本地镜像完整应用(已汉化),注入深链引导 + NL 查询接 AI 后端
GET /api/nlq — 规则式自然语言查询(nlq.py,无 LLM):时间窗/活跃天数/链/题材/日期,静态站前端与 MCP 同口径
POST /api/ask — AI 问答(qa.py,模型/端点经 /settings/llm 配置):链内(chain 参数)/全局,Playground NL 与链页问答框共用
POST /api/llm/test — LLM 连通性测试(最小请求,返回延迟/回复/错误)
POST /image/<id>/parse — 按需图片解析(异步提交,前端轮询)

5. 技术选型与理由

选型 理由
SQLite 单文件 实例数据随 git 仓库管理、零部署;内网 MySQL 不可达时 Wiki 仍完整可用
Flask + 服务端渲染 页面少、交互轻,无需前后端分离;Bootstrap 5 走 CDN 免构建
规则引擎优先(观点/评级) 正则可解释、零成本、可审计;LLM 仅用于批量归纳型任务(链映射)
开放字典(JSON 注册表) 类型扩展零迁移;_pending 待审区保证脏数据不丢失
Playground 本地镜像 内网无外网依赖;汉化后嵌入自家 Web,与 fork Pages 双形态并存
全量登记 + 选择性解析(图片) LAS 1 QPM + 计费硬约束下的必然取舍

6. 部署形态

双形态:本机 Flask(实例数据全功能)+ 公网静态研报站(CI 自动发布)。

  • 本机:python app.py 监听 127.0.0.1:5010,数据与代码同仓库;LLM 问答、图片 AI 解析等需后端的能力仅此形态可用
  • 公网静态站:https://xgb-wiki-site.pages.dev/ (Cloudflare Pages,大陆直连)。push master 触发 .github/workflows/deploy-site.yml(全功能测试 → build_static_site → wrangler 部署),data/output/site/ 不入库由构建生成;本地立即发布用 scripts/deploy/deploy_site.py。含近90天研报正文,对外分享应 --no-content 构建
  • 对外查询能力:scripts/ops/mcp_server.py(MCP stdio 4 工具 + --cli)与 skills/xgb-wiki(install_skill.py 装到 ~/.zcode/skills/)供其他智能体/本机 agent 查询题材数据,无需 LLM key
  • WeKnora 后台核心知识库(7.weknora 部署实例,API 18080 / UI 18081):scripts/sync/push_to_weknora.py 已将 2025-01-01 以来 4844 篇研报(篇级 Markdown + 观点内嵌 + 月份标签,推送进度标记幂等,数据至 2026-09-30)推入其混合检索库;后续按 融合方案 v0.2 的 S0–S4 路线将 RAG 问答(现 /api/ask)与图谱浏览(现 /graph)迁往 WeKnora,本站收敛为精确结构化查询

约束与演进:

  • 仓库 private / 站点公开:GitHub 仓库私有(含付费正文),CI 经 CF token 部署不受影响;公网只有 pages.dev 产物(见 publishing.md §0 可见性矩阵与收紧路径)
  • 静态站为快照(构建时的 SQLite 数据);全量 ETL 仍需内网 MySQL,手动重跑(幂等);时间窗可脱离内网用 refresh_trends.py 重算
  • data/xgb_wiki.db 随仓库增长(当前 7797 篇/12746 图规模尚可),显著增大时再评估 Git LFS 或发布产物化