Przeglądaj źródła

提交批处理逻辑,修改日志逻辑

wangyang 4 dni temu
rodzic
commit
dc593a81ee

+ 2 - 2
.gitignore

@@ -43,8 +43,8 @@ ENV/
 logs/
 llmops/logs/
 
-# API results
-llmops/api_results/
+# API results (包括所有带编号的文件夹,如 api_results_1/, api_results_2/ 等)
+llmops/api_results*/
 
 # OS
 .DS_Store

+ 38 - 1
README

@@ -9,4 +9,41 @@ pip install langchain
 pip install langchain_openai
 pip install fastapi
 pip install uvicorn
-pip install pdfplumber   (pdf交易流水单解析需要)
+pip install pdfplumber   (pdf交易流水单解析需要)
+
+三、使用说明
+==========
+
+1. 环境准备:
+   # 安装依赖
+   pip install -r requirements.txt
+
+   # 配置API密钥
+   cp env_example.txt .env
+   # 编辑 .env 文件,填入你的 DEEPSEEK_API_KEY
+
+2. 批量运行工作流(推荐):
+   # 方法1:通过模块运行(推荐)
+   python -m llmops
+
+   # 方法2:直接执行文件(适用于PyCharm)
+   python llmops/batch_runner.py
+
+   # 如果需要修改参数,请直接编辑 llmops/batch_runner.py 中的配置参数:
+   # RUNS = 2         # 运行次数
+   # INDUSTRY = "农业"  # 行业
+   # DATA_FILE = "data_files/交易流水样例数据.csv"  # 数据文件
+   # QUESTION = "..."  # 查询问题
+
+⚠️ 重要:如果遇到依赖版本冲突,请参考 RUN_GUIDE.md 中的解决方案
+
+四、日志管理
+==========
+
+每次运行会创建独立的日志文件夹:
+- api_results_1/     # 第一次运行
+- api_results_2/     # 第二次运行
+- api_results_3/     # 第三次运行
+- ...
+
+这样便于整理和对比不同运行的结果。

+ 120 - 0
gitignore_说明.md

@@ -0,0 +1,120 @@
+# .gitignore 文件使用说明
+
+## 🎯 问题背景
+
+在使用 Git 进行版本控制时,经常会遇到明明已经配置了 `.gitignore` 文件,但某些文件仍然出现在 Git 状态中、能够被提交的问题。
+
+## 🔍 常见原因及解决方案
+
+### 1. **文件已被 Git 跟踪(最常见原因)**
+
+#### 📖 原理
+`.gitignore` 文件 **只能忽略未被 Git 跟踪的文件**。如果文件已经被 `git add` 命令添加到了暂存区或提交到了仓库,那么 `.gitignore` 对这些文件就无效了。
+
+#### 🔧 解决方法
+```bash
+# 从 Git 跟踪中移除文件,但保留本地文件
+git rm --cached <文件名>
+
+# 对于目录
+git rm -r --cached <目录名>/
+
+# 然后提交这个删除操作
+git commit -m "移除不应跟踪的文件"
+```
+
+### 2. **.gitignore 语法错误**
+
+#### 📖 原理
+- 以 `/` 开头的规则只匹配根目录
+- 以 `/` 结尾的规则匹配目录
+- `*.txt` 匹配所有 .txt 文件
+- `!` 开头表示否定规则
+
+#### 🔧 常见错误示例
+```gitignore
+# ❌ 错误:只匹配根目录的 venv
+/venv/
+
+# ✅ 正确:匹配任何位置的 venv 目录
+venv/
+
+# ❌ 错误:缺少常见 Python 文件类型
+*.pyc
+
+# ✅ 正确:包含所有 Python 缓存文件
+__pycache__/
+*.py[cod]
+*$py.class
+```
+
+### 3. **IDE 自动生成文件的问题**
+
+#### 📖 原理
+像 PyCharm、VS Code 等 IDE 会自动生成配置文件(如 `.idea/`、`.vscode/`),这些文件经常被意外提交。而且 IDE 运行时会不断重新创建这些文件。
+
+#### 🔧 解决方法
+1. 将所有 IDE 文件添加到 `.gitignore`
+2. 从 Git 跟踪中移除已存在的 IDE 文件
+3. 重启 IDE 让其重新生成配置
+
+### 4. **Git 缓存问题**
+
+#### 📖 原理
+Git 有自己的文件系统缓存,有时需要手动清除。
+
+#### 🔧 解决方法
+```bash
+# 清除 Git 缓存(谨慎使用,会重新扫描所有文件)
+git rm -r --cached .
+git add .
+git commit -m "刷新 Git 缓存"
+```
+
+## 📚 核心知识点总结
+
+### 1. **Git 跟踪状态**
+- **未跟踪**:文件存在但未被 Git 管理
+- **已跟踪**:文件已被 `git add` 或 `git commit`
+- **已忽略**:文件被 `.gitignore` 排除
+
+### 2. **.gitignore 生效规则**
+- 只对**未跟踪**文件生效
+- 对**已跟踪**文件无效
+- 规则是**从上到下**匹配的
+- 可以使用 `!` 进行例外处理
+
+### 3. **文件状态转换**
+```
+新建文件 → git add → 暂存区 → git commit → 仓库
+     ↓
+.gitignore 可以忽略
+```
+
+### 4. **最佳实践**
+1. **尽早创建** `.gitignore` 文件
+2. **定期检查** `git status` 和 `git ls-files`
+3. **使用标准模板**(GitHub 有各种语言的 .gitignore 模板)
+4. **团队统一** .gitignore 规则
+
+## 🛠️ 常用检查命令
+
+```bash
+# 查看文件是否被忽略
+git check-ignore <文件名>
+
+# 查看所有被跟踪的文件
+git ls-files
+
+# 查看未跟踪的文件
+git status --porcelain | grep "^??"
+```
+
+## 💡 预防措施
+
+1. **项目初始化时**就创建完整的 `.gitignore`
+2. **定期审查**仓库中的文件
+3. **使用 GitHub 的官方模板**
+4. **配置 IDE**不自动添加文件到 Git
+
+这样就能避免大部分 .gitignore 相关的问题了!

+ 10 - 0
llmops/__main__.py

@@ -0,0 +1,10 @@
+#!/usr/bin/env python3
+"""
+llmops 包的主入口点
+允许通过 `python -m llmops` 运行批量任务
+"""
+
+from .batch_runner import main
+
+if __name__ == "__main__":
+    main()

