2026-05-23-genericagent-vs-hermes-lcm-prompt-compaction
title: GenericAgent agent_loop / compress_history_tags vs Hermes LCM / Prompt Compaction
GenericAgent 的 agent_loop.py 和 llmcore.compress_history_tags 不是 Hermes LCM 的替代物。它们更像一套轻量运行时压缩纪律:靠最小循环、单轮消息重建、标签级截断、周期性压旧历史,减少上下文噪音。
不要把 compress_history_tags 原样搬进 Hermes messages 上原地改
不调用真实 executor;生产动作另走审批。
关键判断
| 判断项 | 摘要 |
|---|---|
| 推荐方案 | 不要把 compress_history_tags 原样搬进 Hermes messages 上原地改 |
| 关键依据 | 见完整记录中的评分依据、状态摘要和证据链。 |
| 落地方式 | 按行动清单推进,保持可回退。 |
| 风险边界 | 不跨执行边界;真实执行需另走审批。 |
证据摘要
- 由 Hermes 会话生成。证据点 1
- 如涉及外部事实,应在正文中保留来源或验证路径。证据点 2
行动清单
compress_history_tags 原样搬进 Hermes messages 上原地改<key_info> 原文;这类经常是用户约束和中间状态context_win * 3 替代 Hermes token counter边界 / 风险
未记录额外风险。
完整记录
---
title: GenericAgent agent_loop / compress_history_tags vs Hermes LCM / Prompt Compaction
created: 2026-05-23
updated: 2026-05-23
type: technical-comparison
status: active
tags: [GenericAgent, Hermes, LCM, prompt-compaction, context-density]
source:
- https://github.com/lsdefine/GenericAgent/blob/main/agent_loop.py
- https://github.com/lsdefine/GenericAgent/blob/main/llmcore.py
- /home/ht/.hermes/plugins/hermes-lcm/engine.py
- /home/ht/.hermes/hermes-agent/agent/context_prompt_compactor.py
- /home/ht/.hermes/hermes-agent/agent/tool_description_compactor.py
public_html: https://taoge-morning-brief.pages.dev/decision-traces/2026-05-23-genericagent-vs-hermes-lcm-prompt-compaction.html
confidence: high
---
GenericAgent agent_loop / compress_history_tags vs Hermes LCM / Prompt Compaction
结论
GenericAgent 的 agent_loop.py 和 llmcore.compress_history_tags 不是 Hermes LCM 的替代物。它们更像一套轻量运行时压缩纪律:靠最小循环、单轮消息重建、标签级截断、周期性压旧历史,减少上下文噪音。
Hermes 当前 LCM 是更重、更可审计的lossless context management:原文落库、DAG summary、可 grep/describe/expand 回捞;Prompt Compaction 是入场前静态 prompt/schema/prose 压缩。
最合理的吸收方式:不改 LCM 主链路;在 prompt compaction 与非 LCM / overflow fallback 场景吸收 GenericAgent 的“标签级保头尾截断”和“工具结果轻量清洗”思路。
GenericAgent 机制读后摘要
1. agent_loop.py 主循环
文件只有 133 行,核心在 agent_runner_loop:
- 初始 messages:
system+user - 每 turn 调
client.chat(messages=messages, tools=tools_schema) - tool call 由
handler.dispatch分发到do_<tool_name> - 每个 tool 返回
StepOutcome(data, next_prompt, should_exit) next_prompt聚合后作为下一轮唯一 user message- 第 104 行关键:
messages = [{"role": "user", "content": next_prompt, "tool_results": tool_results}] - 注释说明:
just new message, history is kept in *Session
这意味着 GA 自己的 loop 不在本地 message list 里保完整长历史,而依赖 LLM session backend 维护历史;每轮只把下一步 prompt 和 tool_results 送进去。它的上下文控制重点不在 DAG,而在:
- loop 很短,减少框架层噪音
- tool schema 少,减少固定输入
- verbose=false 时清洗 assistant content 和工具参数展示
- 每 10 turn 重置
client.last_tools,重新发工具描述,避免长期工具描述状态异常
2. _clean_content
用于非 verbose 输出清洗:
- 缩长代码块:超过 6 行只留前 5 行和行数提示
- 删除
<file_content>...</file_content> - 删除
<tool_use>/<tool_call>块 - 合并多余空行
这不是严格上下文压缩,而是展示/回灌内容降噪。可借鉴点是:对 code block、tool call、file content 这类高噪声块按类型处理,不做泛化摘要。
3. _compact_tool_args
用于工具参数短显:
- path 只显示 basename
update_working_checkpoint只留前 60 字ask_user保留问题和候选项- 其他 args JSON 截到 120 字
可借鉴点是 tool args 的“可读短显”和“保留关键字段”。但这更影响 UI/日志,不应直接影响模型真实 tool call 参数。
4. compress_history_tags
核心实现 36-67 行:
- 每次调用有冷却计数
_cd,默认interval=5,不是每轮都压 force=True时立即压- 默认保护最近
keep_recent=10条消息 - 对旧消息:
<thinking>/<think>/<tool_use>/<tool_result>标签内容保头尾截断到max_len=800<history>/<key_info>/<earlier_context>整块替换成<tag>[...]</tag>- Claude content-block 里:
- text block 做同样标签处理
- tool_result content 截断字符串或 text block
- tool_use input dict 每个字段截断
- 打印
[Cut] before -> after
它是原地 lossy trimming,没有外部原文存储,也没有检索回捞。
5. trim_messages_history
它把 compress_history_tags 纳入上下文守门:
cap = sess.context_win * 3:用字符数粗略估算 tokentarget = cap * trim_keep_rate,默认 0.6- 先按 interval 尝试压旧 tag
- 如果仍超 cap:force 压,只保最近 4 条
- 如果还超:从头丢消息,保留至少 9 条左右,并清理开头孤立 tool_result
这是典型“轻量、粗糙、可用”的运行时上下文削峰策略。
Hermes 当前机制
1. LCM
LCM 是插件 /home/ht/.hermes/plugins/hermes-lcm,主入口 engine.py。它的架构明确:
- 每条消息原文持久化到 immutable
MessageStore - context pressure 时,把 fresh tail 之外的旧消息压成 D0 summary node
- D0 累积后按 fan-in 压成 D1/D2...
- active context = system prompt + DAG summaries + fresh tail
- 提供
lcm_grep / lcm_describe / lcm_expand / lcm_expand_query回捞
关键区别:LCM 是 lossless 管理,summary 只是 active context 的投影;原文仍可查。
2. LCM 的压缩细节
从 engine.py 看:
should_compress_preflight会先 ingest messages,再判断是否需要压缩compress会保护 system prompt 和 fresh tail- leaf chunk 可以 dynamic 调整,overflow 时可强制压旧 raw backlog
- summarization 失败会尝试缩小 chunk rescue
- tool result 在序列化前可能 externalize,大输出用 placeholder
- summary node 带
source_ids/source_type/earliest_at/latest_at/expand_hint - active context 组装时按高 depth 优先,summary budget 和 tail budget 分开控制
- assembly cap 可由
max_assembly_tokens与reserve_tokens_floor约束
这比 GA 的 compress_history_tags 重很多,但可审计、可回捞、适合长会话。
3. Hermes Prompt Compaction
现有实现分三层:
agent/context_prompt_compactor.py- 保护 URL / inline code / path
- 遇到 bullet / numbered list 默认不压
- 只删 filler prose
agent/tool_description_compactor.py- 保护 URL / inline code / path / CLI flag
- 对 tool description 做保守替换
- 不够收益或过度压缩就回退原文
agent/system_prompt.py里 compact guidance blocks- memory / session_search / skills / search_router 等 guidance 有 compact 版
根据本机已有 rollout 记录:
- compact guidance blocks:约 45.06% 收益
- compact context files:约 37.64% sample 收益
- compact skills prompt:约 6.66%
- compact tool descriptions:约 1.33%
Prompt Compaction 与 LCM 的层级不同:前者压固定 prompt/schema/prose,后者压动态会话历史。
对比表
| 维度 | GenericAgent compress_history_tags | Hermes LCM | Hermes Prompt Compaction |
|---|---|---|---|
| 目标 | 运行时旧历史削峰 | 长会话 lossless 管理 | 固定 prompt/schema/prose 减重 |
| 是否保原文 | 否 | 是,MessageStore | 不涉及会话原文 |
| 压缩方式 | 标签级 regex 截断/删除 | LLM summary + DAG | 保守规则替换/compact 文案 |
| 回捞能力 | 无 | lcm_grep/describe/expand | 无需回捞 |
| 触发 | interval / force / 超 cap | token threshold / preflight / deferred maintenance / overflow | config flag,构造 prompt 时 |
| 粒度 | message content 内部 tag/block | message chunk / summary node | guidance/context/tool description prose |
| 风险 | 丢细节且不可恢复 | summary 失真但可 expand 原文 | 误伤规则,已有保护 |
| 工程复杂度 | 低 | 高 | 中低 |
| 适合 Hermes 主线 | 只适合 fallback/局部 | 已是主线 | 已是主线 |
关键判断
1. 不要用 GenericAgent 替换 LCM
GA 的压缩是 lossy trimming,优点是便宜、简单、稳定;缺点是被截掉的信息无法恢复。Hermes 当前 LCM 的核心价值正是“active context 变短,但原文还在”。这条不能倒退。
2. GenericAgent 对 LCM 的启发是“预清洗”,不是“替代 summarization”
LCM 已经在 _serialize_messages 中做了类似事情:
- sanitize content
- tool output externalize
- 长 assistant/tool/user content 头尾截断
- tool call arguments sanitize + 500 字截断
GenericAgent 可补的点是:对 <thinking>/<tool_use>/<tool_result>/<history>/<key_info> 这类 tag 的显式标签级策略。如果 Hermes 会话里确实出现这类 tag,可在 LCM pre-compaction sanitize 阶段加入保守处理,但必须只用于送 summarizer 的序列化文本,不能改 MessageStore 原文。
3. GenericAgent 对 Prompt Compaction 的启发有限但有一条有价值
Prompt Compaction 现在主要处理固定 prose。GA 的 _compact_tool_args/_clean_content 提醒我们:除了 prompt,还可以做展示层 / 日志层 / summarizer 输入层压缩,避免工具参数和代码块污染下一轮 reasoning。
但这不应和正式 prompt compaction 混成一个开关。建议单独归类为:
lcm.pre_summary_tag_trimmingdisplay.compact_tool_call_echogateway/cardify_output_cleanup
4. GA 的“单轮 messages 重建”不适合 Hermes
GA 第 104 行每轮只保留下一条 user message,完整历史在 backend session。Hermes 要支持多 provider、gateway、cron、LCM、tool calls、session DB 和 exact recall,不能依赖 provider 侧 session state。Hermes 当前本地完整 message 管理是必要架构。
建议吸收项
P0:吸收到 LCM pre-summary sanitize
做一个保守函数,只作用于“送 summarizer 的 serialized copy”,不改原始存储:
<thinking>/<think>:保头尾,默认 800-1200 chars<tool_use>/<tool_call>:保 tool name / 参数摘要,长字段截断<tool_result>:已有 externalize 优先;未 externalize 的 tag 内容保头尾<history>/<earlier_context>:如果是嵌套历史块,替换为 placeholder<key_info>:谨慎,不建议整块删;可以保留首尾或摘要,因为里面可能有用户约束
验证:构造包含这些 tag 的 assistant/tool messages,确认 MessageStore 原文不变,serialize 后变短,summary 仍含关键 tool name/path/url/error。
P1:为非 LCM compressor / overflow fallback 增加轻量 tag trimming
如果某些 session 禁用 LCM 或 LCM summarization 失败,可以用 GA 风格做最后防线:
- 先压旧消息里的 tool/thinking/history tag
- 再保 fresh tail
- 最后才丢旧消息
这比直接 pop old messages 更温和。
P1:工具回显压缩
Hermes gateway / CLI 显示 tool call arguments 时,可以参考 _compact_tool_args:
- path 显示 basename + hover/expand 原文
- 长 JSON 参数折叠
- ask_user 保留 candidates
- memory/checkpoint 只展示摘要
这属于 UI/日志,不影响模型输入。
P2:agent loop 参考,不改主循环
保留参考意义:短 loop、handler dispatch、StepOutcome 都很干净。但 Hermes 主循环要处理 provider fallback、budget、toolsets、gateway、memory、LCM、interrupt、cron 等,不适合向 GA 的极简 loop 回退。
不建议做的事
- 不要把
compress_history_tags原样搬进 Hermes messages 上原地改 - 不要删除
<key_info>原文;这类经常是用户约束和中间状态 - 不要用字符数
context_win * 3替代 Hermes token counter - 不要让 provider session history 接管 Hermes 本地会话历史
- 不要把 prompt compaction、LCM pre-summary trimming、UI echo cleanup 混成一个开关
最小落地路线
- 新增
agent/history_tag_sanitizer.py或放入 LCMextraction/sanitize附近,只处理 copy。 - 在 LCM
_serialize_messages调sanitize_pre_compaction_content后接 tag trimming。 - 增加 focused tests:
- raw MessageStore 内容不变
- serialized text 变短
- thinking/tool_result/history tag 被处理
- URL/path/error/tool name 保留
- 跑 LCM tests 与一次真实长会话压缩 smoke。
最终结论
GenericAgent 这部分对 Hermes 的价值不是“更好的 LCM”,而是给 LCM 前处理和 fallback trimming 提供一个非常实用的小模式。建议做 P0 局部吸收:LCM pre-summary tag trimming,但必须坚持 lossless 边界:原文永远进 MessageStore,压缩只发生在 summarizer input / active projection / display echo。