- 新增 report_db 包: MySQL 连接/建表/幂等写入 (news_report/news_event, myquant 库) - 新增 report_import 包: 历史 178 份日报 HTML 解析入库, 表头驱动列映射 - reporter.py 完全切换: generate_report 结构化入库, 不再生成/上传 HTML - CLI: 新增 report-import 子命令 - 依赖: uv add pymysql; 配置: NEWS_DB_* / REPORT_HISTORY_DIR - 文档: docs/report_db_design.md(实现逻辑), docs/db_schema.md(表结构供 API/前端) - 测试: 24 个单测通过 (parser/builder/models/importer)
701 lines
14 KiB
Markdown
701 lines
14 KiB
Markdown
# project_plan.md
|
||
|
||
# A股 Deep Research 私有投研平台项目计划
|
||
|
||
版本:v1.0
|
||
|
||
最后更新:2026-06-16
|
||
|
||
---
|
||
|
||
# 一、项目目标
|
||
|
||
构建一个面向 A 股投资研究的私有化 Deep Research 平台,实现:
|
||
|
||
1. 自动抓取国内财经新闻网站;
|
||
2. 支持 JavaScript 动态渲染网站;
|
||
3. 自动提取中文新闻正文;
|
||
4. 自动去重;
|
||
5. 利用大模型抽取投资事件;
|
||
6. 自动生成向量知识;
|
||
7. 构建长期财经知识库;
|
||
8. 支持语义检索;
|
||
9. 支持 Cherry Studio、Claude Code、MCP 调用;
|
||
10. 自动生成 A 股投研分析报告。
|
||
|
||
本项目定位:
|
||
|
||
> 「A 股研究辅助平台」,而非自动交易系统。
|
||
|
||
---
|
||
|
||
# 二、总体技术架构
|
||
|
||
Crawl4AI
|
||
(网页抓取)
|
||
|
||
↓
|
||
|
||
GNE
|
||
(中文正文提取)
|
||
|
||
↓
|
||
|
||
标准化处理
|
||
|
||
↓
|
||
|
||
新闻去重
|
||
|
||
↓
|
||
|
||
LLM 投资事件抽取
|
||
|
||
↓
|
||
|
||
Embedding 向量化
|
||
|
||
↓
|
||
|
||
Qdrant 向量知识库
|
||
|
||
↓
|
||
|
||
MCP 服务
|
||
|
||
↓
|
||
|
||
Cherry Studio / Claude Code Agent
|
||
|
||
↓
|
||
|
||
A 股深度研究分析
|
||
|
||
---
|
||
|
||
# 三、开发原则
|
||
|
||
Claude Code 在整个开发过程中必须遵守以下原则。
|
||
|
||
## 3.1 分阶段开发原则
|
||
|
||
严禁一次性生成整个项目。
|
||
|
||
必须按照 Milestone(里程碑)逐步开发。
|
||
|
||
每个阶段必须:
|
||
|
||
* 独立运行;
|
||
* 独立测试;
|
||
* 独立验收。
|
||
|
||
验收通过后再进入下一阶段。
|
||
|
||
---
|
||
|
||
## 3.2 生产级代码原则
|
||
|
||
所有生成代码必须满足:
|
||
|
||
* 使用 Python 类型注解;
|
||
* 必须记录日志;
|
||
* 必须具备异常处理;
|
||
* 必须支持重试机制;
|
||
* 不允许硬编码配置;
|
||
* 配置必须可修改;
|
||
* 必要时编写测试代码。
|
||
|
||
禁止为了简洁而牺牲可维护性。
|
||
|
||
---
|
||
|
||
## 3.3 配置驱动原则
|
||
|
||
网站抓取规则不得写死。
|
||
|
||
所有新闻源配置必须来自 YAML 文件。
|
||
|
||
示例:
|
||
|
||
sources.yaml
|
||
|
||
* id: sina
|
||
enabled: true
|
||
homepage: https://finance.sina.com.cn
|
||
article_selector: article
|
||
title_selector: h1
|
||
|
||
---
|
||
|
||
## 3.4 中文优先原则
|
||
|
||
本系统主要服务于中文财经研究。
|
||
|
||
优先支持:
|
||
|
||
* 财联社
|
||
* 东方财富
|
||
* 新浪财经
|
||
* 证券时报
|
||
* 中国证券网
|
||
* 界面新闻
|
||
* 第一财经
|
||
* 雪球
|
||
|
||
后续支持:
|
||
|
||
* 微博财经
|
||
* 微信公众号
|
||
* B站财经UP主
|
||
* 知乎专栏
|
||
|
||
---
|
||
|
||
## 3.5 可持续演进原则
|
||
|
||
后续新增网站时:
|
||
|
||
不得修改已有核心逻辑。
|
||
|
||
新增网站应仅通过:
|
||
|
||
* 修改配置;
|
||
* 新增适配器;
|
||
|
||
完成扩展。
|
||
|
||
---
|
||
|
||
# 四、推荐项目结构
|
||
|
||
a_share_research/
|
||
|
||
├─ app/
|
||
│
|
||
├─ crawler/ # 抓取模块
|
||
├─ extractor/ # 正文提取
|
||
├─ dedup/ # 去重模块
|
||
├─ llm/ # 大模型抽取
|
||
├─ embedding/ # 向量生成
|
||
├─ vectorstore/ # Qdrant
|
||
├─ scheduler/ # 定时任务
|
||
├─ mcp/ # MCP服务
|
||
├─ api/ # 对外接口
|
||
├─ configs/ # 配置文件
|
||
├─ prompts/ # Prompt模板
|
||
├─ tests/ # 测试
|
||
├─ scripts/ # 工具脚本
|
||
├─ logs/
|
||
├─ docs/
|
||
│
|
||
├─ main.py
|
||
├─ pyproject.toml
|
||
├─ docker-compose.yml
|
||
├─ README.md
|
||
├─ CLAUDE.md
|
||
├─ continuation.md
|
||
└─ project_plan.md
|
||
|
||
---
|
||
|
||
# 五、Milestone 1:新闻抓取模块
|
||
|
||
目标:
|
||
|
||
建立稳定可靠的新闻抓取能力。
|
||
|
||
任务:
|
||
|
||
1. 安装 Crawl4AI;
|
||
2. 验证浏览器环境;
|
||
3. 实现 crawler 模块;
|
||
4. 从 YAML 读取网站配置;
|
||
5. 支持异步并发抓取;
|
||
6. 支持导出原始 HTML;
|
||
7. 支持导出 Markdown;
|
||
8. 本地保存抓取结果。
|
||
|
||
交付物:
|
||
|
||
crawler/
|
||
configs/sources.yaml
|
||
tests/test_crawler.py
|
||
|
||
验收标准:
|
||
|
||
* 至少支持 5 个财经网站;
|
||
* 抓取成功率 ≥ 90%;
|
||
* 抓取失败自动重试。
|
||
|
||
---
|
||
|
||
# 六、Milestone 2:正文提取模块
|
||
|
||
目标:
|
||
|
||
提取高质量中文新闻正文。
|
||
|
||
任务:
|
||
|
||
1. 集成 GNE;
|
||
2. 实现 extractor 模块;
|
||
3. 自动去除广告;
|
||
4. 自动去除相关推荐;
|
||
5. 自动去除评论区;
|
||
6. 提取:
|
||
|
||
* 标题
|
||
* 正文
|
||
* 发布时间
|
||
* 作者
|
||
* 来源
|
||
|
||
统一输出格式:
|
||
|
||
{
|
||
"title":"",
|
||
"content":"",
|
||
"publish_time":"",
|
||
"author":"",
|
||
"source":""
|
||
}
|
||
|
||
交付物:
|
||
|
||
extractor/
|
||
tests/test_extractor.py
|
||
|
||
验收标准:
|
||
|
||
主流财经网站正文提取效果达到人工可接受水平。
|
||
|
||
---
|
||
|
||
# 七、Milestone 3:新闻去重
|
||
|
||
目标:
|
||
|
||
避免重复新闻污染知识库。
|
||
|
||
任务:
|
||
|
||
实现三层去重:
|
||
|
||
第一层:
|
||
|
||
URL Hash 去重;
|
||
|
||
第二层:
|
||
|
||
正文 Hash 去重;
|
||
|
||
第三层:
|
||
|
||
模糊匹配去重。
|
||
|
||
交付物:
|
||
|
||
dedup/
|
||
tests/test_dedup.py
|
||
|
||
验收标准:
|
||
|
||
重复新闻比例 ≤ 5%。
|
||
|
||
---
|
||
|
||
# 八、Milestone 4:投资事件抽取
|
||
|
||
目标:
|
||
|
||
将新闻转换为结构化投资信息。
|
||
|
||
任务:
|
||
|
||
调用 DeepSeek 或 Qwen API。
|
||
|
||
抽取:
|
||
|
||
* 股票代码;
|
||
* 公司名称;
|
||
* 所属行业;
|
||
* 利好/利空;
|
||
* 影响程度;
|
||
* 事件类型。
|
||
|
||
输出 JSON。
|
||
|
||
示例:
|
||
|
||
{
|
||
"stock_codes":["300750"],
|
||
"company_names":["宁德时代"],
|
||
"industries":["锂电池"],
|
||
"sentiment":"positive",
|
||
"importance":5,
|
||
"event_type":"合作签约"
|
||
}
|
||
|
||
交付物:
|
||
|
||
llm/
|
||
prompts/
|
||
|
||
验收标准:
|
||
|
||
JSON 输出成功率 ≥ 95%。
|
||
|
||
---
|
||
|
||
# 九、Milestone 5:Embedding 向量化
|
||
|
||
目标:
|
||
|
||
构建语义检索能力。
|
||
|
||
任务:
|
||
|
||
支持:
|
||
|
||
本地模型:
|
||
|
||
* BGE-M3;
|
||
|
||
远程API:
|
||
|
||
* Qwen Embedding;
|
||
* 百炼 Embedding。
|
||
|
||
输出:
|
||
|
||
List[float]
|
||
|
||
交付物:
|
||
|
||
embedding/
|
||
|
||
验收标准:
|
||
|
||
向量生成稳定可用。
|
||
|
||
---
|
||
|
||
# 十、Milestone 6:Qdrant 向量知识库
|
||
|
||
目标:
|
||
|
||
建立长期财经知识库。
|
||
|
||
任务:
|
||
|
||
1. Docker 部署 Qdrant;
|
||
2. 创建 Collection;
|
||
3. 定义 Payload;
|
||
4. 写入向量;
|
||
5. 支持检索;
|
||
6. 支持过滤。
|
||
|
||
交付物:
|
||
|
||
docker-compose.yml
|
||
vectorstore/
|
||
|
||
验收标准:
|
||
|
||
Top-K 检索正确。
|
||
|
||
---
|
||
|
||
# 十一、Qdrant Payload 规范
|
||
|
||
{
|
||
"id":"",
|
||
"title":"",
|
||
"content":"",
|
||
"publish_time":"",
|
||
"source":"",
|
||
"url":"",
|
||
|
||
```
|
||
"stock_codes":[],
|
||
"company_names":[],
|
||
"industries":[],
|
||
|
||
"sentiment":"",
|
||
"importance":0,
|
||
"event_type":""
|
||
```
|
||
|
||
}
|
||
|
||
---
|
||
|
||
# 十二、Milestone 7:定时任务
|
||
|
||
目标:
|
||
|
||
实现无人值守更新。
|
||
|
||
任务:
|
||
|
||
集成 APScheduler。
|
||
|
||
执行时间:
|
||
|
||
07:00
|
||
|
||
12:00
|
||
|
||
18:00
|
||
|
||
22:00
|
||
|
||
执行流程:
|
||
|
||
抓取
|
||
|
||
↓
|
||
|
||
正文提取
|
||
|
||
↓
|
||
|
||
新闻去重
|
||
|
||
↓
|
||
|
||
LLM 抽取
|
||
|
||
↓
|
||
|
||
Embedding
|
||
|
||
↓
|
||
|
||
Qdrant 入库
|
||
|
||
交付物:
|
||
|
||
scheduler/
|
||
|
||
验收标准:
|
||
|
||
能够长期稳定运行。
|
||
|
||
---
|
||
|
||
# 十三、Milestone 8:MCP 服务
|
||
|
||
目标:
|
||
|
||
支持 Agent 调用知识库。
|
||
|
||
任务:
|
||
|
||
实现 MCP 工具:
|
||
|
||
search_news
|
||
|
||
search_company_news
|
||
|
||
search_industry_news
|
||
|
||
search_stock_events
|
||
|
||
search_sentiment_trend
|
||
|
||
验收标准:
|
||
|
||
Cherry Studio 能够成功调用。
|
||
|
||
交付物:
|
||
|
||
mcp/
|
||
|
||
---
|
||
|
||
# 十四、Milestone 9:投研 Agent
|
||
|
||
目标:
|
||
|
||
生成 A 股深度研究报告。
|
||
|
||
任务:
|
||
|
||
设计 Prompt。
|
||
|
||
支持:
|
||
|
||
* 公司分析;
|
||
* 行业分析;
|
||
* 利好利空梳理;
|
||
* 新闻时间线追踪;
|
||
* 情绪变化分析;
|
||
* 风险识别;
|
||
* 投资逻辑总结。
|
||
|
||
输出:
|
||
|
||
结构化研究报告。
|
||
|
||
交付物:
|
||
|
||
docs/agent_prompt.md
|
||
|
||
验收标准:
|
||
|
||
研究报告具备实际参考价值。
|
||
|
||
---
|
||
|
||
# 十五、运行与运维要求
|
||
|
||
所有服务必须支持 Docker 部署。
|
||
|
||
要求:
|
||
|
||
* 使用 .env 管理敏感配置;
|
||
* API Key 禁止提交至 Git;
|
||
* 日志自动轮转;
|
||
* 支持增量更新;
|
||
* 支持断点恢复;
|
||
* 提供健康检查接口。
|
||
|
||
---
|
||
|
||
# 十六、非目标(Non-Goals)
|
||
|
||
本项目不负责:
|
||
|
||
* 自动下单交易;
|
||
* 股票价格预测;
|
||
* 提供投资建议;
|
||
* 保证投资收益;
|
||
* 替代人工决策。
|
||
|
||
本项目定位为:
|
||
|
||
> A 股研究辅助与知识管理平台。
|
||
|
||
---
|
||
|
||
# 十七、Claude Code 执行规则
|
||
|
||
Claude Code 必须严格遵守:
|
||
|
||
1. 每次只完成一个 Milestone;
|
||
2. 完成后停止并等待人工验收;
|
||
3. 每个阶段更新 README;
|
||
4. 未经允许不得重构已验收模块;
|
||
5. 必须保持向后兼容;
|
||
6. 需求冲突时主动提问;
|
||
7. 优先保证稳定性和可维护性;
|
||
8. 不得追求炫技式实现;
|
||
9. 所有关键设计必须记录到 docs/;
|
||
10. 每次提交前必须确认代码可运行。
|
||
|
||
项目完成标准:
|
||
|
||
> 用户能够通过 Cherry Studio 提出类似:
|
||
|
||
“请分析宁德时代最近30天的利好利空变化,并给出主要投资逻辑演化过程。”
|
||
|
||
系统自动检索知识库、分析新闻事件,并生成完整研究报告。
|
||
|
||
---
|
||
|
||
# 十八、Milestone 10:日报结构化入库(前后端分离数据层)
|
||
|
||
> 状态:✅ 已实施(2026-08-03,等待人工验收)
|
||
> 范围:本项目只负责「日报内容生成 + 结构化存入 MySQL」,**不实现 API 与前端**(由用户另行实现)。
|
||
|
||
## 背景与决策
|
||
|
||
| 决策点 | 结论 |
|
||
| --- | --- |
|
||
| DB | 192.168.1.10:13306(pi 上 autossh 隧道 → doorcome.cn:3306 MariaDB 10.11.18),业务库 `myquant`,表前缀 `news_` |
|
||
| API / 前端 | 用户另行实现,本项目只保证数据完整、表结构文档清晰 |
|
||
| 日报生成 | 完全切换:只存 DB + 前端渲染,不再生成 HTML 静态文件 |
|
||
| 历史数据 | doorcome `/var/www/html/echart/research/{YYYYMMDD}/` 下 178 份 `*_news_daily_*.html`(finance×50 + intl×128,日期 20260608~20260803),解析入库 |
|
||
|
||
## 表结构设计
|
||
|
||
### news_report(日报主表)
|
||
|
||
```sql
|
||
CREATE TABLE IF NOT EXISTS news_report (
|
||
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||
report_date DATE NOT NULL COMMENT '日报日期',
|
||
report_type VARCHAR(16) NOT NULL COMMENT 'finance=A股日报 / intl=国际财经日报',
|
||
file_name VARCHAR(160) NOT NULL DEFAULT '' COMMENT '源文件名(历史解析);新生成可为空',
|
||
generated_at DATETIME NOT NULL COMMENT '生成时间',
|
||
ai_summary TEXT NULL COMMENT 'AI 摘要全文',
|
||
stats JSON NULL COMMENT '数据总览统计快照(管道/情绪/重要度/事件类型/来源分布)',
|
||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
UNIQUE KEY uk_report_file (report_date, report_type, file_name),
|
||
KEY idx_report_date (report_date)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='每日日报主表';
|
||
```
|
||
|
||
### news_event(日报事件明细,新闻联播/财经新闻/公告调研/intl 事件统一入此表)
|
||
|
||
```sql
|
||
CREATE TABLE IF NOT EXISTS news_event (
|
||
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||
report_id BIGINT UNSIGNED NOT NULL COMMENT 'FK → news_report.id',
|
||
section VARCHAR(16) NOT NULL COMMENT '板块: xwlb=新闻联播 / news=财经新闻 / cninfo=公告调研 / intl=国际重要事件',
|
||
rank INT NOT NULL DEFAULT 0 COMMENT '板块内序号',
|
||
importance INT NULL COMMENT '重要度 1-5',
|
||
event_type VARCHAR(64) NULL COMMENT '事件类型',
|
||
title VARCHAR(512) NOT NULL COMMENT '标题',
|
||
summary TEXT NULL COMMENT '摘要/正文',
|
||
sentiment VARCHAR(8) NULL COMMENT 'positive/negative/neutral',
|
||
source VARCHAR(64) NULL COMMENT '来源',
|
||
url VARCHAR(512) NULL COMMENT '原文链接',
|
||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
KEY idx_report_section (report_id, section)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='日报事件明细';
|
||
```
|
||
|
||
设计说明:
|
||
|
||
- 数据总览统计(M1→M6 管道、各源数据、情绪/重要度/事件类型/来源分布)以 JSON 快照存 `news_report.stats`,前端自行解析。
|
||
- 幂等:导入/生成按 `(report_date, report_type, file_name)` 唯一键,重复执行跳过或覆盖,不产生重复行。
|
||
- 历史同一天多次生成(intl 一日 3 次)保留多行,前端取最新。
|
||
|
||
## 阶段划分(每阶段验收后进入下一阶段)
|
||
|
||
### M10-A:DB 连接层与建表
|
||
|
||
- `uv add pymysql`(纯 Python 驱动,无编译依赖)
|
||
- 新包 `report_db/`:`db.py`(连接、事务、建表)、`schema.py`(DDL)
|
||
- `.env` 新增 `NEWS_DB_HOST / NEWS_DB_PORT / NEWS_DB_USER / NEWS_DB_PASSWORD / NEWS_DB_NAME`(默认 myquant),`.env.example` 同步
|
||
- 验收:连接成功、`news_report` / `news_event` 建表成功;`tests/test_report_db.py` 通过(测试用 sqlite3 内存模拟同构 SQL,真实 MySQL 走 integration 标记)
|
||
|
||
### M10-B:历史日报解析入库
|
||
|
||
- 一次性将 doorcome 178 份 HTML 拉到 `data/reports_history/`
|
||
- 新包 `report_import/`:`parser.py`(finance/intl 两类 HTML → 结构化 dict,容错缺板块)、`importer.py`(幂等入库)
|
||
- CLI 子命令:`a-share report-import [--date YYYYMMDD] [--type finance|intl]`(默认全量)
|
||
- 验收:178 份全部入库,`SELECT COUNT(*)` 与文件数一致;抽查 finance/intl 各 2 份字段正确;重复执行不产生重复行
|
||
|
||
### M10-C:日报生成改造(完全切换)
|
||
|
||
- `scheduler/reporter.py`:`generate_report()` 改为「收集结构化数据 → 写入 news_report/news_event」,移除 `_render_html` / `_upload` 调用(函数可保留但不再触发)
|
||
- `scheduler/pipeline.py` 调用签名保持兼容(仍调 `generate_report(day_str)`)
|
||
- 验收:`uv run a-share report --date YYYYMMDD` 后 DB 出现当日记录且无 HTML 文件产出;AI 摘要、事件行、stats JSON 完整
|
||
|
||
### M10-D:文档与收尾
|
||
|
||
- `docs/db_schema.md`:完整表结构 + 字段说明 + 示例数据(供用户实现 API/前端)
|
||
- 更新 README、continuation.md;提交信息 `feat: 日报结构化入库`
|
||
|
||
## 待确认项(不阻塞开发,部署前需用户决策)
|
||
|
||
1. **生产连接**:pi5(192.168.1.160)无法直连 `192.168.1.10:13306`(隧道只绑 loopback)。可选:a) pi 的 autossh 改为绑定 0.0.0.0(需改 pi 系统配置)b) pi5 自建隧道 c) 其他
|
||
2. **intl 日报生成方**:项目代码中无 intl 生成逻辑(doorcome 上另有来源)。历史解析照做;未来 intl 新日报如需入库,由生成方按同一表结构写入
|
||
3. **个股日报**(002714.SZ_0724.html 等 research 根目录文件):本期不处理,如需请另行提出
|
||
|
||
—— project_plan.md 结束 ——
|
||
|