FinAgent交易员阶段:设计、实现逻辑与报告输出

摘要:在 FinAgent 的单股分析流水线中,交易员(trader)负责把上游的研究结论整理成一份可执行的交易方案——包括买入/持有/卖出建议、目标价与理由说明。本文从设计、代码实现到报告与前端展示,说明该阶段如何接入LangGraph主图、如何调用大语言模型(LLM)并提取结构化交易意图,以及在 LLM 不可用时的兜底方法。

关键词:FinAgent;LangGraph;交易员;LLM;风控;


一、交易员在流水线中做什么

FinAgent对单只股票的分析,由LangGraph按固定顺序串联多个阶段完成,顺序如下:

analyst→research_debate→trader→risk_review→portfolio_manager→build_report

对照真实的投研流程,各阶段可以这样理解:

阶段职责主要产出
analyst三位分析师分别从行情、新闻、基本面收集信息三份 *_report 报告
research_debate研究员辩论,研究经理综合investment_plan(投资计划)、debate_verdict(偏多/偏空/中性)
trader(本文重点)在research结论的基础上,给出具体交易建议trader_investment_plan(方案正文)、trade_intent(买/持/卖)
risk_review风控视角审议交易方案,必要时进行修正风控辩论记录、风险评估裁决
portfolio_manager组合层面给出最终评级最终结论与评级
build_report汇总全部结果,供页面展示与导出report_json、Markdown 报告

交易员是第一个把结论落实为“买还是卖、目标价多少”的角色,但需要明确的是,它只生成研究性质的文字建议,不连接券商下单,也不能替代后续的风控审核。


二、设计思路:输入、输出与上下游衔接

2.1 设计原则

开发交易员节点时,我们定了四条基本约定:

  1. 只读上游,不重复拉数:交易员不再调用AkShare等接口,避免重复耗时,只阅读前面阶段已经写好的文本。
  2. 一份输出,两种用途:既要有一段完整的中文方案供人阅读,也要提取机器可识别的trade_intent(交易员结论的结构化缩写,包括buy/hold/sell),供风控与评分卡使用。
  3. LLM 失败时仍能出结果:API未配置、超时或报错时,流水线不应在此处中断,而应根据研究辩论的结论给出规则化兜底方案。

2.2 输入字段

轮到交易员执行时,从共享状态state中读取以下信息:

字段来源用途
ticker/analysis_date用户创建任务时的输入标明分股票、哪一天,用于构造Prompt
investment_planresearch_debate研究经理综合后的投资计划,是交易员的首要参考
三份reportanalyst市场、新闻、基本面报告;拼接后传入,默认最多12000 字符
debate_verdictresearch_debate研究侧的粗结论(偏多/偏空/中性);仅在LLM不可用时,映射为 buy/sell/hold

四份分析师报告合计篇幅往往很长。若原样全部送入 LLM,既容易超出上下文长度限制,也会增加token成本。因此在用 combined_analyst_reports_text 将四份报告以空行连接,并截断到指定上限:

def combined_analyst_reports_text(state, *, max_chars: int = 12000) -> str:
    return "\n\n".join([
        state.get("market_report") or "",
        state.get("social_report") or "",
        state.get("news_report") or "",
        state.get("fundamentals_report") or "",
    ])[:max_chars]

此外还会在 Prompt 中补充 A 股代码、名称及人民币计价等说明,减少模型误用其他市场或错误单位的情况。

小结:交易员的输入=研究经理计划+四份分析师报告(截断后的)+标的上下文;在此基础上由 LLM 撰写交易方案。

2.3 输出字段

字段类型说明
trader_investment_plan字符串LLM生成的完整方案,最长12000字符;前端折叠区和Markdown报告主要展示此字段
trader_output.trade_intentbuy/hold/sell从正文中解析出的交易方向,供程序使用
trader_output.llm_raw字符串或空LLM原文的前4000字符,便于调试与评分
memory_log字符串列表各阶段的短日志,写入任务运行快照

2.4 下游如何使用交易员的输出

交易员的结果不会到此为止,而是继续流入后续的阶段:

  • 风控Risk Judgerisk_manager.py):以trader_investment_plan为起点,结合激进/保守/中性三方辩论进行修正;若交易员未产出正文,则回退使用研究辩论阶段的investment_plan
  • 规则风险基线risk_state.py):计算risk_score时会参考trade_intent,例如卖出意图会略提高风险分,买入意图会略降低。
  • Agent 评分卡agent_scorecards.py):给各阶段Agent自动估的展示分;交易员的分来自正文厚度+买/持/卖意图,仅供页面展示,不参与真实决策或阻断流程。

三、实现逻辑:代码里具体怎么走

核心实现在agents/trader/trader.pytrader_node函数。逻辑可概括为两条路径:LLM 正常时走主路径,异常的时候就走规则兜底方案

否或异常

