在线AI教程 / AI工具

[Amazon Bedrock] 生产级 AI agent 的四层上下文工程:Deep Insight 如何把它们写进工作代码

· 转自:aws.amazon.com

生产级 AI agent 的四层上下文工程:Deep Insight 如何把它们写进工作代码 当生产级 AI agent 处理数据分析、报告生成这类任务时,上下文管理会成为主要瓶颈

转载本文转自「aws.amazon.com」,版权归原作者所有,内容已摘录正文、去除外部链接。

生产级 AI agent 的四层上下文工程:Deep Insight 如何把它们写进工作代码

当生产级 AI agent 处理数据分析、报告生成这类任务时,上下文管理会成为主要瓶颈。200K token 的窗口听起来很宽裕,直到一个真实任务在几分钟之内就烧掉其中的大半。数据分析与报告生成会让 agent 执行到一半就失败、准确率下滑,或者把成本推高。已有的公开指南讲的都是这件事,但单项技巧读起来容易、用起来难。把它们一起用上,差别是可量化的:在本文逐步讲解的这份参考实现里,单个写入并执行(write-and-execute)工具把每个脚本新增进上下文的 token 削减约 95%,而按需加载 skill 把 system prompt 缩短约 97%。

本系列把这些指南整理成你可以直接落地的实践。Anthropic 的工程博文,加上 Strands Agents SDK 内置的各项能力,共同收敛到上下文工程的四层:在架构层面隔离上下文,用 prompt 控制它,把它外置到文件系统,再用独立的 agent 与防护措施来校验。在这篇(第 2 部分)里,你会了解每一层如何工作、在可运行的代码里长什么样。我们在 Deep Insight 中应用了这些技巧——一个基于 Strands Agents SDK 与 Amazon Bedrock AgentCore 构建的开源多 agent 数据分析方案,它贯穿全文作为参考实现。

博文系列

第 1 部分:多 agent 系统的 5 个生产挑战,以及 Deep Insight 如何解决它们。 第 2 部分:生产级 AI agent 的四层上下文工程:Deep Insight 如何把它们写进工作代码。 第 3 部分:实践中的 harness 工程:把 Deep Insight 从开发推进到生产。(即将发布!)

第一篇定义了生产级多 agent 系统必须解决的五个核心挑战,并用代码示例介绍了 Strands Agents SDK、Amazon Bedrock 与 Bedrock AgentCore、AWS Fargate 分别如何应对问题的不同层次。这第二篇承接建立在该架构之上的四层上下文工程实践,逐一展示它们的实现。第三篇会指导你在 Amazon Virtual Private Cloud(Amazon VPC)的安全私有网络里部署和运维 agent,覆盖真实运行所需的一切。

什么是上下文工程?

上下文工程是一门学科,研究对象是如何在大语言模型(LLM)有限的上下文窗口里优化所放置的信息,让 agent 表现到最佳。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)

上下文工程解决的正是这些问题,而且它不只是一堆技巧的集合。它横跨架构设计、prompt 撰写、工具实现与校验,是一门分层的学科,每一层都补上前一层漏掉的部分。本文详细讲解你可以用来高效管理上下文的四层方法。

如何处理超出上下文窗口的任务

Anthropic 已经发布了好几种处理长周期任务的技巧。Deep Insight 把这些技巧归为四层,每一层都用来补上其他层的短板。下表列出这四层。

层实践核心原则局限 第 1 层:架构通过多 agent 架构隔离上下文每个 agent 在自己的独立上下文中运行单靠隔离不够时 第 2 层:Prompt输出控制与行为规则用 prompt 限制进入上下文的内容单靠 prompt 不够时 第 3 层:工具基于文件的上下文外置把重内容放在上下文之外的文件里仍然出问题时 第 4 层:校验 agent 与防护措施独立校验与防护捕获错误、防止上下文溢出最后一道防线

下面各节按顺序逐层展开:这一层要求做什么、为什么光靠前面的层不够、以及在 Deep Insight 里这个实践是怎么实现的。

  1. 通过多 agent 架构隔离上下文

让每个专职 agent 都拥有自己的上下文窗口,只把压缩后的结果交给编排器。Deep Insight 用 Coordinator、Planner、Plan Reviewer、Supervisor 与工具 agent(Coder、Validator、Reporter、Tracker、Auditor)组成的层级结构来实现这一点。

