生产环境 AI 代理的四层上下文工程:Deep Insight 如何在可运行代码中落地
生产环境中的 AI 代理处理数据分析和报告生成这类任务时,上下文管理往往成为主要瓶颈。20 万 token 的窗口听起来很宽裕,但真实任务几分钟就能吃掉大半。数据分析和报告生成会让代理执行到一半就失败、准确率下降,或者成本飙升。
已有不少公开指南讨论过这个问题,但单项技术读起来容易,落地却不简单。把这些技术组合使用,效果相当可观:本文介绍的参考实现中,一个“写入并执行”工具把每个脚本添加到上下文的 token 减少了约 95%,按需加载技能则让系统提示词缩小了约 97%。本系列把这些指南整理成可以直接上手的实践。Anthropic 的工程博客和 Strands Agents SDK 内置的功能,最终汇聚成四层上下文工程:在架构层隔离上下文、通过提示控制上下文、将上下文外部化到文件系统、用独立代理和防护措施来验证上下文。
本文是第二部分,将介绍每一层如何工作,以及在可运行代码中长什么样。我们在 Deep Insight 中应用了这些技术——这是一个开源的多代理数据分析方案,基于 Strands Agents SDK 和 Amazon Bedrock AgentCore 构建,也是全文的参考实现。
系列文章
- 第一部分:多代理系统中的 5 个生产挑战,以及 Deep Insight 如何解决它们。
- 第二部分:生产环境 AI 代理的四层上下文工程:Deep Insight 如何在可运行代码中落地。
- 第三部分:实践中的 Harness 工程:把 Deep Insight 从开发环境推进到生产环境。(即将发布!)
第一篇定义了生产级多智能体系统必须解决的五个核心难题,并配以代码示例,说明 Strands Agents SDK、Amazon Bedrock、Bedrock AgentCore 和 AWS Fargate 各自解决问题的哪个层次。本篇(第二篇)把架在架构之上的四层上下文工程实践逐一展开,每一层都给出具体实现。第三篇则带你完成智能体在 Amazon Virtual Private Cloud(Amazon VPC)安全私有网络中的部署与运维,覆盖真实生产所需的全部环节。
什么是上下文工程?
上下文工程,说白了就是把大语言模型(LLM)有限的上下文窗口管好、把里面的信息优化到位,让智能体跑出最佳状态。Amazon Bedrock 上可用的 Anthropic Claude Sonnet 4.5 提供 200K 的上下文窗口,可复杂的生产任务很容易就超出这个长度。
举个例子,一个看似简单的请求——「分析销售数据并生成 DOCX 报告」——实际上要经过好几个阶段:数据加载与探索(5 分钟)、按品类做销售分析(3 分钟)、生成 5 张时序分析图表(10 分钟)、统计验证(3 分钟)、最终报告生成(5 分钟)。整个过程耗时约 15 分钟,消耗超过 150K token。
把这类任务塞进单个上下文会出问题:任务做到一半窗口就溢出,过时的上下文拖累表现,一旦出错整个流程还得重跑。上下文越长,模型对关键信息的注意力越弱;效率一低,按 token 计费的成本也跟着上去。
随着上下文窗口里 token 数量的增加,模型准确回忆其中信息的能力会下降(即「上下文腐化」,Context rot)。
—— Anthropic,《Effective Context Engineering for AI Agents》(2025.09)
上下文工程正是冲着这些问题来的,而且它不只是一堆技巧的集合。它横跨架构设计、提示词撰写、工具实现和验证,是一个分层的实践体系——每一层都在补上一层的漏。本文会详细拆解这套四层方法,帮你有条理地管好上下文。
如何处理超出上下文窗口的任务
Anthropic 公布过多种应对长周期任务的技术方案。Deep Insight 把这些技术归为四层,每一层都在弥补其他层的不足。下表列出这四层。
| 层级 | 做法 | 核心原则 | 局限 |
|---|---|---|---|
| 第 1 层:架构 | 通过多智能体架构隔离上下文 | 每个智能体在独立的上下文中运行 | 仅靠隔离还不够时 |
| 第 2 层:提示词 | 输出控制与行为规则 | 通过提示词限制上下文摄入 | 仅靠提示词还不够时 |
| 第 3 层:工具 | 基于文件的上下文外置 | 把重量级内容留在上下文之外的文件里 | 仍然出现问题时 |
| 第 4 层:验证 | 智能体与防护机制 | 独立验证与防护 | 捕捉错误、防止上下文溢出 |
接下来的几节会依次讲每一层:它规定了什么、为什么单靠前面的层还不够、以及 Deep Insight 如何落地这套做法。
1. 通过多智能体架构隔离上下文
给每个专用智能体分配自己的上下文窗口,只把压缩后的结果交给编排器。Deep Insight 用一套层级结构来做这件事:协调器(Coordinator)、规划器(Planner)、计划审查器(Plan Reviewer)、监督器(Supervisor),以及各类工具智能体(编码器 Coder、验证器 Validator、报告器 Reporter、追踪器 Tracker、审计器 Auditor)。
如果只用单个智能体,所有信息——从用户请求到数据探查、分析、图表生成、验证、出报告——都会堆在同一个上下文里,很容易超出窗口。让每个智能体拥有自己的上下文后,即便用得最多的编码器,总消耗也能压在 25K token 以内。每个智能体只接收自己需要的东西,再用一条完成通知加简要摘要来告知其他智能体。
隔离的关键在于尽量少共享信息。Deep Insight 用一个 Python 字典 shared_state,其中只存四样东西:
messages:上一个智能体的最终消息(不是完整对话历史)。clues:从各智能体收集的压缩摘要。full_plan:由 Planner 生成、Tracker 更新的检查清单。history:智能体名称和消息的简短日志。
clues 使用固定的 CLUES_FORMAT:只传递压缩后的核心结果,而不是每个智能体的完整对话(动辄数万 token)。
# coder_agent_tool.py -- context passing format
CLUES_FORMAT = "Here is clues from {}:\n\n<clues>\n{}\n</clues>\n\n"
RESPONSE_FORMAT = "Response from {}:\n\n<response>\n{}\n</response>\n\n*Please execute the next step.*"
# After Coder completes: add only compressed result to clues
clues += CLUES_FORMAT.format("coder", response["text"])
这种模式正是 Anthropic 在《How We Built Our Multi-Agent Research System》一文中推荐的:编排器-工作者模式(orchestrator-worker),由主智能体把任务分派给专职子智能体,每个智能体只在自己的上下文中工作。你不需要自己实现这套机制:Strands Agents SDK 的“智能体即工具”(agents-as-tools)模式已经在框架层面提供了这种隔离。
2. 通过提示词控制上下文流入
光靠第 1 层隔离还不够:即使上下文彼此独立,只要某个智能体输出很长,Supervisor 的上下文照样会被撑大。第 2 层用提示词限制每个智能体的输出。在 Deep Insight 中,我们用提示词限制每个智能体返回给 Supervisor 的信息量。正如 Deep Insight 的提示词所示,三条规则承担了大部分工作。
“先用最强的模型和最简洁的提示词起步,再根据实际观察到的失败案例逐步补充具体指令。”
—— Anthropic,《Effective Context Engineering for AI Agents》(2025.09)
实现细节 2-1:为每个智能体明确设定输出 token 预算
每个智能体的提示词里都规定了最大响应 token 数,避免冗长回复污染 Supervisor 的上下文。
| Agent | 输出 Token 预算 | 原因 |
|---|---|---|
| Coder | 1,000–1,500 tokens | 分析代码会保存到文件,因此 agent 只返回状态、已完成任务和关键洞见的摘要 |
| Validator | 800 tokens | 验证结果会写入 citations.json,agent 只返回摘要 |
| Reporter | 1,000 tokens | agent 将报告生成为 DOCX 文件,只返回结果摘要 |
Anthropic 的《Writing Effective Tools for Agents》一文建议,为了节省上下文,给工具提供 CONCISE(简洁)或 DETAILED(详细)两种响应选项。把这个思路往上提一层,用到每个 agent 的系统提示词里。在 Deep Insight 中,所有 agent 共用同一套标准格式:
## Status
[SUCCESS | PARTIAL_SUCCESS | ERROR]
## Completed Tasks
- [Task 1 from FULL_PLAN -- use exact wording so Tracker can match]
- [Task 2 -- be specific, not generic]
## Key Insights
- [Key finding 1 with numbers and ratios]
- [Key finding 2 with business implications]
## Generated Files
- ./artifacts/chart.png -- brief description
- ./artifacts/calculation_metadata.json -- N calculations
实现细节 2-2:自包含代码原则
Coder agent 的提示词明确写了「变量不会跨脚本保留」。每个脚本都必须带上所需的全部 import,并自行加载数据。提示词里同时给出了错误示例和正确示例:
# WRONG -- Attempting to use a variable from Turn 1 in Turn 2
# Turn 1:
df = pd.read_csv('data.csv')
total = df['Amount'].sum()
# Turn 2:
print(f"Total: {total}") # NameError: name 'total' is not defined
# CORRECT -- Every script is self-contained
import pandas as pd
df = pd.read_csv('./artifacts/cache/df_main.csv') # Load from cache
total = df['Amount'].sum()
print(f"Total: {total}")
这条规则跟上下文工程的关系在于:如果脚本要引用之前脚本里的变量,agent 就得「记住」之前的对话,也就意味着旧代码必须一直留在上下文里。而自包含原则让旧代码可以安全地从上下文里移除。
实现细节 2-3:Supervisor 的章节完成规则
Supervisor 的提示词里有一条规则:「当前 agent 章节里的所有清单项都标记为 [x] 之前,不要切换到下一个 agent。」我们把这条规则写进提示词,是因为要判断 Coder 的工作是否完成,Supervisor 得结合 Tracker 的更新来解读计划。这种判断很难只用代码表达。
3. 「上下文只放指针,实际数据放文件」
Layer 1 把上下文隔离在各个 agent 之间,Layer 2 限制 agent 内部的输出。但 Coder agent 生成 100 行 Python 代码时,这些代码本身就会进入上下文。即便提示词要求「简短回复」,有些代码就是没法写短。Layer 3 靠工具设计,把体量大的内容挪到上下文之外,放进文件系统。下面的实现细节展示了其中四项技术,大部分收益都来自它们。
实现细节 3-1:用 Write and Execute Tool 把代码移出上下文
Coder 读取分析计划,编写 Python,再执行它生成可视化结果。可代码一长,常规做法(把写文件和执行拆成两个工具)每跑一个脚本就往上下文里塞 100 行,累积下来能超过 1000 行。解决办法是把这两步合并成一个工具,让代码不再以消息形式进入上下文。Deep Insight 的 Coder agent 为此用了一个 write_and_execute_tool。下面是 write_and_execute_tool 的一部分。写完并执行文件之后,它只返回一段摘要:「写入了 105 行,执行成功,完成了五个类别的分析。」代码留在文件里,上下文里只多了大约三行摘要。按这个例子算,能省下约 95% 的 token。
# write_and_execute_tool.py
def _handle_write_and_execute_tool(file_path, content, timeout=300):
"""Write a Python script and immediately execute it."""
# Step 1: Write file
with open(file_path, 'w', encoding='utf-8') as f:
f.write(content)
# Step 2: Execute immediately
result = subprocess.run(
f"python {file_path}",
shell=True,
capture_output=True,
timeout=timeout
)
```python
# 只返回摘要
return f"已将 {len(content.split(chr(10)))} 行写入 {file_path}\n" \
f"执行成功\n" \
f"输出:{result.stdout[:500]}" # 只取前 500 个字符
"服务端过滤:数据在到达上下文之前,先在执行层完成过滤,token 减少 98.7%(从 150K 降到 2K)。"
—— Anthropic,《Code Execution with MCP》(2025.11)
实现细节 3-2:在 Coder agent 里把常用逻辑复用为模块
同一批模块会在多次分析中反复用到。与其每次重新生成,不如把高频函数定义成模块、按需导入,既省 token,也避免上下文重复。否则每次分析都要重新定义 to_python_type() 或 track_calculation() 这类函数,10 次分析下来就会积累 200–300 行重复代码。Deep Insight 会在第一个任务开始前生成一个名为 coder_analysis_utils.py 的模块,里面包含 numpy 类型转换、计算元数据追踪、写入 JSON 等函数。后续分析直接导入它,原本需要重新生成的 20–30 行代码,现在只靠两行 import 就搞定——既省 token,也让代码更一致、更好调试。
# coder_analysis_utils.py -- 第一个任务前生成的公共模块
import numpy as np
import json
from datetime import datetime
_calculations = []
def to_python_type(value):
"""把 numpy/pandas 类型转换为 Python 原生类型"""
if isinstance(value, (np.integer, np.int64)): return int(value)
elif isinstance(value, (np.floating, np.float64)): return float(value)
elif isinstance(value, np.ndarray):
return value.tolist()
return value
def track_calculation(calc_id, value, description, formula,
source_file, source_columns, importance):
"""追踪计算元数据——之后由 Validator 独立校验"""
_calculations.append({
"id": calc_id, "value": to_python_type(value),
"description": description, "formula": formula,
"source_file": source_file, "source_columns": source_columns,
"importance": importance
})
def save_calculation_metadata(path="./artifacts/calculation_metadata.json"):
"""Save all tracked calculations to JSON"""
with open(path, 'w', encoding='utf-8') as f:
json.dump({"generated_at": datetime.now().isoformat(),
"calculations": _calculations}, f, ensure_ascii=False, indent=2)
实现细节 3-3:用结构化笔记保存并共享分析结果
我们用结构化笔记来共享详细的分析结果,而不必让这些数据在每个智能体的上下文里来回传递。Deep Insight 把结果存到一个名为 all_results.txt 的文件里,各智能体需要用的时候再读取。比如 Coder 智能体每完成一次分析任务,就把结果追加到这个文件:
with open('./artifacts/all_results.txt', 'a', encoding='utf-8') as f:
f.write(f"""
## Category Sales Analysis (completed at: 14:32)
- Top revenue category: Fruit (417,166,008 KRW, 45% of total)
- Top 3 categories: Fruit, Vegetables, Meat (78% of total)
- Generated file: ./artifacts/category_sales_chart.png
""")
Coder 每完成一次分析就往这个文件里记录详细结果,Reporter 在写最终报告时读取它。其他智能体也通过 all_results.txt 以同样的方式协作。
如果不用笔记,Coder 每完成一个任务就要把详细结果交给 Supervisor,这些内容会不断堆积在它的上下文里。用了笔记之后,只需传一条大约 30 token 的消息,比如「品类销售分析完成,找到 3 个关键洞察,详细结果已保存到 all_results.txt」,Reporter 需要时再去读文件即可。
这套做法并不局限于单个文件。文件系统本身就可以充当智能体之间的通信总线,Deep Insight 就是这么做的:
| 文件名 | 生产者 | 消费者 | 作用 |
|---|---|---|---|
| all_results.txt | Coder | Reporter | 分析结果的累积日志 |
| calculation_metadata.json | Coder | Validator | 数值计算记录:来源、公式和数值(用于校验) |
| citations.json | Validator | Reporter | 已核实的引用数据(在报告里以 [1]、[2] 形式插入) |
| audit_findings.json | Auditor | Reporter | 最终报告中发现的引用缺陷(用于触发 Reporter 定向重试) |
| coder_analysis_utils.py | Coder | 所有脚本 | 共享工具函数(写一次,反复导入) |
| full_plan(shared_state) | Planner/Tracker | Supervisor | 清单状态(勾选 [x] 更新) |
「『刚好及时』的做法——在运行时把数据动态加载进上下文,而不是事先处理所有相关数据——能让上下文保持新鲜、贴切,并随任务状态的演变而调整。」
—— Anthropic,《Effective Context Engineering for AI Agents》(2025.09)
实现细节 3-4:用 Skills 只加载需要的知识
这种做法不把所有专业知识都塞进系统提示,而是按需加载。如果把每一份技能指南(数据结构检查、README 生成、技能创建、系统提示编写、工具创建)都放进去,会多出 20K 以上的 token,每次调用 Coder 智能体都往它的上下文里加载用不上的信息,而且想新增一个技能还得重新部署。
Deep Insight 的 Skills 系统启动时只加载约 500 token 的技能目录,列表里仅有技能名称和简短描述。当用户要求「创建一个 README 文件」时,智能体判断「我需要 readme-generator 这个技能」,然后调用 skill_tool(skill_name="readme-generator")。SkillLoader 读取 readme-generator/SKILL.md,返回一份约 3K token 的详细指南。
# 1. Skill Discovery (at initialization)
from src.utils.skills.skill_utils import initialize_skills
它返回完整的 SKILL.md 内容,约 3K token。每个技能对应一个 SKILL.md 文件,文件由 YAML frontmatter(前置元数据)和详细的 markdown 指南组成,包含名称、描述、许可证、allowed-tools 等元数据,以及 Overview、When to Use This Skill、详细说明和最佳实践。添加新技能时,只需在 skills/ 目录下新建一个目录,写一个 SKILL.md 文件,系统就会自动发现。启动时,agent 先加载约 500 token 的技能目录,而不是把 20,000 多 token 浪费在完整指南上,省下约 97%。需要时,再按需加载几千 token 的技能详细说明。
4. 用验证 agent 和安全网来验证质量
即使有了第 1–3 层,风险依然存在:agent 彼此独立,看不到对方的工作,所以如果 Coder 算错了,Reporter 会把这个错误带进报告。第 4 层就是最后一道防线。
“提供测试工具,让 agent 能自行验证功能,并修复仅靠代码不明显的 bug。让模型用描述性提交信息把进度提交到 git,并在进度文件中写进度摘要。”——Anthropic,《Effective Harnesses for Long-Running Agents》(2025.11)
实现细节 4-1:Tracker、Validator 和 Auditor agent:进度跟踪与质量保证
Tracker 实时更新计划的检查清单。当 Coder 完成数据加载时,Supervisor 调用 Tracker,Tracker 根据“数据加载完成(1,000 行,5 列)”之类的信息,把计划项从 [ ] 更新为 [x]。这样用户和系统都能准确了解进度。
Validator 独立重新执行 Coder 的计算来验证准确性。它读取 calculation_metadata.json,从源数据重新执行每项计算并比较结果:误差在 0.01 以内即通过,不匹配则标记。验证过的计算会写入 citations.json,供 Reporter 引用。
Reporter 完成后,Auditor 会对照 citations.json 和 calculation_metadata.json 检查最终 DOCX,但不修改它们。它把引用缺陷记录在 audit_findings.json 中,并且最多可以请求 Reporter 进行两次针对性重试。
实现细节 4-2:按重要性优先验证计算
逐项验证所有计算效率不高,所以按重要性划定验证范围。Deep Insight 的 OptimizedValidator 采用以下阈值:
- 计算超过 50 项:激进过滤,验证所有高重要性计算,加上仅 10 项中等重要性计算。
- 计算超过 20 项:适度过滤,验证所有高重要性计算,加上 15 项中等重要性计算。
- 计算不超过 20 项:验证大部分,包括所有高重要性计算、所有中等重要性计算,再加 5 项低重要性计算。
它还应用类型安全的比较:为了避免 numpy 与 Python 类型问题,所有值都转换为 float(),并检查绝对差是否小于 0.01。
异常情况下上下文仍可能溢出,所以在其他层之下保留一个安全网。Deep Insight 为此使用 Strands Agents SDK 中的 SummarizingConversationManager。
# strands_sdk_utils.py -- safety net configuration at agent creation
agent = Agent(
model=llm,
system_prompt=system_prompts,
tools=tools,
conversation_manager=SummarizingConversationManager(
summary_ratio=0.5, # summarize oldest 50% on overflow
preserve_recent_messages=10, # always preserve 10 most recent messages
summarization_system_prompt=apply_prompt_template("summarization", {})
)
当上下文溢出时,LLM 会把最旧的 50% 消息总结成一条,同时始终保留最近 10 条消息,以维持当前任务的上下文。总结 prompt(summarization.md)要求把线索、计划和跟踪状态逐字保留。
实现细节 4-4:按需启用 prompt 缓存以优化成本
上下文工程不只是节省 token,也包括成本优化。根据各 agent 被相同 prompt 调用的频率,可以为每个 agent 单独开启 prompt 缓存。Deep Insight 的逐 agent 设置如下:
| Agent | Prompt 缓存 | 工具缓存 | 原因 |
|---|---|---|---|
| Supervisor | 是 | 是 | 重复调用频率高,系统 prompt 和工具定义都很大 |
| Coder | 是 | 是 | 依次运行多个分析脚本,每次 prompt 相同 |
| Reporter | 是 | 是 | 逐节增量生成报告,prompt 复用频率高 |
| Auditor | 是 | 是 | 用相同的 prompt 和工具,多轮检查 DOCX 和 JSON 文件,并在每次 Reporter 重试后重新运行 |
| Coordinator | 否 | 否 | 一次性调用,缓存没有收益 |
| Planner | 否 | 否 | 每个请求调用一次,只在用户要求修改计划时再次调用 |
| Validator | 否 | 否 | 每次调用的数据都不同,缓存命中率低 |
| Tracker | 否 | 否 | 轻量任务,不用工具,没必要缓存 |
开启缓存的 agent 会把缓存点插入系统 prompt 和工具定义中,在重复调用时最多可减少 90% 的输入 token 成本。这是 Strands Agents SDK 原生支持的功能。
Plan Reviewer 没有出现在表中,因为它是一个 human-in-the-loop 步骤,负责收集用户批准或反馈,不调用模型。
结语
本文详细介绍了四层工程方法,可以用来高效管理超出上下文窗口的复杂任务所需的上下文。
- 第一层(架构级隔离):通过多智能体架构,让每个智能体在独立上下文中工作,彼此之间只传递压缩后的摘要。
- 第二层(提示词层面的控制):限定输出 token 的预算、统一响应格式、坚持「自带完整信息」的代码风格,主动减少进入上下文的内容。
- 第三层(利用文件系统):用
write_and_execute_tool让代码留在上下文之外;把文件系统当作智能体之间的通信总线;知识按需懒加载,用到时才读。 - 第四层(校验与兜底):Validator 独立重算复核,Auditor 对最终报告做只读引用审查,Tracker 跟踪进度,
SummarizingConversationManager防止上下文溢出,再加上选择性的提示词缓存,兼顾质量与成本。
这四层加起来构成一套防御体系,前一层漏掉的由后一层补上。架构隔离不够,就用提示词约束输出;提示词不够,就用工具把内容放到上下文之外;还是出问题,就靠校验把它抓出来。
这些做法在 Anthropic 的几篇工程博客里都有记录,包括《Effective Context Engineering for AI Agents》《Code Execution with MCP》和《How We Built Our Multi-Agent Research System》。其中不少已经内置在 Strands Agents SDK 里,不需要你自己去搭,比如 SummarizingConversationManager、提示词缓存,以及把智能体当作工具的「agents-as-tools」模式。
做生产级智能体时,光靠大语言模型(LLM)的上下文窗口往往不够用。用上这些上下文工程技巧,才能高效管理上下文,让智能体扛住生产负载。文中作为示例的参考实现 Deep Insight 已经开源,你可以去看代码,再按自己的业务领域扩展。