Architecture Specification

Kuaixun 快讯系统架构规范

文本流处理架构 · 事件驱动管道 · AI 增强管线 · 数据管道同级规范

2026-08-09 · v1.0 · 基于当前架构深度分析

一、系统概览

1.1 快讯 vs 数据管道:本质区别

维度数据管道(findatahub-core)快讯系统(kuaixun-service)
数据类型结构化数值(OHLCV / 财务指标)非结构化文本(标题 + 内容)
数据量14.7M 行 / 天增量实时流 / 每次采集数百条
处理模式批量 Pipeline(采集后整批处理)实时事件驱动(30 秒循环 + WebSocket 推送)
采集方式API 拉取(TuShare / AKShare HTTP)网页爬虫(12 源 asyncio 并发)
质量保障双源交叉验证(数值对比)去重引擎(文本指纹 + 语义)
AI 增强无(纯统计)翻译 → 评分 → 打标签 → 摘要 → 内容增强
消费方式SDK → API → MCPWebSocket 实时推送 + 6 渠道通知
关键结论:快讯系统是 文本流处理系统,不是批量数据管道。它的架构风格应该是 事件驱动管道(Event-Driven Pipeline),而非 Medallion 三层。但两者共享相同的 分层原则(采集层 → 处理层 → 消费层)和 Clean Architecture 依赖方向。

二、当前架构深度分析

2.1 模块全景

kuaixun-service/
├── app/                       # FastAPI 后端(7 路由 + DAL)
│   ├── main.py                # 入口,端口 8100
│   ├── dal.py                 # 数据访问层(571 行 ⚠ 过大)
│   ├── database.py            # SQLAlchemy SessionLocal
│   ├── dependencies.py        # 鉴权 + WebSocket 管理器
│   └── routers/               # 6 个路由模块
│       ├── public.py          # /api/v1/news/live | summary | heat | tags
│       ├── external.py        # /api/v1/news | /search(需 X-API-Key)
│       ├── internal.py        # POST /batch | /score | /push
│       ├── admin.py           # API Key 管理
│       ├── collector.py       # 采集器 start/stop/restart
│       └── websocket.py       # ws://.../live 实时推送
├── common/                    # 公共基础设施
│   ├── config.py              # load_env()
│   └── security.py            # CORS + 限流 + 安全头
├── extend/                    # 扩展模块(核心管线)
│   ├── pipeline.py            # Pipeline 主循环(194 行)
│   ├── fetchers/              # 12 个数据源采集器
│   │   └── manager.py         # FetcherManager 调度器
│   ├── dedup/                 # 三层去重引擎
│   ├── notifier/              # 6 个推送渠道
│   ├── translator.py          # AI 翻译
│   ├── scorer.py              # AI 评分 0-5
│   ├── tagger.py              # AI 打标签
│   ├── summarizer.py          # AI 摘要
│   ├── content_enricher.py    # 原文抓取 + 背景搜索
│   └── bridge.py              # MySQL → TrendRadar 桥
└── tests/                     # 10 个测试文件

2.2 发现的关键问题

问题严重度影响
DedupEngine 未被 Pipeline 使用P0已实现的三层去重完全闲置,只用 DB IN 查重。相似快讯无法去重
ExtendConfig 是死代码P1dataclass 定义但从未实例化,各模块各自 os.getenv
DAL 571 行单文件P1CRUD + 统计 + 标签 + 收藏 + 鉴权全在一个文件
Pipeline 是串行单体循环P1fetch_and_insert 中 8 步全部串行耦合,不是真正的管道
无 pyproject.tomlP1不能 pip install,不能声明依赖
无 src/ 层P1不符合 Python 包规范
2 个 fetcher 未注册P2fastbull/mktnews 有代码但未在 FetcherManager 实例化
缺少 test_pipeline.pyP2核心编排逻辑无单测覆盖

三、架构风格选择:事件驱动管道

3.1 为什么不用 Medallion 三层