读取 state

LLM 可用?

组装 Prompt 并调用 LLM

解析正文,提取 trade_intent

写入 trader_investment_plan 与 trader_output

按 debate_verdict 映射方向

生成兜底文案并写入 state

3.1 LLM 主路径

System Prompt(系统指令) 规定模型角色与输出格式,要点包括:

  • 扮演专业交易员,仅依据给定材料分析,不得编造数据;
  • 必须给出具体目标价(人民币 ¥),不得留空或回避;
  • 正文须包含:投资建议、目标价、置信度(0-1)、风险评分(0-1)及理由;
  • 文末固定格式最终交易建议: **买入/持有/卖出**,后续程序靠这一行来提取交易方向。

User Prompt(用户输入) 按顺序提供三块材料:股票代码与日期、研究经理的investment_plan、三份分析师报告的拼接文本。

模型通过get_chat_model(deep=False)调用,与分析师、研究辩论等节点使用同一档快思考模型,在输出质量与分析耗时之间取得平衡。

3.2 交易意图提取

LLM返回的是长文,而风控和评分卡只需要「买/持/卖」三个值之一。因此用正则函数_extract_trade_intent从正文中提取,按优先级依次尝试:

  1. 匹配约定结尾:最终交易建议: **买入|持有|卖出**
  2. 兼容英文格式:FINAL TRANSACTION PROPOSAL: **BUY|HOLD|SELL**
  3. 在全文搜索「买入/BUY」「卖出/SELL」等关键词
  4. 以上均未命中时,默认hold(持有)

3.3 规则兜底方案

当LLM调用失败,或项目配置中关闭LLM时,不再调用模型,改为根据研究辩论结论映射交易方向:

debate_verdict(研究侧结论)映射为trade_intent
bullish(偏多)buy
bearish(偏空)sell
其他 / neutral(中性)hold

四、如何接入LangGraph主图

代码分为两层:

  • trader_node:纯业务逻辑,负责读 state、调 LLM、写结果;
  • _trader_node(在 runner.py):图编排包装,负责阶段开关、进度记录与状态持久化。

包装层主要做四件事:

  1. 读取FINAGENT_ENABLED_STAGES:未包含trader时标记skipped,并清空trader_output
  2. 更新stage_log,前端进度条会显示交易员阶段;
  3. 调用_persist_running_snapshot,长任务运行中轮询中间结果;
  4. trader_outputtrader_investment_plan写回状态,供风控等下游节点进行读取与后续操作。

五、报告输出与前端展示

5.1 写入report_json

在最后的build_report阶段,除基础分析字段外,还会把交易员相关结果写入 report_json

  • trader_investment_plan:交易员方案正文
  • trader_output:含trade_intent的结构化对象,是交易员结论的结构化缩写

同一阶段还会调用 process_trading_signal,从 风控/组合经理终稿 final_trade_decision 中解析出 trading_signal(操作建议、目标价、置信度等)。

5.2 Markdown 导出

services/report_generator.py的处理规则:

  • trader_plan正文时,增加章节 Trader交易方案(原文),完整地收录LLM的输出;
  • 仅有trader_output而无正文时,退化为 Trader交易方案(结构化),只列出 trade_intenttrade_intent是交易员结论的结构化缩写,表示买/持/卖,方便下游代码直接用,不用再去解析整篇报告)。

导出长报告中,交易员通常排在牛熊报告之后、风控辩论之前,与流水线执行顺序一致。
在这里插入图片描述

5.3 前端交易员Tab

实现位于 pages/SingleStockAnalysisPage.tsx

  • hasTraderPayload:判断有没有东西,存在trading_signal.actiontrader_investment_plantrade_intent任一即认为有内容;
  • TraderTab:顶部TradingSignalHero是一排标签,显示操作建议(买入/持有/卖出)、目标价¥xxx、置信度、风险分还有一句理由摘要,下方CollapsibleMarkdownBlock展示方案正文;
  • 评分卡:是后端算好、塞进报告JSON里的一小块数据,可显示意图BUY/HOLD/SELL,数据来自 agent_scorecards.trader

单股结果页中,交易员与研究辩论、风控、组合经理 Tab 并列,与主图各阶段一一对应。
在这里插入图片描述

六、总结

FinAgent 的交易员阶段,接收研究经理计划与四份分析师报告,由LLM生成中文交易方案,并提取trade_intent,供风控与页面展示使用。在LangGraph中,该节点接口清晰:trader_investment_plan交易方案供人阅读,trader_output供程序使用,再交由风控阶段审议与修正;结果同时进入Markdown报告与前端独立Tab(结果页交易员有自己单独的报告页)。

Logo

这里是“一人公司”的成长家园。我们提供从产品曝光、技术变现到法律财税的全栈内容,并连接云服务、办公空间等稀缺资源,助你专注创造,无忧运营。

更多推荐