AI Agent 上下文工程实践:从长任务崩溃到稳定运行

2025/11/24 ai-generation

# AI Agent 上下文工程实践:从长任务崩溃到稳定运行

在构建高性能 AI Agent 的过程中,我发现真正限制长任务成功率的,往往不是底层模型能力,而是上下文管理。经过多次框架重构和数百万真实用户会话的验证,我们在 MaybeAi 沉淀出一套高度结构化的上下文工程体系。

# 为什么上下文工程是核心竞争力

Agent 竞争不是比模型,是比整个系统。真正影响成功率的,往往是任务拆解、工具链、失败重试、上下文管理这些工程细节。更关键的是,这套"上下文工程"的实践经验不是天上掉下来的,它需要在真实任务场景里一刀一枪练出来。

我们的 Agent 平均每个会话需要 50 步工具调用,处理的任务包括多文件数据分析、跨平台内容抓取、复杂报告生成等。如果上下文管理不当,Agent 会在第 20 步左右开始"目标漂移",或者因为上下文窗口溢出直接崩溃。

# 上下文设计的核心原则

# 文件系统是无限外部记忆

把文件系统视为 Agent 的"终极上下文":无限大小、持久化、可直接操作。任何大块内容(网页全文、CSV 数据、PDF、长日志)绝不直接放入上下文,而是保存到文件,只保留路径和必要摘要。

# 错误做法:把完整 CSV 内容放进上下文
observation = f"CSV content: {full_csv_content}"  # 可能几万行

# 正确做法:外部化存储,只保留元信息
save_file("/data/stock_data.csv", csv_content)
observation = "File saved to /data/stock_data.csv (756 rows, date range 2022-12-14 to 2025-12-14)"

# 可逆压缩

信息压缩后必须可恢复。我们不是丢弃信息,而是把它移到文件系统,需要时通过主动读取工具拉回。

比如处理一个 50 页的 PDF 财报:

  • 上下文中只放:"这是一份 50 页财报,关键点是营收增长 20%,路径:/reports/q3.pdf"
  • 完整 PDF 内容存在文件里
  • 后续需要时,Agent 调用 read_file("/reports/q3.pdf") 获取

# 注意力操纵:Recitation 机制

这是我们对抗"lost-in-the-middle"问题的核心武器。通过将最关键的信息(如当前计划和进度)强制追加到上下文最末尾,确保 LLM 的注意力机制优先看到。

核心文件是 todo.md

# 整体目标:分析 NVDA、MRVL、TSM 过去 3 年股票相关性并生成投资报告

- [x] 获取过去 3 年每日收盘价数据
- [x] 下载并保存为 CSV 文件
- [x] 清洗数据(处理缺失值、对齐日期)
- [ ] 计算 Pearson 相关系数矩阵
- [ ] 绘制相关性热力图和股价时间序列图
- [ ] 分析见解
- [ ] 评估风险
- [ ] 生成最终报告

当前进度:数据已清洗,下一步计算相关性。
全局提醒:报告需客观、专业。

每完成一个主要阶段(通常 3-10 步工具调用),Agent 必须更新 todo.md,然后系统自动将最新内容追加到上下文末尾。

# 固定的四层上下文结构

我们严格遵循以下四层顺序拼接上下文,确保可预测性和稳定性:

┌────────────────────────────────────────────┐
│ 1. 系统提示(固定,最前)                    │
├────────────────────────────────────────────┤
│ 2. 历史行动-观察对(从旧到新,追加式)         │
│    <action> ... </action>                    │
│    <observation> ... </observation>          │
│    <action> ... </action>                    │
│    <observation> ... </observation>          │
│    ...                                     │
├────────────────────────────────────────────┤
│ 3. 当前轮临时读取的文件内容(可选,仅本轮)     │
├────────────────────────────────────────────┤
│ 4. 关键文件 recitation(强制,最末尾)         │
│    └─ todo.md 最新完整内容(必有)            │
│    └─ 其他关键文件(如 insights.md,可选)    │
└────────────────────────────────────────────┘

# 第一层:系统提示

固定不变,放在最前面。包含 Agent 身份、能力描述、工具定义、核心原则。

You are MaybeAi, a powerful AI agent capable of browsing the web, executing code, reading/writing files, etc.
Tools available: browser_*, shell_*, read_file, write_file, ...
Key principles: Use files as external memory. Always update todo.md after each major step. Keep context lean by summarizing large content...

# 第二层:历史行动-观察对

追加式(append-only),从最旧到最新依次排列。每对的固定格式:

<action>
<write_file path="todo.md">
# 整体目标:分析股票相关性
- [ ] 获取数据
...
</write_file>
</action>

<observation>
File todo.md created successfully.
</observation>

<action>
<browser_navigate url="https://finance.yahoo.com" />
</action>

<observation>
Page loaded. Title: Yahoo Finance - Stock Market Live...
</observation>

关键点:observation 里绝不放完整大内容,只放路径 + 摘要。

# 第三层:当前轮临时读取内容

