Deep Agents 学习笔记(六):长期记忆与 Human-in-the-Loop

学习资料:

本篇重点:Checkpointer、Store、CompositeBackend、Memory、interrupt_on、Command(resume=...)、人工审批与状态恢复。

一、为什么 Agent 需要记忆和人工干预?

前面学习了 Deep Agents 的任务规划、SubAgent 和 Skills,分别解决了复杂任务拆解、任务委派与专业能力复用的问题。

但要让 Agent 真正用于长期、复杂的工作,还有两个问题:

1. Agent 如何记住过去?

例如,第一次对话告诉 Agent 项目的代码规范,下一次开启新对话时,希望它仍然按照相同规范工作。

这需要 Long-term Memory(长期记忆)。

2. Agent 如何安全地执行操作?

例如,Agent 自动修改代码、删除文件、发送邮件。如果完全自主执行,可能造成不可逆的结果。

这需要 Human-in-the-Loop(HITL,人在回路),在关键操作前引入人工审批。

两者共同解决的是 Agent 的状态连续性与执行可控性。

二、Memory:短期记忆与长期记忆

Deep Agents 将记忆分为两类:

对比 短期记忆 长期记忆
作用域 Thread-scoped Cross-thread
核心机制 Checkpointer Store
存储内容 对话历史、Todo、状态 用户偏好、项目知识
跨线程共享 默认不支持 支持
典型用途 恢复当前任务 积累长期知识

2.1 Checkpointer:短期状态管理

LangGraph 使用 Checkpointer 保存 Agent 的执行状态。

复制代码
from langgraph.checkpoint.memory import MemorySaver
from deepagents import create_deep_agent

checkpointer = MemorySaver()

agent = create_deep_agent(
    model=model,
    checkpointer=checkpointer,
)

config = {
    "configurable": {
        "thread_id": "conversation-001"
    }
}

同一个 thread_id 可以恢复之前保存的状态。

但如果切换新的 thread_id,不同线程之间的 State 默认相互隔离。

因此:

Checkpointer 解决的是线程内状态恢复,而不是跨线程知识共享。

此外,MemorySaver 只保存在内存中,程序重启后会丢失。生产环境通常需要持久化 Checkpointer,例如 PostgresSaver。

2.2 Store:跨线程长期记忆

长期记忆需要使用 Store,存储用户偏好、项目背景或 Agent 积累的经验。

Deep Agents 将记忆组织为文件,通过 Backend 决定文件实际保存在哪里。

其中最重要的是 CompositeBackend。

复制代码
Agent 文件系统
       |
       v
 CompositeBackend
       |
       +-- StateBackend
       |   当前线程临时文件
       |
       +-- StoreBackend
           跨线程共享记忆

核心配置如下:

复制代码
from deepagents.backends import (
    CompositeBackend,
    StateBackend,
    StoreBackend,
)
from langgraph.store.memory import InMemoryStore

store = InMemoryStore()

backend = CompositeBackend(
    default=StateBackend(),
    routes={
        "/memories/": StoreBackend(
            namespace=("user-001", "memories")
        )
    }
)

这样,普通文件保存在 State 中,而 /memories/ 路径下的文件会进入 Store。

对于 Agent 而言,都是 read_file、write_file 等文件操作,区别在于存储位置。

三、长期记忆如何加载和更新?

Deep Agents 提供 memory= 参数加载记忆文件。

复制代码
agent = create_deep_agent(
    model=model,
    backend=backend,
    store=store,
    memory=[
        "/memories/preferences.md",
        "/memories/project.md"
    ],
)

这里需要区分:

  • memory=:指定启动时读取的已有文件。

  • edit_file:修改已有记忆。

  • write_file:写入文件,已有文件会被整体覆盖。

**memory=**只负责加载,不会自动创建或更新记忆文件。

因此,使用长期记忆通常需要三个步骤:

  1. 预先创建记忆文件并配置 Store。

  2. 通过 memory= 将已有记忆加载到上下文。

  3. 通过提示词约定更新条件,再由 Agent 调用文件工具保存新信息。

3.1 namespace:记忆隔离

Store 使用 namespace 区分记忆的归属。

类型 namespace 示例 用途
Agent 级 ("agent-001",) Agent 共享知识
用户级 ("user-001",) 个人偏好
组织级 ("org-001",) 团队规范

例如,科研 Agent 可以将个人代码习惯保存到用户级记忆,将团队实验规范保存到组织级记忆。

实际部署时,用户身份应来自可信的认证上下文,不能由 LLM 自行生成。

3.2 Memory Consolidation:记忆整合

长期运行后,记忆可能产生重复、冲突或过期内容。

