第一次把 TradingAgents 完整跑通的那天晚上,我盯着终端里刷出来的十几段分析文本发了很久呆。四个分析师各自交完观点,多空双方来回吵了两轮,交易员拍了个方向,紧接着三个风控角色又把它从头到尾拆了一遍,最后汇总成一段决策文本。整个过程里没有任何一行代码在算指标权重,全程都是自然语言在互相传递判断。那一刻我才意识到,这东西跟我以前接触的量化框架根本不是一个物种——它不是在算,它是在"开会"。
TradingAgents 是一个用多智能体协作来模拟真实交易机构决策流程的开源框架,核心思路是把"研究—辩论—决策—风控"这条人类机构的流水线,用大模型智能体一比一搬进代码里。它不承诺给你一个能赚钱的策略,它给你的是一套可拆解、可观察、可改造的决策生成流水线。适合三类人看:想研究多智能体编排的工程师、想给自己的投研流程加一层"AI 讨论会"的从业者,以及单纯好奇大模型在复杂推理链条里到底会怎么崩的人。下面我按自己从读源码到改造再到踩坑的完整路径,把里面的结构、取舍和容易翻车的地方一次讲清楚。
1. TradingAgents 更像一家微型交易公司,而不是一个策略脚本
很多人第一眼看到这个项目,会下意识把它归类成"AI 选股工具",然后拿它跟传统因子模型对比,接着就会失望——它没有明确的信号公式,输出也不稳定。这个预期本身就错了。它的设计隐喻不是"公式",而是"组织":一家小型交易机构里有不同岗位的人,各自看不同的材料,得出不同的判断,然后通过辩论和复核把分歧收敛成一个可执行的决定。TradingAgents 把这条组织链路拆成了角色,每个角色由一次或多次大模型调用承担。
理解这个隐喻之后,很多设计上的"怪"就顺了。比如为什么要有那么多重复的分析环节、为什么允许角色之间互相反驳、为什么最终决策只有一段文字而不是一个数字。因为现实中的机构决策就是这样运作的:没有人能拿到全部信息,结论是在冲突中被磨出来的。
1.1 四个分析师:同一只股票,四套完全不同的证据链
分析师层是整个框架的输入层,四类角色的分工可以用一句话概括:基本面看这家公司值多少钱,技术面看市场现在怎么想,新闻看外部发生了什么,情绪看散户在怕什么或在贪什么。
- 基本面分析师负责吃财务报表:资产负债表、利润表、现金流量表,另外还会关注内部人交易这类信号。它的产出通常包含营收与利润的同比环比变化、毛利率走势、现金流是否匹配净利润、负债结构是否恶化。这个角色的价值在于把"这家公司赚钱吗"翻译成可核查的数字。
- 技术分析师完全换一套语言:均线关系、动量指标、波动区间、成交量配合。它输出的是诸如某条均线是否上穿、某指标是否进入超买区间、当前价格位于布林带哪一侧这类可量化的描述。注意它不做预测,它做的是"把当前形态描述清楚"。
- 新闻分析师盯的是公司公告、行业动态和宏观事件,关注的是"有没有新信息进入市场"。它的难点在于噪音过滤——一天几十条新闻,哪条对这家公司真的有影响。
- 情绪分析师更微妙,它读的是社区讨论、散户情绪倾向这类非结构化文本,产出类似"讨论热度上升但情绪偏向恐慌"这种判断。
这四个角色的关键设计在于它们之间不共享中间结论,只看同一份原始数据。这是刻意为之:如果让基本面分析师先看到技术面的结论,它很可能会不自觉地向已有判断靠拢,四个角色就退化成了一个角色说了四遍。我在改造时试过让分析师互相读对方的报告,结果是报告之间的分歧明显变小、但决策质量没有提升,反而更容易集体看错。这个教训后面还会再提到。
1.2 多空研究员辩论:把"我觉得"逼成"因为所以"
分析师交完报告,接下来是我认为整个框架里最有意思的一环:多头研究员和空头研究员围绕同一批报告进行多轮辩论。
流程大致是这样:多头先发言,从报告里挑出支持看多的证据,形成一套逻辑;空头接着反驳,既要指出多头论证里的漏洞,也要拿出自己那一侧的证据;然后多头再回应,如此往复若干轮;最后由一个裁判角色总结双方论点,给出一个平衡后的投资计划。
这个机制解决的是一个非常实际的问题:**大模型天然倾向于给出模棱两可的结论。**你直接问它"这只股票该不该买",它十有八九会给你"需要综合考虑多方面因素"这种废话。但当它被强制分配到一个立场上,并且对面有个明确反对者在等着抓漏洞时,它就被逼着把论据具体化。我在实测里最明显的感受是,辩论进行到第二轮以后,双方开始引用具体的报表科目和具体的时间区间,而不是停留在"行业前景广阔"这种层面。
还有一点值得注意:辩论的轮次是一个可配置参数,通常两到三轮就够了。轮次太少,分歧没被充分展开;轮次太多,双方会开始为了辩论而辩论,编造一些并不存在的论据来维持立场。我自己的经验是三轮是收益递减的临界点,第四轮开始基本只是换措辞重复。
1.3 交易员、风控三方与最终拍板的人
辩论结束后,交易员角色登场,把研究阶段的投资计划转换成具体的方向判断和行动方案。这个角色的定位很关键:**研究员关心"这个判断对不对",交易员关心"这个判断值不值得下注、以什么姿态下注"。**它需要综合四个分析师的原始报告和辩论的最终结论,给出一个带理由的方向性决定。
紧随其后的是风控层,同样是三方辩论的结构,但立场划分不同:
| 风控角色 | 立场 | 关注的典型问题 |
|---|---|---|
| 激进方 | 强调机会成本 | 过度保守会错过多少上行空间 |
| 中性方 | 强调平衡 | 当前仓位与波动是否匹配,有没有更优的折中 |
| 保守方 | 强调下行风险 | 最坏情况下的损失边界在哪里 |
这三方吵完之后,由最终决策角色(可以理解为组合经理)整合全部信息给出最终结论。这里的设计意图非常清楚:**任何一个方向性判断,都必须先经过一次"如果错了会怎样"的压力测试。**我在读源码时注意到,最终决策的提示词里明确要求它不能简单复述交易员的观点,而要说明风控辩论改变了什么。这个约束很聪明,它迫使最终层真正承担综合职责,而不是当传声筒。
2. 用 LangGraph 把"开会流程"翻译成状态图
看清角色分工之后,下一个问题就是工程实现:这么多角色、这么多来回,靠什么串起来?TradingAgents 选的是 LangGraph,用状态图的方式描述整个流程。我一开始觉得这是过度设计——自己写个函数按顺序调用不就行了?改了两版之后我就服了,因为这个流程里存在太多天然的循环和条件分支,用链式调用写会变成一团意大利面。
2.1 为什么是图而不是链:辩论天然需要环
链式结构的假设是"一步接一步,线性推进",但辩论不是线性的。多头说完要说空头,空头说完可能还要回到多头,转几轮才往下走。用链去表达这种结构,你只能写死"多头→空头→多头→空头→裁判",轮次一改就要动代码。
状态图的表达方式完全不同:**节点代表角色,边代表流转条件。**辩论这件事被拆成三个节点——多头节点、空头节点、判断节点——配合一条条件边。判断节点每次执行时读一下当前轮次计数,没到上限就指回多头节点,到了上限就指向交易员节点。轮次从一个配置项读进来,想改成五轮就改个数字,代码逻辑一行不动。
更重要的是,图结构天然支持"断点恢复"。多智能体流程动辄几十次模型调用,中间任何一次超时或限流都会让整轮白跑。图可以把每一步的执行状态落盘,出问题后从上一个检查点继续,而不是从头再来。这一点在调试期尤其救命——我调提示词的时候经常需要反复跑同一段流程,有检查点之后迭代速度快了不止一倍。
2.2 共享状态字段怎么定,决定了后面能怎么扩展
图里各个节点靠什么交换信息?靠一份共享状态。你可以把它理解成会议室的白板:每个角色进来写一笔,下一个角色读白板上的全部内容再决定写什么。
状态通常是一个类型化的字典结构,字段大体分几类:
# 简化后的状态结构示意,字段命名按语义归组 class AgentState(TypedDict): # 输入上下文 company_of_interest: str # 标的标识 trade_date: str # 决策日期,回测时极其关键 # 分析师产出(各自独立字段,互不覆盖) market_report: str sentiment_report: str news_report: str fundamentals_report: str # 研究辩论的滚动记录 investment_debate_state: dict # 含双方发言历史、当前轮次、裁判结论 # 交易员与风控 trader_investment_plan: str risk_debate_state: dict final_trade_decision: str # 历史经验注入 past_memory_str: str这里有两个设计细节值得单独说。第一,四个分析师的产出用四个独立字段而不是一个列表。看起来冗余,但好处是下游任何角色想引用某一份报告时可以精确定位,不用去列表里按顺序猜。第二,辩论状态被组织成一个带轮次计数的字典,而不是简单地把发言往一个数组里追加。轮次计数是条件边做判断的依据,没有它就没法在代码层面控制循环。
我自己的改造经验是:**新增角色时,先想清楚它的产出放在哪个字段、谁会读它。**有一次我加了个"行业对比分析师",随手把结果塞进新闻报告字段里做拼接,结果下游的新闻分析师引用时把行业数据当新闻引用,输出了一堆奇怪的表述。后来单独开了一个字段,问题立刻消失。状态字段的设计质量,直接决定这套系统能长到多大。
2.3 轮次控制与防死循环的兜底设计
只要图里有环,就有死循环风险。TradingAgents 在这块的防护做得挺扎实,主要有三层:
第一层是显式配置的最大轮次。辩论轮次、风控轮次都是配置项,默认值偏保守。这不是限制能力,而是成本控制——每多一轮就是多几次模型调用。
第二层是计数器存在共享状态里,由路由函数读取。路由函数是个纯函数,输入是当前状态,输出是下一个节点的名字。它不关心业务逻辑,只做一件事:轮次到没到。这种职责分离让流程逻辑特别清晰,你改辩论内容不会影响流转控制。
第三层是兜底分支。路由函数里通常会有个默认返回,即使状态里的字段缺失或类型不对,流程也能落到一个终止节点,而不是直接抛异常卡死。我在调试阶段改状态结构时踩过坑,某个字段名写错了,因为路由函数有兜底所以流程没崩,只是提前结束了——这反而帮我快速定位到问题。
提示:如果你要在这个框架里加新的循环环节(比如让分析师在看到辩论结果后补一次数据),务必同时加轮次上限和路由兜底。我见过有人加了个"分析师复盘"环节忘了加上限,跑一次烧掉的钱够跑一周。
3. 提示词之外的约束设计:让模型少说废话、少编数据
框架结构搭好之后,真正决定输出质量的是提示词和各类约束。这部分我在项目里花的调试时间最多,也最有心得。核心矛盾是:**大模型在开放性任务上表现很好,但投研决策需要的是具体、可核查、有依据的输出。**这个矛盾不能靠"写更好的提示词"完全解决,得靠结构性的约束设计。
3.1 证据与结论分离:先摆数据再下判断
最有效的一条约束,是在提示词里强制要求先列出证据,再给出判断,并且规定证据必须是具体数值或具体事件,不能是笼统描述。
这条规则看起来简单,效果却非常明显。原因是模型的生成是自回归的:如果让它先给结论,它后面所有内容都会朝着维护这个结论的方向去组织,变成"先射箭再画靶"。反过来,先让它把数据点铺开,结论就成了对数据的归纳,逻辑链条更扎实。
具体写法上,我会把输出模板拆成固定的几段:数据概览、关键变化、正向证据、反向证据、综合判断。其中"反向证据"这一段是必须项,哪怕结论是强烈看多,也必须列出至少两条不利因素。这一条硬约束能显著降低输出一边倒的概率。
还有个细节:要求模型区分"数据说了什么"和"我认为这意味着什么"。前者可以直接引用,后者必须显式标注为推断。这个区分在后续的辩论环节特别有价值,因为辩论双方都能清楚地看到哪些是事实、哪些是解释,吵起来就事论事,而不是各说各的。
3.2 结构化输出与失败重试,别让一次解析错误毁掉整轮
多智能体系统里有个很容易被低估的脆弱点:**一个角色的输出格式错误,会导致整条链路失败。**比如最终决策角色需要输出一个包含方向、理由、风险等级的结构化对象,如果模型这次没按格式来,下游解析就会炸。
处理方式有两层。第一层是用结构化输出能力约束模型。主流框架都支持传入一个数据模型定义,让模型输出直接反序列化成对象。这里的关键是模型定义要尽量简单——字段越少、嵌套越浅,成功率越高。我见过有人定义了个五层嵌套的模型,成功率掉到七成以下,每一层都是风险点。
第二层是重试要带上下文。解析失败后不要原样重发,要把失败原因和原始输出一起塞回提示词,告诉模型"上次你这样输出,缺少了某字段"。实测下来带错误信息的重试,第二次成功率能到九成以上,比盲目重试高得多。重试次数也要设上限,通常是两到三次,超过就走降级路径,比如用一段纯文本结论兜底,至少不能让整个流程白跑。
3.3 跨天的记忆与反思:把"上次类似情况"喂回去
这套框架里我觉得最有想象力的一块,是记忆机制。它会维护一个经验库,把"当时的情境 + 当时的判断 + 后来的结果"作为一条记录存起来。当新的决策开始时,系统会先根据当前情境去检索历史记录里最相似的几条,作为参考注入到提示词里。
举个例子:如果过去几次在市场波动率快速抬升时,系统给出的看多判断后来都被证明偏早了,那么当再次遇到类似的高波动情境时,检索出来的经验就会提醒它"这种环境下你的历史判断偏乐观"。这不是参数更新,而是把经验以文本形式放回上下文。
配套的还有反思环节:隔一段时间回看自己的判断和实际走势,生成一段"我哪里错了、下次该怎么调整"的文本,写回经验库。这一步的价值在于把零散的判断沉淀成可复用的模式。我在测试时明显感觉到,接了记忆机制之后,系统在相似情境下的输出一致性提升了,不会今天一个说法明天一个说法。
不过这里也有个坑:**经验库会污染。**如果某条经验是基于一个特殊事件(比如某次突发的行业政策)形成的,它在相似情境里被反复检索出来,就会持续误导判断。所以要定期清理,或者给经验加个时间衰减权重,让老经验的影响逐步降低。
4. 我踩过的坑:跑通之后才会遇到的四件事
前面讲的是"应该怎么设计",这部分讲"实际会怎么崩"。这几个坑都不在文档里,全是我自己跑废几轮之后才摸清楚的。
4.1 一次决策的真实调用次数与成本账
先算笔账。一次完整流程的模型调用次数大致是:
| 环节 | 调用次数估算 | 说明 |
|---|---|---|
| 四个分析师 | 8~20 次 | 每个角色至少一次,带工具调用的会更多 |
| 多空辩论 | 4~6 次 | 两到三轮,双方各一次 |
| 辩论裁判 | 1 次 | 汇总双方论点 |
| 交易员 | 1~2 次 | 含一次可能的修正 |
| 风控三方辩论 | 6~9 次 | 三轮三个角色 |
| 最终决策 | 1 次 | 综合全部信息 |
加起来单次决策大概落在25 到 40 次模型调用之间。这个数字意味着什么?意味着如果你用同一个小参数模型跑全流程,单次成本还能接受;但如果你图省事,全部用大参数模型,单次成本会直接翻十几倍。
我自己的配置策略是分层用模型:分析师的单点信息提取用快模型,辩论、裁判和最终决策用强模型。理由是分析师做的其实是"从数据里读出发生了什么",属于信息提炼,不需要太强的推理;而辩论和最终决策需要处理冲突、权衡取舍,是真正的推理任务。这个搭配实测下来,成本能压到全用强模型的三成左右,而输出质量的主观感受差别不大。
还有一点:**调试期一定要开缓存。**同一份数据被反复拉取、同一段流程被反复执行是常态,没有缓存的话,光是调一个提示词就能烧掉可观的额度。
4.2 上下文膨胀:越聊越贵,也越聊越糊
多轮辩论加上多角色产出,上下文增长得非常快。四个分析师的报告加起来可能已经很长,再叠加辩论历史和风控讨论,到最终决策那一步时,输入上下文可能已经非常庞大。
这带来两个问题:成本上升和注意力稀释。后者更麻烦。当上下文里塞了太多内容,模型对关键信息的把握会下降,容易出现"读了半天没抓住重点"的情况。我在测试时遇到过最终决策完全忽略风控方提出的某个关键风险点,一查发现那条内容埋在很长的历史中段,被稀释掉了。
我的处理办法有三个:一是对历史做摘要压缩,辩论超过一定轮次后,把早期轮次压缩成要点列表,只保留最近一轮原文;二是在最终决策阶段的提示词里显式做"关键信息置顶",把风控的核心结论、辩论的主要分歧点单独提炼到提示词前部;三是控制记忆注入的条数,检索出来的历史经验控制在三条以内,多了就是噪音。
4.3 回测时的时间穿越,是最隐蔽的假象
这个坑我必须单独拎出来讲,因为它太容易发生了,而且发生后你几乎察觉不到。
用历史日期回测时,框架会带着一个"决策日期"去跑流程。但很多数据工具的默认行为是返回当下的数据,而不是那个历史日期的数据。这意味着你在回测某个半年前的日期时,新闻工具可能返回了最近几天的新闻——你的系统在"用未来的信息做过去的决策"。
结果就是回测表现好得离谱,实盘一跑完全不是那么回事。我第一次发现这个问题时,是注意到某次回测里早于决策日期的新闻真的被引用了,那一刻后背发凉。
防范方式很直接:回测时要么关掉所有在线数据工具,要么强制所有工具调用都带上决策日期参数,并且验证工具确实尊重了这个参数。另外,把决策日期作为强制字段贯穿整个流程,在每个角色的提示词里都明确"你只能依据该日期及之前的信息",再加一层输出校验,看有没有明显越界的引用。
注意:任何带你回测历史日期的多智能体流程,都要专门做一次"时间穿越"检查。这不是可选项,是必做项。
4.4 可复现性:同一个日期跑两次,答案不一样
大模型有随机性,这一点大家都知道,但在多智能体流程里它的影响会被放大。因为每个角色的输出都会成为下一个角色的输入,一次微小的措辞差异可能在几轮传递后演变成完全不同的结论。同一个日期、同一份数据,跑两次可能得到方向相反的结果。
把温度参数调到最低能缓解,但不能完全消除。所以评估时不能拿单次结果说事。我的做法是对同一批日期重复跑多次,看结论的分布。如果某一天五次跑出来三次看多两次看空,那说明这个日期上的信息本身就是矛盾的,这本身也是个有价值的信息——它告诉你这个决策点的不确定性很高,应该谨慎处理,而不是让系统硬给一个方向。
5. 想真正用起来,还得补哪几块
框架本身跑通只是起点。从"能跑"到"能用",中间还差几块基础设施,这部分往往比调提示词更重要。
5.1 数据层与缓存:先解决"重复拉同一份报表"
多智能体流程有个天然特征:**多个角色会需要同一份数据。**基本面分析师要财报,新闻分析师可能也需要财报里的某个数字,交易员还要再确认一次。如果没有缓存层,同一个接口会被反复打。
我的做法是在数据获取层统一加一层缓存,按"数据类型 + 标的 + 日期"做键。第一次拉取后落盘,后续直接读缓存。这一层加上之后,不仅成本下来了,流程的稳定性也明显提升——外部接口的抖动不再直接影响流程执行。
另一个建议是把数据获取和数据处理分开。工具函数只负责拿原始数据,格式化、指标计算这些放到独立的处理层。这样做的好处是,当你想换数据源时,只需要改写获取层,下游逻辑完全不用动。我在换过一次数据源之后才明白这个分层有多值。
5.2 评估体系:收益曲线不是唯一的尺子
这是我最想强调的一点。用一个多智能体系统生成决策,如果你只用"最终收益"来评估它,那你几乎学不到任何东西——因为收益是结果,而你需要优化的是过程。
我会从四个维度分开看:
- 方向命中率:决策方向与后续实际走势的一致比例。这是最基础的指标,但要按不同市场环境分组统计,否则会被单边行情掩盖。
- 论证质量:报告里引用的数据点是否真实存在、是否被正确解读。这个可以抽样人工核查,也可以用一个独立的模型做交叉验证。
- 辩论有效性:多空辩论是否真的产生了新的论据,还是只是在换措辞重复。如果第二轮的发言和第一轮高度相似,说明辩论机制没起作用。
- 成本与延迟:单次决策的调用次数、耗时、花费。这是工程可行性指标,容易被忽略但很关键。
把这四项分开看之后,你才能定位问题到底出在流程设计、提示词质量,还是数据本身。只看收益曲线的话,你永远不知道该怎么改。
5.3 它适合谁、不适合谁
跑了一段时间之后,我对这个框架的适用边界有了比较清楚的认识。
适合的场景:单标的的深度研究辅助,比如你想对某家公司形成一份多方视角的研究备忘录;教学和研究场景,用来观察多智能体协作在复杂推理任务上的行为特征;作为投研流程的一个环节,生成讨论材料供人参考。它的核心价值在于把一个问题的多个侧面同时摆到桌面上,这在人工研究里需要几个人花几天才能做到。
不适合的场景:全市场大范围扫描,因为单次决策的成本摆在那里,几百个标的跑一遍不现实;高频场景,多轮模型调用的延迟决定了它做不了分钟级的响应;直接对接自动执行,把决策生成和资金操作直接连起来,这个跨度太大了,中间缺少足够的验证环节。
还有一点必须说清楚:**这套系统的输出是研究材料,不是投资建议。**它生成的每一段文字都建立在大模型的推断之上,存在事实错误和逻辑跳跃的可能。把它当成一个能提问题的讨论伙伴,比当成一个能给答案的决策者,要理性得多。
最后分享一个我折腾很久才想明白的体会。我一开始总想把系统调成"每次都给出一致且明确的方向",后来发现这个目标本身就是错的。这套框架最大的价值不是给你一个更准的答案,而是把不确定性显式地摆出来——让多空双方都有机会说话,让风控有机会说"如果错了怎么办",让最终决策必须面对"哪些信息我其实不知道"。当某天五次运行给出不同结论时,它其实在告诉你这个决策点本身就很难判断。承认这一点,比强行让模型给出一个确定答案,要有价值得多。