AgentDepthAgent 工程学习指南
输入概念或问题,检索正文和待编写目录。
第一次学习?从 L0 总览开始 →

TTL、纠错、遗忘与隐私

我的学习 →

正在读取学习记录…

保存记忆以后,还需要决定何时更正、何时停止使用、怎样删除。TTL是存活时间,例如一条临时偏好保存10分钟,超过这个时长便失效。纠错把错误记录替换成新版本;遗忘移除以后不再使用的信息;隐私管理决定哪些内容可以保存、谁能读取以及用户怎样要求删除。

像更新通讯录:新号码替换旧号码,临时通行信息到期作废,客户要求删除时还要清理留在快捷查询里的副本。只删主记录,缓存仍可能读到旧内容。

观察一条偏好怎样失效与更正

固定时间用整数表示,便于精确观察边界。u1的中文偏好在时刻0写入、版本为v1、存期10,到时刻10失效。随后在时刻20重新写入中文,版本递增为v2;时刻22纠正为英文v3,确认缓存跟随更新。最后执行用户删除,当前记录和缓存一并移除。

缓存是为了快速读取保存的副本。版本让副本能够识别更新;删除版本继续保留递增的编号,避免同一键重新写入时撞上旧缓存编号。

记忆的到期、纠错与删除:时刻0:中文v1,失效时刻10,时刻9:可读取中文;时刻10:到期 → 删除当前记录与缓存,版本计数保留1;时刻20:中文v2 → 时刻22:英文v3,更新清缓存 → 读取新值;用户删除 → 当前记录清空,缓存也清空,不能再召回
图1:记忆的到期、纠错与删除。

跟着固定样本运行

先在 PowerShell 创建并进入学习目录:

Bash
mkdir "F:\学习\l5-forgetting" -Force
cd "F:\学习\l5-forgetting"

保存下面的文件后,在这个终端运行 dir 核对文件名,再执行本节给出的运行命令。

新建 F:\学习\l5-forgetting,将下面完整代码保存为 forgetting_demo.py。

先在 PowerShell 创建并进入学习目录:

Bash
mkdir "F:\学习\l5-forgetting" -Force
cd "F:\学习\l5-forgetting"

保存下面的文件后,在这个终端运行 dir 核对文件名,再执行本节给出的运行命令。

Python
"""检查到期、纠错版本与用户删除后的缓存状态。"""
from dataclasses import dataclass


@dataclass(frozen=True)
class Entry:
    value: str
    version: int
    expires_at: int


class MemoryStore:
    def __init__(self):
        self.rows = {}
        self.versions = {}
        self.cache = {}

    def put(self, user, value, now, ttl):
        if ttl <= 0:
            raise ValueError("存期必须为正")
        # 版本号独立于当前记录保存,删除后重建也继续递增。
        version = self.versions.get(user, 0) + 1
        self.versions[user] = version
        self.rows[user] = Entry(value, version, now + ttl)
        self.cache.pop(user, None)
        return version

    def get(self, user, now):
        row = self.rows.get(user)
        if row is None:
            return None
        if now >= row.expires_at:
            self.delete(user)
            return None
        # 缓存带版本,读取前和当前记录核对。
        cached = self.cache.get(user)
        if cached is None or cached.version != row.version:
            self.cache[user] = row
        return self.cache[user].value

    def delete(self, user):
        # 主记录与快捷读取副本同时删除;这里只保留无内容的版本计数。
        self.rows.pop(user, None)
        self.cache.pop(user, None)


if __name__ == "__main__":
    store = MemoryStore()
    store.put("u1", "中文", now=0, ttl=10)
    print("到期前:" + str(store.get("u1", 9)))
    print("到期时:" + str(store.get("u1", 10)))
    first = store.put("u1", "中文", now=20, ttl=10)
    store.get("u1", 21)
    updated = store.put("u1", "英文", now=22, ttl=10)
    print(f"纠错:v{first} → v{updated},读取={store.get('u1', 23)}")
    store.delete("u1")
    print(f"用户删除:读取={store.get('u1', 24)},缓存条数={len(store.cache)}")

在 PowerShell 中进入保存目录并运行:

Bash
cd "F:\学习\l5-forgetting"
ls
python -X utf8 forgetting_demo.py

输出为:

TXT
到期前:中文
到期时:None
纠错:v2 → v3,读取=英文
用户删除:读取=None,缓存条数=0

时刻9还能读取中文,时刻10返回None,并清理已到期的记录和缓存。再次写入得到v2,因为最早那次写入已经使用v1;更正英文得到v3。编号没有随删除归零。

最后一行显示读取为空、缓存条数为0。当前程序在读取时检查到期,只有被访问的过期记录才会立即清理;没有访问的条目还留在字典里,直到执行清理或删除。

