本文是 Agent 工程里的经典架构 系列的一篇。文中的业务场景和代码为讲解设计,产品能力以所链接的官方资料为准。

客服 Agent 第二次见到用户时,不记得上次答应过什么,体验当然不好。把所有历史对话都塞进提示词,短期内似乎能解决,时间久了却会遇到成本、长度和信息干扰的问题。真正困难的是,今天的任务需要哪些历史,以及这些历史还是否可信。

MemGPT 论文借鉴了操作系统分层内存管理的思路,在有限上下文和外部存储之间调度信息,形成更长的可用上下文。这个类比很有启发性,但模型上下文不是字节级内存,摘要和检索也不会像读取内存地址那样保证信息完整。

我会把资料分成当前任务必需的信息、稳定的用户偏好,以及可以按需查找的历史。订单编号、待执行动作和授权状态必须结构化管理;用户喜欢简短回复可以作为偏好;一年前的咨询记录只有相关时再读取。三类信息的可信度、保留期限和读取方式都不同。

机制图:区分工作上下文与外部记忆,按当前任务选择证据。

下面是一个简化的上下文组装器。它先保留任务必需内容,再从外部记录中按用户和关键词选择相关信息,在字符预算内加入。字符预算只是为了便于运行示例,真实系统应按所用模型的 tokenizer 计算,并为工具说明与输出预留空间。这不是 MemGPT 的官方实现。

records = [
    {"user": "u1", "topic": "退款", "text": "已提交申请 R17,尚未批准"},
    {"user": "u1", "topic": "配送", "text": "偏好工作日收货"},
    {"user": "u2", "topic": "退款", "text": "另一位客户的私人记录"},
]


def context(user, topic, mandatory, budget_chars):
    if len(mandatory) > budget_chars:
        raise ValueError("必需上下文已超预算")
    parts = [mandatory]
    used = len(mandatory)
    for item in records:
        if item["user"] != user or item["topic"] != topic:
            continue
        cost = len(item["text"]) + 1
        if used + cost <= budget_chars:
            parts.append(item["text"])
            used += cost
    return "\n".join(parts)


result = context("u1", "退款", "任务:查询 R17 状态", 60)
assert "尚未批准" in result
assert "另一位客户" not in result
assert "工作日收货" not in result
assert len(result) <= 60
print(result)

完整示例可下载,使用 Python 3.9 或以上版本运行:python3 example.py。只依赖标准库,不调用真实业务服务。

代码最先检查的是用户范围。检索准确度再高,也不能把其他客户的记录放进当前上下文。权限过滤应当在检索层或数据访问层落实,而不是先取回所有内容,再请模型“不要使用不属于这个用户的信息”。缓存和向量索引也要保持相同的隔离边界。

接下来才是相关性。关键词匹配只是教学用法,实际可以结合向量、结构化条件和时间排序。但相关不等于正确:一条很像当前问题的旧记录,可能已经被后续事件撤销。记忆应带来源、发生时间和状态,关键结论要能够回到权威系统核实。

摘要同样需要谨慎。把“客户询问是否可以退款”压缩成“客户需要退款”,看起来只差几个字,业务含义已经变化。对承诺、授权和金额等信息,适合保存结构化事实与原始证据引用,避免只保留模型写的一段总结。压缩可以减少读取成本,不能改变证据标准。

这里与缓存设计有相似之处:需要考虑什么信息常驻、何时失效、如何回源。但缓存未命中通常可以重新读取,记忆压缩丢失的信息可能已经无法恢复。如果外部原始数据仍然存在,摘要可以重建;如果已经删除,就必须接受能力和可解释性上的限制。

评估记忆系统时,我会设计跨会话用例:用户纠正偏好、撤销承诺、同名客户隔离,以及旧事实被新事实替代。除了最终回答是否正确,还要检查检索到的来源、遗漏的重要记录和无关信息占用的预算。仅看回答“像是记得”,并不能说明记忆机制可靠。

长期运行也意味着持续维护。错误记忆需要纠正渠道,个人信息需要删除与过期策略,共享记忆需要并发更新规则。读写外部记忆如果属于工作流的一部分,还需要纳入执行记录,避免恢复时使用了不同的历史信息却没有解释。

这个方向最有用的地方,是迫使我们把上下文当作有限资源认真设计。扩大窗口可以推迟容量问题,却不能替代权限、相关性和来源判断。给模型更合适的信息,通常比给它更多未经整理的信息,更接近一个可以长期工作的 Agent。

上一篇 · 系列目录 · 下一篇