+ 51 - 123
llmops/agents/metric_calculation_agent.py

@@ -272,38 +272,26 @@ class MetricCalculationAgent:
                                         # 从result字段中提取JSON
                                         extracted_result = self._extract_json_from_result(data["result"])
 
-                            # 记录API调用结果
+                            # 记录API调用结果 - 简化版
                             end_time = datetime.now()
                             call_id = f"api_{config_name}_{'{:.2f}'.format((end_time - start_time).total_seconds())}"
                             api_call_info = {
                                 "call_id": call_id,
-                                "timestamp": end_time.isoformat(),
-                                "agent": "MetricCalculationAgent",
-                                "api_endpoint": url,
-                                "config_name": config_name,
-                                "request": {
-                                    "method": method,
-                                    "url": url,
-                                    "headers": headers,
-                                    "json_data": json_data if method.upper() == "POST" else None,
-                                    "params": params if method.upper() == "GET" else None,
-                                    "start_time": start_time.isoformat()
-                                },
                                 "response": {
                                     "status_code": response.status_code,
                                     "data": response_data,
-                                    "extracted_result": extracted_result,
-                                    "end_time": end_time.isoformat(),
-                                    "duration": (end_time - start_time).total_seconds()
-                                },
-                                "success": True
+                                    "extracted_result": extracted_result
+                                }
                             }
                             self.api_calls.append(api_call_info)
 
-                            # 保存API结果到文件
-                            api_results_dir = "api_results"
+                            # 保存API结果到文件 - 成功状态
+                            # 使用运行ID创建独立的文件夹
+                            run_id = os.environ.get('FLOW_RUN_ID', 'default')
+                            api_results_dir = f"api_results_{run_id}"
                             os.makedirs(api_results_dir, exist_ok=True)
-                            filename = f"{call_id}.json"
+                            timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
+                            filename = f"{timestamp}_{call_id}_success.json"
                             filepath = os.path.join(api_results_dir, filename)
 
                             try:
@@ -320,38 +308,26 @@ class MetricCalculationAgent:
                                 "status_code": response.status_code
                             }
                         except json.JSONDecodeError:
-                            # 记录API调用结果(JSON解析失败)
+                            # 记录API调用结果(JSON解析失败)- 简化版
                             end_time = datetime.now()
                             call_id = f"api_{config_name}_{'{:.2f}'.format((end_time - start_time).total_seconds())}"
                             api_call_info = {
                                 "call_id": call_id,
-                                "timestamp": end_time.isoformat(),
-                                "agent": "MetricCalculationAgent",
-                                "api_endpoint": url,
-                                "config_name": config_name,
-                                "request": {
-                                    "method": method,
-                                    "url": url,
-                                    "headers": headers,
-                                    "json_data": json_data if method.upper() == "POST" else None,
-                                    "params": params if method.upper() == "GET" else None,
-                                    "start_time": start_time.isoformat()
-                                },
                                 "response": {
                                     "status_code": response.status_code,
                                     "data": response.text,
-                                    "error": "JSON解析失败",
-                                    "end_time": end_time.isoformat(),
-                                    "duration": (end_time - start_time).total_seconds()
-                                },
-                                "success": False
+                                    "error": "JSON解析失败"
+                                }
                             }
                             self.api_calls.append(api_call_info)
 
-                            # 保存API结果到文件
-                            api_results_dir = "api_results"
+                            # 保存API结果到文件 - 失败状态
+                            # 使用运行ID创建独立的文件夹
+                            run_id = os.environ.get('FLOW_RUN_ID', 'default')
+                            api_results_dir = f"api_results_{run_id}"
                             os.makedirs(api_results_dir, exist_ok=True)
-                            filename = f"{call_id}.json"
+                            timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
+                            filename = f"{timestamp}_{call_id}_fail.json"
                             filepath = os.path.join(api_results_dir, filename)
 
                             try:
@@ -368,37 +344,25 @@ class MetricCalculationAgent:
                                 "status_code": response.status_code
                             }
                     else:
-                        # 记录API调用结果(HTTP错误)
+                        # 记录API调用结果(HTTP错误)- 简化版
                         end_time = datetime.now()
                         call_id = f"api_{config_name}_{'{:.2f}'.format((end_time - start_time).total_seconds())}"
                         api_call_info = {
                             "call_id": call_id,
-                            "timestamp": end_time.isoformat(),
-                            "agent": "MetricCalculationAgent",
-                            "api_endpoint": url,
-                            "config_name": config_name,
-                            "request": {
-                                "method": method,
-                                "url": url,
-                                "headers": headers,
-                                "json_data": json_data if method.upper() == "POST" else None,
-                                "params": params if method.upper() == "GET" else None,
-                                "start_time": start_time.isoformat()
-                            },
                             "response": {
                                 "status_code": response.status_code,
-                                "error": response.text,
-                                "end_time": end_time.isoformat(),
-                                "duration": (end_time - start_time).total_seconds()
-                            },
-                            "success": False
+                                "error": response.text
+                            }
                         }
                         self.api_calls.append(api_call_info)
 
-                        # 保存API结果到文件
-                        api_results_dir = "api_results"
+                        # 保存API结果到文件 - 失败状态
+                        # 使用运行ID创建独立的文件夹
+                        run_id = os.environ.get('FLOW_RUN_ID', 'default')
+                        api_results_dir = f"api_results_{run_id}"
                         os.makedirs(api_results_dir, exist_ok=True)
-                        filename = f"{call_id}.json"
+                        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
+                        filename = f"{timestamp}_{call_id}_fail.json"
                         filepath = os.path.join(api_results_dir, filename)
 
                         try:
@@ -418,36 +382,24 @@ class MetricCalculationAgent:
                     break
 
                 except requests.exceptions.Timeout:
-                    # 记录API调用结果(超时)
+                    # 记录API调用结果(超时)- 简化版
                     end_time = datetime.now()
                     call_id = f"api_{config_name}_{'{:.2f}'.format((end_time - start_time).total_seconds())}"
                     api_call_info = {
                         "call_id": call_id,
-                        "timestamp": end_time.isoformat(),
-                        "agent": "MetricCalculationAgent",
-                        "api_endpoint": url,
-                        "config_name": config_name,
-                        "request": {
-                            "method": method,
-                            "url": url,
-                            "headers": headers,
-                            "json_data": json_data if method.upper() == "POST" else None,
-                            "params": params if method.upper() == "GET" else None,
-                            "start_time": start_time.isoformat()
-                        },
                         "response": {
-                            "error": "API调用超时",
-                            "end_time": end_time.isoformat(),
-                            "duration": (end_time - start_time).total_seconds()
-                        },
-                        "success": False
+                            "error": "API调用超时"
+                        }
                     }
                     self.api_calls.append(api_call_info)
 
                     # 保存API结果到文件
