跳到正文

上下文与记忆治理 ​

一句话:企业 Agent 的上下文不是“把能查到的都塞进去”,而是先按权限、安全和相关性做 Guard,再按五层记忆装配;换来的是不越权和可解释,代价是要维护多层存储、压缩和失效策略。

为什么需要 ​

一个常见的失败路径:为了让 Agent“更懂业务”,把用户历史、知识库检索结果、工具返回和团队记忆全部拼进提示词。结果三个问题同时出现:

  • 越权:检索到了用户无权查看的文档,模型在回答里复述出来;提醒“不要泄露”已经晚了。
  • 腐化:几十轮后窗口里全是过期结果和重复段落,模型抓不住当前目标,开始引用旧结论。
  • 不可解释:回答错了,无法判断是记忆里的事实错了、检索漏了,还是权限过滤把关键证据挡住了。

根因是把“记忆”当成一个桶,把“注入”当成字符串拼接。企业场景里,上下文是一条有权限、有来源、有生命周期的装配流水线。

核心机制 ​

Guard > Memory:先治理,再注入 ​

三个判定节点都写成“能放行吗”,所以右边只有一条通行路径、三条丢弃路径,不存在“守住不守”的歧义。丢弃必须带层名落审计:被安全层挡下的和因为不相关被裁掉的,是两种完全不同的事故线索。

三层 Guard 的顺序不能反:先过滤越权内容,再过滤敏感和注入,最后才判断相关性。反过来先算相关性,会把“很相关但无权看”的内容排到前面,后面再删已经浪费了预算,也容易在日志里留下不该留的内容。

Guard 的判定要尽量确定性:权限来自 ACL 和数据处理,安全检查来自规则和分类器,相关性可以用检索分数加规则。把三层都交给模型判断,既慢又不可解释。

五层记忆 ​

层存什么生命周期典型存储
轮次记忆当前轮的消息与工具结果单轮进程内 / 短 TTL 缓存
会话记忆本次会话的历史与已确认事实会话Redis
任务记忆任务图、步骤状态、中间结果任务关系库 + 对象存储
团队记忆团队共享的偏好、术语、决策长期向量库 + 元数据
跨会话记忆用户长期偏好与稳定事实长期向量库 + 关系库

分层的意义是不同层有不同的写入者、读取者和失效策略。轮次记忆可以随请求结束丢弃;会话记忆要支持恢复;任务记忆要能审计和重放;团队与跨会话记忆必须经过策展,不能把每次对话原样写入,否则噪声会随时间累积。

上下文注入管道 ​

  1. 解析身份与作用域:用户、租户、业务域、数据级别、当前任务。
  2. 收集候选:会话历史、任务状态、用户记忆、团队记忆、知识检索、工具结果。
  3. Guard 过滤:权限 → 安全 → 相关性,逐层裁剪。
  4. 去重与合并:同一事实多来源时保留最新、最权威的一条,记录来源。
  5. 预算分配:稳定规则、任务状态、证据、历史各占多少,预留输出空间。
  6. 压缩或引用化:超长结果落盘留摘要,旧历史结构化压缩。
  7. 编译视图:按“稳定前缀 → 会话能力 → 动态任务”排序,生成 Manifest。
  8. 校验:目标、未决项、权限和关键证据是否还在;不通过则回到第 3 步。

Manifest 记录每个来源的作用域、版本、可信度、入选原因和 token 数。没有它,回答错了只能猜;有了它,可以回答“模型当时看到了什么、为什么没看到另一份文档”。

压缩:先提交事实,再压叙述 ​

压缩不是删消息,而是一次生命周期:

  • Commit:把目标、已完成、阻塞、关键决策、待审批动作写入权威状态。
  • Compact:把叙述性历史压成带来源的摘要,原始记录留在日志。
  • Rebuild:用摘要、状态和最近消息重建视图。
  • Validate:检查目标、权限、证据是否完整;不完整就回到 Commit。

规划状态、权限记录、未决审批和用户置顶约束属于永不压缩的内容。压缩切点不能切断工具调用与结果的配对,否则模型看到的是残缺因果链。所谓“最近”也不只按时间:未解决的错误、待审批动作和验收失败的证据,即使更早也必须保持活动。

记忆写入与策展 ​

