Files
blog/content/posts/forgot-who-it-is.md
T

4.5 KiB

title, description, date, draft, tags
title description date draft tags
它忘了自己是谁 会话重置清空了 4036 条历史之后,执行 Agent 拿管理员的身份建了单。根因不是权限漏洞,是更隐蔽的东西:它对「我是谁」的全部感知,建立在会被重启抹掉的对话记忆上。 2026-09-02T18:40:00+08:00 false
AI Agent
架构
身份
事故复盘

事故:五笔张冠李戴的审计记录

一次会话重置,清空了某执行 Agent 的 4036 条对话历史。紧接着它处理建单请求时,做了件危险的事:操作人参数填了管理员——建单、审核、修改、派单,五笔操作全部挂在错误的用户名下,直接污染了操作审计库。

排查权限体系:没有漏洞。代码逻辑:也是对的。问题出在一个更隐蔽的地方。

根因:它的「我是谁」是幻觉

两层反直觉的事实:

1. 它对身份的全部感知,来自对话记忆。 会话没重置时,历史消息里出现过"我是谁",它就照着办;历史一清空,这个认知就跟着消失。之前 13 天里它还往自己的记忆库塞了上千条客户手机号——「记忆」这个东西在 Agent 身上,既不可靠也不安全

2. 运维文档里写着「从会话头部读用户 ID」——这是一条幻觉规则。 文档假设了一个不存在的能力:框架压根没把用户 ID 拼进系统提示(实测相关钩子触发 0 次)。规则写得再清楚,读不到的信息就是不存在。

排查方向还被纠偏过一次:一开始在翻框架源码找拼接逻辑,用户一句「别翻源码,直接验证」——把真实消息跑一遍,看系统提示里到底有什么。答案:没有身份。

修复:五版补丁的演进

既然框架没给,那就框架来给。补丁迭代了五版,每一版都在教我们一件事:

  • v1 在消息通道层加身份前缀 → 私聊有效,群聊不覆盖
  • v2 群聊场景三重判断 → 补上群聊
  • v3 修幂等时发现诡异现象:同一条消息出现双前缀——消息处理管线把同一条消息构建了两次,两个通道各注入一次
  • v4 注入点迁移到「每请求单次必经路径」——从根上消除重复
  • v5 最终形态:在构建 Agent 的系统提示里写强指令(查成员映射表 → 显式传操作人 → 禁止猜测默认值),且身份信息不进对话历史——每请求重新构建,不累积

v5 还配了升级体检脚本:框架每次更新后自动检查补丁在位,防止悄悄丢失。

重启后第一个真实建单请求,操作人参数自动填对了。闭环。

同一天,它还「假装干了活」

身份只是今天 Agent 不可控性的其中一面。同一天另外三起,像四张面孔的同一个人:

  • 日报推送了两次。Agent 第一次明明执行成功,却误判「输出被截断疑似失败」,自作主张「再跑一次拿完整输出」——重复推送到工作群。修复不是改 Agent 的判断,是给脚本加当日去重标记:推过就不再推
  • 巡检连续六次超时。LLM 流式响应无首包时,并发信号量的槽不释放;定时任务的 120 秒超时只杀调用方,杀不掉底层挂死的流——并发池卡死。处置:超时放宽到 600 秒 + 这类任务迁移到系统级 crontab 直调脚本
  • 假运行第三例。两个定时任务状态显示 success,实际从未真跑(文本型任务发到空会话,无人执行)——这正是上周 Agent 记忆污染反弹的根因:调度系统以为每天在清理,实际一天都没跑过

戒律

  1. 身份必须在系统提示里。 对话记忆会丢(重启/重置/压缩),文档规则可能依赖不存在的能力。凡「每次请求都必须成立」的东西,走框架的单次必经路径注入
  2. 执行真相只看业务日志。 调度层说 success、Agent 回复了文本,都不等于脚本跑了。有没有开始/结束记录、写没写数据,以业务侧为准
  3. 幂等必须在脚本层。 Agent 会误判、会重试、会「验证性重跑」——推送类脚本一律加当日去重,不能指望上层永远判断正确
  4. 验证要实证,不要读码。 「框架应该会拼进去」和「实际拼进去了」之间,隔着一整个生产事故

Agent 的记忆、身份、甚至进程生死,都托管在基础设施手里。凡是丢不起的,都别存在它的脑子里。


本文已脱敏,不含真实用户名、工单号、域名或系统内部标识。