你在一个 AI 投放助手里输入一句话:「帮我看看计划 A 最近怎么回事,消耗越来越高,效果越来越差。」
它不会立刻回答你。
它会先去查数据。查一次还不够,可能查完总消耗,又查分素材,再对比行业均值。查了好几轮,最后才告诉你:问题出在哪。
这篇文章就做一件事:跟踪你那句话发出去之后的完整旅程。它怎么被”听懂”,数据怎么被查出来,结论怎么一步步得出来,中间哪些环节会出错、出了错会怎样。
先交代一个前提,后面全靠它:模型本身不会查数据。它只会做一件事——读一段文字,生成下一段文字。所以整个旅程的本质是:一个只会读写的”大脑”,配上一套替它跑腿的机制。这套机制叫 Agent Loop,智能体循环。
第一站:先把”记忆”发给模型
你的那句话发出去后,系统做的第一件事不是回答,而是把它放进一份对话历史里,然后整份发给模型。
为什么要整份重发?因为模型没有记忆。它不记得你 30 秒前说过什么,更别说昨天。每次调用都是第一次见面,必须把前情提要全部塞给它。
模型像一个每天失忆的顾问。你每次找他,都得把之前的谈话记录重新给他看一遍,他才能接上话。
这个特点不是小事。如果历史发漏了——比如漏了你上周说过的”只看计划 A”——模型可能转头就去查计划 B。失忆的代价就是答非所问。
所以,对话历史是这场旅程的地基。模型每做一轮判断,都要把更新后的历史重新读一遍。
第二站:模型说”我要查数据”
模型读完历史,没有直接回答,而是返回一句:我要调用消耗查询工具,查计划 A 近 7 天数据。
注意,模型只是”说”要查,它自己不会查。它输出的只是一段结构化的文字:工具名,加参数。真正去查的,是外面那层循环代码。模型是大脑,循环是手脚。
这一轮,模型可能不止查一个东西。它说”顺便再查下行业均值”。一轮两个调用,回来两条结果。
问题来了:两条结果,哪条是计划 A 的消耗,哪条是行业均值?
每条工具结果都带一个编号,跟发起调用的那句话一一对应。没有这个编号,”计划 A 消耗”和”行业均值”就会送错,后面基于数据的诊断全错。
这就像快递单号。同时寄出两个包裹,回来的两件货必须贴单才知道谁是谁。对号这件事,是刚需,不是优雅设计。
第三站:查到的结果去了哪
循环执行完工具,拿到结果——比如”7 天消耗 12 万,环比涨 38%”——然后把这条结果追加进对话历史,再次把整份历史发给模型。
这一步叫写回。它是整个循环最容易被忽视、也最要命的一步。
模型下一轮能”知道”查询结果,唯一途径就是结果出现在它重读的历史里。不写回,查了等于白查,模型下一轮还在问:数据呢?
到这里,一个完整的圈转完了:发历史 → 模型说要查 → 真的去查 → 结果写回 → 再发历史。
agent 的”智能”,就是靠这个圈一圈圈转出来的。第二轮,模型读到消耗数据,可能说”再查下分素材的数据”,于是再转一圈。第三轮,读到素材 X 的 CPM 涨了 40%,它说”问题找到了”,不再调用工具。
旅程结束,结论给你。

第四站:循环什么时候停下来
刚才说,转到第三圈模型”说完了”,旅程结束。这里其实藏着两个问题:循环怎么知道模型说完了?万一模型一直不肯说完呢?
先看第一个。模型每次回答完,都会附带一句”我为什么停下来”:想调工具,还是说完了。循环拿它当红绿灯——想调工具就接着转,说完了就收工。
再看第二个。万一模型判断失误,一直”再查一下”,循环就永远停不下来,钱和时间都在烧。所以需要一个兜底:一次模型调用算一个 iteration,默认最多 90 次。这就是那脚刹车。
有意思的是,这个限制叫”预算”而不叫”上限”。因为它不是一个静态计数器,而是一份可以消耗、可以共享的资源。
共享是什么意思?假如这次诊断中,主 agent 派了一个子 agent 去拉 30 天的长周期数据。子 agent 花掉的调用次数,是从主 agent 的 90 次里扣的,不是另外再领一份。主 agent 自己用了 10 次,子 agent 用了 15 次,主 agent 就从剩下的 65 次接着干活。
这个设计一口气推出三个结论:不管派多少层子 agent,总成本封顶在 90;层数再多也不会指数级烧钱;父子在同一个钱包里抢资源,模型被迫把钱花在刀刃上。
做产品的同学可以直接抄这个设计。给 agent 产品设计计费时,“一个任务一个共享钱包”比”每次调用单独算”更贴近工程现实,也更容易向客户解释成本。