只用一个 agent 时,从用户请求到数据探索、分析、生成图表、校验再到报告,所有信息都会堆在同一个上下文里,很容易就超出窗口。给每个 agent 各自的上下文之后,连用量最大的 Coder 总共也控制在 25K token 以内。每个 agent 只接收自己需要的信息,并用一条完成通知加简短摘要向其他 agent 发出信号。

隔离的关键在于尽量少共享信息。Deep Insight 用一个 Python 字典 shared_state,里面只存四样东西:

messages:上一个 agent 的最后一条消息(不是完整的对话历史)。 clues:从每个 agent 收集来的压缩摘要。 full_plan:Planner 生成、Tracker 负责更新的清单。 history:agent 名称与消息的简要日志。

clues 使用固定的 CLUES_FORMAT:不传每个 agent 的完整对话(几万 token),只传压缩后的核心结果。

coder_agent_tool.py -- context passing format

CLUES_FORMAT = "Here is clues from {}:\n\n\n{}\n\n\n" RESPONSE_FORMAT = "Response from {}:\n\n\n{}\n\n\nPlease 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” 一文所推荐的:它描述了一种编排器-worker 模式,由一个 lead agent 向专职 subagent 分派任务,每个 agent 只在自己的上下文内工作。你不必自己动手搭建:Strands Agents SDK 的 agents-as-tools 模式在框架层面就提供了这种隔离。

  1. 用 prompt 控制上下文流入

只有第 1 层的隔离并不够:即便上下文彼此独立,一个总是生成长回复的 agent 仍会把 Supervisor 的上下文撑大。第 2 层用 prompt 限制每个 agent 的输出。

在 Deep Insight 里,我们用 prompt 来限制每个 agent 返回给 Supervisor 的信息量。三条规则承担了大部分工作,Deep Insight 的 prompt 里就能看到。

“从最强的模型和最简单的 prompt 开始,然后根据实际观察到的失败案例,逐步加入具体的指令。” — Anthropic,“Effective Context Engineering for AI Agents”(2025.09)

实现细节 2-1:为每个 agent 显式规定输出 token 预算

每个 agent 的 prompt 都规定了响应的最大 token 数,避免长回复污染 Supervisor 的上下文。

agent输出 token 预算理由 Coder1,000–1,500 tokens分析代码会存进文件,所以该 agent 只返回状态、已完成任务和洞察的摘要 Validator800 tokens校验结果存进 citations.json。该 agent 只返回摘要 Reporter1,000 tokens该 agent 把报告生成为 DOCX 文件,只返回结果的摘要

Anthropic 的 ” Writing Effective Tools for Agents” 一文建议给工具提供 CONCISE 或 DETAILED 两种响应选项,以便节省上下文。把同样的思路往上提一层,用在每个 agent 的 system prompt 里。在 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 的 prompt 明确写着“脚本之间不保留变量”。每个脚本都必须包含全部所需的 import,并直接加载数据。prompt 同时给出了错误示范和正确示范:

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 的 prompt 里包含这样一条规则:“在当前 agent 小节里的清单项全部标记为 [x] 之前,不要转到下一个 agent。”我们把这条规则写进 prompt,是因为判断 Coder 的工作是否完成,需要 Supervisor 依据 Tracker 更新的信息来解读计划,这种判断很难只用代码表达。

  1. “上下文里只放指针,真实数据放进文件”

第 1 层在 agent 之间隔离上下文,第 2 层在 agent 内部限制输出。可当 Coder agent 生成 100 行 Python 代码时,这段代码本身就会进入上下文。就算 prompt 里写了“简要回复”,有些代码也没法简略。第 3 层借助工具设计,把重内容挪出上下文、放进文件系统。其中四种技巧带来大部分收益,下面的实现细节逐一展示。

实现细节 3-1:用 Write and Execute Tool 把代码移出上下文

Coder 读取分析计划、写下 Python 并执行它来生成可视化。但代码一长,常规做法(把写文件和执行拆成两个工具)每个脚本会直接往上下文里加 100 行,累计下来超过 1,000 行。

解决办法是把两步合并成一个工具,让代码永远不会作为消息进入上下文。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 )

Return only summary