快讯系统处理的是实时文本流,不是批量结构化数据。Medallion 三层的 Bronze→Silver→Gold 适合"采集后等一天再清洗",但快讯需要采集后秒级推送。

3.2 事件驱动管道模型

flowchart LR
    subgraph Collect["采集层"]
        F[12 Fetchers] -- async gather --> Q1[(事件队列)]
    end
    subgraph Process["处理层"]
        Q1 --> D[去重
3 层引擎] D --> T[翻译] T --> S[AI 评分] S --> G[打标签] G --> M[AI 摘要] M --> E[内容增强] end subgraph Deliver["消费层"] E --> DB[(MySQL)] E --> WS[WebSocket] E --> PUSH[6 渠道推送] end style Collect fill:#eff6ff,stroke:#2563eb,stroke-width:2px style Process fill:#f5f3ff,stroke:#7c3aed,stroke-width:2px style Deliver fill:#f0fdf4,stroke:#059669,stroke-width:2px
图 1:快讯系统事件驱动管道架构
1

阶段解耦

每阶段独立运行,通过 Queue 通信。单阶段失败不影响其他。翻译慢了不阻塞评分,去重重试不阻塞采集。

2

背压控制

处理层慢于采集层时,Queue 自动堆积。设置 maxsize 限制内存,超出时采集层 async.wait_for 等待。

3

可插拔阶段

新增 AI 处理阶段只需注册到 Pipeline,不改动现有阶段。默认阶段可被跳过(如禁用评分)。

3.3 与数据管道的共性——共享分层原则

虽然处理模型不同,但分层原则完全一致:采集层不关心处理,处理层不关心消费,依赖单向流动。

flowchart LR
    subgraph allow["依赖方向(采集层 → 处理层 → 消费层)"]
        C[采集层
fetchers/] P[处理层
dedup/ + AI 模块] D[消费层
API + WebSocket + Push] end C --> P --> D style allow fill:#f0fdf4,stroke:#059669,stroke-width:2px
图 2:依赖方向(与数据管道规范一致)

四、依赖规则

禁
处理层(dedup/AI 模块)不得 import 采集层(fetchers/)

当前合规:dedup/translator/scorer 等均不依赖 fetchers。

禁
采集层不得 import 处理层

当前合规。

禁
DAL 层不得 import 业务逻辑(pipeline/fetchers)

当前合规:DAL 只有 SQL 查询,无业务逻辑引用。

建议
Pipeline(编排层)允许跨层引用,但应通过 Protocol/接口而非直接 import

当前:pipeline.py 直接 import app.dal / app.database / extend.* 全栈引用。建议:定义 NewsProcessor Protocol,DAL 作为注入的 Repository。

必
所有 Python 包必须有 pyproject.toml + src/ 层

当前违反:kuaixun-service 无 pyproject.toml,无 src/ 层。

五、核心组件设计契约

5.1 Fetcher(采集器)

属性规范
接口契约async fetch() → list[NewsItem],返回标准化字典列表
异常隔离单个 fetcher 失败不影响其他,返回空列表
超时保护asyncio.wait_for 施加超时,FetchManager 统一管理
注册机制FetcherManager 从配置动态加载,不硬编码
标准化输出所有 fetcher 输出统一 NewsItem 字段:source / source_news_id / title / content / url / published_at

5.2 DedupEngine(去重引擎)

属性规范
三层串联L1(精确匹配 source_news_id)→ L2(SimHash 64-bit + Hamming)→ L3(Jaccard 语义)
有状态引擎维护 LRU 缓冲区(deque 10000),自动淘汰旧条目
必须启用Pipeline 中必须调用 DedupEngine.is_duplicate(),不能仅靠 DB IN 查重
独立单测test_dedup.py 覆盖三层算法及边界情况
阈值可配置Hamming < 12 / Jaccard > 0.6,从统一配置读取

5.3 AI 增强模块

