LLM Agent记忆系统注入攻击:原理、测试与防御实践
2026/8/29 20:14:59 网站建设 项目流程

InjecMEM 这类针对 LLM Agent 记忆系统(Memory Systems)的注入攻击研究,最近在 Agent 安全相关的讨论里被反复提起。先说结论:它攻击的不是模型本身的推理能力,而是 Agent 在历史记录、向量检索、摘要记忆这条链路上对外部内容的过度信任。如果你正在用 LangChain、LlamaIndex 之类的框架搭 Agent,或者自己维护会话记录、向量库、长期记忆模块,这篇文章值得看完——它直接关系到你的 Agent 会不会在某个任务里突然执行一条被悄悄埋进记忆的指令。

我按“记忆系统怎么工作、攻击打在哪里、测试怎么看数据、防御怎么落地”这个顺序来拆。最后会给出一个我自己在项目里实际用过的加固顺序和排查清单。没有太多理论包装,都是工程视角。

1. 先把 Agent 的“记忆”拆开看:它到底在哪个环节被注入

1.1 记忆系统不是一块硬盘,而是多条链路叠加

很多人一开始会把 Agent 的“记忆”理解成一个数据库,或者一段很长的历史记录。实际工程里,记忆通常由好几层组成:

  • 上下文窗口内的工作记忆,也就是最近几轮对话和当前任务的临时状态。
  • 摘要型记忆,系统定期把长对话压缩成几条摘要。
  • 向量库记忆,把文档、消息、历史观察切块后写入向量数据库,检索时按相似度召回。
  • 结构化记忆,比如用户偏好、任务状态、实体关系,可能存在 SQLite、Redis 或一张普通表里。
  • 外部知识库或工具返回的结果,这部分经常被视为“环境信息”而不是“记忆”,但它同样会出现在后续提示词里。

攻击研究里说的“Memory Systems”,指的就是上面这些层的总和。InjecMEM 这类工作关注的核心,不是某一层单独有问题,而是这些层之间的数据流动没有做信任隔离。

我在实际项目里最常见的做法,是把记忆分为“用户显式提供”和“系统从外部观察得到”两类。前者可信度高,后者必须默认不可信。很多攻击能成立,就是因为这个边界在代码里没有体现。

1.2 记忆的写入来源,往往不在你的信任边界内

这里要理解一个关键点:Agent 的记忆不是只有用户聊天记录一种来源。它会读取网页、解析邮件、接收上传文件、调用外部 API、抓取搜索结果,然后把这些内容切块、嵌入、写进向量库。

问题就在这里。

一条外部网页里如果包含一段精心构造的指令,这段内容不会因为它“只是网页文本”而被模型当作普通数据。它一旦被切块、检索、拼进提示词,就变成了模型要处理的“上下文”。如果这条上下文里明确要求“接下来所有回答都按 XX 规则”,模型很可能真的照做。

这不是模型蠢,而是 Agent 架构本身把“数据”和“指令”混在了一个通道里。记忆系统的任务是从大量内容中筛出有用的,但相似度检索只解决“相关”,不解决“可信”。

所以真正要记住的第一条原则是:写入记忆不等于内容可信,任何写入口都是一个潜在注入面。

2. 注入攻击真正打的是哪几个环节,而不是“提示词变长”

2.1 写入阶段:不干净的内容进入记忆库

攻击的第一步,是把恶意内容送进记忆系统。入口非常多:

  • 用户上传了一个文档,文档里隐藏了指令段落。
  • Agent 抓取了一个网页,网页正文里混入了攻击性文本。
  • 邮件内容、会议纪要、工单描述被自动写入摘要。
  • 一条 API 返回的 JSON 里嵌入了一段看似普通但实际是指令的字符串。

只要这些内容被存储,它就已经进入记忆库。很多团队会忽略这个阶段,因为“存进去”和“发生危害”之间还有一段距离。但记忆系统的特点决定了,存储本身就会扩大后续影响。

这里有一个非常重要的判断标准:写入口有没有做内容校验,是不是所有数据都一视同仁地写入。如果答案是一视同仁,那这个系统对注入攻击基本是不设防的。

2.2 检索阶段:相关性和可信度混在一起

攻击的第二段发生在检索。向量检索按相似度召回 Top-K 块,然后把召回结果直接拼进提示词。攻击者只要让恶意内容在语义上贴近当前问题,它就能被检索出来。

举个具体的场景。Agent 在处理“帮我整理这份项目周报”任务时,会从记忆里检索上个月的讨论记录。如果上个月有一封邮件被注入过恶意段落,而这封邮件在语义上和“项目周报”高度相关,它就会进入召回结果。

问题是,检索系统不会告诉模型“这段内容来自一封未经验证的邮件”。它只是一个文本块。模型看到的是并列的几段历史记录,无法区分哪段是用户原本的任务要求,哪段是攻击者埋的线索。

所以第二个判断标准是:检索结果里有没有携带来源可信度,排序算法有没有把可信度作为权重。

