ReMe/tests/light/test_reme_light.py

196 lines
8.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""测试 ReMeLight
演示 ReMeLight 的完整功能,并使用 AsMsgHandler 跟踪每步 Token 变化:
1. compact_tool_result - 压缩超长工具输出
2. compact_memory - 生成压缩摘要
3. summary_memory - 生成完整摘要并写入文件
4. pre_reasoning_hook - 推理前预处理钩子
5. memory_search - 语义搜索记忆
6. ReMeInMemoryMemory.estimate_tokens - 估算 Token 使用
7. ReMeInMemoryMemory.get_history_str - 获取格式化历史记录
"""
import asyncio
import logging
from test_utils import build_sample_messages, get_msg_handler
from reme.reme_light import ReMeLight
def print_token_change(_step_name: str, before: int, after: int):
"""打印 Token 变化统计。"""
change = after - before
change_pct = (change / before * 100) if before > 0 else 0
print(f" 📊 Token 统计: {before:,}{after:,} (变化: {change:+,}, {change_pct:+.1f}%)")
# ==================== 主测试流程 ====================
async def main():
"""测试 ReMeLight 的完整功能,并跟踪每步 Token 变化。"""
# 初始化 AsMsgHandler 用于 Token 统计
msg_handler = get_msg_handler()
# 初始化 ReMeLight
reme = ReMeLight(
default_as_llm_config={"model_name": "qwen3.5-35b-a3b"},
# default_embedding_model_config={"model_name": "text-embedding-v4"},
default_file_store_config={"fts_enabled": True, "vector_enabled": False},
enable_load_env=True,
)
logging.getLogger("reme").setLevel(logging.WARNING)
await reme.start()
print("=" * 70)
print("ReMeLight 已启动")
print("=" * 70)
# 构建模拟对话历史(包含超长 tool_result确保超过 128K token
original_messages = build_sample_messages(include_large_tool_result=True)
initial_tokens = await msg_handler.count_msgs_token(original_messages)
print(f"\n[原始消息]: {len(original_messages)} 条, {initial_tokens:,} tokens")
print(f" 目标阈值: 128K = {128 * 1024:,} tokens")
print(f" 超出阈值: {initial_tokens > 128 * 1024}")
# ==================== 1. compact_tool_result ====================
print("\n" + "=" * 70)
print("[步骤 1] compact_tool_result - 压缩超长工具输出")
print("=" * 70)
# 重新获取原始消息
messages = build_sample_messages(include_large_tool_result=True)
tokens_before = await msg_handler.count_msgs_token(messages)
messages_after_step1 = await reme.compact_tool_result(messages)
tokens_after = await msg_handler.count_msgs_token(messages_after_step1)
print(f" 消息数量: {len(messages)}{len(messages_after_step1)}")
print_token_change("compact_tool_result", tokens_before, tokens_after)
# ==================== 2. compact_memory ====================
print("\n" + "=" * 70)
print("[步骤 2] compact_memory - 生成结构化压缩摘要")
print("=" * 70)
# 重新获取原始消息
messages = build_sample_messages(include_large_tool_result=True)
tokens_before = await msg_handler.count_msgs_token(messages)
compact_summary = await reme.compact_memory(
messages=messages,
previous_summary="",
)
summary_tokens = await msg_handler.count_str_token(compact_summary)
print(f" 输入消息 tokens: {tokens_before:,}")
print(f" 压缩摘要长度: {len(compact_summary)} 字符, {summary_tokens:,} tokens")
print(f" 压缩比: {summary_tokens / tokens_before * 100:.1f}%" if tokens_before > 0 else " 压缩比: N/A")
print(f" 摘要预览: {compact_summary[:200]}..." if len(compact_summary) > 200 else f" 摘要: {compact_summary}")
# ==================== 3. summary_memory ====================
print("\n" + "=" * 70)
print("[步骤 3] summary_memory - 生成完整摘要并写入文件")
print("=" * 70)
# 重新获取原始消息
messages = build_sample_messages(include_large_tool_result=True)
tokens_before = await msg_handler.count_msgs_token(messages)
summary_result = await reme.summary_memory(messages=messages)
print(f" 输入消息 tokens: {tokens_before:,}")
print(f" 摘要结果长度: {len(summary_result)} 字符")
print(f" 摘要预览: {summary_result[:200]}..." if len(summary_result) > 200 else f" 摘要: {summary_result}")
# ==================== 4. pre_reasoning_hook ====================
print("\n" + "=" * 70)
print("[步骤 4] pre_reasoning_hook - 推理前预处理")
print("=" * 70)
# 重新获取原始消息
messages = build_sample_messages(include_large_tool_result=True)
tokens_before = await msg_handler.count_msgs_token(messages)
processed_messages, compressed_summary = await reme.pre_reasoning_hook(
messages=messages,
system_prompt="你是一个有帮助的 AI 助手。",
compressed_summary="",
max_input_length=128000,
compact_ratio=0.7,
memory_compact_reserve=10000,
enable_tool_result_compact=True,
tool_result_compact_keep_n=3,
)
tokens_after = await msg_handler.count_msgs_token(processed_messages)
compressed_summary_tokens = await msg_handler.count_str_token(compressed_summary)
print(f" 消息数量: {len(messages)}{len(processed_messages)}")
print_token_change("pre_reasoning_hook", tokens_before, tokens_after)
print(f" 压缩摘要: {len(compressed_summary)} 字符, {compressed_summary_tokens:,} tokens")
print(f" 总上下文: {tokens_after + compressed_summary_tokens:,} tokens")
# ==================== 5. memory_search ====================
print("\n" + "=" * 70)
print("[步骤 5] memory_search - 语义搜索记忆")
print("=" * 70)
search_result = await reme.memory_search(query="Python 版本偏好", max_results=5)
if search_result.content:
print(f" 搜索结果: {search_result.content}")
else:
print(" 未找到相关记忆")
# ==================== 6 & 7. ReMeInMemoryMemory ====================
print("\n" + "=" * 70)
print("[步骤 6] ReMeInMemoryMemory - 会话内存管理")
print("=" * 70)
# 重新获取原始消息
messages = build_sample_messages(include_large_tool_result=True)
memory = reme.get_in_memory_memory()
for msg in messages:
await memory.add(msg)
print(f" 已添加 {len(messages)} 条原始消息到内存")
# 6.1 estimate_tokens
print("\n[6.1] estimate_tokens - 估算 Token 使用:")
token_stats = await memory.estimate_tokens(max_input_length=128000)
print(f" - 总消息数: {token_stats['total_messages']}")
print(f" - 消息 Token 数: {token_stats['messages_tokens']:,}")
print(f" - 压缩摘要 Token 数: {token_stats['compressed_summary_tokens']:,}")
print(f" - 预估总 Token 数: {token_stats['estimated_tokens']:,}")
print(f" - 最大输入长度: {token_stats['max_input_length']:,}")
print(f" - 上下文使用率: {token_stats['context_usage_ratio']:.2f}%")
# 6.2 get_history_str
print("\n[6.2] get_history_str - 格式化历史记录:")
history_str = await memory.get_history_str(max_input_length=128000)
print(history_str[:1000] + "..." if len(history_str) > 1000 else history_str)
# ==================== 等待后台任务完成 ====================
print("\n" + "=" * 70)
print("[步骤 7] 等待后台任务完成")
print("=" * 70)
await_result = await reme.await_summary_tasks()
print(f" 后台任务完成,结果长度: {len(await_result)} 字符")
# ==================== 总结 ====================
print("\n" + "=" * 70)
print("📊 Token 变化总结")
print("=" * 70)
print(f" 原始消息: {initial_tokens:,} tokens")
print(f" Step 1 compact_tool_result 后: {(await msg_handler.count_msgs_token(messages_after_step1)):,} tokens")
print(f" Step 2 compact_memory 摘要: {summary_tokens:,} tokens")
print(
f" Step 4 pre_reasoning_hook 后: {tokens_after:,} tokens + 摘要 {compressed_summary_tokens:,} "
f"tokens = {tokens_after + compressed_summary_tokens:,} tokens",
)
print(
f" 最大节省: {initial_tokens - tokens_after:,} "
f"tokens ({(initial_tokens - tokens_after) / initial_tokens * 100:.1f}%)",
)
print(f" 目标阈值: {128 * 1024:,} tokens")
# 关闭 ReMeLight
await reme.close()
print("\n" + "=" * 70)
print("ReMeLight 已关闭")
print("=" * 70)
if __name__ == "__main__":
asyncio.run(main())