仅在本轮需要时出现。如果 Agent 上一步调用了 read_fileheadgrep 等,工具返回的内容会直接追加在这里,作为本轮的"即时记忆"。

<action>
<read_file path="/data/stock_data.csv" />
</action>

<observation>
Date,Close
2022-12-14,178.35
2022-12-15,180.22
...
(756 rows total, showing first 100)
</observation>

下轮如果不再需要,这些内容不会被永久保留(除非 Agent 主动写到文件里)。

# 第四层:关键文件 Recitation

这是整个上下文结构的"杀手锏",几乎每轮都必须有。放置位置:整个 context 的绝对末尾(最近位置),确保 LLM 的注意力机制优先看到。

[todo.md content start]
# 整体目标:分析 NVDA、MRVL、TSM 过去 3 年股票相关性并生成投资报告

- [x] 获取过去 3 年每日收盘价数据
- [x] 下载并保存为 CSV 文件
- [x] 清洗数据
- [ ] 计算 Pearson 相关系数矩阵
...

当前进度:数据已清洗,下一步计算相关性。
[todo.md content end]

# 长任务中的读写流程

以"分析 NVDA、MRVL、TSM 过去三年股票价格相关性并生成投资报告"为例,展示完整的上下文演变过程。

# 任务启动(第 1 轮)

[系统提示]
You are MaybeAi, a powerful AI agent...

[历史行动-观察对]  // 目前为空

[用户任务]
分析 NVIDIA (NVDA)、Marvell Technology (MRVL) 和 TSMC (TSM) 过去三年股票价格的相关性,
计算 Pearson 相关系数,绘制热力图和时间序列图,最后生成一份投资报告。

[Agent 行动 1]
<write_file path="todo.md">
# 整体目标:分析 NVDA、MRVL、TSM 过去 3 年股票相关性并生成投资报告

- [ ] 获取过去 3 年每日收盘价数据
- [ ] 下载并保存为 CSV 文件
- [ ] 清洗数据
- [ ] 计算 Pearson 相关系数矩阵
- [ ] 绘制相关性热力图和股价时间序列图
- [ ] 分析见解
- [ ] 评估风险
- [ ] 生成最终报告

当前进度:刚开始。
</write_file>

[观察 1]
File todo.md created successfully.

[todo.md 最新内容 - recitation]
# 整体目标:分析 NVDA、MRVL、TSM 过去 3 年股票相关性并生成投资报告
...(完整内容)

此时上下文大约 3-4k tokens。

# 数据下载完成(第 8 轮)

[系统提示]  // 固定

[历史行动-观察对]  // 前面 7 轮的历史
<action> download NVDA CSV </action>
<observation> File saved to /data/nvda_data.csv (756 rows) </observation>

<action> download MRVL CSV </action>
<observation> File saved to /data/mrvl_data.csv (756 rows) </observation>

<action> download TSM CSV </action>
<observation> File saved to /data/tsm_data.csv (756 rows) </observation>

<action> 更新 todo.md </action>
<observation> todo.md updated </observation>

[todo.md 最新内容 - recitation]
- [x] 获取过去 3 年每日收盘价数据
- [x] 下载并保存为 CSV 文件
- [ ] 清洗数据(处理缺失值、对齐日期)
...

当前进度:数据已下载,下一步清洗。

此时上下文大约 15-20k tokens。注意:CSV 原始数据完全没进来,只在观察里提了一句路径。

# 数据清洗阶段(第 12 轮)

Agent 决定清洗数据,需要读取 CSV。

[系统提示 + 历史行动-观察对]  // 前面所有历史

[最近行动]
<read_file path="/data/nvda_data.csv" />
<read_file path="/data/mrvl_data.csv" />
<read_file path="/data/tsm_data.csv" />

[观察]
nvda_data.csv content: (返回前 100 行 + 统计摘要)
Date,Close
2022-12-14,178.35
...
(756 rows total)

[todo.md 最新内容 - recitation]
- [x] 获取...
- [x] 下载...
- [ ] 清洗数据(处理缺失值、对齐日期)   ← 当前焦点
...

这轮上下文临时变大(因为读了三个 CSV 片段),但下轮清洗完后,Agent 会把清洗结果保存为新文件 cleaned_data.csv,下次就不需要再读原始 CSV 了。

# 任务接近尾声(第 25 轮)

[系统提示 + 完整历史行动-观察对]  // 约 50 步历史

[最近几轮关键观察摘要]
- cleaned_data.csv saved (756 aligned rows)
- Pearson correlation matrix: NVDA-MRVL: 0.85, NVDA-TSM: 0.78
- heatmap.png saved to /images/heatmap.png
- price_chart.png saved to /images/price_chart.png
- insights.md written
- todo.md updated: all items checked except final report

[todo.md 最新内容 - recitation]
- [x] 获取过去 3 年每日收盘价数据
- [x] 下载并保存为 CSV 文件
- [x] 清洗数据
- [x] 计算 Pearson 相关系数矩阵
- [x] 绘制相关性热力图和股价时间序列图
- [x] 分析见解
- [x] 评估风险
- [ ] 生成最终报告(Markdown + 图表)

