fix: 分页拉取增强

废除错误的终止条件: 原先逻辑中如果 API 返回的消息数量(93条)小于请求数量(100条),会判定为“已到达历史尽头”并退出循环。这在 NapCat 等后端中并不可靠,因为后端可能会由于内部缓存页限制或消息过滤返回略少于请求数的结果。 现在:只要 API 返回了至少 1 条消息,且时间戳未超出限制,逻辑就会根据当前最旧消息的 message_id 作为锚点,继续发起下一页请求。
强化无限循环防护: 增加了锚点变化一致性检查 (new_anchor_id == current_anchor_id),确保只有在真正无法获取到更旧消息时才停止,防止在极端情况下出现死循环。
对齐 portrayal 插件逻辑: 确认并统一了 reverseOrder=True 和 message_seq 的使用方式,这在 NapCat 中是触发“从当前位置向回溯扫描”的正确方式。
增强调试日志: 添加了详细的
debug
 日志,您现在可以在日志中清晰地看到分页拉取的每一轮进度(处理条数和当前锚点 ID),方便在云端环境中进一步排查。
This commit is contained in:
SXP-Simon
2026-02-21 19:30:51 +08:00
committed by Helian Nuits
parent 867b78a11c
commit 5c2d7dfb0b
@@ -126,13 +126,18 @@ class OneBotAdapter(PlatformAdapter):
result = await self.bot.call_action("get_group_msg_history", **params)
if not result or "messages" not in result:
logger.debug(
f"OneBot 分页拉取:API 调用返回空或无效数据,停止回溯。群: {group_id}"
)
break
messages = result.get("messages", [])
if not messages:
logger.debug(
f"OneBot 分页拉取:获取到 0 条消息,停止回溯。群: {group_id}"
)
break
# 时间过滤与列表合并
# 消息通常是按时间正序排列的,即 messages[0] 最旧,messages[-1] 最新
chunk_earliest_msg = messages[0]
chunk_earliest_time = chunk_earliest_msg.get("time", 0)
@@ -150,12 +155,30 @@ class OneBotAdapter(PlatformAdapter):
all_raw_messages.append(raw_msg)
# 更新锚点为该批次最旧的消息 ID,用于下一次回溯请求
current_anchor_id = chunk_earliest_msg.get("message_id")
new_anchor_id = chunk_earliest_msg.get("message_id")
# 如果该批次最旧的消息已经早于 start_time,或者拉取的数量不足,说明已到达回溯终点
if chunk_earliest_time < start_timestamp or len(messages) < fetch_count:
# 如果时间已经超过限制,或者锚点没有变化(说明已经到底),则停止
if chunk_earliest_time < start_timestamp:
logger.debug(
f"OneBot 分页拉取:消息时间 ({chunk_earliest_time}) 早于起始时间 ({start_timestamp}),回溯完成。"
)
break
if str(new_anchor_id) == str(current_anchor_id):
logger.debug(
"OneBot 分页拉取:消息锚点没有变化,可能已到达历史尽头。"
)
break
current_anchor_id = new_anchor_id
logger.debug(
f"OneBot 分页拉取进度: 已获取 {len(all_raw_messages)} 条符合条件的消息,下一次锚点: {current_anchor_id}"
)
# 如果这批消息全都是旧的(不在我们要的时间范围内),也应该可以考虑停止
# 但由于 get_group_msg_history 的 reverseOrder 行为在不同实现下可能不一致,
# 只要时间没越界且还有消息,我们就继续拉取直到 max_count 或时间越界。
# 稍微延迟,减缓服务端压力(避免 NapCat 瞬间 CPU 飙升)
await asyncio.sleep(0.05)