尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

TradingAgents源码解析:多智能体协作如何重塑金融决策流程

TradingAgents源码解析:多智能体协作如何重塑金融决策流程 1. 为什么是TradingAgents从“单个更强模型”到“一组协作的普通模型”先说一个背景。过去一年里我一直在折腾LLM Agent相关的项目也试过AutoGen、CrewAI、LangGraph这些框架最直观的感受是单模型能力提升带来的边际收益已经越来越小而“多智能体协作”这件事正在把同样一个模型的潜力成倍放大。但市面上的多智能体Demo多半停留在客服、写作、代码助手这些场景真正能让我觉得“这东西有点东西”的其实是TradingAgents这个项目。TradingAgents是斯坦福和剑桥背景的开发者开源的金融交易多智能体LLM框架GitHub上热度很高。它的核心思路不是让你拿一个GPT-4o去预测股价而是模拟一家真实的投资公司里面有分析师、交易员、风险管理团队、交易主管每个角色都由一个LLM Agent扮演他们有自己的系统提示词、职责边界和工具调用能力通过结构化流程完成“基本面分析、新闻解读、技术面判断、多空辩论、风控审核、最终决策”一整条链路。我最初是被它的架构图吸引的看代码之后发现它比想象中要扎实得多。这篇文章我想从“读代码”的角度把这个项目的骨架、核心机制、以及运行一个回测真正需要准备的东西讲清楚。如果你正在做多智能体应用或者想把LLM引入金融分析场景这篇文章应该能让你少走不少弯路。先声明一下这篇文章不是投资建议TradingAgents本身也是研究性质的框架别拿真金白银去盲信任何AI的交易信号。但从工程角度它把一个复杂业务拆成多Agent协作流水线的思路非常值得学习。2. 源码骨架agents.py、graphs/、utils/到底是怎么协同的拿到项目后先别急着看某个文件先把目录结构和数据流搞清楚。TradingAgents的核心代码量不算大但它把“角色定义”、“流程编排”、“工具/记忆”分得很清楚这也是多智能体框架最标准的组织方式。2.1 项目结构的整体脉络我当时的阅读顺序是这样的agents.py定义了所有的Agent类。每一个Agent本质上是一个“系统提示词 LLM调用 工具函数”的组合有的Agent还会维护对话历史。graphs/用LangGraph组织多智能体的执行流程。graph.py是主力流程debate_graph.py专门处理多空辩论环节。utils/一堆支撑模块包括LLM工厂、Faiss记忆检索、新闻抓取处理器、财务数据拉取、并发锁等。backtester.py回测入口把上面的流程封装成“给定一个股票和日期区间按周期跑决策”。data/stocks.json预置的股票清单和对应信息。读多智能体项目的最大误区是陷入单个文件的细节。我建议先跑通backtester.py的调用链然后回到graphs/graph.py看状态流转最后再回头抠agents.py里每个角色的prompt设计。2.2 Agent的本质一个类一段prompt一个LLM调用agents.py里的代码模式高度统一。以FundamentalResearcher基本面研究员为例它的构造函数大致接收一个llm对象、系统提示词、以及conversation_history列表。调用的时候把历史对话和当前任务拼成消息发给LLM拿回文本回复。# 简化后的示意结构 class FundamentalResearcher: def __init__(self, llm, system_prompt, conversation_historyNone, **kwargs): self.llm llm self.system_prompt system_prompt self.conversation_history conversation_history or [] def _get_response(self, user_prompt): messages [{role: system, content: self.system_prompt}] for msg in self.conversation_history: messages.append({role: user, content: msg}) messages.append({role: user, content: user_prompt}) response self.llm.call(messages) return response def fundamental_research(self, ticker, company_info, market_data, portfolio, news): ... return self._get_response(user_prompt)这里最值得注意的点是每个Agent的“个性”完全靠system prompt塑造代码本身没有任何金融逻辑。比如RiskManagementTeam的prompt会要求它模拟一位保守、严格的风控官如果交易员给出的仓位或者止损逻辑不合理它必须驳回。也就是说这个框架的聪明之处全部沉淀在文本里而不是硬编码规则里。这也带来了一个工程启示你在多智能体应用里花时间打磨系统提示词性价比往往高于换更强的主模型。TradingAgents里每个角色都有很长一段详细的prompt包括角色背景、任务边界、输入数据格式、输出格式要求等。想看prompt原文直接在agents.py里找system_prompt参数或者在项目初始化时打印出来。2.3 LangGraph的状态流转设计graphs/graph.py里定义了一个TradingAgentsGraph类核心是LangGraph的StateGraph。State状态是多智能体流程里所有节点共享的一个字典里面装着当前股票代码、市场数据、新闻列表、各阶段产出的分析结果等。# 简化示意 class TradingAgentsGraph: def __init__(self, agents: TradingAgents, ...): self.agents agents self.graph self._build_graph() def _build_graph(self): workflow StateGraph(AgentState) # 注册各分析师节点 workflow.add_node(fundamental_researcher, self.agents.fundamental_researcher.fundamental_research) workflow.add_node(news_analyst, self.agents.news_analyst.news_analysis) workflow.add_node(technical_analyst, self.agents.technical_analyst.technical_analysis) workflow.add_node(bull_trader, self.agents.bull_trader.bull_analysis) workflow.add_node(bear_trader, self.agents.bear_trader.bear_analysis) ...如果你之前只用过OpenAI Function Calling来做单Agent工具调用LangGraph最大的不同是它把流程当成一个有向图节点是函数边是条件跳转状态是节点间唯一的数据传递方式。好处是流程清晰、可插拔、方便可视化坏处是调试时如果某个节点的返回字段和State定义对不上报错会比较隐晦。后面我会专门讲一个我踩过的State字段坑。3. 核心机制拆解分析师团队、多空辩论、交易员与风控这条流水线TradingAgents最有意思的地方不在于单个Agent而在于它把“一群Agent”组织成了一条像真实投资公司一样的决策流水线。我按数据流的顺序拆给你看。3.1 分析师团队四个角色各管一摊整个流程的第一步是让一组分析师各自独立地看同一个标的每个分析师只负责自己擅长的一块Fundamental Researcher基本面研究员根据公司财务指标、行业地位、宏观环境等信息输出对标的长期价值的判断。它像是一个“读财报的人”。News Analyst新闻分析师抓取并分析近期新闻判断事件对股价的潜在影响。它像是一个“看消息面的人”。Technical Analyst技术分析师读取价格走势、均线、成交量等技术指标判断短期趋势与关键价位。它像是一个“看K线的人”。Social Sentiment Analyst社交情绪分析师分析社交媒体上的投资者情绪。这个角色依赖Twitter/X的API实际运行时可能是可选的。Valuation Analyst估值分析师把PE、PB、DCF等估值方法和同行对比做一个参考锚定。每个分析师跑完之后把自己的结论写入State。注意这里是有意让所有分析师并行且独立地工作而不是先让基本面分析师影响新闻分析师。这样做的目的是减少信息级联偏差——每个角度都先给出“干净”的判断后面再由辩论环节去碰撞。3.2 多空辩论为什么奇数轮牛方先说话分析师出完报告之后进入整个框架最吸引人的部分Bull-Bear Debate多空辩论。debate_graph.py里实现了这个机制。系统会初始化一个BullTrader和一个BearTrader分别代表多方和空方双方围绕分析师报告展开辩论。这里有个细节很多人没注意辩论用的是奇数轮、轮流向对方提问并陈述观点的机制源码里的顺序逻辑大致是# debate_graph.py 中的核心循环示意 for i in range(num_rounds): if i % 2 0: # 偶数轮第1轮、第3轮...bull先发言 bull_message self.agents.bull_trader.bull_analysis(...) bear_message self.agents.bear_trader.bear_analysis(..., bull_casebull_message) else: # 奇数轮第2轮、第4轮...bear先发言 bear_message self.agents.bear_trader.bear_analysis(...) bull_message self.agents.bull_trader.bull_analysis(..., bear_casebear_message)为什么要这样设计如果你让两边同时各说各的最后得到的只是两份独立陈述没有真正的“对抗”。而轮流发言意味着后手方必须看到对方的论据然后针对性地反驳。奇数轮次则保证了辩论以其中一方“做总结陈词”结束——不会出现谁都不收尾的尴尬。至于为什么是牛方先发言逻辑上是因为多数市场情绪天然偏多头让空方后发制人更符合真实博弈中“挑战主流观点”的需要。从Prompt设计的角度看BullTrader的系统提示词会强调“你要寻找一切支持买入的理由但同时不能忽视风险”BearTrader则被塑造成“批判性审视所有多头论点指出潜在陷阱”。这种“角色对立的双Agent对抗”模式比单个Agent自问自答更容易挖出盲区。3.3 交易员与风控最后的两个守门人辩论结束之后所有分析结果汇总给Trader交易员由交易员生成一份完整的交易决策买入/卖出/持有以及仓位占比、止损价位和入场逻辑。但这里还没完接下来RiskManagementTeam风控团队会审核交易员的决策。这笔仓位是不是过于激进止损是否合理如果风控给出否定意见交易员需要根据反馈修改方案。源码里这部分同样通过LLM对话实现风控返回的审核意见会作为附加上下文拼进交易员的下一轮prompt里。最后是HeadOfTrading交易主管做终审。它的判断倾向是“大局观”结合团队输出和市场环境确认最终持仓是否适合当前投资组合。在这个环节前面所有Agent的输出都会作为对话历史传入形成一个“往上看一眼全貌”的角色。这条流水线本质上是在复刻一个投资团队的决策机制分析师输出观点交易员形成方案风控挑刺主管拍板。每个环节都有独自的职责边界也有否决或驳回的权力。这正是多智能体系统跟普通LLM工作流的本质区别——流程中的每个节点都有足够的上下文做判断而不仅仅是在一个超长prompt里堆砌所有要求。4. RAG记忆与新闻处理faiss_processor和工具函数里藏着的细节TradingAgents不只是调用LLM聊天它还有一个被很多人忽略但非常关键的模块记忆系统RAG。它的作用是把公司历史新闻和金融事实向量化然后在分析师写作时检索出最相关的内容作为上下文相当于给Agent配了一个“公司历史档案库”。4.1 Faiss索引背后的设计意图utils/faiss_processor.py封装了Faiss索引逻辑。大致流程是先把一批新闻/文档切成长度合适的chunk用Embedding模型转成向量写入Faiss索引查询时拿当前要分析的事件或股票名对应的向量去索引里搜最相似的Top-K条。# 简化示意faiss_processor 的核心接口 class FAISSDocumentStore: def __init__(self, embedding_model, index_pathNone): self.embedding_model embedding_model self.index faiss.IndexFlatIP(dimension) self.docstore {} def add_documents(self, docs): vectors self.embedding_model.encode(docs) self.index.add(vectors) ... def search(self, query, top_k5): query_vector self.embedding_model.encode([query]) scores, indices self.index.search(query_vector, top_k) return [self.docstore[i] for i in indices[0]]这里有个工程判断值得学习为什么不用Redis或Elasticsearch而是用Faiss因为在这个场景里检索的核心诉求是“语义相似”不是关键词匹配。比如“苹果发布新款iPhone”和“AAPL供应链景气度提升”在字面上重合度很低但在语义上高度相关。向量检索能抓住这层关系关键词搜索则很难做到。另外Faiss的IndexFlatIP用的是内积相似度适合归一化后的Embedding向量如果你的Embedding模型输出不归一化直接用内积容易出现“长文本得分虚高”的问题。实际用的时候可以注意一下要么在写入前对所有向量做L2归一化要么改用IndexFlatL2。4.2 新闻抓取与清洗一个不容易做好的脏活utils/news_processor.py负责从网上抓取新闻。金融新闻抓取有几个很容易翻车的点TradingAgents都做了相应处理请求头伪装很多新闻站点对爬虫有UA检测需要设置看起来像真实浏览器的请求头。语言检测有些新闻页面返回的是非英文内容框架会用langdetect检测并过滤避免把乱码塞给LLM。HTML正文提取用BeautifulSoup去标签、提取正文段落而不是直接把整个HTML丢给LLM——后者既浪费Token又容易让模型被导航菜单等无关内容干扰。深度对比用deepdiff对比新闻正文变化避免同一事件的重复报道反复进入上下文。这里面的核心原则是喂给LLM的内容要简洁、干净、聚焦。很多人做RAG时只关注检索准不准忽略了抓取清洗这层最后LLM拿到一堆噪音效果自然差。TradingAgents在这块的实现验证了一个经验脏数据清洗的优先级不比模型选型低。4.3 工具调用与并发控制utils/financial_datasets.py封装了多个外部数据源的API调用FinnHub、Financial Modeling Prep等包括拉取K线、公司财报、估值指标等。而utils/lock.py解决了多Agent并发时的文件/API访问冲突——比如多个Agent同时往同一个日志文件里写内容或者同时请求同一个外部API如果不加锁轻则乱序重则触发限流。我建议在读代码时特别留意这个模块多智能体系统的很多bug不在LLM调用本身而在共享资源的并发管理上。这一块往往是最先出现的工程痛点。5. 回测配置与真实运行体验要准备哪些东西哪些参数最容易踩坑光看代码不跑一遍等于没看。TradingAgents提供了一套回测脚本下面是我实际运行下来觉得最关键的信息。5.1 跑通回测需要的配置清单Python环境建议用Python 3.10以上的虚拟环境requirements.txt一次装齐。如果你不做细粒度的股票Embedding可以先不装flash_attn它能省掉很多编译痛苦。LLM API配置TradingAgents通过utils/llm.py统一管理模型调用支持OpenAI兼容接口。想省钱可以用GPT-4o-mini级别的模型跑完整流程想追求效果再上更强的模型。环境变量里需要配置OPENAI_API_KEY或DEEPSEEK兼容Endpoint。News API和财务数据Key需要FinnHub或Financial Modeling Prep的API Key否则新闻分析和基本面分析很大程度跑不起来。这两家的免费额度对于回测几天是够用的但如果你拉长周期、加多股票很快就撞限流。# 示例设置环境变量后运行回测 export OPENAI_API_KEYsk-... export FINNHUB_API_KEY... export FINANCIAL_MODELING_PREP_API_KEY... python backtester.py \ --ticker AAPL \ --start-date 2024-01-01 \ --end-date 2024-06-30 \ --portfolio-size 100000 \ --num-company-news 205.2 几个容易忽略但影响巨大的参数--start-date和--end-date这是回测的生命线。如果设得太宽LLM分析的Token消耗会成倍增加而且临近“当前时间”的数据容易被模型当作“未来”信息使用产生数据泄漏。建议先设一个4到8周的小区间跑通流程。决策频率项目默认每隔一段时间取决于数据粒度做一次决策。太频繁LLM调用费用会失控太稀疏回测结论又没法反映市场变化。我跑下来觉得5到10个交易日一次比较平衡。轮次参数辩论轮数直接影响成本和效果。默认的轮次已经够用强行加大轮次并不会带来线性收益反而容易让两个Agent陷入车轱辘话。5.3 实测下来的成本与效果体感我拿AAPL跑了大约一个月的日线数据用的模型是GPT-4o-mini完整流程跑下来一次决策大概涉及10到15次LLM调用Token消耗中等。效果方面它的分析报告质量明显高于单次Prompt生成的结果——尤其是风控环节真的会驳回一些仓位过重的方案这在单一Agent里很难看到。但如果要说缺点主要有三个一是慢——每个决策节点都要串行调用好几次LLM一轮决策按秒级计二是贵——如果用强模型跑长周期回测几千次调用轻轻松松烧掉几十美元三是脆弱——外部API一旦限流或者返回格式异常流程会中断重跑时还得注意幂等性。这些都是研究型项目的通病不代表它没有价值。6. 从TradingAgents里能带走的设计模式五个可以直接迁移的思路读代码的最终目的不是复述代码而是提炼出能用到自己项目里的东西。TradingAgents虽然是一个金融交易框架但它背后的多智能体设计模式完全可以平移到其他垂直领域。6.1 角色分工比模型更强更重要TradingAgents证明了在一个复杂决策场景里五六个各司其职的普通模型Agent协作效果可能好于一个更强的通用模型在超长Prompt里做“全能选手”。原因很简单分工让每个Agent的上下文更聚焦也更容易通过对抗和审核机制发现错误。这个思路可以迁移到任何“需要多维度判断”的业务中。比如医疗问诊场景可以拆成“症状采集员、检验报告解读员、用药安全审核员”三个Agent再比如法务审查场景“合同条款分析师、风险审计员、谈判策略师”之间也可以做对抗辩论。6.2 对抗性审核给每个方案配一个“挑刺的人”多空辩论和风控审核本质上都是给主决策Agent配一个对抗性审核Agent。这背后的思想是单Agent在生成方案时容易陷入“自我确认偏差”——它倾向于寻找支持自己论点的证据而忽略反面信号。让一个角色专门负责挑刺可以有效降低这个偏差。实现上很简单在Agent生成第一版方案后用一个角色扮演“魔鬼代言人”去质疑它然后把质疑意见拼回上下文让它修改。很多人把这理解成“多轮反思”但TradingAgents做得更好的是——质疑者是一个有独立视角和独立prompt的Agent而不是同一个模型对着自己的输出再想一遍。后者很容易原地打转前者才可能出现真正的信息补充。6.3 Memory RAG是Agent的长期记忆TradingAgents把新闻历史和公司财务数据做成Faiss索引让Agent在分析时可以“查阅档案”。这套思路对任何需要“长期上下文”的Agent应用都适用。不要把Agent的所有历史都塞进上下文窗口而是借由RAG让它按需召回相关的记忆。6.4 状态驱动流程LangGraph的值得与不值得TradingAgents用LangGraph来编排整个流程这让我对LangGraph的实际体验有了更立体的认识。值得的地方在于它的可视化调试、节点复用、条件跳转都做得很好不值得的地方在于如果业务流程比较线性、Agent数量不多自己写一个状态机可能更省事。LangGraph的学习曲线和State字段对齐成本是真实存在的别为了“用了框架”而用框架。6.5 数据源的隔离和失败降级金融场景里数据源特别多而且每个都有概率挂掉。TradingAgents把“新闻抓取”、“财报数据”、“价格数据”分成了独立模块任何一个挂了都只影响对应Agent的分析质量不会让整个流程崩掉。这种“接线式”的模块解耦是所有多智能体应用最值得参考的工程实践。很多失败不是模型的错而是数据链路太脆。7. 几个我实际踩过的坑和想法代码读得再细不如亲手跑一遍。最后分享几个我在复现TradingAgents时踩到的坑这些在官方README里大概率找不到但能帮你省下大量排查时间。第一个坑是LLM返回格式不稳定的问题。TradingAgents的早期版本里很多Agent的输出被直接拼进后续Prompt但如果模型偶尔返回了Markdown格式或者多余解释解析时可能出现字段错位。我自己跑的时候遇到过bull_case参数里混入无关文本的情况。解决思路有两个一是使用更低温度比如0.1的采样参数二是把所有关键输出都封装成带有明确符号的文本段落而不是裸的自然语言。第二个坑是外部API的限流策略。有些免费数据接口对每分钟请求次数有严格限制而TradingAgents在抓新闻或财务数据时可能在短时间内发出大量请求。如果你发现回测跑到一半卡住先去看是不是API返回了429。处理方式也很简单在调用外部API前做一个简单的Token Bucket限流或者强制加time.sleep()。第三个坑是回测期间的“未来信息”泄漏。这个问题在金融回测里特别致命。比如你用2024-06-30之前的数据做回测但模型在生成分析报告时它的训练数据里可能已经包含了对未来事件的记忆尤其是热门股票。TradingAgents对这种问题没有完美解法它只是通过限制数据范围和让模型基于输入而非记忆推理来缓解。所以你在回测结果里看到的“涨幅”真到了实盘未必可复现。读代码的人需要时刻提醒自己多智能体系统的输出可信不等于金融预测可信。第四个想法是关于“多智能体框架到底该选哪一个”。TradingAgents用LangGraph这已经是目前生态比较成熟的选择但如果你只需要两个Agent做对话对抗——比如“方案A vs 方案B”的辩论——那用LangGraph就有点重了。我在另一个项目里用纯异步函数就实现了类似的Bird-Bear辩论机制代码量只有几十行反而更容易调试和扩展。框架是手段流程设计才是灵魂。最后一个实用的建议是别急着上最强模型。用TradingAgents调试业务逻辑时可以先接一个便宜的轻量模型跑通全流程等确认流程无误后再换成更强模型做最终实验。否则一旦流程里有bug每跑一次完整回测都在烧钱。我自己的经验是先跑gpt-4o-mini验证逻辑再换gpt-4o做最终实验成本可以省将近70%。在工程开发阶段模型能力过剩带来的收益远小于快速迭代带来的收益。如果你正打算基于TradingAgents做二次开发我的建议是优先去改专家的系统提示词和辩论轮次的编排逻辑这是整个框架里“性价比”最高的部分然后再考虑引入你自己的数据源和记忆系统。别一上来就重写架构——这个项目的代码骨架虽然不算复杂但很多细节如并发锁、数据清洗、向量检索都是多年工程经验的沉淀贸然推翻不如先站在它的肩膀上看问题。
返回列表