Files
intl_news/docs/llm-cost-analysis.md
simon c1ab751d95 feat: 日报改为每日一次 + 新增 LLM 使用/成本/缓存文档
- domestic_full.sh / pipeline.sh 新增 --no-report 参数:跳过日报生成,
  保持 M1 抓取 + M2→M6 管道不变,用于 12:00/18:00 只抓不生成日报
- crontab: 07:00 全量含日报,12:00/18:00 --no-report(日报每日一次,降低 LLM 费用)
- docs/llm-models.md: 各 LLM 调用点分别用的 provider/model 事实清单
- docs/llm-cost-analysis.md: 真实 token 消耗与费用构成、降本建议
- docs/llm-cache-optimization.md: DeepSeek 上下文缓存机制与命中率提升设计
- docs/README.md 增加上述三个文档索引
2026-09-04 10:38:33 +08:00

126 lines
7.7 KiB
Markdown
Raw Permalink 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.
# LLM 使用点与成本分析
> 本文档基于 2026-08-30 的代码与真实运行数据编写,用于:
> 1. 盘点本项目所有使用大模型(LLM / embedding)的位置与调用方式;
> 2. 分析 DeepSeek 每日费用的构成与量级;
> 3. 给出降本改善建议(不改写生产代码,仅供决策参考)。
## 一、本项目所有用到「大模型」的地方
本项目有两类大模型能力,计费方式和对成本的影响完全不同:
- **对话 / 补全类(chat completion)**:贵,按「输入 token + 输出 token」计费。目前全部走 **DeepSeek(`deepseek-v4-flash`)**。
- **向量化(embedding)**:便宜,按 token 计费。目前走 **DashScope(`text-embedding-v3`)**,与 DeepSeek 是两套账户/两笔账单。
### 1.1 对话类 LLM 调用点(付费大头,DeepSeek)
| # | 场景 | 位置 | 触发频率 | 单次 token 规模 | 说明 |
|---|------|------|----------|----------------|------|
| 1 | **M4 全文英译中 + 投资事件抽取** | `llm/extractor.py::translate_and_extract`(`_call_llm_sync`) | 每个去重后的唯一文章 **1 次**(失败重试最多 3 次) | 单篇平均 输入≈1667 / 输出≈2342 | 这是**最大的成本来源**,每篇独立调用、整篇中文全文均输出 |
| 2 | **M7 日报 AI 摘要** | `scheduler/reporter.py::_call_llm_simple`(`_generate_ai_summary`) | 每天 3 次定时(07:00/12:00/18:00),每次 1~N 批 + 截断重试 | 每批 max_tokens 500–800(截断重试 1200) | 依赖当日高重要度事件条数;事件 ≤10 一条批,超过则分批 |
> ⚠️ 是否重复翻译(重要成本放大项):
> M4 设计了**增量机制**——同一 `url_hash` 的 `data/events/{date}/{hash}.json` 已存在就跳过,不重复调用 LLM。但每天 3 次定时全流程都会把**当天新增的去重文章**翻译一遍,若某天连续中断/失败多次,缺的篇会在下次补齐,当周补跑可能一次性翻译多天积压文章。
### 1.2 向量类(embedding,DashScope,低费用)
| # | 场景 | 位置 | 触发 | 说明 |
|---|------|------|------|------|
| 3 | **M5 向量生成(入库)** | `embedding/pipeline.py::embed_all_events` | 每天对已翻译文章批量 | `text-embedding-v3`,dim=1024,batch_size=10 |
| 4 | **M6 / MCP 检索查询向量化** | `vectorstore/pipeline.py::search_news`、`mcp_server/server.py` | 每次语义搜索 | 单个查询向量化,量极小 |
### 1.3 不使用大模型的环节
- M1 抓取、M2 正文提取(trafilatura)、M3 去重(SimHash/指纹库)、M6 Qdrant 入库、M9 MySQL 写入 —— 均**不调用大模型**。
---
## 二、真实 token 消耗与费用估算
以 `deepseek-v4-flash`(官方模型名 `DeepSeek-V4-Flash-0731`)当前价格计([官方定价](https://api-docs.deepseek.com/zh-cn/quick_start/pricing/)):
| 计价项 | 空闲时段 | 高峰时段(周一至五 9:00–12:00、14:00–18:00) |
|---|---|---|
| 输入(缓存未命中) | 1.5 元 / 百万 token | 3.0 元 / 百万 token |
| 输出 | 4.5 元 / 百万 token | 9.0 元 / 百万 token |
> 注:本项目常见的定时运行在 07:00(空闲)与 12:00/18:00(接近高峰边界),因此同一日费用波动约 ±100%。
### 2.1 M4 翻译实测 token(来自 `data/events/*/` 的 `prompt_tokens`/`completion_tokens`)
| 日期 | 去重后篇数 | 输入 token | 输出 token | 合计 |
|------|-----------|-----------|-----------|------|
| 2026-08-21(大日) | 82 | 135,616 | 208,146 | **343,762** |
| 2026-08-22(中) | 43 | 74,063 | 88,893 | 162,956 |
| 2026-08-30(小日) | 44 | 73,364 | 103,091 | 176,455 |
单篇平均:输入 ≈1650–1720,输出 ≈2050–2540 token。
### 2.2 单日费用估算(仅 M4)
**小日(约 44 篇,176k token)**
- 空闲:176,455 输入˝中位 ×1.5 + … 简化按 输入73k×1.5 + 输出103k×4.5 = 0.11 + 0.46 = **≈ 0.57 元**
- 高峰:输入73k×3 + 输出103k×9 = 0.22 + 0.93 = **≈ 1.15 元**
**大日(约 82 篇,344k token)**
- 空闲:135,616×1.5 + 208,146×4.5 = 0.20 + 0.94 = **≈ 1.14 元**
- 高峰:135,616×3 + 208,146×9 = 0.41 + 1.87 = **≈ 2.28 元**
### 2.3 日报摘要(M7)
每次约 1–3 批,每批输出几百 token、输入为事件列表,单日 3 次合计约几千 token,费用 ≈ **0.03–0.1 元/天**,可忽略。
### 2.4 结论:费用的绝对构成
- **M4 翻译是绝对主力(>95% 费用)**,日报摘要与 embedding 开销可忽略。
- 单日正常落在 **1–3 元** 区间(视当天文章量与命不命中高峰时段)。
- 若出现 **补跑/积压**:一次把一两天缺的篇全翻,或当日文章量冲到 80+ 篇,单日可能到 **3–6 元**。这通常是用户感受到「费用较高」的真实触发点。
---
## 三、成本高的根因分析
1. **输出 token 巨大**:M4 做的是「全文英译中」,每篇都把整篇中文翻译完整输出,单篇输出 2000+ token,是费用的绝对主体(输出单价是输入的 3 倍)。
2. **每篇独立调用**:82 篇文章 = 82 次往返,system prompt(约 3000 字符模板)每篇重复计入输入。
3. **每天 3 次全流程**:虽增量去重,但当天新文章都翻译,且 07/12/18 各跑一次,频繁触发。
4. **重试放大**:`max_attempts=3`,失败自动重试(实测约 +3%)。
5. **高峰时段触发**:12:00/18:00 的定时可能落入高峰计价,费用 ×2。
6. **付费墙源白跑**:CNBC/Reuters/FT/WSJ 等源抓不到正文,M2 标记 no_content 后**不会**进入 LLM(有防御过滤),因此不会为这些源付费——但它们也没产出,相当于 M1/M2 白耗。真正进 LLM 的只有 investinglive/zerohedge 等能抓到的源,这些源文章较长、翻译输出也就大。
---
## 四、降本改善建议(按性价比排序)
> 以下均为「建议」,未改动生产代码;实施前请评估收益与副作用。
### 建议 A(收益最大):限制 / 缩短 M4 输出
- 全文英译中的输出是主要开销。考虑:
- 将 `llm_scenes.translation.max_tokens` 从 8192 降到合理值(如 4096),或
- 改 prompt,只输出**中文摘要 + 关键事件**,不再整篇英译中(日报和检索实际只消费 `content_zh_preview` 前 300 字与 events,不必整篇全文翻译)。
- 收益:可显著削减输出 token(目前占费用 >60%)。
### 建议 B:尽量把翻译放在空闲时段
- M4 翻译集中到 07:00(空闲,半价)。避免 12:00/18:00 落入高峰计价。
- 仅日报生成放在 18:00(摘要量小,价差影响可忽略)。
### 建议 C:减少不必要的重复翻译(积压/补跑)
- 确保增量机制生效,避免因重复运行把同日文章翻译多遍。
- 若当日中断,下个定时点补齐即可;不要为了「补日报」频繁手动全流程重跑。
### 建议 D:缓存命中优化
- DeepSeek 对「缓存命中」输入大幅降价(0.05 元 vs 1.5 元/百万)。把 system prompt 固定化、相同前缀复用,可提高缓存命中率,降低输入成本(输入约占 40% 费用)。
### 建议 E:换更便宜的模型 / 分流
- 若质量可接受,翻译/摘要改用更低价的同类模型或「空闲时段」更明显的档位。
- embedding 已用 DashScope 低价档,无需动。
### 建议 F:成本监控
- 为 `_process_one` 的成功返回顺带累计 token 到日报 `stats`,或定期统计 `data/events/*/prompt_tokens` 总和,用于成本对账与异常预警。
---
## 五、参考
- [DeepSeek 官方模型与价格](https://api-docs.deepseek.com/zh-cn/quick_start/pricing/)
- 相关代码:`llm/extractor.py`、`llm/pipeline.py`、`scheduler/reporter.py`
- 配置:`configs/system.yaml` 的 `llm` / `llm_scenes` / `embedding` 段