-                    api_results_dir = "api_results"
+                    # 使用运行ID创建独立的文件夹
+                    run_id = os.environ.get('FLOW_RUN_ID', 'default')
+                    api_results_dir = f"api_results_{run_id}"
                     os.makedirs(api_results_dir, exist_ok=True)
-                    filename = f"{call_id}.json"
+                    timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
+                    filename = f"{timestamp}_{call_id}_fail.json"
                     filepath = os.path.join(api_results_dir, filename)
 
                     try:
@@ -469,36 +421,24 @@ class MetricCalculationAgent:
                             "message": "API调用超时"
                         }
                 except requests.exceptions.RequestException as e:
-                    # 记录API调用结果(请求异常)
+                    # 记录API调用结果(请求异常)- 简化版
                     end_time = datetime.now()
                     call_id = f"api_{config_name}_{'{:.2f}'.format((end_time - start_time).total_seconds())}"
                     api_call_info = {
                         "call_id": call_id,
-                        "timestamp": end_time.isoformat(),
-                        "agent": "MetricCalculationAgent",
-                        "api_endpoint": url,
-                        "config_name": config_name,
-                        "request": {
-                            "method": method,
-                            "url": url,
-                            "headers": headers,
-                            "json_data": json_data if method.upper() == "POST" else None,
-                            "params": params if method.upper() == "GET" else None,
-                            "start_time": start_time.isoformat()
-                        },
                         "response": {
-                            "error": str(e),
-                            "end_time": end_time.isoformat(),
-                            "duration": (end_time - start_time).total_seconds()
-                        },
-                        "success": False
+                            "error": str(e)
+                        }
                     }
                     self.api_calls.append(api_call_info)
 
                     # 保存API结果到文件
-                    api_results_dir = "api_results"
+                    # 使用运行ID创建独立的文件夹
+                    run_id = os.environ.get('FLOW_RUN_ID', 'default')
+                    api_results_dir = f"api_results_{run_id}"
                     os.makedirs(api_results_dir, exist_ok=True)
-                    filename = f"{call_id}.json"
+                    timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
+                    filename = f"{timestamp}_{call_id}_fail.json"
                     filepath = os.path.join(api_results_dir, filename)
 
                     try:
@@ -520,36 +460,24 @@ class MetricCalculationAgent:
                             "message": f"API调用异常: {str(e)}"
                         }
                 except Exception as e:
-                    # 记录API调用结果(其他异常)
+                    # 记录API调用结果(其他异常)- 简化版
                     end_time = datetime.now()
                     call_id = f"api_{config_name}_{'{:.2f}'.format((end_time - start_time).total_seconds())}"
                     api_call_info = {
                         "call_id": call_id,
-                        "timestamp": end_time.isoformat(),
-                        "agent": "MetricCalculationAgent",
-                        "api_endpoint": url,
-                        "config_name": config_name,
-                        "request": {
-                            "method": method,
-                            "url": url,
-                            "headers": headers,
-                            "json_data": json_data if method.upper() == "POST" else None,
-                            "params": params if method.upper() == "GET" else None,
-                            "start_time": start_time.isoformat()
-                        },
                         "response": {
-                            "error": str(e),
-                            "end_time": end_time.isoformat(),
-                            "duration": (end_time - start_time).total_seconds()
-                        },
-                        "success": False
+                            "error": str(e)
+                        }
                     }
                     self.api_calls.append(api_call_info)
 
                     # 保存API结果到文件
-                    api_results_dir = "api_results"
+                    # 使用运行ID创建独立的文件夹
+                    run_id = os.environ.get('FLOW_RUN_ID', 'default')
+                    api_results_dir = f"api_results_{run_id}"
                     os.makedirs(api_results_dir, exist_ok=True)
-                    filename = f"{call_id}.json"
+                    timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
+                    filename = f"{timestamp}_{call_id}_fail.json"
                     filepath = os.path.join(api_results_dir, filename)
 
                     try:

+ 28 - 21
llmops/agents/outline_agent.py

@@ -326,38 +326,45 @@ class OutlineGeneratorAgent:
             print(f"解析大纲响应失败: {e},使用默认大纲")
             # 不在这里创建大纲,在函数末尾统一处理
 
-        # 记录API调用结果
+        # 记录API调用结果 - 简化版:只保存提示词和结果大纲
         call_id = f"api_mll_大纲生成_{'{:.2f}'.format((end_time - start_time).total_seconds())}"
+
+        # 从content中提取JSON结果
+        extracted_json = ""
+        try:
+            json_start = content.find('{')
+            json_end = content.rfind('}') + 1
+            if json_start >= 0 and json_end > json_start:
+                extracted_json = content[json_start:json_end]
+        except:
+            extracted_json = content  # 如果提取失败,使用原始content
+
         api_call_info = {
-            "call_id": call_id,
-            "timestamp": end_time.isoformat(),
-            "agent": "OutlineGeneratorAgent",
-            "model": "deepseek-chat",
-            "request": {
-                "question": question,
-                "sample_data_count": len(sample_data),
-                "prompt": prompt,
-                "start_time": start_time.isoformat()
-            },
-            "response": {
-                "content": content,
-                "end_time": end_time.isoformat(),
-                "duration": (end_time - start_time).total_seconds()
-            },
-            "success": True
+            "prompt": full_prompt,
+            "outline_result": extracted_json
         }
         self.api_calls.append(api_call_info)
 
-        # 保存API结果到文件
-        api_results_dir = "api_results"
+        # 保存API结果到文件 (Markdown格式,更易阅读)
+        # 使用运行ID创建独立的文件夹
+        run_id = os.environ.get('FLOW_RUN_ID', 'default')
+        api_results_dir = f"api_results_{run_id}"
         os.makedirs(api_results_dir, exist_ok=True)
         timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
-        filename = f"{timestamp}_{call_id}.json"
+        filename = f"{timestamp}_{call_id}.md"
         filepath = os.path.join(api_results_dir, filename)
 
         try:
             with open(filepath, 'w', encoding='utf-8') as f:
