← 返回
IT技术

我实测了只存记忆不学习的Agent:2000轮后差距摆在这

✍️ zhirenhun 📅 2026/10/15 👁 101 阅读 ⏱ 17 分钟
我实测了只存记忆不学习的Agent:2000轮后差距摆在这

我实测了只存记忆不学习的Agent:2000轮后差距摆在这

今天刷 dev.to 热榜,看到一篇《Memory Isn't Learning: Why AI Agents Keep Making the Same Mistakes》排在前面,评论区一堆人附和“记忆就是 Agent 的全部”。这个说法我一直不太服气:记忆只是把过去发生的事存下来,学习是根据反馈修正策略,这两件事在工程上根本不是一回事。光说不练没意思,我决定亲手做一个最小实验,把“只存记忆”和“持续学习”两种 Agent 放到同一个环境里比一比,看看差距到底有多大。

我选的环境是多臂老虎机,因为它足够简单,简单到所有变量都摊在桌面上——每个动作的真实胜率是隐藏的,Agent 只能通过“拉一次、看一次结果”来积累信息。这个设定其实和很多线上 Agent 场景很像:你只能通过真实交互发现哪个策略好,而且每一次试错都有成本。下面是我搭的实验和跑出来的结果。

热榜上的说法

那篇热榜文章的核心论点大致是:很多 Agent 框架把“记住了”当成了“学会了”。Agent 把历史对话、工具调用结果、用户偏好都塞进记忆库,下次检索出来照着用,但从不根据新的反馈修正自己的行为模式。听起来挺有道理,但文章没给任何量化证据,全是定性描述和几个案例截图。

我不服的点在于:如果记忆真的接近学习,那在一个有噪声的环境里,一个“把早期经验刻死了”的 Agent 和一个“持续用反馈修正”的 Agent,长期收益应该差不多。如果差得多,说明记忆和学习之间有条鸿沟;如果差不多,那热榜那篇就是在贩卖焦虑。这就是我想验证的命题。

实验设计与代码

环境设定:5 个动作(臂),隐藏的真实胜率分别是 0.1、0.3、0.5、0.7、0.9,最优臂是第 4 个。每局 2000 轮,重复 200 个 trial 取平均。冻结型 Agent 的行为是:前 20 轮每个臂探测 4 次,把结果记下来,之后永远根据这份冻结的记忆选臂,记忆不再更新。学习型 Agent 用同样一份记忆,但每个反馈都写回去,探索率从 0.4 逐渐衰减到 0.05。代码如下:

import random
from collections import Counter

random.seed(42)
ARMS = [0.1, 0.3, 0.5, 0.7, 0.9]   # hidden true win rates of 5 actions
BEST_I = ARMS.index(max(ARMS))
ROUNDS, TRIALS = 2000, 200

def pull(a):
    return 1.0 if random.random() < ARMS[a] else 0.0

def frozen_agent():
    # memorizes only the first 20 pulls, then replays frozen memory forever
    mem = [[0.0, 0] for _ in range(5)]  # [win_sum, pulls]
    total = 0.0
    for t in range(ROUNDS):
        if t < 20:
            a, keep = t % 5, True      # brief probe: 4 samples per arm
        else:
            a = max(range(5), key=lambda i: mem[i][0]/mem[i][1] if mem[i][1] else 0)
            keep = False               # memory never updates again
        r = pull(a)
        total += r
        if keep:
            mem[a][0] += r
            mem[a][1] += 1
    final = max(range(5), key=lambda i: mem[i][0]/mem[i][1] if mem[i][1] else 0)
    return total, final

def learning_agent():
    # same memory, but it keeps updating; exploration decays over time
    wins, pulls = [0.0]*5, [0]*5
    total = 0.0
    late = late_best = 0
    for t in range(ROUNDS):
        eps = max(0.05, 0.4 - t / ROUNDS * 0.35)
        if random.random() < eps:
            a = random.randrange(5)
        else:
            a = max(range(5), key=lambda i: wins[i]/pulls[i] if pulls[i] else 1.0)
        r = pull(a)
        total += r
        wins[a] += r
        pulls[a] += 1
        if t >= ROUNDS - 500:
            late += 1
            late_best += (a == BEST_I)
    return total, late_best / late

f_tot = l_tot = l_late = 0.0
f_dist = Counter()
for _ in range(TRIALS):
    tf, ff = frozen_agent()
    tl, lb = learning_agent()
    f_tot += tf
    l_tot += tl
    l_late += lb
    f_dist[ff] += 1

f_avg, l_avg = f_tot / TRIALS, l_tot / TRIALS
ceil = ROUNDS * max(ARMS)
f_reg = (ceil - f_avg) / ceil * 100
l_reg = (ceil - l_avg) / ceil * 100
l_pct = l_late / TRIALS * 100

