初始化

This commit is contained in:
2026-07-18 16:13:52 +08:00
parent c0070f0a5c
commit fe8b417ab6
75 changed files with 12898 additions and 1 deletions
+672
View File
@@ -0,0 +1,672 @@
# 国际财经 Deep Research 平台 — 使用手册
> 版本:v1.0
> 最后更新:2026-06-21
> 项目路径:国内 `/home/pi/intlnews` / 海外 `/opt/intlgrab`
---
## 目录
1. [项目概述](#1-项目概述)
2. [部署拓扑](#2-部署拓扑)
3. [环境配置](#3-环境配置)
4. [CLI 命令参考](#4-cli-命令参考)
5. [M1 — 新闻抓取](#5-m1--新闻抓取)
6. [M2 — 正文提取](#6-m2--正文提取)
7. [M3 — 三层去重](#7-m3--三层去重)
8. [M4 — 翻译 + 事件抽取](#8-m4--翻译--事件抽取)
9. [M5 — 向量生成](#9-m5--向量生成)
10. [M6 — Qdrant 入库与检索](#10-m6--qdrant-入库与检索)
11. [M7 — 全链路管道 + 日报](#11-m7--全链路管道--日报)
12. [M8 — MCP 服务](#12-m8--mcp-服务)
13. [数据目录结构](#13-数据目录结构)
14. [定时任务](#14-定时任务)
15. [常见问题](#15-常见问题)
---
## 1. 项目概述
本项目构建面向**国际英文财经新闻**的私有化 Deep Research 平台。
核心能力:
- 英文财经新闻抓取(Crawl4AI,12 个源)
- 正文提取(trafilatura
- 全文英译中(DeepSeek LLM
- 投资事件抽取(美股代码识别 + 情绪判断 + 重要度评分)
- 双语向量知识库(Qdrant,1024 维)
- 语义检索(中文自然语言)
- MCP 服务(Claude Code / Cherry Studio Agent 深度研究)
- 每日 AI 摘要日报(HTML
**本项目不是**:交易系统 / 股票预测系统 / 投资顾问系统。
---
## 2. 部署拓扑
```
┌──────────────────────────────────────────────────┐
│ Overseas Server (海外) │
│ M1 Crawl4AI 抓取 → data/raw/ │
│ 每天 4 次打包 → rsync 推送 │
│ SSH: <海外服务器> │
│ 路径: /opt/intlgrab │
└────────────────────┬─────────────────────────────┘
│ rsync
┌──────────────────────────────────────────────────┐
│ Domestic Server (国内) │
│ M2 正文提取 → M3 去重 → M4 翻译+事件 │
│ → M5 向量生成 → M6 Qdrant 入库 │
│ → M7 调度 + 日报 → M8 MCP 服务 │
│ SSH: <国内服务器> │
│ 路径: /home/pi/intlnews │
└──────────────────────────────────────────────────┘
```
---
## 3. 环境配置
### 3.1 依赖安装
```bash
cd /home/pi/intlnews
uv sync
```
### 3.2 配置文件
| 文件 | 用途 | 示例 |
|------|------|------|
| `.env` | API Key / URL(不入 Git | `DEEPSEEK_API_KEY=sk-xxx` |
| `configs/system.yaml` | 功能参数(模型、阈值、超时) | `llm.provider: deepseek` |
| `configs/sources.yaml` | 新闻源定义 | 12 个英文财经源 |
### 3.3 必需环境变量(`.env`
```bash
# DeepSeekM4 翻译+事件抽取)
DEEPSEEK_API_KEY=sk-your-key
DEEPSEEK_BASE_URL=https://api.deepseek.com
# Qwen(备选 LLM
QWEN_API_KEY=sk-your-key
QWEN_BASE_URL=https://dashscope.aliyuncs.com/compatible-mode/v1
# DashScopeM5 向量生成)
DASHSCOPE_API_KEY=sk-your-key
# Qdrant(留空使用本地文件模式)
QDRANT_URL=http://localhost:6333
QDRANT_API_KEY=
```
### 3.4 关键配置项(`configs/system.yaml`
```yaml
crawler:
max_memory_mb: 1800 # 串行抓取内存上限
dedup:
hamming_distance_threshold: 3 # SimHash 汉明距离阈值
simhash_window_days: 30 # 时间窗口
llm:
provider: "deepseek"
deepseek_model: "deepseek-v4-flash"
concurrency: 3 # LLM 并发数
embedding:
provider: "dashscope"
dashscope_model: "text-embedding-v3"
dimension: 1024
qdrant:
collection: "en_finance_news"
schedule:
day_cutoff_hour: 6 # 新闻日切分点(06:00
```
---
## 4. CLI 命令参考
所有命令通过 `uv run en-news` 执行:
| 命令 | Milestone | 功能 |
|------|-----------|------|
| `crawl` | M1 | 抓取英文财经新闻 |
| `extract` | M2 | 正文提取 |
| `dedup` | M3 | 三层去重 |
| `translate` | M4 | 翻译 + 事件抽取 |
| `embed` | M5 | 向量生成 |
| `index` | M6 | Qdrant 入库 |
| `search <query>` | M6 | 语义检索 |
| `pipeline` | M7 | 一键全链路 M2→M6 |
| `report` | M7 | 日报生成 |
| `mcp-server` | M8 | 启动 MCP 服务 |
常用选项:
```bash
# 指定源
uv run en-news crawl --source forexlive
uv run en-news extract --source forexlive
# 指定 top_k
uv run en-news search "美联储利率决议" --top-k 5
# 重建 Qdrant collection
uv run en-news index --recreate
# 全链路跳过日报
uv run en-news pipeline --skip-report
```
---
## 5. M1 — 新闻抓取
### 5.1 手动抓取
```bash
# 抓取所有启用的源
uv run en-news crawl
# 只抓取指定源
uv run en-news crawl -s forexlive
```
### 5.2 新闻源列表
| 源 ID | 名称 | 类型 |
|-------|------|------|
| reuters | Reuters | 综合财经 |
| cnbc | CNBC | 市场新闻 |
| marketwatch | MarketWatch | 市场数据 |
| ft | Financial Times | 财经深度 |
| yahoo_finance | Yahoo Finance | 综合 |
| investing | Investing.com | 全球市场 |
| seekingalpha | Seeking Alpha | 投资分析 |
| barrons | Barrons | 市场评论 |
| wsj | WSJ | 综合财经 |
| economist | The Economist | 经济分析 |
| forexlive | ForexLive | 外汇新闻 |
| zerohedge | ZeroHedge | 另类财经 |
### 5.3 反爬策略
部分新闻源设有反爬保护(如 DataDome)。系统支持三种策略,按优先级自动选择:
| 优先级 | 策略 | 配置字段 | 说明 | 适用源 |
|--------|------|---------|------|--------|
| 1 | **RSS 抓取** | `rss_url` | 通过 RSS/Atom Feed 获取文章列表,完全绕过反爬 | MarketWatch ✅ |
| 2 | **Stealth 模式** | `anti_bot_mode: "stealth"` | 隐藏 webdriver 特征(`--disable-blink-features=AutomationControlled`) | Reuters(海外内存不足待验证) |
| 3 | **Headful 模式** | `anti_bot_mode: "headful"` | 非 headless 浏览器,最像真人 | 重度反爬源回退 |
配置示例(`configs/sources.yaml`):
```yaml
- id: "marketwatch"
rss_url: "https://feeds.marketwatch.com/marketwatch/topstories" # RSS 优先
anti_bot_mode: "headful" # RSS 失败时回退
- id: "reuters"
anti_bot_mode: "stealth" # 无 RSS,直接 stealth
```
**已验证**
| 源 | 方式 | 结果 |
|----|------|------|
| MarketWatch | RSS | ✅ 10/10 |
| WSJ | RSS | ✅ 20/20 |
| ForexLive | 标准 headless | ✅ 17/17 |
| ZeroHedge | 标准 + URL 过滤 | ✅ 15/15 |
| Barron's | RSS (Dow Jones) | ✅ 10/10 |
| Reuters | stealth | ⚠️ DataDome |
| SeekingAlpha | stealth | ⚠️ PerimeterX |
### 5.4 海外定时抓取
```cron
# crontab<海外服务器>)— 每天 4 次
# 时序: 抓取(60min) → 打包(5min) → 10min后国内拉取
0 6 * * * cd /opt/intlgrab && bash scripts/overseas_crawl.sh
5 7 * * * cd /opt/intlgrab && bash scripts/overseas_pack.sh
0 12 * * * cd /opt/intlgrab && bash scripts/overseas_crawl.sh
5 13 * * * cd /opt/intlgrab && bash scripts/overseas_pack.sh
0 18 * * * cd /opt/intlgrab && bash scripts/overseas_crawl.sh
5 19 * * * cd /opt/intlgrab && bash scripts/overseas_pack.sh
0 22 * * * cd /opt/intlgrab && bash scripts/overseas_crawl.sh
5 23 * * * cd /opt/intlgrab && bash scripts/overseas_pack.sh
```
### 5.4 增量抓取机制
抓取采用**两层增量**确保不重复下载和存储:
| 层级 | 位置 | 机制 |
|------|------|------|
| 抓取层 | `_extract_article_urls` | 读取当日 `index.jsonl` 中已抓取的 url_hash,跳过已存在的 URL,不重复下载 |
| 存储层 | `write_index_jsonl` | 追加写入前再次检查 url_hash,已存在则跳过 |
同一天内多次执行 `crawl`,只有新文章才会被下载和存储。
### 5.5 产物
```
data/raw/{source_id}/{YYYYMMDD}/
├── {url_hash}.html # 原始 HTML
├── {url_hash}.md # Crawl4AI Markdown
└── index.jsonl # 文章索引
```
---
## 6. M2 — 正文提取
### 6.1 执行
```bash
# 提取所有源
uv run en-news extract
# 提取指定源
uv run en-news extract -s forexlive
```
### 6.2 技术方案
- 优先使用 Crawl4AI 输出的 Markdown
- 回退 `trafilatura` 英文正文提取
- 最小正文字数阈值:50 词
### 6.3 产物
```
data/processed/{source_id}/{YYYYMMDD}/
├── {url_hash}.json # ProcessedArticle
└── index.jsonl # 处理索引
```
---
## 7. M3 — 三层去重
### 7.1 执行
```bash
uv run en-news dedup
```
### 7.2 去重逻辑
| 层级 | 方法 | 说明 |
|------|------|------|
| L1 | URL Hash | 完全相同 URL 直接命中 |
| L2 | 内容 Hash | 标准化后 SHA1[:16] 匹配(去标点/空白) |
| L3 | SimHash | 字符 3-gram,汉明距离 ≤ 3,30 天窗口 |
### 7.3 产物
```
data/deduped/{YYYYMMDD}/
├── uniques/{url_hash}.json # 唯一文章
└── index.json # 去重索引
data/dedup/fingerprints.sqlite3 # 指纹库
```
---
## 8. M4 — 翻译 + 事件抽取
### 8.1 执行
```bash
uv run en-news translate
```
### 8.2 技术方案
- **Provider**: DeepSeek v4-flash(默认)/ Qwen 备选
- **单次调用**:翻译 + 事件抽取合并,节省 token
- **并发**3 线程(`system.yaml``llm.concurrency`
- **重试**:3 次指数退避(1s → 2s → 4s)
### 8.3 输出格式
```json
{
"title": "Fed Holds Rates Steady as Markets Rally",
"title_zh": "美联储维持利率不变,市场上涨",
"content_en": "The Federal Reserve held...",
"content_zh": "美联储周三维持利率不变...",
"events": [
{
"event_type": "央行决议",
"stock_codes": [],
"sentiment": "neutral",
"importance": 5,
"summary_zh": "美联储维持利率不变,市场反弹"
}
]
}
```
### 8.4 14 种事件类型
`财报披露` `并购收购` `产品发布` `监管政策` `宏观经济`
`央行决议` `行业动态` `技术突破` `高管变动` `诉讼法律`
`市场异动` `地缘政治` `大宗商品` `外汇波动` `其他`
### 8.5 产物
```
data/events/{YYYYMMDD}/
├── {url_hash}.json # EnTranslatedArticle
└── index.json # 事件索引
```
---
## 9. M5 — 向量生成
### 9.1 执行
```bash
uv run en-news embed
```
### 9.2 技术方案
- **Provider**: DashScope `text-embedding-v3`
- **维度**: 1024
- **嵌入文本**: `标题: {title_zh}` + `事件: [{sentiment}] {event_type} 重要度{n} {summary_zh}` + `正文: {content_zh[:3000]}`
- **截断**: 4000 字符上限
### 9.3 产物
```
data/embeddings/{YYYYMMDD}/
├── {url_hash}.json # EmbeddingResult1024 维)
└── index.json # 向量索引
```
---
## 10. M6 — Qdrant 入库与检索
### 10.1 入库
```bash
# 增量入库
uv run en-news index
# 重建 collection(清空旧数据)
uv run en-news index --recreate
```
### 10.2 语义搜索
```bash
# 基本搜索
uv run en-news search "美联储利率决议"
# 指定返回条数
uv run en-news search "伊朗霍尔木兹海峡" --top-k 5
```
### 10.3 技术方案
- **模式**: 本地文件(`data/qdrant_storage/`),无需 Docker
- **Collection**: `en_finance_news`
- **距离**: Cosine
- **Payload**: title / title_zh / url / source_id / events / content_zh_preview
### 10.4 产物
```
data/qdrant_storage/ # Qdrant 本地文件存储
```
---
## 11. M7 — 全链路管道 + 日报
### 11.1 手动全链路运行(完整流程)
当需要手工执行完整的数据处理流程时,按顺序执行以下命令:
```bash
# 步骤 1(海外): 抓取英文财经新闻
ssh <海外服务器> "cd /opt/intlgrab && uv run en-news crawl"
# 步骤 2(海外): 打包 raw 数据
ssh <海外服务器> "cd /opt/intlgrab && bash scripts/overseas_pack.sh"
# 步骤 3(国内): 拉取海外数据
cd /home/pi/intlnews && bash scripts/domestic_sync.sh
# 步骤 4: 一键全链路 M2→M6 + 日报
cd /home/pi/intlnews && uv run en-news pipeline
```
也可以分步执行(适合调试):
```bash
# 分步模式
uv run en-news extract # M2: 正文提取
uv run en-news dedup # M3: 三层去重
uv run en-news translate # M4: 翻译 + 事件抽取
uv run en-news embed # M5: 向量生成
uv run en-news index # M6: Qdrant 入库
uv run en-news report # 日报生成
```
### 11.2 一键管道(自动)
```bash
# 全链路 M2→M6 + 日报
uv run en-news pipeline
# 跳过日报生成
uv run en-news pipeline --skip-report
# 只生成日报
uv run en-news report
```
### 11.2 管道步骤
```
M2 extract → M3 dedup → M4 translate → M5 embed → M6 index → 日报
```
每步失败记录日志但不阻断后续步骤(降级继续)。
### 11.3 HTML 日报
日报包含五个板块:
1. 🤖 **AI 摘要** — LLM 根据当日 important≥4 事件生成要点总结
2. 🔥 **重要事件** — 高重要度事件表格(标题/情绪/重要度/摘要/链接)
3. 📊 **数据总览** — M1→M6 管道统计数据
4. 📈 **情绪分布** — 利好/利空/中性比例条 + 重要度分布
5. 📋 **事件类型 TOP 10**
日报输出:`data/reports/intl_news_daily_{YYYYMMDD}.html`(约 9KB),同时自动上传到
`https://echart.doorcome.cn/research/{YYYYMMDD}/intl_news_daily_{YYYYMMDD}.html`
### 11.4 国内定时调度
```cron
# crontab<国内服务器>)— 每天 3 次
# 全流程:SSH 触发海外打包 → 下载 → 管道串行 M2→M6 → 日报
0 7 * * * cd /home/pi/intlnews && bash scripts/domestic_full.sh
0 12 * * * cd /home/pi/intlnews && bash scripts/domestic_full.sh
0 18 * * * cd /home/pi/intlnews && bash scripts/domestic_full.sh
```
`domestic_full.sh` 统一完成:远程打包 → 同步 → 管道 → 日报。
---
## 12. M8 — MCP 服务
### 12.1 启动
```bash
uv run en-news mcp-server
```
### 12.2 可用 Tool
| Tool | 功能 | 示例 |
|------|------|------|
| `search_news` | 语义检索新闻 | `search_news("美联储利率决议")` |
| `search_by_stock` | 美股代码检索 | `search_by_stock("AAPL")` |
| `search_by_sentiment` | 按情绪检索 | `search_by_sentiment("加息", sentiment="negative")` |
| `get_today_events` | 当日重要事件 | `get_today_events(importance_min=4)` |
| `get_stats` | 系统统计 | `get_stats()` |
### 12.3 Claude Code 配置
在 Claude Code 的 MCP 配置中添加:
```json
{
"mcpServers": {
"intl-news": {
"command": "uv",
"args": ["run", "en-news", "mcp-server"],
"cwd": "/home/pi/intlnews"
}
}
}
```
---
## 13. 数据目录结构
```
data/
├── raw/ # M1: 原始抓取
│ └── {source_id}/{YYYYMMDD}/
│ ├── {url_hash}.html
│ ├── {url_hash}.md
│ └── index.jsonl
├── processed/ # M2: 正文提取
│ └── {source_id}/{YYYYMMDD}/
│ └── {url_hash}.json
├── dedup/ # M3: 指纹库
│ ├── fingerprints.sqlite3
│ └── {YYYYMMDD}/
│ ├── uniques/{url_hash}.json
│ └── index.json
├── events/ # M4: 翻译+事件
│ └── {YYYYMMDD}/
│ └── {url_hash}.json
├── embeddings/ # M5: 向量
│ └── {YYYYMMDD}/
│ └── {url_hash}.json
├── qdrant_storage/ # M6: Qdrant 本地存储
└── reports/ # M7: 日报
└── intl_news_daily_{YYYYMMDD}.html
```
---
## 14. 定时任务
### 14.1 时间线
```
海外 国内
───────────────────────────── ─────────────────────────
06:00 crawl (≈60min) 07:00 全流程(打包→下载→管道→日报)
12:00 crawl (≈60min) 12:00 全流程
18:00 crawl (≈60min) 18:00 全流程
22:00 crawl (≈60min) (夜间 crawl 结果次日 07:00 处理)
```
国内 `domestic_full.sh` 流程:`SSH触发海外打包 → 下载 → M2→M3→M4→M5→M6 → 日报`(串行)。
### 14.2 新闻日定义
- 切分点:`day_cutoff_hour: 6`(凌晨 06:00
- 当天 06:00 至次日 05:59 属于同一个新闻日
- 例如:2026-06-19 04:00 → 新闻日 "20260618"
---
## 15. 常见问题
### Q: 如何新增新闻源?
编辑 `configs/sources.yaml`,添加源配置:
```yaml
- id: "new_source"
name: "New Source Name"
enabled: true
homepage: "https://example.com/finance/"
article_url_pattern: "/news/[^/]+/"
js_render: false
max_articles_per_run: 30
```
### Q: 翻译质量不好怎么办?
1. 调整 `configs/system.yaml``llm.temperature`(降低更保守)
2. 编辑 `prompts/translation_and_extraction.md` 优化 Prompt
3. 切换 Provider`llm.provider: "qwen"`
### Q: Qdrant 检索太慢?
- 本地文件模式已足够快(17 条 < 0.01s
- 数据量 > 10 万条时建议切换到 Docker 模式
- 设置 `QDRANT_URL=http://your-server:6333`
### Q: 如何查看日志?
```bash
tail -f logs/sync.log # 同步日志(国内)
tail -f logs/pipeline.log # 管道日志(国内)
tail -f logs/crawl.log # 抓取日志(海外)
tail -f logs/pack.log # 打包日志(海外)
```
日志自动清理:每周日凌晨 3 点删除 14 天前的 `.log` 文件(`scripts/cleanup_logs.sh`)。
### Q: 数据如何备份?
```bash
# 备份整个 data 目录
tar czf intlnews_backup_$(date +%Y%m%d).tar.gz data/
```
---
## 附录:技术栈
| 组件 | 技术 |
|------|------|
| 语言 | Python 3.11 |
| 包管理 | uv + pyproject.toml |
| 抓取 | Crawl4AI + Playwright |
| 正文提取 | trafilatura |
| 去重 | SimHash + SQLite |
| LLM | DeepSeek v4-flashOpenAI SDK |
| Embedding | DashScope text-embedding-v3 |
| 向量库 | Qdrant(本地文件模式) |
| MCP | FastMCP |
| CLI | Typer |
| 配置 | YAML + .env |
| 数据模型 | Pydantic v2 |