The full article body is currently published in Chinese. English titles, summaries, and site navigation are available first; full translations can be added article by article.
Agent 产品里,上下文治理经常被简化成几个局部问题:
- 历史太长,怎么摘要?
- 文件太多,怎么检索?
- 工具调用太多,怎么裁剪?
- prompt 太乱,怎么重写?
这些问题都真实存在,但它们不是起点。对 Execution Agent 来说,更关键的问题应该是:
Agent 在执行当前任务的这一刻,到底需要什么样的任务状态?
如果这个问题没有被回答,上下文治理就会变成一组补丁:长了就压缩,缺了就 RAG,乱了就改 prompt。每一次优化都只能解决局部症状,很难沉淀成可持续迭代的系统能力。
我认为,一个更稳定的锚点是 Task Context。
Task Context 不是聊天历史,也不是 prompt 模板。它是 Execution Agent 在某一执行时刻进行决策和行动所需的结构化任务状态。它由原始目标、计划、当前步骤、权限、工具结果、工作区状态、用户约束、执行进度和事件日志共同构建。
换句话说,Task Context 是 Execution Agent 的工作记忆结构。
为什么需要 Task Context
很多 Agent 失败并不是因为模型完全不知道怎么做,而是因为它在执行过程中逐渐丢失了任务状态:
- 忘记用户最初的目标;
- 把中间摘要当成新的指令;
- 不知道当前应该执行计划中的哪一步;
- 从大量 tool result 里误判了刚刚发生的事情;
- 忽略了用户授权边界;
- 在多次压缩后丢失关键决策;
- 无法解释自己为什么采取某个动作。
这些问题表面上是上下文窗口不够,实质上是任务状态没有被显式建模。
Execution Agent 不是普通聊天模型。它会读文件、改代码、调用工具、执行命令、创建变更、等待审批,也可能需要从失败中恢复。因此,它看到的上下文不应该只是若干轮 message,而应该是一个清晰的执行契约:
- 原始目标是什么?
- 当前计划是什么?
- 现在正在执行哪一步?
- 这一步允许使用哪些工具?
- 上一步得到了什么结果?
- 哪些信息是事实证据?
- 哪些内容只是模型推断?
- 哪些历史可以省略,哪些必须保留?
- 当前是否需要用户确认?
- 如果失败,应该从哪个 checkpoint 恢复?
Task Context 的价值,是把“上下文治理”从 prompt 工程问题转成产品和架构问题。
Task Context 不等于 Prompt
我不建议把 Task Context 定义成 prompt 本身。
更合理的定义是:
Task Context = Agent 执行状态的结构化中间表示
Prompt = Task Context 的一次渲染结果
也就是说:
User / Agent / Tool / System Events
↓
runtimeReducer
↓
Runtime State
↓
contextBuilder
↓
Task Context
↓
promptRenderer
↓
Execution Agent LLM Input
这三个层次应该分开:
runtimeReducer负责把事件折叠成事实状态;contextBuilder负责选择、压缩、组织当前执行所需上下文;promptRenderer负责把结构化 Task Context 渲染成模型输入。
这种分层有一个直接好处:同一个 Task Context 可以被渲染给不同角色使用。
例如:
- 给 execution agent,用于继续执行;
- 给 planning agent,用于调整计划;
- 给 reviewer agent,用于检查结果;
- 给 recovery agent,用于失败恢复;
- 给用户界面,用于解释 Agent 当前状态。
Prompt 可以持续变化,但 Task Context 应该是系统内部相对稳定的契约。
渲染层约束:不能破坏 Append-only
Task Context 是结构化中间表示,但它最终仍然要被渲染成 LLM input。
这里有一个很重要的工程约束:不要每一轮都把完整 Task Context 重新生成后塞到 prompt 前部。
原因是多步 Agent 任务高度依赖 prompt cache。传统 AgentLoop 的执行历史天然是 append-only 的:第一轮是 system + task,第二轮追加 assistant 和 tool result,第三轮继续追加。后一轮请求通常以前一轮请求作为稳定前缀,因此缓存命中率会更好。
如果 Context Manager 每一轮都在消息前部重写完整上下文,尤其是把 event id、observation id、trace id、最新 tool result、文件片段等高变化字段放到前面,就会很快破坏 prefix matching。上下文治理虽然变得“结构化”,但长任务的成本和 prefill latency 可能显著上升。
因此,Task Context 的渲染策略应该遵守一个原则:
stable start context
append-only execution transcript
minimal context deltas
periodic context checkpoints
稳定的任务目标、输出要求、项目规则和持久约束应该进入 stable prefix;执行过程中的 assistant/tool 消息应该保持 append-only;普通状态变化通过短 delta 追加到尾部;长任务每隔若干步骤追加 compact checkpoint。
完整 provenance、raw ids、candidate selection、excluded context 等审计信息不应该全部塞进 prompt。它们应该进入 snapshot、trace、event log 和 tool result store。
换句话说:
Task Context 定义模型需要什么任务状态,cache-aware rendering 决定这些状态如何以低成本、低延迟、可缓存的方式进入模型。
这个问题可以单独展开成一篇文章:Agent 上下文渲染的缓存优化:为什么 Task Context 不能每轮全量重写。
初版结构
一个可落地的 Task Context 0.1 版本,可以先分成八个部分。
1. Task Identity
Task Identity 保存任务源头,不能被摘要替换。
interface TaskIdentity {
id: string;
originalTarget: string;
interpretedGoal: string;
successCriteria: string[];
nonGoals?: string[];
}
这里需要区分:
originalTarget:用户最初说了什么;interpretedGoal:系统理解后的目标;successCriteria:什么结果才算完成;nonGoals:明确不做什么。
例如,用户说“帮我修复上传文件 413 的问题”,系统理解后可以变成:
originalTarget: 修复上传文件 413 问题
interpretedGoal: 定位是前端、后端、Nginx 还是网关限制,并让 10MB 文件可以正常上传
successCriteria:
- 10MB 文件上传成功
- 错误提示合理
- 不破坏已有上传流程
nonGoals:
- 不重构整个上传模块
- 不引入新的对象存储服务
原始目标必须长期保留。否则 Agent 在多轮执行和多次压缩后,很容易发生任务漂移。
2. Plan
Plan 保存任务执行计划。
interface TaskPlan {
version: number;
status: "draft" | "approved" | "executing" | "revising" | "completed";
steps: PlanStep[];
currentStepId?: string;
}
interface PlanStep {
id: string;
title: string;
description?: string;
status: "pending" | "running" | "blocked" | "done" | "skipped" | "failed";
dependsOn?: string[];
expectedOutput?: string;
}
Execution Agent 不应该每一轮都重新理解整个任务。它应该明确知道自己当前处在计划的哪一步。
3. Current Step Context
Current Step Context 是执行稳定性的关键。
interface CurrentStepContext {
id: string;
objective: string;
expectedOutput?: string;
inputContext?: string[];
allowedTools?: string[];
constraints?: string[];
riskLevel?: "low" | "medium" | "high";
}
例如:
objective: 检查 Nginx 配置中是否存在 client_max_body_size 限制
allowedTools:
- read_file
- grep
- list_dir
constraints:
- 不要修改代码
- 只做定位
expectedOutput: 给出限制来源和相关配置文件路径
这能显著减少 Agent 发散。Agent 看到的不是“修复上传问题”这样的大目标,而是“当前只做定位,不做修改”的具体执行约束。
4. Recent Progress
LLM 不擅长从几十条工具调用里稳定判断“刚刚发生了什么”。Recent Progress 应该显式告诉 Agent 上一步结果。
interface RecentProgress {
completedSteps: string[];
lastStep?: {
id: string;
result: "success" | "failed" | "partial" | "blocked";
summary: string;
findings?: string[];
changedArtifacts?: string[];
unresolvedIssues?: string[];
};
}
这个结构解决的是连续执行问题:Agent 当前这一轮应该接着哪里做,而不是重新从历史里猜。
5. Execution Control
Execution Agent 会产生真实副作用,因此权限和 checkpoint 必须进入上下文。
interface ExecutionControl {
status:
| "idle"
| "running"
| "waiting_user"
| "blocked"
| "failed"
| "completed";
pendingQuestion?: string;
pendingApproval?: string;
currentCheckpointId?: string;
rollbackAvailable?: boolean;
}
权限可以进一步独立出来:
interface Permissions {
allowedTools: string[];
deniedTools?: string[];
requiresApproval?: string[];
fileScopes?: string[];
}
这部分直接影响 Agent 行为:
- 可以读文件,但不能写文件;
- 可以修改
frontend/src,但不能改backend; - 删除文件前必须请求确认;
- 当前 checkpoint 是
cp_20260607_001。
如果权限不结构化,Agent 很容易在长任务中遗忘边界。
6. Evidence
Tool call history 是证据,但不能无限塞进 prompt。
interface Evidence {
recentToolCalls: ToolCallRecord[];
importantFindings: string[];
referencedArtifacts?: ArtifactRef[];
omittedHistorySummary?: string;
}
interface ToolCallRecord {
id: string;
stepId?: string;
toolName: string;
arguments: unknown;
resultSummary: string;
status: "success" | "error";
timestamp: string;
rawResultRef?: string;
}
关键点是 resultSummary + rawResultRef。
大段文件内容、grep 结果、测试日志、编译错误、diff 不应该默认全部进入 prompt。它们应该被摘要化、索引化、引用化。需要时,Agent 再按 rawResultRef 读取原始结果。
7. Event History
Event History 应该是事实源。
Tool Call History、Recent Progress、Audit Timeline、Runtime State 都应该是从 Event History 派生出的视图,而不是彼此割裂的重复状态。
interface EventSummary {
id: string;
type: string;
timestamp: string;
actor: "user" | "agent" | "system" | "tool";
summary: string;
causationId?: string;
correlationId?: string;
}
底层事件可以包括:
task.createdplan.createdplan.updatedstep.startedstep.completedtool.calledtool.result.receivedpermission.requestedpermission.grantedpermission.deniedcheckpoint.createdfile.modifiederror.occurreduser.interrupted
这意味着系统不需要纠结 tool history 和 event history 谁包含谁:
Event Log 是原始账本
Tool Call History 是派生视图
Task Context 是执行视图
8. Memory
Task Context 还可以引入 memory,但需要谨慎区分长期记忆和当前任务记忆。
interface MemoryContext {
durableFacts?: string[];
userPreferences?: string[];
projectConventions?: string[];
workingMemory?: string[];
}
长期 memory 不应该被每一轮随意改写。当前任务中刚形成的判断,更适合先进入 working memory,等任务结束或用户确认后再决定是否持久化。
分层进入 Prompt
不是 Task Context 的所有字段都应该每一轮进入 LLM。
更合理的方式是分层:
| 层级 | 含义 | 是否进入 prompt |
|---|---|---|
| Core Context | 原始目标、成功标准、硬约束 | 每次进入 |
| Step Context | 当前步骤、允许工具、预期输出 | 每次进入 |
| Recent Context | 最近进展、最近工具调用摘要 | 高频进入 |
| Referenced Context | 大型日志、文件、diff、原始工具结果 | 按需读取 |
| Audit Context | 完整事件账本、权限记录、checkpoint | 默认不进入 |
| Recovery Context | 失败恢复所需上下文 | 恢复时进入 |
这比简单地“保留最近 20 条消息”更接近 Agent 产品真实需要。
上下文治理的目标不是把所有东西塞进模型,而是让 Agent 在正确时刻看到正确粒度的信息。
产品价值
Task Context 不只是内部架构,它也可以成为产品能力。
当 Agent 出错时,用户通常不知道:
- 它为什么执行这一步?
- 它是否还记得原始目标?
- 它参考了哪些证据?
- 它忽略了哪些历史?
- 它当前拥有哪些权限?
- 它是否正在等待用户确认?
- 它是否已经偏离计划?
如果系统维护了结构化 Task Context,就可以把这些问题可视化出来:
当前目标
当前步骤
执行计划
最近进展
关键证据
权限边界
待确认事项
被省略历史
可回滚 checkpoint
这会直接提升 Agent 产品的信任感。
很多 Agent 产品的问题不是“不够智能”,而是“不够可解释”。用户看不到 Agent 的任务理解、上下文选择和执行边界,就很难放心把复杂任务交给它。
Task Context 可以成为运行时信任、审计回放、失败恢复和上下文治理的共同接口。
落地路线
我会按三个阶段落地。
第一阶段:只做最小 Task Context
先实现:
taskplancurrentStepprogresspermissionsevidence
不急着做复杂 memory,也不急着做高级压缩。目标是让 Agent 每一轮都知道:原始目标是什么,当前步骤是什么,刚刚发生了什么,允许做什么。
第二阶段:事件日志和派生视图
把用户消息、Agent 动作、工具调用、工具结果、审批、checkpoint 都写入 Event Log。
然后从 Event Log 派生:
- Recent Progress;
- Tool Call History;
- Audit Timeline;
- Prompt Context;
- Recovery Context。
这样系统就有了可回放、可解释、可恢复的基础。
第三阶段:上下文治理策略
在结构稳定之后,再做更智能的治理:
- 哪些字段必须保留原文;
- 哪些字段可以摘要;
- 哪些字段只保留引用;
- 哪些历史可以按需检索;
- 哪些上下文不能作为指令;
- 哪些 memory 需要用户确认后持久化;
- 每次压缩丢弃了什么,保留了什么。
到这个阶段,上下文治理才真正从 prompt 优化变成系统能力。
结论
Task Context 的核心思想是:
不要先问怎么压缩上下文,而要先定义 Execution Agent 为了完成当前任务需要什么上下文结构。
一旦这个结构被定义出来,很多问题都会有稳定的讨论对象:
- prompt 如何渲染;
- 历史如何压缩;
- 工具结果如何引用;
- 权限如何注入;
- memory 如何持久化;
- 失败如何恢复;
- 执行过程如何解释;
- 用户如何审计 Agent 行为。
因此,Task Context 不是一次性的 prompt 方案,而是 Agent 产品持续迭代的上下文治理契约。