-                json.dump(api_call_info, f, ensure_ascii=False, indent=2)
+                f.write("# 大纲生成结果\n\n")
+                f.write("## 提示词入参\n\n")
+                f.write("```\n")
+                f.write(api_call_info["prompt"])
+                f.write("\n```\n\n")
+                f.write("## 生成的大纲结果\n\n")
+                f.write("```json\n")
+                f.write(api_call_info["outline_result"])
+                f.write("\n```\n")
             print(f"[API_RESULT] 保存API结果文件: {filepath}")
         except Exception as e:
             print(f"[ERROR] 保存API结果文件失败: {filepath}, 错误: {str(e)}")

+ 23 - 20
llmops/agents/planning_agent.py

@@ -211,39 +211,42 @@ class PlanningAgent:
             # 返回默认决策
             decision = self._get_default_decision(current_state)
 
-        # 记录API调用结果
+        # 记录API调用结果 - 简化版
         content = response.content if hasattr(response, 'content') else str(response)
+
+        # 从content中提取JSON结果
+        extracted_json = ""
+        try:
+            json_start = content.find('{')
+            json_end = content.rfind('}') + 1
+            if json_start >= 0 and json_end > json_start:
+                extracted_json = content[json_start:json_end]
+        except:
+            extracted_json = content  # 如果提取失败,使用原始content
+
         call_id = f"api_mll_规划决策_{'{:.2f}'.format((end_time - start_time).total_seconds())}"
         api_call_info = {
             "call_id": call_id,
-            "timestamp": end_time.isoformat(),
-            "agent": "PlanningAgent",
-            "model": "deepseek-chat",
-            "request": {
-                "question": question,
-                "status_info": status_info,
-                "start_time": start_time.isoformat()
-            },
-            "response": {
-                "content": content,
-                "decision": decision.dict() if hasattr(decision, 'dict') else decision,
-                "end_time": end_time.isoformat(),
-                "duration": (end_time - start_time).total_seconds()
-            },
-            "success": True
+            "response": extracted_json
         }
         self.api_calls.append(api_call_info)
 
-        # 保存API结果到文件
-        api_results_dir = "api_results"
+        # 保存API结果到文件 - Markdown格式,更易阅读
+        # 使用运行ID创建独立的文件夹
+        run_id = os.environ.get('FLOW_RUN_ID', 'default')
+        api_results_dir = f"api_results_{run_id}"
         os.makedirs(api_results_dir, exist_ok=True)
         timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
-        filename = f"{timestamp}_{call_id}.json"
+        filename = f"{timestamp}_{call_id}.md"
         filepath = os.path.join(api_results_dir, filename)
 
         try:
             with open(filepath, 'w', encoding='utf-8') as f:
-                json.dump(api_call_info, f, ensure_ascii=False, indent=2)
+                f.write("# 规划决策结果\n\n")
+                f.write("## 决策结果\n\n")
+                f.write("```json\n")
+                f.write(api_call_info["response"])
+                f.write("\n```\n")
             print(f"[API_RESULT] 保存API结果文件: {filepath}")
         except Exception as e:
             print(f"[ERROR] 保存API结果文件失败: {filepath}, 错误: {str(e)}")

+ 132 - 235
llmops/agents/rules_engine_metric_calculation_agent.py

@@ -290,37 +290,22 @@ class RulesEngineMetricCalculationAgent:
                 try:
                     response_data = response.json()
 
-                    # 记录API调用结果
+                    # 记录API调用结果 - 简化版
                     end_time = datetime.now()
                     call_id = f"rules_api_{config_name}_{'{:.2f}'.format((end_time - start_time).total_seconds())}"
                     api_call_info = {
                         "call_id": call_id,
-                        "timestamp": end_time.isoformat(),
-                        "agent": "RulesEngineMetricCalculationAgent",
-                        "api_endpoint": url,
-                        "config_name": config_name,
-                        "request": {
-                            "method": method,
-                            "url": url,
-                            "headers": headers,
-                            "json_data": json_data,
-                            "start_time": start_time.isoformat()
-                        },
-                        "response": {
-                            "status_code": response.status_code,
-                            "data": response_data,
-                            "end_time": end_time.isoformat(),
-                            "duration": (end_time - start_time).total_seconds()
-                        },
-                        "success": True
+                        "response": response_data
                     }
                     self.api_calls.append(api_call_info)
 
-                    # 保存API结果到文件
-                    api_results_dir = "api_results"
+                    # 保存API结果到文件 - 成功状态
+                    # 使用运行ID创建独立的文件夹
+                    run_id = os.environ.get('FLOW_RUN_ID', 'default')
+                    api_results_dir = f"api_results_{run_id}"
                     os.makedirs(api_results_dir, exist_ok=True)
                     timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
-                    filename = f"{timestamp}_{call_id}.json"
+                    filename = f"{timestamp}_{call_id}_success.json"
                     filepath = os.path.join(api_results_dir, filename)
 
                     try:
@@ -336,38 +321,26 @@ class RulesEngineMetricCalculationAgent:
                         "status_code": response.status_code
                     }
                 except json.JSONDecodeError:
-                    # 记录API调用结果(JSON解析失败)
+                    # 记录API调用结果(JSON解析失败)- 简化版
                     end_time = datetime.now()
                     call_id = f"rules_api_{config_name}_{'{:.2f}'.format((end_time - start_time).total_seconds())}"
                     api_call_info = {
                         "call_id": call_id,
-                        "timestamp": end_time.isoformat(),
-                        "agent": "RulesEngineMetricCalculationAgent",
-                        "api_endpoint": url,
-                        "config_name": config_name,
-                        "request": {
-                            "method": method,
-                            "url": url,
-                            "headers": headers,
-                            "json_data": json_data,
-                            "start_time": start_time.isoformat()
-                        },
                         "response": {
                             "status_code": response.status_code,
                             "data": response.text,
-                            "error": "JSON解析失败",
-                            "end_time": end_time.isoformat(),
-                            "duration": (end_time - start_time).total_seconds()
-                        },
-                        "success": False
+                            "error": "JSON解析失败"
+                        }
                     }
                     self.api_calls.append(api_call_info)
 
-                    # 保存API结果到文件
-                    api_results_dir = "api_results"
+                    # 保存API结果到文件 - 失败状态
+                    # 使用运行ID创建独立的文件夹
+                    run_id = os.environ.get('FLOW_RUN_ID', 'default')
+                    api_results_dir = f"api_results_{run_id}"
                     os.makedirs(api_results_dir, exist_ok=True)
                     timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
