如何设计 Agent:组成、运行环境与生命周期
本文根据我在 PyCon China 2026 上的演讲《如何设计 Agent 制度体系与运行平台》整理,幻灯片版本见 Slides。
一个 Agent 如何组成,又何以成为“一个”个体?本文从上下文与运行环境出发,讨论 Agent 的实现方式、状态管理与生命周期,以及自由性与可管理性之间的冲突。
一、Agent 的组成
本文讨论的是截至 2026 年 9 月主流 Agent 的组织形式,可以从上下文与运行环境两个方面理解。
上下文(Context)
上下文包含以下两个部分:
- 历史记录(History)
- Instruction
运行环境(Runtime)
运行环境需要提供以下两方面的能力:
- 执行能力:通过工具提供,Shell 是其中通用性很强的一种。
- 状态管理:文件系统(FS)提供了通用的状态存储与管理能力。
二、实现方案
历史记录
历史记录的处理主要有两条路线:压缩和检索。
压缩路线
压缩历史记录的方式包括丢弃工具输出、完全丢弃中间推理和工具调用,以及压缩或丢弃最旧的上文。
检索路线
检索路线将历史记录保存在上下文之外,需要时再查找相关内容并放入上下文。检索方式可以从检索次数和索引形式两个独立维度描述。
- 按检索次数分类:
- 单次检索:只进行一次检索,通常延迟较低,召回率也较低。
- 自动多次检索:由 Agent 根据已有结果继续检索,通常延迟较高,但有机会获得更高的召回率。
- 按索引形式分类:
- 基于文件系统的无索引检索:历史数据直接保存在普通文件中,由 Agent 使用
sed等工具读取、筛选和查找,无需专门的索引基础设施。这种方式的精确率往往较低,通常搭配自动多次检索以提高召回率。 - 基于索引的检索:引入语义嵌入(semantic embedding)、全文索引(full-text index)、知识图谱(knowledge graph)等技术及相应的基础设施,也可以将这些能力组织为记忆系统(Memory)。这类方案旨在提高精确率,理想情况下可以搭配单次检索实现低延迟,也可以搭配自动多次检索,同时实现高精确率和高召回率。
- 基于文件系统的无索引检索:历史数据直接保存在普通文件中,由 Agent 使用
这里的精确率(precision)衡量检索结果中有多少是相关信息,召回率(recall)衡量全部相关信息中有多少被检索到了:
- 精确率 = 检索到的相关信息量 / 检索到的全部信息量。
- 召回率 = 检索到的相关信息量 / 全部相关信息量。
高召回率意味着检索结果尽可能包含完整的有用信息。即使精确率较低、大部分结果都无关,依靠当下大模型的上下文学习能力,Agent 仍有机会从中捕获所需信息并正确推进会话,代价是额外的 Token 消耗。因此,高召回率对低精确率的弥补,体现在后续任务所需的信息覆盖上,并不意味着检索结果本身的精确率提高了。
Instruction
Instruction 的组织方式包括以下三种,其区别主要在于内容何时进入上下文,以及由谁决定读取或注入:
- 基本 Prompt:直接放进用户输入,随用户消息进入上下文。
- 渐进式 Prompt:由系统预设一组 Prompt 字典或者 KV,并根据预设条件决定何时将对应的值注入上下文。例如,检测到基本 Prompt 中的某个关键字后,注入该关键字对应的 Prompt。
- 主动渐进式 Prompt:为 Agent 提供读取 Prompt 的工具,由 Agent 在运行过程中判断需要哪些指令,并自行调用工具读取,使其进入上下文。
SKILL.md就是这种方式的一种载体,但它只是 Agent Skill 的一个部分。
运行环境
定义运行环境,首先需要定义 Agent 可以使用的工具(Tool)。例如内置工具(built-in tool)、JSON Schema Tool、MCP,以及终极通用工具 Shell。
其次,需要考虑 Agent 自身状态的管理。工具可以对外部系统产生副作用,但这些变化不一定属于 Agent 自身的状态。对于运行平台,更关键的问题是:哪些状态属于 Agent,应随 Agent 一同保存、复制和删除,以及如何根据保存的状态创建或恢复 Agent。
工具协议可以提供跨调用关联状态的机制,但具体状态仍需由应用管理。例如,旧版 MCP 支持协议级 Session;2026 年 7 月的新版规范则移除了这一机制,改为要求应用通过显式标识符引用跨调用状态。这些机制本身并不负责 Agent 及其状态的保存、复制、恢复与删除。
文件系统则提供了一种直接管理这些状态的方式:将属于 Agent 的程序、配置和运行数据保存在明确的目录范围内。通过保存、复制或删除这些目录,就能管理相应的持久化状态,并据此创建或恢复 Agent。
Shell 和文件系统是操作系统(OS)提供的核心工具。因此,直接使用一个 OS 为 Agent 提供执行能力和状态管理能力,是最直接的解决方式。OS 的通用性使 Agent 能够灵活组合工具、组织文件并开展工作,从而获得最大的行动灵活性。
三、当下的解决方案
Agent Skill
Agent Skill 在 Instruction 上全面采用主动渐进式 Prompt,在运行环境上全面采用基于 OS 的方式。它将 SKILL.md、可通过 Shell 执行的工具(通常是 CLI 工具),以及文件系统中的一个文件夹打包在一起,形成高内聚的能力封装。
缺陷
- 工具分发:Skill 中的 CLI 通常使用 Python 等语言编写;如果需要打包编译后的二进制,分发会更复杂。
- 内容与状态的边界:Skill 规范没有约定目录之外应当存放哪些内容,例如配置和运行数据应该放在哪里。如果程序、配置和运行数据都保存在 Skill 目录中,修改其中任何一类内容都会改变这个目录。将 Skill 目录打包迁移到另一个位置或机器时,也就需要决定:配置和运行数据是否应当一起打包,哪些状态需要携带,哪些需要排除。
CoW 沙盒
CoW 沙盒用写时复制(Copy-on-Write,CoW)技术管理文件系统,配合微型虚拟机(microVM)或容器(container)等技术,实现支持快照(snapshot)和分叉(fork)的完整沙盒。
缺陷
CoW 的管理粒度通常在整个文件系统级别,无法对细粒度的某个组件进行管理。比如对某个工具的 .config 和 .local/state 单独做 snapshot,然后 apply 到另一个沙盒里。
自由性与可管理性
事实上,上述单一问题都可以有相应的解决方案:
- 工具安装与分发:要求 Skill 打包的工具通过包管理器分发,并使用
uvx、npx等方式运行。 - 配置与运行数据的存放:要求 Skill 内的工具遵循 XDG 规范,约定这些内容的存放位置。
- 组件级状态管理:实现细粒度的 CoW 沙盒系统,支持对单个组件执行 snapshot 与迁移。
但核心在于自由性和可管理性的冲突:基于 OS 的 Agent 的目的本意是自由的,使 Agent 可以用任意的方式工作;但一旦考虑到用户之间的协作、共享、工具之间的隔离,我们就不得不进行规范和限制。
过去,各大 OS 发行版通过包管理器、打包者的努力、XDG 规范等等去解决这一问题;对当下野蛮生长的 Agent 来说,这或许是一条要重新走的老路。
四、生命周期
“一个” Agent 是什么
Agent 本身的组成已经讨论过了,那现在值得讨论的是,“一个” Agent 是什么,其生命周期如何定义。
有状态的 Session
一个基本的方向是定义有状态的 Session,作为“一个” Agent。这一设计在当下的主流 Agent 实现中都有所体现。
通常来说,这里的状态指的是上下文历史和工作空间(Workspace),也就是 Agent 在一个文件夹下工作,产生的历史记录和文件夹下的文件变更,就属于一个 Session 或者说“一个” Agent 的生命旅途。
从 Turn 到持续实时的交互
Session 用于界定“一个” Agent 及其持续保存的状态,Turn 则用于划分它的行动过程。过去我们会基于 LLM 的行为方式为 Agent 的生命周期引入 Turn 的概念,作为 Agent 一次行动的最小单位。
但如今我们看到了更复杂的交互方式,比如 Steer,在 Agent 运行过程中插入消息;又比如异步执行的命令,在一个 Turn 结束后,Agent 执行的异步命令还在运行,只是 Agent 自己进入休息状态。
因此,这种基于 Turn 的建模正在被取代,转为持续实时的交互,这一点也可以从 ACP v2 的更新中得到体现。
Recap
- Agent = 上下文 + 运行环境
- 上下文 = 历史记录(压缩 / 检索)+ Instruction(基本 / 渐进式 / 主动渐进式)
- 运行环境 = 执行能力 + 状态管理;OS 通过 Shell 与文件系统提供通用支持
- 当前方案 = Agent Skill + CoW 沙盒
- 核心冲突 = 自由性 ↔ 可管理性
- Agent 的边界:包含上下文历史与工作空间状态的 Session
- 交互与执行模型:从以 Turn 为单位,走向支持 Steer 和异步执行的持续实时交互