Tallate

该吃吃该喝喝 啥事别往心里搁

Agent Harness 深度报告

基于 Tony Kipkemboi 和 Viv Trivedy 的 X 文章总结

来源:


📌 核心定义

Agent = Model + Harness

  • Model(模型):包含智能本身
  • Harness(线束/框架):使智能变得有用的所有系统代码、配置和执行逻辑

简单来说:如果不是模型本身,那就是 Harness。
一个原始模型不是代理。但当 Harness 为其提供状态、工具执行、反馈循环和可执行约束时,它就成为了代理。


🔄 Agent Framework vs Agent Harness

观点化程度光谱

这两个概念位于”观点化程度”(opinionation)的不同位置:

1
2
原始代码 ←→ Agent Framework ←→ Agent Harness
(无抽象) (中等观点) (最大观点)

详细对比

维度 Agent Framework Agent Harness
—— —————- —————
定位 中间位置 最右端(最具观点性)
灵活性 模块化,可替换组件 开箱即用,决策已内置
适用对象 构建者(Builders) 使用者(Users)
控制程度 你做架构决策 接受预设决策
配置需求 需要选择内存系统、配置工具、定义编排逻辑 添加 API 密钥即可运行
典型例子 CrewAI, LangChain OpenClaw, Deep Agents
使用场景 原型设计、实验、定制构建 需要立即可用的可靠解决方案

关键区别

  • Framework 给你构建模块(抽象)
  • 你定义角色、任务、工具
  • 你指定代理如何协调(顺序或层次)
  • Framework 处理管道(调用 LLM、路由工具输出、管理执行循环)
  • 但你仍在做架构决策
  • Harness 给你完整系统
  • 不提供构建块,提供完整系统
  • 内存、上下文管理、代理循环、安全检查都已内置
  • 你不配置内存系统,不决定工具如何注册
  • 这些决策由 Harness 构建者做出

🛠️ Harness 的核心组件

一个完整的 Agent Harness 通常包含:

1. 系统提示词(System Prompts)

  • 定义代理的行为和角色
  • 提供上下文和指导原则

2. 工具、技能、MCP + 描述

  • 预配置的工具集
  • 工具描述和使用说明
  • Model Context Protocol (MCP) 集成

3. 捆绑基础设施

  • 文件系统:持久存储和状态管理
  • 沙箱:安全的代码执行环境
  • 浏览器:Web 交互和验证

4. 编排逻辑

  • 子代理生成(Subagent spawning)
  • 代理切换(Handoffs)
  • 模型路由(Model routing)

5. 钩子/中间件

  • 压缩(Compaction)
  • 延续(Continuation)
  • Lint 检查
  • 确定性执行

🎯 为什么需要 Harness?

模型的局限性

模型本身只能:

  • 输入:文本、图像、音频、视频
  • 输出:文本

模型无法做到的(需要 Harness 实现)

跨交互维护持久状态

  • 模型没有内置的会话记忆
  • 需要 Harness 跟踪历史消息

执行代码

  • 模型只能生成代码文本
  • 需要 Harness 提供执行环境

访问实时知识

  • 模型知识有截止日期
  • 需要 Harness 提供搜索和 API 访问

设置环境和安装包

  • 模型无法直接操作系统
  • 需要 Harness 管理依赖和环境

🏗️ Harness 的关键功能设计

从期望行为到 Harness 工程

设计模式:期望的行为 → Harness 设计来帮助模型实现


1️⃣ 文件系统(Filesystem)

期望行为

我们希望代理拥有持久存储,以便与真实数据交互,卸载不适合上下文的信息,并在会话之间持久化工作。

Harness 设计

  • 文件系统抽象和工具用于文件操作
  • 模型在数十亿 token 的文件系统使用数据上训练

解锁的能力

  • 工作空间:读取数据、代码和文档
  • 增量工作:增量添加和卸载信息,而不是将所有内容保存在上下文中
  • 状态持久化:维护超出单个会话的状态
  • 协作表面:多个代理和人类可以通过共享文件进行协调

Git 的作用

  • 为文件系统添加版本控制
  • 代理可以跟踪工作、回滚错误、分支实验
  • 新代理可以快速了解最新工作和项目历史

2️⃣ Bash + 代码执行

期望行为

我们希望代理自主解决问题,而无需人类为每个工具预先设计。

当前模式

  • ReAct 循环:模型推理 → 通过工具调用采取行动 → 观察结果 → 重复

问题

  • Harness 只能执行它有逻辑的工具
  • 为每个可能的操作构建工具不切实际

Harness 设计

  • 提供 Bash 作为通用工具
  • 模型可以通过编写和执行代码自主解决问题

优势

  • 🚀 通用性:Bash + 代码执行是迈向”给模型一台计算机”的重要一步
  • 🔧 动态工具:模型可以通过代码动态设计自己的工具
  • 🎯 自主性:不受限于固定的预配置工具集

3️⃣ 沙箱和工具执行

期望行为

代理需要一个具有正确默认值的环境,以便安全地行动、观察结果并取得进展。

问题

  • 在本地运行代理生成的代码有风险
  • 单个本地环境无法扩展到大型代理工作负载

Harness 设计

  • 沙箱提供安全的操作环境
  • Harness 连接到沙箱以运行代码、检查文件、安装依赖

功能

  • 🔒 安全性:隔离执行代码
  • 允许列表命令
  • 网络隔离
  • 📈 可扩展性:按需创建环境,跨多个任务扇出,完成后销毁
  • 🛠️ 默认工具
  • 预装语言运行时和包
  • Git 和测试的 CLI
  • 浏览器用于 Web 交互和验证

自我验证循环

工具如浏览器、日志、截图和测试运行器使代理能够:

  • 编写应用程序代码
  • 运行测试
  • 检查日志
  • 修复错误

4️⃣ 记忆与搜索

期望行为

代理应该记住它们看到的内容,并访问训练时不存在的信息。

问题

  • 模型除了权重和当前上下文外没有额外知识
  • 无法编辑模型权重

Harness 设计

