
前阵子我把一只科技类ETF的走势数据直接丢给 DeepSeek问它未来一周趋势怎么看。回答倒是结构清晰但仔细一读就发现不对味指标解释头头是道最终结论却永远是“若放量突破则看多若失守支撑则看空”这种两头堵。多试几只标的之后我彻底意识到单模型聊天窗口承担不了完整的决策分析任务于是动手拆了一个股票趋势分析多Agent系统。这篇文章就是我的完整实践笔记从架构、Prompt、数据校验到回测踩坑全部摊开讲给想用大模型做量化投研辅助的朋友一条能少走弯路的参考路径。1. 为什么我把“单模型对话”拆成了五个Agent先说结论多Agent不是为了炫技而是因为单模型对话在股票趋势分析这个场景里存在四个我无法忍受的缺陷。1.1 单模型做趋势判断的四个致命缺陷第一上下文过载。股票趋势分析要同时看K线形态、均线排列、成交量能、MACD和RSI、近期财报、行业新闻这些数据全塞进一次对话模型注意力会被严重稀释。我实测过一个很典型的现象给DeepSeek同时喂了60根日K线和10条行业新闻它盯着新闻写了大量分析K线部分却只泛泛说“趋势偏强”连关键支撑位都没标出来。不是模型能力不行是我这个用法本身就有问题。第二角色漂移。同一个模型既当数据员、又当分析师、还要当风险审核员它自己很难切换角色。最常见的结果就是它把“客观指标计算”和“主观判断”混在一个回答里明明前面刚算出RSI72属于超买后面却因为消息面偏暖直接给出“继续看涨”的结论。这在单轮对话里非常常见模型为了回答连贯会把相互矛盾的逻辑强行圆回来。第三幻觉校验缺失。让模型“算一下20日年化波动率”它经常给你一个像模像样的“约15%”。我拿脚本一算实际是23.6%。为什么会差这么多因为模型在凭印象生成数字而不是真去执行计算。更危险的是指标算错之后所有后续分析都建立在错误数值上而且单模型对话模式下你很难定位是哪一步错的。第四决策不可追溯。我常需要复盘“为什么昨天系统给出了看多的判断”单模型对话回答完就结束了没有中间产物没有置信度没有风险标记。你只能看到一句结论中间的依据全靠它自己说完全没法审计。1.2 多Agent的思路不是堆模型而是拆角色我最后定下来的方案很朴素把原来一个模型干完的活拆成五个专职Agent每个Agent只负责一个环节输入输出都定义成严格的结构化JSON。整个链路是消息面信息Agent抓新闻和公告 → 数据处理Agent清洗行情数据 → 特征计算Agent算技术指标 → 趋势研判Agent基于指标输出观点 → 风险复核Agent做压力测试和矛盾检查 → 报告生成Agent汇总成自然语言报告。每个Agent都用DeepSeek来驱动但用的是不同角色设定和不同的工具权限。数据类Agent基本不“思考”只做清洗和计算结果必须由工具函数落地研判类Agent只做判断不允许自己编造指标风险Agent专门负责给前一个Agent泼冷水。这就是我理解的多Agent系统——把模糊的大需求拆成一个个可验证的步骤每个步骤的输出都能检查、能纠错、能量化。2. 系统整体架构与Agent分工边界整个系统我用Python搭建没有引入重型流程编排框架而是自己写了一个不到200行的任务调度器。核心思路是“状态机”每个Agent是一个节点节点之间传递标准化消息包前一个节点的输出schema校验通过才允许进入下一个节点。2.1 五个Agent的分工表Agent名称输入输出核心职责消息面归纳Agent新闻标题、公告摘要、板块涨跌榜事件热度列表、相关标的传导路径过滤噪音识别可能影响趋势的事件信号数据处理Agent原始行情快照标准K线DataFrame、数据质量报告复权处理、缺失值补全、去除异常跳变特征计算Agent标准K线DataFrame技术指标表、趋势结构标签用脚本计算指标禁止模型心算任何数值趋势研判Agent技术指标表、资金流向摘要、事件信号结构化观点方向/置信度/关键价位给出可解释的分析逻辑必须引用指标数值风险复核Agent趋势观点、历史波动参数、持仓成本信息风险等级、最大回撤预估、矛盾信号列表专门挑刺输出“可以跟、可以轻仓、必须观望”三类建议报告生成Agent所有上游输出最终趋势分析报告把结构化结果转成自然语言保留置信度说明注意我把Agent数量定在五个没有继续膨胀是因为每个Agent的职责边界必须足够清晰。曾经试过加一个“资金流分析Agent”和一个“情绪量化Agent”结果它们和消息面Agent职能重叠报告里经常出现互相矛盾的表述。后来干脆合并让消息面Agent顺带输出资金流信号。2.2 调度器一张流程图背后的顺序依赖调度器的规则很简单消息面Agent和数据处理Agent可以并行它们不依赖彼此特征计算Agent必须等数据处理Agent完成趋势研判Agent要等特征计算和消息面归纳都完成风险复核Agent和报告生成Agent串行收尾。实际编码时我用一个队列和依赖计数器实现每个消息包里有task_id、upstream_tasks、payload、schema_version。上一环节通过校验后下游任务的依赖计数器减一减到零才会被调度执行。别小看这个机制它保证了一点系统某一次分析用了错误数据我能从流水日志里精确看到是哪个上游节点产出的坏数据而不是整盘推翻。这里有个我特别想强调的细节Agent之间的消息包必须自带schema_version。因为我在迭代过程中改过三四次指标字段格式比如最早MACD的hist字段叫histogram后来改成macd_hist。如果下游Agent还在读旧字段运行时不报错但会拿到一堆None。线上系统最怕这种静默失败字段版本号就是用来防这个的。2.3 数据层复权方式不一致会直接导致分析翻车数据处理Agent里最容易翻车的是复权。A股和ETF行情通常有前复权、后复权、不复权三种。我一开始图省事直接用不复权数据结果在分红除权日K线图出现一个巨大的跳空缺口均线系统全乱套趋势研判Agent据此给出了错误的“破位下跌”信号。后来我定了一条死规矩做趋势分析、画均线、算MACD全部用前复权数据做历史回测计算真实收益率用后复权数据两种数据在消息包里用adjust_type字段显式标注下游使用前必须检查这个字段。之所以这样是因为前复权数据保持最新价格连续适合看当前形态后复权数据保持历史真实涨跌幅适合算策略表现。两者混用是一切指标分析失灵的头号元凶。3. Prompt设计、工具调用与防幻觉落地这一部分是整个系统能不能稳定输出的关键。模型本身能力再强如果Prompt不把“边界”和“动作”约束清楚输出质量就会飘忽不定。3.1 趋势研判Agent的Prompt模板我给趋势研判Agent设计了一套固定模板核心是限制它的“信源”和“动作”。以下是简化后的版本我在实际项目里保存为prompt_trend_judge.txt每次调用都会组装进去。你是股票趋势研判分析师。你只能基于输入给你的结构化工具有限数据做分析严禁自行回忆任何行情数据。 约束 1. 所有指标数值都以参数数据表中的值为准禁止心算或估计。 2. 如果某些指标缺失或异常必须明确写missing并标注“数据不足无法判断”禁止用假设值补全。 3. 你的输出必须是JSON包含direction(up/down/range)、confidence(0到100的整数)、key_levels(最多三个关键价位)、logic_chain(至少三条每条必须引用具体指标值)。 4. 禁止给出买卖指令只允许描述趋势状态和风险条件。 5. 当你发现指标信号互相矛盾时direction必须输出range并在logic_chain中说明矛盾点。这段Prompt最有价值的是第5条把“矛盾时输出震荡”变成硬性规则而不是让模型自己临场发挥。加了这一条之后双子信号下的胡说八道明显减少。3.2 我用“双轨制”彻底杜绝模型算数前面提到模型心算数值非常不靠谱所以我做了一个硬性规定指标计算类Agent一律不给模型计算权限指标全部用脚本算好模型只做“解读”。具体做法是特征计算Agent不调用DeepSeek而是直接执行一段pandas计算逻辑算出MA5、MA10、MA20、MACD、RSI(14)、ATR、量比、近20日最大回撤等一批指标然后把这张指标表当作趋势研判Agent的输入。趋势研判Agent看不到原始K线只能看到指标表。这样即便模型想编一个MA5的数值它也没有原始数据支撑只能引用我传过去的真值。但万一模型仍然编数字怎么办我还有最后一层保险报告生成Agent在输出最终置信度时会由调度器做一个字段交叉校验凡是在logic_chain里出现的数值必须在指标表中存在。这个校验逻辑只有十来行代码但真实拦截过两次模型自己编支撑位的情况。比如模型写“支撑位在10.5元附近”我查遍指标表根本没有10.5这个数字报告直接被打回重写。3.3 工具调用的设计模型只做选择计算交给函数消息面Agent和数据处理Agent需要用工具调用能力。我给DeepSeek定义了三个工具函数get_news_keywords(symbol, date): 获取某标的相关新闻的热词及情绪标签。fetch_kline(symbol, period, adjust_type): 拉取K线并做指定复权处理。calculate_basic_stats(df): 计算标准差、最大回撤、收益率等基础统计值。工具调用格式用的就是标准的函数调用协议返回结果会放进消息上下文里模型只能基于返回结果总结。举一个工具定义示例方便你直接复刻思路{ name: calculate_basic_stats, description: 计算输入DataFrame的基础统计指标返回JSON, parameters: { type: object, properties: { df: {type: object, description: 标准K线DataFrame包含close、volume、date字段}, metrics: {type: array, items: {type: string}, description: 需要计算的指标名列表} }, required: [df, metrics] } }设计这个工具调用的核心原则是模型负责“决定要算什么”函数负责“真实去算”最终结果由函数返回。这一步能做到后面所有防幻觉手段才算有地基。4. 回测方案与实测过程中的坑系统能跑通是一回事判断靠不靠谱又是另一回事。我给自己定的规矩是任何Agent输出的分析结论先回测再小仓位观察绝不上来就大仓跟随。4.1 回测必须防“未来函数”我最早做回测时踩了一个典型的大坑用某指标筛选历史信号时不小心在指标计算里用了全样本数据做归一化相当于让模型在“当时”就看到了“未来”的统计分布。回测结果漂亮得离谱连续三个月胜率超八成。直到我把特征计算改成逐日滚动计算胜率直接掉到五成多才意识到之前的回测是假的。正确的做法是指标只能用截止当天的数据计算消息面Signal只能使用该时间点之前已公开的信息。我在代码里用了一个严格的时间戳游标ensure_no_future_data函数会检查特征计算窗口的截止日期是否等于信号生成日期。这个函数是回测可信度的守门员。另外回测数据要分成三段训练段做参数调整验证段做模型选择样本外段做最终验收。我习惯用7:2:1的比例样本外段只跑一次拿到结果就算数不再回头调任何参数。很多人都挂在“样本外表现不好于是回头调参再跑一次”这个循环上这本质上就是过拟合。4.2 我实测过的一个真实案例信号矛盾时保持观望在回测和观察期里我拿一只宽基ETF做了连续两周的模拟记录。某天价格站上20日均线MACD金叉消息面有一条行业利好所有指标都偏多。单模型如果看到这些大概率直接给“看涨”。但我的趋势研判Agent在logic_chain里又捕捉到一个矛盾信号RSI指标已经接近72且量能没有同步放大。按照Prompt第5条的硬性规则它最终输出了“震荡方向不明”的结论风险复核Agent将风险等级标记为“中高”给出的建议是“未持仓者观望持仓者降低仓位”。结果后续五个交易日标的果然进入横盘缩量还温和跌了不到1%。这次系统没有用它选到大牛股但它避开了无数个“看着要突破、一进去就被套”的假突破陷阱。这套系统的价值不在于预测单日涨跌而在于它能结构性地呈现风险信号并且在多个维度信号冲突时敢于输出“不知道”和“观望”。很多人忽略这个能力但对趋势分析而言识别“不该交易的时间段”比识别“该交易的标的”更重要。4.3 踩过的技术坑时间戳与时区错位除了未来函数还有一个非常隐蔽的坑K线数据的时间戳时区问题。我拉到的数据时间是北京时间但脚本用Python的datetime处理时默认是本地时区有一次部署在服务器上因为系统时区被设置成UTC所有日期整体偏移了八小时。导致的结果是特征计算Agent的“截至今天”实际截到了“明天”于是系统拿到了未来数据回测结果虚高。排查了很久才发现这个低级错误。现在我的所有时间处理全部用带时区的时间戳并且入库前统一转成UTC存储到展示层再转北京时间。时区问题听起来不像AI项目该踩的坑但在股票趋势分析里它和模型幻觉一样危险。5. Token成本、延迟优化与后续扩展方向完成后我测了一下整体资源消耗。一次全流程分析大约消耗1.8万个tokens其中趋势研判Agent和报告生成Agent占了大头数据处理Agent几乎不消耗大模型调用。整体耗时90秒左右其中一半花在消息面数据抓取和指标计算上模型推理大约20秒。5.1 省钱又提速的三个优化手段第一个手段是压缩输入。趋势研判Agent不需要看几百行K线数据我改成只传最近60个交易日的收盘价序列以及已经算好的20个技术指标输入规模直接缩了一半模型理解效果反而更好。第二个手段是给消息面Agent设置关键词过滤只有热度超过阈值的事件才进研判链路大多数噪音新闻根本传不到下游。第三个手段是缓存中间结果同一标的同一天的指标表命中缓存后可以跳过整个特征计算Agent直接把结果放在缓存里读对复盘历史信号特别有用。我计算过加了缓存之后同一标的的重复分析成本能降到原来的四成左右。这个经验对做长期运行服务的人很关键因为单个标的的成本看起来不高但一旦把这个系统跑成每天几十个标的的批处理token成本就会涨得很快。5.2 后续我想扩展的Agent方向目前这个系统还停留在“单标的趋势分析”阶段后续我想加两个Agent。一个是板块轮动Agent专门输出当前市场哪些板块资金在流入、哪些在流出为单标的分析提供上下文另一个是宏观因子Agent把无风险利率、汇率、市场情绪指数等宏观变量算成风险调整项塞进风险复核Agent的输入里。不过我不会轻易加。每多一个Agent就多一条出错链路和一份token成本。加Agent的前提一定是它能回答一个明确的问题而不是为了把架构做得更复杂。唯一我会马上去做的事情是把现在所有Agent的输出都落盘保存成trace.json这样每次分析都能完整回溯从原始数据到最终报告每一步中间产物都能查。这套系统做下来我最深的感受是多Agent的价值不在“多”而在“隔”。把数据分析的脏活、趋势判断的虚活、风险复核的挑刺活、报告输出的整理活分开让每一步都有清晰边界和可验证的格式整个系统的可用性就上来了。最后再分享一个实操小技巧每次跑完系统打开trace.json看一眼最后一个Agent的最终输出同时往前翻一步看看趋势研判Agent的原始JSON。你会发现很多最终报告里的“高级表述”其实都来自一个特别朴素的判断逻辑。真正做到可解释、可追溯才是多Agent系统最值钱的地方。