当前位置: 首页 > news >正文

龙虾-OpenClaw一文详细了解-手搓OpenClaw-5 短期历史窗口与压缩

0. 为什么要手搓 OpenClaw

OpenClaw 很强,但完整工程体量也很大。对于大多数开发者来说,直接阅读全量代码会有三个痛点:

  • 模块多:Gateway、Agent、Tools、Sessions、Channels 互相耦合
  • 路径长:一条消息从输入到回复,跨越多个子系统
  • 调试难:没有自己的“最小版本”,很难定位问题

所以这个系列采用一个更实用的学习路径:
先做最小闭环,再逐步补齐能力。

代码地址:https://gitee.com/wisdomfriend/openclaw_py


1. 目标

用 Python 从 0 到 1 复现 OpenClaw 的核心能力:

  • Agent Loop(工具调用 + 多轮推理)
  • Session 与并发隔离
  • 记忆系统(短期 + 长期)
  • Skills 系统(分层加载)
  • Web/Telegram 等渠道接入

第一篇的阶段目标是:

  • 跑起 FastAPI 服务
  • 打通一个最小/v1/chat对话接口
  • 具备会话隔离与并发控制(每会话锁 + 全局信号量)

2. 目标架构

用户输入: CLI/Web/Telegram/Discord

Gateway Server

SessionManager

Session Lock + Global Semaphore

Agent Loop

Prompt Builder

LLM Provider Adapter

Tool Runtime

exec/web/search/read/write...

Memory Manager

短期会话历史

长期记忆: MEMORY.md + 日志

Knowledge RAG

BM25 + Embedding + RRF + Rerank

Skill Registry

L1 元数据

L2 指令加载

L3 资源加载

Cron Scheduler

3. 本篇目标

实现短期历史管理能力:

  • 历史窗口裁剪(保留最近关键消息)
  • 触发式压缩(达到阈值再做摘要)
  • 压缩后继续多轮对话,不丢核心目标

4. 为什么第 5 篇先做这个

到第 4 篇为止,Agent 已经有 Provider + Tool Runtime。
下一步如果不先控制上下文,就会遇到:

  • 对话越长,token 消耗越高
  • 模型开始丢上下文,回复变飘
  • 工具结果越来越多,prompt 膨胀明显

所以第 5 篇先解决“短期窗口 + 压缩”,第 6 篇再做长期记忆。


5. 本篇范围

做什么

  • 定义滑动窗口策略(最近 N 条)
  • 设计压缩触发条件(按消息数或 token 估算)
  • 保留不可压缩信息(system 指令、最新工具结果)
  • 给出压缩前后对比与验证方式

不做什么

  • 不做长期记忆落盘(第 6 篇)
  • 不做 RAG 检索融合(第 7 篇)

6. 设计草图:窗口 + 压缩

新消息进入

构建上下文

是否超过阈值

直接调用模型

压缩旧历史为摘要

保留最近窗口 + 摘要


7. 项目关键代码

7.1 配置层:窗口与压缩阈值

文件:openclaw_py/app/config.py

short_term_max_messages:int=Field(default=40,validation_alias="SHORT_TERM_MAX_MESSAGES")short_term_compact_threshold:int=Field(default=24,validation_alias="SHORT_TERM_COMPACT_THRESHOLD",)short_term_recent_keep:int=Field(default=10,validation_alias="SHORT_TERM_RECENT_KEEP")short_term_compact_token_threshold:int=Field(default=3000,validation_alias="SHORT_TERM_COMPACT_TOKEN_THRESHOLD",)short_term_summary_max_chars:int=Field(default=1800,validation_alias="SHORT_TERM_SUMMARY_MAX_CHARS",)

这组参数把“按消息数触发”和“按 token 粗估触发”结合起来,避免仅按条数裁剪导致上下文体积失控。

7.2 Agent 压缩触发与保留窗口

文件:openclaw_py/app/core/agent.py

def_maybe_compact_history(self)->None:non_system_messages=[mforminself.historyifm.get("role")!="system"]ifnotnon_system_messages:returnestimated_tokens=self._estimate_tokens_rough(self.history)if(len(non_system_messages)<self.short_term_compact_thresholdandestimated_tokens<self.short_term_compact_token_threshold):returnrecent_keep=min(self.short_term_recent_keep,self.short_term_max_messages)iflen(non_system_messages)<=recent_keep:returnhead=non_system_messages[:-recent_keep]tail=non_system_messages[-recent_keep:]summary=self._compact_messages(head)

这里的recent_keep = min(...)用于分离“策略值”和“系统硬上限”:
可调的保留策略不会突破系统可承受的最大窗口。

7.3 历史摘要注入与去重

文件:openclaw_py/app/core/agent.py

base_system_messages=[]formsginself.history:ifmsg.get("role")!="system":continuecontent=msg.get("content")ifisinstance(content,str)andcontent.startswith(self.HISTORY_SUMMARY_PREFIX):continuebase_system_messages.append(msg)summary_message={"role":"system","content":f"{self.HISTORY_SUMMARY_PREFIX}\n{summary}",}self.history=[*base_system_messages,summary_message,*tail]self.compaction_count+=1