当前进度:所有分析完成,只剩合成报告。

最终生成报告时,Agent 会再次 read_file 读取 insights.md、图路径等必要片段,合成最终 Markdown。

# 关键文件的使用规范

# todo.md:Agent 的外部大脑

每完成一个主要阶段(通常 3-10 步工具调用)必须更新:

  • 勾选已完成项
  • 调整剩余任务顺序
  • 重述全局目标

更新后立即 recitation 到上下文末尾。

# 其他常见文件

文件类型 用途 示例
中间数据 存储处理结果 cleaned_data.csv, analysis_result.json
错误日志 保留完整错误栈 error_log.txt, logs.json
草稿笔记 临时思考和见解 insights.md, draft.md, scratchpad.txt
图像路径 生成的图表 heatmap.png, price_chart.png

这些文件按需读取,读取后内容仅用于当前或后续几轮推理。

# 四大工程模块的核心经验

# 任务拆解

核心做法

  • 将复杂任务拆解为 ~50 步工具调用链,每步遵循"选择行动 → 执行 → 追加观察"的循环
  • 使用 todo.md 作为"外部大脑",明确分解粒度(按"5 秒级操作单元")
  • 支持子代理(sub-agents)隔离子任务,共享上下文但独立窗口

关键教训

  • 长序列易导致"目标漂移"和"中间丢失"问题
  • 通过 recitation 机制,成功率提升 20-30%,无需重训模型
  • 任务粒度过粗会导致级联失败,优化后按"5 秒级操作单元"拆解

# 工具链

核心做法

  • 采用上下文感知状态机管理工具,不动态加载/卸载(避免 KV-cache 失效)
  • 用 logit masking(解码时屏蔽 token 概率)约束选择
  • 工具设计标准化:统一前缀(如 browser_*, shell_*),总工具数控制在 <20 个原子工具

关键教训

  • 动态工具切换在生产中常引发"schema violation"
  • masking 后,工具调用稳定性达 99%
  • 通过前缀分组和沙箱,减少了 80% 的工具输出噪声

# 失败重试

核心做法

  • 保留所有失败痕迹:行动、观察和错误日志追加到上下文中
  • 自调试机制:日志流记录失败上下文,供重试时引用
  • 支持"部分回滚":失败步骤隔离重跑,而非全序列重启

关键教训

  • 隐藏失败是"伪优化":早期版本清理错误导致模型重复犯错
  • 保留失败后,Agent 学会"避坑",重试效率提升
  • 错误恢复率从 30% 升至 70%

# 上下文管理

核心做法

  • 文件系统作为"无限上下文",保存中间结果
  • 可恢复压缩:大文件外部化但留路径,确保信息不永久丢失
  • 操纵注意力:通过 todo 背诵推全局计划到上下文末尾
  • 确定性追加:稳定 JSON 序列化,避免时间戳变异

关键教训

  • 上下文膨胀是 Agent 杀手:无优化时,50 步后窗口溢出
  • 文件外部化 + 压缩后,成本降 50%,支持长任务
  • 上下文工程是"船而非建筑":随模型进步迭代

# 实际效果

经过这套体系的打磨,我们在 MaybeAi 取得了以下成果:

指标 优化前 优化后 提升
长任务成功率 50% 96%+ +92%
上下文 token 消耗 基准 -50% 成本减半
错误恢复率 30% 70% +133%
支持最大步数 ~20 步 50+ 步 +150%
目标漂移率 近零 显著改善

在第三方基准测试中,自动化率和多步任务成功率位居前列。用户反馈:"Agent 记性超好,不会忘中间结果"、"现在它像个可靠的助手,不会半途而废"。

# 核心洞察

回顾整个上下文工程的迭代过程,几个关键认知:

失败不是 bug,而是 feature。保留失败痕迹让 Agent 能够自适应学习,避免重复犯错。

上下文不是垃圾桶,而是可塑工具。Agent 不是死记硬背,而是像程序员一样"查文件、看笔记"。

文件系统是最好的外部记忆。无限大小、持久化、可直接操作,完美解决上下文窗口限制。

Recitation 是对抗遗忘的利器。将关键信息强制放在上下文末尾,利用 LLM 的注意力机制特性。

工程壁垒远超模型。当大模型能力趋于同质化,上下文工程已成为 Agent 领域最值得深耕的差异化方向。

# 总结

这套结构化、文件驱动、可逆的上下文管理体系,既是我们在生产环境中的实战结晶,也适用于任何希望构建可靠长任务 Agent 的团队。

上下文工程不是一次性设计,而是持续迭代的过程。我们经历了四次框架重构,每次都是从真实用户反馈中提炼原则。这个过程没有捷径,必须在真实任务场景里一刀一枪练出来。

未来,随着模型上下文窗口继续扩大,这套体系仍将保持价值——因为高效的记忆管理永远是智能体的核心竞争力。