# 流水线详解 本文档描述 M1→M9 每一步的输入、输出、配置与增量机制。 ## M1 新闻抓取 - 模块:`crawler/` - 输入:`configs/sources.yaml` 中的新闻源配置 - 输出:`data/raw/{source_id}/{YYYYMMDD}/` - `index.jsonl`:本次/当日抓取索引,包含 `url_hash`、标题、URL、摘要、时间 - `{url_hash}.html` / `{url_hash}.md`:原始网页或 Markdown - 策略: 1. 有 `rss_url` 的源先走 RSS/Atom/Google News RSS; 2. RSS 失败或返回空时,根据 `anti_bot_mode` 走 stealth/headful Web; 3. 单源串行,`index.jsonl` 按 `url_hash` 追加去重。 - 常用命令: - `bash scripts/domestic_crawl_8g.sh [source_id]` - `uv run en-news crawl --source cnbc` ## M2 正文提取 - 模块:`extractor/` - 输入:`data/raw/{source_id}/{date}/index.jsonl` - 输出:`data/processed/{source_id}/{date}/{url_hash}.json` - `ProcessedArticle` 包含标题、正文 `content`、词数、提取器名、发布时间等。 - 提取器:`trafilatura`,失败时回退 Markdown。 - 增量:已存在同名 `{url_hash}.json` 则跳过。 ```bash uv run en-news extract # 或只处理一个源 uv run en-news extract --source cnbc ``` ## M3 三层去重 - 模块:`dedup/` - 输入:`data/processed/**/{date}/*.json` - 输出: - `data/deduped/{date}/uniques/{url_hash}.json`(唯一篇) - `data/dedup/fingerprints.sqlite3`(指纹库) - `data/deduped/{date}/index.json`(去重统计) - 逻辑: 1. URL 完全一致 → 重复 2. 正文 hash 一致 → 重复 3. SimHash 汉明距离 ≤ 阈值 → 模糊重复 - 跨源合并:重复篇的来源 ID 会追加到保留唯一篇的 `source_ids`,日报可展示多来源。 - 合并后会同步更新已生成的 `events` 与 Qdrant payload;历史数据可执行: ```bash uv run en-news sync-sources ``` ```bash uv run en-news dedup ``` ## M4 翻译 + 投资事件抽取 - 模块:`llm/` - 输入:`data/deduped/{date}/uniques/*.json` - 输出:`data/events/{date}/{url_hash}.json` - `EnTranslatedArticle`:英文原字段 + `title_zh` / `content_zh` / `events` / `source_ids` - 事件结构:`event_type` / `stock_codes` / `sentiment` / `importance` / `summary_zh` - LLM:默认 DeepSeek `deepseek-v4-flash`,场景 `translation` - 并发:默认 3 线程,来自 `system.yaml llm.concurrency` - 增量:`events/{date}/{url_hash}.json` 存在则跳过。 ```bash uv run en-news translate ``` ## M5 向量生成 - 模块:`embedding/` - 输入:`data/events/{date}/*.json` - 输出:`data/embeddings/{date}/{url_hash}.json` - 包含 `url_hash`、`source_id`、`vector` 等 - `data/embeddings/{date}/index.json` 记录该批统计 - 向量:DashScope `text-embedding-v3`,默认 1024 维、batch_size=10 - 增量:已存在向量文件则跳过。 ```bash uv run en-news embed ``` ## M6 Qdrant 入库与检索 - 模块:`vectorstore/` - 输入:`data/embeddings/{date}/` 与 `data/events/{date}/` - 输出:Qdrant collection `en_finance_news` - collection 大小:1024 维,余弦距离 - point ID:`url_hash` 通过 UUIDv5 转换,确定性幂等 - payload:标题、双语标题、事件、来源、时间、正文预览等 - 支持模式: - 本地文件模式(默认):`data/qdrant_storage` - 远程 HTTP 模式:`.env` 中配置非本地的 `QDRANT_URL` - 命令: ```bash # 入库 uv run en-news index # 重建 collection(会清空) uv run en-news index --recreate # 重建并全量回灌所有历史向量 uv run en-news index --recreate --all # 指定日期入库 uv run en-news index --date 20260801 # 检索 uv run en-news search "苹果 财报" ``` ## M7 全链路管道编排 - 模块:`scheduler/pipeline.py` - 串行执行:`extract → dedup → translate → embed → index → report` - 每步失败不阻断后续,最终返回各步骤成功/失败统计。 - CLI:`uv run en-news pipeline` / `--skip-report` - Shell:`bash scripts/pipeline.sh [--resume]` ## M8 MCP 服务 - 模块:`mcp_server/server.py` - 启动:`uv run en-news mcp-server` - 工具: - `search_news`:语义搜索 - `search_by_stock`:按美股代码搜索 - `search_by_sentiment`:按情绪过滤搜索 - `get_today_events`:当日重要事件 - `get_stats`:系统统计 - 用途:供 Claude Code / Cherry Studio 等 MCP 客户端做深度研究。 ## M9 日报结构化入库 - 模块:`scheduler/reporter.py` + `report_db/` - 时间窗口:最近 25 小时 - 输出:MySQL `myquant` 库 - `news_report`:`report_type='intl'`、`report_date`、`generated_at`、`ai_summary`、`stats` - `news_event`:`section='intl'`、Top 事件明细 - 幂等:`(report_date, report_type='intl', file_name='')` 唯一键覆盖 - 命令:`uv run en-news report` ## 数据目录速查 ```text data/ ├── raw/{source_id}/{YYYYMMDD}/ M1 原始 ├── processed/{source_id}/{YYYYMMDD}/ M2 正文 ├── dedup/fingerprints.sqlite3 M3 指纹库 ├── deduped/{YYYYMMDD}/uniques/ M3 去重后唯一篇 ├── events/{YYYYMMDD}/ M4 翻译+事件 ├── embeddings/{YYYYMMDD}/ M5 向量 ├── qdrant_storage/ M6 本地 Qdrant ├── run_state/ 步骤级 --resume 状态 └── reports/ 历史 HTML 日报(M9 已不再产出) ``` ## 失败恢复建议 1. 如果某个 Python 步骤失败,直接重跑同一命令即可,已完成的文件会自动跳过。 2. 如果 Shell 脚本中断,使用 `bash scripts/domestic_full.sh --resume` 或 `bash scripts/pipeline.sh --resume`。 3. 日报失败通常与 MySQL 连接/凭据有关,可先单独执行 `uv run en-news report` 查看日志。 4. 若 Qdrant 本地文件损坏,可考虑备份后删除 `data/qdrant_storage` 并重新 `uv run en-news index`(需重新入库全部向量)。