"""测试 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())