-                    filename = f"{timestamp}_{call_id}.json"
+                    filename = f"{timestamp}_{call_id}_fail.json"
                     filepath = os.path.join(api_results_dir, filename)
 
                     try:
@@ -383,36 +356,25 @@ class RulesEngineMetricCalculationAgent:
                         "status_code": response.status_code
                     }
             else:
-                # 记录API调用结果(HTTP错误)
+                # 记录API调用结果(HTTP错误)- 简化版
                 end_time = datetime.now()
                 call_id = f"rules_api_{config_name}_{'{:.2f}'.format((end_time - start_time).total_seconds())}"
                 api_call_info = {
                     "call_id": call_id,
-                    "timestamp": end_time.isoformat(),
-                    "agent": "RulesEngineMetricCalculationAgent",
-                    "api_endpoint": url,
-                    "config_name": config_name,
-                    "request": {
-                        "method": method,
-                        "url": url,
-                        "headers": headers,
-                        "json_data": json_data,
-                        "start_time": start_time.isoformat()
-                    },
                     "response": {
                         "status_code": response.status_code,
-                        "error": response.text,
-                        "end_time": end_time.isoformat(),
-                        "duration": (end_time - start_time).total_seconds()
-                    },
-                    "success": False
+                        "error": response.text
+                    }
                 }
                 self.api_calls.append(api_call_info)
 
-                # 保存API结果到文件
-                api_results_dir = "api_results"
+                # 保存API结果到文件 - 失败状态
+                # 使用运行ID创建独立的文件夹
+                run_id = os.environ.get('FLOW_RUN_ID', 'default')
+                api_results_dir = f"api_results_{run_id}"
                 os.makedirs(api_results_dir, exist_ok=True)
-                filename = f"{call_id}.json"
+                timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
+                filename = f"{timestamp}_{call_id}_fail.json"
                 filepath = os.path.join(api_results_dir, filename)
 
                 try:
@@ -429,91 +391,97 @@ class RulesEngineMetricCalculationAgent:
                 }
 
         except requests.exceptions.Timeout:
-            # 记录API调用结果(超时)
+            # 记录API调用结果(超时)- 简化版
             end_time = datetime.now()
             call_id = f"rules_api_{config_name}_{'{:.2f}'.format((end_time - start_time).total_seconds())}"
             api_call_info = {
                 "call_id": call_id,
-                "timestamp": end_time.isoformat(),
-                "agent": "RulesEngineMetricCalculationAgent",
-                "api_endpoint": url,
-                "config_name": config_name,
-                "request": {
-                    "method": method,
-                    "url": url,
-                    "headers": headers,
-                    "json_data": json_data if 'json_data' in locals() else None,
-                    "start_time": start_time.isoformat()
-                },
                 "response": {
-                    "error": "API调用超时",
-                    "end_time": end_time.isoformat(),
-                    "duration": (end_time - start_time).total_seconds()
-                },
-                "success": False
+                    "error": "API调用超时"
+                }
             }
             self.api_calls.append(api_call_info)
 
+            # 保存API结果到文件 - 失败状态
+            # 使用运行ID创建独立的文件夹
+            run_id = os.environ.get('FLOW_RUN_ID', 'default')
+            api_results_dir = f"api_results_{run_id}"
+            os.makedirs(api_results_dir, exist_ok=True)
+            timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
+            filename = f"{timestamp}_{call_id}_fail.json"
+            filepath = os.path.join(api_results_dir, filename)
+
+            try:
+                with open(filepath, 'w', encoding='utf-8') as f:
+                    json.dump(api_call_info, f, ensure_ascii=False, indent=2)
+                print(f"[RULES_API_RESULT] 保存规则引擎API结果文件: {filepath}")
+            except Exception as e:
+                print(f"[ERROR] 保存规则引擎API结果文件失败: {filepath}, 错误: {str(e)}")
+
             return {
                 "success": False,
                 "message": "规则引擎API调用超时"
             }
         except requests.exceptions.RequestException as e:
-            # 记录API调用结果(请求异常)
+            # 记录API调用结果(请求异常)- 简化版
             end_time = datetime.now()
             call_id = f"rules_api_{config_name}_{'{:.2f}'.format((end_time - start_time).total_seconds())}"
             api_call_info = {
                 "call_id": call_id,
-                "timestamp": end_time.isoformat(),
-                "agent": "RulesEngineMetricCalculationAgent",
-                "api_endpoint": url,
-                "config_name": config_name,
-                "request": {
-                    "method": method,
-                    "url": url,
-                    "headers": headers,
-                    "json_data": json_data if 'json_data' in locals() else None,
-                    "start_time": start_time.isoformat()
-                },
                 "response": {
-                    "error": str(e),
-                    "end_time": end_time.isoformat(),
-                    "duration": (end_time - start_time).total_seconds()
-                },
-                "success": False
+                    "error": str(e)
+                }
             }
             self.api_calls.append(api_call_info)
 
+            # 保存API结果到文件 - 失败状态
+            # 使用运行ID创建独立的文件夹
+            run_id = os.environ.get('FLOW_RUN_ID', 'default')
+            api_results_dir = f"api_results_{run_id}"
+            os.makedirs(api_results_dir, exist_ok=True)
+            timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
+            filename = f"{timestamp}_{call_id}_fail.json"
+            filepath = os.path.join(api_results_dir, filename)
+
+            try:
+                with open(filepath, 'w', encoding='utf-8') as f:
+                    json.dump(api_call_info, f, ensure_ascii=False, indent=2)
+                print(f"[RULES_API_RESULT] 保存规则引擎API结果文件: {filepath}")
+            except Exception as e:
+                print(f"[ERROR] 保存规则引擎API结果文件失败: {filepath}, 错误: {str(e)}")
+
             return {
                 "success": False,
                 "message": f"规则引擎API调用异常: {str(e)}"
             }
         except Exception as e:
-            # 记录API调用结果(其他异常)
+            # 记录API调用结果(其他异常)- 简化版
             end_time = datetime.now()
             call_id = f"rules_api_{config_name}_{'{:.2f}'.format((end_time - start_time).total_seconds())}"
             api_call_info = {
                 "call_id": call_id,
-                "timestamp": end_time.isoformat(),
-                "agent": "RulesEngineMetricCalculationAgent",
-                "api_endpoint": url,
-                "config_name": config_name,
-                "request": {
-                    "method": method,
-                    "url": url,
-                    "headers": headers,
-                    "json_data": json_data if 'json_data' in locals() else None,
-                    "start_time": start_time.isoformat()
-                },
                 "response": {
-                    "error": str(e),
-                    "end_time": end_time.isoformat(),
-                    "duration": (end_time - start_time).total_seconds()
-                },
-                "success": False
+                    "error": str(e)
+                }
             }
             self.api_calls.append(api_call_info)
 
