用递归语言模型突破上下文窗口限制:Amazon Bedrock AgentCore 实战

2026-05-22 38 预计阅读时间:1 分钟
来源:aws.amazon.com AI 摘要 原文链接

免责声明:本文为 AI 摘要整理,建议结合原文阅读。摘要可能省略上下文、版本差异或边界条件,不作为官方说明。

预计阅读时间:12 分钟

大模型的上下文窗口一直在增长——128K、256K、甚至 1M tokens——但现实中的文档处理需求增长更快。一份年度财报、一套完整法规修订稿、一个大型代码仓库的跨模块审计,轻松就能超出任何单次调用的承载能力。Amazon Bedrock AgentCore 结合 Strands Agents SDK 提出了一种新思路:递归语言模型(Recursive Language Model, RLM),让模型在沙箱化的 Python 环境中反复调用自身,用持久化的工作记忆逐步消化任意长度的文档,不再有上限。

上下文窗口的真正瓶颈

传统做法面对超长文档有两条路:

  • 截断或摘要:丢掉细节,分析结果天然不完整。
  • 分片并行处理:各片独立推理,丢失跨章节的关联与因果链。

两条路都妥协了"全局理解"这个核心需求。你读一份 200 页的诉讼材料,第 180 页的关键证据只有和第 12 页的陈述对照才有意义——分片处理根本无法建立这种联系。

RLM 的思路不同:它不试图把整份文档塞进一次调用,而是让一个"编排者"在持久化的执行环境中反复调度子调用(sub-LLM),每次只处理一个片段,但把中间结论写入工作记忆,后续调用可以读取前序积累。这样既不超出单次上下文窗口,又保留了全局连贯性。

RLM 的运作机制

整个流程可以拆成三层:

  1. 编排层:一个 Agent(基于 Strands Agents SDK)负责规划——决定先读哪一段、什么时候汇总、什么时候做交叉验证。
  2. 执行层:Amazon Bedrock AgentCore Code Interpreter 提供沙箱化的 Python 运行环境,Agent 在这里写代码、读文件、维护状态。这个环境是持久化的,不是一次性 sandbox,前一轮写入的变量和文件下一轮还在。
  3. 推理层:每次 sub-LLM 调用只拿当前片段 + 工作记忆中的摘要进来,在单次上下文窗口内完成局部推理,结果再写回工作记忆。

关键在于"递归"二字:Agent 可以在 Code Interpreter 中写一段 Python,这段 Python 又调用 LLM 做推理,推理结果触发新的代码执行,代码执行又可能调度下一轮 LLM 调用——形成嵌套循环,直到 Agent 判断分析完成。

用 Strands Agents SDK 实现 RLM

下面是一个可改造运行的示例,展示如何用 Strands Agents SDK + Bedrock AgentCore Code Interpreter 构建一个最简 RLM 流程,对超长文档做迭代分析。

前置准备

# 安装 Strands Agents SDK
pip install strands-agents

# 确保 AWS 凭证已配置(Bedrock AgentCore 需要)
aws configure
# 或使用环境变量
export AWS_REGION=us-east-1
export AWS_ACCESS_KEY_ID=your_key
export AWS_SECRET_ACCESS_KEY=your_secret

核心代码

import boto3
from strands.agent import Agent
from strands.tools import code_interpreter

# 1. 创建带 Code Interpreter 工具的 Agent
#    Code Interpreter 即 Bedrock AgentCore 提供的沙箱化持久执行环境
agent = Agent(
    model_id="us.anthropic.claude-sonnet-4-20250514",  # 或其他 Bedrock 模型
    tools=[code_interpreter],  # 注入 Code Interpreter 工具
)

# 2. 构造 RLM 提示词——让 Agent 自己编排分片读取与递归推理
rlm_prompt = """
你是一个递归语言模型(RLM)分析器。你的任务是分析一份超长文档,但你无法一次性读取全文。

策略:
1. 在 Code Interpreter 中用 Python 读取文档,每次只读一个章节(约 2000-4000 tokens)。
2. 每读完一个章节,将关键发现以 JSON 格式写入工作记忆文件 /workspace/memory.json。
3. 读取下一章节时,先加载已有的工作记忆,结合新内容做增量分析。
4. 当所有章节处理完毕,读取完整工作记忆,生成最终综合报告。
5. 如果发现前后章节存在矛盾或关联,立即在工作记忆中标注交叉引用。

文档路径:/workspace/document.txt
开始分析第一章,然后递归推进。
"""

# 3. 启动 RLM 流程
result = agent(rlm_prompt)
print(result.message)

Code Interpreter 内部的递归逻辑

Agent 在 Code Interpreter 中生成的 Python 大致会遵循这样的模式(以下为 Agent 可能自动生成的代码骨架,可手动预置到 /workspace 以引导方向):

# /workspace/rlm_runner.py — Agent 可在沙箱中执行此脚本
import json, os

MEMORY_PATH = "/workspace/memory.json"
DOC_PATH = "/workspace/document.txt"

def load_memory():
    if os.path.exists(MEMORY_PATH):
        with open(MEMORY_PATH) as f:
            return json.load(f)
    return {"chapters_processed": [], "findings": [], "cross_references": []}

