Gliding Horse 工具结果压缩体系:如何用“指针”驯服上下文膨胀

📅 2026/6/29 18:26:20
Gliding Horse 工具结果压缩体系:如何用“指针”驯服上下文膨胀
本文深入解析 Gliding Horse流马Agent 操作系统的工具结果压缩体系。针对 AI Agent 执行长周期任务时上下文窗口易被工具调用结果撑爆的痛点流马设计了一套“指针摘要”的纵深防御式压缩方案。文章详细拆解了 ResultRouter 智能路由、ToolResultCompressor 安全网、ContextWindowManager 全局控制三层架构以及智能回收、流式/非流式路径统一等核心机制。通过将大块结果替换为轻量 IRI 引用并注册微工具该方案在降低 90% Token 消耗的同时实现了关键信息的 100% 可追溯是构建长周期、高可靠自主 Agent 的关键基础设施。关键词Gliding Horse流马Agent 操作系统工具结果压缩上下文窗口管理LLMToken 优化ResultRouterContextWindowManager智能回收IRI 引用微工具在 AI Agent 执行任务的过程中工具调用结果的体积往往是上下文的头号杀手。一个grep搜索可能返回上万字符的匹配列表一次bash命令可能输出几十 KB 的编译日志如果把这些结果原封不动地塞进 LLM 的上下文窗口不出几轮 Token 就会爆炸轻则成本飙升重则直接触发 API 限制。Gliding Horse流马作为面向长周期、多步执行的 Agent 操作系统设计了一套纵深防御式的工具结果压缩体系。它并非简单截断而是通过“指针 摘要”的模式将大块结果替换为轻量引用同时保留 LLM 随时通过微工具查询完整细节的能力。信息不丢失上下文不爆炸。一、三层压缩架构纵深防御流马的工具结果管理分为三个层次在结果注入上下文的不同阶段递进式压缩16KB: 原样IRI16~32KB: 截断micro-toolUnsupported markdown: blockquoteUnsupported markdown: blockquote安全网: 二次压缩保留最近4条中间摘要工具执行结果(可能数万字节)① ResultRouterroute_tool_result()注入 messages[]② ToolResultCompressorcompress_tool_messages()更新后的 messages[]③ ContextWindowManager消息数/Token 超限时最终上下文第一层 (ResultRouter)结果进入上下文之前根据大小和类型自动选择处理策略——小结果原样放行大结果截断或图谱化并注册微工具供 LLM 按需查询。第二层 (ToolResultCompressor)在上下文已有压力时对 message 列表中的旧工具结果做二次摘要压缩作为兜底安全网。第三层 (ContextWindowManager)当消息总数或估算 Token 超过硬上限时对整个消息序列进行结构化压缩保留最近关键信息中间段用摘要替代。三层相互配合既保证了单条结果不撑爆上下文又防止了多次小结果累积膨胀。二、第一层ResultRouter 的智能路由ResultRouter 是整个压缩体系的核心防线。它在工具结果返回后、注入 messages 前工作能够访问 L0 存储和 ToolExecutor拥有完整上下文。 16KB16KB ~ 32KBUnsupported markdown: blockquoteUnsupported markdown: blockquoteUnsupported markdown: blockquote原始工具结果结果大小?PassThrough原样 IRITruncatesmart_truncate micro-toolGraphify知识图谱化 micro-toolsSummarizetext_summary micro-tool注入上下文截断结果 IRI micro-tool图谱摘要 IRI micro-tools文本摘要 IRI micro-tool关键机制Micro-tool 模式任何被压缩或截断的结果系统都会自动注册一个专用微工具如read_full_result_{call_id}LLM 可以随时调用它来获取完整原始数据。信息零丢失。PassThrough 增强即使结果小于 16KB 原样放行只要超过 3KB系统也会预注册微工具。这为后续的“智能回收”埋下伏笔——当上下文压力增大时这些较大的 PassThrough 结果可以被替换为轻量引用而不丢失可回溯性。Graphify 图谱化对于大型 JSON 结构数据如 API 返回的复杂对象自动提取关键实体和关系存入知识图谱L0/L2LLM 拿到的是简洁的图谱摘要后续可通过 SPARQL 或微工具深入探索。下面是一个 Python 代码示例展示 ResultRouter 如何根据结果大小和类型选择不同的压缩策略from typing import Any, Optional import json class ResultRouter: 智能路由根据结果大小和类型选择压缩策略 def __init__(self, micro_tool_registry: dict): self.registry micro_tool_registry # 微工具注册表 def route_tool_result(self, call_id: str, result: Any) - dict: 路由工具结果返回注入上下文的压缩内容 raw json.dumps(result) if not isinstance(result, str) else result size len(raw.encode(utf-8)) # 策略 1小于 16KB —— 原样放行超过 3KB 预注册微工具 if size 16 * 1024: if size 3 * 1024: self._register_micro_tool(call_id, raw) return {content: raw, iri: firi://tool-result/{call_id}} # 策略 216KB ~ 32KB —— 截断 微工具 if size 32 * 1024: truncated self._smart_truncate(raw, max_bytes2048) self._register_micro_tool(call_id, raw) return {content: truncated, iri: firi://tool-result/{call_id}} # 策略 3大于 32KB —— 根据类型选择图谱化或摘要 if self._is_json(result): graph_summary self._graphify(result) # 提取实体关系图谱 self._register_micro_tool(call_id, raw) return {content: graph_summary, iri: firi://tool-result/{call_id}} else: summary self._summarize(raw, max_chars500) # 文本摘要 self._register_micro_tool(call_id, raw) return {content: summary, iri: firi://tool-result/{call_id}} def _smart_truncate(self, text: str, max_bytes: int) - str: 智能截断保留开头和结尾的关键信息 encoded text.encode(utf-8) if len(encoded) max_bytes: return text head encoded[:max_bytes // 2].decode(utf-8, errorsignore) tail encoded[-max_bytes // 2:].decode(utf-8, errorsignore) return f{head}\n...中间省略 {len(encoded) - max_bytes} 字节...\n{tail} def _is_json(self, result: Any) - bool: 判断结果是否为 JSON 结构数据 if isinstance(result, (dict, list)): return True if isinstance(result, str): try: json.loads(result) return True except (json.JSONDecodeError, ValueError): return False return False def _graphify(self, data: Any) - str: 将大型 JSON 图谱化为摘要示意实现 if isinstance(data, dict): keys list(data.keys())[:5] return f[图谱摘要] 包含 {len(data)} 个字段: {, .join(keys)}... if isinstance(data, list): return f[图谱摘要] 包含 {len(data)} 条记录首条字段: {list(data[0].keys()) if data else 空} return [图谱摘要] 非结构化数据 def _summarize(self, text: str, max_chars: int) - str: 文本摘要示意实现 return text[:max_chars] f\n...全文 {len(text)} 字符请调用微工具查看... def _register_micro_tool(self, call_id: str, full_result: str): 注册微工具供 LLM 按需查询完整结果 self.registry[call_id] { name: fread_full_result_{call_id}, description: f获取工具调用 {call_id} 的完整原始结果, handler: lambda: full_result } # 使用示例 router ResultRouter(micro_tool_registry{}) # 场景 1小结果 16KB—— 原样放行 small_result {status: ok, count: 42} print(router.route_tool_result(call_001, small_result)) # 输出: {content: {status: ok, count: 42}, iri: iri://tool-result/call_001} # 场景 2中等结果16KB ~ 32KB—— 截断 微工具 medium_result A * 20_000 # 约 20KB 文本 routed router.route_tool_result(call_002, medium_result) print(f截断后长度: {len(routed[content])} 字符) print(f微工具已注册: {call_002 in router.registry}) # 场景 3大型 JSON 32KB—— 图谱化 微工具 large_json {users: [{id: i, name: fuser_{i}} for i in range(1000)]} routed router.route_tool_result(call_003, large_json) print(f图谱摘要: {routed[content]}) # 场景 4大型文本 32KB—— 摘要 微工具 large_text B * 50_000 routed router.route_tool_result(call_004, large_text) print(f摘要长度: {len(routed[content])} 字符)代码要点说明route_tool_result是核心路由方法根据结果字节大小和类型分发到四种策略PassThrough、Truncate、Graphify、Summarize。任何被压缩的结果都会通过_register_micro_tool注册一个微工具LLM 可随时调用read_full_result_{call_id}获取完整原始数据实现信息零丢失。_smart_truncate采用“头尾保留”策略避免截断丢失关键上下文_graphify和_summarize为示意实现生产环境可接入 LLM 或知识图谱引擎。三、第二层ToolResultCompressor 安全网当上下文中的工具消息累积到一定数量默认 10 条时ToolResultCompressor会启动对最旧的工具结果执行二次压缩超过长度限制的仅保留前几行并附加“已压缩”标记。这一层是有损压缩的安全网主要覆盖那些未被第一层充分处理的小结果累积情况。在实践中由于第一层已将大结果截断到 2KB 左右第二层真正触发压缩的概率很低——但它提供了一个兜底保障。四、第三层ContextWindowManager 全局控制当前消息总数超过 30 条或估算总 Token 超过 16000 时ContextWindowManager介入保留最近 4 条消息包括 user/assistant/tool 配对原样不动。中间段消息用智能摘要替代提取每轮的关键动作、涉及 IRI、工具调用次数等信息生成结构化历史引用。确保不拆散消息对工具调用assistant role和工具结果tool role始终成对保留避免孤儿消息导致 API 报错。压缩后的历史引用示例[历史摘要] [轮1/PA] 制定分析计划 → iri://archive/task/xxx/turn_1 [轮2/DA] 搜索认证接口 (grep×3) → iri://archive/task/xxx/turn_2 [轮3/DA] 分析JWT流程 → iri://archive/task/xxx/turn_3 如需详细信息请使用 kg_search / knowledge_query 查询 IRI。LLM 可以清晰知道此前做过什么并随时通过 IRI 检索任意轮次的完整详情。五、智能回收两阶段压缩优化在第一层和第三层之间我们引入了一个智能回收环节形成完整的“准备—回收”闭环阶段一准备ResultRouter 在 PassThrough 分支中对大于 3KB 的结果预注册微工具。此时消息内容不变仍为全文但已具备“可回收”的条件。阶段二回收当ContextWindowManager或ToolResultCompressor触发压缩后系统扫描 messages 中的所有 tool 消息对于内容仍较大500 字节且已有对应微工具的结果将其替换为轻量引用[已压缩 10240 字节] 完整结果请调用 read_full_result_call_abc 工具 IRI: iri://tool-result/call_abc