+            # 保存API结果到文件 - 失败状态
+            # 使用运行ID创建独立的文件夹
+            run_id = os.environ.get('FLOW_RUN_ID', 'default')
+            api_results_dir = f"api_results_{run_id}"
+            os.makedirs(api_results_dir, exist_ok=True)
+            timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
+            filename = f"{timestamp}_{call_id}_fail.json"
+            filepath = os.path.join(api_results_dir, filename)
+
+            try:
+                with open(filepath, 'w', encoding='utf-8') as f:
+                    json.dump(api_call_info, f, ensure_ascii=False, indent=2)
+                print(f"[RULES_API_RESULT] 保存规则引擎API结果文件: {filepath}")
+            except Exception as e:
+                print(f"[ERROR] 保存规则引擎API结果文件失败: {filepath}, 错误: {str(e)}")
+
             return {
                 "success": False,
                 "message": f"处理规则引擎API调用时发生错误: {str(e)}"
@@ -621,37 +589,22 @@ class RulesEngineMetricCalculationAgent:
                 try:
                     response_data = response.json()
 
-                    # 记录API调用结果
+                    # 记录API调用结果 - 简化版
                     end_time = datetime.now()
                     call_id = f"rules_api_{knowledge_id}_{'{:.2f}'.format((end_time - start_time).total_seconds())}"
                     api_call_info = {
                         "call_id": call_id,
-                        "timestamp": end_time.isoformat(),
-                        "agent": "RulesEngineMetricCalculationAgent",
-                        "api_endpoint": url,
-                        "config_name": knowledge_id,
-                        "request": {
-                            "method": method,
-                            "url": url,
-                            "headers": headers,
-                            "json_data": json_data,
-                            "start_time": start_time.isoformat()
-                        },
-                        "response": {
-                            "status_code": response.status_code,
-                            "data": response_data,
-                            "end_time": end_time.isoformat(),
-                            "duration": (end_time - start_time).total_seconds()
-                        },
-                        "success": True
+                        "response": response_data
                     }
                     self.api_calls.append(api_call_info)
 
-                    # 保存API结果到文件
-                    api_results_dir = "api_results"
+                    # 保存API结果到文件 - 成功状态
+                    # 使用运行ID创建独立的文件夹
+                    run_id = os.environ.get('FLOW_RUN_ID', 'default')
+                    api_results_dir = f"api_results_{run_id}"
                     os.makedirs(api_results_dir, exist_ok=True)
                     timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
-                    filename = f"{timestamp}_{call_id}.json"
+                    filename = f"{timestamp}_{call_id}_success.json"
                     filepath = os.path.join(api_results_dir, filename)
 
                     try:
@@ -667,38 +620,26 @@ class RulesEngineMetricCalculationAgent:
                         "status_code": response.status_code
                     }
                 except json.JSONDecodeError:
-                    # 记录JSON解析失败的API调用
+                    # 记录JSON解析失败的API调用 - 简化版
                     end_time = datetime.now()
                     call_id = f"rules_api_{knowledge_id}_{'{:.2f}'.format((end_time - start_time).total_seconds())}"
                     api_call_info = {
                         "call_id": call_id,
-                        "timestamp": end_time.isoformat(),
-                        "agent": "RulesEngineMetricCalculationAgent",
-                        "api_endpoint": url,
-                        "config_name": knowledge_id,
-                        "request": {
-                            "method": method,
-                            "url": url,
-                            "headers": headers,
-                            "json_data": json_data,
-                            "start_time": start_time.isoformat()
-                        },
                         "response": {
                             "status_code": response.status_code,
                             "data": response.text,
-                            "error": "JSON解析失败",
-                            "end_time": end_time.isoformat(),
-                            "duration": (end_time - start_time).total_seconds()
-                        },
-                        "success": False
+                            "error": "JSON解析失败"
+                        }
                     }
                     self.api_calls.append(api_call_info)
 
-                    # 保存API结果到文件
-                    api_results_dir = "api_results"
+                    # 保存API结果到文件 - 失败状态
+                    # 使用运行ID创建独立的文件夹
+                    run_id = os.environ.get('FLOW_RUN_ID', 'default')
+                    api_results_dir = f"api_results_{run_id}"
                     os.makedirs(api_results_dir, exist_ok=True)
                     timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
-                    filename = f"{timestamp}_{call_id}.json"
+                    filename = f"{timestamp}_{call_id}_fail.json"
                     filepath = os.path.join(api_results_dir, filename)
 
                     try:
@@ -714,36 +655,25 @@ class RulesEngineMetricCalculationAgent:
                         "status_code": response.status_code
                     }
             else:
-                # 记录失败的API调用
+                # 记录失败的API调用 - 简化版
                 end_time = datetime.now()
                 call_id = f"rules_api_{knowledge_id}_{'{:.2f}'.format((end_time - start_time).total_seconds())}"
                 api_call_info = {
                     "call_id": call_id,
-                    "timestamp": end_time.isoformat(),
-                    "agent": "RulesEngineMetricCalculationAgent",
-                    "api_endpoint": url,
-                    "config_name": knowledge_id,
-                    "request": {
-                        "method": method,
-                        "url": url,
-                        "headers": headers,
-                        "json_data": json_data,
-                        "start_time": start_time.isoformat()
-                    },
                     "response": {
                         "status_code": response.status_code,
-                        "error": response.text,
-                        "end_time": end_time.isoformat(),
-                        "duration": (end_time - start_time).total_seconds()
-                    },
-                    "success": False
+                        "error": response.text
+                    }
                 }
                 self.api_calls.append(api_call_info)
 
-                # 保存API结果到文件
-                api_results_dir = "api_results"
+                # 保存API结果到文件 - 失败状态
+                # 使用运行ID创建独立的文件夹
+                run_id = os.environ.get('FLOW_RUN_ID', 'default')
+                api_results_dir = f"api_results_{run_id}"
                 os.makedirs(api_results_dir, exist_ok=True)
-                filename = f"{call_id}.json"
+                timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
+                filename = f"{timestamp}_{call_id}_fail.json"
                 filepath = os.path.join(api_results_dir, filename)
 
                 try:
@@ -760,35 +690,24 @@ class RulesEngineMetricCalculationAgent:
                 }
 
         except requests.exceptions.Timeout:
