Browse Source

修改了日志的配置,改为按照日期滚动。

wangxq 1 month ago
parent
commit
1faefca376

+ 6 - 2
agent/citu_agent.py

@@ -41,14 +41,16 @@ class CituLangGraphAgent:
     
     def _create_workflow(self, routing_mode: str = None) -> StateGraph:
         """根据路由模式创建不同的工作流"""
+        self.logger.info(f"🏗️ [WORKFLOW] 动态创建workflow被调用")
+        
         # 确定使用的路由模式
         if routing_mode:
             QUESTION_ROUTING_MODE = routing_mode
-            self.logger.info(f"创建工作流,使用传入的路由模式: {QUESTION_ROUTING_MODE}")
+            self.logger.info(f"使用传入的路由模式: {QUESTION_ROUTING_MODE}")
         else:
             try:
                 from app_config import QUESTION_ROUTING_MODE
-                self.logger.info(f"创建工作流,使用配置文件路由模式: {QUESTION_ROUTING_MODE}")
+                self.logger.info(f"使用配置文件路由模式: {QUESTION_ROUTING_MODE}")
             except ImportError:
                 QUESTION_ROUTING_MODE = "hybrid"
                 self.logger.warning(f"配置导入失败,使用默认路由模式: {QUESTION_ROUTING_MODE}")
@@ -90,6 +92,7 @@ class CituLangGraphAgent:
             workflow.add_edge("format_response", END)
             
         else:
+            self.logger.info(f"🧠 [WORKFLOW] 构建hybrid模式的workflow...")
             # 其他模式(hybrid, llm_only):使用新的拆分工作流
             workflow.add_node("classify_question", self._classify_question_node)
             workflow.add_node("agent_chat", self._agent_chat_node)
@@ -813,6 +816,7 @@ class CituLangGraphAgent:
                 self.logger.info(f"使用指定路由模式: {routing_mode}")
             
             # 动态创建workflow(基于路由模式)
+            self.logger.info(f"🔄 [PROCESS] 调用动态创建workflow")
             workflow = self._create_workflow(routing_mode)
             
             # 初始化状态

+ 1 - 1
app_config.py

