《AgentScope 2.0实战指南》07 - 上下文压缩

简介: 《AgentScope 2.0实战指南》第7节详解上下文压缩:通过智能摘要替代冗余历史,在不丢失关键信息(如编号、要点)的前提下,动态“瘦身”长对话,确保始终守住模型窗口上限。支持自动触发、指令引导摘要、参数精细调控,是生产级长对话的必备防线。(239字)

《AgentScope 2.0实战指南》07 - 上下文压缩:让长对话始终待在模型窗口内

7.1 问题:上下文不是无限的

大模型都有上下文窗口上限(如 128K token)。长对话、多轮工具调用、大段检索结果,都会快速消耗窗口。

一旦超过窗口,轻则报错,重则模型「失忆」。超窗的典型症状:

  • 忘记任务目标;
  • 重复调用工具;
  • 前后矛盾。

AgentScope 2.0 提供两套解决方案:

  • 上下文压缩:把较早的消息汇总成结构化摘要,保留最近的重要消息——相当于给上下文「瘦身」;
  • 上下文卸载(Offload):把暂时用不到的上下文移到外部存储,需要时再取回——相当于给上下文「外接硬盘」。

两者可以配合使用。本节实战压缩,因为它是绝大多数长对话场景的第一道防线。

官方对压缩流程的描述如下(五步):

  1. 判断当前 token 用量是否超过阈值;
  2. 超过则从上下文中拆分出「可压缩的历史部分」与「保留的最近部分」;
  3. 调用 LLM 将历史部分压缩为结构化摘要;
  4. 用摘要消息替换掉历史消息;
  5. 继续正常推理。

as_compress.png

理解这套流程的关键是第 3 步:压缩不是简单截断,而是让模型「读一遍旧消息,写一份结构化摘要」。摘要会保留关键事实与决策,所以压缩后的模型依然「记得」旧信息——这一点稍后用实测验证。

7.2 参数:ContextConfig

所有开关都在 ContextConfig 里,四个参数决定了压缩的「何时、留多少、多细」:

参数 含义 本文演示值
trigger_ratio token 用量超过 trigger_ratio × context_size 时触发压缩 0.8
reserve_ratio 压缩后保留最近 reserve_ratio × context_size 的消息 0.1
tool_result_limit 单条工具结果超过该 token 数时截断 800
compression_fallback_to_truncation 压缩失败时是否退回「删除最旧消息」 True

as_compress_config_table.png

调参直觉:

  • trigger_ratio:太小会频繁压缩(费 token 且打断节奏),太大则容易撞窗;
  • reserve_ratio:太小会把最近对话也压掉(丢失关键细节),太大则腾不出空间。

生产环境常用组合是 trigger_ratio=0.7~0.8、reserve_ratio=0.1~0.3。

7.3 完整可运行源码

为了让压缩效果几轮对话内肉眼可见,示例把模型 context_size 故意调小到 3000(生产环境请用真实窗口,如 128000),然后连续投喂长消息,观察上下文长度「涨 → 触发 → 回落」:

# context_compression.py

"""第 7 节 · 上下文压缩:让长对话始终待在模型窗口内"""
import asyncio

from agentscope.agent import Agent, ContextConfig
from agentscope.credential import OpenAICredential
from agentscope.message import UserMsg
from agentscope.model import OpenAIChatModel
from agentscope.tool import Toolkit

from config import API_KEY, BASE_URL, CHAT_MODEL

SMALL_CONTEXT = 3000  # 故意调小窗口,几轮即可触发压缩(生产用真实窗口)

def long_message(index: int) -> str:
    """生成一段较长、带编号的话题内容,便于观察摘要保留了哪些信息。"""
    return (
        "正在讨论的项目材料清单:编号 {i} 包含需求分析、架构设计、接口契约、"
        "测试用例、部署方案与运维手册六个部分,其中接口契约需要团队评审,"
        "部署方案依赖测试环境完成验收。请记住这条材料的要点。"
    ).format(i=index)

async def main() -> None:
    credential = OpenAICredential(api_key=API_KEY, base_url=BASE_URL)
    model = OpenAIChatModel(
        credential=credential,
        model=CHAT_MODEL,
        stream=True,
        context_size=SMALL_CONTEXT,  # 压缩阈值以此为基数

    )

    agent = Agent(
        name="compress-demo",
        system_prompt="你是一个耐心的助手,请逐条记住用户给出的材料要点并简单回应。",
        model=model,
        toolkit=Toolkit(),
        context_config=ContextConfig(
            trigger_ratio=0.8,       # 用量 > 80% × 3000 = 2400 token 时触发

            reserve_ratio=0.1,       # 压缩后保留最近 10% 的消息

            tool_result_limit=800,
            compression_fallback_to_truncation=True,
        ),
    )

    print(f"模型 context_size = {SMALL_CONTEXT},压缩阈值 ≈ {int(SMALL_CONTEXT * 0.8)} token\n")
    for i in range(1, 13):
        await agent.reply(UserMsg(name="user", content=long_message(i)))
        print(f"第 {i:>2} 轮后:上下文共 {len(agent.state.context):>3} 条消息")

    # 手动压缩:注入指令引导摘要重点(例如要求保留编号与材料名)

    from agentscope.message import HintBlock
    await agent.compress_context(
        instructions=HintBlock(hint="压缩时务必保留每条材料的编号与名称,便于后续按编号检索。"),
    )
    print(f"手动压缩后:上下文共 {len(agent.state.context)} 条消息")

    # 压缩后继续对话,验证摘要是否承载了旧信息

    reply = await agent.reply(
        UserMsg(name="user", content="请根据你记住的内容,说出编号 3 的材料有哪些部分。")
    )
    text = "".join(b.text for b in reply.content if b.type == "text")
    print("\n[压缩后回答] ", text)