-            # 记录API调用结果(超时)
+            # 记录API调用结果(超时)- 简化版
             end_time = datetime.now()
             call_id = f"rules_api_{knowledge_id}_{'{:.2f}'.format((end_time - start_time).total_seconds())}"
             api_call_info = {
                 "call_id": call_id,
-                "timestamp": end_time.isoformat(),
-                "agent": "RulesEngineMetricCalculationAgent",
-                "api_endpoint": url,
-                "config_name": knowledge_id,
-                "request": {
-                    "method": method,
-                    "url": url,
-                    "headers": headers,
-                    "json_data": json_data if 'json_data' in locals() else None,
-                    "start_time": start_time.isoformat()
-                },
                 "response": {
-                    "error": "API调用超时",
-                    "end_time": end_time.isoformat(),
-                    "duration": (end_time - start_time).total_seconds()
-                },
-                "success": False
+                    "error": "API调用超时"
+                }
             }
             self.api_calls.append(api_call_info)
 
-            # 保存API结果到文件
-            api_results_dir = "api_results"
+            # 保存API结果到文件 - 失败状态
+            # 使用运行ID创建独立的文件夹
+            run_id = os.environ.get('FLOW_RUN_ID', 'default')
+            api_results_dir = f"api_results_{run_id}"
             os.makedirs(api_results_dir, exist_ok=True)
-            filename = f"{call_id}.json"
+            timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
+            filename = f"{timestamp}_{call_id}_fail.json"
             filepath = os.path.join(api_results_dir, filename)
 
             try:
@@ -803,35 +722,24 @@ class RulesEngineMetricCalculationAgent:
                 "message": "规则引擎API调用超时"
             }
         except requests.exceptions.RequestException as e:
-            # 记录API调用结果(请求异常)
+            # 记录API调用结果(请求异常)- 简化版
             end_time = datetime.now()
             call_id = f"rules_api_{knowledge_id}_{'{:.2f}'.format((end_time - start_time).total_seconds())}"
             api_call_info = {
                 "call_id": call_id,
-                "timestamp": end_time.isoformat(),
-                "agent": "RulesEngineMetricCalculationAgent",
-                "api_endpoint": url,
-                "config_name": knowledge_id,
-                "request": {
-                    "method": method,
-                    "url": url,
-                    "headers": headers,
-                    "json_data": json_data if 'json_data' in locals() else None,
-                    "start_time": start_time.isoformat()
-                },
                 "response": {
-                    "error": str(e),
-                    "end_time": end_time.isoformat(),
-                    "duration": (end_time - start_time).total_seconds()
-                },
-                "success": False
+                    "error": str(e)
+                }
             }
             self.api_calls.append(api_call_info)
 
-            # 保存API结果到文件
-            api_results_dir = "api_results"
+            # 保存API结果到文件 - 失败状态
+            # 使用运行ID创建独立的文件夹
+            run_id = os.environ.get('FLOW_RUN_ID', 'default')
+            api_results_dir = f"api_results_{run_id}"
             os.makedirs(api_results_dir, exist_ok=True)
-            filename = f"{call_id}.json"
+            timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
+            filename = f"{timestamp}_{call_id}_fail.json"
             filepath = os.path.join(api_results_dir, filename)
 
             try:
@@ -846,35 +754,24 @@ class RulesEngineMetricCalculationAgent:
                 "message": f"规则引擎API调用异常: {str(e)}"
             }
         except Exception as e:
-            # 记录API调用结果(其他异常)
+            # 记录API调用结果(其他异常)- 简化版
             end_time = datetime.now()
             call_id = f"rules_api_{knowledge_id}_{'{:.2f}'.format((end_time - start_time).total_seconds())}"
             api_call_info = {
                 "call_id": call_id,
-                "timestamp": end_time.isoformat(),
-                "agent": "RulesEngineMetricCalculationAgent",
-                "api_endpoint": url,
-                "config_name": knowledge_id,
-                "request": {
-                    "method": method,
-                    "url": url,
-                    "headers": headers,
-                    "json_data": json_data if 'json_data' in locals() else None,
-                    "start_time": start_time.isoformat()
-                },
                 "response": {
-                    "error": str(e),
-                    "end_time": end_time.isoformat(),
-                    "duration": (end_time - start_time).total_seconds()
-                },
-                "success": False
+                    "error": str(e)
+                }
             }
             self.api_calls.append(api_call_info)
 
-            # 保存API结果到文件
-            api_results_dir = "api_results"
+            # 保存API结果到文件 - 失败状态
+            # 使用运行ID创建独立的文件夹
+            run_id = os.environ.get('FLOW_RUN_ID', 'default')
+            api_results_dir = f"api_results_{run_id}"
             os.makedirs(api_results_dir, exist_ok=True)
-            filename = f"{call_id}.json"
+            timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
+            filename = f"{timestamp}_{call_id}_fail.json"
             filepath = os.path.join(api_results_dir, filename)
 
             try:

+ 205 - 0
llmops/batch_runner.py

