Files
news/docs/user-guide.md
T
simon 65ead54b4f docs: 文档清理与重构 — 统一为 3 个核心文档
- 删除 5 个过时/残留文档(project_plan/agent_prompt/optimization_plan/report_db_design/deploy/README)
- 新建 docs/architecture.md(项目架构:11 包职责+数据模型+配置+产物)
- 重写 docs/user-guide.md(CLI 全量+增量/断点续跑+MCP+FAQ)
- 重写 README.md(精简入口+文档索引)
- 更新 continuation.md(追加本次记录)
- 更新 .gitignore(排除 data/* 运行产物)
2026-08-22 17:10:39 +08:00

752 lines
20 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# A 股 Deep Research 用户手册
> 版本:v2.0 | 最后更新:2026-08-22
---
## 目录
1. [项目概述](#1-项目概述)
2. [环境准备](#2-环境准备)
3. [快速开始](#3-快速开始)
4. [统一 CLI 参考](#4-统一-cli-参考)
5. [全链路与 Pipeline](#5-全链路与-pipeline)
6. [分模块使用](#6-分模块使用)
7. [定时任务与 systemd](#7-定时任务与-systemd)
8. [MCP 服务](#8-mcp-服务)
9. [日报系统](#9-日报系统)
10. [环境变量参考](#10-环境变量参考)
11. [常见问题](#11-常见问题)
---
## 1. 项目概述
**A 股 Deep Research** 是一个私有化 A 股投研辅助平台,自动完成:
```
财经网站抓取 → 正文提取 → 去重 → LLM 投资事件抽取 → 向量化 → 知识库检索 → MCP 服务
```
**核心能力**:
- 从 14 个财经新闻源自动抓取(含 cninfo 公告)
- 23 种投资事件类型自动抽取(利好/利空/重要度)
- 1024 维语义向量检索(Qdrant 本地文件模式)
- MCP 协议接入 Cherry Studio / Claude Code
- 每日自动生成结构化日报并入库 MySQL
**定位**:研究辅助与知识管理平台,**非**交易系统、**非**预测工具、**非**投资顾问。
**技术栈**:Python 3.11 / Crawl4AI / GNE / DeepSeek / Qwen / DashScope / Qdrant / APScheduler / MCP
---
## 2. 环境准备
### 2.1 前置条件
- Python 3.11
- uv 包管理器
```bash
# macOS
brew install uv
# Linux
curl -LsSf https://astral.sh/uv/install.sh | sh
```
### 2.2 安装
```bash
cd /home/pi/news
uv sync
# 可选:本地 BGE-M3 嵌入(离线,无需 API key)
uv sync --extra local-embedding
# 可选:Playwright 浏览器(仅 JS 渲染源抓取需要)
uv run python -m playwright install chromium
```
### 2.3 配置
```bash
cp .env.example .env
# 编辑 .env,至少填写:
# DASHSCOPE_API_KEY=sk-xxx (百炼 LLM + Embedding)
# DEEPSEEK_API_KEY=sk-xxx (DeepSeek LLM,可选)
```
### 2.4 验证
```bash
uv run pytest -m "not integration" # 应显示 225+ passed
uv run a-share status # 查看数据状态
```
---
## 3. 快速开始
### 3.1 三条命令入门
```bash
# 1. 抓取全网新闻,跑通全链路
uv run a-share pipeline --once
# 2. 语义检索
uv run a-share search "宁德时代固态电池"
# 3. 查看数据总览
uv run a-share status
```
### 3.2 全链路 + 日报
```bash
# 跑全链路末尾生成日报
uv run a-share pipeline --once --report
# 或单独生成日报(已有数据时)
uv run a-share report --date 20260822
```
### 3.3 cninfo 公告管道
```bash
# 全链路:公告抓取 → 提取 → PDF → 去重 → LLM → 入库
uv run a-share pipeline --cninfo-once
# 或分步
uv run a-share cninfo # 只抓公告
uv run a-share cninfo --enrich-pdf # 下载 PDF 补充正文
```
---
## 4. 统一 CLI 参考
全部操作通过 `a-share` 命令完成。子命令速查:
| 子命令 | 功能 | 常用参数 |
|--------|------|----------|
| `crawl` | M1 新闻抓取 | `--source cls` |
| `extract` | M2 正文提取 | `--date 20260822` |
| `dedup` | M3 三层去重 | `--date 20260822 --reset` |
| `events` | M4 LLM 事件抽取 | `--provider qwen --limit 5` |
| `embed` | M5 向量化 | `--provider local-bge` |
| `ingest` | M6 Qdrant 入库 | `--date 20260822 --recreate` |
| `pipeline` | 全链路/定时守护 | `--once --resume --report` |
| `search` | 语义检索 | `--source --stock --sentiment` |
| `status` | 数据总览 | 无参数 |
| `report` | 生成日报 | `--date 20260822` |
| `report-import` | 历史日报入库 | `--date 20260616 --type finance` |
| `cninfo` | 公告/调研/互动易 | `--enrich-pdf` |
| `stock-report` | 个股日报 | `--no-upload` |
| `watchlist` | 关注列表管理 | `add`/`remove`/`list` |
| `discover` | 站点分析 | `url --name --add` |
| `add-entry` | 追加多频道入口 | `source_id url...` |
### 4.1 `a-share crawl` — M1 抓取
```bash
uv run a-share crawl # 抓取全部启用源
uv run a-share crawl --source cls # 单源调试
uv run a-share crawl --no-save # 试跑,不写文件
```
### 4.2 `a-share extract` — M2 提取
```bash
uv run a-share extract --date 20260822 # 指定日期
uv run a-share extract --source sina --date ... # 单源
```
产物:`data/processed/{source}/{date}/{url_hash}.json` (Article)
### 4.3 `a-share dedup` — M3 去重
```bash
uv run a-share dedup --date 20260822 # 增量去重
uv run a-share dedup --date 20260822 --reset # 重建指纹库
```
产物:`data/deduped/{date}/uniques/*.json` + `data/dedup/fingerprints.sqlite3`
### 4.4 `a-share events` — M4 LLM 抽取
```bash
uv run a-share events --date 20260822 # 默认读 configs/llm_models.yaml
uv run a-share events --provider qwen --model qwen-plus # 临时覆盖
uv run a-share events --limit 5 # 小批量调试
uv run a-share events --concurrency 5 # 调并发(默认 3)
```
产物:`data/events/{date}/{url_hash}.json` (ExtractedEvent)
### 4.5 `a-share embed` — M5 向量化
```bash
uv run a-share embed --date 20260822
uv run a-share embed --provider local-bge # 本地 BGE-M3
```
产物:`data/embeddings/{date}/{url_hash}.json` (1024 维向量)
### 4.6 `a-share ingest` — M6 入库
```bash
uv run a-share ingest --date 20260822
uv run a-share ingest --recreate # 重建 collection
```
### 4.7 `a-share search` — 语义检索
```bash
# 基础检索
uv run a-share search "宁德时代固态电池"
# 结构化过滤
uv run a-share search "政策" --source cls --sentiment positive
uv run a-share search "减持" --stock 300750 --min-importance 3
uv run a-share search "芯片" --industry 半导体 --top 5
```
### 4.8 `a-share status` — 数据总览
```bash
uv run a-share status
```
输出各层统计(M1→M6 数据量) + 今日高重要度事件 TOP 10 + systemd 服务状态。
### 4.9 `a-share discover` — 站点分析
```bash
# 自动分析首页,输出 yaml 建议
uv run a-share discover https://wallstreetcn.com/news/global
# 自动写入 sources.yaml
uv run a-share discover https://example.com/news --name 某某财经 --add
# 多频道入口
uv run a-share discover https://example.com/news \
--extra https://example.com/tech \
--extra https://example.com/market \
--name 某某财经 --add
```
### 4.10 `a-share add-entry` — 追加入口
```bash
uv run a-share add-entry wallstreetcn https://xxx.com/news/新频道
```
### 4.11 `a-share watchlist` — 关注列表
```bash
uv run a-share watchlist add 300750 宁德时代 --note "动力电池龙头"
uv run a-share watchlist list
uv run a-share watchlist remove 000001
```
关注列表存储在 `configs/watchlist.yaml`,用于 cninfo 公告过滤和个股日报。
### 4.12 `a-share cninfo` — 公告管道
```bash
uv run a-share cninfo # 抓取关注公司公告+调研+互动易
uv run a-share cninfo --enrich-pdf # 下载 PDF 补充正文
uv run a-share cninfo --pdf-limit 50 # 限制 PDF 处理数量
```
### 4.13 `a-share stock-report` — 个股日报
```bash
uv run a-share stock-report # 为关注列表中每家公司生成日报
uv run a-share stock-report --no-upload # 仅生成,不上传
```
### 4.14 `a-share report` — 日报生成
```bash
uv run a-share report --date 20260822 # 生成指定日期日报并入库 MySQL
```
日报内容:新闻联播摘要 + 高重要度新闻 + 公告调研 + AI 要点分析。
### 4.15 `a-share report-import` — 历史日报导入
```bash
uv run a-share report-import # 全量导入(幂等)
uv run a-share report-import --date 20260616 # 只导入指定日期
uv run a-share report-import --type intl # 只导入 intl 日报
uv run a-share report-import --force # 覆盖已存在
```
---
## 5. 全链路与 Pipeline
### 5.1 一次性执行
```bash
# 全链路 M1→M6
uv run a-share pipeline --once
# 全链路 + 日报
uv run a-share pipeline --once --report
# 指定步骤
uv run a-share pipeline --once --steps crawler,extractor,dedup
# cninfo 全链路
uv run a-share pipeline --cninfo-once
```
### 5.2 增量处理与断点续跑
**增量跳过**:M2/M4/M5 产物已存在时自动跳过,不重复调用 API/计费。使用 `--force` 参数可强制全量重建。
```bash
# pipeline 断点续跑:从上次失败步骤继续
uv run a-share pipeline --once --resume
# 断点续跑 + 日报(中断后直接重跑同一条命令即可)
uv run a-share pipeline --once --resume --report
```
断点状态文件:`data/pipeline/state.json`(按日期隔离,记录每步骤 ok/failed + 耗时)
### 5.3 全链路耗时参考(100 篇文章)
| 步骤 | 耗时 | 说明 |
|------|------|------|
| crawler | ~3 min | 含 Playwright 浏览器渲染 |
| xwlb | ~1 s | 新闻联播 API |
| extractor | ~24 s | GNE 正文提取 |
| dedup | ~2 s | 三层去重 |
| llm | ~45 s | DeepSeek 事件抽取 |
| embedding | ~10 s | DashScope 向量化 |
| qdrant | ~4 s | 写入知识库 |
### 5.4 步骤超时配置
优先级:`TIMEOUT_{NAME}` 环境变量 > `PIPELINE_STEP_TIMEOUT` > 硬编码默认值
```bash
# .env 中设置
PIPELINE_STEP_TIMEOUT=1800 # 全局兜底
TIMEOUT_CRAWLER=900 # 单步精确控制
TIMEOUT_LLM=900
TIMEOUT_DEDUP=300
```
---
## 6. 分模块使用
### 6.1 M1 — 新闻抓取
**新闻源**:14 个(13 Web + 1 API:新闻联播),配置文件 `configs/sources.yaml`
**抓取分流**:
| 条件 | 引擎 | 特点 |
|------|------|------|
| `js_render=false` 且无 `wait_for` | httpx 直连 | 快,不受反爬影响 |
| `js_render=true` 或有 `wait_for` | Playwright | 支持 JS 渲染 |
**新增新闻源**:
```bash
# 自动分析 → 输出 yaml 建议
uv run a-share discover https://example.com/news
# 自动分析 + 写入 sources.yaml
uv run a-share discover https://example.com/news --name 某某财经 --add
# 验证新源
uv run a-share crawl --source example
```
**为已有源追加多频道入口**:
```bash
uv run a-share add-entry wallstreetcn https://xxx.com/news/china https://xxx.com/news/tech
```
### 6.2 M2 — 正文提取
输入:`data/raw/{source}/{date}/*.html`
输出:`data/processed/{source}/{date}/{url_hash}.json` (Article)
```bash
uv run a-share extract --date 20260822
uv run a-share extract --source cls --date 20260822
```
### 6.3 M3 — 三层去重
| 层 | 算法 | 说明 |
|----|------|------|
| L1 | URL Hash | 完全相同 URL |
| L2 | Content Hash | 标准化正文完全一致 |
| L3 | SimHash | 汉明距离 ≤ 3(默认) |
```bash
uv run a-share dedup --date 20260822
uv run a-share dedup --reset # 重建指纹库
```
### 6.4 M4 — 投资事件抽取
**23 种事件类型**:业绩预告/业绩快报/财报披露/合作签约/投资并购/重大合同/产品发布/技术突破/监管处罚/诉讼仲裁/股东减持/股东增持/回购/分红/高管变动/资产重组/停牌复牌/ST警示/退市风险/宏观政策/行业政策/国际局势/其他
**LLM 配置**:`configs/llm_models.yaml`(4 场景独立配置),支持 DeepSeek 和 Qwen
```bash
uv run a-share events --date 20260822
uv run a-share events --provider qwen --model qwen-plus
uv run a-share events --limit 5 --concurrency 3
```
### 6.5 M5 — 向量化
**两种模式**:
| 模式 | 命令 | 要求 |
|------|------|------|
| DashScope 远程 | 默认 | `DASHSCOPE_API_KEY` |
| 本地 BGE-M3 | `--provider local-bge` | `uv sync --extra local-embedding` |
```bash
uv run a-share embed --date 20260822
uv run a-share embed --provider local-bge --date 20260822
```
### 6.6 M6 — Qdrant 知识库
**默认本地文件模式**(零依赖,ARM64 兼容),数据在 `data/qdrant_storage/`
```bash
uv run a-share ingest --date 20260822
uv run a-share ingest --recreate # 重建 collection
```
**Python 检索示例**:
```python
from vectorstore import VectorStore, SearchFilter, make_qdrant_client
c = make_qdrant_client()
store = VectorStore(c)
hits = store.query(
query_vector=my_vector,
top_k=10,
filter=SearchFilter(
source_id="cls",
importance_min=3,
sentiment="positive",
stock_codes=["300750"],
),
)
store.close()
```
### 6.7 cninfo 公告管道
cninfo(巨潮资讯网)是独立的 A 股公告/调研/互动易抓取管道,与新闻抓取分开调度。
```bash
# 全链路一条命令
uv run a-share pipeline --cninfo-once
# 分步操作
uv run a-share cninfo # 只抓公告(关注公司)
uv run a-share cninfo --enrich-pdf # PDF 正文补充
uv run a-share extract --source cninfo --date 20260822 # 正文提取
```
---
## 7. 定时任务与 systemd
### 7.1 安装 systemd 服务
```bash
sudo cp scripts/a-share-research.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable a-share-research
```
### 7.2 日常操作
```bash
sudo systemctl start a-share-research # 启动
sudo systemctl stop a-share-research # 停止
sudo systemctl restart a-share-research # 重启
sudo systemctl status a-share-research # 查看状态
# 查看日志
journalctl -u a-share-research -f # 实时系统日志
tail -f logs/scheduler.log # 文件日志
```
### 7.3 调度时间表
| 时间 | 步骤 |
|------|------|
| 06:30 | cninfo 公告管道 |
| 07:00 | crawler→xwlb→extractor→dedup→llm→embedding→qdrant→**日报** |
| 07:30 | 个股日报 |
| 12:00 | crawler→xwlb→extractor→dedup→llm→embedding→qdrant |
| 18:00 | crawler→xwlb→extractor→dedup→llm→embedding→qdrant |
| 22:00 | crawler→xwlb→extractor→dedup→llm→embedding→qdrant |
### 7.4 修改调度时间
```bash
# 编辑 .env 中的 SCHEDULE_TIMES,格式: HH:MM,HH:MM,...
nano /home/pi/news/.env
# 例: SCHEDULE_TIMES=08:00,14:00,20:00
# 重启生效
sudo systemctl restart a-share-research
```
### 7.5 前台守护模式(调试)
```bash
uv run a-share pipeline
# Ctrl+C 退出
```
---
## 8. MCP 服务
### 8.1 连接 Cherry Studio
Cherry Studio → 设置 → MCP 服务器 → 添加:
```json
{
"mcpServers": {
"a-share-research": {
"command": "uv",
"args": ["run", "python", "-m", "scripts.run_mcp_server"],
"cwd": "/home/pi/news"
}
}
}
```
### 8.2 连接 Claude Code
编辑项目根目录 `.mcp.json`:
```json
{
"mcpServers": {
"a-share-research": {
"command": "uv",
"args": ["run", "python", "-m", "scripts.run_mcp_server"],
"cwd": "/home/pi/news"
}
}
}
```
### 8.3 5 个 MCP 工具
| 工具 | 参数 | 示例 |
|------|------|------|
| `search_news` | query, top_k | `search_news("宁德时代固态电池")` |
| `search_company_news` | query, company, top_k | `search_company_news("价格", company="贵州茅台")` |
| `search_industry_news` | query, industry, top_k | `search_industry_news("政策", industry="半导体")` |
| `search_stock_events` | query, stock_code, top_k | `search_stock_events("重大事件", stock_code="300750")` |
| `search_sentiment_trend` | query, sentiment, top_k | `search_sentiment_trend("AI算力", sentiment="all")` |
### 8.4 调试(SSE 模式)
```bash
uv run python -m scripts.run_mcp_server --sse 8765
# 浏览器访问 http://<host>:8765/sse
```
### 8.5 工作原理
```
用户输入自然语言查询
→ DashScope 嵌入(1024 维)
→ Qdrant 余弦相似度检索
→ 按过滤条件筛选
→ Markdown 格式化返回
```
---
## 9. 日报系统
### 9.1 日报生成
```bash
uv run a-share report --date 20260822
```
日报内容:新闻联播摘要 + 近 30 小时高重要度新闻 + 近 15 日公告/调研 + AI 要点分析。
**入库目标**:MySQL `myquant` 库,表 `news_report`(主表) + `news_event`(事件明细)。
### 9.2 数据库表结构
详见 `docs/db-schema.md`(供 API/前端对接)。
### 9.3 历史日报导入
```bash
# 一次性导入 178 份历史日报 HTML
uv run a-share report-import
# 或按日期/类型筛选
uv run a-share report-import --date 20260616 --type finance
uv run a-share report-import --force # 覆盖已存在
```
### 9.4 个股日报
```bash
uv run a-share stock-report
```
为 `configs/watchlist.yaml` 中每家公司生成综合日报(AI 要点 + 公告 + 新闻 + 互动问答)。
---
## 10. 环境变量参考
### 10.1 LLM 与 Embedding
| 变量 | 默认值 | 说明 |
|------|--------|------|
| `LLM_PROVIDER` | `deepseek` | 默认 LLM 提供商 |
| `DEEPSEEK_API_KEY` | — | DeepSeek API Key |
| `DEEPSEEK_BASE_URL` | `https://api.deepseek.com` | DeepSeek API 地址 |
| `DASHSCOPE_API_KEY` | — | 百炼 API Key(LLM Qwen + Embedding 共用) |
| `QWEN_BASE_URL` | `https://dashscope.aliyuncs.com/compatible-mode/v1` | Qwen API 地址 |
| `EMBEDDING_PROVIDER` | `dashscope` | 嵌入提供商 |
| `LLM_RETRY_TIMES` | `3` | AI 摘要调用失败重试次数 |
| `LLM_RETRY_BACKOFF_SEC` | `2.0` | 指数退避基数(秒) |
> **LLM 场景配置**:`configs/llm_models.yaml` 优先级高于环境变量,每个场景(事件抽取/日报摘要/个股分析/嵌入)可独立指定 provider 和 model。
### 10.2 调度与超时
| 变量 | 默认值 | 说明 |
|------|--------|------|
| `SCHEDULE_TIMES` | `07:00,12:00,18:00,22:00` | 定时任务时间 |
| `CNINFO_SCHEDULE_TIME` | `06:30` | cninfo 公告时间 |
| `STOCK_REPORT_TIME` | `07:30` | 个股日报时间 |
| `STOCK_REPORT_DAYS` | `15` | 个股日报回溯天数 |
| `PIPELINE_STEP_TIMEOUT` | — | 全局步骤超时(秒) |
| `TIMEOUT_CRAWLER` | — | 抓取步骤超时 |
| `TIMEOUT_LLM` | — | LLM 步骤超时 |
| `TIMEOUT_DEDUP` | — | 去重步骤超时 |
| `TIMEOUT_EMBEDDING` | — | 向量化步骤超时 |
| `TIMEOUT_QDRANT` | — | Qdrant 步骤超时 |
| `TIMEOUT_XWLB` | — | 新闻联播步骤超时 |
### 10.3 Qdrant
| 变量 | 默认值 | 说明 |
|------|--------|------|
| `QDRANT_HOST` | `localhost` | Qdrant 服务地址 |
| `QDRANT_PORT` | `6333` | Qdrant 端口 |
| `QDRANT_COLLECTION` | `a_share_news` | Collection 名 |
### 10.4 日报入库
| 变量 | 默认值 | 说明 |
|------|--------|------|
| `NEWS_DB_HOST` | `127.0.0.1` | 日报 MySQL 主机 |
| `NEWS_DB_PORT` | `13306` | 日报 MySQL 端口 |
| `NEWS_DB_USER` | `myquant` | 数据库用户 |
| `NEWS_DB_PASSWORD` | — | 数据库密码 |
| `NEWS_DB_NAME` | `myquant` | 数据库名 |
| `REPORT_HISTORY_DIR` | `data/reports_history` | 历史日报目录 |
### 10.5 cninfo
| 变量 | 默认值 | 说明 |
|------|--------|------|
| `CNINFO_PDF_BASE` | `http://static.cninfo.com.cn` | PDF 基础 URL |
---
## 11. 常见问题
**Q: 某源抓取 0 篇文章?**
检查 `configs/sources.yaml` 中该源的 `article_url_pattern` 正则是否匹配真实链接格式。先用 `uv run a-share crawl --source <id>` 单源调试。
**Q: M2 提取的正文是模板文本(如"郑重声明")?**
提取器已内置关键词黑名单自动过滤。若遇到新模板,可在 `extractor/parser.py` 的 `_BOILERPLATE_PATTERNS` 追加。
**Q: M4 调用 LLM 报错?**
检查 `.env` 中 `DASHSCOPE_API_KEY` 是否填写。可用 `--provider qwen` 切换到百炼测试。模型名缺失时直接报错,检查 `configs/llm_models.yaml` 中 `event_extraction` 场景的 `model` 字段。
**Q: Qdrant 搜索不到结果?**
```bash
uv run python -c "
from vectorstore import VectorStore, make_qdrant_client
c=make_qdrant_client(); s=VectorStore(c)
print(s.count()); s.close()
"
```
若 count=0,运行 `uv run a-share ingest --date <date>` 入库。
**Q: 如何从零重建知识库?**
```bash
rm -rf data/raw data/processed data/dedup data/deduped data/events data/embeddings data/qdrant_storage
uv run a-share pipeline --once
```
**Q: 如何避免重复调用 LLM/Embedding API?**
M2/M4/M5 默认增量处理:产物已存在即跳过(2026-08-12 新增)。中断后重跑:
```bash
uv run a-share pipeline --once --resume --report
```
从断点继续,已成功的步骤不会重复执行。
**Q: 树莓派 Qdrant Docker 启动崩溃?**
树莓派 ARM64 内核使用 16KB 内存页,Qdrant 官方 Docker 镜像内置的 jemalloc 仅支持 4KB 页。使用本地文件模式(默认)即可,无需 Docker。
**Q: 如何新增新闻源?**
```bash
uv run a-share discover https://example.com/news --name 某某财经 --add
uv run a-share crawl --source 某某财经 # 验证
```
**Q: 服务器 .env 和本地 .env 有何不同?**
- **生产 pi5**:`NEWS_DB_HOST=192.168.1.10`(直连 DB 隧道)
- **Mac 本地**:`NEWS_DB_HOST=127.0.0.1`(通过 ssh 隧道)
- 两处 `.env` 不同,**勿互相覆盖**
---
—— 用户手册结束 ——