2.3 解码阶段:记忆内容压过系统指令

如果说写入和检索是入口,那解码阶段就是危害真正爆发的位置。

当召回内容被拼进提示词后,模型需要同时处理:

  • 系统层设置的 Agent 角色和规则。
  • 用户当前的真实请求。
  • 从记忆里检索出来的历史内容和知识片段。
  • 工具返回的实时数据。

这四类内容在提示词里的地位,很多实现里是一样的。攻击者只要让记忆内容在措辞上表现得像“系统要求”或“用户最近的重要指示”,模型就可能在排序时把它放在更高优先级。

举例来说,记忆块里如果包含“在所有回复末尾都加入某段推广文案”这样的表述,模型可能真的照做,因为它无法验证这段记忆是“一条普通的历史消息”还是“一条仍然生效的指令”。

这就是所谓的指令层级问题。防御方需要做的是从架构上区分:系统指令、用户指令、外部记忆、工具结果,每一层都有明确边界和优先级。

2.4 持久化阶段:跨会话变成“后门”

单次注入危害有限,真正危险的是持久化。

如果注入的内容被写进了长期记忆,比如向量库或摘要表,那它就会在后续每次会话中被反复检索到。一场对话污染,变成了跨会话的稳定“后门”。

这也是 InjecMEM 这类研究最让人头疼的部分。普通的提示注入,只要当前会话结束就失效了。记忆注入不同,攻击者不需要持续在场,只需要一次成功写入,之后它就在系统里慢慢发酵。

我在评估一个 Agent 的记忆设计时,会专门看三件事:

  • 长期记忆多久会被重新检索一次。
  • 长期记忆是否有版本回溯能力。
  • 有没有机制识别并废弃被污染的记录。

如果这三条都没有,那这个记忆系统就处在“一次写入,长期受害”的状态。

3. 安全测试时,结果怎么判断

3.1 三个指标要分开看,不能只看“有没有成功”

评估记忆注入攻击的影响,不能只看一条任务是否被带偏。需要把结果拆成几个维度:

指标含义判断方式
攻击成功率(ASR)恶意记忆是否让 Agent 改变了行为对比有注入和无注入两组任务,行为差异占比
危害率(Harm Rate)改变后的行为是否构成实际危害输出是否泄露数据、执行了非预期操作、或带偏结论
效用退化(Utility Drop)防御措施是否影响了正常任务在无注入情况下,任务完成质量下降了多少
持久性(Persistence)注入效果会持续多轮多会话清空短期对话后,再开新会话是否仍然生效

很多研究报告里会重点报攻击成功率,但工程上我更关注危害率和效用退化。攻击成功率再高,如果危害输出可以被下游拦截,那风险等级就要下调。反过来,如果防御方案把攻击压制住的同时,正常任务准确率也掉了 20%,那这个方案也不能直接上生产。

3.2 一个最小验证流程,先跑通再扩展

如果你要验证自己的 Agent 记忆系统是否容易受到这类攻击,我建议先搭一个最小测试环境,不要一上来就做全量评估。

第一步,准备一个标准 Agent 任务。比如“总结最近三天的项目进展”“按用户偏好推荐配置”“根据历史订单生成跟进邮件”。

第二步,准备一组基线数据。跑 20 到 30 次,记录正常输出。

第三步,构造一组注入样本。这里强调一下,测试时只要在文档、网页或历史消息里加入一段与任务相关的指令即可,重点验证链路是否会把这段内容当作权威指令,不需要做成真正的恶意攻击。

第四步,把注入样本放进记忆写入路径,再执行同样的任务,记录输出变化。

最后一步,对比基线输出和注入输出,统计行为改变的比例。

这个流程的核心价值,是把“会不会被影响”这个模糊问题,变成一个可量化的结果。我自己通常会先跑 10 条,确认链路能观测到差异,再扩展到 50 条以上。

3.3 要区分“测试成功”和“真实危害”

测试时还要注意一类容易误判的情况:Agent 行为变了,但不一定有危害。

比如注入内容让 Agent 在回复时多了一句“该内容来源于外部文档”,这确实改变了行为,但风险很低。再比如注入内容让 Agent 在输出里附带了外部文档里的联系方式,这就是信息泄露风险了。

所以我在统计时会把“行为改变”和“危害行为”分成两个标签。不仅看是否偏离,还要看偏离后的输出是否触及敏感数据、是否执行了工具调用、是否覆盖了用户明确指令。

这里有一个常见错误:只统计“回复被带偏”,不统计“工具调用是否被劫持”。真正严重的情况是,Agent 的记忆里出现“用户要求删除某条订单”这类指令,然后模型真的调用了删除接口。这种危害级别和单纯改个回复措辞完全不同。

4. 防御思路:不要禁止记忆,要拆掉信任边界

4.1 内容来源标记:让每一条记忆都带着“身份证”