@@ -0,0 +1,205 @@
+#!/usr/bin/env python3
+"""
+批量运行器 - 批量执行Complete Agent Flow
+========================================
+
+此脚本可以批量运行多次完整的智能体工作流,每次运行会创建独立的日志文件夹。
+
+使用方法:
+    python batch_runner.py
+
+配置参数:
+    - 运行次数: RUNS = 10
+    - 行业: INDUSTRY = "农业"
+    - 数据文件: DATA_FILE = "data_files/交易流水样例数据.csv"
+    - 查询问题: QUESTION = "请生成一份详细的农业经营贷流水分析报告..."
+
+文件夹结构:
+    api_results_1/     # 第一次运行的日志
+    api_results_2/     # 第二次运行的日志
+    ...
+    api_results_10/    # 第十次运行的日志
+
+作者: Big Agent Team
+版本: 1.0.0
+创建时间: 2024-12-20
+"""
+
+import asyncio
+import os
+from datetime import datetime
+from typing import List, Dict, Any
+
+import sys
+import os
+
+# 添加项目根目录到路径,以便导入config
+current_dir = os.path.dirname(os.path.abspath(__file__))
+parent_dir = os.path.dirname(current_dir)
+sys.path.insert(0, parent_dir)
+
+# 根据执行方式选择导入方式
+if __name__ == "__main__":
+    # 直接执行文件时,使用绝对导入
+    from llmops.complete_agent_flow_rule import run_complete_agent_flow
+    from llmops.agents.data_manager import DataManager
+else:
+    # 作为模块导入时,使用相对导入
+    from .complete_agent_flow_rule import run_complete_agent_flow
+    from .agents.data_manager import DataManager
+
+import config
+
+# ========== 配置参数 ==========
+RUNS = 2  # 运行次数
+INDUSTRY = "农业"  # 行业
+DATA_FILE = "data_files/交易流水样例数据.csv"  # 数据文件路径
+QUESTION = "请生成一份详细的农业经营贷流水分析报告,需要包含:1.总收入和总支出统计 2.收入笔数和支出笔数 3.各类型收入支出占比分析 4.交易对手收入支出TOP3排名 5.按月份的收入支出趋势分析 6.账户数量和交易时间范围统计 7.资金流入流出月度统计等全面指标"  # 分析查询
+# ==============================
+
+
+async def run_single_flow(run_id: str, question: str, industry: str, data: List[Dict[str, Any]], file_name: str) -> Dict[str, Any]:
+    """
+    运行单个工作流实例
+
+    Args:
+        run_id: 运行ID
+        question: 用户查询
+        industry: 行业
+        data: 数据集
+        file_name: 文件名
+
+    Returns:
+        运行结果
+    """
+    print(f"\n{'='*60}")
+    print(f"🚀 开始运行 #{run_id}")
+    print(f"📁 日志文件夹: api_results_{run_id}")
+    print(f"{'='*60}")
+
+    # 设置环境变量,让所有agent使用正确的文件夹
+    os.environ['FLOW_RUN_ID'] = run_id
+
+    try:
+        result = await run_complete_agent_flow(
+            question=question,
+            industry=industry,
+            data=data,
+            file_name=file_name,
+            api_key=config.DEEPSEEK_API_KEY,
+            session_id=f"batch-run-{run_id}"
+        )
+
+        if result.get('success'):
+            summary = result.get('execution_summary', {})
+            print(f"✅ 运行 #{run_id} 成功完成")
+            print(f"   规划步骤: {summary.get('planning_steps', 0)}")
+            print(f"   指标计算: {summary.get('metrics_computed', 0)}")
+        else:
+            print(f"❌ 运行 #{run_id} 失败: {result.get('error', '未知错误')}")
+
+        return result
+
+    except Exception as e:
+        print(f"❌ 运行 #{run_id} 发生异常: {e}")
+        return {
+            "success": False,
+            "error": str(e),
+            "run_id": run_id
+        }
+
+
+async def run_batch(runs: int, question: str, industry: str, data_file: str):
+    """
+    批量运行工作流
+
+    Args:
+        runs: 运行次数
+        question: 用户查询
+        industry: 行业
+        data_file: 数据文件路径
+    """
+    print("🚀 批量运行器启动")
+    print(f"📊 计划运行次数: {runs}")
+    print(f"🏭 行业: {industry}")
+    print(f"📁 数据文件: {data_file}")
+    print(f"❓ 查询: {question}")
+    print(f"{'='*80}")
+
+    # 检查API密钥
+    if not config.DEEPSEEK_API_KEY:
+        print("❌ 未找到API密钥,请检查config.py")
+        return
+
+    # 加载数据
+    try:
+        # 如果是相对路径,从项目根目录查找
+        if not os.path.isabs(data_file):
+            data_file = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), data_file)
+        data = DataManager.load_data_from_csv_file(data_file)
+        print(f"📊 数据加载成功: {len(data)} 条记录")
+    except Exception as e:
+        print(f"❌ 数据加载失败: {e}")
+        return
+
+    # 运行结果统计
+    successful_runs = 0
+    failed_runs = 0
+    results = []
+
+    # 逐个运行
+    for i in range(1, runs + 1):
+        run_id = str(i)
+        result = await run_single_flow(run_id, question, industry, data, os.path.basename(data_file))
+
+        results.append(result)
+
+        if result.get('success'):
+            successful_runs += 1
+        else:
+            failed_runs += 1
+
+        # 添加短暂延迟,避免API调用过于频繁
+        if i < runs:  # 最后一次不需要延迟
+            await asyncio.sleep(1)
+
+    # 输出统计结果
+    print(f"\n{'='*80}")
+    print("📊 批量运行完成统计")
+    print(f"{'='*80}")
+    print(f"总运行次数: {runs}")
+    print(f"成功次数: {successful_runs}")
+    print(f"失败次数: {failed_runs}")
+    print(f"成功率: {successful_runs/runs*100:.1f}%")
+
+    # 显示各运行的日志文件夹
+    print(f"\n📁 日志文件夹列表:")
+    for i in range(1, runs + 1):
+        folder_name = f"api_results_{i}"
+        status = "✅" if results[i-1].get('success') else "❌"
+        print(f"  {status} {folder_name}")
+
+    print("\n🎉 批量运行完成!")
+    print(f"💡 提示: 每次运行的完整日志保存在对应的 api_results_[数字] 文件夹中")
+
+
+def main():
+    """主函数"""
+    print("🚀 使用配置参数运行批量任务")
+    print(f"📊 运行次数: {RUNS}")
+    print(f"🏭 行业: {INDUSTRY}")
+    print(f"📁 数据文件: {DATA_FILE}")
+    print(f"❓ 查询: {QUESTION[:50]}...")
+    print("-" * 80)
+
+    # 运行批量任务
+    asyncio.run(run_batch(
+        runs=RUNS,
+        question=QUESTION,
+        industry=INDUSTRY,
+        data_file=DATA_FILE
+    ))
+
+
+if __name__ == "__main__":
+    main()

+ 1 - 2
llmops/config.py

@@ -54,8 +54,7 @@ RULES_ENGINE_BASE_URL = os.getenv("RULES_ENGINE_BASE_URL", "http://10.192.72.11:
 PATHS = {
     "json_configs": "json_files",      # JSON配置文件目录 - 存储指标计算配置
     "knowledge_base": "knowledge_base", # 知识库目录 - 存储生成的知识文档
-    "logs": "logs",                   # 日志目录 - 存储系统运行日志
-    "api_results": "api_results"      # API结果目录 - 存储所有API调用结果
+    "logs": "logs"                   # 日志目录 - 存储系统运行日志
 }
 
 # ============================================================================

+ 1 - 0
requirements.txt

@@ -46,3 +46,4 @@ uuid_utils==0.12.0
 uvicorn==0.38.0
 xxhash==3.6.0
 zstandard==0.25.0
+python-dotenv==1.0.0