长期记忆最大的风险不是“记不住”,而是“记错还一直用”。写入要做四件事:

  • 抽取:只保留稳定事实、偏好和决策,不保存寒暄和临时推理。
  • 归因:记录来源会话、时间和可信度;冲突时保留双方并标注。
  • 去重:同一事实的多次表达合并,保留最新确认版本。
  • 过期:给时效性事实设 TTL,过期后降权或标记待确认。

团队记忆还要有 owner 和评审:一条错误的团队规范会被所有 Agent 复用,破坏面远大于单次对话。

隔离 ​

维度隔离要求
租户记忆命名空间物理或逻辑隔离,检索默认不跨租户
业务域不同业务域的知识与团队记忆不互相召回
用户跨会话记忆按用户隔离,共享前必须显式授权
任务任务记忆按 task_id 隔离,子任务只读父任务授权范围内的结果
环境内网与互联网闭环不共享记忆存储

隔离要在存储层和检索层同时做:只靠查询条件过滤,一次漏写就可能跨租户;只在存储层隔离,跨域检索仍可能把数据带出来。

实战场景 ​

场景一:A 租户的记忆进了 B 租户的窗口——先注入后 Guard ​

现象:SaaS 客服 Agent 由两个租户共用一套平台。一个周末 B 租户管理员投诉 14 次:助手回答里带出了 A 租户的内部项目代号和订单号,法务按跨客户数据泄露评估责任。翻轨迹发现模型不是幻觉,它引用的内容真实存在,且属于另一个租户。

排查:按“排障先看 Manifest,再看模型”定位问题层:

排除对象判定证据结论
模型引用内容真实,Manifest 里有来源与入选原因模型只是复述它看到的,不是幻觉
检索检索请求带租户条件,没有命中跨租户记录召回侧干净,不是检索问题
装配与写入策展批处理把群聊摘要写进了团队记忆默认命名空间,没有租户字段漏写标签,装配按公开放行

故障是两个错误叠加:为了省延迟,权限 Guard 被挪到预算分配和编译视图之后,无标签记忆被当作公开内容通过,进了窗口只剩“不要泄露”的提示,属于事后补救;写入侧漏标签,正是正文说的“一次漏写就可能跨租户”。

对症:三层 Guard 顺序回归“权限 → 安全 → 相关性”,且必须先于预算分配和编译视图;写入侧拒收无标签记忆:

yaml
context:
  guards: [permission, safety, relevance]   # 在 budget 与编译视图之前执行
  memory_write:
    require_fields: [tenant, owner, source_session]
    reject_if_missing: true                 # 缺标签的记忆不落库

复盘:Guard 挡的是候选,不是已注入内容,“召回后再删”会在窗口和日志里留下痕迹,还浪费预算。隔离要在写入、存储、检索三处同时做;验收回到正文两条:越权内容不出现在 Manifest,跨租户检索返回空。

场景二:压缩把限定条件压掉,结论反转 ​

现象:合同审阅助手在 52 轮会话后触发压缩,摘要丢了“该折扣仅限 2026-06-30 前下单、渠道客户除外”里的限定条件,下一轮直接答复“渠道客户可用”。销售按它报了 3 单,回滚花 2 个工作日逐客户改报价。

排查:用固定任务集回放这条轨迹,对比压缩前后视图:

排除对象判定证据结论
检索条款原文在压缩前的 Manifest 里证据进过窗口,不是漏检
模型把原文放回窗口,同题答对模型读得懂原文
压缩摘要里限定词消失,Validate 却判通过Validate 只查目标、权限、证据,没覆盖约束

对症:问题定位在 Commit 到 Compact 之间——限定条件被当作叙述内容一并压掉。做法是先把事实提交进任务记忆,再压叙述;限定词做成结构化字段并进 Validate 断言:

修饰词类别压缩处理Validate 断言
仅限 / 除外 / 上限结构化字段入任务记忆,按永不压缩处理每条结论必须携带字段引用
生效日期 / 时效随 TTL 写入,到期降权或标记待确认未确认事实不得作为结论依据
前置条件 / 待审批归入 never_compress压缩后不得缺失

分级压缩的顺序不动:先清理无用工具结果,再摘要历史,最后才强制压缩;连续 3 次校验失败熔断(经验值,需校准),回退到未压缩视图并转人工。

