LLM是无状态函数:AI记忆机制的本质与陷阱

LLM是无状态函数,AI'记忆'不过是调用方决定往消息数组里放什么的策略。
文章借一个四十行代码地图代理的踩坑经历,讲透了AI记忆的本质:大模型是无状态函数,每次调用只看到请求中携带的消息数组,端点根本不记得任何先前交互。作者用一个看似正确的bug说明这一点——代码构造临时消息列表发出去就丢,调用方列表从未增长。修复只需三行,核心是让调用方拥有并修改这份对话记录,且必须在同一函数里同时追加用户消息和助手回复,否则模型会收到一串没有答案的问题,表现得像推理能力很差。每次请求携带完整数组导致输入成本按 T·n(n+1)/2 三角形增长。文章给出三种策略——全部发送、摘要旧轮次、保留指针按需重读,并强调把对话记录写到磁盘是首要的可观测手段。
每个AI产品中的"记忆",本质上都是某个人在某处决定往数组里放什么。这个洞察来自一篇关于构建代码地图代理的系列技术文章,作者用一个四十行程序踩出的坑,把大模型记忆这件事讲透了。

一个看起来对的bug
作者写完四十行版本的代码地图工具后,让它读第二个文件并回答"这个文件和上一个什么关系"。模型反问:你说的是哪个文件?
第一反应是某个flag掉了、session id忘了传。于是花了远超预期的时间去找这个不存在的session id。结论很残酷:端点根本不知道90秒前调用过它,而且没有任何配置能改变这一点。
问题的根源藏在一段看起来完全正确的代码里。函数签名接收一个消息列表,返回回复,读起来像一段对话。但 messages + [...] 只是构建了一个临时列表发出去就丢了,调用方的列表从未被修改。每次调用都从同一个起点开始。
这段代码能通过代码审查,是因为类型注解暗示了"历史"的存在,你必须注意到列表从未增长。
没有会话,只有一个列表
修复只需要三行,核心思路是:调用方拥有这个列表。
第一行追加用户消息,中间调用模型,第三行追加助手的回复。函数故意修改传入的列表——只有一份对话记录,调用方持有它,每次追加都发生在一个可以打断点的函数里。
第二行追加是最容易漏掉的,而它的失败模式比没有记忆更糟糕。如果不追加助手回复,模型收到的是一串没有答案的问题——一段它似乎从未开口的对话记录。于是它会重新回答已经回答过的问题,推翻两轮前的结论,表现得像一个推理能力很差的模型。你会在重写系统提示词和初始指令上浪费一个晚上,才发现问题所在。
把两次追加放在同一个函数里,不是代码风格问题,而是消除"只记录了一半对话"这种状态。
每次请求携带完整数组,意味着第一轮在第二轮被重新计费,第三轮又被计费一次。
**无状态(Stateless)**是大模型API调用的一个基础特性:每次HTTP请求都是独立的,服务端不会为你保留任何跨请求的上下文,也不会自动把上一轮的用户消息和助手回复拼接到本次请求中。模型推理时接收的输入就是一个完整的消息数组,输出只是基于这个数组得到的一次纯计算结果,计算完成后服务端不保留该数组。这意味着所谓"多轮对话"完全是客户端通过反复发送增长中的数组伪造出来的效果。理解这一点非常关键:很多初学者会预设端点"记得"刚才说了什么,从而花时间去找并不存在的session id或隐式会话机制。事实是,只要调用方不在请求里带上历史,模型在物理上就无法看到历史。
你的智能体只有一份状态
因为模型是数组的纯函数,数组就是程序的完整状态。所以把它写到磁盘上。
这一行代码结束了main函数,transcript.json 进入 .gitignore。当输出出错时,你真正需要回答的问题不是"模型为什么这么说",而是"模型看到了什么"。只有一个产物能回答这个问题,现在它在磁盘上。
几乎所有在这个阶段追查的坏答案,三十秒内都能在文件里看到原因:某个文件从未被追加、源码因为路径相对于错误目录被读成空字符串、系统消息被后续赋值覆盖。这些都不是模型问题,但打开对话记录之前,它们看起来都像模型问题。
这还让运行变得可复现。输入是一个JSON数组,你可以逐字节重新发送,改一条消息再发一次。
账单是三角形,不是直线
每次调用携带整个数组,如果每轮大约增加 T 个token,第 n 次请求携带约 nT 个输入token,整轮运行的成本是 T·n(n+1)/2。十轮相当于五十五轮的输入量,二十轮是两百一十轮。
对于聊天助手这还能接受,因为一轮就是一句话。但对于读取源文件的智能体,每轮是一整个文件,T 极大,三角形在个位数轮次就变得可怕。
三种诚实的策略各有取舍:
- 全部发送:成本随轮次平方增长,适合短会话和学习阶段
- 摘要旧轮次:成本在阈值后持平,但丢失了当时不知道重要的细节,适合聊天场景
- 保留指针按需重读:成本持平加每次查找一次调用,适合内容在磁盘上且重读成本低的场景
对于代码库,第三种明显正确——仓库还在那里,重读一个文件就是一次磁盘读取。这也是为什么智能体最终需要自己获取内容,而不是被喂内容。
Token是大模型处理文本的基本单位,一个英文单词通常被切分成一到几个token,一个中文字符大约对应一到两个token。计费按输入token和输出token分别统计,本段讨论的主要是输入侧。所谓"三角形"增长来自两个叠加效应:一是每一轮都把之前所有轮次的消息重新发送一遍,二是随着轮数增加,单次请求里承载的历史越来越长。两者相乘就得到了 T·n(n+1)/2 的累加公式。这也解释了一个常见困惑:为什么一次看起来只有十轮的智能体会话,账单却像是跑了几十轮。在智能体读取源文件的场景下,T本身可能高达数千甚至上万token,三角形很快就从"可以接受"变成"不可承受"。
实践建议
- 把对话记录作为参数传递。一旦它变成对象上的隐藏属性,你就再也看不到自己发了什么。
- 在同一个函数里追加双方消息。让"只记录一半"的状态无法被表达。
- 每次运行都把数组写到磁盘,从第一天就开始。四行代码,是你很长一段时间内唯一的可观测手段。
- 在测试中断言角色顺序。检查两轮对话产生 system、user、assistant、user、assistant 的序列,能立刻抓住上面那个bug。
- 在能说清需要哪一列策略之前,不要装记忆库。三种方案都是一页代码,难的是选择,没有库能替你做这个决定。
"记忆"是一个产品词汇。它的每一种实现,都是关于往数组里放什么的策略。选好这个策略,是后续大部分工作的核心。
相关推荐

Claude Pro不含API权限?Max与Team计划新增API额度详解
Claude Pro订阅不含API访问权限,API需单独计费。但Max和Team计划现已包含每月API额度:Max 5x为100美元,Max 20x为200美元,Team每席位最高合计500美元。本文详解各档位额度、领取方式及对开发者的影响。

隔离环境实测35万星REA:4秒装完,但两个坑要当心
隔离实验室实测35万星开源逆向工程工具REA:4秒安装、15秒列出截图工具全部外联地址、梳理565个通信通道,同时暴露写入用户级设置与31个高风险工具权限两个坑,附三条安全使用规则。
逆向工程+AI Agent:几周克隆Adobe应用的技术真相
逆向工程+AI Agent:几周克隆Adobe应用的技术真相
一位开发者因Adobe提前取消费转向逆向工程,用AI Coding Agent几周内做出7款开源替代品。本文解析逆向工程原理、Reverse Engineer Anything这个MCP Server六天破10万星的原因,以及AI克隆应用在性能、专有数据和法律层面的真实边界。