后台:内部记录和发给模型的,是两份
到这里,旅程的主线讲完了。但有个后台环节值得单独看一眼。
前面我一直说”把整份历史发给模型”,其实不完全准确。系统内部存的历史,和实际发给模型的,是两份东西。
内部那份是底稿,什么都记,包括模型的思考过程、token 统计这些调试信息。排查问题时全靠它,信息越全越好。
发出去那份是誊写后的信。把模型看不懂、也不需要看的内部字段剥掉,再把 system prompt(人设、规则、工具说明)拼在最前面。
为什么必须分两份?算笔账:一条模型回复带着 500 token 的思考过程,不剥掉,每轮都原样发出去,十轮对话光这几条就多烧几千 token。而且多余字段发给 API,轻则浪费,重则直接报错。
system prompt 也是同理。它每次调用时临时拼在最前面,不存进历史。否则它会被持久化、被每轮重发几十份。
底稿像日记,什么都写;寄出的信像工作邮件,只写对方需要知道的。这个“内部字段不出系统边界”的分层意识,在任何 API 设计里都成立。

基建:让循环在多平台跑得起
到目前为止,讲的是单次对话。但真实产品里,这个循环要同时服务终端、Telegram、飞书等十几个平台,还要控制成本。这需要三个基建决策。
第一个:循环主体用同步写,异步工具走桥。
八成工具——读写文件、跑命令——本来就是同步的。少数工具,比如网络请求、浏览器操作,是异步的。如果为了少数派把整个循环改成异步,所有同步工具都得白包一层,报错堆栈变深,调试难受。
所以选择是:循环保持同步,遇到异步工具,就交给一个常驻的事件循环去跑。这座桥不能临时搭。想象 agent 在广告后台连续翻页拉报表,浏览器登录态得一直保持。桥一拆,连接就断,下一轮得重新登录。
第二个:agent 实例复用,而不是每条消息新建。
多平台入口下,每条消息都新建一个 agent 实例很浪费。真实做法是按配置签名缓存复用——模型、密钥、工具集没变,就接着用旧的。只有重置会话、换模型时才淘汰。
深层原因是钱。模型厂商的缓存机制要求 system prompt 在多轮之间保持不变才能命中,命中就意味着更便宜更快。实例复用,system prompt 就不变,缓存就一直命中。
但比实现更重要的是一条铁律:对话历史每次从数据库传入,实例随时可能被淘汰重建。代码不许依赖实例”活着”。
第三个:续聊时,system prompt 读回旧的,不重新组装。
继续一个老会话时,直接从数据库把当初那份 system prompt 读回来。为什么不重新拼一份?因为重新拼的可能不一样——记忆文件中途被改了一行,新拼的就和旧会话对不上,缓存当场失效。
这里藏着一个真实的工程拉扯:记忆要更新,缓存要不变。两头都要,就得在架构上做取舍。这个拉扯,后面讲记忆系统的那篇会展开。
三个决策放一起看,产品上的启示只有一句:会话状态全部外置,实例本身无状态。这是 agent 产品能水平扩展、能多端同步的架构前提。哪天你想做”手机上聊一半,电脑上接着聊”,靠的就是这个。
复盘:六个岗位,一张表
整趟旅程走完了。回头看,agent 能干活,靠的是六个岗位各就各位:
| 岗位 | 谁干的 | 出事会怎样 |
|---|---|---|
| 大脑 | 模型:读历史、做决策 | 没有它,agent 是空壳 |
| 记忆 | 对话历史:每轮整份重发 | 漏了,模型失忆、答非所问 |
| 手和眼睛 | 工具调用:真的去查数据 | 没有它,agent 只会空谈 |
| 汇报 | 结果写回:放回历史 | 漏了,查了等于白查 |
| 刹车 | 停止原因 + 迭代预算 | 没有它,要么中断要么烧钱 |
| 分拣员 | 底稿与寄信分离 | 不分,报错或白烧 token |
这张表可以存下来。以后不管是自己写 agent,还是评审别人的方案,六个岗位挨个问一遍,比泛泛地问”你们 agent 稳不稳”有用得多。
最后,三个能带走的判断。
一,鉴别真假 agent。拿到任何 agent 产品,先问它的循环在哪。模型说完”我要查”之后,有没有一层代码真的去查、把结果喂回去?找不到这层,就是 prompt 套壳。
二,计费设计抄作业。共享钱包式的预算模型可以直接搬进产品方案:一个任务一个预算,子任务从父任务里扣,总成本天然封顶。
三,扩展性的前提。会话状态外置,实例无状态,历史落库。多端同步、水平扩容,都靠这个地基。
下一篇,我们拆开”手和眼睛”这个岗位,看看一个生产级 agent 的工具系统是怎么注册、怎么分发的。
