年初有朋友问我,天天折腾AI,有没有让AI直接告诉他明天买什么股票。我当场给他否了:大模型直接预测涨跌,和抛硬币没什么本质区别,它只是把随机性包装成一套看似缜密的逻辑。真正让我觉得有价值的是另一个方向——既然投研圈每天都在靠"多空辩论"来逼近真相,为什么不让多个AI也吵起来?于是我搭了一套会辩论的A股分析系统:一个多头Agent负责找逻辑,一个空头Agent负责挑毛病,一个裁判Agent负责裁决。三个人设针对同一只股票展开三轮互驳,最后输出一份带风险清单的结论。这套东西跑了小半年,我自己最大的感受是:它不会告诉你明天涨还是跌,但能帮你把该质疑的地方都提前摆到桌面上。这篇文章就把整套系统的架构、Prompt、踩坑和实测结果完整拆给你。
1. 为什么我做的不是"预测AI",而是"辩论AI"
1.1 单模型预测的致命伤:一本正经地胡说八道
先从最核心的问题说起:为什么我不能接受"一个AI直接给涨跌结论"?
大模型本质上是一个语言模型,它的训练目标是"生成看起来合理连贯的文本",而不是"对金融市场负责"。你让它预测明天涨跌,它会怎么做?它会为了维持一个自信可靠的人设,先编一个结论,再倒推一套听起来无比合理的逻辑链,甚至不惜伪造数据。我早期踩过一个坑:问一个通用大模型某家小市值公司的营收情况,它非常笃定地给出一串数字,还附带"根据公司年报"这种表述。后来我去翻了原始财报,发现那串数字是两年前的,中间还混进了一个完全不存在的分项指标。
这种"幻觉式自信"在单模型预测场景里最致命,因为你会下意识地把AI给出的中间论据当成真实信息去吸收。如果你没有做交叉验证的习惯,这些编造的数据就会变成你的投资依据。而且更麻烦的是,单模型只会给你一条单向逻辑链,它不会自己反驳自己。你看到的是一个观点,而不是一场讨论。
1.2 辩论本质上是在复刻投研圈的"多空对抗"
为什么"辩论"这个思路能解决上面的问题?
真实世界里的投研不是一个人拍板的。卖方研究报告有买入评级也有卖出评级,买方团队里更是专门养着一批"抬杠的人"。券商研究员提出一个看多逻辑,基金经理的第一反应往往是让风控或者另一组研究员去找这个逻辑里的漏洞。这种多空对抗的机制,本质上是在用竞争关系逼近真相:你不是要一个观点,你是要让相互冲突的观点暴露彼此的隐含假设。
AI Agent落地到这个领域,正好就是这种思路。不过不是让一个模型"模拟多个声音",而是真的在系统里创建多个独立角色,各自负责自己的视角。这就是业内常说的多智能体协作,或者叫Multi-Agent Debate。学术界早就验证过:让两个模型互相辩论、质疑对方的推理过程,比单个模型直接输出答案在事实性和推理质量上都有显著提升。原因是辩论迫使模型必须不断核查自己引用的依据,不能光靠训练记忆里的统计规律蒙混过关。
我实际跑下来之后,发现这套机制在A股这种信息噪音极大的市场里尤其合适。A股的核心矛盾不是"没有信息",而是"信息太多、口径太杂、角度太乱"。你需要的是一个能帮你把冗余信息打散、把互相矛盾的点拎出来对峙的工具,而不是一个拍脑袋的"预测器"。
2. 多头Agent、空头Agent和裁判:三巨头怎么分工
2.1 为什么一定是三个角色,不能一个Agent干完所有事
有人问过我:大模型本身就能理解多空两种观点,你把它拆成三个独立Agent,有什么本质区别吗?
说实话,我最初也这么想。后来我做了一组A/B对比:在同一个对话里,让AI"先提出看多逻辑,再提出看空逻辑",结果它输出的看空部分明显在给看多部分让路——语气软、攻击点模糊、甚至自己把自己反驳掉了。问题出在上下文污染:同一个上下文窗口里,先进入的观点会对后面的生成产生强烈的锚定效应。
拆成独立Agent之后,效果完全不同。多头Agent看不到空头Agent内部的思考链,它只能看到对方的公开观点,这样它的反驳才是针对论据的,而不是顺着对方话头滑坡。而且每个Agent都有独立的角色人设和历史,对抗性会强很多。
裁判Agent更不能省。如果让多头或空头来总结,一定会偏心;如果让同一个Agent既辩论又裁定,它会倾向于维护自己前面说过的观点。所以我的底线配置是三个角色,一个都不能少。以下是它们的职责划分。
| 角色 | 核心任务 | 说话风格 | 典型思维方式 |
|---|---|---|---|
| 多头Agent | 挖掘做多逻辑,寻找预期差 | 乐观、积极、但必须论据充分 | 从行业景气度、财报质量、估值、催化事件找依据 |
| 空头Agent | 攻击多方逻辑,提示风险 | 苛刻、挑剔、专门盯着逻辑裂缝 | 逐条拆解多方论据,检查数据口径,寻找被忽视的利空 |
| 裁判Agent | 整理论点,做出裁决 | 中性、克制、强调风险和置信度 | 把双方论据映射到同一框架,标注未证实数据,输出结构化结论 |
2.2 数据包怎么喂:行情、财报与公告的格式化处理
辩论不能光靠AI的记忆,必须给它"当下能拿到的最新数据"。我选的数据源是akshare这类开源接口,可以拉取个股近几个季度的财务摘要、近几十个交易日的日线行情、最近的公告标题。这里有一个极其关键的设计原则:数据包里的信息必须有明确的截止日期。
为什么要标注截止日期?因为A股市场最危险的事情之一就是"用明天才发布的数据指导今天的决策"。如果数据包里混入了一批未来信息,AI会把它当作已知事实,辩论再精彩也是空中楼阁。所以在生成数据包时,我会严格把快照日期截断在实盘时间之前。
典型的单个数据包长这样,我直接给出结构示例:
【数据包:标的600XXX | 数据截止:2025-01-15】 一、近四季度核心财务摘要 2024Q3:营收12.34亿(同比+8.2%),归母净利1.87亿(同比+12.5%),毛利率34.6% 2024Q2:营收11.95亿(同比+7.1%),归母净利1.69亿(同比+9.8%),毛利率33.9% ... 二、近20个交易日日线行情 01-15 收盘 8.25,涨跌幅 -0.72%,成交额 2.31亿 01-14 收盘 8.31,涨跌幅 +1.96%,成交额 2.78亿 ... 三、近期公告标题列表 2025-01-10:关于公司部分董事减持股份的预披露公告 2024-12-28:关于子公司签订重大销售合同的公告 ...这些内容全部转成纯文本塞进Prompt。不要给AI看K线图截图,它的多模态能力在这种精细数字分析和逻辑对抗里帮不上忙,反而容易引入视觉幻觉。
2.3 人设Prompt的写法:别只说"你是空头",要给它攻击框架
这是我最想分享的细节之一。很多人写角色提示词,只会写"你是一名专业的空头分析师,请对以下股票提出看空理由"。这种Prompt跑出来的结果就是垃圾——空头Agent会流于套路化输出:"该股面临宏观经济不确定性""行业竞争加剧风险",全是正确的废话。
我给每个角色都规定了一套思考框架。以多头Agent的系统提示词为例:
你是一位深度价值型买方研究员,对A股中盘股有十年跟踪经验。你的任务是对给定标的提出尽可能扎实的做多逻辑。 你必须从以下四个维度寻找依据,每个维度都必须引用数据包中的具体数据,禁止空泛表述: 1. 行业景气度:行业处于周期哪个位置?当前价格是否隐含了过度悲观预期? 2. 财报质量:毛利率、净利率、现金流、应收账款的变动趋势是否互相印证? 3. 估值分位:当前PE/PB处于近三年的什么分位,是否存在预期差? 4. 催化事件:近期公告或行业数据是否提供了潜在的向上催化? 如果某个维度数据包中缺失,必须明确输出"该维度数据缺失",不得编造。空头Agent的Prompt则完全不同,我给它设置了对抗逻辑:
你是一位以严格著称的量化风控研究员,专门负责拆解多头逻辑。你的任务不是自己编利空,而是逐条审查对方的看多依据。 你必须执行以下操作: 1. 检查数据口径:多头引用的财务数据是否匹配正确的报告期?增长率是否算错了基数?毛利率变化是否受非经常性损益干扰? 2. 寻找数据矛盾:用数据包中的另一项数据直接对抗对方引用的数据,比如营收增长但经营性现金流恶化。 3. 暴露隐含假设:对方说"毛利率提升说明产品力增强",你要追问是否可能是低价原材料库存带来的短期幻觉。 4. 指出幸存者偏差:对方拿单一成功案例做类比时,你要用数据包里的整体数据拆台。你会发现,空头Agent的工作不是"唱反调",而是"做审计"。它攻击的是论据的可靠性,而不是立场本身。这个区别至关重要。当对抗建立在事实核查层面,辩论的产出才有真实参考价值。
3. 三轮辩论的完整链路:从开题到裁决
3.1 辩论流程:定题、开题、互驳、总结、裁决
整体流程我设定为五步。首先是定题,也就是明确当前要分析哪只标的、数据截止到哪一天。然后是开题,多头和空头各自基于同一份数据包给出初始观点,这一步两个Agent可以并行调用,省时间。接着进入互驳轮,把双方第一轮的完整输出同时粘贴进对方的上下文,让它们针对具体论据逐条回击。再往下是总结轮,双方做最终陈述,重点必须回应"你上一轮没有回答的反驳"。最后是裁判裁决,裁判Agent查看整场辩论记录,不看任何一方的主观结论,只依据论据本身做结构化判断。
关键的对抗信息传递是通过上下文拼接实现的。每一轮Prompt的构造逻辑是:
- 第一轮:系统人设 + 数据包
- 第二轮:系统人设 + 数据包 + 对方第一轮完整发言 + "请逐条反驳对方的论点,并指出对方使用数据时的错误"
- 第三轮:系统人设 + 数据包 + 对方前两轮完整发言 + "请做最终陈述,明确回应此前你尚未回应过的质疑,如果对方指出你的数据错误,必须承认并重新评估你的观点"
这里有个容易忽略的点:不要让Agent看到整场辩论的全部历史,那会超出它的有效注意范围。我做了个折中——第二轮让它只看对方上一轮发言,第三轮才让它看对方前两轮的浓缩版本。信息量逐步释放,对抗性反而更强。
3.2 上下文管理与Prompt拼接:让AI记住"对方说了什么"
直接上代码骨架,我用Python写的核心调度逻辑:
import asyncio async def run_debate(stock_data_pack: str, bull_prompt: str, bear_prompt: str, judge_prompt: str): # 第一轮:并行开题 bull_round1, bear_round1 = await asyncio.gather( call_llm(bull_prompt + stock_data_pack, temperature=0.7), call_llm(bear_prompt + stock_data_pack, temperature=0.7) ) # 第二轮:互驳,把对方第一轮发言喂进去 bull_round2 = await call_llm( bull_prompt + stock_data_pack + "\n\n【对方第一轮观点】\n" + bear_round1 + "\n请逐条反驳对方论点,并指出对方数据使用错误。", temperature=0.7 ) bear_round2 = await call_llm( bear_prompt + stock_data_pack + "\n\n【对方第一轮观点】\n" + bull_round1 + "\n请逐条反驳对方论点,并指出对方数据使用错误。", temperature=0.7 ) # 第三轮:最终陈述 bull_final = await call_llm( bull_prompt + stock_data_pack + "\n\n【对方前两轮观点】\n" + bear_round1 + "\n" + bear_round2 + "\n请做最终陈述,回应所有未回应的质疑。", temperature=0.7 ) bear_final = await call_llm( bear_prompt + stock_data_pack + "\n\n【对方前两轮观点】\n" + bull_round1 + "\n" + bull_round2 + "\n请做最终陈述,回应所有未回应的质疑。", temperature=0.7 ) debate_record = "\n\n".join([ "【多头第一轮】\n" + bull_round1, "【空头第一轮】\n" + bear_round1, "【多头第二轮】\n" + bull_round2, "【空头第二轮】\n" + bear_round2, "【多头最终陈述】\n" + bull_final, "【空头最终陈述】\n" + bear_final, ]) # 裁判裁决:低温度保证输出稳定 verdict = await call_llm( judge_prompt + stock_data_pack + "\n\n【完整辩论记录】\n" + debate_record, temperature=0.2 ) return verdict这里有两个参数我重点说一下。辩论阶段temperature设0.7,是为了允许模型在反驳时发散,不要偷懒顺着对方逻辑滑坡;裁判阶段设0.2,是为了语义输出稳定,尽量保证同一套数据每次跑出来的裁决风格一致。至于为什么是三轮而不是五轮,我看过五轮的实测效果:从第三轮开始,双方基本都在重复已经表达过的论据,新增信息量骤减,而token消耗还在线性上涨。三轮是边际收益最合适的点。
3.3 裁决输出的结构化设计:结论、置信度与风险清单
裁判的输出不能是一段散文,必须是结构化数据,否则没法自动化对接下游工作流。我设计的输出格式如下:
{ "标的": "600XXX", "数据截止日期": "2025-01-15", "结论类别": "中性偏多", "置信度": "中", "核心逻辑": "毛利率连续三个季度改善,但同期应收账款增速高于营收增速,持续性待验证", "风险清单": [ "应收账款周转天数上升,需关注下游回款质量", "近期股东减持公告可能压制短期估值", "行业竞争加剧导致毛利率改善不可持续" ], "需要人工复核的数据": [ "2024Q3经营性现金流具体数值(数据包未提供)", "最新股东减持数量和价格区间(公告标题未披露细节)" ] }这个结构是我跑了几十次之后迭代出来的。早期裁判只会给一个"偏多"或者"偏空"的单词,完全没有可用性。后来我强制要求JSON Schema输出,才真正把它接进后续的自动化工单流程。尤其"风险清单"和"需要人工复核的数据"这两个字段,价值远远大于"结论类别"——因为决策者最需要的不是一句模棱两可的判断,而是一份"我在拍板之前必须搞清楚什么"的清单。
4. 跑了两百多次实测后,高光与翻车我都给你列清楚
4.1 高光时刻:AI揪出一个被市场忽略的财报细节
有一个案例让我对这系统的印象彻底改观。某家消费类公司,市场当时的主流叙事是"需求疲软、增长乏力",估值被压到近三年低位。多头Agent在辩论中提出一个角度:虽然营收增速放缓,但毛利率连续三个季度回升,而且回升幅度逐季加大,说明产品结构在改善。空头Agent立刻反击:毛利率回升可能只是提价效果,如果销量在下跌,那这种改善就是不可持续的。
这里出现了一个我没想到的转折。到第三轮,多头Agent补充了库存数据:期末库存周转天数在持续下降。这个数据点正好回应了空头的质疑——如果提价导致滞销,库存周转天数应该上升而不是下降。库存下降和毛利率回升同时出现,说明公司确实在卖掉更贵的产品,而不是单纯靠压库存撑报表。裁判最终给出"中性偏多"的裁决,并把"下一季度销量数据"列为人工复核重点。
这个案例让我明白了一件事:它真正的价值不是做出精准预测,而是把多个孤立指标组合成了一个完整证据链。市场当时讨论这家公司的人,大多数只盯着营收增速这一个指标,没人把毛利率、库存周转和估值分位串起来看。AI做完了串联工作,等于帮我建立了一个"市场尚未充分讨论"的分析框架。
4.2 翻车现场:AI们集体误判的两种情况
高光时刻归高光时刻,翻车的时候也不少,而且翻车的模式很固定。
第一种翻车是"陈旧数据陷阱"。某次分析一家制造业公司,当时公司已经在盘后发了重大合同公告,但我抓数据的时间点还没更新这个信息。结果三个Agent一本正经地围绕旧数据辩论,多头说"在手订单充足",空头说"增长缺乏支撑",裁判还给出了中等置信度的偏多结论。第二天公告落地,股价直接高开,整个辩论完全失效。这个问题的根源在于:Agent对数据新鲜度没有感知能力,你必须从工程层面保证输入永远是最新的。
第二种翻车更隐蔽,叫"乐观情绪的传染"。我发现当大盘连续走强、市场情绪被彻底点燃的那段时间,空头Agent的攻击强度明显下降。它会说"虽然存在一定风险,但当前市场趋势向好,短期不改乐观判断"——这种话术根本不是空头该说的话,它被多头的话术带偏了。我查了很多轮辩论记录,规律是:当数据包里出现连续阳线的行情信息时,空头Agent的反驳力度会被系统性削弱。后来我在裁判阶段加入了一个硬约束:要求裁判必须检查多空双方论据数量是否平衡,如果某一方的论据数量明显偏少,就强制下调那一方的置信度。这个规则上线后,乐观情绪传染的问题改善了很多。
4.3 正确使用姿势:把辩论结论当"检查清单"而不是"指令"
实测跑了大半年之后,我形成了自己的使用习惯。我基本不看"结论类别"这个字段,重点只看两样东西:一是"风险清单"里有没有我此前没考虑到的风险点,如果有,我会花时间专门去研究那个风险对应的原始数据;二是"需要人工复核的数据"里列出的条目,这些就是AI明确告诉我"它没把握、希望人去确认"的地方。
这样做的原因是:任何基于公开数据的AI分析,本质上都无法获得超越市场平均的信息优势。它的最大价值在于"穷举角度"——把我没想到的风险、没注意的指标关联、没想过要验证的数据全部榨出来,逼着我在决策前把功课做完整。至于最终的买不买、买多少,我从来都是自己拍板。如果你把AI的辩论结论当成操作指令,那是把工具用错了方向。
5. 成本、延迟与幻觉:部署这套系统时踩过的三个坑
5.1 一次完整辩论的成本账:token到底烧在哪
先算一笔成本账。一次完整的辩论流程包含6次Agent调用(两个角色各三轮)加1次裁判调用。数据包大约800 token,系统人设大约600 token,关键是辩论历史会逐轮累积。第一轮Prompt大约1500 token,第二轮因为拼接了对方发言,涨到约3000 token,第三轮约4500 token。两个Agent三轮加起来,输入部分大概18000 token,输出部分按照每轮600 token计算,约5400 token,裁判还要额外读一遍完整辩论记录。
所以一次完整辩论大约消耗2.5万到3万token。按主流商用模型的大致价格(输入约2元每百万token,输出约10元每百万token)去估算,单次成本在0.1元到0.2元之间。这个成本其实很低,但有个陷阱:如果每个Agent的输出不加限制,让它洋洋洒洒写两千字,一次辩论能轻松烧到5万token以上。我的解决办法是在Prompt里强制限制输出长度:"每个维度不超过三句话,总体不超过600字"。效果非常明显,成本直接砍掉近一半。
5.2 响应延迟与工程优化:怎么把3分钟压到40秒
A股盘中时间是宝贵的,3分钟的等待基本宣判了工具只能盘后用。第一版系统串行跑完一轮,耗时接近3分钟,我完全接受不了。做了三个优化之后,压缩到了40到60秒。
第一个优化是开题轮并行化,用asyncio让多头和空头同时发起调用。第二个优化是历史压缩——之前第二轮和第三轮会把对方所有发言原文拼接进去,上下文越来越长、生成越来越慢。现在我在第二轮的Prompt里让一个独立的文本摘要Agent先把对方上一轮发言压缩成四个要点,再喂给对方,输入规模直接减少一半。第三个优化是输出流式打印,虽然总的生成时间没变,但用户的感知等待时间大幅缩短。实测下来,盘中看盘间隙刷新一次分析是完全来得及的。
5.3 幻觉治理:让AI学会说"我这里没有数据"
最后是每个做AI分析的人都会撞上的幻觉问题。我总结了三板斧。第一板斧是强制数据追溯:凡是在辩论中引用财务数据,必须标注报告期;凡是没有明确来源的数据,一律视为无效论据。第二板斧是缺失字段声明:Prompt里白纸黑字写明"如果数据包中不包含某维度数据,必须输出'该维度数据缺失',禁止根据训练记忆补充具体数字"。第三板斧是裁判预审:裁判在输出裁决之前,先执行"事实核查指令",把辩论记录中所有无法在当前数据包里溯源的数据标成"未证实"。
这三板斧下来,我的实测幻觉率从早期的每轮至少出现一两次,降到现在的偶尔出现一次。而且即使出现,也会在裁判阶段被单独标出来,不会混进决策依据里。
6. 如果你也想复刻一套,我把经验浓缩成这几条
6.1 起步姿势:先做双Agent对抗,再加裁判
如果你想照着这个思路做一套自己的系统,我的建议是先别急着搭三个Agent的完整架构。先做最简版:一个多头Agent加一个空头Agent,只跑两轮互驳,不设裁判,直接把双方的辩论记录输出成文本,先读几天原始记录,感受一下对抗质量和数据引用规范。等你摸清两个角色在同一份数据包下的行为模式,再去加裁判Agent。原因很简单:裁判Prompt的质量取决于你对前两个角色输出风格的熟悉程度。你都没见过它们平时怎么吵,你没法设计出一个能裁定输赢的规则。
6.2 回测优先:用历史数据验证辩论质量
任何金融AI工具上线之前都必须先跑历史回测。我的做法是:把两年前的行情快照和数据包重新喂进系统,让Agent完全只基于当时能获得的信息辩论,然后拿后视镜里的真实走势去对照辩论结论的方向。这里要特别强调数据窗口切割,确保你喂给AI的每一个数据包都不包含任何"未来信息",否则回测结果就是一场自欺欺人的表演。建议至少跑50个标的样本再统计正确率和误判模式,三五个案例说明不了任何问题。
6.3 最后的大实话:AI给的是"讨论质量",不是"印钞能力"
很多人听到"AI+炒股",第一反应是"能不能帮我稳定赚钱"。我得把话说得很直接:做不到,任何声称能做到的人都是在骗你。这套辩论系统真正帮我的是另一件事——它让我的决策过程不再依赖单一视角。A股的信息噪音大、情绪摆动剧烈,你很容易被市场主叙事带着走,丢掉独立判断。有了这套系统之后,我在每次决策前都强制获得了一场高密度对抗思考:多头视角怎么想、空头视角怎么拆、哪些数据被忽略了、哪些逻辑其实站不住脚。这才是它最值钱的地方。至于最终按不按结论动手,永远是人的责任,AI只是把该摆上桌面的问题都摆齐了。我的建议是:动手之前,先认真问自己一句——如果最坏情况发生,我还能不能接受?能,再说别的。