return f"Written {len(content.split(chr(10)))} lines to {file_path}\n" \ f"Execution successful\n" \ f"Output: {result.stdout[:500]}" # Only first 500 chars

“服务端过滤:在数据进入上下文之前先在执行层完成过滤,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 的函数。后续分析直接导入它,用两行 import 取代重新生成的 20–30 行代码,既省 token,也让一致性和调试更好。

coder_analysis_utils.py -- common module generated before first task

import numpy as np import json from datetime import datetime

_calculations = []

def to_python_type(value): """Convert numpy/pandas types to Python native types""" 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): """Track calculation metadata -- Validator independently verifies later""" _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:通过结构化笔记保存并共享分析结果

我们用结构化笔记来共享详细的分析结果,而不必让它们穿过每个 agent 的上下文。Deep Insight 把这些结果存进一个叫 all_results.txt 的文件,再由各 agent 按需读取。

例如,Coder agent 在每次分析任务之后把结果追加进 all_results.txt:

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 在撰写最终报告时读取它。其他 agent 也以同样的方式通过 all_results.txt 协作。

不做笔记的话,Coder 每次任务后都要把详细结果传给 Supervisor,不断堆积在 Supervisor 的上下文里。做了笔记,传过去的只是一条约 30 token 的消息——“品类销售分析完成,找到 3 条关键洞察,详细结果已存入 all_results.txt”,Reporter 需要时再去读那个文件。

这个模式的适用范围不限于单个文件。文件系统本身就能充当 agent 之间的通信总线,Deep Insight 就是这么做的:

文件名生产者消费者作用 all_results.txtCoderReporter分析结果的累积日志 calculation_metadata.jsonCoderValidator数值计算的记录:来源、公式与取值(用于校验) citations.jsonValidatorReporter已校验的引用数据(在报告中以 [1]、[2] 的形式插入) audit_findings.jsonAuditorReporter最终报告中发现的引用缺陷(驱动 Reporter 的定向重试) coder_analysis_utils.pyCoder所有脚本共享的工具函数(写一次,反复导入) full_plan (shared_state)Planner/TrackerSupervisor清单状态(更新 [x])

““just in time” 这种做法——在运行时动态地把数据加载进上下文,而不是预先处理所有相关数据——能让上下文保持新鲜、切题,并适应任务不断变化的状态。” — Anthropic,“Effective Context Engineering for AI Agents”(2025.09)

实现细节 3-4:用 Skills 只加载所需的知识

这种做法不是把所有专业知识都塞进 system prompt,而是只在需要时加载。如果把每个 skill 指南(数据结构检查、README 生成、skill 创建、system prompt 撰写、工具创建)都包含进来,会多出 20K 以上的 token,每次调用都往 Coder agent 里灌入不必要的信息,而且每加一个 skill 就得重新部署一次。

Deep Insight 的 Skills 系统启动时只加载一份约 500 token 的 skill 目录,skill 列表里只放名称和简短描述。当用户提出“创建一个 README 文件”时,agent 判断“我需要 readme-generator 这个 skill”,然后调用 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 available_skills, skill_prompt = initialize_skills( skill_dirs=["./skills"], verbose=True )

2. Add to System Prompt (~500-token catalog)

system_prompt = base_prompt + skill_prompt

3. Runtime -- Agent loads skill when needed

Agent decides: "This is README generation, I need the readme-generator skill"

-> skill_tool(skill_name="readme-generator")

-> Returns full SKILL.md content (~3K tokens)

每个 skill 都定义为一个 SKILL.md 文件,由 YAML frontmatter 和详细的 markdown 指南组成。它包含 name、description、license、allowed-tools 这类元数据,以及 Overview、When to Use This Skill、详细指令和 Best Practices。要新增一个 skill,就在 skills/ 下新建一个目录、写一个 SKILL.md 文件,它会被自动发现。

启动时,agent 加载的是约 500 token 的 skill 目录,而不是为完整指南浪费 20,000 以上的 token(少了约 97%)。需要时,它再为某个 skill 加载几千 token 的详细指令。

  1. 用校验 agent 与防护措施保证质量

即便有了第 1–3 层,仍有一个风险留存:彼此隔离的 agent 看不见对方的工作,所以 Coder 一旦算错,Reporter 就会把这个错误带进报告。第 4 层是最后一道防线。