def save_memory(memory):
    with open(MEMORY_PATH, "w") as f:
        json.dump(memory, f, ensure_ascii=False, indent=2)

def read_chapter(doc_lines, chapter_idx, lines_per_chapter=80):
    """按行数分片,每次取一个章节"""
    start = chapter_idx * lines_per_chapter
    end = start + lines_per_chapter
    return "\n".join(doc_lines[start:end])

def main():
    with open(DOC_PATH) as f:
        doc_lines = f.readlines()

    total_chapters = len(doc_lines) // 80 + 1
    memory = load_memory()

    for idx in range(total_chapters):
        if idx in memory["chapters_processed"]:
            continue  # 跳过已处理章节(持久化记忆的威力)

        chapter_text = read_chapter(doc_lines, idx)
        # 这里 Agent 会调度一次 sub-LLM 调用,
        # 输入 = 当前章节文本 + 工作记忆摘要
        # 输出 = 该章节的结构化发现
        # 实际调用由 Strands Agent 在运行时自动编排

        memory["chapters_processed"].append(idx)
        # memory["findings"].append(sub_llm_result)  # 由 Agent 填入
        save_memory(memory)  # 每步持久化,中断后可恢复

    # 最终汇总:读取完整记忆,生成综合报告
    # 同样由 Agent 调度 sub-LLM 完成

if __name__ == "__main__":
    main()

这段代码的核心设计意图:

  • 分片读取:按固定行数切分,每次只喂给 sub-LLM 一个片段。
  • 持久化工作记忆memory.json 存在沙箱文件系统中,跨调用轮次保留。即使中途失败,重启后从 chapters_processed 判断进度,跳过已完成部分。
  • 交叉引用空间cross_references 字段专门存放跨章节关联,这是分片并行处理做不到的。

为什么 Code Interpreter 是关键基础设施

普通 Agent 框架的工具调用是无状态的——每次调用独立,前一轮的局部变量、临时文件全部消失。RLM 需要的是一个跨轮次持久化的执行环境,Bedrock AgentCore Code Interpreter 正好满足:

能力 普通 Tool Call AgentCore Code Interpreter
状态保持 无,每次重新初始化 文件系统 + 变量跨轮次保留
文件读写 仅通过 API 传递字符串 直接操作沙箱内文件系统
子进程调度 不支持 可在 Python 内部编排多步逻辑
安全边界 依赖外部过滤 沙箱化,网络与资源受限

这意味着 Agent 可以在 Code Interpreter 中写一个完整的分析脚本,脚本内部再按需调用 LLM——递归嵌套自然发生,而不是靠外部循环硬拼。

实践中的几个决策点

分片粒度怎么选? 太大可能撑爆单次 sub-LLM 的上下文窗口;太小则跨章节关联的密度不够,汇总时容易丢失线索。经验值:每个片段控制在模型上下文窗口的 30%-40%(留空间给工作记忆摘要和指令),例如对 128K 窗口的模型,每片 40K-50K tokens。

工作记忆的结构化程度? 纯文本摘要最简单,但后续 sub-LLM 解析成本高。建议用 JSON Schema 约束——每个章节提取固定字段(主题、关键实体、数值结论、与前文的矛盾点),这样后续读取只需少量 tokens 就能理解前序积累。

何时停止递归? 两类终止条件:一是所有章节已处理完毕,进入汇总轮;二是 Agent 在某轮判断"当前记忆已足够回答用户问题",提前终止。后者需要你在提示词中明确判断标准。

成本控制。 递归意味着多轮 sub-LLM 调用,tokens 总消耗可能达到文档长度的 2-3 倍(每片原文 + 记忆摘要重复进入)。对于成本敏感场景,可以在中间轮次使用更小/更便宜的模型做提取,最终汇总轮次用强模型做综合——这就是原文提到的 "sub-LLM" 策略的精髓。

上手清单

  1. 确认文档格式:纯文本最简单;PDF/Word 需要先在 Code Interpreter 中用 Python 库(pdfplumberpython-docx)提取文本。
  2. 估算分片数量:文档 tokens 数 ÷ 目标片段大小,得到递归轮次上限,据此预估成本。
  3. 设计记忆 Schema:至少包含 chapters_processed(进度追踪)、findings(结构化提取)、cross_references(跨章节关联)三个顶层字段。
  4. 选择模型组合:提取轮用轻量模型(如 Haiku),汇总轮用强模型(如 Sonnet/Opus)。
  5. 设置中断恢复:每轮结束前必须 save_memory,确保任意轮次失败后可从断点续跑。
  6. 验证安全边界:Code Interpreter 沙箱已隔离网络和系统资源,但仍需检查文档中是否含敏感数据,确认符合合规要求后再上传。

上下文窗口的物理限制不会消失,但 RLM 模式把"一次塞完"的思路换成了"逐步消化、持久记忆、递归汇总"——用工程结构弥补模型能力的边界。Bedrock AgentCore Code Interpreter 提供了让这种结构落地的执行环境,Strands Agents SDK 让编排逻辑自然表达。下次面对一份超出窗口的文档,不用再截断或分片丢细节,试试让 Agent 自己递归地读完它。


相关推荐