常见策略包括:

  • Hot Path:对话过程中实时更新。

  • Background Consolidation:通过独立任务定期提取、去重和整理。

后台整合需要自行调度,并不是配置 Store 后就自动发生。

对于长期科研项目,可以将文献、实验进展与研究决策拆分保存,而不是全部堆积在一个文件中。

四、Human-in-the-Loop:为什么需要人工审批?

Agent 可以自主调用工具,但并不是所有操作都适合自动执行。

例如:

  • 删除重要文件;

  • 修改生产配置;

  • 发送正式邮件;

  • 执行数据库写入;

  • 调用有成本或不可逆影响的外部 API。

Human-in-the-Loop 的核心思想是:

Agent 在执行敏感操作前暂停,由人类审核操作内容,再决定是否继续。

Deep Agents 通过 interrupt_on 配置工具审批。

复制代码
from deepagents import create_deep_agent
from langgraph.checkpoint.memory import MemorySaver

agent = create_deep_agent(
    model=model,
    tools=[delete_file, send_email],
    interrupt_on={
        "delete_file": {
            "allowed_decisions": [
                "approve",
                "edit",
                "reject"
            ]
        },
        "send_email": {
            "allowed_decisions": [
                "approve",
                "reject"
            ]
        },
    },
    checkpointer=MemorySaver(),
)

这里的 delete_file 和 send_email 是需要提前定义的工具。

配置后,Agent 调用对应工具时会触发中断,而不是立即执行。

五、四种人工决策

HITL 支持四种决策:

决策 含义 应用场景
approve 批准原始调用 确认删除文件
edit 修改参数后执行 修改收件人
reject 拒绝执行 取消部署
respond 人工提供工具结果 回答 Agent 的问题

其中有一个重要区别:

reject 表示工具没有执行。

respond 则将人工输入作为成功的工具结果返回。

因此,对于删除、发送、部署等具有副作用的操作,应该使用 reject,而不是用 respond 表示拒绝。

六、Interrupt:中断与恢复机制

HITL 的关键不是弹出确认框,而是保存当前执行状态,并在收到人工决策后恢复工作流。

完整流程:

复制代码
Agent 正常执行
      |
      v
准备调用敏感工具
      |
      v
interrupt() 触发中断
      |
      v
Checkpointer 保存状态
      |
      v
等待人工审批
      |
      +-- approve
      +-- edit
      +-- reject
      +-- respond
      |
      v
Command(resume=...)
      |
      v
恢复 Agent 执行

6.1 代码示例

复制代码
from langgraph.types import Command

config = {
    "configurable": {
        "thread_id": "task-001"
    }
}

# 第一次执行
result = agent.invoke(
    {
        "messages": [{
            "role": "user",
            "content": "删除 temp.txt"
        }]
    },
    config=config,
    version="v2",
)

# 检查中断
if result.interrupts:
    request = result.interrupts[0].value
    print(request["action_requests"])

    # 示例:假定人工已经确认批准
    decisions = [{"type": "approve"}]

    result = agent.invoke(
        Command(
            resume={"decisions": decisions}
        ),
        config=config,
        version="v2",
    )

实际应用中,decisions 应来自用户的真实审批结果,不能自动填入 approve。

这个流程有三个关键要求:

1. 必须配置 Checkpointer。

否则没有可恢复的状态。

2. 恢复时必须使用相同的 thread_id。

否则无法找到对应的中断位置。

3. 多个工具同时中断时,决策必须与请求一一对应。

对于多个并行中断,可以通过中断 ID 绑定不同的恢复结果。

6.2 中断恢复不等于继续 Python 调用栈

LangGraph 恢复时会重新进入中断所在节点,而不是从原来的 Python 代码行继续运行。

因此,如果在同一个节点内先执行外部写操作,再调用 interrupt(),恢复时可能重复执行前面的操作。

这也是为什么有副作用的操作需要考虑幂等性(Idempotency)。

内置 interrupt_on 通过独立审批节点处理工具调用,可以减少这类问题。

七、按风险等级设计审批机制

并不是所有工具都需要审批,否则会降低 Agent 的执行效率。

比较合理的方案是分层管理:

风险等级 操作示例 建议策略
低 搜索、普通文件读取 自动执行
中 修改普通项目文件 按需审批
高 删除、发送、生产部署 强制审批
人工输入 询问用户偏好 respond

Deep Agents 还支持条件中断,通过 when 判断具体参数是否需要审批。

例如,只拦截工作区之外的文件写入操作,而允许 Agent 自动修改普通工作区文件。

此外,文件系统可以通过 FilesystemPermission 设置 mode="interrupt",对敏感路径提供额外保护。

八、自定义 Middleware 与 interrupt()

