[Feature] 多轮 context 历史 tool results 清理:保留最近 N 轮 assistant 之后的 tool,更早替换占位符

Open Beginner friendly
#8,033 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
2/5
Estimated time
1-3 hours
Newbie friendliness
68/100
Issue type
Feature
Clarity
Clearly specified
Activity status
Quiet
Tech stack
python

Research direction

Start in astrbot/core/provider/sources/openai_source.py at _query and inspect the context_query flow before _materialize_context_image_parts. Add the requested cleanup so tool messages before the recent two assistant boundaries use the stated placeholder while user, assistant, and system messages remain unchanged; done means older tool results no longer inflate the payload and recent ones remain intact.

Written by the indexing model from the issue text.

Description

area:provider enhancement
Description / 描述

当前问题:
astrbot/core/provider/sources/openai_source.py 的 _query 把整个
context_query(含全部历史 tool role messages)打包成 payloads 发给 LLM。
Agent 循环 / 多步工具调用对话场景下,历史 tool results 累积爆 token。

典型 tool result 大小:
- web search: 5K-30K tokens(snippets + extracts)
- RAG / vector search: 5K-50K tokens(top-K 文档全文)
- list / get 类 API: 1K-10K tokens(多条记录)
- 单个 tool 返回 50K+ tokens 的情况也存在(OCR 长文档 / log 抓取)

10 轮多步对话累积 = 单次请求 100K+ token 不奇怪。但旧轮 tool results 的
实际信息价值快速衰减——agent 关心的是"最近的状态",不是"3 轮前的搜索结果"。

建议:
在 _query 内 _materialize_context_image_parts 之前增加一步清理:
从尾巴倒序扫 context_query,数 role='assistant' 消息,找到第 N 个 assistant
的位置(默认 N=2,即"最近 2 轮 assistant 边界")。在该位置之前的所有
role='tool' messages 的 content 替换为占位符 "[工具结果已省略]"。

逻辑示意:

  _tool_keep_after = 0
  _assistant_count = 0
  for _i in range(len(context_query) - 1, -1, -1):
      if context_query[_i].get("role") == "assistant":
          _assistant_count += 1
          if _assistant_count >= 2:
              _tool_keep_after = _i
              break
  for _i in range(_tool_keep_after):
      if context_query[_i].get("role") == "tool":
          context_query[_i]["content"] = "[工具结果已省略]"

影响:
- 最近 2 轮完整 tool 上下文保留(agent 推理需要的"刚刚发生了什么"完整可见)
- 更早 tool results 替换占位符(LLM 仍知道"那一轮调过工具",不至于上下文断裂)
- 不影响 user / assistant / system messages,纯粹处理 tool role
- 跟补丁 7(历史 image 剥离)独立但配合使用收益叠加(图 + tool 都剥)

~10 行新增代码,无外部依赖。

可配置性建议:
keep_recent_assistant_count 设为可配置参数(默认 2),让重度 agent 用户
调到 3-5 保留更长上下文,简单聊天场景调到 1 极限省 token。

Use Case / 使用场景
  1. Agent 循环(多步推理):
    LLM 调多个工具完成一个任务(搜索 → 读取 → 摘要 → 发送),每一步都带
    tool result。任务完成后下一轮对话不需要再看前一个任务的中间 tool 输出。
    保留最近 2 轮 = 保留当前任务 + 上一个任务,足够上下文连续。

  2. 长上下文 RAG / web search 场景:
    web_search / vector_search 类工具单次返回 5K-50K tokens。
    累积 10 轮 = 单次 LLM 请求 input 50K-500K tokens(很多 model 直接超 context window)。
    清理后回到合理范围。

  3. 数据查询型助手 (MoSphere 实际场景):
    墨墨调 recall_memory / recall_node / get_health_stats / web_search /
    recall_recent_events 等工具,每轮典型调 2-4 个。
    长对话累积 tool results 价值随时间衰减(旧搜索结果跟当前问题不相关)。
    保留最近 2 轮 = 当前讨论 + 上一个话题,符合实际记忆衰减曲线。

  4. Tool result 含大块外部内容场景:
    web extract / OCR / 长文档读取等工具输出。这类内容本质 ephemeral
    (用完即弃,LLM 提取关键事实写回复后不需要原文),最适合占位符替换。
    单次 extract 50K tokens 累积 5 轮就 250K——直接撑爆 context window
    触发 framework 截断(halving truncation 或类似机制)。

  5. cron / 长跑场景:
    长期跑的 AstrBot 实例,conversation 累积 N 天后 tool history 巨大。
    清理后 token 占用回到稳定水平,不会随时间线性增长。

实现简单(~10 行),保留语义连续性(占位符),LLM 体验受影响极小
(agent 不需要看 3 轮前的 tool 输出)。
愿意提 PR。

注:本优化跟另一个 prompt cache issue 配合使用最佳——
cache 减少 input cost / 清理 tool 减少 token / 剥图减少 vision token,
三个独立 + 收益叠加。

Willing to Submit PR? / 是否愿意提交PR?
  • Yes, I am willing to submit a PR. / 是的,我愿意提交 PR。
Code of Conduct
Dominant language
Python
Stars
40.7k
Forks
2.9k
Avg merge
1d 5h
Merged PRs (30d)
112

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from AstrBotDevs/AstrBot

All issues in AstrBotDevs/AstrBot

Similar issues

More Python issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.