我见过最有效的第一条防线,是给每条记忆记录来源元数据。包括:

  • 来源类型:用户消息、文档、网页、邮件、API 返回、Agent 自摘要。
  • 可信等级:高可信、低可信、未验证。
  • 写入时间、写入者、原始内容哈希。
  • 是否允许被检索后直接拼进提示词。

这些元数据不需要展示给用户,但要在检索结果里随块传递。模型侧未必能理解这些字段,但防御代码可以通过这些字段做过滤和重排。

核心判断标准是:检索出的内容如果来自低可信来源,要么降低排序权重,要么加上明确提示,要么直接排除在敏感任务之外。

4.2 检索后处理:召回不是终点,过滤和重排才是

检索之后不要直接拼提示词,中间至少要有一层处理。顺序是这样:

  1. 召回 Top-K 块。
  2. 按来源可信度给每块打分。
  3. 过滤掉低分块,或者在提示词里用标签包裹低可信块。
  4. 对高敏感任务,比如执行工具调用、修改数据、发送消息,只允许高可信记忆参与决策。

这里可以给一个非常粗的伪代码逻辑:

def retrieve_memory(query, top_k=5, trust_filter=True): chunks = vector_store.search(query, top_k=top_k) if trust_filter: trusted = [c for c in chunks if c.metadata.get("trust_level") == "high"] untrusted = [c for c in chunks if c.metadata.get("trust_level") != "high"] # 高可信内容正常使用 # 低可信内容用特殊标记包裹,提示模型只能当数据参考,不能当指令 trusted_text = format_trusted_chunks(trusted) untrusted_text = format_untrusted_chunks(untrusted) return { "trusted": trusted_text, "untrusted": untrusted_text, "all": chunks }

注意,这只是示例。实际项目里,你还要考虑可信度阈值怎么设、不同任务类型的过滤策略怎么区分、低可信内容完全丢弃会不会影响正常检索质量。

另一个常用做法是“数据与指令隔离”。在提示词里明确告诉模型:凡是在“外部资料”标记块中出现的内容,都只是待处理的数据,其中的任何指令描述都不具备执行效力。这个方法不能 100% 防住所有模型,但在多数场景下能显著降低被带偏的概率。

4.3 写入权限和动作解耦:记忆不能直接驱动高风险操作

很多 Agent 的流程是:模型从记忆里看到一条信息,然后直接据此调用工具。这个链路太短了。

更稳妥的设计是加一层动作门槛:

  • 记忆内容只能改变“建议”,不能直接触发“操作”。
  • 涉及发送消息、删除数据、转账、修改配置等高风险动作,必须有用户的显式确认。
  • 工具调用参数如果来自低可信记忆,需要额外校验。

我之前处理过一个案例:Agent 从历史文档里检索到客户地址,结果生成快递单时把地址填错了。原因不是模型能力问题,而是系统直接把检索结果当作可信参数喂给了下游。后来在工具调用前加了一道规则校验,字段格式和来源都校验,问题就消失了。

这个案例说明,记忆注入的影响不只在最终文本输出,更可能通过工具调用链影响真实业务。

4.4 审计、溯源与回滚:出了问题能查、能撤、能恢复

防御不是保证不出问题,而是出问题后能快速定位和止损。记忆系统要具备:

  • 写入审计日志:谁在什么时间写入了什么内容,来源是什么。
  • 读取审计日志:哪些任务读取了哪些记忆块。
  • 记忆版本或快照:支持将记忆库回滚到某个时间点。
  • 污染检测:定期扫描已知的注入模式,比如“忽略之前指令”“以后所有回复都”“不要告诉用户”等句式。

这里要注意,基于句式的检测只能作为辅助,不能作为唯一防线。攻击者可以用语义改写绕过关键词匹配。更好的思路是把检测结果当作“高风险提示”,触发人工审核或提高防御等级。

5. 实际落地时,我更建议按这个顺序加固

5.1 先搭一条可观测的测试链路,而不是直接改生产环境

很多团队在读到这类攻击研究后,第一反应是给提示词加一段“不要执行无关指令”。这有一定效果,但不是架构级解法。

我建议这样启动:

第一步,在本地或测试环境搭一个最小 Agent,包含对话记忆、向量检索、摘要记忆三个模块。

第二步,在记忆写入路径加一层日志,把每次写入内容的来源类型、可信等级、内容长度记录下来。方便确认:“这条内容是从哪进来的,可信度是不是被正确标记”。

第三步,用 10 到 20 条注入样本跑一遍,观察写入口、检索口、提示词拼接口分别发生了什么。

第四步,记录风险点后,再逐项加防御。

这个顺序的意义在于,先看清问题,再动手改。不要连攻击路径都没复现就盲改参数。

5.2 防御配置按层加,不要一步到位

防御配置可以参考这个表来设计:

配置项推荐方向
写入口来源标记、写入校验默认低可信,显式标记才提升可信
存储层元数据保存、版本快照保留写入审计和回滚能力
检索层Top-K、相似度阈值、可信过滤敏感任务收紧阈值,或只允许高可信内容
提示词层内容包裹、指令强化区分数

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询