Browse Source

规范化获取ask_react_agent对话历史记录的API,返回结果符合标准。

wangxq 1 month ago
parent
commit
52c3eb150b
3 changed files with 363 additions and 93 deletions
  1. 1 0
      common/result.py
  2. 182 15
      react_agent/enhanced_redis_api.py
  3. 180 78
      unified_api.py

+ 1 - 0
common/result.py

@@ -58,6 +58,7 @@ def success_response(response_text=None, data=None, message=MessageTemplate.SUCC
     response_data = data or {}
     if response_text is not None:
         response_data["response"] = response_text
+    response_data["timestamp"] = datetime.now().isoformat()
     
     return {
         "code": code,

+ 182 - 15
react_agent/enhanced_redis_api.py

@@ -105,12 +105,53 @@ def get_conversation_detail_from_redis(thread_id: str, include_tools: bool = Fal
         messages = extract_messages_from_checkpoint(checkpoint_data)
         logger.info(f"🔍 找到 {len(messages)} 条原始消息")
         
-        # 解析并过滤消息 - 这里是关键的开关逻辑
-        parsed_messages = parse_and_filter_messages(messages, include_tools)
+        # 🔑 关键改进:构建消息ID到时间戳的映射(模仿LangGraph API)
+        logger.info(f"🔍 开始构建消息时间戳映射...")
+        message_timestamps = _build_message_timestamp_map_from_redis(redis_client, thread_id)
+        
+        # 提取最新checkpoint时间戳作为备用
+        checkpoint_ts = None
+        if ('checkpoint' in checkpoint_data and 
+            isinstance(checkpoint_data['checkpoint'], dict) and 
+            'ts' in checkpoint_data['checkpoint']):
+            
+            ts_value = checkpoint_data['checkpoint']['ts']
+            if isinstance(ts_value, str):
+                try:
+                    # 转换为中国时区格式
+                    from datetime import datetime
+                    import pytz
+                    dt = datetime.fromisoformat(ts_value.replace('Z', '+00:00'))
+                    china_tz = pytz.timezone('Asia/Shanghai')
+                    china_dt = dt.astimezone(china_tz)
+                    checkpoint_ts = china_dt.strftime('%Y-%m-%d %H:%M:%S.%f')[:-3]
+                    logger.info(f"🕒 备用checkpoint时间戳: {checkpoint_ts}")
+                except Exception as e:
+                    logger.warning(f"⚠️ 时间戳转换失败: {e}")
+        
+        # 解析并过滤消息 - 使用消息时间戳映射
+        parsed_messages = parse_and_filter_messages(messages, include_tools, checkpoint_ts, message_timestamps)
         
         # 提取用户ID
         user_id = thread_id.split(':')[0] if ':' in thread_id else 'unknown'
         
+        # 解析created_at时间(从thread_id中提取)
+        created_at = None
+        if ':' in thread_id:
+            try:
+                timestamp_str = thread_id.split(':')[1]
+                # 转换为中国时区格式
+                from datetime import datetime
+                import pytz
+                # 假设timestamp是YYYYMMDDHHmmssSSS格式
+                dt = datetime.strptime(timestamp_str, '%Y%m%d%H%M%S%f')
+                china_tz = pytz.timezone('Asia/Shanghai')
+                china_dt = china_tz.localize(dt)
+                created_at = china_dt.strftime('%Y-%m-%d %H:%M:%S.%f')[:-3]
+                logger.info(f"🕒 解析created_at: {created_at}")
+            except Exception as e:
+                logger.warning(f"⚠️ 解析created_at失败: {e}")
+        
         # 生成对话统计信息
         stats = generate_conversation_stats(parsed_messages, include_tools)
         
@@ -120,6 +161,8 @@ def get_conversation_detail_from_redis(thread_id: str, include_tools: bool = Fal
             "success": True,
             "data": {
                 "thread_id": thread_id,
+                "conversation_id": thread_id,  # 添加conversation_id字段
+                "created_at": created_at,  # 添加created_at字段
                 "user_id": user_id,
                 "include_tools": include_tools,
                 "message_count": len(parsed_messages),
@@ -166,7 +209,113 @@ def extract_messages_from_checkpoint(checkpoint_data: Dict[str, Any]) -> List[An
     
     return messages
 
-def parse_and_filter_messages(raw_messages: List[Any], include_tools: bool) -> List[Dict[str, Any]]:
+def _build_message_timestamp_map_from_redis(redis_client, thread_id: str) -> Dict[str, str]:
+    """
+    构建消息ID到时间戳的映射,模仿LangGraph API的逻辑
+    遍历所有历史checkpoint,为每条消息记录其首次出现的时间戳
+    """
+    message_timestamps = {}
+    
+    try:
+        # 获取所有checkpoint keys
+        pattern = f"checkpoint:{thread_id}:*"
+        keys = []
+        cursor = 0
+        while True:
+            cursor, batch = redis_client.scan(cursor=cursor, match=pattern, count=1000)
+            keys.extend(batch)
+            if cursor == 0:
+                break
+        
+        if not keys:
+            logger.warning(f"⚠️ 未找到任何checkpoint keys: {pattern}")
+            return message_timestamps
+        
+        # 获取所有checkpoint数据并按时间戳排序
+        checkpoints_with_ts = []
+        
+        for key in keys:
+            try:
+                # 检查key类型并获取数据
+                key_type = redis_client.type(key)
+                data = None
+                
+                if key_type == 'string':
+                    data = redis_client.get(key)
+                elif key_type == 'ReJSON-RL':
+                    data = redis_client.execute_command('JSON.GET', key)
+                else:
+                    continue
+                
+                if not data:
+                    continue
+                
+                # 解析checkpoint数据
+                checkpoint_data = json.loads(data)
+                
+                # 提取时间戳
+                checkpoint_ts = None
+                if ('checkpoint' in checkpoint_data and 
+                    isinstance(checkpoint_data['checkpoint'], dict) and 
+                    'ts' in checkpoint_data['checkpoint']):
+                    
+                    ts_value = checkpoint_data['checkpoint']['ts']
+                    if isinstance(ts_value, str):
+                        try:
+                            # 转换为中国时区格式
+                            from datetime import datetime
+                            import pytz
+                            dt = datetime.fromisoformat(ts_value.replace('Z', '+00:00'))
+                            china_tz = pytz.timezone('Asia/Shanghai')
+                            china_dt = dt.astimezone(china_tz)
+                            checkpoint_ts = china_dt.strftime('%Y-%m-%d %H:%M:%S.%f')[:-3]
+                        except Exception as e:
+                            logger.warning(f"⚠️ 解析时间戳失败 {key}: {e}")
+                            continue
+                
+                if checkpoint_ts:
+                    checkpoints_with_ts.append({
+                        'key': key,
+                        'timestamp': checkpoint_ts,
+                        'data': checkpoint_data,
+                        'raw_ts': ts_value  # 用于排序
+                    })
+                    
+            except Exception as e:
+                logger.warning(f"⚠️ 处理checkpoint失败 {key}: {e}")
+                continue
+        
+        # 按时间戳排序(最早的在前)
+        checkpoints_with_ts.sort(key=lambda x: x['raw_ts'])
+        
+        logger.info(f"🔍 找到 {len(checkpoints_with_ts)} 个有效checkpoint,按时间排序")
+        
+        # 遍历每个checkpoint,为新消息分配时间戳
+        for checkpoint_info in checkpoints_with_ts:
+            checkpoint_data = checkpoint_info['data']
+            checkpoint_ts = checkpoint_info['timestamp']
+            
+            # 提取消息
+            messages = extract_messages_from_checkpoint(checkpoint_data)
+            
+            # 为这个checkpoint中的新消息分配时间戳
+            for msg in messages:
+                if isinstance(msg, dict) and 'kwargs' in msg:
+                    msg_id = msg['kwargs'].get('id')
+                    if msg_id and msg_id not in message_timestamps:
+                        message_timestamps[msg_id] = checkpoint_ts
+                        logger.debug(f"🕒 消息 {msg_id} 分配时间戳: {checkpoint_ts}")
+        
+        logger.info(f"✅ 成功构建消息时间戳映射,包含 {len(message_timestamps)} 条消息")
+        
+    except Exception as e:
+        logger.error(f"❌ 构建消息时间戳映射失败: {e}")
+        import traceback
+        traceback.print_exc()
+    
+    return message_timestamps
+
+def parse_and_filter_messages(raw_messages: List[Any], include_tools: bool, checkpoint_ts: str = None, message_timestamps: Dict[str, str] = None) -> List[Dict[str, Any]]:
     """
     解析和过滤消息列表 - 关键的开关逻辑实现
     
@@ -183,11 +332,22 @@ def parse_and_filter_messages(raw_messages: List[Any], include_tools: bool) -> L
     
     for msg in raw_messages:
         try:
-            parsed_msg = parse_single_message(msg)
+            # 获取消息ID,用于查找其真实时间戳
+            msg_id = None
+            if isinstance(msg, dict) and 'kwargs' in msg:
+                msg_id = msg['kwargs'].get('id')
+            
+            # 使用消息映射中的时间戳,如果没有则使用checkpoint时间戳
+            msg_timestamp = checkpoint_ts
+            if message_timestamps and msg_id and msg_id in message_timestamps:
+                msg_timestamp = message_timestamps[msg_id]
+                logger.debug(f"🕒 使用消息映射时间戳: {msg_id} -> {msg_timestamp}")
+            
+            parsed_msg = parse_single_message(msg, msg_timestamp)
             if not parsed_msg:
                 continue
             
-            msg_type = parsed_msg['type']
+            msg_type = parsed_msg['role']  # 使用新的字段名
             
             if include_tools:
                 # 完整模式:包含所有消息类型
@@ -222,9 +382,13 @@ def parse_and_filter_messages(raw_messages: List[Any], include_tools: bool) -> L
     logger.info(f"📊 解析结果: {len(parsed_messages)} 条消息 (include_tools={include_tools})")
     return parsed_messages
 
-def parse_single_message(msg: Any) -> Optional[Dict[str, Any]]:
+def parse_single_message(msg: Any, checkpoint_ts: str = None) -> Optional[Dict[str, Any]]:
     """
     解析单个消息,支持LangChain序列化格式
+    
+    Args:
+        msg: 原始消息数据
+        checkpoint_ts: checkpoint的时间戳,用作消息的真实时间(备用)
     """
     if isinstance(msg, dict):
         # LangChain序列化格式
@@ -249,12 +413,15 @@ def parse_single_message(msg: Any) -> Optional[Dict[str, Any]]:
             else:
                 msg_type = 'unknown'
             
-            # 构建基础消息对象
+            # 使用传入的时间戳(现在将通过消息ID映射获得)
+            final_timestamp = checkpoint_ts or datetime.now().isoformat()
+            
+            # 构建基础消息对象 - 修改字段名称
             parsed_msg = {
-                "type": msg_type,
+                "role": msg_type,  # type -> role
                 "content": kwargs.get('content', ''),
-                "id": kwargs.get('id'),
-                "timestamp": datetime.now().isoformat()
+                "message_id": kwargs.get('id'),  # id -> message_id
+                "timestamp": final_timestamp  # 使用消息自己的时间戳或备用时间戳
             }
             
             # 处理AI消息的特殊字段
@@ -284,10 +451,10 @@ def parse_single_message(msg: Any) -> Optional[Dict[str, Any]]:
         # 简单字典格式
         elif 'type' in msg:
             return {
-                "type": msg.get('type', 'unknown'),
+                "role": msg.get('type', 'unknown'),  # type -> role
                 "content": msg.get('content', ''),
-                "id": msg.get('id'),
-                "timestamp": datetime.now().isoformat()
+                "message_id": msg.get('id'),  # id -> message_id
+                "timestamp": checkpoint_ts or datetime.now().isoformat()  # 使用真实时间戳
             }
     
     return None
@@ -300,9 +467,9 @@ def clean_ai_message_for_simple_mode(ai_msg: Dict[str, Any]) -> Dict[str, Any]:
     logger.info(f"🔍 清理AI消息,原始内容: '{original_content}', 长度: {len(original_content)}")
     
     cleaned_msg = {
-        "type": ai_msg["type"],
+        "role": ai_msg["role"],  # 使用新的字段名
         "content": original_content,
-        "id": ai_msg.get("id"),
+        "message_id": ai_msg.get("message_id"),  # 使用新的字段名
         "timestamp": ai_msg.get("timestamp")
     }
     

+ 180 - 78
unified_api.py

@@ -24,10 +24,13 @@ from core.logging import initialize_logging, get_app_logger
 initialize_logging()
 
 # 标准 Flask 导入
-from flask import Flask, request, jsonify, session, send_file
+from flask import Flask, request, jsonify, session, send_file, Response, stream_with_context
 import redis.asyncio as redis
 from werkzeug.utils import secure_filename
 
+# 导入标准化响应格式
+from common.result import success_response, internal_error_response, bad_request_response
+
 # 基础依赖
 import pandas as pd
 import json
@@ -100,6 +103,121 @@ def _format_timestamp_to_china_time(timestamp_str):
         logger.warning(f"⚠️ 时间格式化失败: {e}")
         return timestamp_str
 
+def _parse_conversation_created_time(conversation_id: str) -> Optional[str]:
+    """从conversation_id解析创建时间并转换为中国时区格式"""
+    try:
+        # conversation_id格式: "wang10:20250717211620915"
+        if ':' not in conversation_id:
+            return None
+        
+        parts = conversation_id.split(':')
+        if len(parts) < 2:
+            return None
+        
+        timestamp_str = parts[1]  # "20250717211620915"
+        
+        # 解析时间戳: YYYYMMDDHHMMSSMMM (17位)
+        if len(timestamp_str) != 17:
+            logger.warning(f"⚠️ conversation_id时间戳长度不正确: {timestamp_str}")
+            return None
+        
+        year = timestamp_str[:4]
+        month = timestamp_str[4:6]
+        day = timestamp_str[6:8]
+        hour = timestamp_str[8:10]
+        minute = timestamp_str[10:12]
+        second = timestamp_str[12:14]
+        millisecond = timestamp_str[14:17]
+        
+        # 构造datetime对象
+        dt = datetime(
+            int(year), int(month), int(day),
+            int(hour), int(minute), int(second),
+            int(millisecond) * 1000  # 毫秒转微秒
+        )
+        
+        # 转换为中国时区
+        china_tz = pytz.timezone('Asia/Shanghai')
+        # 假设原始时间戳是中国时区
+        china_dt = china_tz.localize(dt)
+        
+        # 格式化为要求的格式
+        formatted_time = china_dt.strftime('%Y-%m-%d %H:%M:%S.%f')[:-3]  # 保留3位毫秒
+        return formatted_time
+        
+    except Exception as e:
+        logger.warning(f"⚠️ 解析conversation_id时间戳失败: {e}")
+        return None
+
+def _get_conversation_updated_time(redis_client, thread_id: str) -> Optional[str]:
+    """获取对话的最后更新时间(从Redis checkpoint数据中的ts字段)"""
+    try:
+        # 扫描该thread的所有checkpoint keys
+        pattern = f"checkpoint:{thread_id}:*"
+        
+        keys = []
+        cursor = 0
+        while True:
+            cursor, batch = redis_client.scan(cursor=cursor, match=pattern, count=1000)
+            keys.extend(batch)
+            if cursor == 0:
+                break
+        
+        if not keys:
+            return None
+        
+        # 获取最新的checkpoint(按key排序,最大的是最新的)
+        latest_key = max(keys)
+        
+        # 检查key类型并获取数据
+        key_type = redis_client.type(latest_key)
+        
+        data = None
+        if key_type == 'string':
+            data = redis_client.get(latest_key)
+        elif key_type == 'ReJSON-RL':
+            # RedisJSON类型
+            try:
+                data = redis_client.execute_command('JSON.GET', latest_key)
+            except Exception as json_error:
+                logger.error(f"❌ JSON.GET失败: {json_error}")
+                return None
+        else:
+            return None
+        
+        if not data:
+            return None
+        
+        # 解析JSON数据
+        try:
+            checkpoint_data = json.loads(data)
+        except json.JSONDecodeError:
+            return None
+        
+        # 检查checkpoint中的ts字段
+        if ('checkpoint' in checkpoint_data and 
+            isinstance(checkpoint_data['checkpoint'], dict) and 
+            'ts' in checkpoint_data['checkpoint']):
+            
+            ts_value = checkpoint_data['checkpoint']['ts']
+            
+            # 解析ts字段(应该是ISO格式的时间戳)
+            if isinstance(ts_value, str):
+                try:
+                    dt = datetime.fromisoformat(ts_value.replace('Z', '+00:00'))
+                    china_tz = pytz.timezone('Asia/Shanghai')
+                    china_dt = dt.astimezone(china_tz)
+                    formatted_time = china_dt.strftime('%Y-%m-%d %H:%M:%S.%f')[:-3]
+                    return formatted_time
+                except Exception:
+                    pass
+        
+        return None
+        
+    except Exception as e:
+        logger.warning(f"⚠️ 获取对话更新时间失败: {e}")
+        return None
+
 def validate_request_data(data: Dict[str, Any]) -> Dict[str, Any]:
     """验证请求数据,并支持从thread_id中推断user_id"""
     errors = []
@@ -350,12 +468,21 @@ def get_user_conversations_simple_sync(user_id: str, limit: int = 10):
                                         preview = content[:50] + "..." if len(content) > 50 else content
                                         break
                         
+                        # 解析时间戳
+                        created_at = _parse_conversation_created_time(thread_id)
+                        updated_at = _get_conversation_updated_time(redis_client, thread_id)
+                        
+                        # 如果无法获取updated_at,使用created_at作为备选
+                        if not updated_at:
+                            updated_at = created_at
+                        
                         conversations.append({
-                            "thread_id": thread_id,
+                            "conversation_id": thread_id,  # thread_id -> conversation_id
                             "user_id": user_id,
-                            "timestamp": thread_info["timestamp"],
                             "message_count": len(messages),
-                            "conversation_preview": preview
+                            "conversation_title": preview,  # conversation_preview -> conversation_title
+                            "created_at": created_at,
+                            "updated_at": updated_at
                         })
                         
                     except json.JSONDecodeError:
@@ -2184,17 +2311,14 @@ async def get_user_conversations_react(user_id: str):
             response_text=f"获取用户对话列表失败: {str(e)}"
         )), 500
 
-@app.route('/api/v0/react/users/<user_id>/conversations/<thread_id>', methods=['GET'])
-async def get_user_conversation_detail_react(user_id: str, thread_id: str):
+@app.route('/api/v0/react/conversations/<thread_id>', methods=['GET'])
+async def get_user_conversation_detail_react(thread_id: str):
     """异步获取特定对话的详细历史(从 custom_react_agent 迁移)"""
     global _react_agent_instance
     
     try:
-        # 验证thread_id格式是否匹配user_id
-        if not thread_id.startswith(f"{user_id}:"):
-            return jsonify(bad_request_response(
-                response_text=f"Thread ID {thread_id} 不属于用户 {user_id}"
-            )), 400
+        # 从thread_id中提取user_id
+        user_id = thread_id.split(':')[0] if ':' in thread_id else 'unknown'
         
         logger.info(f"📖 异步获取用户 {user_id} 的对话 {thread_id} 详情")
         
@@ -2308,35 +2432,31 @@ def test_redis_connection():
 
 @app.route('/api/v0/react/direct/users/<user_id>/conversations', methods=['GET'])
 def test_get_user_conversations_simple(user_id: str):
-    """测试简单Redis查询获取用户对话列表(从 custom_react_agent 迁移)"""
+    """直接从Redis获取用户对话列表"""
     try:
         limit = request.args.get('limit', 10, type=int)
         limit = max(1, min(limit, 50))
         
-        logger.info(f"🧪 测试获取用户 {user_id} 的对话列表(简单Redis方式)")
+        logger.info(f"📋 获取用户 {user_id} 的对话列表(直接Redis方式)")
         
         # 使用简单Redis查询
         conversations = get_user_conversations_simple_sync(user_id, limit)
         
-        return jsonify({
-            "success": True,
-            "method": "simple_redis_query",
-            "data": {
+        return jsonify(success_response(
+            response_text="获取用户对话列表成功",
+            data={
                 "user_id": user_id,
                 "conversations": conversations,
                 "total_count": len(conversations),
                 "limit": limit
-            },
-            "timestamp": datetime.now().isoformat()
-        }), 200
+            }
+        )), 200
         
     except Exception as e:
-        logger.error(f"❌ 测试简单Redis查询失败: {e}")
-        return jsonify({
-            "success": False,
-            "error": str(e),
-            "timestamp": datetime.now().isoformat()
-        }), 500
+        logger.error(f"❌ 获取用户对话列表失败: {e}")
+        return jsonify(internal_error_response(
+            response_text=f"获取用户对话列表失败: {str(e)}"
+        )), 500
 
 @app.route('/api/v0/react/direct/conversations/<thread_id>', methods=['GET'])
 def get_conversation_detail_api(thread_id: str):
@@ -2370,32 +2490,26 @@ def get_conversation_detail_api(thread_id: str):
         # 如果提供了user_id,验证thread_id是否属于该用户
         thread_user_id = thread_id.split(':')[0]
         if user_id and thread_user_id != user_id:
-            return jsonify({
-                "success": False,
-                "error": f"Thread ID {thread_id} does not belong to user {user_id}",
-                "timestamp": datetime.now().isoformat()
-            }), 400
+            return jsonify(bad_request_response(
+                response_text=f"Thread ID {thread_id} does not belong to user {user_id}"
+            )), 400
         
         logger.info(f"📖 获取对话详情 - Thread: {thread_id}, Include Tools: {include_tools}")
         
         # 检查enhanced_redis_api是否可用
         if get_conversation_detail_from_redis is None:
-            return jsonify({
-                "success": False,
-                "error": "enhanced_redis_api 模块不可用",
-                "timestamp": datetime.now().isoformat()
-            }), 503
+            return jsonify(service_unavailable_response(
+                response_text="enhanced_redis_api 模块不可用"
+            )), 503
         
         # 从Redis获取对话详情(使用我们的新函数)
         result = get_conversation_detail_from_redis(thread_id, include_tools)
         
         if not result['success']:
             logger.warning(f"⚠️ 获取对话详情失败: {result['error']}")
-            return jsonify({
-                "success": False,
-                "error": result['error'],
-                "timestamp": datetime.now().isoformat()
-            }), 404
+            return jsonify(internal_error_response(
+                response_text=result['error']
+            )), 404
         
         # 添加API元数据
         result['data']['api_metadata'] = {
@@ -2411,22 +2525,19 @@ def get_conversation_detail_api(thread_id: str):
         mode_desc = "完整模式" if include_tools else "简化模式"
         logger.info(f"✅ 成功获取对话详情 - Messages: {result['data']['message_count']}, Mode: {mode_desc}")
         
-        return jsonify({
-            "success": True,
-            "data": result['data'],
-            "timestamp": datetime.now().isoformat()
-        }), 200
+        return jsonify(success_response(
+            response_text=f"获取对话详情成功 ({mode_desc})",
+            data=result['data']
+        )), 200
         
     except Exception as e:
         import traceback
         logger.error(f"❌ 获取对话详情异常: {e}")
         logger.error(f"❌ 详细错误信息: {traceback.format_exc()}")
         
-        return jsonify({
-            "success": False,
-            "error": str(e),
-            "timestamp": datetime.now().isoformat()
-        }), 500
+        return jsonify(internal_error_response(
+            response_text=f"获取对话详情失败: {str(e)}"
+        )), 500
 
 @app.route('/api/v0/react/direct/conversations/<thread_id>/compare', methods=['GET'])
 def compare_conversation_modes_api(thread_id: str):
@@ -2518,31 +2629,25 @@ def get_conversation_summary_api(thread_id: str):
         
         # 验证thread_id格式
         if ':' not in thread_id:
-            return jsonify({
-                "success": False,
-                "error": "Invalid thread_id format. Expected format: user_id:timestamp",
-                "timestamp": datetime.now().isoformat()
-            }), 400
+            return jsonify(bad_request_response(
+                response_text="Invalid thread_id format. Expected format: user_id:timestamp"
+            )), 400
         
         logger.info(f"📊 获取对话摘要 - Thread: {thread_id}, Include Tools: {include_tools}")
         
         # 检查enhanced_redis_api是否可用
         if get_conversation_detail_from_redis is None:
-            return jsonify({
-                "success": False,
-                "error": "enhanced_redis_api 模块不可用",
-                "timestamp": datetime.now().isoformat()
-            }), 503
+            return jsonify(service_unavailable_response(
+                response_text="enhanced_redis_api 模块不可用"
+            )), 503
         
         # 获取完整对话信息
         result = get_conversation_detail_from_redis(thread_id, include_tools)
         
         if not result['success']:
-            return jsonify({
-                "success": False,
-                "error": result['error'],
-                "timestamp": datetime.now().isoformat()
-            }), 404
+            return jsonify(internal_error_response(
+                response_text=result['error']
+            )), 404
         
         # 只返回摘要信息,不包含具体消息
         data = result['data']
@@ -2563,14 +2668,14 @@ def get_conversation_summary_api(thread_id: str):
         if messages:
             # 第一条human消息预览
             for msg in messages:
-                if msg['type'] == 'human':
+                if msg['role'] == 'human':
                     content = str(msg['content'])
                     summary['first_message_preview'] = content[:100] + "..." if len(content) > 100 else content
                     break
             
             # 最后一条ai消息预览
             for msg in reversed(messages):
-                if msg['type'] == 'ai' and msg.get('content', '').strip():
+                if msg['role'] == 'ai' and msg.get('content', '').strip():
                     content = str(msg['content'])
                     summary['last_message_preview'] = content[:100] + "..." if len(content) > 100 else content
                     break
@@ -2587,19 +2692,16 @@ def get_conversation_summary_api(thread_id: str):
         
         logger.info(f"✅ 成功获取对话摘要")
         
-        return jsonify({
-            "success": True,
-            "data": summary,
-            "timestamp": datetime.now().isoformat()
-        }), 200
+        return jsonify(success_response(
+            response_text="获取对话摘要成功",
+            data=summary
+        )), 200
         
     except Exception as e:
         logger.error(f"❌ 获取对话摘要失败: {e}")
-        return jsonify({
-            "success": False,
-            "error": str(e),
-            "timestamp": datetime.now().isoformat()
-        }), 500
+        return jsonify(internal_error_response(
+            response_text=f"获取对话摘要失败: {str(e)}"
+        )), 500
 
 # ==================== 启动逻辑 ====================