if __name__ == "__main__":
    asyncio.run(main())

运行结果(终端实跑输出):

run_context_compression.png

代码里有两点要注意:

  • context_size 放在模型上:压缩阈值 = trigger_ratio × context_size,所以 context_size 必须设对;
  • compress_context(instructions=HintBlock(...)):手动压缩可以注入指令,引导摘要保留哪些信息——「压缩时务必保留编号与名称」这种指令,能让摘要更贴合你的后续查询需求。这是自动压缩没有的精细控制。

7.4 实测输出

自动压缩全程(节选关键行):

模型 context_size = 3000,压缩阈值 ≈ 2400 token

第  1 轮后:上下文共   2 条消息
第  2 轮后:上下文共   4 条消息
第  3 轮后:上下文共   6 条消息
[INFO] Current token count 2717 exceeds the threshold 2400, activating compression.
[INFO] The context compression finished.
第  4 轮后:上下文共   3 条消息   ← 6 → 3,历史被压缩成摘要
第  5 轮后:上下文共   5 条消息
...
第 12 轮后:上下文共   1 条消息

手动压缩后:上下文共 1 条消息

[压缩后回答]  编号 3 的材料包含以下 6 个标准部分:
需求分析、架构设计、接口契约、测试用例、部署计划、运维手册。

三个观察点:

  1. 触发是自动的:第 3 轮 token 用量 2717 > 阈值 2400,框架自动启动压缩,无需任何人工干预;
  2. 长度确实回落:6 条 → 3 条,多次压缩后甚至压到 1 条——窗口被持续释放;
  3. 信息没丢:最后一问「编号 3 的材料有哪些部分」,Agent 准确答出六个部分——这条信息早在第 3 轮就被压缩进摘要了,但模型依然能回答。

WARNING 说明:当消息增长过快、预留上下文不足时,框架会打印「maybe failed due to insufficient reserved context」并自动退回截断策略(删除最旧消息)。生产环境调参思路:context_size 设真实值,trigger_ratio 0.6~0.8,reserve_ratio 0.1~0.3,优先保证最近对话完整。

7.5 什么时候用 Offload

如果任务特别长、还需要随时翻旧账(比如几万行的数据清洗任务),压缩可能不够——摘要会丢细节。这时配 Offload:把完整旧消息卸载到外部存储,按需检索取回。

选型规则:

  • 普通长对话:用压缩;
  • 超长且高频翻旧账:用 Offload;
  • 两者不冲突,可以叠加。

7.6 压缩的成本与收益

压缩是否费 token,要算两笔账:

  • 压缩本身的成本:每次压缩要调用一次 LLM 读历史、写摘要,大约消耗「历史消息 token 数」的一次输出级开销;
  • 压缩省下的成本:之后每一轮推理都少携带那批历史消息,省下的 token 是线性持续的。

  • 20 轮以上的长对话:压缩几乎总是划算;

  • 3~5 轮的短对话:不需要压缩。

所以 trigger_ratio 设 0.8(只用满 80% 才压缩)正好兼顾两头:大部分短任务根本不会触发,只有真正的长对话才付出压缩成本。

7.7 调参速查表

场景 context_size trigger_ratio reserve_ratio
教学/演示(本文) 3000 0.8 0.1
通用问答助手 128000 0.8 0.2
长文档处理 128000 0.6 0.3
工具密集任务 128000 0.7 0.25

原则:工具结果多、任务碎,就多留 reserve_ratio;纯对话场景可以压得狠一点。

7.8 压缩对工具调用链的影响

还有一点:压缩的对象包括工具调用的历史。

一个跑了 30 轮工具调用的任务,前 20 轮的「调用参数 + 返回结果」都会在压缩时被摘要化。这通常是好事(省 token),但如果业务需要「模型精确回忆起第 5 轮某个工具的完整输出」,摘要可能丢细节。

应对方案:

  • 关键中间结果主动写文件,不依赖上下文保存;
  • 对「必须保留完整执行记录」的任务,用第 7.5 节提到的 Offload 而非压缩;
  • 用 tool_result_limit 从源头控制单条工具结果体积,降低压缩时的压力。

上下文是易失的,存成文件才是持久的。把「必须记住的东西」尽早变成文件或记忆。

第 8 节 ReMe 的「记忆持久化」与第 9 节 RAG 的「资料入库」都是这一点的工程化实现——压缩管窗口,记忆管跨会话,检索管私有知识,三层各司其职、互不冲突。