“提供测试工具,让 agent 能自行验证功能、修复那些只看代码发现不了的 bug。让模型把进度以带描述的 commit message 提交到 git,并在一个 progress 文件里写下进度摘要。” — 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 拿最终的 DOCX 去对照 citations.json 和 calculation_metadata.json,但不修改它们。它把引用缺陷记录到 audit_findings.json,并可以要求 Reporter 做最多两次定向重试。

实现细节 4-2:按优先级挑选要校验的计算

逐项校验所有计算效率很低,所以要按重要程度界定校验范围。Deep Insight 的 OptimizedValidator 采用以下阈值:

超过 50 项计算:激进过滤,校验全部 high,另外只校验 10 项 medium。 超过 20 项计算:中度过滤,校验全部 high,另外校验 15 项 medium。 20 项及以下:校验大部分,全部 high、全部 medium,再加 5 项 low。

它同时采用类型安全的比较:为了避免 numpy 类型与 Python 类型之间的差异问题,所有值都先转成 float(),再检查绝对差是否小于 0.01:

validator.md -- type-safe numerical comparison

try: match = abs(float(expected) - float(actual)) < 0.01 except: match = str(expected) == str(actual)

实现细节 4-3:SummarizingConversationManager:最后一道安全网

极端情况下上下文仍可能溢出,所以在其他层之下再留一道安全网。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)要求 clues、plans 和 tracking status 逐字保留。

实现细节 4-4:用选择性 prompt caching 优化成本

上下文工程不只关乎省 token,也关乎成本优化。按 agent 分别启用 prompt caching,依据是每个 agent 用同一份 prompt 被调用的频率。Deep Insight 的各 agent 设置如下:

agentPrompt 缓存工具缓存理由 Supervisor是是重复调用频率高,system prompt 与工具定义都很大 Coder是是顺序运行多个分析脚本,每次用同一份 prompt Reporter是是逐节增量生成报告,prompt 复用频率高 Auditor是是用同一份 prompt 和同一批工具多轮检查 DOCX 与 JSON 文件,且 Reporter 每次重试后都要重跑 Coordinator否否一次性调用,没有缓存收益 Planner否否每个请求只调用一次,只有用户要求修改计划时才会再调用 Validator否否每次用不同的数据调用,缓存命中率低 Tracker否否任务轻量、没有工具,不需要缓存

启用了缓存的 agent 会在 system prompt 和工具定义里插入缓存点,在重复调用时最多降低 90% 的输入 token 成本。这是 Strands Agents SDK 原生支持的能力。Plan Reviewer 没有出现在表里,因为它是人在环中的环节,负责收集用户的批准或反馈,而不是调用模型。

结论

本文详细讲解了这套四层工程方法,你可以用它为超出上下文窗口的复杂任务高效管理上下文。

第 1 层(架构层面隔离):通过多 agent 架构让每个 agent 在独立的上下文中工作,只传递压缩后的摘要。 第 2 层(基于 prompt 的控制):输出 token 预算、标准化的响应格式和自包含代码的理念,主动限制上下文流入。 第 3 层(使用文件系统):write_and_execute_tool 把代码留在上下文之外,文件系统充当 agent 之间的通信总线,知识只在需要时才加载。 第 4 层(校验与防护):Validator 独立复核计算、Auditor 对最终报告做只读的引用审计、Tracker 跟踪进度、SummarizingConversationManager 防溢出,再加上选择性 prompt caching,同时管住质量与成本。

每一层都构成一道防御体系,补上前面的层漏掉的东西。架构隔离不够时,prompt 来限制输出;prompt 不够时,工具把内容留在外部;仍然出问题时,由校验来捕获。

这几层都能在 Anthropic 的工程博文里找到依据:“Effective Context Engineering for AI Agents”、“Code Execution with MCP” 与 “How We Built Our Multi-Agent Research System”。它们建议的许多内容,Strands Agents SDK 已经自带,而不是要你自己造:SummarizingConversationManager、prompt caching 和 agents-as-tools 模式。

构建生产级 agent 时,光靠 LLM 的上下文窗口往往不够。把这些上下文工程技巧用起来,高效管理上下文,让你的 agent 撑得起生产负载。

本文使用的参考实现 Deep Insight 是开源的。欢迎审阅代码,并把它扩展到你自己的领域。

GitHub Workshop

关于作者