20 KiB
A 股 Deep Research 用户手册
版本:v2.0 | 最后更新:2026-08-22
目录
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 包管理器
# macOS
brew install uv
# Linux
curl -LsSf https://astral.sh/uv/install.sh | sh
2.2 安装
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 配置
cp .env.example .env
# 编辑 .env,至少填写:
# DASHSCOPE_API_KEY=sk-xxx (百炼 LLM + Embedding)
# DEEPSEEK_API_KEY=sk-xxx (DeepSeek LLM,可选)
2.4 验证
uv run pytest -m "not integration" # 应显示 225+ passed
uv run a-share status # 查看数据状态
3. 快速开始
3.1 三条命令入门
# 1. 抓取全网新闻,跑通全链路
uv run a-share pipeline --once
# 2. 语义检索
uv run a-share search "宁德时代固态电池"
# 3. 查看数据总览
uv run a-share status
3.2 全链路 + 日报
# 跑全链路末尾生成日报
uv run a-share pipeline --once --report
# 或单独生成日报(已有数据时)
uv run a-share report --date 20260822
3.3 cninfo 公告管道
# 全链路:公告抓取 → 提取 → 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 抓取
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 提取
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 去重
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 抽取
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 向量化
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 入库
uv run a-share ingest --date 20260822
uv run a-share ingest --recreate # 重建 collection
4.7 a-share search — 语义检索
# 基础检索
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 — 数据总览
uv run a-share status
输出各层统计(M1→M6 数据量) + 今日高重要度事件 TOP 10 + systemd 服务状态。
4.9 a-share discover — 站点分析
# 自动分析首页,输出 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 — 追加入口
uv run a-share add-entry wallstreetcn https://xxx.com/news/新频道
4.11 a-share watchlist — 关注列表
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 — 公告管道
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 — 个股日报
uv run a-share stock-report # 为关注列表中每家公司生成日报
uv run a-share stock-report --no-upload # 仅生成,不上传
4.14 a-share report — 日报生成
uv run a-share report --date 20260822 # 生成指定日期日报并入库 MySQL
日报内容:新闻联播摘要 + 高重要度新闻 + 公告调研 + AI 要点分析。
4.15 a-share report-import — 历史日报导入
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 一次性执行
# 全链路 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 参数可强制全量重建。
# 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 > 硬编码默认值
# .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 渲染 |
新增新闻源:
# 自动分析 → 输出 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
为已有源追加多频道入口:
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)
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(默认) |
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
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 |
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/
uv run a-share ingest --date 20260822
uv run a-share ingest --recreate # 重建 collection
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 股公告/调研/互动易抓取管道,与新闻抓取分开调度。
# 全链路一条命令
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 服务
sudo cp scripts/a-share-research.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable a-share-research
7.2 日常操作
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 修改调度时间
# 编辑 .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 前台守护模式(调试)
uv run a-share pipeline
# Ctrl+C 退出
8. MCP 服务
8.1 连接 Cherry Studio
Cherry Studio → 设置 → MCP 服务器 → 添加:
{
"mcpServers": {
"a-share-research": {
"command": "uv",
"args": ["run", "python", "-m", "scripts.run_mcp_server"],
"cwd": "/home/pi/news"
}
}
}
8.2 连接 Claude Code
编辑项目根目录 .mcp.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") |
📄 工具完整说明(参数/返回格式/降级策略/工作原理/调试):见
docs/mcp_tools.md
8.4 调试(SSE 模式)
uv run python -m scripts.run_mcp_server --sse 8765
# 浏览器访问 http://<host>:8765/sse
8.5 工作原理
用户输入自然语言查询
→ DashScope 嵌入(1024 维)
→ Qdrant 余弦相似度检索
→ 按过滤条件筛选
→ Markdown 格式化返回
9. 日报系统
9.1 日报生成
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 历史日报导入
# 一次性导入 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 个股日报
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 搜索不到结果?
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: 如何从零重建知识库?
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 新增)。中断后重跑:
uv run a-share pipeline --once --resume --report
从断点继续,已成功的步骤不会重复执行。
Q: 树莓派 Qdrant Docker 启动崩溃?
树莓派 ARM64 内核使用 16KB 内存页,Qdrant 官方 Docker 镜像内置的 jemalloc 仅支持 4KB 页。使用本地文件模式(默认)即可,无需 Docker。
Q: 如何新增新闻源?
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不同,勿互相覆盖
—— 用户手册结束 ——