Article

Task Context: The Context Governance Contract For Execution Agents

Reframing Execution Agent context governance from prompt compression into a structured task-state, permission, evidence, and auditable decision contract.

Jun 07, 2026 Updated Jun 07, 2026
  • Agent
  • Context engineering
  • Product design
  • AI PM

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.created
  • plan.created
  • plan.updated
  • step.started
  • step.completed
  • tool.called
  • tool.result.received
  • permission.requested
  • permission.granted
  • permission.denied
  • checkpoint.created
  • file.modified
  • error.occurred
  • user.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

先实现:

  • task
  • plan
  • currentStep
  • progress
  • permissions
  • evidence

不急着做复杂 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 产品持续迭代的上下文治理契约。