#!/usr/bin/env python3 """ 完整错误信息诊断脚本 运行工作流并捕获完整的错误信息 """ import sys import os import json import traceback from datetime import datetime # 添加项目路径 project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) sys.path.insert(0, project_root) sys.path.insert(0, os.path.join(project_root, 'src')) from langgraph.runtime import Runtime from coze_coding_utils.runtime_ctx.context import Context, new_context def run_test_with_full_error_capture(): """运行测试并捕获完整错误信息""" # 准备测试数据 test_data = { "student_homework": [ { "student_id": 1, "student_name": "张三呀", "homework_images": [ "https://dpcclass.oss-cn-beijing.aliyuncs.com/umsupload/2026/03/18/69baa4f5-4826-4901-00e1-c6e66f02947f.jpg?x-oss-process=image/resize,w_1000", "https://dpcclass.oss-cn-beijing.aliyuncs.com/umsupload/2026/03/25/69c344ba-4826-4901-00e1-c6ff235a12b2.jpg?x-oss-process=image/resize,w_1000", "https://dpcclass.oss-cn-beijing.aliyuncs.com/umsupload/2026/03/25/69c344ba-4826-4901-00e1-c7055a396422.jpg?x-oss-process=image/resize,w_1000", "https://dpcclass.oss-cn-beijing.aliyuncs.com/umsupload/2026/03/25/69c344ba-4826-4901-00e1-c6fe7f9c07ef.jpg?x-oss-process=image/resize,w_1000" ] }, { "student_id": 2, "student_name": "李四呀", "homework_images": [ "https://dpcclass.oss-cn-beijing.aliyuncs.com/umsupload/2026/03/25/69c344ba-4826-4901-00e1-c70052d895e3.jpg?x-oss-process=image/resize,w_1000", "https://dpcclass.oss-cn-beijing.aliyuncs.com/umsupload/2026/03/25/69c344ba-4826-4901-00e1-c6fc6ca7c4bf.png?x-oss-process=image/resize,w_1000", "https://dpcclass.oss-cn-beijing.aliyuncs.com/umsupload/2026/03/25/69c33f31-4826-4901-00e1-c6fb50697e06.png?x-oss-process=image/resize,w_1000", "https://dpcclass.oss-cn-beijing.aliyuncs.com/umsupload/2026/03/23/69c1029b-4826-4901-00e1-c6f614bc06d9.jpg?x-oss-process=image/resize,w_1000", "https://dpcclass.oss-cn-beijing.aliyuncs.com/umsupload/2026/03/25/69c344ba-4826-4901-00e1-c6fd479e0a0e.jpg?x-oss-process=image/resize,w_1000", "https://dpcclass.oss-cn-beijing.aliyuncs.com/umsupload/2026/03/23/69c1029b-4826-4901-00e1-c6f569b31a14.jpeg?x-oss-process=image/resize,w_1000" ] } ], "answer_doc_url": "https://dpc-oss.23544.com/umsupload/2026/03/25/69c353d0-4826-4901-00e1-c7081bcab988.docx", "comment_max_length": 50, "max_concurrent": 5, "grade_standards": {} } print("=" * 80) print("开始运行完整错误诊断测试") print("=" * 80) print(f"测试数据: {len(test_data['student_homework'])} 个学生") total_images = sum(len(s['homework_images']) for s in test_data['student_homework']) print(f"总图片数: {total_images}") print(f"答案文档: {test_data['answer_doc_url'][:50]}...") print("=" * 80) print() # 初始化上下文 ctx = new_context(method="run") try: # 导入主图 from graphs.graph import main_graph print("✓ 成功导入主图") print() # 运行测试 print("开始运行工作流...") print("-" * 80) result = main_graph.invoke(test_data, config={"recursion_limit": 100}) print("-" * 80) print() print("=" * 80) print("✓ 测试成功!") print("=" * 80) print() # 输出结果摘要 if "student_results" in result: for student_result in result["student_results"]: # StudentResult 是 Pydantic 对象,使用属性访问而不是 .get() student_name = getattr(student_result, "student_name", "未知") total_images = getattr(student_result, "total_images", 0) total_score = getattr(student_result, "total_score", 0) full_score = getattr(student_result, "full_score", 0) grade = getattr(student_result, "grade", "N/A") print(f"学生: {student_name}") print(f" 图片数: {total_images}") print(f" 得分: {total_score}/{full_score}") print(f" 等级: {grade}") print() # 保存完整结果到文件(先转换为 dict) result_dict = result.model_dump() if hasattr(result, 'model_dump') else result result_file = f"/tmp/diagnostic_result_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json" with open(result_file, 'w', encoding='utf-8') as f: json.dump(result_dict, f, ensure_ascii=False, indent=2) print(f"完整结果已保存到: {result_file}") return True except Exception as e: print("-" * 80) print() print("=" * 80) print("✗ 测试失败!") print("=" * 80) print() print("错误类型:", type(e).__name__) print("错误消息:", str(e)) print() print("完整堆栈跟踪:") print("-" * 80) traceback.print_exc() print("-" * 80) print() # 保存错误信息到文件 error_file = f"/tmp/diagnostic_error_{datetime.now().strftime('%Y%m%d_%H%M%S')}.log" with open(error_file, 'w', encoding='utf-8') as f: f.write(f"错误类型: {type(e).__name__}\n") f.write(f"错误消息: {str(e)}\n") f.write("\n完整堆栈跟踪:\n") f.write("=" * 80 + "\n") traceback.print_exc(file=f) print(f"错误信息已保存到: {error_file}") print() # 分析错误类型 print("错误分析:") print("-" * 80) error_str = str(e).lower() if "404" in error_str or "not found" in error_str: print("⚠️ 404 错误:资源不存在") print(" 可能原因:") print(" 1. URL 已过期(签名 URL 有时效性)") print(" 2. 文件已被删除或移动") print(" 3. URL 拼写错误") elif "403" in error_str or "forbidden" in error_str: print("⚠️ 403 错误:禁止访问") print(" 可能原因:") print(" 1. 访问权限不足") print(" 2. 需要 IP 白名单") print(" 3. 需要认证") elif "401" in error_str or "unauthorized" in error_str: print("⚠️ 401 错误:未授权") print(" 可能原因:") print(" 1. API 密钥无效") print(" 2. 认证失败") print(" 3. Token 过期") elif "timeout" in error_str: print("⚠️ 超时错误") print(" 可能原因:") print(" 1. 网络连接慢") print(" 2. 服务器响应慢") print(" 3. 图片或文档太大") elif "connection" in error_str or "network" in error_str: print("⚠️ 网络连接错误") print(" 可能原因:") print(" 1. 无法连接到外部网络") print(" 2. DNS 解析失败") print(" 3. 防火墙阻止") elif "html" in error_str: print("⚠️ HTML 错误页面") print(" 可能原因:") print(" 1. URL 返回了 404/403/500 错误页面") print(" 2. 网络重定向失败") print(" 3. CDN 或代理返回错误") elif "json" in error_str: print("⚠️ JSON 解析错误") print(" 可能原因:") print(" 1. LLM 返回的不是有效的 JSON") print(" 2. JSON 格式错误") print(" 3. 缺少必需字段") elif "llm" in error_str or "model" in error_str: print("⚠️ LLM 调用错误") print(" 可能原因:") print(" 1. LLM 服务不可用") print(" 2. 模型配置错误") print(" 3. API 配额不足") else: print("⚠️ 未知错误类型") print(" 请查看上面的错误详情和堆栈跟踪") print() return False if __name__ == "__main__": print() print("=" * 80) print("初中数学作业批改工作流 - 完整错误诊断") print("=" * 80) print() success = run_test_with_full_error_capture() print() print("=" * 80) if success: print("诊断完成:工作流运行正常") sys.exit(0) else: print("诊断完成:发现错误,请查看上面的错误详情") sys.exit(1)