2026/8/30 2:29:08

阿里Scroll:让大模型自主管理上下文的上下文引擎

阿里Scroll:让大模型自主管理上下文的上下文引擎 初次接触阿里 Scroll这个概念时我心里冒出的第一个问题是模型写代码这件事本身已经很复杂了为什么还要让模型去管理自己的上下文直到我在一个多文件、多轮迭代的实际项目里反复遇到模型写到后面已经把前面定义的函数忘光了的尴尬场景才意识到对长任务的模型来说上下文不是越堆越多越好而是需要像人整理工作台一样随时把该收的收起来、该拿的拿到手边。而 Scroll 正是阿里通义实验室开源的一个上下文引擎它把上下文管理这件事从外部脚本和人工裁剪交给了模型自己。这篇文章我会从背景、原理、环境搭建、代码实战到排错建议完整梳理一遍适合正在做 Agent 开发、长对话应用或代码生成工具的开发者参考。1. 背景为什么大模型需要上下文管理1.1 上下文窗口是模型的第一道瓶颈Transformer 架构的注意力机制让模型能够捕捉长距离依赖但代价是计算复杂度随序列长度呈平方级增长。这也是为什么今天的主流大模型虽然有 128K、200K 甚至更大的上下文窗口实际使用时却很少真的把所有内容都塞进去。更现实的问题是内容一多模型对早期信息的关注度会下降。你在 20K 上下文里塞了 15 份文件模型到后面可能连第一份文件的核心字段都记不清楚不是窗口放不下而是注意力被稀释了。1.2 长任务中的典型痛点以让模型写代码为例一个稍微正式一点的任务往往包含需求文档说明要做什么。已有项目的目录结构和关键代码。多轮的修改记录第一轮实现了登录第二轮改了数据库连接第三轮加了缓存。运行报错信息和修复方案。这些内容加在一起很容易超过模型的有效处理范围。最常见的做法有两种第一种是滑动窗口只保留最近几轮对话。它的缺点是早期定下的需求和技术约束会被无差别丢掉模型可能会在后面的轮次里写出和最初设计完全冲突的代码。第二种是人工或脚本定期做摘要把历史对话压缩成一段总结。这种方式在任务简单时还算能用但摘要由外部决定模型没有参与什么该保留、什么可以丢的判断信息损失往往比较大。1.3 从外部裁剪到模型自主管理Scroll 的思路刚好相反让模型自己决定上下文的组织方式。它把每个上下文块看作一个可以卷起来的卷轴。暂时用不到的内容可以先 Roll 起来只留下摘要或关键标签等需要修改或者深入阅读时再把这个块 Unroll 展开。这个决策过程由模型通过工具调用来完成而不是写死在代码里。这种思路在 Agent 场景里尤其有价值。Agent 执行多步任务时需要同时记住目标、当前状态、已完成动作和下一步计划。如果能让 Agent 自己维护一张工作台那它处理长任务的能力会明显提升。这也是上下文工程Context Engineering这个方向的核心理念与其优化模型去适应所有上下文不如设计一套机制让上下文本身变得可控、可查、可回收。2. 认识 Scroll定位与核心概念2.1 Scroll 是什么Scroll 是阿里通义实验室开源的一个上下文引擎Context Engine目标是为大语言模型提供独立的上下文管理能力。它不是一个具体的模型而是一套中间层基础设施。你可以把它理解成模型的外部硬盘加上文件管理系统。模型原本的上下文窗口是内存内存有限程序大了就装不下。Scroll 把上下文落到更持久、结构化的存储里并提供了按需读取、压缩、组织和恢复的能力。模型不再需要把所有内容一次性装进内存而是只在需要的时候加载相关片段。2.2 核心概念Scroll 里有几个关键名词理解它们就理解了整个框架Context Roller上下文管理的最小单元一个 Roller 就是一段上下文及其元数据标签、摘要、状态等的组合。Roll把某个上下文块压缩并收起来。压缩后保留摘要、标签或关键信息减小占用空间。Unroll把一个已收起的上下文块展开恢复到完整的原始内容供模型详细阅读。Context Tree上下文树上下文的组织形态一个任务下可以有多个节点节点之间保存父子关系形成一棵树。例如一个代码任务下挂着需求文档接口定义已完成文件待办清单等子节点。用一张简单的图来理解┌─────────────────────────────────┐ │ 当前上下文窗口 │ │ ┌───────────────────────────┐ │ │ │ main.py 展开 │ │ │ │ utils.py 卷起 │ │ │ │ 需求文档摘要 卷起 │ │ │ │ 运行日志 卷起 │ │ │ └───────────────────────────┘ │ └─────────────────────────────────┘模型在生成代码时可以随时调用 Scroll 提供的接口把不再需要的文件 Roll 起来或者把即将修改的文件 Unroll 出来。2.3 与 RAG、Memory 的区别很多初学者会把 Scroll 和检索增强生成RAG、记忆框架Memory混在一起。其实它们的定位完全不同。方案核心思想适合场景典型问题RAG从外部知识库检索相关片段拼到提示词里知识问答、文档问答检索质量受切分和向量化影响较大Memory 框架把跨会话的用户偏好和历史信息保存下来长期记忆、用户画像更多面向过去对当前任务的上下文组织帮助有限Scroll允许模型在单任务内自主 Roll/Unroll 上下文长对话、多文件代码、Agent 多步任务需要模型支持工具调用且任务本身要有结构化上下文简单说RAG 解决的是找外部知识Memory 解决的是记住过去Scroll 解决的是当前任务怎么组织、怎么取舍、怎么恢复。3. 环境准备与安装3.1 运行环境Scroll 以 Python SDK 的形式提供服务同时也包含独立的服务端。本文重点讲解 SDK 的使用方式。建议环境如下Python 3.9 或更高版本。一个支持工具调用/函数调用的模型 API。示例中使用阿里云百炼平台的通义千问兼容接口。pip 包管理器。3.2 安装 SDK安装命令如下pip install scroll-sdk如果你需要和 LangChain 一起使用可以同时安装 LangChain 相关依赖pip install langchain langchain-community这里需要特别说明Scroll 还处于快速迭代阶段不同版本的 API 命名可能略有差异。本文示例展示的是核心使用思路具体方法名和参数建议以官方最新文档为准。如果安装时找不到scroll-sdk可以直接从 GitHub 拉取源码按 README 安装思路都是通用的。3.3 获取模型 API KeyScroll 本身不提供大模型能力它需要调用一个 LLM 来完成 Roll、Unroll 时的摘要生成和工具调用决策。我这里以通义千问的 DashScope 兼容接口为例。在阿里云百炼平台创建 API Key 后可以在代码里这样配置export DASHSCOPE_API_KEY你的API Key3.4 项目结构为了方便后续实战建议按下面结构组织代码scroll-demo/ ├── main.py # 主入口 ├── context_demo.py # 上下文管理演示 ├── langchain_demo.py # LangChain 集成演示 └── requirements.txt # 依赖文件4. 核心原理解读模型如何管理上下文4.1 上下文树的设计逻辑Scroll 用一个树状结构来组织上下文而不是简单的列表。原因在于真实任务天然具有层级一个项目下面有需求、设计、代码、测试代码下面又有不同模块模块下面还有具体文件。树状结构有几个优势层级清晰模型可以根据任务目标只展开某个分支下的内容。支持局部压缩同一棵树上一部分节点可以 Roll 起来另一部分保持展开。便于追踪变更新增一个文件时在对应父节点下挂一个子节点不会影响其他上下文。4.2 Roll 和 Unroll 的具体含义Roll 并不是简单地把文本删掉而是做一次信息压缩。一个典型的 Roll 过程大致是模型或开发者选中某个上下文节点。Scroll 调用 LLM把该节点的完整内容总结成一段摘要同时保留标签、文件名、更新时间等元数据。摘要写回节点原始内容进入持久化存储。上下文窗口中只保留摘要和标签。Unroll 则是逆过程模型根据摘要或标签判断需要查看完整内容。Scroll 从持久化存储中取出原始内容。完整内容重新放回上下文窗口。这样做的好处是模型始终保留对有哪些信息的感知只是暂时不读全文。等需要时再展开不会像滑动窗口那样直接把信息忘掉。4.3 模型通过什么方式管理上下文Scroll 的核心设计是让模型自己触发 Roll 和 Unroll。实现方式是在系统提示词中注入一组工具调用说明或通过函数调用Function Calling机制暴露以下操作context.create创建一个新的上下文树。context.add在某个节点下添加内容。context.roll卷起指定节点。context.unroll展开指定节点。context.query查看当前树的结构和节点摘要。模型在生成本轮回复之前可以按需调用这些操作。例如当发现接下来的任务不再需要某个已经完成的文件时模型会调用context.roll。当需要读取详细需求时模型会调用context.unroll。这样一来上下文的长短就不再是静态的而是随着任务推进动态变化。模型在每一轮都能看到被压缩后的全貌和展开后的细节既有全局视角又有局部精度。4.4 压缩策略不是只有摘要摘要只是 Roll 的一种实现方式。Scroll 在底层还支持向量化存储、结构化记录等方式。例如对于一个代码文件Roll 时不仅保存摘要还可以保存文件依赖了哪些模块。导出了哪些函数和类。当前编译/运行状态。最近一次修改记录。这些结构化信息比纯文本摘要更适合模型在需要时做局部恢复。你可以把 Roll 理解成把文件从正文模式切换成卡片模式卡片上有文件名、标签、摘要和关键接口信息。这比直接丢原文更省空间也比只留一句话摘要更有用。5. 实战用 Scroll 让模型自主管理代码开发上下文下面我们用一个完整的场景来演示 Scroll 的用法。5.1 场景设计假设我们要让模型开发一个小型 Python CLI 工具功能是读取 CSV 文件并生成统计报告。项目包含三个文件main.py命令行入口。processor.py数据处理逻辑。config.py配置文件读取。任务要求模型分多轮完成先实现 CSV 读取再实现统计逻辑最后处理命令行参数。由于涉及多个文件和反复修改这是一个非常适合演示上下文管理的场景。5.2 初始化 Scroll 客户端首先创建一个main.py# 文件路径scroll-demo/main.py from scroll import Scroll # 初始化 Scroll 客户端 scroll Scroll( api_key你的API Key, # 使用 DashScope 兼容 OpenAI 的接口地址 base_urlhttps://dashscope.aliyuncs.com/compatible-mode/v1, modelqwen-plus ) print(Scroll 客户端初始化完成) print(当前配置模型qwen-plus)这段代码做了三件事创建Scroll实例负责与上下文引擎和 LLM 通信。指定模型接口地址这里用的是通义千问的兼容模式。打印基础信息确认初始化成功。5.3 创建上下文树一个代码任务开始前先创建一棵上下文树# 创建上下文树 ctx scroll.context.create( nameCSV 统计工具开发, description读取 CSV 文件并生成统计报告包含数据清洗、统计、输出三个模块 ) print(f上下文树已创建ID{ctx.id})上下文树创建后所有后续内容都挂在这棵树上。这样模型每次和 Scroll 交互都能明确知道当前属于哪个任务。5.4 添加需求与文件节点接下来把需求和已产生的代码片段挂到树上# 添加需求文档节点 scroll.context.add( parentctx.id, name需求文档, content 实现一个命令行工具功能要求 1. 支持 --input 参数指定 CSV 文件路径。 2. 统计每列的非空值数量、均值、最大值、最小值。 3. 支持 --output 参数导出报告为 JSON 文件。 , labels[需求, CLI, CSV] ) # 添加 config.py 代码节点 scroll.context.add( parentctx.id, nameconfig.py, content import argparse def parse_args(): parser argparse.ArgumentParser(descriptionCSV 统计工具) parser.add_argument(--input, requiredTrue, help输入 CSV 路径) parser.add_argument(--output, defaultreport.json, help输出 JSON 路径) return parser.parse_args() , labels[代码, 参数解析] ) # 添加 processor.py 代码节点 scroll.context.add( parentctx.id, nameprocessor.py, content import csv from collections import defaultdict def load_csv(path): with open(path, r, encodingutf-8) as f: reader csv.DictReader(f) return list(reader) def compute_stats(rows): stats {} for col in rows[0].keys(): values [float(r[col]) for r in rows if r[col] ! ] stats[col] { count: len(values), mean: sum(values) / len(values), max: max(values), min: min(values) } return stats , labels[代码, 数据处理] )这里的关键点是每个节点都带了labels。标签在 Roll 之后特别有用模型即使看不到完整内容也能通过标签判断这个节点和当前要做的事有没有关系。5.5 多轮迭代中让模型 Roll / Unroll现在模拟一次模型生成过程。假设模型第一轮已经完成了config.py和processor.py接下来要写main.py。此时两个已完成文件对当前步骤来说不是最关键的模型可以选择暂时 Roll 起来# 模型选择把已完成的 config.py 和 processor.py 卷起 scroll.context.roll(node_idconfig.py节点ID) scroll.context.roll(node_idprocessor.py节点ID) # 查询当前上下文树确认状态 tree scroll.context.query(ctx.id) print(tree)Roll 之后上下文窗口里这两个节点只剩下摘要和标签。例如节点config.py 状态rolled 摘要实现命令行参数解析支持 --input 和 --output。 标签代码, 参数解析 节点processor.py 状态rolled 摘要实现 CSV 读取与统计计算包含 load_csv 和 compute_stats 函数。 标签代码, 数据处理这样做的意义在于模型写main.py时不需要把processor.py的完整实现一直放在窗口里只要知道它提供了load_csv和compute_stats两个函数就够了。窗口空间被释放出来留给新代码。当后续需要修改processor.py时模型再把它展开# 模型判断需要修改 processor.py执行 Unroll scroll.context.unroll(node_idprocessor.py节点ID) full_content scroll.context.get(processor.py节点ID) print(full_content)这个过程完全由模型在推理过程中触发。开发者的工作只是创建上下文树和初始节点剩下的什么时候卷、什么时候展由模型根据任务进展自主决定。5.6 结合 run 方法一次性完成完整任务上面的分步调用主要是为了展示 API。真实场景里更推荐的方式是把决策完全交给模型通过run方法直接交互# 文件路径scroll-demo/context_demo.py from scroll import Scroll scroll Scroll( api_key你的API Key, base_urlhttps://dashscope.aliyuncs.com/compatible-mode/v1, modelqwen-plus ) # 创建上下文树 ctx scroll.context.create( nameCSV 统计工具开发, description读取 CSV 文件并生成统计报告 ) # 添加初始上下文 scroll.context.add( parentctx.id, name需求文档, content实现命令行工具支持 --input 读取 CSV统计每列指标--output 导出 JSON。, labels[需求] ) # 多轮交互 queries [ 请先写出 config.py 和 processor.py并确保参数解析逻辑完整。, 接下来写 main.py注意调用 processor 中的 load_csv 和 compute_stats。, 我现在想给 processor.py 增加一个中位数统计请找到该文件并修改。 ] for query in queries: response scroll.run( context_idctx.id, user_inputquery ) print(用户输入, query) print(模型回复, response.answer) print(上下文操作, response.operations) print(- * 60)scroll.run会做几件事把用户输入追加到当前上下文树。让模型在生成回答前按需调用 Roll/Unroll/Add 等操作。返回模型最终回答和本次执行过的上下文操作记录。通过response.operations你可以很直观地看到模型在这一轮里的上下文管理行为。比如第三轮要求修改processor.py时操作记录里大概率会出现一条unroll操作表示模型自主决定把该文件展开后再修改。5.7 与 LangChain Agent 集成如果你已经在用 LangChain 构建 Agent可以把 Scroll 封装成一个工具让 Agent 在任务执行过程中调用。# 文件路径scroll-demo/langchain_demo.py from langchain.agents import AgentExecutor, create_tool_calling_agent from langchain_community.chat_models import ChatOpenAI from langchain_core.prompts import ChatPromptTemplate from scroll import Scroll from scroll.langchain import ScrollContextTool # 初始化 Scroll scroll Scroll( api_key你的API Key, base_urlhttps://dashscope.aliyuncs.com/compatible-mode/v1, modelqwen-plus ) # 创建上下文树 ctx scroll.context.create(name代码开发任务) # 把 Scroll 管理能力包装成 Tool scroll_tool ScrollContextTool( scrollscroll, context_idctx.id, description管理当前代码开发任务的上下文支持创建节点、添加内容、卷起和展开上下文。 ) # 创建 LLM llm ChatOpenAI( api_key你的API Key, base_urlhttps://dashscope.aliyuncs.com/compatible-mode/v1, modelqwen-plus ) # 创建 Agent prompt ChatPromptTemplate.from_messages([ (system, 你是一个代码开发助手需要根据任务进度自主管理上下文。), (human, {input}), (placeholder, {agent_scratchpad}) ]) agent create_tool_calling_agent(llm, [scroll_tool], prompt) agent_executor AgentExecutor(agentagent, tools[scroll_tool], verboseTrue) # 执行任务 result agent_executor.invoke({ input: 先读取需求文档再看一下代码目录下有哪几个文件然后开始实现登录模块。 }) print(result[output])在这个集成里Scroll 工具是 Agent 的一只手Agent 在规划任务时如果发现上下文过长或缺少信息可以主动调用工具去 Roll、Unroll 或添加节点。这比写死提示词要灵活得多。5.8 结果说明运行上述代码后你会看到一个比较明显的现象随着交互轮次增加Scroll 管理的上下文树会越来越丰富但模型每一轮实际看到的完整内容并不会无限膨胀。它看到的可能是这样的结构上下文树CSV 统计工具开发 ├── 需求文档rolled摘要CLI工具需求 ├── 已完成文件 │ ├── config.pyrolled摘要参数解析 │ └── processor.pyrolled摘要CSV读取、统计 └── 当前任务 └── main.pyunrolled完整内容模型既能快速了解全局又能聚焦当前任务这就是 Scroll 带来的核心价值。6. 常见问题与排查思路6.1 问题一模型不会主动调用 Roll / Unroll现象模型在长任务中上下文越积越多没有出现预期中的管理行为。可能原因模型版本不支持工具调用。系统提示词里没有对模型进行充分引导。上下文还没有达到模型认为需要管理的阈值。排查思路确认使用的模型支持 Function Calling。在系统提示词中加入明确要求例如当某个文件暂时不需要使用时调用 roll 操作以释放上下文空间。检查scroll.run返回的operations确认模型是否真的没有调用工具。6.2 问题二Roll 之后重要信息丢失现象Roll 之后模型回答问题时缺少了被卷起内容中的关键细节。可能原因摘要质量不高漏掉了关键参数。标签设置不够具体。模型后续需要完整内容时没有正确触发 Unroll。排查思路查看 Roll 时生成的摘要是否完整覆盖原始内容的核心要素。如果摘要质量差可以在context.add时补充更细的标签和描述。调整系统提示词提醒模型当需要修改某个节点时必须先 unroll 该节点。6.3 问题三接口报 401 或 403现象调用模型接口时返回认证错误。可能原因API Key 设置错误。账号没有开通对应模型的访问权限。接口地址不匹配。排查思路检查环境变量或代码中的 API Key 是否正确。确认模型名称如qwen-plus在当前平台可用。直接使用 curl 调用模型接口排除 SDK 配置问题。问题现象常见原因解决思路模型不会主动管理上下文模型不支持工具调用或提示词引导不足升级模型版本强化系统提示词Roll 后信息丢失摘要质量差、标签不完整增加标签优化摘要生成策略认证报错API Key 错误或接口地址不正确检查密钥和 base_url用 curl 验证上下文树越来越乱节点命名不规范、缺少父节点规划设计清晰的树层级统一命名规范成本偏高频繁 Unroll 导致 token 消耗大合理设置 Roll 粒度避免过度展开7. 最佳实践与工程建议7.1 上下文树要有清晰的分层设计不要把所有内容都挂到根节点下面。建议按照任务 - 阶段 - 文件/主题的层级来组织根节点整个开发任务。二级节点需求、设计、代码、测试、日志。三级节点具体文件或具体子任务。层级清晰后模型 Roll 时可以按分支批量处理而不是逐个文件操作。7.2 合理设置 Roll 粒度Roll 粒度过小比如每段代码都拆成节点模型管理成本很高粒度过大比如整个项目作为一个节点Roll 了等于没 Roll。我的经验是以文件或模块作为 Roll 的最小单位。一个文件通常几百行展开时占用的上下文可控Roll 起来又能释放明显空间。7.3 在系统提示词里显式说明管理策略模型默认不会主动想到管理上下文至少在早期版本里需要引导。建议在系统提示词中加入类似下面的描述你是一个代码开发助手。在完成任务时你需要通过上下文管理工具来维持工作台的整洁。 规则 1. 当某个文件已经完全实现且短时间内不会再修改时使用 roll 操作收起它。 2. 当需要修改某个已经收起的文件时先使用 unroll 操作展开它。 3. 每次执行完重要步骤后将当前进度摘要记录到上下文中。这样模型在多轮迭代中会更有意识地使用 Scroll 提供的能力。7.4 结合 RAG 和长期记忆Scroll 解决的是当前任务上下文的问题它不能替代 RAG 和长期记忆。跨会话的用户偏好、历史项目经验仍然需要 Memory 类框架。大量外部文档的知识检索仍然需要 RAG。Scroll 负责的是单个长任务内部的动态上下文组织。生产环境建议三者结合Memory 保存持久信息RAG 检索外部知识Scroll 管理当前任务的即时上下文。7.5 关注安全和权限在团队协作或企业环境中使用 Scroll有几个安全要点最小权限原则给模型授予的上下文操作权限限定在当前任务范围内不要让它可以读取无关项目的数据。敏感信息保护Roll 只是压缩不是删除。被卷起的原始内容仍然存储在持久化层要对这部分存储做好访问控制。审计日志记录每次 Roll/Unroll 的操作日志方便追溯模型在推理过程中访问了哪些敏感内容。7.6 控制成本和性能Roll 和 Unroll 都会调用 LLM 生成摘要或执行决策这对成本和延迟有影响。建议不要在每个对话轮次都强制触发 Roll。设置触发条件例如上下文节点数量超过 10 个或开放文件超过 5 个时才进行自动整理。摘要模型可以使用轻量级模型例如qwen-turbo降低摘要成本。8. 总结与学习路径通过这篇文章我们完整梳理了阿里 Scroll 的核心概念和使用方法。你至少应该掌握以下几个关键点Scroll 的定位让模型自己管理上下文的上下文引擎而不是又一个记忆库或检索工具。核心机制Context Roller 通过 Roll 和 Unroll 实现上下文的动态收起与展开上下文树负责组织复杂任务。使用方式通过 SDK 创建上下文树、添加节点并把管理操作开放给模型。典型场景多文件代码任务、长对话、Agent 多步执行。下一步我建议你按下面顺序继续深入先把本文的context_demo.py跑通观察多轮交互中operations的变化。尝试用 Scroll 管理一个真实的小项目至少包含 5 个文件体验需求 - 编码 - 修改 - 测试完整流程。如果你已经在开发 Agent把 Scroll 封装成 LangChain 工具结合工具调用观察 Agent 的上下文行为。阅读 Scroll 官方文档中关于服务端部署的部分了解如何把它独立部署成团队共享的上下文服务。实践时优先关注两个风险一是摘要质量Roll 之后的摘要直接决定了模型能否在需要时准确判断是否 Unroll二是权限管理持久化存储中的原始内容需要做好安全控制。写代码这件事模型的能力边界已经越来越宽真正决定长任务质量的往往是它能不能像人一样把工作台整理得井井有条。Scroll 提供了一条值得一试的路径。如果你在实操中遇到问题欢迎在评论区交流也建议把文章收藏备用。