复盘:压缩必然有损,损失要落在叙述上而不是约束上;Validate 不过的摘要不是压缩,是毁信息。原始记录必须保留,关键事实先提交。

场景三:长会话成本随轮次近似二次上涨 ​

现象:运维答疑 Agent 平均会话 60 轮以上,会话记忆整段历史逐轮重放,每轮 prompt 近似线性增长、整段会话累计成本近似二次。模型开始引用旧结论、抓不住当前目标,用户中途放弃率上升,一个季度内单会话 prefill 成本翻了一倍。

排查:用 Manifest 里每轮的 token 数分层归因:知识检索入选条数每轮基本稳定,排除检索问题;模型与提示词未变更,排除模型问题;60 轮时每轮 token 约七成被历史重放占据,锁定装配层的预算分配。compact_at: 0.8 其实一直在触发,但更早发生的未解决错误被反复引用,校验步骤通不过,裁剪只动历史尾部,下一轮又涨回来。

对症:用任务记忆做卸载——工具全量结果落盘留摘要,窗口里只留引用;引用化在去重合并与预算分配之间执行,校验步骤按 Manifest 来源指针回读:

yaml
budget:
  history: { mode: reference, inline_recent_turns: 6 }  # 经验值,需校准
  evidence: { spill_at_tokens: 512 }                    # 经验值,需校准
read_back: 校验缺关键证据 / 用户引用窗口外结论 / 待审批重新激活

复盘:“最近”不只按时间——未解决的错误、待审批动作和验收失败的证据即使更早也必须保持活动,回读时机由这三类事件触发,不靠模型自行决定;成本失控优先在存储层解决——轮次记忆随请求丢弃、会话记忆结构化压缩、任务记忆可重放,五层各有卸载策略,先分层再谈换便宜模型。

最小上手 ​

先实现三层:会话、任务、知识,不要一开始做五层。

yaml
context:
  identity: { user, tenant, domain, data_level }
  guards: [permission, safety, relevance]
  budget: { reserve_output: 8000, compact_at: 0.8 }
  never_compress: [goal, permissions, pending_approvals]
  manifest: [source, scope, version, trust, reason, tokens]
memory:
  session: redis
  task: postgres
  knowledge: vector_store
  ttl: { session: 7d, task: 30d }

验收看五件事:越权文档不会出现在 Manifest;压缩后模型仍能说出目标和下一步;同一事实冲突时能追到来源;会话恢复后权限没有变化;跨租户检索返回空。

生产动作 ​

  • 先过滤再排序:把权限和数据处理放在检索之前,避免“先召回再删除”。
  • 记录 Manifest:每轮保存来源、版本、入选原因和 token;排障先看 Manifest,再看模型。
  • 分级压缩:先清理无用工具结果,再摘要历史,最后才强制压缩;连续失败要熔断。
  • 记忆写入评审:团队记忆和长期事实走评审或抽样复核,避免错误规范扩散。
  • 失效策略:制度、价格、权限这类时效性事实必须有 TTL 和版本,过期自动降权。
  • 回放测试:用固定任务集回放,比较压缩前后、记忆开关前后的成功率与成本。

边界 ​

  • 记忆不是越多越好:长期记忆的噪声会降低检索准确率,策展比容量更重要。
  • Guard 不能保证绝对安全:分类器会漏,真正的边界仍在工具权限和执行环境。
  • 压缩必然有损:摘要会丢细节,原始记录必须保留,关键事实必须先提交。
  • 跨会话记忆有隐私成本:用户可能不希望被长期记住,要有查看、删除和关闭入口。
  • 小规模系统不需要五层:会话加知识两层就能跑,等出现团队共享和长期偏好需求再拆。

讲清楚 ​

企业上下文治理的顺序是 Guard 先于 Memory:先按权限、安全和相关性裁剪候选,再按预算装配;否则“先召回再提醒模型别泄漏”只是事后补救。记忆分五层,是为了让不同生命周期的事实各有存储和失效策略,而不是把所有东西塞进一个向量库。压缩要先提交事实再压叙述,规划、权限和待审批动作永不压缩。判断这套机制是否可靠,看三件事:Manifest 能否解释模型看到了什么,越权内容是否在检索前就被挡住,压缩后任务是否还能继续。

适用:2026 年企业级 Agent 上下文与记忆治理 | 初稿 2026-10

把 AI 工程讲到既懂也会用