会主动移除旧的[history_summary],保证每轮压缩后只保留最新摘要,避免摘要层层嵌套。


8. 规则压缩实现细节

文件:openclaw_py/app/core/agent.py

def_compact_messages(self,messages:list[dict[str,Any]])->str:lines:list[str]=[]formsginmessages:role=str(msg.get("role","unknown"))content=msg.get("content")tool_calls=msg.get("tool_calls")iftool_calls:names=[]fortcintool_calls:fn=tc.get("function")or{}name=fn.get("name")or"unknown_tool"names.append(name)lines.append(f"- assistant requested tools:{', '.join(names)}")ifisinstance(content,str)andcontent.strip():collapsed=" ".join(content.strip().split())lines.append(f"-{role}:{collapsed[:220]}")
summary="\n".join(lines)iflen(summary)>self.short_term_summary_max_chars:returnsummary[:self.short_term_summary_max_chars]+"\n...[summary_truncated]"returnsummary

当前版本采用“规则压缩”:保留角色信息、工具调用信息和内容摘要,并加上摘要长度上限。
后续升级为 LLM 摘要时,可以在不改调用方逻辑的前提下平滑替换。


9. 和当前系列的衔接关系

  • 第 1~4 篇:把 Agent 跑起来(能调用工具)
  • 第 5 篇:让 Agent 在长对话下还能稳定工作
  • 第 6 篇:把关键事实写入长期记忆,跨会话复用

10. 下一篇衔接

第 6 篇进入长期记忆:MEMORY.md持久化 + 召回注入。


11. 看到这里,不妨支持一下

如果这篇对你有帮助,欢迎点赞、收藏、关注。
后面第 6~8 篇会进入记忆与检索的核心区域(也是最实用的部分)。
有余力的话欢迎打赏支持,我会把实战代码和踩坑案例更新得更快。

http://www.jsqmd.com/news/630777/

相关文章:

  • Linux解压神器gunzip:10个实用技巧让你效率翻倍(附真实案例)
  • 别再让pip和conda打架了!用mamba一键搞定PyTorch 2.1.2 + CUDA 11.8 + xformers环境
  • Python面试30分钟突击掌握-LeetCode2-Strings
  • SQL Server下载 SQL Server 2025下载 SQL Server 2022下载 SQL Server 2019下载 SQL Server 2016下载
  • 告别命令恐惧:给设计师/剪辑师的CasaOS搭建指南(Ubuntu 22.04 + 图形化操作)
  • Ansible自动化部署Kubernetes 1.28集群:openEuler 24.03实战指南
  • 龙芯k - 走马观碑组ST驱动移植餐
  • Frps服务端一键安装脚本详解:从下载到面板访问的全流程指南(国内VPS优化版)
  • Modelsim原理图窗口实战指南:从基础操作到高级调试技巧
  • 西门子S7-200SMART与三菱变频器通讯程序:Modbus RTU协议下的高效控制解决方案
  • 穿山甲广告平台新手避坑指南:从注册到收益提升的完整攻略
  • AI 时代:祛魅、适应与重新定义咎
  • 测试文章 - AI工具调用测试
  • AI Agent Harness Engineering 测试与评估:如何衡量智能体的能力边界
  • 国内镜像源极速部署Qt5.15+开发环境(5分钟避坑指南)
  • 基于Nunchaku FLUX.1 CustomV3的室内设计辅助系统
  • 苍穹外卖实战:从百度地图AK配置到微信小程序配送范围校验全流程解析
  • 54k+Star 爆火! AI “新王者框架 “Harness Agent 来了!尼恩 来一次Harness穿透式解读
  • 避开这些坑!GD32F407读写FLASH时,如何防止程序‘跑飞’?
  • Fofax进阶技巧:自定义Fx语法规则与实战应用
  • 为什么92%的LLM项目卡在SITS2026第4.3.1条?——首份标准条款失效根因分析报告(内部流出版)
  • 揭秘千亿参数模型如何在8GB显存运行:SITS2026披露4大轻量化技术栈与实测吞吐对比数据
  • TF卡性能大比拼:AS SSD Benchmark实测4K随机读写速度差异
  • cv_unet_image-colorization问题解决:PyTorch兼容性报错修复指南
  • 【MQTT实战】SpringBoot + EMQX:构建高可靠物联网消息收发系统
  • 在Windows 10上搭建ROS开发环境:从零到一的完整实践
  • Fluent新手避坑指南:从自动保存到报告文件,这些设置细节千万别忽略
  • 从期末考题到实战:模式识别与深度学习核心考点深度解析
  • ReSpeaker 2-Mics Pi HAT:从开箱到唤醒,打造你的树莓派语音交互核心
  • onlyoffice 部署优化:解除连接限制、文件大小限制及中文字体适配