源码地址:https://github.com/LarryLi93/agentscope2

相关文章
|
2月前
|
存储 Shell API
《AgentScope 2.0实战指南》02 - 安装 AgentScope 2.0
《AgentScope 2.0实战指南》第2章详解安装全流程:要求Python≥3.11,推荐虚拟环境;支持`pip install "agentscope[rag,reme,vdb-qdrant]"`按需安装;提供清华镜像加速、uv/conda多方案及常见问题排查三步法,确保核心模块一键导入成功。(239字)
579 0
|
2月前
|
中间件 数据安全/隐私保护 人工智能
《AgentScope 2.0实战指南》03 - 接入AI模型
《AgentScope 2.0实战指南》第3节详解如何接入AI模型:以火山方舟为例,演示Credential(密钥+base_url)与Model(调用协议)解耦配置,支持OpenAI兼容服务;涵盖流式/非流式调用、参数配置及多厂商切换,代码简洁、可扩展性强。
353 0
《AgentScope 2.0实战指南》03 - 接入AI模型
|
2月前
|
前端开发 安全 中间件
《AgentScope 2.0实战指南》01 - 国内项目数最多的Agent框架
《AgentScope 2.0实战指南》是面向国产主流Agent框架的入门到生产落地教程,聚焦国内项目数最多的AgentScope 2.0——阿里通义实验室开源的生产级多智能体平台。全系列11节实战,从模型接入、工具调用、RAG知识库、跨会话长期记忆(ReMe)到带Web界面的完整问答助手,覆盖安全、高效、灵活、完备四大核心能力,助你零基础构建企业级智能体应用。
1323 1
|
2月前
|
存储 运维 中间件
《AgentScope 2.0实战指南》08 - 长期记忆(ReMe 实现):跨会话记住用户
《AgentScope 2.0实战指南》第8节详解ReMe长期记忆:以纯Markdown文件实现零运维、跨会话记忆。自动抽取偏好/信息,支持语义检索与人工可读可编辑,无需数据库,`pip install`即用,兼顾轻量部署与生产可审计性。(239字)
314 0
|
2月前
|
人工智能 开发者 索引
《AgentScope 2.0实战指南》06 - 创建「小红书爆款标题生成」技能
《AgentScope 2.0实战指南》第6章详解「技能(Skill)」机制:无需代码,仅用Markdown定义可检索、可复用、可插拔的能力。以「小红书爆款标题生成」为例,通过SKILL.md规范流程、约束输出、提供示例,实现高质量结构化生成。技能与工具协同,推动AI应用工程化升级。(239字)
228 0
|
2月前
|
人工智能 安全 前端开发
《AgentScope 2.0实战指南》04 - 使用内置文件工具
AgentScope 2.0 内置安全文件工具(Read/Write/Edit/Grep/Glob),支持异步调用与智能体自主操作。强制“先读后写”、目录白名单权限控制,兼顾效率与安全,助AI真正可靠地读写、编辑、检索文件。
305 0
|
2月前
|
JSON 人工智能 安全
《AgentScope 2.0实战指南》05 - 创建 AnySearch 搜索工具
《AgentScope 2.0实战指南》第5节详解如何集成AnySearch联网搜索工具:解决模型知识滞后问题,支持实时热点、政策、价格等动态信息检索。提供FunctionTool快速封装与ToolBase生产级定制两种方式,并涵盖权限控制、并发安全、错误处理及工程化实践,助Agent从“离线”跃升为“实时智能助手”。
272 0
|
2月前
|
存储 自然语言处理 中间件
《AgentScope 2.0实战指南》09 - RAG 检索增强生成
《AgentScope 2.0实战指南》第9章详解RAG服务化:将私有文档(PDF/Word/Markdown等)经解析、切块、向量化后构建可检索知识库,通过RAGMiddleware无缝接入Agent,实现“所问即所得、答案可溯源”的生产级增强问答。代码开箱即用,支持多租户与动态更新。(239字)
340 0
|
中间件 决策智能 Python
《AgentScope 2.0实战指南》10 - 总结、排错与学习路线
《AgentScope 2.0实战指南》第10章系统总结框架核心能力(模型接入、工具、技能、记忆、RAG等),梳理高频排错方案,提供渐进式学习路线与生产部署 checklist,并指引多智能体进阶方向,助开发者高效构建可靠AI助手。(239字)
273 0
《AgentScope 2.0实战指南》10 - 总结、排错与学习路线
|
1月前
|
前端开发 安全 中间件
《AgentScope 2.0实战指南》11 - 完整实战:RAG 问答助手(带 UI 界面)
《AgentScope 2.0实战指南》第11节打造了一个结构完整、可运行的RAG问答助手Web应用:FastAPI后端+原生HTML/CSS/JS前端,集成RAG检索、ReMe跨会话长期记忆与AnySearch联网搜索,支持文档上传、流式响应、多会话隔离及Markdown安全渲染,代码开源,直面生产落地差距。
266 0

热门文章

最新文章