7 个人工作记录——分析耗时治理
7 分析耗时治理
日期:2026-06-04
项目:FinAgent
单股分析跑通之后,遇到最多的问题不是报告不对,而是怎么这么久。这篇把我在项目里为压耗时做过、且当前仓库仍生效的措施整理成一篇,方便日后对照 .env 和代码复盘。
文中路径均相对于 FinAgent 仓库根目录。
关键代码入口:
server/finagent/core/config.py:各类FINAGENT_*默认值与 clampserver/finagent/services/analysis_prepare.py:分析前prepare_stock_dataserver/finagent/dataflows/interface.py、dataflows/cache/local_cache.py:vendor 回退与磁盘缓存server/finagent/graph/analyst_setup.py:分析师子图(默认并行 + 串行回退)server/finagent/graph/runner.py:主图、stage_log/analyst_progress落盘server/finagent/api/routes/analysis.py:任务后台线程、首页 TTL 缓存
一、墙钟 vs 体感
演示时分析太慢有两层含义:
(1)墙钟(wall-clock)
从创建任务到 status=succeeded,服务器真实经过的时间。决定因素:外网拉数、LLM 往返次数、各阶段是否并行、云端 API 是否排队。
(2)体感 / 感知延迟
后台其实在跑,但 stage_log 或 analyst_progress 长时间不变,前端轮询退避后像「卡死」。这和 GPU/模型是否还在算是两回事。
后面每条优化都标一下主要影响哪一层,避免把页面刷新快了误说成模型算得更快。
二、耗时大致花在哪(按阶段)
结合 data/processed/langgraph_states/ 里几次 000001 任务的 started_at / finished_at,我目前的经验分布大致是:
| 阶段 | 典型占比 | 主要瓶颈 |
|---|---|---|
| 数据 prepare(若开启) | 首跑 5分钟以上分钟;命中缓存后很短 | AkShare 新闻多源、宏观快讯;行情空数据时多一次 GM 回退 |
| analyst | 常占全链路 20%–40% | 3 专科 × ReAct + LLM;并行后≈最慢专科 |
| research_debate | 约 2–4 分钟 | 牛熊 + 经理,长 Prompt |
| trader | 约 0.5 分钟 | 单次 quick LLM |
| risk_review | 波动最大(2 分钟~异常时 10 分钟+) | 3 辩手 + Judge,四份报告全文塞进 Prompt |
| portfolio_manager | 约 0.5–1 分钟 | deep LLM |
| build_report | 秒级 | 本地拼装 |
风控阶段莫名其妙很久多半不是死循环,而是 4 次大上下文 LLM + API 超时重试;stage_log 又只在整段开始/结束更新,中间无子步骤,体感尤其差。这块暂时还没有改动,因为出现频率较低,下文只记现状。
三、数据层:少打重复外网
1)分析前 prepare
主图 execute_analysis_langgraph_task 在 graph.invoke 之前调用 prepare_analysis_data(默认开,FINAGENT_ANALYSIS_PREPARE=0 可关)。
prepare_stock_data 用 ThreadPoolExecutor(max_workers=4) 并行预拉:
get_stock_dataget_indicators_batchget_newsget_global_news
结果写入 route_to_vendor 使用的 vendor 磁盘缓存(data/processed/vendor_cache/),后续分析师工具命中缓存时可零网络重复。
取舍:首跑会在数据准备文案下集中等待最慢的数据项(往往是新闻/宏观快讯);第二次同标的、同窗口会快很多。
2)vendor 回退链(AkShare → GM → …)
.env 里我常用:
FINAGENT_DATA_VENDOR_CORE_STOCK=akshare,gm
FINAGENT_GM_TOKEN=...
AkShare 返回空 OHLCV 时,route_to_vendor 会继续试掘金,避免任务死在「行情证据为空」。细节见之前的博客。
3)指标 batch + 进程内 LRU
get_indicators_batch:一次工具调用多个指标只拉一趟 OHLCV。fetch_stock_ohlcv的@lru_cache(maxsize=512):同进程重复窗口命中更快。
4)新闻条数与摘要截断
akshare_vendor.get_news_akshare 里:个股新闻约 20 条上限,单条摘要 800 字符截断,控制 ReAct 喂给 LLM 的体积。
四、分析师阶段:当前最大的墙钟优化
1)三专科默认并行
TradingAgents-CN 原版 setup.py 是 selected_analysts 严格串行(Market → … → Fundamentals,中间 Msg Clear)。FinAgent 在 TA-CN 语义之上加了 并行调度:
- 每个专科仍是独立子图:Analyst ↔ tools → Msg Clear → finalize
- 外层
parallel_analysts节点用ThreadPoolExecutor同时invoke三个子图 - 墙钟由「三段相加」变为 ≈ max(market, news, fundamentals)
FINAGENT_ANALYST_PARALLEL=0时退回与 TA-CN 一致的串行链
代码:server/finagent/graph/analyst_setup.py 中 _compile_parallel_ta_cn_subgraph、_compile_single_role_subgraph;开关在 config.py 的 analyst_parallel_enabled() / analyst_parallel_workers()(默认 parallel=开,workers=3)。
2)专科裁剪
当前 .env:
FINAGENT_SELECTED_ANALYSTS=market,news,fundamentals
不跑 social,少一段 LLM + 工具。排障时还可只留 market,fundamentals 做最小闭环。
(这里之前有social是学习别人项目的实现,但发现国内似乎没有社媒源,所以先取消。)
3)内联工具与补救
- 模型发起
tool_calls后,try_inline_tool_report尽量 工具 → 二次 LLM → 报告,减少 ReAct 来回。 _remediate_force_tool_messages:模型不调工具时由代码代拉,避免空头报告。FINAGENT_ANALYST_MAX_TOOL_ROUNDS默认 3,防止单专科工具死循环。
4)共享新闻(可选)
prepare 已缓存 get_news 时,若 FINAGENT_ANALYST_SHARED_NEWS=1 或 FINAGENT_ANALYSIS_SPEED=fast,news 专科可注入 ToolMessage,少一次 get_news 外网。默认 balanced 模式下未显式开启。
五、下游阶段与全链路开关
| 措施 | 默认值 / 我 .env |
作用 |
|---|---|---|
FINAGENT_DEBATE_MAX_PAIRS |
1(已写 .env) |
牛熊 1 对 + 经理,对齐 TA-CN max_debate_rounds=1 |
FINAGENT_RISK_MAX_CYCLES |
1 | 风控 Risky→Safe→Neutral 一轮(日志里 ×3 是 3 次发言,不是 3 轮) |
FINAGENT_ENABLED_STAGES |
六阶段全开 | 排障可只开 analyst,build_report,演示从十几分钟压到几分钟 |
| quick / deep 模型 | 见 .env |
目前 quick、deep 同为 DeepSeek-V3.2;理想上辩手用小模型、Judge 用大模型会更省 |
六、工程与前端体感
| 措施 | 说明 |
|---|---|
POST /api/analysis/tasks + 后台 threading.Thread |
HTTP 立即返回 task_id,长任务不堵请求线程 |
stage_log + _persist_running_snapshot |
各阶段 running/succeeded 落盘,供轮询 |
analyst_progress |
并行分析师时 market/news/fundamentals 逐位 running/done,缓解「签名不变导致退避」 |
| 首页新闻 / 词云 TTL | 实时新闻约 60s、词云约 30min 内存缓存,减轻重复打开首页的 LLM 压力 |
A 股简称表 @lru_cache |
查代码、词云校验不反复读大表 |
七、常用 .env 对照
FINAGENT_DATA_VENDOR_CORE_STOCK=akshare,gm
FINAGENT_SELECTED_ANALYSTS=market,news,fundamentals
FINAGENT_DEBATE_MAX_PAIRS=1
# 并行分析师:默认即开,无需写;若要 TA-CN 串行:
# FINAGENT_ANALYST_PARALLEL=0
# FINAGENT_ANALYST_PARALLEL_WORKERS=2 # API 限流时可降到 2
未写但默认生效的:FINAGENT_ANALYSIS_PREPARE=1、FINAGENT_ANALYST_PARALLEL=1、FINAGENT_RISK_MAX_CYCLES=1、FINAGENT_DATAFLOW_CACHE=1 等,完整列表见 server/finagent/core/config.py。
八、小结
目前来说有效的:
- 分析师三专科并行 — 对 analyst 墙钟帮助最直接(FinAgent 扩展,非 TA-CN 原版)。
- prepare + vendor 磁盘缓存 + indicators batch — 少重复拉外网;首跑慢、二跑快。
- 专科裁剪 + 辩论/风控默认 1 轮 + 工具轮次上限 — 少 LLM 调用。
- AkShare→GM 回退 — 少因行情空数据失败重跑。
- 任务异步 + 细粒度进度 — 主要改善体感,不缩短模型本身算力时间。
待商榷的:
- prepare 会把「新闻/宏观慢」集中到任务开头,前端长期显示「数据准备」并不等于后面 LLM 也在卡。
- 风控阶段仍可能偶发很长,与 prepare/并行无关;根因是大 Prompt + 云端 API。
- 并行会同时打 3 路 LLM,Sophnet 限流时宁可
FINAGENT_ANALYST_PARALLEL_WORKERS=2或临时串行。
若后续还要压耗时,我认为的优先级是:风控/辩手 Prompt 摘要化 > quick/deep 模型分流 > GM 优先于 AkShare 减少空回退 。
更多推荐


所有评论(0)