模块接口开关
Translatortranslate_items(items) → items中文字符 < 30% 触发
Scorerscore_news(title, content) → int 0-5AI_SCORE_ENABLED
Taggertag_item(title, content, full_text, context) → list[str]AI_TAGGING_ENABLED
Summarizersummarize(title, content) → str ≤100字AI_SUMMARY_ENABLED
ContentEnricherenrich_item(item) → item默认启用,URL 为空时跳过

5.4 DAL(数据访问层)

P1 重构:571 行单文件必须按领域拆分为:dal/news.py(CRUD)+ dal/stats.py(统计)+ dal/tags.py(标签)+ dal/favorites.py(收藏)。每模块 < 150 行。

5.5 Notifier(推送渠道)

插件式架构已很合理(Base → 6 实现 + Manager),无需变动。新增渠道只需继承 PushSender。

六、数据流设计

sequenceDiagram
    participant Timer as Timer(30s)
    participant FM as FetcherManager
    participant Q as asyncio.Queue
    participant Pipe as Pipeline
    participant Dedup as DedupEngine
    participant AI as AI Modules
    participant DB as MySQL
    participant WS as WebSocket

    Timer->>FM: 触发采集
    FM->>FM: asyncio.gather(12 fetchers)
    FM->>Q: 放入原始 items
    
    loop Pipeline 循环
        Q->>Pipe: 取出 items
        Pipe->>Dedup: is_duplicate(item)
        Dedup-->>Pipe: True/False
        Pipe->>AI: translate → score → tag → summarize → enrich
        Pipe->>DB: batch_insert
        Pipe->>WS: broadcast(items)
    end
  
图 3:端到端数据流

6.1 阶段解耦改进

当前 Pipeline.fetch_and_insert 中 8 步全部在一个 async 方法中串行调用。改进为 Queue 驱动的独立阶段:

# extend/pipeline.py — 改进后的结构
class Pipeline:
    def __init__(self):
        self.input_queue = asyncio.Queue(maxsize=1000)
        self._stages = [
            Stage("dedup", self._run_dedup, input_queue=self.input_queue),
            Stage("translate", self._run_translate),
            Stage("score", self._run_score),
            Stage("store", self._run_store),
        ]
    
    async def run_forever(self, interval=30):
        """采集 → 放入队列,各 Stage 独立消费"""
        asyncio.create_task(self._run_collector(interval))
        await asyncio.gather(*(s.run() for s in self._stages))

七、去重策略三层设计

7.1 当前状态

DedupEngine 已完整实现但 Pipeline 中未使用。当前的去重仅靠 check_existing_ids(DB IN 查 source_news_id),相当于只做了 L1。L2(SimHash)和 L3(Jaccard 语义匹配)从未被调用。

7.2 启用方案

在 Pipeline 的 fetch_and_insert 中,将 check_existing_ids 替换为 DedupEngine.is_duplicate():

# 改进前(仅 L1 DB 查重)
existing = dal.check_existing_ids(table, ids)
new_items = [i for i in items if i["source_news_id"] not in existing]

# 改进后(三层查重)
dedup = DedupEngine()
new_items = []
for item in items:
    if not dedup.is_duplicate(item["source_code"], item["source_news_id"], item["title"]):
        new_items.append(item)

7.3 去重配置

层算法阈值LRU 大小
L1精确匹配 (source_code, source_news_id)100%10000
L2SimHash 64-bit + 256 桶分桶索引 + Hamming距离 < 12桶内 ≤ 300
L3Jaccard 加权(单字 0.4 + 双字 0.6)+ 长度快速剪枝> 0.60—

七-B、news_unified 整合库设计

核心设计:借鉴数据管道的 Medallion 三层架构,快讯系统增加 news_unified 作为统一 Silver 层。12 个源的数据经过四层去重后,只写入一张干净的整合表。所有外部消费者(API / WebSocket / 推送)只从 news_unified 读取。

7B.1 架构对照