@@ -37,7 +37,7 @@ API_DEEPSEEK_CONFIG = {
 API_QIANWEN_CONFIG = {
     "api_key": os.getenv("QWEN_API_KEY"),  # 从环境变量读取API密钥
     "base_url": "https://dashscope.aliyuncs.com/compatible-mode/v1",  # 千问API地址
-    "model": "qwen-plus",
+    "model": "qwen-plus-latest",
     "allow_llm_to_see_data": True,
     "temperature": 0.6,
     "n_results": 6,

+ 18 - 12
config/logging_config.yaml

@@ -18,8 +18,9 @@ default:
     format: "%(asctime)s [%(levelname)s] [%(name)s] %(filename)s:%(lineno)d - %(message)s"
     rotation:
       enabled: true
-      max_size: "50MB"
-      backup_count: 10
+      when: "midnight"
+      interval: 1
+      backup_count: 30
 
 # 模块特定配置
 modules:
@@ -36,8 +37,9 @@ modules:
       format: "%(asctime)s [%(levelname)s] [%(name)s] %(filename)s:%(lineno)d - %(message)s"
       rotation:
         enabled: true
-        max_size: "50MB"
-        backup_count: 10
+        when: "midnight"
+        interval: 1
+        backup_count: 30
   
   data_pipeline:
     level: DEBUG
@@ -52,8 +54,9 @@ modules:
       format: "%(asctime)s [%(levelname)s] [%(name)s] %(filename)s:%(lineno)d - %(message)s"
       rotation:
         enabled: true
-        max_size: "20MB"
-        backup_count: 5
+        when: "midnight"
+        interval: 1
+        backup_count: 30
   
   agent:
     level: DEBUG
@@ -68,8 +71,9 @@ modules:
       format: "%(asctime)s [%(levelname)s] [%(name)s] %(filename)s:%(lineno)d - %(message)s"
       rotation:
         enabled: true
-        max_size: "30MB"
-        backup_count: 8
+        when: "midnight"
+        interval: 1
+        backup_count: 30
   
   vanna:
     level: DEBUG
@@ -84,8 +88,9 @@ modules:
       format: "%(asctime)s [%(levelname)s] [%(name)s] %(filename)s:%(lineno)d - %(message)s"
       rotation:
         enabled: true
-        max_size: "20MB"
-        backup_count: 5
+        when: "midnight"
+        interval: 1
+        backup_count: 30
   
   react_agent:
     level: DEBUG
@@ -100,5 +105,6 @@ modules:
       format: "%(asctime)s [%(levelname)s] [%(name)s] %(filename)s:%(lineno)d - %(message)s"
       rotation:
         enabled: true
-        max_size: "30MB"
-        backup_count: 8 
+        when: "midnight"
+        interval: 1
+        backup_count: 30 

+ 17 - 7
core/logging/log_manager.py

@@ -180,15 +180,25 @@ class LogManager:
         """创建文件处理器(支持自动轮转)"""
         log_file = self.base_log_dir / file_config.get('filename', f'{module}.log')
         
-        # 使用RotatingFileHandler实现自动轮转和清理
+        # 使用RotatingFileHandler或TimedRotatingFileHandler实现自动轮转和清理
         rotation_config = file_config.get('rotation', {})
         if rotation_config.get('enabled', False):
-            handler = logging.handlers.RotatingFileHandler(
-                log_file,
-                maxBytes=self._parse_size(rotation_config.get('max_size', '50MB')),
-                backupCount=rotation_config.get('backup_count', 10),
-                encoding='utf-8'
-            )
+            # 检查是否配置了时间滚动
+            if 'when' in rotation_config:
+                handler = logging.handlers.TimedRotatingFileHandler(
+                    log_file,
+                    when=rotation_config.get('when', 'midnight'),
+                    interval=rotation_config.get('interval', 1),
+                    backupCount=rotation_config.get('backup_count', 30),
+                    encoding='utf-8'
+                )
+            else:
+                handler = logging.handlers.RotatingFileHandler(
+                    log_file,
+                    maxBytes=self._parse_size(rotation_config.get('max_size', '50MB')),
+                    backupCount=rotation_config.get('backup_count', 10),
+                    encoding='utf-8'
+                )
         else:
             handler = logging.FileHandler(log_file, encoding='utf-8')
         

+ 0 - 221
test_api_analysis.py

@@ -1,221 +0,0 @@
-#!/usr/bin/env python3
-"""
-测试当前API的真实输出,分析数据结构以确定是否能满足需求
-"""
-import requests
-import json
-from datetime import datetime
-
-def test_current_api():
-    """测试当前的对话历史API"""
-    print("=" * 60)
-    print("测试当前API的真实输出")
-    print("=" * 60)
-    
-    # API URL
-    api_url = "http://localhost:8084/api/v0/react/users/wang10/conversations/wang10:20250717211620915"
-    
-    try:
-        print(f"📡 调用API: {api_url}")
-        response = requests.get(api_url, timeout=30)
-        
-        print(f"📊 状态码: {response.status_code}")
-        print(f"📄 响应头: {dict(response.headers)}")
-        
-        if response.status_code == 200:
-            data = response.json()
-            print(f"✅ API调用成功")
-            print(f"📋 响应数据结构分析:")
-            analyze_response_structure(data)
-            
-            # 分析消息结构
-            if 'data' in data and 'messages' in data['data']:
-                analyze_messages(data['data']['messages'])
-            
-            # 保存完整响应到文件
-            with open('api_response_full.json', 'w', encoding='utf-8') as f:
-                json.dump(data, f, ensure_ascii=False, indent=2)
-            print(f"💾 完整响应已保存到 api_response_full.json")
-            
-        else:
-            print(f"❌ API调用失败: {response.status_code}")
-            print(f"📄 错误响应: {response.text}")
-            
-    except requests.exceptions.RequestException as e:
-        print(f"❌ 网络请求失败: {e}")
-    except Exception as e:
-        print(f"❌ 其他错误: {e}")
-
-def analyze_response_structure(data):
-    """分析响应数据结构"""
-    print(f"   🔍 顶级键: {list(data.keys())}")
-    
-    if 'data' in data:
-        data_section = data['data']
-        print(f"   🔍 data部分键: {list(data_section.keys())}")
-        
-        if 'message_count' in data_section:
-            print(f"   📊 消息总数: {data_section['message_count']}")
-        
-        if 'messages' in data_section:
-            messages = data_section['messages']
-            print(f"   📊 消息列表长度: {len(messages)}")
-
-def analyze_messages(messages):
-    """详细分析消息结构"""
-    print(f"\n📨 消息详细分析:")
-    print(f"   总消息数: {len(messages)}")
-    
-    # 统计消息类型
-    message_types = {}
-    has_id_count = 0
-    has_timestamp_count = 0
-    has_tool_calls_count = 0
-    
-    print(f"\n   前5条消息样例:")
-    for i, msg in enumerate(messages[:5]):
-        print(f"   消息 {i+1}:")
-        print(f"     类型: {msg.get('type', 'unknown')}")
-        print(f"     内容长度: {len(str(msg.get('content', '')))}")
-        print(f"     是否有ID: {'id' in msg}")
-        print(f"     是否有时间戳: {'timestamp' in msg}")
-        print(f"     是否有工具调用: {'tool_calls' in msg}")
-        
-        if 'id' in msg:
-            print(f"     ID值: {msg['id']}")
-        if 'timestamp' in msg:
-            print(f"     时间戳: {msg['timestamp']}")
-        if 'tool_calls' in msg and msg['tool_calls']:
-            print(f"     工具调用数量: {len(msg['tool_calls']) if isinstance(msg['tool_calls'], list) else 'non-list'}")
-        
-        print(f"     所有字段: {list(msg.keys())}")
-        print()
-    
-    # 统计所有消息的类型和字段
-    for msg in messages:
-        msg_type = msg.get('type', 'unknown')
-        message_types[msg_type] = message_types.get(msg_type, 0) + 1
-        
-        if 'id' in msg:
-            has_id_count += 1
-        if 'timestamp' in msg:
-            has_timestamp_count += 1
-        if 'tool_calls' in msg:
-            has_tool_calls_count += 1
-    
-    print(f"   📊 消息类型统计: {message_types}")
-    print(f"   📊 包含ID的消息数: {has_id_count}/{len(messages)}")
-    print(f"   📊 包含时间戳的消息数: {has_timestamp_count}/{len(messages)}")
-    print(f"   📊 包含工具调用的消息数: {has_tool_calls_count}/{len(messages)}")
-
-def test_with_parameters():
-    """测试带参数的API调用(虽然可能不支持)"""
-    print("\n" + "=" * 60)
-    print("测试带参数的API调用")
-    print("=" * 60)
-    
-    base_url = "http://localhost:8084/api/v0/react/users/wang10/conversations/wang10:20250717211620915"
-    
-    test_params = [
-        {},
-        {"include_tools": "false"},
-        {"simplified": "true"},
-        {"include_tools": "false", "simplified": "true"}
-    ]
-    
-    for i, params in enumerate(test_params):
-        print(f"\n🧪 测试 {i+1}: 参数 = {params}")
-        
-        try:
-            response = requests.get(base_url, params=params, timeout=10)
-            print(f"   状态码: {response.status_code}")
-            
-            if response.status_code == 200:
-                data = response.json()
-                message_count = data.get('data', {}).get('message_count', 0)
-                print(f"   消息数量: {message_count}")
-                
-                # 检查是否有参数相关的字段
-                data_section = data.get('data', {})
-                if 'mode' in data_section:
-                    print(f"   模式: {data_section['mode']}")
-                if 'include_tools' in data_section:
-                    print(f"   include_tools: {data_section['include_tools']}")
-                if 'simplified' in data_section:
-                    print(f"   simplified: {data_section['simplified']}")
-            else:
-                print(f"   失败: {response.text[:100]}")
-                
-        except Exception as e:
-            print(f"   错误: {e}")
-
-def analyze_feasibility():
-    """基于实际数据分析可行性"""
-    print("\n" + "=" * 60)
-    print("需求可行性分析")
-    print("=" * 60)
-    
-    try:
-        with open('api_response_full.json', 'r', encoding='utf-8') as f:
-            data = json.load(f)
-        
-        messages = data.get('data', {}).get('messages', [])
-        
-        print(f"📋 基于 {len(messages)} 条消息的分析:")
-        
-        # 需求1: 过滤消息类型
-        human_messages = [msg for msg in messages if msg.get('type') == 'human']
-        ai_messages = [msg for msg in messages if msg.get('type') == 'ai']
-        tool_messages = [msg for msg in messages if msg.get('type') == 'tool']
-        
-        print(f"\n🎯 需求1 - 消息过滤:")
-        print(f"   Human消息: {len(human_messages)} 条")
-        print(f"   AI消息: {len(ai_messages)} 条")
-        print(f"   Tool消息: {len(tool_messages)} 条")
-        
-        # 分析AI消息中哪些有实际内容
-        ai_with_content = [msg for msg in ai_messages if msg.get('content', '').strip()]
-        ai_with_tools = [msg for msg in ai_messages if msg.get('tool_calls')]
-        
-        print(f"   有内容的AI消息: {len(ai_with_content)} 条")
-        print(f"   有工具调用的AI消息: {len(ai_with_tools)} 条")
-        
-        # 需求2: 时间戳分析
-        print(f"\n🕐 需求2 - 时间戳分析:")
-        messages_with_timestamp = [msg for msg in messages if 'timestamp' in msg]
-        messages_with_id = [msg for msg in messages if 'id' in msg]
-        
-        print(f"   有时间戳的消息: {len(messages_with_timestamp)} 条")
-        print(f"   有ID的消息: {len(messages_with_id)} 条")
-        
-        if messages_with_timestamp:
-            sample_timestamp = messages_with_timestamp[0]['timestamp']
-            print(f"   时间戳样例: {sample_timestamp}")
-            
-        if messages_with_id:
-            sample_id = messages_with_id[0]['id']
-            print(f"   ID样例: {sample_id}")
-        
-        # 可行性结论
-        print(f"\n✅ 可行性结论:")
-        print(f"   需求1 (消息过滤): {'✅ 可行' if human_messages and ai_with_content else '❌ 不可行'}")
-        print(f"   需求2 (真实时间戳): {'✅ 可行' if messages_with_timestamp else '❌ 需要进一步分析'}")
-        
-    except FileNotFoundError:
-        print("❌ 请先运行主测试获取数据")
-    except Exception as e:
-        print(f"❌ 分析失败: {e}")
-
-if __name__ == "__main__":
-    print(f"🚀 开始API分析测试 - {datetime.now()}")
-    
-    # 测试当前API
-    test_current_api()
-    
-    # 测试参数支持
-    test_with_parameters()
-    
-    # 分析可行性
-    analyze_feasibility()
-    
-    print(f"\n🏁 测试完成 - {datetime.now()}") 

+ 0 - 89
test_api_format.py

@@ -1,89 +0,0 @@
-#!/usr/bin/env python3
-"""
-测试API响应格式是否符合标准化要求
-验证是否包含 code 字段和其他必需字段
-"""
-import requests
-import json
-from datetime import datetime
-
-def test_api_response_format():
-    """测试API响应格式"""
-    base_url = "http://localhost:8084"
-    
-    # 测试用例
-    test_cases = [
-        {
-            "name": "获取用户对话列表",
-            "url": f"{base_url}/api/v0/react/users/wang10/conversations?limit=3",
-            "method": "GET"
-        },
-        {
-            "name": "获取特定对话详情",
-            "url": f"{base_url}/api/v0/react/users/wang10/conversations/wang10:20250717211620915",
-            "method": "GET"
-        }
-    ]
-    
-    print(f"🧪 开始测试API响应格式 - {datetime.now()}")
-    print("=" * 60)
-    
-    for i, test_case in enumerate(test_cases, 1):
-        print(f"\n📋 测试 {i}: {test_case['name']}")
-        print(f"🔗 URL: {test_case['url']}")
-        
-        try:
-            response = requests.get(test_case['url'], timeout=30)
-            
-            print(f"📊 HTTP状态码: {response.status_code}")
-            
-            if response.status_code == 200:
-                try:
-                    data = response.json()
-                    
-                    print(f"✅ JSON解析成功")
-                    
-                    # 检查必需字段
-                    required_fields = ["code", "success", "message", "data"]
-                    missing_fields = []
-                    
-                    for field in required_fields:
-                        if field not in data:
-                            missing_fields.append(field)
-                    
-                    if missing_fields:
-                        print(f"❌ 缺少必需字段: {missing_fields}")
-                    else:
-                        print(f"✅ 所有必需字段都存在")
-                        
-                        # 显示关键字段值
-                        print(f"📋 响应字段:")
-                        print(f"   - code: {data.get('code')}")
-                        print(f"   - success: {data.get('success')}")
-                        print(f"   - message: {data.get('message')}")
-                        print(f"   - data类型: {type(data.get('data'))}")
-                        
-                        if 'data' in data and isinstance(data['data'], dict):
-                            data_keys = list(data['data'].keys())
-                            print(f"   - data字段: {data_keys}")
-                    
-                    # 显示完整响应(格式化)
-                    print(f"\n📄 完整响应:")
-                    print(json.dumps(data, ensure_ascii=False, indent=2))
-                    
-                except json.JSONDecodeError as e:
-                    print(f"❌ JSON解析失败: {e}")
-                    print(f"📄 原始响应: {response.text}")
-            else:
-                print(f"❌ HTTP请求失败")
-                print(f"📄 响应内容: {response.text}")
-                
-        except requests.exceptions.RequestException as e:
-            print(f"❌ 请求异常: {e}")
-        
-        print("-" * 40)
-    
-    print(f"\n🏁 测试完成 - {datetime.now()}")
-
-if __name__ == "__main__":
-    test_api_response_format() 

+ 0 - 121
test_message_attributes.py

@@ -1,121 +0,0 @@
-#!/usr/bin/env python3
-"""
-测试LangChain消息对象的属性,查看是否包含id和时间戳信息
-"""
-import asyncio
-import sys
-import os
-from pathlib import Path
-
-# 添加项目路径
-project_root = Path(__file__).parent
-sys.path.insert(0, str(project_root))
-
-from react_agent.agent import CustomReactAgent
-
-async def test_message_attributes():
-    """测试消息对象的属性"""
-    print("=" * 60)
-    print("测试LangChain消息对象属性")
-    print("=" * 60)
-    
-    try:
-        # 初始化Agent
-        print("🚀 初始化Agent...")
-        agent = await CustomReactAgent.create()
-        
-        # 获取对话历史
-        thread_id = "wang10:20250717211620915"
-        print(f"📖 获取对话历史: {thread_id}")
-        
-        # 直接从checkpointer获取原始数据
-        thread_config = {"configurable": {"thread_id": thread_id}}
-        conversation_state = await agent.checkpointer.aget(thread_config)
-        
-        if not conversation_state:
-            print("❌ 未找到对话数据")
-            return
-        
-        messages = conversation_state.get('channel_values', {}).get('messages', [])
-        print(f"📊 找到 {len(messages)} 条原始消息")
-        
-        # 分析前5条消息的属性
-        print(f"\n🔍 分析前5条消息的所有属性:")
-        for i, msg in enumerate(messages[:5]):
-            print(f"\n消息 {i+1}:")
-            print(f"  类型: {type(msg).__name__}")
-            print(f"  内容长度: {len(str(msg.content))}")
-            
-            # 获取所有属性
-            all_attrs = dir(msg)
-            # 过滤出非私有属性
-            public_attrs = [attr for attr in all_attrs if not attr.startswith('_')]
-            print(f"  公共属性: {public_attrs}")
-            
-            # 检查关键属性
-            key_attrs = ['id', 'timestamp', 'created_at', 'time', 'date', 'additional_kwargs', 'response_metadata']
-            for attr in key_attrs:
-                if hasattr(msg, attr):
-                    value = getattr(msg, attr)
-                    print(f"  {attr}: {value} (类型: {type(value).__name__})")
-            
-            # 检查additional_kwargs和response_metadata
-            if hasattr(msg, 'additional_kwargs') and msg.additional_kwargs:
-                print(f"  additional_kwargs内容: {msg.additional_kwargs}")
-            
-            if hasattr(msg, 'response_metadata') and msg.response_metadata:
-                print(f"  response_metadata内容: {msg.response_metadata}")
-            
-            # 打印消息的dict表示(如果有的话)
-            if hasattr(msg, 'dict'):
-                try:
-                    msg_dict = msg.dict()
-                    print(f"  dict()方法返回的键: {list(msg_dict.keys())}")
-                except:
-                    pass
-        
-        # 检查conversation_state的其他信息
-        print(f"\n🔍 conversation_state的顶级键: {list(conversation_state.keys())}")
-        
-        # 检查是否有时间戳相关的元数据
-        for key, value in conversation_state.items():
-            if 'time' in key.lower() or 'date' in key.lower() or 'created' in key.lower():
-                print(f"  时间相关字段 {key}: {value}")
-        
-        await agent.close()
-        
-    except Exception as e:
-        print(f"❌ 测试失败: {e}")
-        import traceback
-        traceback.print_exc()
-
-async def test_create_new_message():
-    """测试创建新消息时是否自动添加时间戳"""
-    print(f"\n" + "=" * 60)
-    print("测试新建消息的属性")
-    print("=" * 60)
-    
-    try:
-        from langchain_core.messages import HumanMessage, AIMessage
-        from datetime import datetime
-        import uuid
-        
-        # 创建新消息
-        human_msg = HumanMessage(content="测试消息", id=str(uuid.uuid4()))
-        ai_msg = AIMessage(content="AI回复", id=str(uuid.uuid4()))
-        
-        print("🔍 新建HumanMessage属性:")
-        print(f"  id: {getattr(human_msg, 'id', 'None')}")
-        print(f"  所有属性: {[attr for attr in dir(human_msg) if not attr.startswith('_')]}")
-        
-        print("🔍 新建AIMessage属性:")
-        print(f"  id: {getattr(ai_msg, 'id', 'None')}")
-        print(f"  所有属性: {[attr for attr in dir(ai_msg) if not attr.startswith('_')]}")
-        
-    except Exception as e:
-        print(f"❌ 新消息测试失败: {e}")
-
-if __name__ == "__main__":
-    print(f"🚀 开始消息属性测试 - {asyncio.get_event_loop()}")
-    asyncio.run(test_message_attributes())
-    asyncio.run(test_create_new_message()) 

+ 0 - 103
test_new_api.py

@@ -1,103 +0,0 @@
-#!/usr/bin/env python3
-"""
-测试新的API实现
-"""
-import requests
-import json
-from datetime import datetime
-
-def test_api():
-    """测试新的API端点"""
-    print("=" * 60)
-    print("测试新的API实现")
-    print("=" * 60)
-    
-    base_url = "http://localhost:8084"
-    thread_id = "wang10:20250717211620915"
-    user_id = "wang10"
-    
-    # 测试不包含工具消息的API
-    print(f"\n🚀 测试API (不包含工具消息)...")
-    url = f"{base_url}/api/v0/react/users/{user_id}/conversations/{thread_id}"
-    
-    try:
-        response = requests.get(url, timeout=30)
-        print(f"📊 响应状态码: {response.status_code}")
-        
-        if response.status_code == 200:
-            data = response.json()
-            print(f"✅ API调用成功")
-            print(f"📝 响应结构:")
-            print(f"  success: {data.get('success')}")
-            print(f"  timestamp: {data.get('timestamp')}")
-            
-            if 'data' in data:
-                api_data = data['data']
-                print(f"  data.user_id: {api_data.get('user_id')}")
-                print(f"  data.thread_id: {api_data.get('thread_id')}")
-                print(f"  data.message_count: {api_data.get('message_count')}")
-                print(f"  data.created_at: {api_data.get('created_at')}")
-                print(f"  data.total_checkpoints: {api_data.get('total_checkpoints')}")
-                
-                messages = api_data.get('messages', [])
-                print(f"\n📋 前3条消息:")
-                for i, msg in enumerate(messages[:3]):
-                    print(f"  消息 {i+1}:")
-                    print(f"    id: {msg.get('id')}")
-                    print(f"    type: {msg.get('type')}")
-                    print(f"    timestamp: {msg.get('timestamp')}")
-                    print(f"    content: {msg.get('content', '')[:50]}...")
-            
-            # 保存完整响应到文件
-            with open('api_response_no_tools.json', 'w', encoding='utf-8') as f:
-                json.dump(data, f, ensure_ascii=False, indent=2)
-            print(f"\n💾 完整响应已保存到 api_response_no_tools.json")
-            
-        else:
-            print(f"❌ API调用失败")
-            print(f"响应内容: {response.text}")
-            
-    except Exception as e:
-        print(f"❌ 请求失败: {e}")
-    
-    # 测试包含工具消息的API
-    print(f"\n🚀 测试API (包含工具消息)...")
-    url_with_tools = f"{base_url}/api/v0/react/users/{user_id}/conversations/{thread_id}?include_tools=true"
-    
-    try:
-        response = requests.get(url_with_tools, timeout=30)
-        print(f"📊 响应状态码: {response.status_code}")
-        
-        if response.status_code == 200:
-            data = response.json()
-            print(f"✅ API调用成功")
-            
-            if 'data' in data:
-                api_data = data['data']
-                messages = api_data.get('messages', [])
-                print(f"📝 包含工具消息的总数: {len(messages)}")
-                
-                # 统计消息类型
-                type_counts = {}
-                for msg in messages:
-                    msg_type = msg.get('type', 'unknown')
-                    type_counts[msg_type] = type_counts.get(msg_type, 0) + 1
-                
-                print(f"📊 消息类型统计:")
-                for msg_type, count in type_counts.items():
-                    print(f"  {msg_type}: {count}")
-            
-            # 保存完整响应到文件
-            with open('api_response_with_tools.json', 'w', encoding='utf-8') as f:
-                json.dump(data, f, ensure_ascii=False, indent=2)
-            print(f"\n💾 完整响应已保存到 api_response_with_tools.json")
-            
-        else:
-            print(f"❌ API调用失败")
-            print(f"响应内容: {response.text}")
-            
-    except Exception as e:
-        print(f"❌ 请求失败: {e}")
-
-if __name__ == "__main__":
-    test_api() 

+ 0 - 88
test_new_method.py

@@ -1,88 +0,0 @@
-#!/usr/bin/env python3
-"""
-直接测试新的get_conversation_history方法
-"""
-import asyncio
-import sys
-import json
-from pathlib import Path
-
-# 添加项目路径
-project_root = Path(__file__).parent
-sys.path.insert(0, str(project_root))
-
-from react_agent.agent import CustomReactAgent
-
-async def test_new_method():
-    """测试新的get_conversation_history方法"""
-    print("=" * 60)
-    print("直接测试新的get_conversation_history方法")
-    print("=" * 60)
-    
-    try:
-        # 初始化Agent
-        print("🚀 初始化Agent...")
-        agent = await CustomReactAgent.create()
-        
-        thread_id = "wang10:20250717211620915"
-        print(f"\n📖 测试Thread: {thread_id}")
-        
-        # 测试不包含工具消息
-        print(f"\n🔍 测试不包含工具消息...")
-        result = await agent.get_conversation_history(thread_id, include_tools=False)
-        
-        print(f"📊 结果类型: {type(result)}")
-        print(f"📝 结果键: {list(result.keys()) if isinstance(result, dict) else 'Not a dict'}")
-        
-        if isinstance(result, dict):
-            messages = result.get("messages", [])
-            print(f"💬 消息数量: {len(messages)}")
-            print(f"🕐 线程创建时间: {result.get('thread_created_at')}")
-            print(f"📋 总checkpoint数: {result.get('total_checkpoints')}")
-            
-            if messages:
-                print(f"\n📋 前3条消息:")
-                for i, msg in enumerate(messages[:3]):
-                    print(f"  消息 {i+1}:")
-                    print(f"    id: {msg.get('id')}")
-                    print(f"    type: {msg.get('type')}")
-                    print(f"    timestamp: {msg.get('timestamp')}")
-                    print(f"    content: {str(msg.get('content', ''))[:50]}...")
-            
-            # 保存结果
-            with open('direct_method_test_no_tools.json', 'w', encoding='utf-8') as f:
-                json.dump(result, f, ensure_ascii=False, indent=2)
-            print(f"\n💾 结果已保存到 direct_method_test_no_tools.json")
-        
-        # 测试包含工具消息
-        print(f"\n🔍 测试包含工具消息...")
-        result_with_tools = await agent.get_conversation_history(thread_id, include_tools=True)
-        
-        if isinstance(result_with_tools, dict):
-            messages_with_tools = result_with_tools.get("messages", [])
-            print(f"💬 包含工具的消息数量: {len(messages_with_tools)}")
-            
-            # 统计消息类型
-            type_counts = {}
-            for msg in messages_with_tools:
-                msg_type = msg.get('type', 'unknown')
-                type_counts[msg_type] = type_counts.get(msg_type, 0) + 1
-            
-            print(f"📊 消息类型统计:")
-            for msg_type, count in type_counts.items():
-                print(f"  {msg_type}: {count}")
-            
-            # 保存结果
-            with open('direct_method_test_with_tools.json', 'w', encoding='utf-8') as f:
-                json.dump(result_with_tools, f, ensure_ascii=False, indent=2)
-            print(f"\n💾 结果已保存到 direct_method_test_with_tools.json")
-        
-        await agent.close()
-        
-    except Exception as e:
-        print(f"❌ 测试失败: {e}")
-        import traceback
-        traceback.print_exc()
-
-if __name__ == "__main__":
-    asyncio.run(test_new_method()) 

+ 0 - 188
test_state_history_timestamps.py

@@ -1,188 +0,0 @@
-#!/usr/bin/env python3
-"""
-测试LangGraph StateSnapshot的created_at时间戳
-"""
-import asyncio
-import sys
-from pathlib import Path
-from datetime import datetime
-
-# 添加项目路径
-project_root = Path(__file__).parent
-sys.path.insert(0, str(project_root))
-
-from react_agent.agent import CustomReactAgent
-
-async def test_state_history_timestamps():
-    """测试StateSnapshot的created_at时间戳"""
-    print("=" * 60)
-    print("测试LangGraph StateSnapshot的created_at时间戳")
-    print("=" * 60)
-    
-    try:
-        # 初始化Agent
-        print("🚀 初始化Agent...")
-        agent = await CustomReactAgent.create()
-        
-        thread_id = "wang10:20250717211620915"
-        print(f"\n📖 分析Thread: {thread_id}")
-        
-        # 使用get_state_history获取所有历史状态
-        thread_config = {"configurable": {"thread_id": thread_id}}
-        
-        print(f"🔍 获取状态历史...")
-        # agent_executor是编译后的graph
-        if hasattr(agent, 'agent_executor') and hasattr(agent.agent_executor, 'get_state_history'):
-            print(f"✅ 找到get_state_history方法")
-            
-            # 获取前5个历史状态
-            history_count = 0
-            for state_snapshot in agent.agent_executor.get_state_history(thread_config):
-                history_count += 1
-                if history_count > 5:  # 只看前5个状态
-                    break
-                
-                print(f"\n📊 状态 #{history_count}:")
-                print(f"  🆔 Checkpoint ID: {state_snapshot.config.get('configurable', {}).get('checkpoint_id', 'N/A')}")
-                print(f"  ⏰ Created At: {state_snapshot.created_at}")
-                print(f"  📝 Messages Count: {len(state_snapshot.values.get('messages', []))}")
-                print(f"  🔄 Next: {state_snapshot.next}")
-                print(f"  📋 Step: {state_snapshot.metadata.get('step', 'N/A')}")
-                
-                # 解析时间戳
-                if state_snapshot.created_at:
-                    try:
-                        dt = datetime.fromisoformat(state_snapshot.created_at.replace('Z', '+00:00'))
-                        print(f"  📅 解析后时间: {dt}")
-                        print(f"  🕐 本地时间: {dt.astimezone()}")
-                    except Exception as e:
-                        print(f"  ❌ 时间解析失败: {e}")
-                
-                # 如果有消息,显示最后一条消息的类型
-                messages = state_snapshot.values.get('messages', [])
-                if messages:
-                    last_msg = messages[-1]
-                    msg_type = getattr(last_msg, 'type', 'unknown')
-                    content_preview = str(getattr(last_msg, 'content', ''))[:50]
-                    print(f"  💬 最后消息: {msg_type} - {content_preview}...")
-            
-            if history_count == 0:
-                print("❌ 没有找到历史状态")
-            else:
-                print(f"\n✅ 总共分析了 {history_count} 个历史状态")
-                
-        else:
-            print("❌ 未找到get_state_history方法")
-            print("📝 可用方法:")
-            if hasattr(agent, 'agent_executor'):
-                methods = [m for m in dir(agent.agent_executor) if not m.startswith('_')]
-                print(f"  agent_executor methods: {methods}")
-            
-        await agent.close()
-        
-    except Exception as e:
-        print(f"❌ 测试失败: {e}")
-        import traceback
-        traceback.print_exc()
-
-async def test_current_state_timestamp():
-    """测试当前状态的时间戳"""
-    print(f"\n" + "=" * 60)
-    print("测试当前状态的时间戳")
-    print("=" * 60)
-    
-    try:
-        # 初始化Agent
-        agent = await CustomReactAgent.create()
-        
-        thread_id = "wang10:20250717211620915"
-        thread_config = {"configurable": {"thread_id": thread_id}}
-        
-        print(f"🔍 获取当前状态...")
-        if hasattr(agent, 'agent_executor') and hasattr(agent.agent_executor, 'get_state'):
-            current_state = agent.agent_executor.get_state(thread_config)
-            
-            print(f"📊 当前状态:")
-            print(f"  🆔 Checkpoint ID: {current_state.config.get('configurable', {}).get('checkpoint_id', 'N/A')}")
-            print(f"  ⏰ Created At: {current_state.created_at}")
-            print(f"  📝 Messages Count: {len(current_state.values.get('messages', []))}")
-            print(f"  🔄 Next: {current_state.next}")
-            
-            if current_state.created_at:
-                try:
-                    dt = datetime.fromisoformat(current_state.created_at.replace('Z', '+00:00'))
-                    print(f"  📅 解析后时间: {dt}")
-                    print(f"  🕐 本地时间: {dt.astimezone()}")
-                except Exception as e:
-                    print(f"  ❌ 时间解析失败: {e}")
-        else:
-            print("❌ 未找到get_state方法")
-            
-        await agent.close()
-        
-    except Exception as e:
-        print(f"❌ 测试失败: {e}")
-        import traceback
-        traceback.print_exc()
-
-async def test_checkpointer_access():
-    """测试直接通过checkpointer访问历史"""
-    print(f"\n" + "=" * 60)
-    print("测试通过checkpointer访问历史")
-    print("=" * 60)
-    
-    try:
-        # 初始化Agent
-        agent = await CustomReactAgent.create()
-        
-        thread_id = "wang10:20250717211620915"
-        thread_config = {"configurable": {"thread_id": thread_id}}
-        
-        print(f"🔍 通过checkpointer获取历史...")
-        if hasattr(agent, 'checkpointer') and hasattr(agent.checkpointer, 'alist'):
-            print(f"✅ 找到checkpointer.alist方法")
-            
-            # 获取前5个checkpoint
-            history_count = 0
-            async for checkpoint_tuple in agent.checkpointer.alist(thread_config):
-                history_count += 1
-                if history_count > 5:  # 只看前5个状态
-                    break
-                
-                print(f"\n📊 Checkpoint #{history_count}:")
-                print(f"  🆔 Config: {checkpoint_tuple.config}")
-                print(f"  ⏰ Checkpoint TS: {checkpoint_tuple.checkpoint.get('ts', 'N/A')}")
-                print(f"  📋 Metadata: {checkpoint_tuple.metadata}")
-                
-                # 解析checkpoint中的时间戳
-                ts_value = checkpoint_tuple.checkpoint.get('ts')
-                if ts_value:
-                    try:
-                        dt = datetime.fromisoformat(ts_value.replace('Z', '+00:00'))
-                        print(f"  📅 解析后时间: {dt}")
-                        print(f"  🕐 本地时间: {dt.astimezone()}")
-                    except Exception as e:
-                        print(f"  ❌ 时间解析失败: {e}")
-                
-                # 检查消息
-                messages = checkpoint_tuple.checkpoint.get('channel_values', {}).get('messages', [])
-                print(f"  📝 Messages Count: {len(messages)}")
-                
-            if history_count == 0:
-                print("❌ 没有找到checkpoint历史")
-            else:
-                print(f"\n✅ 总共分析了 {history_count} 个checkpoint")
-        else:
-            print("❌ 未找到checkpointer.alist方法")
-            
-        await agent.close()
-        
-    except Exception as e:
-        print(f"❌ 测试失败: {e}")
-        import traceback
-        traceback.print_exc()
-
-if __name__ == "__main__":
-    asyncio.run(test_state_history_timestamps())
-    asyncio.run(test_current_state_timestamp())
-    asyncio.run(test_checkpointer_access()) 

+ 0 - 109
test_timestamp.py

@@ -1,109 +0,0 @@
-#!/usr/bin/env python3
-"""
-检查conversation_state中的时间戳信息
-"""
-import asyncio
-import sys
-from pathlib import Path
-from datetime import datetime
-
-# 添加项目路径
-project_root = Path(__file__).parent
-sys.path.insert(0, str(project_root))
-
-from react_agent.agent import CustomReactAgent
-
-async def test_timestamp_info():
-    """检查时间戳相关信息"""
-    print("=" * 60)
-    print("检查时间戳信息")
-    print("=" * 60)
-    
-    try:
-        # 初始化Agent
-        print("🚀 初始化Agent...")
-        agent = await CustomReactAgent.create()
-        
-        # 获取对话历史
-        thread_id = "wang10:20250717211620915"
-        print(f"📖 获取对话历史: {thread_id}")
-        
-        # 直接从checkpointer获取原始数据
-        thread_config = {"configurable": {"thread_id": thread_id}}
-        conversation_state = await agent.checkpointer.aget(thread_config)
-        
-        if not conversation_state:
-            print("❌ 未找到对话数据")
-            return
-        
-        # 检查conversation_state的时间戳信息
-        print(f"\n🔍 conversation_state详细信息:")
-        for key, value in conversation_state.items():
-            print(f"  {key}: {value} (类型: {type(value).__name__})")
-        
-        # 特别关注ts字段
-        if 'ts' in conversation_state:
-            ts_value = conversation_state['ts']
-            print(f"\n⏰ 时间戳分析:")
-            print(f"  原始ts值: {ts_value}")
-            print(f"  ts类型: {type(ts_value).__name__}")
-            
-            # 尝试解析时间戳
-            if isinstance(ts_value, (int, float)):
-                # 可能是Unix时间戳
-                try:
-                    if ts_value > 1000000000000:  # 毫秒时间戳
-                        dt = datetime.fromtimestamp(ts_value / 1000)
-                        print(f"  解析为毫秒时间戳: {dt}")
-                    else:  # 秒时间戳
-                        dt = datetime.fromtimestamp(ts_value)
-                        print(f"  解析为秒时间戳: {dt}")
-                except:
-                    print(f"  时间戳解析失败")
-            elif isinstance(ts_value, str):
-                # 可能是ISO格式字符串
-                try:
-                    dt = datetime.fromisoformat(ts_value.replace('Z', '+00:00'))
-                    print(f"  解析为ISO时间: {dt}")
-                except:
-                    print(f"  字符串时间戳解析失败")
-        
-        # 检查thread_id中的时间信息
-        print(f"\n🔍 Thread ID时间分析:")
-        print(f"  Thread ID: {thread_id}")
-        if ':' in thread_id:
-            parts = thread_id.split(':')
-            if len(parts) >= 2:
-                timestamp_part = parts[1]  # wang10:20250717211620915
-                print(f"  时间戳部分: {timestamp_part}")
-                
-                # 尝试解析thread_id中的时间戳
-                if len(timestamp_part) >= 14:
-                    try:
-                        year = timestamp_part[:4]
-                        month = timestamp_part[4:6] 
-                        day = timestamp_part[6:8]
-                        hour = timestamp_part[8:10]
-                        minute = timestamp_part[10:12]
-                        second = timestamp_part[12:14]
-                        ms = timestamp_part[14:] if len(timestamp_part) > 14 else "000"
-                        
-                        dt_str = f"{year}-{month}-{day} {hour}:{minute}:{second}.{ms}"
-                        print(f"  解析为: {dt_str}")
-                        
-                        # 创建datetime对象
-                        dt = datetime.strptime(f"{year}-{month}-{day} {hour}:{minute}:{second}", "%Y-%m-%d %H:%M:%S")
-                        print(f"  DateTime对象: {dt}")
-                        
-                    except Exception as e:
-                        print(f"  Thread ID时间解析失败: {e}")
-        
-        await agent.close()
-        
-    except Exception as e:
-        print(f"❌ 测试失败: {e}")
-        import traceback
-        traceback.print_exc()
-
-if __name__ == "__main__":
-    asyncio.run(test_timestamp_info()) 

+ 0 - 166
test_ts_meaning.py

@@ -1,166 +0,0 @@
-#!/usr/bin/env python3
-"""
-测试conversation_state['ts']的确切含义
-"""
-import asyncio
-import sys
-from pathlib import Path
-from datetime import datetime
-
-# 添加项目路径
-project_root = Path(__file__).parent
-sys.path.insert(0, str(project_root))
-
-from react_agent.agent import CustomReactAgent
-
-async def test_ts_meaning():
-    """测试ts字段的含义"""
-    print("=" * 60)
-    print("测试conversation_state['ts']的含义")
-    print("=" * 60)
-    
-    try:
-        # 初始化Agent
-        print("🚀 初始化Agent...")
-        agent = await CustomReactAgent.create()
-        
-        # 测试多个不同的thread_id
-        thread_ids = [
-            "wang10:20250717211620915",  # 原始的长对话
-            # 如果有其他thread_id可以添加
-        ]
-        
-        for thread_id in thread_ids:
-            print(f"\n📖 分析Thread: {thread_id}")
-            
-            # 从checkpointer获取原始数据
-            thread_config = {"configurable": {"thread_id": thread_id}}
-            conversation_state = await agent.checkpointer.aget(thread_config)
-            
-            if not conversation_state:
-                print(f"  ❌ 未找到对话数据")
-                continue
-            
-            # 分析时间戳
-            ts_value = conversation_state.get('ts')
-            messages = conversation_state.get('channel_values', {}).get('messages', [])
-            
-            print(f"  📊 消息总数: {len(messages)}")
-            print(f"  ⏰ conversation_state['ts']: {ts_value}")
-            
-            # 解析时间戳
-            if ts_value:
-                try:
-                    dt = datetime.fromisoformat(ts_value.replace('Z', '+00:00'))
-                    print(f"  ⏰ 解析后的时间: {dt}")
-                except:
-                    print(f"  ❌ 时间戳解析失败")
-            
-            # 分析Thread ID中的时间
-            if ':' in thread_id:
-                parts = thread_id.split(':')
-                if len(parts) >= 2:
-                    timestamp_part = parts[1]
-                    if len(timestamp_part) >= 14:
-                        try:
-                            year = timestamp_part[:4]
-                            month = timestamp_part[4:6] 
-                            day = timestamp_part[6:8]
-                            hour = timestamp_part[8:10]
-                            minute = timestamp_part[10:12]
-                            second = timestamp_part[12:14]
-                            ms = timestamp_part[14:] if len(timestamp_part) > 14 else "000"
-                            
-                            thread_dt = datetime.strptime(f"{year}-{month}-{day} {hour}:{minute}:{second}", "%Y-%m-%d %H:%M:%S")
-                            print(f"  🆔 Thread ID时间: {thread_dt}")
-                            
-                            # 比较两个时间
-                            if ts_value:
-                                ts_dt = datetime.fromisoformat(ts_value.replace('Z', '+00:00')).replace(tzinfo=None)
-                                time_diff = (ts_dt - thread_dt).total_seconds()
-                                print(f"  🔄 时间差: {time_diff:.2f} 秒 (ts - thread_time)")
-                                
-                                if abs(time_diff) < 60:
-                                    print(f"    💡 时间差很小,ts可能是对话开始时间")
-                                else:
-                                    print(f"    💡 时间差较大,ts可能是最后更新时间")
-                        except Exception as e:
-                            print(f"  ❌ Thread ID时间解析失败: {e}")
-            
-            # 检查其他可能的时间字段
-            print(f"  🔍 conversation_state所有字段:")
-            for key, value in conversation_state.items():
-                if 'time' in key.lower() or 'date' in key.lower() or 'created' in key.lower() or 'updated' in key.lower():
-                    print(f"    {key}: {value}")
-        
-        await agent.close()
-        
-    except Exception as e:
-        print(f"❌ 测试失败: {e}")
-        import traceback
-        traceback.print_exc()
-
-async def create_test_conversation():
-    """创建一个测试对话来观察ts的变化"""
-    print(f"\n" + "=" * 60)
-    print("创建测试对话观察ts变化")
-    print("=" * 60)
-    
-    try:
-        # 初始化Agent
-        agent = await CustomReactAgent.create()
-        
-        # 创建新的测试对话
-        test_user = "test_user"
-        test_message = "你好,这是一个测试消息"
-        
-        print(f"🚀 发送测试消息...")
-        result = await agent.chat(test_message, test_user)
-        
-        if result.get('success'):
-            thread_id = result.get('thread_id')
-            print(f"✅ 对话创建成功,Thread ID: {thread_id}")
-            
-            # 立即检查ts
-            thread_config = {"configurable": {"thread_id": thread_id}}
-            conversation_state = await agent.checkpointer.aget(thread_config)
-            
-            if conversation_state:
-                ts_value = conversation_state.get('ts')
-                messages = conversation_state.get('channel_values', {}).get('messages', [])
-                
-                print(f"📊 首次对话后:")
-                print(f"  消息数量: {len(messages)}")
-                print(f"  ts值: {ts_value}")
-                
-                # 发送第二条消息
-                print(f"\n🚀 发送第二条消息...")
-                result2 = await agent.chat("这是第二条消息", test_user, thread_id)
-                
-                if result2.get('success'):
-                    # 再次检查ts
-                    conversation_state2 = await agent.checkpointer.aget(thread_config)
-                    
-                    if conversation_state2:
-                        ts_value2 = conversation_state2.get('ts')
-                        messages2 = conversation_state2.get('channel_values', {}).get('messages', [])
-                        
-                        print(f"📊 第二次对话后:")
-                        print(f"  消息数量: {len(messages2)}")
-                        print(f"  ts值: {ts_value2}")
-                        
-                        # 比较两次的ts
-                        if ts_value != ts_value2:
-                            print(f"  💡 ts值发生了变化!这说明ts是最后更新时间")
-                        else:
-                            print(f"  💡 ts值没有变化,可能是创建时间")
-        
-        await agent.close()
-        
-    except Exception as e:
-        print(f"❌ 测试对话创建失败: {e}")
-
-if __name__ == "__main__":
-    asyncio.run(test_ts_meaning())
-    # 注释掉测试对话创建,避免产生过多测试数据
-    # asyncio.run(create_test_conversation())