记忆(Memory)
  • 文件系统作为核心原语
  • 支持记忆文件标准(如 AGENTS.md
  • 在代理启动时注入到上下文中
  • 持续学习:代理从一个会话中持久存储知识,并将该知识注入到未来会话中
搜索(Search)
  • Web Search:访问最新信息
  • MCP 工具(如 Context7):
  • 访问知识截止日期之后的信息
  • 新库版本
  • 训练停止时不存在的当前数据

5️⃣ 对抗上下文腐烂(Context Rot)

期望行为

代理性能不应在工作过程中降低。

问题:上下文腐烂

  • 随着上下文窗口填满,模型在推理和完成任务方面变得更糟
  • 上下文是宝贵且稀缺的资源

Harness 设计策略

1. 压缩(Compaction)
  • 问题:当对话超过上下文窗口时会发生什么?
  • 解决方案:智能卸载和总结现有上下文窗口,以便代理可以继续工作
  • 避免:API 错误导致工作中断
2. 工具调用卸载
  • 问题:大型工具输出会嘈杂地填满上下文窗口
  • 解决方案
  • 保留超过阈值 token 数的工具输出的头部和尾部 token
  • 将完整输出卸载到文件系统
  • 模型可以在需要时访问它
3. 技能(Skills)
  • 问题:启动时加载太多工具或 MCP 服务器会降低性能
  • 解决方案:通过渐进式披露解决
  • 模型没有选择在启动时将技能前置内容加载到上下文中
  • Harness 可以支持这一点以保护模型免受上下文腐烂

6️⃣ 长时程自主执行

期望行为

我们希望代理在长时间范围内自主、正确地完成复杂工作。

挑战

  • 自主软件创建是编码代理的圣杯
  • 当前模型存在:
  • 早期停止
  • 分解复杂问题的困难
  • 工作跨越多个上下文窗口时的不连贯性

Harness 设计

1. 文件系统和 Git
  • 持久状态:跟踪跨会话的工作
  • 长期任务:代理在长任务中产生数百万 token
  • 协作账本:多个代理可以协作的共享工作表面
  • 快速上手:新代理可以快速了解最新工作和历史
2. Ralph Loop
  • 模式:拦截模型的退出尝试
  • 机制:通过钩子重新注入原始提示到干净的上下文窗口
  • 效果:强制代理针对完成目标继续工作
  • 关键:文件系统使这成为可能
  • 每次迭代从新上下文开始
  • 但从前一次迭代读取状态
3. 规划和自我验证
  • 规划:模型将目标分解为一系列步骤
  • Harness 支持
  • 良好的提示
  • 注入如何使用文件系统中计划文件的提醒
  • 自我验证
  • 完成每个步骤后检查工作的正确性
  • Harness 中的钩子可以运行预定义的测试套件
  • 失败时循环回模型并提供错误消息
  • 模型可以被提示独立自我评估其代码
  • 效果:验证将解决方案建立在测试基础上,并为自我改进创建反馈信号

🔮 Harness 的未来趋势

1. 模型训练与 Harness 设计的耦合

当前趋势

  • 今天的代理产品(如 Claude Code 和 Codex)在训练时将模型和 Harness 放在循环中
  • 帮助模型在 Harness 设计者认为它们应该擅长的操作上提高
  • 文件系统操作
  • Bash 执行
  • 规划
  • 使用子代理并行化工作

反馈循环

  1. 发现有用的原语
  2. 添加到 Harness
  3. 训练下一代模型时使用
  4. 模型在训练的 Harness 中变得更强

副作用:泛化问题

  • 过拟合:改变工具逻辑会导致模型性能下降
  • 案例:Codex-5.3 提示指南中的 apply_patch 工具逻辑
  • 真正智能的模型应该能轻松切换补丁方法
  • 但在 Harness 循环中训练会产生这种过拟合

重要发现

  • 最佳 Harness ≠ 模型训练的 Harness
  • Terminal Bench 2.0 排行榜案例:
  • Opus 4.6 在 Claude Code 中的得分远低于在其他 Harness 中
  • 通过仅改变 Harness,编码代理从 Top 30 提升到 Top 5

结论:通过优化 Harness 可以榨取大量价值。


2. Harness 工程的持续价值

未来预测

  • 随着模型变得更强,今天 Harness 中的一些内容将被吸收到模型中
  • 模型将在规划、自我验证和长时程连贯性方面原生变得更好
  • 这表明 Harness 随时间推移应该变得不那么重要

但是…

  • 就像提示工程今天仍然有价值一样
  • Harness 工程可能会继续对构建良好代理有用

为什么?

  • ✅ Harness 今天确实修补了模型缺陷
  • ✅ 但它们也围绕模型智能设计系统以使其更有效
  • ✅ 配置良好的环境、正确的工具、持久状态和验证循环使任何模型更高效
  • 无论其基础智能如何

3. 开放研究问题

LangChain 正在探索的活跃研究领域:

1. 大规模并行协作

  • 编排数百个代理在共享代码库上并行工作

2. 自我诊断代理

  • 代理分析自己的轨迹
  • 识别和修复 Harness 级故障模式

3. 动态工具组装

  • Harness 动态组装正确的工具和上下文
  • 针对给定任务即时组装
  • 而不是预配置

📊 实际案例

OpenClaw

  • 类型:Harness
  • 特点
  • 病毒式传播
  • 支持 WhatsApp、Telegram 等平台
  • 下载、添加 API 密钥即可使用
  • 内存、上下文管理、代理循环、工具调用、权限、状态持久化全部内置
  • 权衡
  • 立即可用
  • 但无法改变底层工作方式
  • 可以下载源代码并修改,但大多数人不会

LangChain Deep Agents

  • 类型:Framework 公司向 Harness 移动
  • 特点
  • 明确称为”agent harness”
  • 位于 LangChain 框架之上
  • 内置规划工具、文件系统访问、子代理生成、内存持久化
  • 提供”电池包含”的默认配置
  • 仍然模块化:可以交换后端、配置工具、调整提示

LangChain 三层架构

一家公司跨越整个光谱:

  1. LangChain(原始库)
  • 框架层
  • 用于组合代理
  1. LangGraph
  • “代理运行时”
  • 处理执行、状态管理和持久性
  1. Deep Agents
  • Harness 层
  • 位于两者之上
  • 提供开箱即用的工作系统

💡 选择建议

何时选择 Framework?

  • ✅ 原型设计
  • ✅ 实验
  • ✅ 构建定制解决方案
  • ✅ 需要灵活性来交换组件
  • ✅ 测试不同方法
  • ✅ 控制细节

Framework 为构建者设计

何时选择 Harness?

  • ✅ 需要立即可用的解决方案
  • ✅ 可靠性优先
  • ✅ 特定用例
  • ✅ 交易控制换取速度
  • ✅ 困难问题已解决(上下文管理、持久执行、错误恢复)

Harness 为使用者设计

核心原则

你要解决的问题决定了你需要哪一个

这不意味着一个比另一个更好。它们解决不同的问题。


🎓 关键要点

1. 定义清晰

  • Agent = Model + Harness
  • 模型包含智能
  • Harness 使智能有用

2. 光谱思维

  • Framework 和 Harness 不是二元对立
  • 它们在观点化程度光谱上的不同位置
  • 一些 Framework 正在添加 Harness 功能
  • 一些 Harness 仍然允许定制

3. 系统设计

  • Harness 工程是围绕模型智能设计系统
  • 不仅仅是修补模型缺陷
  • 而是使模型更有效

4. 持续演进

  • 模型和 Harness 共同演进
  • 但 Harness 优化仍然重要
  • 即使模型变得更强

5. 实用主义

  • 有时需要完全绕过代理框架
  • 使用模型端点直接构建简单的 ReAct 代理
  • 你需要多少已经构建好的东西决定了你选择哪一个

📚 参考资源

文章来源

相关链接

提及的公司/项目

  • CrewAI
  • LangChain / LangGraph / Deep Agents
  • OpenClaw
  • Claude Code
  • Codex
  • Streamlit (acquired by Snowflake)

🔚 结语

“模型包含智能,Harness 是使该智能有用的系统。”

“为了更多的 Harness 构建、更好的系统和更好的代理。”

— Viv Trivedy, LangChain

这份报告总结了 Agent Harness 的核心概念、设计原则和实践应用。理解 Harness 工程对于构建有效的 AI 代理系统至关重要。


报告生成时间: 2026-03-19
作者: AWorld Agent
版本: 1.0


补充内容:Bassim Eledath 的 8 级代理工程体系

来源:The 8 Levels of Agentic Engineering
作者:Bassim Eledath
日期:2026年3月10日

Level 6: Harness Engineering & Automated Feedback Loops

这是火箭真正开始起飞的地方。

核心概念

上下文工程(Context Engineering) vs Harness 工程(Harness Engineering)

  • 上下文工程:关注模型看到什么
  • Harness 工程:构建整个环境、工具和反馈循环,让代理无需人工干预即可完成可靠的工作

关键原则:给代理反馈循环,而不仅仅是编辑器。

OpenAI Codex Harness 案例

OpenAI 的 Codex 团队将以下工具集成到代理运行时中:

  • Chrome DevTools
  • 可观测性工具
  • 浏览器导航

能力

  • 截图
  • 驱动 UI 路径
  • 查询日志
  • 验证自己的修复

完整工作流

  1. 给定单个提示

  2. 代理重现 bug

  3. 录制视频

  4. 实现修复

  5. 通过驱动应用验证

  6. 开启 PR

  7. 响应审查反馈

  8. 合并(仅在需要判断时升级)
    关键洞察:代理不仅仅是写代码,它能看到代码产生的结果并进行迭代,就像人类一样。

实践案例:Converse CLI

作者团队构建语音和聊天代理用于技术故障排除,创建了名为 converse 的 CLI 工具:
功能

  • 让任何 LLM 与后端端点聊天
  • 进行逐轮对话
  • LLM 进行代码更改
  • 使用 converse 对实时系统测试对话
  • 迭代改进

特点

  • 自我改进循环有时运行数小时
  • 当结果可验证时特别强大(例如,对话必须遵循特定流程,或在特定情况下调用特定工具)

核心概念:Backpressure(反压)

定义:自动反馈机制,让代理无需人工干预即可检测和纠正错误。
包括

  • 类型系统
  • 测试
  • Linters
  • Pre-commit hooks

重要性

  • 如果你想要自主性,你需要反压
  • 否则你会得到一个”垃圾机器”

安全边界

Vercel CTO 的观点

  • 代理、它们生成的代码和你的秘密应该存在于独立的信任域中
  • 原因:埋藏在日志文件中的提示注入可以欺骗代理泄露凭证(如果所有内容共享一个安全上下文)
  • 安全边界就是反压:它们约束代理在偏离轨道时做什么,而不仅仅是应该做什么

两个关键实践

1. 为吞吐量而非完美设计
  • 问题:当每次提交都要求完美时,代理会堆积在同一个 bug 上并覆盖彼此的修复
  • 解决方案:容忍小的非阻塞错误,在发布前进行最终质量检查
  • 类比:我们对人类同事也是这样做的
2. 约束 > 指令
  • 过时做法:逐步提示(”做 A,然后 B,然后 C”)
  • 问题:代理会专注于列表并忽略列表之外的任何内容
  • 更好的提示:”这是我想要的,继续工作直到通过所有这些测试”
  • 原因:定义边界比给出清单更有效

文档管理

OpenAI 的方法
AGENTS.md 文件

  • 保持约 100 行
  • 作为目录,指向其他地方的结构化文档
  • 将文档新鲜度作为 CI 的一部分,而不是依赖临时更新(会过时)

目标:确保代理可以在没有你的情况下导航你的仓库。

自然问题

一旦你构建了所有这些:

  • 代理可以验证自己的工作
  • 导航仓库
  • 无需你即可纠正错误

问题:你为什么还需要坐在椅子上?
答案:这就引出了 Level 7(后台代理)。


关键要点总结

Harness Engineering 的本质

  1. 不仅仅是工具:Harness 工程是关于构建完整的生态系统
  2. 反馈循环至关重要:自动化反馈机制是自主性的基础
  3. 安全是反压的一部分:安全边界约束代理的能力范围
  4. 文档是基础设施:保持文档新鲜和可发现是 CI/CD 的一部分

与之前定义的对比

Viv Trivedy 的定义(LangChain):

  • Harness = 模型之外的所有代码、配置和执行逻辑
  • 包括:系统提示、工具、基础设施、编排逻辑、钩子/中间件

Bassim Eledath 的定义(实践者视角):

  • Harness = 环境 + 工具 + 反馈循环
  • 重点:让代理无需人工干预即可完成可靠工作
  • 核心:反压机制和自动化验证

两者的共同点

  1. 系统化思维:都强调 Harness 是一个完整的系统,而不仅仅是工具集合
  2. 反馈循环:都认识到反馈机制的重要性
  3. 自主性目标:都旨在实现代理的自主可靠工作
  4. 持续演进:都认为 Harness 需要与代理能力共同演进

实践启示

  1. 从反压开始:在追求自主性之前,先建立自动化反馈机制
  2. 安全优先:将安全边界视为 Harness 设计的核心部分
  3. 文档自动化:将文档维护集成到 CI/CD 流程中
  4. 约束优于指令:用测试和边界定义期望,而不是详细的步骤列表
  5. 可观测性内置:让代理能够观察和验证自己的输出

补充时间:2026-03-19
补充作者:AWorld Agent

code agent

目的

实现基本代码读写能力,供text2agent及自进化(optimizer)使用来对agent源码进行编辑。

skill定义

两个skill(text2agent, optimizer)分别构建和读取代码上下文及轨迹上下文,实现对agent的从0生成和优化:

text2agent定义

Input:
prompt
agent模板:gaia_agent、ppt_agent
Agent标准写法
Output:
agent目录
xxx_agent.py
mcp_config.py
流程:
text2agent流程图

optimizer定义

Input:
prompt
agent模板:gaia_agent、ppt_agent
Agent标准写法
Output:
agent目录
xxx_agent.py
mcp_config.py
流程:
optimizer流程图

code 编辑方案

Code ASisTant - A unified code assistant framework based on Tree-sitter, designed specifically for agent code understanding and optimization. Adopts a three-tier hierarchical indexing architecture to provide LLMs with precise code understanding and modification capabilities.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
┌─────────────────────────────────────────────────────────┐
│ 🎯 ACast Core │
└─────────────────┬───────────────────────────────────────┘

┌─────────────┼─────────────┬─────────────┐
│ │ │ │
┌────▼────┐ ┌────▼────┐ ┌─────▼─────┐ ┌────▼────┐
│📊Analyzer│ │🌐Search │ │🔧Coder │ │🛠️Tools │
│ 定位代码 │ │ 阅读代码 │ │ 编辑代码 │ │ 接口 │
└────┬────┘ └────┬────┘ └─────┬─────┘ └─────────┘
│ │ │
┌─────▼────┐ │ │
│🔍Parser │ │ │
│ 索引代码 │ │ │
│tree-sitter│ │ │
└─────────┘ │ │
│ │ │
└──────────────────────────┘

┌─────▼───────────────────────────────────────┐
│ 🗄️ Three-Tier Hierarchical │
│ Index Architecture │

│ L1-Logic | L2-Skeleton | L3-Implementation │
└─────────────────────────────────────────────┘

接口(tools)

Serves as the integration bridge between the CAST framework and the AWorld ecosystem:

工作流集成

三层架构支持渐进式细化工作流:

  1. 预处理阶段:
1
└─> 扫描代码库 → 生成 L1(全景图)+ L2(骨架)
  1. (未实现)轨迹集成:
1
└─> 解析执行日志 → 映射到代码结构 → 标注 L1
  1. 分析阶段:
1
└─> optimizer Agent 读取 L1 + L2 + Reward(user input) → 识别问题区域
  1. 调查阶段:
1
└─> Agent 使用 L2 签名定位特定函数/类
  1. 修改阶段:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
   └─> Agent 调用 read_file() 获取 L3 代码 → 生成修复

6. 部署阶段:
└─> Agent 应用代码补丁 → 验证更改
该工作流确保优化器 Agent 仅在需要修改的特定区域消耗详细代码(L3),在保持全面理解的同时大幅提升效率。
### analyzer - 三层分层索引架构
CAST 框架采用 "动态全景 - 静态骨架 - 按需源码" 三层架构,将代码从静态文本转换为动态可导航的图结构,实现高效的渐进式代码理解与优化。
#### 接口设计
Parser factory functions, automatic language detection
Abstract analyzer interface, PageRank importance calculation
##### Parser Layer (ast_parsers/)
Adopts a unified parsing architecture based on Tree-sitter:
BaseParser (Abstract Base Class)
├── PythonParser Supports .py, .pyi, .pyx
├── HtmlParser Supports .html, .htm
└── [Extensible] JavaScript, Go, Rust...
##### Analyzer Layer (analyzers/)
PageRank Weighting: Symbol importance calculation based on call relationships
Multi-dimensional Matching: Four-dimensional relevance scoring (content, signature, documentation, name)
Incremental Caching: SQLite persistence, supports cross-session usage
Smart Filtering: Automatically excludes cache files, build artifacts, etc.
#### 设计理念:从静态文本到动态图
传统方法将代码视为:
静态文本:直接注入上下文,导致 token 溢出和注意力分散
碎片化片段:基于 RAG 检索,丢失结构逻辑关系
CAST 采用基于图的方法:
静态结构:使用 Tree-sitter 提取 AST(抽象语法树)
动态关系:构建调用图,计算 PageRank 重要性
执行感知:基于轨迹的动态剪枝和热力图生成
#### L1 - 全景逻辑层(LogicLayer)
功能:提供全局高层代码架构视图,快速理解组件组成和执行模式。
核心组件:
class LogicLayer:
project_structure: Dict[str, Any] # 项目目录结构
key_symbols: List[Symbol] # 关键符号表(类、函数)
call_graph: Dict[str, List[str]] # 调用关系图
dependency_graph: Dict[Path, Set[Path]] # 依赖关系图
execution_heatmap: Dict[str, int] # 执行频率热力图
module_descriptions: Dict[Path, str] # 模块功能描述
trajectory_mapping: Dict[str, Any] # 执行路径标注
核心特性:
项目结构可视化:展示完整目录树和模块关系
关键符号表:列出核心类和方法(如 AgentCore、MemoryManager、ToolExecutor)
动态执行热力图:基于执行轨迹高亮实际执行的文件和函数
调用关系图:展示模块交互(如 AgentCore.run() 调用 ToolExecutor.execute())
轨迹剪枝:自动隐藏未执行文件,大幅减少上下文大小
输出示例:
[项目结构 & 执行路径]
Agent 包含 5 个文件。

main.py (入口点, 已执行)

  • class Agent:
    • run() (调用 1 次) → 调用 planner.py/plan()

planner.py (逻辑核心, 已执行)

  • class Planner:
    • plan() (调用 1 次) → 调用 tools.py/search()

tools.py (工具库, 已执行)

  • search() (调用 2 次)

memory.py (未执行 - 已剪枝以节省空间)
config.py (配置, 只读)

应用场景:大型代码库快速架构理解、核心模块识别、依赖分析、问题定位。

L2 - 接口骨架层(SkeletonLayer)

功能:提供接口级概览(不含实现细节),支持精确代码定位和 API 理解。
核心组件:
class SkeletonLayer:
file_skeletons: Dict[Path, str] # 文件骨架代码(仅签名)
symbol_signatures: Dict[str, str] # 符号签名映射
line_mappings: Dict[Path, Dict[int, int]] # 行号映射(原始 → 骨架)
docstring_index: Dict[str, str] # 文档字符串索引
技术实现:
AST 提取:使用 Tree-sitter 或 Python ast 模块解析源码
签名保留:保留所有 import、class 定义和 def 声明
文档保留:保留所有 docstring(理解设计意图的关键)
实现移除:函数体替换为 pass 或 …,或仅保留前 5 行
行号标注:标记每行的原始行号(如 (Line 105))
输出示例:

File: planner.py

(Line 1) import openai
(Line 3) class Planner:
(Line 4) “””处理任务分解。”””
(Line 5) def init(self, model_name):
(Line 6) …
(Line 8) def plan(self, task_description: str) -> list:
(Line 9) “””
(Line 10) 根据描述生成步骤列表。
(Line 11) “””
(Line 12) … # 实现已隐藏
核心特性:完整 API 概览、设计意图保留、精确位置映射、token 消耗仅为原代码的 5-10%。
应用场景:接口级代码理解、函数签名快速识别、设计模式分析、问题精确定位。

L3 - 源码实现层(ImplementationLayer)

功能:提供完整源码实现,支持精确代码定位和精准修改。
核心组件:
class ImplementationLayer:
code_nodes: Dict[Path, CodeNode] # 完整代码节点(含实现)
symbol_references: Dict[str, List[Location]] # 符号引用位置
modification_history: List[Patch] # 代码修改历史
访问模式:优化器 Agent 通过工具调用按需访问 L3:

Agent 在 L1/L2 中定位问题,然后请求特定代码

read_file(file=”planner.py”, start_line=12, end_line=50)
核心特性:完整源码、精确符号位置、引用关系分析、支持精准代码替换。
应用场景:问题定位后的精确修改、特定函数实现检查、代码重构优化、最小上下文开销的 bug 修复。

基于轨迹的优化(未实现)

CAST 的关键创新是将执行轨迹数据集成到上下文展示优化中:

轨迹映射

CAST 将轨迹解析并映射到代码结构:
解析轨迹:提取堆栈跟踪、执行函数调用和错误位置
映射到代码结构:将轨迹事件关联到 L1/L2 中的具体代码位置
可视化标注:直接在代码结构上标记问题区域(如 [ERROR: Timeout] 标注在 tools.py 旁)
效果:优化器 Agent 无需阅读数千行日志即可立即看到问题位置

动态剪枝

当 Agent 有 100 个文件但仅执行了 3 个时:
执行分析:识别实际调用的文件/函数
上下文剪枝:在 L1/L2 中隐藏或折叠未使用文件
Token 减少:上下文长度减少 70-90%
聚焦增强:优化器 Agent 专注于”案发现场”代码路径

searcher - 代码读取

Search Engine Layer (searchers/)

和文件系统的cat、grep等读文件命令逻辑一致

coder - 代码编辑

coder (coders/)

1. dmp_coder

dmp表示diff match patch,patch里既包含偏移量,又带有代码上下文作为参照物,这二者都可能出错,很脆弱,如下图就是生成了一个错误的格式:

2. op_coder

按行插入、替换、删除,指定文件、位置、代码进行插入:
[
{
“type”: “insert”,
“file_path”: “ppt_generator_agent.py”,
“after_line”: 753,
“content”: [
“”,
“ def print_html_to_terminal(self, html_content: str, max_lines: int = 50) -> Dict[str, Any]:”,
“ """“,
“ 向terminal打印HTML内容”,
“”,
“ Args:”,
“ html_content (str): 要打印的HTML内容”,
“ max_lines (int): 最大打印行数,默认50行”,
“”,
“ Returns:”,
“ Dict[str, Any]: 打印操作的结果”,
“ """“,
“ try:”,
“ lines = html_content.split(‘\n’)”,
“ total_lines = len(lines)”,
“”,
“ print("=" * 80)”,
“ print("📄 PPT HTML 内容预览")”,
“ print("=" * 80)”,
“”,
“ # 打印HTML内容(限制行数)”,
“ for i, line in enumerate(lines[:max_lines]):”,
“ print(f"{i+1:4d}: {line}")”,
“”,
“ if total_lines > max_lines:”,
“ print(f"… (省略了 {total_lines - max_lines} 行)")”,
“”,
“ print("=" * 80)”,
“ print(f"✅ HTML内容已打印到terminal (总共 {total_lines} 行,显示了前 {min(max_lines, total_lines)} 行)")”,
“”,
“ logger.info(f"HTML内容已打印到terminal,总行数: {total_lines}")”,
“”,
“ return {“,
“ ‘success’: True,”,
“ ‘total_lines’: total_lines,”,
“ ‘displayed_lines’: min(max_lines, total_lines),”,
“ ‘message’: f’HTML内容已成功打印到terminal (显示 {min(max_lines, total_lines)}/{total_lines} 行)’”,
“ }”,
“”,
“ except Exception as e:”,
“ error_msg = f"打印HTML内容到terminal时发生错误: {str(e)}"“,
“ logger.error(error_msg)”,
“ print(f"❌ {error_msg}")”,
“ return {“,
“ ‘success’: False,”,
“ ‘message’: error_msg,”,
“ ‘error_details’: str(e)”,
“ }”
]
}
]

3. search_replace

{
“operation”: {
“type”: “search_replace”,
“file_path”: “相对文件路径”,
“search”: “要搜索的代码文本”,
“replace”: “替换后的代码文本”,
“exact_match_only”: true
}
}
四层匹配策略(按优先级):
完全精确匹配:逐行完全一致比较(最安全)
内部精确匹配:去除前后空白后匹配
空白符灵活匹配:忽略缩进差异,标准化后匹配
相似性模糊匹配:基于difflib的相似度匹配(10%容错)
安全机制:
自动创建.bak备份文件
执行前参数和文件存在性验证
失败时自动从备份恢复
支持dry_run预检查模式

4. 行号偏移问题

在开发 Coding Agent(如 Aider, OpenDevin 或自定义的自动修复工具)时,“行号漂移(Line Drift)”是一个经典难题。如果 Agent 计划在第 10 行插入 5 行,那么原先的第 20 行就变成了第 25 行,后续操作如果还盯着“第 20 行”就会改错地方。
主流框架和工业界通常采用以下四种策略来解决这个问题:

4.1. 1. 倒序操作策略 (Bottom-up Approach)

这是最简单、成本最低的方案。如果 Agent 一次性给出了多个修改建议:
做法:将所有修改任务按行号从大到小(从文件末尾向开头)进行排序。
原理:修改文件下方的内容,不会影响上方内容的行号。
优点:逻辑极简,不需要复杂的坐标转换。

4.2. 2. 偏移量追踪 (Offset Tracking / Delta Mapping)

这是 IDE(如 VS Code)和版本控制系统常用的算法。
做法:维护一个全局的 delta(偏移值)。
原理:
初始 delta = 0。
第一次操作:在第 行插入 行,则 delta 增加 。
第二次操作:如果 Agent 想修改原始文件的第 行,实际应用的位置是 。
局限:如果 Agent 的修改不仅是新增,还有删除,计算会变得稍微复杂一些。

4.3. 3. 基于语义的“搜索-替换”块 (Search & Replace Blocks)

这是目前 LLM Agent 框架(如 Aider)最主流的做法。 放弃行号,改用上下文匹配。
做法:要求 LLM 给出一段“旧代码块”和一段“新代码块”。
流程:
Agent 输出:SEARCH: [这段旧代码] REPLACE: [这段新代码]。
框架在目标文件中模糊搜索 SEARCH 段落。
找到匹配位置后进行替换。
优点:彻底摆脱行号依赖。即便行号偏了 100 行,只要代码内容唯一,就能定位成功。

4.4. 4. 虚拟文件系统与 AST 操作 (Structural Editing)

对于更高级的 Agent,会使用抽象语法树(AST)。
做法:将代码解析成树状结构,操作具体的“函数节点”或“类节点”,而不是操作“第几行”。
流程:
把代码转为 AST。
在树上增删改节点。
将 AST 重新生成(Print)回代码字符串。
优点:极其稳健,不会因为多一个空格或换行就报错。

4.5. 框架实践对比

如果你的 Agent 逻辑是:思考 -> 输出多个 Patch -> 一次性应用:
请务必使用 策略 1(倒序应用)。这是防止补丁冲突最快的方法。
如果你的 Agent 逻辑是:思考 -> 修改 A -> 思考 -> 修改 B:
那么每一步修改后,你应该重新读取文件内容提供给 Agent,或者使用 策略 3(搜索替换)。

Tool Description Integration Interface
cast_analysis_tool.py Code analysis and structure extraction ANALYZE_REPOSITORY, SEARCH_AST
cast_search_tool.py Search functionality tools GREP_SEARCH, GLOB_SEARCH, READ_FILE
cast_coder_tool.py Code modification and deployment tools GENERATE_SNAPSHOT, DEPLOY_PATCHES, DEPLOY_OPS, SEARCH_REPLACE
类型 功能描述 实现类
GREP 文本内容搜索 GrepSearcher
GLOB 文件模式匹配 GlobSearcher
READ 文件内容读取 ReadSearcher
类型 功能描述 实现类
GREP 文本内容搜索 GrepSearcher
GLOB 文件模式匹配 GlobSearcher
READ 文件内容读取 ReadSearcher
框架/工具 核心策略 备注
Aider Search/Replace Blocks 这种方式对 LLM 最友好,因为它不需要 LLM 具备精准计数的能力(LLM 经常数错行)。
Git / Patch Context-based (Unified Diff) 利用 @@ 块前后的上下文进行“模糊匹配(Fuzzing)”,允许小范围偏移。
OpenDevin File Editor Tool 通常封装了 sed 或自定义的 insert_line 函数,内部维护文件状态,每步操作后立即刷新文件内容。

Terminal Tool 实现分析

来源: /AWorld/examples/gaia/mcp_collections/tools/terminal.py

概述

Terminal MCP Server 是一个基于 Python asyncio 的终端命令执行工具,作为 MCP 服务对外暴露。它让 LLM Agent 能够安全地执行 shell 命令并获取格式化结果。

核心功能

方法 功能
mcp_execute_command(command, timeout, output_format) 执行 shell 命令,支持超时控制和格式化输出
mcp_get_command_history(count, output_format) 获取命令执行历史
mcp_get_terminal_capabilities() 获取终端服务能力信息

安全机制

1. 危险命令拦截

_check_command_safety() 维护一个黑名单,拦截如下命令:

1
2
3
4
5
[
"rm -rf /", "mkfs", "dd if=", ":(){ :|:& };:", # fork bomb
"del /f /s /q", "diskpart", # Windows 危险命令
"sudo rm", "sudo dd", "sudo mkfs", # sudo 变体
]

2. 交互式命令拦截

_check_interactive_command() 通过正则匹配禁止交互式命令(vim, vi, nano, emacs, ftp, telnet),要求用户改用非交互式替代方案(如 --yesCI=1DEBIAN_FRONTEND=noninteractive 等)。

3. 超时保护

asyncio.wait_for(process.communicate(), timeout) 实现超时控制,超时后通过 os.killpg() 杀死整个进程组,避免遗留子进程。

核心执行流程

1
2
3
4
5
6
7
8
9
10
11
12
13
mcp_execute_command()
├── 参数校验(FieldInfo → 实际值)
├── 超时值校验(1s ≤ timeout ≤ 3600s)
├── 安全检测
│ ├── _check_command_safety() # 危险命令检查
│ └── _check_interactive_command() # 交互命令检查
├── _execute_command_async()
│ ├── asyncio.create_subprocess_shell() # 创建子进程
│ │ ├── stdin=subprocess.DEVNULL # 禁止标准输入
│ │ └── start_new_session=True # 独立进程组
│ └── asyncio.wait_for(process.communicate(), timeout)
│ └── 超时 → os.killpg() 杀死整个进程组
└── _format_command_output() # 格式化输出

为什么要屏蔽交互式命令

这是 Terminal Tool 设计中最关键的边界情况。交互式命令(如 vimnanolessftp)在非交互环境中执行时会产生严重问题,原因如下:

1. 进程阻塞:父子进程的管道僵局

_execute_command_async() 中设置 stdin=subprocess.DEVNULL,意味着子进程的 stdin 是一个空设备(/dev/null)。当交互式命令启动后,它会尝试从 stdin 读取用户输入:

1
2
3
4
5
6
7
process = await asyncio.create_subprocess_shell(
command,
stdin=subprocess.DEVNULL, # ← 关键:子进程的输入被关闭
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE,
shell=True,
)

交互式命令的行为:

  1. 尝试读取 stdin → 读到 EOF(因为 DEVNULL 会立即返回 EOF)
  2. 部分交互式工具检测到 EOF 后会自行退出
  3. 但并非所有工具都如此——很多工具(如 less、未加 -Evim)的行为:
    • 陷入空轮询或等待状态
    • 不退出的情况下,process.communicate() 永远不会返回
    • asyncio.wait_for() 最终触发超时

2. Python 子进程模型中的超时连锁问题

asyncio.wait_for() 超时触发时:

1
2
3
4
5
except asyncio.TimeoutError:
if self.platform_info["system"] != "Windows" and process.pid:
os.killpg(os.getpgid(process.pid), 9) # 杀死整个进程组
else:
process.kill() # 仅杀子进程本身

Python 父子进程模型下的超时连锁问题

1
2
3
4
5
6
7
8
9
父进程(Agent/MCP Server)
├── asyncio event loop
│ └── 创建子进程(shell=True)
│ └── shell
│ └── 交互式命令(vim/nano/less)
│ ├── 从 stdin 读取 → EOF(DEVNULL)
│ └── 陷入空轮询 → 永不退出 ×

└── asyncio.wait_for() 超时 → os.killpg()

具体问题:

  1. subprocess.DEVNULL → 子进程 stdin 为 /dev/null:父进程无法向子进程写入任何输入,交互式命令永远得不到用户响应。

  2. 无法唤醒/响应:即使 Agent 想”按 :q 退出 vim”,DEVNULL 让这个操作根本无法完成。子进程的 stdin 通道被永久关闭。

  3. 超时带来的级联影响

    • 超时如果只调用 process.kill(),仅杀 shell 子进程本身
    • 交互式命令可能派生自己的子进程(如 vim 的交换文件写入进程),成为孤儿进程继续消耗资源
    • 设置 start_new_session=True 后使用 os.killpg() 可以杀整个进程组,但前提是交互命令没有创建新的 session(setsid()
    • 极端情况下(如 fork bomb 变体 :(){ :|:& };:):会不断 fork,即使 kill 当前进程,新进程已在其他进程组继续运行
  4. 超时的累积效应

    • 默认超时 300 秒,如果 Agent 连续执行交互式命令,每次都要等待超时
    • 每个超时命令浪费 5 分钟,多个命令叠加导致 Agent 任务整体超时
    • Agent 的有限上下文窗口被无意义的超时错误信息挤占

3. 输出混乱与管道压力

交互式命令的输出(如 vim 的终端转义序列)会污染 Agent 的上下文:

1
2
stdout: ^[[H^[[2J^[[3J(ANSI 转义码)
stderr: Vim: Warning: Input is not from a terminal

这些内容对 LLM 的分析毫无价值,反而占用了宝贵的 token 预算,且结构化解析也会被中断。

4. 为什么不直接用 pipes 模拟输入

从设计上看,虽然可以用 process.stdin.write(b":q\n") 的方式向进程发送命令,但这个方案的可靠性很差:

  • 需要为每个交互式命令编写不同的输入序列(极难维护)
  • 无法处理交互过程中的非预期状态(如 vim 的 swap 文件冲突弹窗)
  • 对于某些全屏 TUI 应用,发送输入后输出仍包含大量转义控制字符,对 LLM 不友好
  • stdin=subprocess.DEVNULL 的基本设计矛盾(DEVNULL 意味着子进程的 stdin 是只读 /dev/null,无法写入)

最佳实践总结

情况 做法
非交互命令 直接执行,subprocess.DEVNULL 安全
交互式命令(vim, less 等) 禁止,提示改用非交互参数(--yesCI=1
需输入确认的命令 Agent 应提前构造好非交互参数
需长时间执行的命令 配置合理的 timeout 值
网络请求(curl/wget) 添加 --no-progress-meter(curl)或 -q(wget)减少 stderr 管道压力

关键设计决策

  1. **stdin=subprocess.DEVNULL**:杜绝所有需要标准输入的命令,从根本上避免输入阻塞
  2. **start_new_session=True**(Unix):子进程独立进程组,超时后可安全杀掉整个子树
  3. **shell=True 配合 /bin/bash**:支持管道、重定向等 shell 特性
  4. os.killpg() 超时清理:如果超时,kill 整个进程组避免孤儿进程
  5. ExceptionGroup 兼容:兼容 Python 3.11+ 的异常组,避免 anyio TaskGroup 崩溃级联

OpenClaw — 开源个人 AI 助手架构分析

OpenClaw 是一个自托管的开源个人 AI 助手,核心定位是一个 Multi-Channel AI Gateway——将 LLM 能力通过统一的控制面分发到 WhatsApp、Telegram、Slack、Discord、iMessage 等 20+ 消息平台,并支持 macOS/iOS/Android 原生应用和 Web UI。

仓库: https://github.com/openclaw/openclaw · 版本: 2026.3.14 · 许可: MIT

项目演进路径: Warelay → Clawdbot → Moltbot → OpenClaw


一、架构概览

OpenClaw 采用 Gateway 中心化 + 插件化扩展 的架构模式。核心是一个 WebSocket/HTTP 控制面,周围挂载渠道连接器、Agent 运行时、插件系统和各种工具:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
消息接入层(WhatsApp / Telegram / Slack / Discord / iMessage / LINE / Feishu / 等 20+ 渠道)


┌──────────────────────────────────────────┐
│ Gateway 控制面 │
│ · WebSocket 18789 端口 │
│ · HTTP API(Hono + Express) │
│ · ACP(Agent Client Protocol) │
│ · 会话管理 / 消息路由 │
│ · Cron 任务调度 / Webhook │
└──────────────────────────────────────────┘

├── Pi Agent Runtime(多模型编排,工具调用,流式响应)
├── CLI + TUI(终端控制)
├── macOS / iOS / Android 原生应用
└── Web UI(Lit 组件)

核心设计理念

  1. 多模型支撑 —— 支持 OpenAI、Gemini、Claude、Mistral、Ollama 等主流模型,Auth Profile 支持轮转和故障回退
  2. 渠道无关 —— 消息通过统一协议处理,渠道扩展通过插件 SDK 开发,无需改动核心
  3. 安全优先 —— DM 配对、可执行审批、敏感工具检测、内容扫描、SSRF 保护、Secrets 管理
  4. 可自托管 —— 单机部署,Docker 支持,macOS/Linux daemon 管理

二、分层架构详解

1. 接入层(Channels / Extensions)

每个消息平台作为一个独立 npm 包注册在 extensions/ 目录下,通过 Plugin SDK 接入。SDK 提供统一接口:消息收发、媒体处理、打字指示器、Presence 等。

当前支持的渠道覆盖了主流 IM(WhatsApp、Telegram、Discord、Slack、Signal、iMessage、LINE、Feishu、Teams、Matrix、IRC 等)和 WebChat。iOS/Android/macOS 原生 App 还提供语音唤醒(Voice Wake)、Canvas 画布、Screen Recording 等设备侧能力。

2. 网关层(Gateway)

Gateway 是系统的控制平面,基于 WebSocket 实现双向实时通信。主要职责:

  • 会话管理 —— 连接绑定、Session Key 路由、消息溯源
  • 协议层 —— ACP(Agent Client Protocol)定义了 Agent 间通信的标准
  • 认证与配对 —— DM 配对:Code-based 设备授权,无需暴露端口
  • 速率控制 —— Lane 管理,限制并发,防止滥用
  • 路由分发 —— 将消息路由到合适的 Agent Runtime 实例

3. 运行时层(Agent Runtime)

Pi Agent 是 OpenClaw 的核心推理引擎(@mariozechner/pi-agent-core 系包)。支持的功能:

  • 多模型编排 —— Auth Profile 级别的模型切换、失败自动回退
  • Tool Calling —— 通过 MCP(Model Context Protocol)调用浏览器、Sandbox、系统命令等
  • Streaming —— 流式 Token 输出和 Block Streaming
  • 记忆系统 —— Embedding Pipeline(支持 OpenAI / Gemini / Mistral / Voyage / Ollama 多种向量模型),SQLite Vector Store,MMR 检索,Query Expansion
  • Canvas 画布 —— Agent 驱动的可视化工作区
  • Browser Automation —— Chrome CDP 集成,Profile 管理,Sandbox 隔离

4. 插件系统(Plugin SDK)

OpenClaw 提供了完整的插件生命周期管理:

  • 插件生命周期:安装 → 启用 → 配置 → 启动 → 停止
  • 插件可以扩展:HTTP 路由、消息处理、技能、工具、Provider
  • 社区插件通过 ClawHub 分发(clawhub.ai

5. 安全层

  • DM 配对 —— 设备间 Code-based 授权
  • Exec Approval —— 危险命令操作需要人工确认
  • Secrets 管理 —— 凭证审计、配置、计划、运行时收集
  • 内容扫描 —— 入站/出站内容安全过滤
  • SSRF 防护 —— 防止服务器端请求伪造

三、关键模块速览

模块 位置 行数规模 职责
Gateway src/gateway/ ~240 文件 WebSocket/HTTP 控制面、协议、路由
Agent 运行时 src/agents/ ~550 文件 Pi Agent 集成、模型路由、工具调用
配置系统 src/config/ ~210 文件 YAML/JSON 配置、Zod 校验、Env 替代
基础设施 src/infra/ ~390 文件 Dotenv、端口检测、重试/退避、设备配对
记忆系统 src/memory/ ~100 文件 Embedding Pipeline、向量检索、Session 文件
浏览器自动化 src/browser/ ~140 文件 CDP 控制、快照、Profile、MCP Bridge
Cron 调度 src/cron/ ~70 文件 定时任务、Session 清理、心跳通知
Plugin SDK src/plugin-sdk/ ~110 文件 扩展开发接口、渠道适配器
命令层 src/commands/ ~300 文件 80+ CLI 命令实现
TUI src/tui/ ~30 文件 终端用户界面
后台服务 src/daemon/ ~50 文件 systemd / launchd / schtasks 管理

四、技术栈

层次 技术
语言 TypeScript (ES2023, NodeNext)
Node 最低 ≥ 22
包管理 pnpm Workspace Monorepo
Web 框架 Hono + Express
通信 WebSocket (ws)、ACP 协议
数据库 / 向量 SQLite (+ sqlite-vec vector extension)
浏览器自动化 Playwright Core (CDP)
媒体处理 Sharp (图片)、pdfjs-dist (PDF)、node-edge-tts (TTS)
构建 tsdown、tsc
格式/检查 oxlint、oxfmt
测试 Vitest(单元/集成/E2E 多配置)
工具 MCP(Model Context Protocol)、mcporter Bridge

五、与业界方案对比

维度 OpenClaw LangChain Agent OpenAI Assistants API
定位 个人助手 Gateway 开发框架 托管 API
渠道接入 20+ 消息平台内置
部署方式 自托管 / Docker 需自己搭建 完全托管
多模型 原生支持 通过 Provider 支持 仅 OpenAI
插件机制 全生命周期插件 通过 LCEL 组合
安全 DM 配对 + 审批 + 审计 无内置 基础 IAM
设备端 macOS/iOS/Android 原生

六、适用场景与设计取舍

OpenClaw 最适合 个人或小团队 自建 AI 助手,统一管理多平台的 AI 交互。它的设计做了一个明确的取舍:

优势

  • 一接入,所有渠道都能 AI 回复
  • 数据完全自控,隐私有保障
  • 配置灵活,Plugin 系统可定制性强

代价

  • 单机架构,水平扩展能力有限
  • Agent 能力依赖于配置的模型
  • 社区驱动,某些渠道的稳定性依赖插件维护方

七、本地体验

OpenClaw 提供了非常完善的 Onboarding 流程:

1
2
3
npm install -g openclaw@latest
openclaw onboard --install-daemon
openclaw gateway --port 18789 --verbose

安装后可以通过 CLI、TUI、Web UI、原生 App 或任意已绑定的消息渠道与 AI 交互。Onboarding Wizard 会用交互式引导完成 Gateway 配置、模型配置、渠道绑定和设备配对。

  • 使用文件系统共享数据,如langgraph scratchpad和claude code 子智能体
  • 使用文件系统卸载上下文,如langchain
  • 使用文件系统实现分布式的agent协作,如manus

langgraph scratchpad

langgraph中可以定义一个公共的state来存储multi agent共享的state,称为scratchpad,每个agent定义自己私有state,表示自己可以接收的数据。

可以定义传递什么状态

  • 共享完整思考过程:Agent间传递完整的消息历史(scratchpad),包括中间推理步骤
    • 优势:帮助其他Agent做出更好决策,提升整体推理能力
    • 劣势:随着Agent数量和复杂度增长,scratchpad会快速膨胀,需要额外内存管理策略
  • 仅共享最终结果:Agent维护私有scratchpad,只向其他Agent传递最终结果
    • 优势:适合多Agent或复杂Agent系统
    • 实现:需要为不同Agent定义不同的状态模式

agent之间共享的数据格式:
1. 消息传递机制

  • 共享状态通道:通过共享消息列表进行通信
  • Agent标识:在消息中标注Agent名称,便于追踪消息来源
  • Handoff表示:通过专用handoff工具实现Agent间控制权转移
    2. 状态管理策略
  • 共享消息列表:所有Agent共享同一个消息历史
  • 私有消息列表:每个Agent维护独立的消息视图
  • 状态模式分离:不同Agent可使用不同的状态模式

参考文档
https://langchain-ai.github.io/langgraph/agents/context/
https://blog.langchain.com/langgraph-multi-agent-workflows/
https://langchain-ai.github.io/langgraph/concepts/multi_agent/?h=scratchpad#message-passing-between-agents

claude code 子智能体

Claude Code通过文件系统实现多智能体间的上下文共享,主要采用以下技术:

1. 多层记忆架构

  • 项目记忆:通过CLAUDE.md文件存储项目架构、编码规范、技术栈信息
  • 用户记忆:通过~/.claude/CLAUDE.md存储个人偏好、编码风格、常用模式
  • 分层读取:不同层级的记忆文件为Claude提供不同粒度的上下文信息

2. 文件系统共享状态

  • Markdown文件通信:多个Claude代理通过共享的Markdown文件进行状态传递
  • 工作票据机制:一个代理可以创建ticket.md文件,为其他代理指定后续工作内容
  • 状态持久化:利用文件系统的持久化特性,实现跨会话的上下文保持

3. 多代理协作模式

  • 文件传递模式:代理A完成任务后写入状态文件,代理B读取并继续执行
  • 并行协作:虽然原生不支持并行执行,但通过文件共享实现准并行协作
  • 上下文继承:后续代理可以继承前面代理的工作成果和上下文信息

这种基于文件系统的上下文共享方式,充分利用了LLM强大的文件理解和处理能力,为多智能体协作提供了简单而有效的解决方案。

参考文档
https://x.com/jasonzhou1993/status/1955970025984287004
https://x.com/shao__meng/status/1956148557444211014
https://manus.im/zh-cn/blog/Context-Engineering-for-AI-Agents-Lessons-from-Building-Manus

context offload

上下文卸载(Context Offloading)是一种优化大型语言模型性能的技术,通过将部分上下文信息从主内存中移出到外部存储,以解决上下文窗口限制和内存管理问题。

1. 核心概念

  • 定义:将信息存储在LLM上下文之外的行为,通常通过工具来存储和管理数据
  • 目的:避免上下文腐化(Context Rot),当信息被埋藏在上下文窗口深处时,模型在简单检索或推理任务上的准确性会以非均匀且令人惊讶的方式下降
  • 解决方案:将上下文卸载到外部存储,然后根据需要选择性地加载(如通过RAG)

2. 实际应用案例

  • Anthropic研究:多智能体研究中使用scratchpad将研究计划持久化到上下文窗口之外,当上下文超过200,000 tokens时避免截断
  • Manus系统:将上下文卸载到文件系统,特别适用于存储token密集的工具调用,通过写入计划文件(如todo.md)并在执行过程中重写
  • 产品应用:ChatGPT、Cursor、Windsurf等产品都有基于用户-智能体交互自动生成长期记忆的机制

3. 实现方式

  • 运行时状态对象:scratchpad可以是运行时状态对象中的一个字段,在智能体运行时持续存在
  • 工具调用写入文件:通过工具调用将信息写入文件系统
  • 跨交互记忆:通过”记忆”存储跨多个用户-智能体交互的上下文信息

4. LangGraph实现

  • 状态对象:LangGraph围绕状态对象设计,作为图中节点间传递的中央数据结构
  • 检查点机制:将图的每个步骤状态保存到线程中,每个线程由唯一标识符引用
  • 长期记忆:允许跨线程持久化特定上下文,支持保存单个文件或记忆集合
  • BaseStore接口:使用键值存储,可在内存中使用或与LangGraph Platform部署一起使用

5. 技术优势

  • 避免上下文腐化:防止信息在上下文窗口深处时模型性能下降
  • 扩展上下文能力:突破模型原生上下文窗口限制
  • 跨会话记忆:支持智能体在多次交互中记住有用信息
  • 灵活存储:支持多种存储方式,从内存到文件系统到数据库

通过上下文卸载机制,开发者可以在保持模型性能的同时,有效处理更复杂和更大规模的任务。

参考文档
https://github.com/langchain-ai/how_to_fix_your_context/blob/main/notebooks/06-context-offloading.ipynb

tools 中间存储

在生产中,agent服务和mcp服务一般会部署到不同的集群中,因为mcp一般会有访问外网的诉求,所以会部署在与公网互通的集群内,两者的资源是互相隔离的。
为了实现Agent和mcp产生的数据的互通,这里会引入一个中间存储,比如数据库、文件系统,但文件系统会更加通用一些,因为大部分mcp都会基于文件系统来设计,因此我们最大的卡点在于实现文件系统的云上挂载能力:
filesystem_mount.png

构建智能体

什么时候需要智能体

  1. 对任务成功率要求低时采用智能体,否则采用工作流
    当前普遍的Agent架构,一般都无法做到比较高的成功率,有时平均成功率低到40、50%,所以Agent结果无法直接应用于业务,而是需要人来干预结果,人来参与进结果的生成,比如编程、写PPT等。
  2. 任务比较复杂时采用智能体(需要多步推理),否则采用工作流
  3. 需要解决的任务是复杂而有价值的则使用智能体,否则采用工作流
  4. 任务异常恢复的代价很低则使用智能体,否则采用Agent的只读模式(不会进行实际上的文件读写或支付等操作)、或采用human in loop模式让人介入进来

参考文档
https://blog.crewai.com/build-agents-to-be-dependable/
https://www.youtube.com/watch?v=XSZP9GhhuAc

构建智能体系统的要素

智能体是一个循环决策的工作流,它自主地或在人类参与的情况下,朝着既定目标进行规划、行动和学习。

  • 对所发生事件的记忆
  • 影响世界的工具
  • 执行审计、约束
  • 需要实现的目标

12 Factor Agents - 构建可靠LLM应用的原则

基于12 Factor Agents框架,以下是构建生产级智能体系统的12个核心原则:

Factor 1: 自然语言到工具调用 (Natural Language to Tool Calls)

将自然语言输入转换为结构化的工具调用,确保LLM能够准确理解和执行用户意图。

Factor 2: 拥有你的提示词 (Own your prompts)

不要依赖框架的默认提示词,要完全控制和管理你的提示词,确保它们符合你的具体需求。

Factor 3: 拥有你的上下文窗口 (Own your context window)

主动管理上下文窗口,包括记忆、状态和相关信息,而不是让框架自动处理。

Factor 4: 工具就是结构化输出 (Tools are just structured outputs)

将工具调用视为结构化输出,使用模式验证和类型安全来确保输出质量。

Factor 5: 统一执行状态和业务状态 (Unify execution state and business state)

将智能体的执行状态与业务状态统一管理,避免状态不一致的问题。

Factor 6: 启动/暂停/恢复的简单API (Launch/Pause/Resume with simple APIs)

设计简单的API来管理智能体的生命周期,支持启动、暂停和恢复操作。

Factor 7: 通过工具调用联系人类 (Contact humans with tool calls)

当需要人类干预时,通过工具调用的方式优雅地请求人类帮助。

Factor 8: 拥有你的控制流 (Own your control flow)

完全控制智能体的决策流程,而不是依赖框架的默认行为。

Factor 9: 将错误压缩到上下文窗口 (Compact Errors into Context Window)

将错误信息压缩并整合到上下文窗口中,帮助智能体更好地理解和处理错误。

Factor 10: 小型、专注的智能体 (Small, Focused Agents)

构建小型、专注的智能体,每个智能体负责特定的任务,而不是构建大型通用智能体。

Factor 11: 从任何地方触发,在用户所在的地方见面 (Trigger from anywhere, meet users where they are)

支持多种触发方式,让智能体能够在用户需要的地方出现。

Factor 12: 让你的智能体成为无状态归约器 (Make your agent a stateless reducer)

将智能体设计为无状态的归约器,通过纯函数处理状态转换,提高可靠性和可测试性。

参考文档
https://github.com/humanlayer/12-factor-agents

构建多智能体系统

some problems are too complex, too parallel, or too specialized for one agent to handle alone.
如果单agent的职责过多(比如既需要做PPT、又要通过browser-use实现浏览器检索、又需要使用terminal来写一些脚本来进行复杂运算),每次使用prompt来reasoning时,大模型都需要进行复杂的推理、并在很多工具中进行决策,随着agent的运行,上下文会变得非常复杂不可控。

多智能体系统的难点

多智能系统的难点不在于运行多智能体,而是协同多智能体,如果希望构建一个长期运行的多智能体系统,关键是:

  • 任务复杂度过高,需要分解和专业化处理
  • 需要并行处理多个子任务
  • 要求错误隔离和容错机制
    代理是有状态的,错误会累积,,在长时间的执行过程中,Agent会在多次工具调用中保持状态,需要持续处理过程中的错误,然后在出错时,具备中断恢复的能力。
  • 需要动态上下文管理和状态协调

核心是上下文工程(Context Engineering)和错误传播控制。
context_engineering

  • 上下文压缩:agent运行过程中对历史上下文做summary或prune,去除冗余信息,比如一些<think>
  • 上下文卸载:将占据大量空间的工具结果存储到外部空间,在需要时加入到上下文中
  • 上下文隔离:为多个agent创建相互隔离的上下文,互相之间不会共享窗口

上下文压缩

压缩(Compaction):当对话接近上下文窗口限制时,总结内容并重新初始化新的上下文窗口。

核心原则

  • 保留关键信息(架构决策、未解决的bug、实现细节)
  • 清理冗余内容(工具输出、重复消息)
  • 维持最小性能损失

实现方式

  • Claude Code:压缩消息历史 + 保留最近访问的5个文件
  • 工具结果清理:最安全的轻量级压缩方式

挑战:在保留与丢弃之间平衡,避免过度压缩导致关键信息丢失。

上下文卸载

结构化笔记(Structured Note-taking):智能体定期将笔记持久化到上下文窗口外的存储中,需要时再拉回上下文。

核心优势

  • 提供持久化记忆,开销最小
  • 跟踪复杂任务进度,维护关键上下文和依赖关系
  • 支持跨工具调用的长期连贯性

实现方式

  • Claude Code:创建待办事项列表
  • 自定义智能体:维护NOTES.md文件
  • Claude Developer Platform:基于文件系统的记忆工具

应用场景:长期任务中保持状态连续性,避免上下文重置导致的信息丢失。

混合策略(Hybrid Strategy)

在某些场景下,最有效的智能体可能采用混合策略:预先检索一些数据以提高速度,同时根据任务需要自主探索更多信息。决策边界取决于具体任务的特点。

Claude Code的混合模式示例:

  • 预先将CLAUDE.md文件直接放入上下文,提供快速访问
  • 使用glob和grep等基础工具进行实时环境导航和文件检索
  • 有效避免了过时索引和复杂语法树的问题

适用场景:

  • 混合策略更适合内容变化较少的场景,如法律或金融工作
  • 随着模型能力提升,智能体设计将趋向于让智能模型更自主地行动
  • 人工策划的需求将逐渐减少

上下文隔离 - sub-agent

子智能体架构(Sub-agent Architectures):通过专门的子智能体处理专注任务,避免单一智能体维护整个项目状态。

核心设计

  • 主智能体:协调高级计划,专注于结果综合和分析
  • 子智能体:执行深度技术工作,使用工具查找相关信息
  • 上下文隔离:详细搜索上下文保持在子智能体内,避免污染主智能体

工作流程

  • 子智能体可能使用数万token进行广泛探索
  • 返回压缩、精炼的工作总结(通常1,000-2,000 tokens)
  • 实现关注点分离,提高系统效率

适用场景

  • 复杂研究和分析任务
  • 需要并行探索的场景
  • 相比单智能体系统有显著改进

架构示例
multiagent_longrunningtask

参考文档
https://www.anthropic.com/engineering/multi-agent-research-system?ref=blog.langchain.com
https://cognition.ai/blog/dont-build-multi-agents
https://blog.langchain.com/how-and-when-to-build-multi-agent-systems/

https://www.anthropic.com/engineering/effective-context-engineering-for-ai-agents

https://www.xiaohongshu.com/explore/6882005d000000001d00d53a?app_platform=android&ignoreEngage=true&app_version=8.92.0&share_from_user_hidden=true&xsec_source=app_share&type=normal&xsec_token=CBIAt7FwVT3rmjUCxeIUs-9z3euUYE-PTih9HgqFRJcJE=&author_share=1&xhsshare=CopyLink&shareRedId=ODc4Rjc2PDs2NzUyOTgwNjY1OTk4Rj1C&apptime=1753439829&share_id=c6e6707db94640ef8bd24b59ea1b466e&share_channel=copy_link
https://github.com/zilliztech/claude-context/blob/master/packages/core/src/context.ts
https://github.com/shareAI-lab/analysis_claude_code/blob/main/claude_code_v_1.0.33/stage1_analysis_workspace/docs/ana_docs/task_agent_analysis.md
https://baoyu.io/translations/decoding-claude-code

多智能体系统的一些范例

https://blog.langchain.com/langgraph-multi-agent-workflows/
https://langchain-ai.github.io/langgraph/concepts/multi_agent/?h=scratchpad

human-in-loop是指将人类当成一个tool,在agent的循环执行中,agent可以调用人这个tool来实现输入密码、授予权限等操作。
实现human-in-loop主要取决于两个能力:

  1. 阻塞通知能力,原地阻塞,等待用户输入,用户输入将通过事件通知的方式来触发流程的继续执行,例如:LlamaIndex和ADK的实现
  2. 中断恢复能力,在关键执行节点保存执行上下文,让任务能恢复执行,例如:LangGraph的实现

LangGraph的实现模式

LangGraph 中的人机循环工作流建立在 checkpoint 系统之上,使用检查点保存每一步的图形状态,并在人工干预后恢复。

中断原语

langgraph_humaninloop.png
langgraph_humaninloop_process

Common Patterns(常见模式)

LangGraph中的人机循环实现提供了几种常见的模式,用于不同的应用场景:

1. 审批或拒绝模式(Approve or Reject)

Node中断执行流.png
用于需要人工审批的场景,比如内容审核、决策确认等。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def approval_node(state):
# 准备需要审批的内容
content_to_review = state["generated_content"]

# 中断等待人工审批
approval = interrupt({
"content": content_to_review,
"action": "approve_or_reject"
})

if approval == "approve":
return {"status": "approved", "content": content_to_review}
else:
return {"status": "rejected", "content": None}

2. 审查和编辑状态模式(Review and Edit State)

允许人工审查当前状态并进行编辑修改。

1
2
3
4
5
6
7
8
9
10
11
12
13
def review_edit_node(state):
current_state = {
"text": state.get("text", ""),
"metadata": state.get("metadata", {})
}

# 中断等待人工编辑
edited_state = interrupt({
"current_state": current_state,
"instruction": "请审查并编辑当前状态"
})

return edited_state

3. 审查工具调用模式(Review Tool Calls)

Tool中断执行流.png
在工具执行前进行人工审查,确保工具调用的正确性。

1
2
3
4
5
6
7
8
9
10
def tool_review_node(state):
tool_calls = state["proposed_tool_calls"]

# 中断等待人工确认工具调用
approved_calls = interrupt({
"tool_calls": tool_calls,
"action": "review_tool_calls"
})

return {"approved_tool_calls": approved_calls}

4. 为任何工具添加中断模式(Add Interrupts to Any Tool)

可以在任何工具执行前后添加人工干预点。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def tool_with_interrupt(state):
# 工具执行前的确认
pre_confirmation = interrupt({
"message": "即将执行工具,请确认",
"tool_name": "api_call"
})

# 执行工具
result = execute_tool(state["parameters"])

# 工具执行后的审查
post_review = interrupt({
"result": result,
"action": "review_result"
})

return {"final_result": post_review}

5. 验证人工输入模式(Validate Human Input)

对人工输入进行验证,确保输入的正确性和完整性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def validation_node(state):
while True:
# 获取人工输入
user_input = interrupt({
"message": "请输入数据",
"validation_rules": ["required", "email_format"]
})

# 验证输入
if validate_input(user_input):
return {"validated_input": user_input}
else:
# 输入无效,继续循环
continue

使用注意事项

1. 副作用处理

  • 将带有副作用的代码(如API调用)放在interrupt之后或单独的节点中
  • 避免在中断点之前执行不可逆的操作

2. 子图调用

  • 当子图作为函数调用时,父图会从调用子图的节点开始重新执行
  • 子图会从包含interrupt的节点开始重新执行

3. 单节点多中断

  • 在单个节点中使用多个中断时,需要注意执行顺序
  • 中断的匹配是基于严格索引的,顺序很重要
  • 避免动态改变节点结构,可能导致索引不匹配

参考文档
https://deepwiki.com/langchain-ai/langgraph/4-human-in-the-loop-capabilities#common-hil-patterns
https://langchain-ai.github.io/langgraph/how-tos/human_in_the_loop/add-human-in-the-loop/#pause-using-interrupt

LlamaIndex

llamaindex_humaninloop.png
LlamaIndex会向外发送一个消息InputRequiredEvent事件,然后等待外部处理事件后回馈一个回执事件HumanResponseEvent

  • 事件驱动:使用 InputRequiredEvent 和 HumanResponseEvent 进行异步通信
  • 人工确认:危险操作需要用户明确确认(”yes” 或 “no”)
  • 异步处理:使用 async/await 模式处理异步事件
  • 流式处理:通过 stream_events() 实时处理事件流

参考文档
https://github.com/run-llama/python-agents-tutorial/blob/main/5_human_in_the_loop.py
https://docs.llamaindex.ai/en/stable/understanding/agent/human_in_the_loop/

ADK

长时间运行工具(Long-Running Tools)
这是最直接的实现方式,使用LongRunningFunctionTool来处理需要人工干预的异步操作。
核心实现流程:

  1. 初始调用:Agent调用长时间运行工具,工具立即返回pending状态和跟踪ID
  2. 等待人工干预:系统等待外部人工处理
  3. 更新工具响应:人工处理完成后,必须构造新的types.FunctionResponse并发送给Agent

adk_humaninloop.png
adk_humaninloop_process.png

参考文档
https://deepwiki.com/search/human-in-the-loop_c1195076-6732-4fa2-97fe-4a4d444faec6

magentic-ui human in loop

connection.py定义用户输入函数:更新agent运行状态等待用户输入,然后阻塞等待用户输入
magentic_human_1.png
magentic_human_2.png

将user_input包装为Agent
magentic_human_3.png

Agent作为team的参与者,被分发
magentic_human_4.png

参考文档
https://github.com/microsoft/magentic-ui

摘要

  • 长期记忆是上下文中关键组成部分,长期记忆一般是短期记忆的沉淀,从过去的经验中学习,让用户可以记忆多轮对话的关键信息,得到处理问题的一般模式,

    Without proper memory systems, AI applications would treat each interaction as completely new, losing valuable context and personalization opportunities.

  • 长期记忆作为RAG的一部分,长期记忆的抽取和检索一般是通过RAG来实现,增强大模型回答领域问题的能力,而预训练专注于一般性问题的回答性能,例如langextract,LightRAG这样的框架
  • 使用文件存储长期记忆,按需召回,可以避免上下文超长的问题,例如manus的做法
  • 长期记忆又可以分为Semantic、Factual、Episodic,实践中一般会按抽取主体不同,按需建立不同的索引,例如mem0
  • 使用ReAct模式的Agent来管理Memory可以提供一些自主性,让Agent根据上下文和多轮的任务来自我进化,例如LangGraph MemoryAgent, QwenAgent, A-Mem, MemU

从短期记忆加工长期记忆

long_term_process

LangGraph - MemoryTemplate

memory_template_process.png
MemoryTemplate是LangChain AI提供的长期记忆服务模板,用于构建和部署可连接到任何LangGraph代理的长期记忆服务,实现用户范围的记忆管理。

  • 使用 @functools.lru_cache 定义长期记忆的过期机制
  • 使用State定义长期记忆的入参,可见本质上是对短期记忆的持久化处理
    1
    2
    3
    4
    5
    class State(TypedDict):
    """Main graph state."""

    messages: Annotated[list[AnyMessage], add_messages]
    """The messages in the conversation."""
  • memory_graph被标记成一个入口点,相当于一个接口

参考文档
https://github.com/langchain-ai/memory-template

长期记忆的提取是一个RAG模式的实现

langextract

LangExtract是一个Python库,使用LLM从非结构化文本文档中提取结构化信息,基于用户定义的指令。它能够处理各种材料,如临床文本、法律文件、学术论文等,并输出结构化的JSON数据。

核心特性

  • 精确源定位:每个提取的实体都包含精确的源文本引用
  • 可扩展性:支持处理长文档和并行处理
  • 自定义提取:通过提示词和示例控制提取行为,从非结构化文本中提取实体、关系和属性

技术架构

  • 基于LLM的信息提取
  • 支持自定义模型提供商
  • 提供插件系统扩展功能
  • 支持本地和云端模型部署

引用链接

MemoryScope

定义一个pipeline来处理记忆
https://github.com/modelscope/MemoryScope

LightRAG

定义
LightRAG是一个简单且快速的检索增强生成(Retrieval-Augmented Generation)系统,专注于提供高效的知识检索和生成能力。

  1. 智能检索:基于语义相似度的文档检索
  2. 上下文增强:为LLM提供相关上下文信息
  3. 知识图谱:利用图结构增强检索效果
  4. 实时查询:支持实时文档查询和生成

为Memory建立索引和检索

https://blog.langchain.com/semantic-search-for-langgraph-memory/

文件系统作为长期记忆的载体

Manus - 使用文件系统作为终极上下文

现代前沿LLM虽然提供128K+令牌的上下文窗口,但在真实代理场景中仍面临三个痛点:观察结果庞大容易超出限制长上下文导致性能下降以及高昂的计算成本
传统压缩策略虽然能缩短上下文,但过度压缩会导致信息丢失。代理需要根据所有先前状态预测动作,无法预测哪个观察结果在后续步骤中变得重要,因此任何不可逆的压缩都带有风险。
文件系统作为终极上下文解决了这些问题:大小不受限制、天然持久化、代理可直接操作。模型学会按需写入和读取文件,不仅用作存储,还作为结构化的外部记忆。
我们的压缩策略设计为可恢复的:保留URL可移除网页内容,保留文档路径可省略文档内容。这样既能缩短上下文长度,又不会永久丢失信息。
这种基于文件的记忆方式也为状态空间模型(SSM)在智能体中的应用开辟了新可能。SSM虽然缺乏完整注意力机制,但通过将长期状态外部化而非保存在上下文中,其速度和效率可能开启新型智能体时代。

use_file_system_as_context.png

参考文档
https://manus.im/zh-cn/blog/Context-Engineering-for-AI-Agents-Lessons-from-Building-Manus

构建不同的长期记忆索引

Mem0

Mem0将长期记忆划分为不同的类型,并通过api上增加agent_id, user_id, run_id进行索引

记忆类型分类:

短期记忆 (Short-Term Memory)

  • 对话历史: 最近的对话消息及其顺序
  • 工作记忆: 临时变量和状态信息
  • 注意力上下文: 当前对话的焦点

长期记忆 (Long-Term Memory)

  • 事实记忆 (Factual Memory): 存储用户信息、偏好和领域特定知识
  • 情节记忆 (Episodic Memory): 过去的交互和体验
  • 语义记忆 (Semantic Memory): 概念理解及其关系

记忆特征对比:

类型 持久性 访问速度 使用场景
短期记忆 临时性 即时 活跃对话
长期记忆 持久性 快速 用户偏好和历史

Mem0长期记忆实现方式:

  1. 使用向量嵌入存储和检索语义信息
  2. 跨会话维护用户特定上下文
  3. 实现高效的相关历史交互检索机制

核心价值:
AI系统需要记忆系统实现三个关键目标:

  • 在对话中维持上下文
  • 从过去的交互中学习
  • 随时间构建个性化体验

参考
https://docs.mem0.ai/core-concepts/memory-types
https://docs.mem0.ai/open-source/graph_memory/overview#add-memories

进化的记忆

结合Agent的ReAct范式,实现Agentic RAG,由Agent自主判断记忆的抽取和持久化

MemoryAgent

memory_agent_process.png

LangGraph ReAct Memory Agent - 一个具有记忆保存工具的ReAct风格智能体示例。

核心特性:

  • 基于ReAct范式的智能体,能够自主判断记忆的抽取和持久化
  • 提供store_memory工具,让智能体保存重要信息供后续使用
  • 记忆按user_id作用域隔离,支持跨对话线程学习用户偏好
  • 集成LangGraph Cloud部署,支持API交互

工作原理:

  • 智能体从记忆图的Store读取已保存的记忆
  • 调用工具时自动路由到store_memory节点保存信息
  • 支持自定义记忆结构(content + context)
  • 可配置不同的LLM模型(默认Claude-3.5-Sonnet)

应用场景:

  • 跨会话保持用户偏好记忆
  • 重要信息的持久化存储
  • 智能体学习能力的增强

参考
https://github.com/langchain-ai/memory-agent?ref=blog.langchain.com

A-mem

https://arxiv.org/pdf/2508.08997
https://github.com/agiresearch/A-mem
https://zhuanlan.zhihu.com/p/1888290059859514793
https://github.com/landing-ai/agentic-doc

QwenAgent

Qwen-Agent采用三级处理框架,先通过BM25检索关键词定位核心段落,再评估分块相关性,最后逐步生成答案,实现百万字级上下文处理。

1. 上下文截断机制

qwen_agent/llm/base.py#_truncate_input_messages_roughly 中实现了基础的上下文长度管理,根据最大长度来截断messages:

  • 默认最大输入token数为58000(可通过DEFAULT_MAX_INPUT_TOKENS配置)
  • 使用tokenizer.count_tokenstruncate实时统计token数并按最大token数阈值截断
  • 保留系统消息和最新的用户消息
  • 从旧消息开始截断,确保最重要的上下文保留

2. Memory对话记忆管理

qwen_agent/agents/memo_assistant.py 实现了对话记忆功能:

  • 使用storage工具存储重要信息
  • 在对话过程中,你可以随时使用storage工具来存储你认为需要记住的信息,同时也随时可以读取曾经可能存储了的历史信息
  • 这将有助于你在和用户的长对话中,记住某些重要的信息,比如用户的喜好、特殊信息、或重大事件等

关于数据存取,有以下两点建议:

  1. 存一条数据的key尽量简洁易懂,可以用所记录内容的关键词
  2. 如果忘记存过什么数据,可以使用scan查看记录过哪些数据

此处展示当前你存入的所有信息,因此你可以省去专门读取数据的操作:

1
2
3
<info>
{storage_info}
</info>

你的记忆很短暂,请频繁的调用工具存储或读取重要对话内容。

  • 自动截断对话历史,保留最近的对话
  • 将存储的信息嵌入系统提示中

3. RAG文件知识库管理

qwen_agent/memory/memory.py#_run,messages中的文件会被保存在知识库中,检索和query最相关的部分内容,而不是将整个文件抛给llm:

  • 支持多种文件格式(PDF、Word、Excel、TXT等)
  • 使用RAG(检索增强生成)技术
  • 可配置的检索策略和关键词生成

4. DialogueRetrievalAgent - 超长对话管理

qwen_agent/agents/dialogue_retrieval_agent.py

  • 将长对话存储为文件
  • 基于检索的历史对话查询
  • 会话级别的历史管理

qwenagent_rag.png

5. VirtualMemoryAgent - 虚拟内存管理

qwen_agent/agents/virtual_memory_agent.py 针对messages中出现的文件名,自动通过deepsearch的方式来检索:

  • 先由llm来决定使用什么工具处理这些文件,然后调用这些工具
  • 直到达到最大调用次数20次,或不再产生新的toolcall
  • 自动检索外部资源
  • 动态更新上下文知识
  • 智能工具调用

参考文档
https://qwenlm.github.io/zh/blog/qwen-agent-2405/
https://github.com/QwenLM/Qwen-Agent
https://community.modelscope.cn/682d45a3870cef736060aaef.html

MemU

MemU采用背景进程对记忆进行加工和抽取,并建立联系存储到图库中,形成自我进化

参考
https://github.com/NevaMind-AI/memU

概述

基础的 ReAct 模式将action描述为 tool ,tool为沟通世界的桥梁,但tool可以有多种解释,比如mcp as tool, agent as tool, task as tool, human as tool(human in loop)等等,task是一种进阶的能力,它是一个需要多agent配合达成的目标。
看了几种实现,可以观察到一个规律:

  • 通过一个reasoning过程来产生plan,这个plan可以在内存中,也可以被保存到一个文件,如manus的todo.md 和 cline 的 Deep Planning
  • 将plan出的任务分派给agent来执行,分配给一个agent,或多个agent来解决复杂的问题,如 claude的sub task机制 和 langgraph的Hierarchical Agent Teams机制
  • 多个task之间应该会有上下文隔离和共享机制,既需要避免上下文爆炸,又需要在某些情况下多agent之间的信息共享

claude sub task

claude_task.png
某些实现会创建 Task 给一组 Agent 执行,这意味着工具实现具有很大自由度。例如 Claude Code 将子任务执行封装为 task 工具,执行结果返回给调用该工具的 agent,并合并到主 Context 中

参考文档
Claude Code Task工具与Agent架构完整技术实现分析

langgraph Hierarchical Agent Teams

hierarchical_agent_teams_process.png
随着智能体系统的发展,单一智能体可能会遇到工具选择困难(工具过多时决策质量下降)、上下文复杂度失控(难以跟踪复杂上下文)以及专业化需求(需要多个专业领域)等问题。多智能体系统通过模块化(独立开发维护)、专业化(领域专家智能体)和控制性(显式通信控制)三大优势来解决这些问题,将复杂应用分解为多个小型、独立的智能体,通过层次化组织实现任务分解和协作,使用LangGraph构建智能体网络并通过状态图管理交互。
在langgraph中可以将task分配给一个 MultiAgent 的 Team 来执行

参考文档
Hierarchical Agent Teams
AutoGen: Enabling Next-Gen LLM Applications via Multi-Agent Conversation

manus todo.md

manus 在处理复杂任务时,倾向于创建一个todo.md文件——并在任务进行过程中逐步更新它,勾选已完成的项目。

参考文档
https://manus.im/zh-cn/blog/Context-Engineering-for-AI-Agents-Lessons-from-Building-Manus

cline deep planning

Cline 的深度规划(Deep Planning)是一种基于上下文工程的智能体规划方法,通过系统性的上下文管理来优化 AI 系统的决策和执行能力。

深度规划的本质

  • 将复杂的任务分解为多层次、可执行的子任务
  • 通过上下文工程确保每个规划步骤都有充分的信息支持
  • 实现从高层目标到具体行动的端到端规划

上下文工程在深度规划中的作用

  1. Write Context(写入上下文):将规划过程中的中间状态、决策依据等写入上下文
  2. Select Context(选择上下文):根据当前规划阶段选择最相关的上下文信息
  3. Compress Context(压缩上下文):对长规划序列进行压缩,保留关键信息
  4. Isolate Context(隔离上下文):将不同规划模块的上下文隔离,避免干扰

规划状态管理

  1. 目标分解:将复杂目标分解为可管理的子目标
  2. 上下文构建:为每个子目标构建专门的上下文
  3. 规划生成:基于上下文生成具体的执行计划
  4. 执行监控:监控执行过程,动态调整规划
  5. 结果整合:将执行结果整合到整体规划中

与 ReAct 模式的对比

特性 ReAct 模式 Cline 深度规划
决策方式 即时反应式 前瞻性规划
上下文使用 简单工具调用 复杂上下文工程
任务分解 单一工具调用 多层次任务分解
执行模式 线性执行 并行+串行混合
错误处理 重试机制 规划调整机制

参考文档
https://cline.bot/blog/how-to-think-about-context-engineering-in-cline
https://x.com/shao__meng/status/1957031656692543939
https://x.com/shao__meng/status/1957682039509118989

ReAct 机制

ReAct是一种将推理(Reasoning)和行动(Acting)与语言模型相结合的通用范式,通过交错生成推理轨迹和特定任务行动来解决复杂问题,是现代大部分框架构建 Agent 的基础理论。

理论基础

核心思想

  • 语言空间中的动作(思想/推理痕迹)不影响外部环境,但更新上下文以支持未来推理
  • 推理轨迹帮助模型归纳、跟踪和更新行动计划,处理异常
  • 行动允许与外部环境交互并收集额外信息

工作机制

1. Reasoning - 通过语言推理制定高级计划,确定下一步行动

大模型推理引擎可以解析 prompt 中的 toolcalls 作为行动计划 sglang function_calling

output parser

tools_are_structured_output
另一种方案是从大模型的结构化输出中解析工具调用,而非依赖 toolcalls 能力,这种方式提供了更大的灵活性 Tools are just structured outputs

例如 ADK 的实现就采用模型的结构化输出来识别行动 ADK Planer

2. Acting - 通过外部交互获取信息,验证推理假设,更新上下文

通常使用工具(tools)进行交互,handoffs 机制可以将其他 Agent 作为可执行工具。是否定义独立 Agent 来执行 Acting 取决于任务复杂度及其价值(因为 Agent 运行成本较高)。此外,Agent 的异常恢复机制相对脆弱,可能需要 human-in-the-loop 介入,需要权衡考虑 Prompting for Agents | Code w/ Claude

plan and execute

plan_and_execute.png
当一次产生多个 Acting 时,会演进为 Plan-And-Execute 机制 Plan-and-Execute
相对ReAct机制,plan-and-execute机制具备前瞻性,每个任务的执行比较自由,可以灵活调度并行或串行执行。

3. Reasoning Loop - 重新规划,直到收敛

Agent 进行多轮循环,不断执行 Reasoning 过程。在多次循环中,Memory 会记录执行历史,Agent 基于历史不断调整策略直到问题收敛 Memory

replan

在 Plan-and-Execute 机制中称为 Re-Plan,但不同之处在于 Re-Plan 需要上下文记录 step 历史 Plan-and-Execute

适用场景

  • 知识密集型推理任务(问答、事实验证)
  • 交互式决策任务(文本游戏、网页导航)
  • 需要动态调整的复杂任务

LangGraph 中构建 ReAct Agent 的要素

react_run.png

核心运行流程

  1. 初始化阶段:用户查询 → 初始化Agent → 生成系统提示词 → 初始化上下文
  2. 多轮循环:开始ReAct循环,直到达到最大轮数或获得最终答案
  3. 推理阶段:调用LLM获取响应 → 解析LLM响应
  4. 决策分支
    • 包含Final Answer → 返回最终答案
    • 不包含Final Answer → 解析Thought和Action → 提取工具名称和参数 → 执行工具调用 → 将工具结果添加到历史 → 继续下一轮循环

构建要素

  1. 上下文管理:定义 AgentState 管理记忆和对话上下文,构建与大模型交互的 prompt schema,进行压缩、剪枝、卸载等优化
  2. 工具:提供与外部知识库、环境交互的手段,决定 Agent 的能力范围
  3. 模型选择:模型能力影响结果质量
  4. 节点编排:设计 Agent 推理节点和工具执行节点的交互流程
  5. 终止机制:防止 ReAct 无限轮询,避免死循环和资源浪费
  6. 响应解析:解析LLM输出中的Thought、Action和Final Answer
0%