数据管道快讯系统说明
tushare_data / akshare_data12 分表(news_cls / news_sina / ...)🥉 Bronze:原始数据,保留来源标签
fin_data_cleannews_unified🥈 Silver:去重后统一表,所有消费唯一入口
SDK / API / MCPAPI / WebSocket / 推送🥇 Gold:消费层只读 news_unified
双源交叉验证(数值对比)四层去重(文本指纹 + 语义)质量保障方式不同,但"写入整合库"模式相同
差异写入 _data_issues重复时合并 source_list保留溯源信息

7B.2 数据流

flowchart TB
    subgraph Bronze["🥉 Bronze: 12 分表"]
        direction LR
        CLS[财联社] --- SINA[新浪] --- WS[华尔街见闻] --- EM[东方财富]
        J10[金十] --- GLH[格隆汇] --- K36[36氪] --- GN[GNews]
    end
    subgraph Worker["四层去重 Worker"]
        L1[L1: content_hash 精确]
        L2[L2: SimHash 指纹]
        L3[L3: Jaccard 语义]
        L4[L4: DB 查重兜底]
    end
    subgraph Silver["🥈 Silver: news_unified"]
        NU[(news_unified)]
        NU_DETAIL["source_list: JSON
同一事件多源合并
primary_source + primary_url"] end subgraph Gold["🥇 Gold: 消费层"] API[REST API] WS[WebSocket] PUSH[6渠道推送] end Bronze --> Worker --> NU --> API & WS & PUSH style Bronze fill:#eff6ff,stroke:#2563eb,stroke-width:2px style Silver fill:#f5f3ff,stroke:#7c3aed,stroke-width:2px style Gold fill:#f0fdf4,stroke:#059669,stroke-width:2px
图 4:快讯系统 Medallion 三层架构

7B.3 news_unified 表结构

CREATE TABLE news_unified (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    content_hash CHAR(32) NOT NULL,          -- L1 精确匹配键 MD5(title + 前200字)
    simhash BIGINT UNSIGNED DEFAULT 0,       -- L2 SimHash 64-bit 指纹
    title VARCHAR(512) NOT NULL,
    content TEXT,
    summary VARCHAR(256),                     -- AI 摘要(选择最高质量来源)
    source_list JSON NOT NULL,                -- ["cls","sina","wallstreetcn"] 多源合并
    source_count INT DEFAULT 1,               -- 来源数量(越多越重要)
    primary_source VARCHAR(32),               -- 主来源(最先采集到的)
    primary_url VARCHAR(1024),                -- 主来源原文链接
    tags JSON,                                -- AI 标签(跨源合并去重)
    importance INT DEFAULT 0,                 -- AI 评分 0-5(取最高分)
    published_at DATETIME,
    first_seen_at DATETIME,                   -- 首次采集时间
    last_seen_at DATETIME,                    -- 最近一次采集时间
    UNIQUE KEY uk_hash (content_hash),
    KEY idx_simhash (simhash),
    KEY idx_published (published_at),
    KEY idx_importance (importance)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

7B.4 四层去重算法

层算法速度准确度命中后动作
L1MD5(title + content[:200]) → content_hash 精确匹配⚡ 微秒100%追加 source 到已有记录
L2SimHash 64-bit + 256 桶索引 + Hamming 距离 < 12⚡ 毫秒~85%合并 source_list,合并 tags
L3Jaccard 加权(单字 0.4 + 双字 0.6)+ 长度剪枝 > 0.60🐢 10ms~70%合并,记录日志
L4DB SELECT WHERE source_news_id IN (...)⚡ 毫秒100%兜底保护

7B.5 窗口策略

去重时只对比 最近 24 小时的 news_unified 记录。3 天前的事件不会和今天重复,全量对比无意义且浪费性能。

7B.6 新增模块

kuaixun-service/
├── src/kuaixun_service/
│   ├── dedup.py              # 四层去重引擎(升级 DedupEngine)
│   └── unified_writer.py     # 新增:去重 → 写入 news_unified
└── sql/
    └── news_unified.sql      # 建表 DDL

八、AI 增强模块规范

8.1 统一配置管理

消除分散 os.getenv:所有 AI 模块的配置(provider / model / api_url / enabled)统一从 extend/config.py 的 AIConfig dataclass 读取。每个模块从 AIConfig 获取,不各自 os.getenv。
# extend/config.py — 统一配置
@dataclass
class AIConfig:
    provider: str = os.getenv("AI_PROVIDER", "ollama")
    model: str = os.getenv("AI_MODEL", "qwen2.5:7b")
    api_url: str = os.getenv("AI_API_URL", "http://localhost:11434")
    score_enabled: bool = os.getenv("AI_SCORE_ENABLED", "true") == "true"
    tag_enabled: bool = os.getenv("AI_TAGGING_ENABLED", "true") == "true"
    summary_enabled: bool = os.getenv("AI_SUMMARY_ENABLED", "true") == "true"

ai_config = AIConfig()  # 单例

九、包结构与标准化

9.1 目标结构

kuaixun-service/
├── pyproject.toml              # 新增:依赖声明 + build
├── src/kuaixun_service/        # 新增:src/ 层
│   ├── __init__.py
│   ├── main.py                 # ← app/main.py
│   ├── dal/
│   │   ├── __init__.py
│   │   ├── news.py             # CRUD(← dal.py 拆分)
│   │   ├── stats.py            # 统计
│   │   ├── tags.py             # 标签管理
│   │   └── favorites.py        # 收藏
│   ├── pipeline.py             # ← extend/pipeline.py
│   ├── dedup.py                # ← extend/dedup/__init__.py
│   ├── fetchers/
│   │   └── manager.py          # ← extend/fetchers/manager.py
│   ├── ai/                     # AI 增强模块
│   │   ├── translator.py
│   │   ├── scorer.py
│   │   ├── tagger.py
│   │   ├── summarizer.py
│   │   └── enricher.py
│   ├── notifier/
│   │   ├── base.py
│   │   ├── manager.py
│   │   └── bark/feishu/...py
│   └── config.py               # 统一配置(合并 extend/config + common/config)
├── app/                        # FastAPI 保持独立(框架层)
│   └── routers/                # 路由不变
└── tests/                      # 测试目录
    ├── test_pipeline.py        # 新增
    └── test_fetchers.py        # 新增

9.2 pyproject.toml 模板

[project]
name = "kuaixun-service"
version = "1.0.0"
requires-python = ">=3.10"
dependencies = [
    "fastapi>=0.115", "uvicorn>=0.34", "sqlalchemy>=2.0",
    "pymysql>=1.0", "httpx>=0.28", "jieba>=0.42",
    "websockets>=12", "pydantic>=2.0",
]

[build-system]
requires = ["setuptools>=75"]
build-backend = "setuptools.build_meta"

[tool.setuptools.packages.find]
where = ["src"]

十、改造路线图

阶段内容工作量优先级
S1补 pyproject.toml + src/ 层 + 创建 kuaixun_service 包30 分钟P0
S2启用 DedupEngine 在 Pipeline 中的调用30 分钟P0
S3统一配置管理(AIConfig 单例 + 消除分散 os.getenv)1 小时P1
S4DAL 拆分(571 行 → 4 文件每 < 150 行)1.5 小时P1
S5Pipeline 解耦为事件驱动阶段(Queue + Stage)2 小时P1
S6补测试(test_pipeline.py + test_dedup_integration.py)1 小时P2
S7注册 fastbull/mktnews fetcher 到 FetcherManager15 分钟P2

总结:快讯系统遵循与数据管道相同的分层原则和依赖方向,但使用事件驱动管道而非 Medallion 三层来处理文本流。改造重点:启用闲置的去重引擎、标准化包结构、统一配置管理、解耦 Pipeline 阶段。共 7 步,约 6.5 小时。完成后快讯系统将达到与数据管道同等的架构规范化水平。