你不需要读完 657 个 Python 文件。真正高效的读法是:先锁定一条调用链,沿着它读三四个文件,建立「手感」,再按需要横向扩展。这一章给你地图、路线和工具箱。
先选目标,再选路线
想改报告文案 → 读 Prompt;想加数据源 → 读 data_provider/;想换模型 → 先读配置,不读代码;想理解结论为什么被降级 → 读守卫。不同目标的最短路径完全不同。
仓库地图:每个目录为什么存在
daily_stock_analysis/
├── main.py # 命令行总入口:参数、模式分派、交易日过滤
├── server.py / webui.py # FastAPI 启动入口
├── src/
│ ├── core/ # 编排:pipeline、交易日历、回测、ETF 轮动、配置管理
│ ├── services/ # 业务服务:分析、历史、持仓、告警、选股、任务队列…
│ ├── analyzer.py # LLM 分析器:Prompt、调用、解析、守卫(5700+ 行,大半是 Prompt)
│ ├── stock_analyzer.py # 技术指标与趋势评分
│ ├── market_analyzer.py # 大盘复盘
│ ├── search_service.py # 新闻/情报检索
│ ├── storage.py # SQLite / SQLAlchemy:32 张表与迁移
│ ├── notification.py # 通知服务:路由、降噪、分片
│ ├── notification_sender/# 各渠道发送器
│ ├── config.py # 环境变量 → Config(近 4000 行)
│ ├── llm/ # 模型后端抽象、LiteLLM、用量归一
│ ├── agent/ # Agent 循环、工具、多智能体、策略路由
│ ├── schemas/ # Pydantic/数据结构与决策刻度
│ └── repositories/ # 数据访问薄封装
├── data_provider/ # 14 个数据源适配器 + 路由/熔断
├── strategies/ # 15 个 YAML 策略(自然语言,无需写代码)
├── api/ # FastAPI 路由(约 131 个端点)
├── bot/ # 命令分发、飞书/钉钉 Stream 接入
├── apps/dsa-web/ # React + Vite 前端
├── templates/ # Jinja2 报告模板(可选渲染引擎)
├── docker/ # Dockerfile / compose
├── scripts/ # CI、环境检查、索引生成、测试脚本
├── tests/ # 300+ 测试文件
└── docs/ # 项目文档(配置、部署、专题契约)
目录边界本身就是一种架构约束:后端能力放 src/、data_provider/、api/、bot/;前端只改 apps/dsa-web/;部署相关放 scripts/、.github/workflows/、docker/。跨边界改动通常意味着设计需要再想一遍。
推荐阅读路线:五次点击建立手感
只看它如何解析参数、判断模式、调用 run_full_analysis()。暂时跳过具体实现。目标是知道「一个命令如何变成一次任务」。
这是单股分析的主函数。按顺序标出:取实时行情、取日线、算趋势、搜新闻、拼上下文、调 LLM、跑守卫、落库。先读函数调用顺序,不读每个 helper 的实现。
找到趋势/乖离/量能/支撑/MACD/RSI 的分值分配,理解「技术分」如何构成。这是全系统最确定、最容易验证的一部分。
不必逐字读完 2000 行 Prompt。先看系统提示词的五段结构、用户消息如何拼、JSON 如何校验、失败如何回退。再看守卫函数。
理解 DataFetcherManager 的市场过滤、优先级、熔断与错误汇总。之后你看任何适配器都会很快。
关键文件速查
| 你想理解 / 修改 | 先看这里 | 备注 |
|---|---|---|
| 命令行参数与模式 | main.py | parse_arguments() 与 main() |
| 单股分析顺序 | src/core/pipeline.py | analyze_stock(),约 434 行起 |
| 批量并发与汇总 | src/core/pipeline.py | run(),线程池默认 3 |
| 技术指标与评分 | src/stock_analyzer.py | MA / MACD / RSI / 乖离 / 量能 |
| Prompt 与 JSON 契约 | src/analyzer.py | 系统提示词、_format_prompt、_parse_response |
| LLM 后端与回退 | src/llm/ | generation_backend.py、litellm_backend.py |
| 数据源路由 | data_provider/base.py | 市场过滤、优先级、熔断 |
| 数据库表与迁移 | src/storage.py | 自愈式 _ensure_* 迁移 |
| 报告与推送 | src/notification.py、src/formatters.py | 各渠道格式差异 |
| Web API | api/v1/router.py | 15 个路由模块 |
| Agent 循环 | src/agent/runner.py | 工具调用、预算、超时 |
| 策略定义 | strategies/*.yaml | 自然语言 + 元数据 |
调试工具箱:先定位,再改代码
命令行
python main.py --stocks 600519 --debug # 详细日志,最快定位
python main.py --dry-run # 只取数,不调 LLM
python main.py --no-notify # 不推送,避免打扰
python main.py --workers 1 # 单线程复现并发问题
python main.py --check-notify # 检查通知渠道配置
python main.py --backtest --backtest-code 600519 --backtest-days 30
日志与诊断
- 日志默认写入
logs/,同时输出到终端;--debug会打开更详细的第三方库与 Prompt 记录。 - Web 的「运行诊断」会展示入口、数据源、分析引擎、产物四段链路,适合排查「哪一段没跑」。
- 单次任务可通过
GET /api/v1/analysis/tasks/{id}/flow读取结构化诊断,不必翻整份日志。 - 数据源问题优先看数据中心的「能力 / 质量 / 警告」,而不是猜。
测试
# 离线测试(CI 默认排除网络标记)
python -m pytest -m "not network"
# 仓库的验证入口
./scripts/ci_gate.sh
# 只做语法检查(改动小、依赖装不全时的最低要求)
python -m py_compile path/to/changed.py
后端约有 300 个测试文件、数千个测试函数,按 unit / integration / network 标记;CI 分 3 片跑离线测试,另有 Docker 构建与前端 lint/build/Playwright。前端本地可执行 npm run test(Vitest),但 CI 并不运行 Vitest——这是一个真实的覆盖缺口,改前端逻辑时要自己补跑。
五个常见改造,从哪下手
换模型 / 加供应商
多数情况只改环境变量:LITELLM_MODEL、LLM_CHANNELS 或 LITELLM_CONFIG。需要多 key 负载均衡时再读 litellm_backend.py。
加一个数据源
继承 BaseFetcher,实现 _fetch_raw_data 与 _normalize_data,声明市场能力,注册到管理器,补离线测试与质量状态。
加一个策略
在 strategies/ 新建 YAML,写清适用场景、条件、加减分与工具依赖。不需要 Python 代码,重启后自动加载。
改报告 / 提示词
文案在系统提示词与模板里;结构在 JSON 契约里;渲染在 templates/ 或通知格式化层。改 Prompt 要同步检查字段校验。
加通知渠道
实现 sender,声明长度/格式/图片能力,接入路由与降噪,补「单渠道失败不影响其他渠道」的测试。
改 Web 页面
apps/dsa-web/src/pages/ + src/api/;注意后端响应统一转 camelCase,认证走 Cookie 与 401 跳转。
贡献前,先读 AGENTS.md
仓库对协作质量有明确要求,摘要如下(以 AGENTS.md 为准):
- 不擅自提交:未经确认不执行
git commit/tag/push;commit message 用英文,不加Co-Authored-By。 - 边界与复用:遵循目录职责,优先复用现有模块,不新增平行实现。
- 文档同步:新增配置要更新
.env.example和文档;用户可见行为变化要更新docs/CHANGELOG.md。 - UI 证据:改报告格式或 Web 界面,PR 需附截图(长期文档示意图除外)。
- 验证:按改动面跑
ci_gate.sh、前端 lint/build,或至少语法检查,并说明未验证项。 - AI 资产:改
AGENTS.md/CLAUDE.md/ 指令文件后运行python scripts/check_ai_assets.py。
文档可能滞后,代码是最终事实
仓库里存在少量文档漂移(例如文档提到过的某个美股源,代码里并没有对应适配器)。读实现时以代码和工作流为准,发现不一致可以在 PR 里顺手修正文档。