print('=== Memory vs Learning: 5-arm bandit, %d rounds x %d trials ===' % (ROUNDS, TRIALS))
print('Hidden arm win rates:', ARMS, ' best = arm %d (%.1f)' % (BEST_I, max(ARMS)))
print('Frozen-memory agent : avg reward %.3f | regret %5.1f%%' % (f_avg, f_reg))
print('Learning agent      : avg reward %.3f | regret %5.1f%%' % (l_avg, l_reg))
print('Frozen agent ended on best arm in %d/%d trials (%.0f%%)' % (f_dist[BEST_I], TRIALS, f_dist[BEST_I]/TRIALS*100))
print('Frozen final-arm distribution:', dict(sorted(f_dist.items())))
print('Learning agent hit best arm %.1f%% of the time in last 500 rounds' % l_pct)
print('Gap: learning agent earns %.0f%% more reward per round' % ((l_avg/f_avg-1)*100))

关键点在于冻结型 Agent 每个臂只采样 4 次。在胜率 0.9 的臂上,4 次里很可能出现 2 次失败;在胜率 0.7 的臂上也可能 4 次全中。噪声完全可能把排序搞反,而冻结型 Agent 对此毫无纠正能力。学习型 Agent 则会在后续轮次里不断用新数据稀释早期噪声。我把完整脚本跑了一遍,输出如下。

真实运行结果

实验真实运行输出

数字先摆出来。冻结型 Agent 2000 轮平均拿到 1504.985 的总奖励,regret 是 16.4%;学习型 Agent 平均 1616.850,regret 是 10.2%。换算下来,学习型 Agent 每轮多赚 7% 的奖励。更扎眼的是冻结型 Agent 的最终落点:200 个 trial 里只有 96 个(48%)锁在了最优的 arm 4 上,剩下的 104 个 trial 全部锁死在错误的臂上——其中 69 个锁在 arm 3,29 个锁在 arm 2,甚至有 1 个锁在最差的 arm 0、5 个锁在 arm 1。

作为对照,学习型 Agent 在最后 500 轮里有 92.4% 的时间选的是最优臂。这两组数字放在一起,热榜那篇文章的定性判断基本被我的实验坐实了:记忆本身不构成学习。冻结型 Agent 把前 20 轮那 4 次采样的噪声永久固化成了“经验”,之后 1980 轮都在为这个错误买单,而且它自己永远不知道。

反直觉发现与局限

真正出乎我意料的是奖励差距只有 7%,而不是我预想的 20% 以上。原因看最终臂分布就明白:104 个锁错的 trial 里,绝大多数(69 个)锁在了胜率 0.7 的 arm 3 上,和最优臂只差 0.2。所以虽然过半的 trial 犯了错,平均损失被“错得不离谱”稀释了。但换个角度想,这在真实业务里更危险——Agent 看起来表现还行,你根本察觉不到它锁死在次优策略上,这种隐性损失比明显翻车难排查得多。

这个实验的局限我也得老实交代。第一,每个臂只采样 4 次是我自己定的,如果把探测期拉长到 50 次,冻结型 Agent 的落点分布会好看很多,“记忆 vs 学习”的差距会缩小——所以这个结论对“探测预算稀缺”的场景最成立。第二,我用的是 eps-greedy 这种最朴素的学习算法,没有上 UCB 或 Thompson Sampling,学习型 Agent 的 10.2% regret 其实还有很大优化空间。第三,环境是非平稳的,200 个 trial 共享 random.seed(42),噪声序列是同一条,这会让方差的估计偏乐观。第四,真实 Agent 的动作空间远不止 5 个,臂越多、噪声越大,冻结记忆的代价只会更夸张,但这个推断需要另外的实验支撑,我没有跑。

我的结论

实验没有翻车,结论和热榜文章的方向一致,但我给了一个它没给的量化刻度:在这套设定下,冻结记忆的 Agent 有 52% 的概率永久锁死在错误臂上,其中 1/200 的运气差的甚至锁在胜率 0.1 的最差臂上;而持续更新策略的 Agent 后期 92.4% 的时间都在最优臂上。7% 的每轮收益差距,在一个只有 5 个动作、差异明显的环境里就能拉开,放到上百个工具、胜率差异更细微的真实场景,这个差距只会被放大。

落到具体建议上:如果你在维护一个带记忆的 Agent,至少做一件事——让记忆里的条目带上“验证次数”和“最近一次被现实反驳的时间”,定期用新反馈重估旧结论,而不是无条件检索回放。记忆是缓存,学习是缓存失效策略,只有前者没有后者的系统,迟早会把某次噪声采样当成真理跑到底。要不要给这个实验加上概念漂移(中途偷偷交换臂的胜率)再测一轮,我还在犹豫,感兴趣的话可以在评论区催我。

——

广告 广告
🧑‍💻

zhirenhun

一个热爱技术的程序员,喜欢分享前沿AI知识和开发经验。

AIAgents 强化学习 多臂老虎机 实验复现