失效与真正移除怎样配合

存期决定何时不再给调用方返回记录。程序可在每次读取时检查失效,也可以用定时清理移除无人访问的过期条目。大型存储常将两者配合:读取及时阻断,后台回收空间。保留时间应根据用途选择,短期会话状态和稳定偏好不必使用相同时长。

纠错时增加版本并清缓存,使下一次读取取得新值。分布式缓存可能在多个服务节点保留副本,需要广播失效、版本核对或短存期策略。数据库中的旧版本、搜索索引、摘要与向量索引也属于可能残留的副本。

用户要求删除时,沿哪些位置找

先按身份确认要删除的记录,再移除主存储、缓存和相关索引;如果保留历史修订,也需要处理对应历史内容。日志中尽量保存操作编号与结果,避免再次记录被删除的原文。备份和审计材料有不同保留策略,需要向用户说明实际覆盖范围和恢复限制。

示例删除的是进程里的记录与缓存,并留下无偏好内容的版本计数。正式系统的用户级彻底删除还应处理这个关联标识,以及外部存储、备份与日志。TTL清理提供时间控制,删除请求提供用户控制,两者可以同时存在。

将存期从10改成20

只把主程序第一次写入的 ttl=10 改为 ttl=20,运行 python -X utf8 forgetting_demo.py。“到期时”一行会显示中文,因为时刻10还没到新期限。该标签描述的是原来的观察点;改成“时刻10”更适合保留这个对照。后续纠错和用户删除仍按原步骤执行。恢复存期10和原标签后重跑,时刻10再次读到None。

现象检查位置
刚到期限仍能读到值是否使用now大于等于失效时刻
更正后仍显示旧偏好缓存版本与失效通知
删除后又读到内容索引、缓存、历史版本和备份
无人读取的过期数据堆积后台清理任务

检查实现中的六种情况

在同一目录将下面测试保存为 test_forgetting_demo.py。测试覆盖正文中的正常路径与边界条件。

测试代码:test_forgetting_demo.py
Python
"""检查存期边界、更新、删除与重新写入。"""
import unittest
from forgetting_demo import MemoryStore


class ForgettingTests(unittest.TestCase):
    def setUp(self):
        self.store = MemoryStore()
        self.store.put("u1", "中文", 0, 10)

    def test_before_expiry(self):
        self.assertEqual(self.store.get("u1", 9), "中文")

    def test_expiry_boundary(self):
        self.store.get("u1", 9)
        self.assertIsNone(self.store.get("u1", 10))
        self.assertNotIn("u1", self.store.cache)

    def test_correction_invalidates_cache(self):
        self.store.get("u1", 1)
        self.assertEqual(self.store.put("u1", "英文", 2, 10), 2)
        self.assertEqual(self.store.get("u1", 3), "英文")

    def test_delete_clears_cache(self):
        self.store.get("u1", 1)
        self.store.delete("u1")
        self.assertNotIn("u1", self.store.rows)
        self.assertNotIn("u1", self.store.cache)

    def test_recreate_keeps_increasing_version(self):
        self.store.delete("u1")
        self.assertEqual(self.store.put("u1", "英文", 2, 10), 2)

    def test_user_isolation_and_ttl_validation(self):
        self.assertIsNone(self.store.get("u2", 1))
        with self.assertRaises(ValueError):
            self.store.put("u1", "中文", 2, 0)


if __name__ == "__main__":
    unittest.main()
Bash
cd "F:\学习\l5-forgetting"
python -X utf8 -m unittest -v test_forgetting_demo

应显示6项通过。将主程序恢复到上面的固定输入后,可以再次对照完整输出。

课后练习展开习题收起习题

4 道练习 · 客观题规则评分 · 其余题目待批改

正在读取本地记录…

不调用模型,不执行代码。简答、代码和场景题仅保存答案并展示自查标准,不生成评分、徽章或认证。输入内容不会自动保存,请点击提交;不要填写个人信息或密钥。

练习 1 / 4 · v1.0.1

选择题 · 先判断边界

关于“TTL、纠错、遗忘与隐私”,哪种做法更稳妥?

对应知识点:L5-forgetting

选择一个答案
练习 2 / 4 · v1.0.0

简答题 · 解释失败

写出一个失败输入并说明记录字段。

对应知识点:L5-forgetting

练习 3 / 4 · v1.0.0

代码题 · 边界测试

补充正常、边界、失败三组输入和预期结果。

对应知识点:L5-forgetting

练习 4 / 4 · v1.0.0

场景题 · 结果未知

证据不足时如何设计状态和人工接管?

对应知识点:L5-forgetting

图片查看器
100%

文章配图 · 按 Esc 关闭