interrupt_on 主要负责工具调用审批,但有些场景并不涉及具体工具。

例如:

  • Agent 生成研究报告后等待人工审稿;

  • 在进入下一阶段前确认研究方案;

  • 对最终结果进行质量审核。

这时可以在自定义 Middleware 中直接调用 LangGraph 的 interrupt()。

通常更适合在 before_model、after_model 等 Node-style Hook 中设置中断。

而 wrap_model_call、wrap_tool_call 更适合模型重试、缓存、工具调用包装等逻辑,不建议作为常规人工审批边界。

九、长期记忆与 HITL 如何结合?

这两章看起来分别讨论记忆和审批,但底层都涉及状态管理。

需要注意,两者使用 Checkpointer 的目的不同:

  • 长期记忆:Checkpointer 保存线程状态,Store 提供跨线程共享信息。

  • HITL:Checkpointer 保存暂停点,使人工审批后能够恢复执行。

可以构建如下工作流:

复制代码
用户提出科研任务
        |
        v
加载长期项目记忆
        |
        v
Agent 制定研究计划
        |
        v
执行检索和分析
        |
        v
准备修改关键文件
        |
        v
人工审批
        |
        v
执行修改并验证结果
        |
        v
更新长期项目记忆

例如,在科研 Agent 中:

  1. 读取历史实验记录,避免重复分析。

  2. 自主执行数据检查和代码调试。

  3. 修改重要实验配置前请求人工确认。

  4. 完成任务后,将验证过的结果写入长期记忆。

这样既能利用历史知识提高效率,也能保留人类对重要决策的控制权。

十、学习总结

这两章让我进一步理解,Agent Harness 不只是让模型能够调用工具,还需要管理状态、权限和执行边界。

长期记忆解决"如何持续积累知识"。

通过 Store 和 Backend,将用户偏好、项目背景和研究经验从对话上下文中独立出来,实现跨线程复用。

Human-in-the-Loop 解决"如何控制自主执行"。

通过 interrupt_on、Checkpointer 和 Command(resume=...),让 Agent 在敏感操作前暂停,等待人工决策后再继续执行。

其中最值得关注的是三个设计思想:

  1. 状态与模型解耦:对话状态、长期记忆和暂停点由外部系统管理,不依赖模型永久记住信息。

  2. 持久化是可恢复执行的基础:没有 Checkpointer,就难以实现可靠的中断恢复。

  3. 自主性与可控性需要平衡:普通操作自动完成,高风险操作引入人工审批。

结合前面几章,Deep Agents 的整体架构逐渐完整:

  • Task Planning:任务拆解与进度管理。

  • SubAgent:任务委派和上下文隔离。

  • Skills:专业流程的封装与复用。

  • Long-term Memory:跨对话知识积累。

  • Human-in-the-Loop:人工审批与安全恢复。

这些机制共同支撑了一个能够长期运行、持续积累经验,同时保留人类控制权的 Agent 系统。

总结:Memory 让 Agent 记住过去,HITL 让人类控制关键决策,而 Checkpointer 是持续执行与可靠恢复的重要基础。


参考资料

  1. Datawhale《Deep Agents 实战》第八章:长期记忆

  2. Datawhale《Deep Agents 实战》第九章:Human-in-the-Loop

  3. Deep Agents GitHub

标签: Deep Agents LangGraph Long-term Memory Human-in-the-Loop Checkpointer Agent Harness

相关推荐
树獭哥4 天前
Deep Agents 学习笔记(七):Grading Rubrics——让 Agent 按验收标准自我迭代
deepagent
Mr. zhihao6 天前
Deep Agent 架构深度解析:主Agent与子Agent完整交互机制与核心参数作用
python·ai·langgraph·deepagent
树獭哥10 天前
Deep Agents 学习笔记(三):任务规划与分解——让 Agent 学会拆解复杂任务
deepagent
树獭哥10 天前
Deep Agents 学习笔记(五):Skills——可复用的 Agent 能力包
deepagent
小马过河R2 个月前
开篇|3天从0到1入门AI应用开发
人工智能·语言模型·llm·agent·ai编程·deepagent
深兰科技3 个月前
深兰科技携手绿地集团布局行业智能体,绿地深兰科技智能体科技公司揭牌
人工智能·科技·启发式算法·推荐算法·深兰科技·绿地集团·deepagent
甘露s3 个月前
Eino DeepAgent 详解:让 Agent 从工具调用走向复杂任务执行
ai·agent·deepagent
学Linux的语莫4 个月前
deepagent中agent的易混淆功能区别
deepagent
学Linux的语莫5 个月前
DeepAgents Skills :掌握 Agent 的可复用专业能力
ai·skill·deepagent