Agent 循环:感知、决策、执行,每一步都会出错
- 把「AI 自己干活」这件事拆成感知、决策、执行三段,看到一个出错的结果能大致定位是哪一段坏的
- 说清每段各自的典型故障:脏数据与过期数据、幻觉与过度自信、重复执行与漏确认,以及为什么执行段的错最贵
- 理解为什么严肃项目要把「授权」这类动作做成代码结构上的边界,而不是写在提示词里的一句叮嘱
你可能已经见过这种东西了:你说一句「帮我看看这家公司最近怎么样」,它不是直接回答你,而是先停一下,去查了一次行情,又去拉了一份公告,中间还算了几个比率,最后才给你一段结论。整个过程有进度条,能看到它在干什么。
这比一问一答的聊天框高级多了。但它高级在哪,很多人说不清楚。说不清楚的后果是:当它给出一个错的结论,你不知道该怀疑哪一环。
这一节就干一件事——把这套「自己干活」的流程拆开,然后逐段告诉你,每一段最容易在什么地方坏掉。
先说人话:它就是个会自己跑腿的助理
我们从一个完全不带技术的画面开始。
假设你请了个助理,你交代他一件事:「帮我看看这家公司最近怎么样。」
一个只会聊天的人,会坐在原地凭记忆跟你说一通。一个会跑腿的助理不一样,他会这样干:
先出门。去交易所网站抄一遍最近的价格,去公司官网下最新的公告,回来把材料摊在桌上——这一步叫看。
然后坐下来想。手里这堆材料说明了什么,还缺哪份东西,要不要再跑一趟——这一步叫想。
想明白了就动手。要么再出门补材料,要么把结论写下来交给你,要么——如果你给了他这个权限——去把某件事办掉——这一步叫做。
关键在于:这三步不是走一遍就完,是一圈一圈转的。 做完一件事,材料变多了,他又回到「看」,重新想,再决定下一步做什么。直到他觉得事情办完了,才停下来跟你交代。
这个「看—想—做」的圈,就是所谓的智能体循环。智能体,就是能自己调工具、分几步把一件事做完的程序,不是只会一问一答的聊天框。它每转一圈,都会向外面的世界要一次东西(这叫工具调用,就是程序替它去执行一个查行情、读文件、算数之类的具体动作),也都会往自己的记事本上添一笔。
投资层:为什么这三段的错,代价完全不一样
对做投研的人来说,这个拆分不是知识点,是一张排错地图。
看错了,是最便宜也最难发现的一种错。 助理抄价格的时候抄的是三天前那一栏,或者他压根没抄到、回来编了一个。你拿到的报告结构完整、逻辑通顺,只是底下的地基是歪的。这种错不会当场爆炸,它会安安静静地穿过后面所有环节,最后变成一个你信了的结论。
想错了,是最容易被你原谅的一种错。 因为它写得漂亮。一段既讲了行业又讲了估值、还带风险提示的分析,读起来跟真的一样。你很难在读的时候意识到,其中某个具体数字它其实没查过。
做错了,是唯一会立刻花掉真钱的一种错。 前两段错了,损失的是你的判断质量;这一段错了,损失的可能是账户余额。同一个下单动作发出去两遍,你的仓位就是你以为的两倍;该等你确认的地方没等,你连拦一下的机会都没有。
所以往下看的时候,请带着这个尺度:三段的容错要求,是从松到紧、成倍收紧的。 任何一个把这三段一视同仁对待的系统,都是危险的。
机制层:这个圈到底是怎么转起来的
技术上,这套东西的骨架很朴素。
程序把你的问题、以及一份「你手上有哪些工具」的说明书,一起交给模型。模型不直接给答案,它回一句话:我要调用某个工具,参数是这些。程序真的去调,把返回结果原样塞回对话里,再问模型一次:现在呢?模型看完新材料,要么再点一个工具,要么说「我讲完了」。
这段对话历史,就是它的全部记忆,业内叫上下文。 它没有别的记事本。这一点后面会反复用到,因为大量诡异的故障都来自这个记事本被动过手脚。
在 Vibe-Trading 这个开源项目里,这个循环被写在一个叫主循环的文件里,文件开头就交代了它有多少层机制在管这个记事本——从「悄悄把旧的工具结果清掉」,到「把长文本掐头去尾留个中段省略」,到「花一次模型调用把前面的内容压成摘要」,一共分了好几层,按记事本的膨胀程度依次触发。
为什么要压?因为记事本装不下。它一圈一圈往里塞材料,总有塞爆的时候。压缩是必需的。但也正是这个必需的动作,制造了下面要讲的一大类故障。
感知段的三种坏法
一、数据是旧的,而它不知道
最常见的一种。系统在任务开始的时候抓一次行情快照塞进去,之后这一趟跑多久,用的都是那一份。跑五分钟没事,跑一个小时,那份「最近行情」就已经不是最近了。
这个问题在 Vibe-Trading 的注入模块里被作者自己写进了残余风险清单——只在启动时抓一次,跑得久了就旧了。他给的理由很实在:这仍然严格好过让模型用训练语料里的价格。注意这是一个两害相权,不是一个解决方案。
对投研来说,这件事和量化里那个老问题是同构的:你以为你在用某个时刻能拿到的信息,实际上用的是另一个时刻的。区别只在于,量化里的时点数据问题至少可以被检查,而 agent 循环里数据的新鲜度往往根本没被记录下来。想补这块直觉,可以看概念库里的 时点数据。
二、工具其实失败了,但看起来像成功
这个更阴。
工具返回的是一段文本。请求超时了、接口改了字段、账号没权限,这些情况返回的也是一段文本。如果没人专门去分辨,模型会把「抱歉,未找到该标的」这句话当成一份材料读进去,然后基于「未找到」继续往下推理——或者更糟,绕过它去凭印象补一个数。
严肃实现会专门写一个判断函数干这件事。Vibe-Trading 里就有一个,专门去解析返回值里的状态字段,命中「错误」「失败」「已取消」这几类,或者成功标记是假,就判定这次调用没成。这么一个不起眼的小函数,挡的是「把失败当数据吃下去」这类事故。
三、材料被压缩没了,但它以为还在
这是最反直觉的一种,也是最值得你记住的一种。
前面说过,记事本会被压缩。压缩的时候,早先那些工具返回的长结果会被清空,只留一句占位。问题来了:模型的对话历史里,还留着它当初「我要调用某工具」的那一句。动作还在,结果没了。
这种一半有一半没有的状态,会让后续调用直接报错。所以 Vibe-Trading 里专门有一段代码做「配对修复」:把找不到发起动作的结果删掉,把丢了结果的动作补一个桩上去。那个桩的内容,翻译过来大意是「这个结果来自更早的上下文,见上面的摘要」。
工程上这个补丁是必要的,不然循环根本转不下去。但你得看清它的副作用:从模型的视角看,它「查过」那份数据,只是内容变成了一句安慰话。 它很可能就顺着这句安慰话往下推,而它推出来的那个数字,你在报告里是看不出区别的。
这是一条很硬的经验:在一个跑得够久的 agent 里,「它说它查过」和「它手上真有那份数据」,是两件事。 这正是为什么严肃项目要额外做证据校验,把结论里的数字逐个拉回原始来源对一遍,具体做法见 幻觉与事实核验。
决策段的两种坏法
一、缺口会被自动补上
模型不会说「这里缺一个数,我停一下」。它会补一个。补出来的东西格式正确、量级合理、读着很顺,唯独没有来源。
而且这件事有个规律:越是靠近「总结」的环节,编得越凶。 干活的环节手里有工具、有原始材料,编的动力小;负责汇总的环节只拿到几段文字,为了让报告显得完整,就会自己把空缺填上。放到人身上也一样——离一手材料越远的人,越容易说出精确但没来源的数字。
所以真正有效的约束不是叮嘱它「不要编」,而是要求它每个数字都得指出这是哪一次工具调用返回的,指不出来就必须删掉,或者明确标注这只是方向性判断、没有数据支撑。这条约束在同一个项目里被写成了硬规则,从一句话到一张委托单,中间隔着多少步 那篇会把这条链路拆得更细。
二、它不知道自己什么时候该停
循环得有个尽头。要么模型自己说「讲完了」,要么外面有个次数上限把它掐掉。
这两种停法都有毛病。它自己说讲完了,可能是真做完了,也可能是它转晕了、把一个半成品当成了成品;被外面掐掉,那报告就是截断的,而截断的报告读起来往往跟完整的一样通顺。
Vibe-Trading 里有一项配置管的就是「一个目标最多能自动续跑几轮」,它是从配置里读的,可以调。注意这类数字全都是当前默认值、可配置,重要的不是它设了几,而是这个设计承认了一件事:没有一个自动的、可靠的方式判断「事情办完了」。 判断权最终还是在你这儿。
执行段的三种坏法(也是最贵的一段)
一、同一个动作做了两遍
这是执行段的头号事故。
原因可以很平淡:一次调用超时了,程序按重试逻辑又发了一遍,而上一遍其实已经生效了。也可以很技术:循环里同一轮返回了好几个动作,程序并发去执行,其中两个撞在了一起。
严肃实现处理这件事的方式,是把工具分成两类。Vibe-Trading 的主循环在派活之前,会先把这一轮的调用切成批次:连着的只读工具打成一包并发跑,写类的工具一个一个串行跑。 只读的意思是这个动作只取东西不改东西,重复做一百遍结果都一样;写类的意思是它会改变外部状态,做两遍就是两次。
这个切分是整段代码里最值钱的一句设计。查行情可以一起查,改状态必须排队来。 落到投研上,这条线的位置很清楚:读取类的活儿放开手让它并发,任何会真正改变账户状态的动作,都必须回到最保守的路径上。
二、「叫停」不是立刻停
用户点了取消,是不是马上就停?
不是。在这个项目里,取消信号是在批次的边界被检查的:正在跑的那一批会跑完,只是不再启动新的。这个设计有它的道理——半路掐断反而更容易留下不一致的中间状态。
但你得把这个事实记牢:「我按了停止」和「它真的停了」之间有一段时间差,而这段时间差里能发生什么,取决于那一批里有什么动作。所以真正的安全阀不能是「出事了我去按停止」,而必须是事前的额度和权限设定。
三、该确认的地方没确认
这是三段里最需要讲清楚的一处。
一个能自己调工具的程序,理论上什么都能调。那么,能不能让它自己给自己开授权?
Vibe-Trading 的答案写在了代码注释里,态度非常硬。它把「写入授权」这件事做成一个刻意不是工具的函数:它不继承工具基类,所以工具注册表根本发现不了它;主循环里也没有任何一行代码引用它。唯一能写授权的路径,要求一个由用户界面产生的确认凭证,而这个凭证模型永远造不出来。注释里管这叫「命门不变式:这是结构性保证,不是提示词层面的保证」。
同一个文件里还有一处细节值得说:授权提案和授权本身被严格分开——提案只是「我建议这样」,存下来不产生任何权力;只有那个不是工具的函数才写真授权,而且写之前还要再核一遍这份提案是否仍然落在用户当初看到的额度上限内。作者在注释里甚至记录了一个曾经的隐患:额度字段在两边的拼写不一致,导致那次复核对某个字段形同虚设。
请把这两处合起来读。它们说明的是同一件事:「在提示词里写一句不许自己下单」是靠不住的。 提示词会被后续文本影响、会在上下文混乱时失效、会被绕过。真正的边界必须在代码结构上成立——想犯错都找不到入口。
这一段是全篇的重点,请不要读成操作指南。它讲的是为什么把执行权交出去这件事在工程上就极难做对:数据可能是旧的、结论可能是编的、停止键可能不即时生效。哪怕上面每一道闸门都装齐了,它挡住的也只是「系统故障导致的损失」,从来不包括「判断错误导致的损失」——后者没有任何技术手段能挡。把下单权交给任何自动系统之前该问自己哪些问题,见 把下单权交给 AI 之前,先问自己这几个问题。本站只讲机制与边界,不提供任何交易系统的搭建方案,也不认为这条路能带来收益。
三段的错会互相放大
单独看,每一段的故障率都不算高。合起来就不是这么回事了。
感知段拿回一份三天前的价格,决策段基于它算出一个「明显低估」,执行段忠实地把这个判断变成动作。三段里没有任何一段觉得自己出错了:数据接口正常返回,模型正常推理,执行程序正常执行。整条链路上没有一个报警。
更麻烦的是事后。等你发现结论不对想回头查,中间那些工具返回的原始内容,可能早就在压缩里被清掉了。你能看到的只有一句「见上面的摘要」。
这就是为什么完整的执行轨迹比结论重要得多。 轨迹就是把每一轮它调了什么工具、传了什么参数、拿回什么结果,全部按顺序记下来的那份日志。同一个项目里,敏感字段在写进轨迹前还会先脱敏。有了这份东西,出问题至少能定位到是哪一段坏的;没有它,你面对的就是一个不可分析的黑箱。
顺带说一句对照:规则型的量化框架在这方面天然占便宜。像 freqtrade 那样,从信号到下单是一条固定的、写死的链路,同样的输入必然走同样的路径,坏了直接复现就行。agent 循环恰恰相反——它每次走的路都可能不一样,这正是它灵活的原因,也正是它难以排错的原因。这两件事是同一枚硬币。
你能拿走的几条判断标准
看到一个号称「AI 自动帮你做投研」的东西,不必去问它用了哪个模型,问这几个更有用:
它的数据是什么时候取的,能不能看到时间戳? 答不上来,感知段就是黑的。
结论里的每个数字,能不能点开看到出处? 只有结论没有轨迹,等于让你凭感觉信任一段生成文本。
它有没有区分「只读」和「会改变状态」的动作? 这两类混着跑的系统,重复执行是迟早的事。
授权是怎么给出去的,能不能限额、能不能撤回、撤回是不是立刻生效? 如果这些问题的答案是「你在设置里勾一下就行」,那这道闸门大概只存在于提示词里。
跑完之后有没有一份能复查的完整记录? 没有记录的自动化,出了事你连复盘都做不了。
这五个问题不需要你懂代码,但能筛掉相当一部分只做了表面功夫的东西。
小结
- 智能体就是能自己调工具、分几步把事做完的程序。它的骨架是一个「看—想—做」不断重复的圈,每转一圈就往对话历史里添一笔,而这份对话历史就是它的全部记忆。
- 三段的容错要求成倍收紧:看错了是安静的地基错误,想错了是好看的编造,做错了是唯一会立刻花掉真钱的。
- 感知段的三种坏法:数据是启动时抓的快照、跑久就旧;工具失败了但返回的也是文本,不专门判断就会被当成材料吃下去;记事本压缩会把旧结果清空只留占位,导致「它说它查过」和「它手上真有」变成两件事。
- 决策段的两种坏法:缺口会被自动补上而且越靠近总结环节编得越凶;以及没有可靠的办法判断「事情办完了」,停止条件本身就是不可靠的。
- 执行段的三种坏法:重试或并发导致同一动作做两遍(对策是只读并发、写类串行);取消信号在批次边界才生效,按下停止和真的停下之间有时间差;以及授权——真正的边界必须写在代码结构里,让模型根本够不着,而不是写在提示词里请它自觉。
- 完整的执行轨迹比结论重要得多。规则型系统坏了能复现,agent 每次走的路都不一样,没有轨迹就等于没有排错能力。
一句话记住这篇:它自己跑腿的每一步都可能出岔子,而这三步里,只有最后一步的错是要拿钱来还的。
本文所述机制来自上述源码快照的阅读,不是运行结果;文中涉及的参数均为当前默认值且可配置。本文为投资教育内容,只讲原理与边界,不构成任何投资建议,也不提供任何自动交易方案,完整边界见 免责声明。
本文为投资教育整理,关键数据与结论请结合下列权威来源验证。