aiecs 1.2.1__py3-none-any.whl → 1.3.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of aiecs might be problematic. Click here for more details.

Files changed (56) hide show
  1. aiecs/__init__.py +1 -1
  2. aiecs/config/config.py +2 -1
  3. aiecs/llm/clients/vertex_client.py +5 -0
  4. aiecs/main.py +2 -2
  5. aiecs/scripts/tools_develop/README.md +111 -2
  6. aiecs/scripts/tools_develop/TOOL_AUTO_DISCOVERY.md +234 -0
  7. aiecs/scripts/tools_develop/validate_tool_schemas.py +80 -21
  8. aiecs/scripts/tools_develop/verify_tools.py +347 -0
  9. aiecs/tools/__init__.py +94 -30
  10. aiecs/tools/apisource/__init__.py +106 -0
  11. aiecs/tools/apisource/intelligence/__init__.py +20 -0
  12. aiecs/tools/apisource/intelligence/data_fusion.py +378 -0
  13. aiecs/tools/apisource/intelligence/query_analyzer.py +387 -0
  14. aiecs/tools/apisource/intelligence/search_enhancer.py +384 -0
  15. aiecs/tools/apisource/monitoring/__init__.py +12 -0
  16. aiecs/tools/apisource/monitoring/metrics.py +308 -0
  17. aiecs/tools/apisource/providers/__init__.py +114 -0
  18. aiecs/tools/apisource/providers/base.py +684 -0
  19. aiecs/tools/apisource/providers/census.py +412 -0
  20. aiecs/tools/apisource/providers/fred.py +575 -0
  21. aiecs/tools/apisource/providers/newsapi.py +402 -0
  22. aiecs/tools/apisource/providers/worldbank.py +346 -0
  23. aiecs/tools/apisource/reliability/__init__.py +14 -0
  24. aiecs/tools/apisource/reliability/error_handler.py +362 -0
  25. aiecs/tools/apisource/reliability/fallback_strategy.py +420 -0
  26. aiecs/tools/apisource/tool.py +814 -0
  27. aiecs/tools/apisource/utils/__init__.py +12 -0
  28. aiecs/tools/apisource/utils/validators.py +343 -0
  29. aiecs/tools/langchain_adapter.py +95 -17
  30. aiecs/tools/search_tool/__init__.py +102 -0
  31. aiecs/tools/search_tool/analyzers.py +583 -0
  32. aiecs/tools/search_tool/cache.py +280 -0
  33. aiecs/tools/search_tool/constants.py +127 -0
  34. aiecs/tools/search_tool/context.py +219 -0
  35. aiecs/tools/search_tool/core.py +773 -0
  36. aiecs/tools/search_tool/deduplicator.py +123 -0
  37. aiecs/tools/search_tool/error_handler.py +257 -0
  38. aiecs/tools/search_tool/metrics.py +375 -0
  39. aiecs/tools/search_tool/rate_limiter.py +177 -0
  40. aiecs/tools/search_tool/schemas.py +297 -0
  41. aiecs/tools/statistics/data_loader_tool.py +2 -2
  42. aiecs/tools/statistics/data_transformer_tool.py +1 -1
  43. aiecs/tools/task_tools/__init__.py +8 -8
  44. aiecs/tools/task_tools/report_tool.py +1 -1
  45. aiecs/tools/tool_executor/__init__.py +2 -0
  46. aiecs/tools/tool_executor/tool_executor.py +284 -14
  47. aiecs/utils/__init__.py +11 -0
  48. aiecs/utils/cache_provider.py +698 -0
  49. aiecs/utils/execution_utils.py +5 -5
  50. {aiecs-1.2.1.dist-info → aiecs-1.3.1.dist-info}/METADATA +1 -1
  51. {aiecs-1.2.1.dist-info → aiecs-1.3.1.dist-info}/RECORD +55 -23
  52. aiecs/tools/task_tools/search_tool.py +0 -1123
  53. {aiecs-1.2.1.dist-info → aiecs-1.3.1.dist-info}/WHEEL +0 -0
  54. {aiecs-1.2.1.dist-info → aiecs-1.3.1.dist-info}/entry_points.txt +0 -0
  55. {aiecs-1.2.1.dist-info → aiecs-1.3.1.dist-info}/licenses/LICENSE +0 -0
  56. {aiecs-1.2.1.dist-info → aiecs-1.3.1.dist-info}/top_level.txt +0 -0
aiecs/__init__.py CHANGED
@@ -5,7 +5,7 @@ A powerful Python middleware framework for building AI-powered applications
5
5
  with tool orchestration, task execution, and multi-provider LLM support.
6
6
  """
7
7
 
8
- __version__ = "1.2.1"
8
+ __version__ = "1.3.1"
9
9
  __author__ = "AIECS Team"
10
10
  __email__ = "iretbl@gmail.com"
11
11
 
aiecs/config/config.py CHANGED
@@ -54,7 +54,7 @@ class Settings(BaseSettings):
54
54
  reload: bool = Field(default=False, alias="RELOAD")
55
55
  port: int = Field(default=8000, alias="PORT")
56
56
 
57
- model_config = ConfigDict(env_file=".env", env_file_encoding="utf-8")
57
+ model_config = ConfigDict(env_file=".env", env_file_encoding="utf-8", extra="allow")
58
58
 
59
59
  @property
60
60
  def database_config(self) -> dict:
@@ -77,6 +77,7 @@ class Settings(BaseSettings):
77
77
  "enable_local_fallback": True,
78
78
  "local_storage_path": "./storage"
79
79
  }
80
+
80
81
 
81
82
  def validate_llm_models_config(self) -> bool:
82
83
  """
@@ -1,6 +1,7 @@
1
1
  import asyncio
2
2
  import logging
3
3
  import os
4
+ import warnings
4
5
  from typing import Dict, Any, Optional, List, AsyncGenerator
5
6
  import vertexai
6
7
  from vertexai.generative_models import GenerativeModel, HarmCategory, HarmBlockThreshold, GenerationConfig, SafetySetting
@@ -9,6 +10,10 @@ from google.oauth2 import service_account
9
10
  from aiecs.llm.clients.base_client import BaseLLMClient, LLMMessage, LLMResponse, ProviderNotAvailableError, RateLimitError
10
11
  from aiecs.config.config import get_settings
11
12
 
13
+ # Suppress Vertex AI SDK deprecation warnings (deprecated June 2025, removal June 2026)
14
+ # TODO: Migrate to Google Gen AI SDK when official migration guide is available
15
+ warnings.filterwarnings('ignore', category=UserWarning, module='vertexai.generative_models._generative_models')
16
+
12
17
  logger = logging.getLogger(__name__)
13
18
 
14
19
  class VertexAIClient(BaseLLMClient):
aiecs/main.py CHANGED
@@ -142,7 +142,7 @@ async def lifespan(app: FastAPI):
142
142
  app = FastAPI(
143
143
  title="AIECS - AI Execute Services",
144
144
  description="Middleware service for AI-powered task execution and tool orchestration",
145
- version="1.2.1",
145
+ version="1.3.1",
146
146
  lifespan=lifespan
147
147
  )
148
148
 
@@ -167,7 +167,7 @@ async def health_check():
167
167
  return {
168
168
  "status": "healthy",
169
169
  "service": "aiecs",
170
- "version": "1.2.1"
170
+ "version": "1.3.1"
171
171
  }
172
172
 
173
173
 
@@ -4,7 +4,116 @@
4
4
 
5
5
  ## 📋 脚本列表
6
6
 
7
- ### 1. 类型注解检查器 (`check_type_annotations.py`)
7
+ ### 1. 工具验证器 (`verify_tools.py`)
8
+
9
+ 快速验证和展示 aiecs.tools 注册的所有工具和功能,帮助开发者了解工具注册情况。
10
+
11
+ **用途**:
12
+ - 列出所有注册的工具及其状态
13
+ - 显示每个工具的描述和功能方法
14
+ - 提供工具使用示例
15
+ - 分析工具注册表信息
16
+ - 展示工具继承关系和模块分布
17
+
18
+ **命令**:
19
+ ```bash
20
+ # 从项目根目录运行(推荐)
21
+ python -m aiecs.scripts.tools_develop.verify_tools
22
+
23
+ # 直接运行脚本
24
+ python aiecs/scripts/tools_develop/verify_tools.py
25
+ ```
26
+
27
+ **输出示例**:
28
+ ```
29
+ ================================================================================
30
+ AIECS Tools 注册工具验证
31
+ ================================================================================
32
+
33
+ 发现 26 个注册的工具
34
+
35
+ ================================================================================
36
+ 📁 任务工具 (10 个)
37
+ ================================================================================
38
+
39
+ [1] chart
40
+ 描述: Chart and visualization operations
41
+ 状态: loaded
42
+
43
+ [2] pandas
44
+ 描述: Data analysis and manipulation
45
+ 状态: loaded
46
+
47
+ ... (更多工具)
48
+
49
+ ================================================================================
50
+ 📁 文档工具 (7 个)
51
+ ================================================================================
52
+
53
+ [11] document_parser
54
+ 描述: Document parsing and content extraction
55
+ 状态: loaded
56
+
57
+ ... (更多工具)
58
+
59
+ ================================================================================
60
+ 📁 数据统计工具 (9 个)
61
+ ================================================================================
62
+
63
+ [18] data_loader
64
+ 描述: Universal data loading from multiple formats
65
+ 状态: loaded
66
+
67
+ ... (更多工具)
68
+
69
+ ================================================================================
70
+ ✅ 工具列表显示完成! 共 26 个工具
71
+ ================================================================================
72
+
73
+ ================================================================================
74
+ 🎮 交互模式
75
+ ================================================================================
76
+
77
+ 提示:
78
+ - 输入工具序号 (1-26) 查看详细功能
79
+ - 输入工具名称查看详细功能
80
+ - 输入 'list' 重新显示工具列表
81
+ - 输入 'q' 或 'quit' 退出
82
+
83
+ 👉 请选择工具 > pandas
84
+
85
+ ================================================================================
86
+ 🔍 加载工具: pandas
87
+ ================================================================================
88
+
89
+ ⏳ 正在加载...
90
+ 已触发 task_tools.pandas_tool 模块加载
91
+
92
+ ✅ 工具已成功加载
93
+ 类名: PandasTool
94
+ 模块: aiecs.tools.task_tools.pandas_tool
95
+
96
+ 📋 原子功能列表 (共 41 个方法):
97
+ --------------------------------------------------------------------------------
98
+
99
+ [1] apply(records: List, func: str, columns: List, axis: int = 0) -> List
100
+ Apply a function to specified columns or rows.
101
+
102
+ [2] astype(records: List, dtypes: Dict) -> List
103
+ Convert column types in DataFrame.
104
+
105
+ [3] concat(records_list: List, axis: int = 0) -> List
106
+ Concatenate multiple DataFrames.
107
+
108
+ ... (更多方法)
109
+
110
+ [41] write_file(records: List, file_path: str, file_type: str = 'csv') -> Dict
111
+ Write DataFrame to a file.
112
+
113
+ --------------------------------------------------------------------------------
114
+ ```
115
+
116
+ ### 2. 类型注解检查器 (`check_type_annotations.py`)
8
117
 
9
118
  检查工具方法的类型注解完整性,确保所有方法都有完整的类型注解(参数类型 + 返回类型)。
10
119
 
@@ -49,7 +158,7 @@ aiecs-tools-check-annotations pandas --verbose
49
158
  ====================================================================================================
50
159
  ```
51
160
 
52
- ### 2. Schema 质量验证器 (`validate_tool_schemas.py`)
161
+ ### 3. Schema 质量验证器 (`validate_tool_schemas.py`)
53
162
 
54
163
  验证自动生成的 Schema 质量,识别需要改进的文档字符串。
55
164
 
@@ -0,0 +1,234 @@
1
+ # 工具自动发现机制
2
+
3
+ ## 📋 概述
4
+
5
+ 从现在开始,**无需手动维护工具列表**!系统会自动发现所有使用 `@register_tool` 装饰器注册的工具。
6
+
7
+ ## ✨ 特性
8
+
9
+ ### 1. 自动工具发现
10
+ - ✅ 自动扫描 `aiecs/tools/task_tools/`、`aiecs/tools/docs/`、`aiecs/tools/statistics/` 目录
11
+ - ✅ 自动识别所有 `@register_tool` 装饰器
12
+ - ✅ 自动提取工具名称和描述
13
+ - ✅ 自动分类(task/docs/statistics)
14
+
15
+ ### 2. 零维护成本
16
+ - ✅ 添加新工具:只需在工具类上添加 `@register_tool("tool_name")` 装饰器
17
+ - ✅ 删除工具:直接删除文件或移除装饰器
18
+ - ✅ 重命名工具:修改装饰器参数即可
19
+ - ✅ 无需修改任何配置文件
20
+
21
+ ## 🔧 工作原理
22
+
23
+ ### aiecs/tools/__init__.py
24
+
25
+ ```python
26
+ def _auto_discover_tools():
27
+ """自动发现所有工具"""
28
+ # 扫描工具目录
29
+ for dir_name, category in [('task_tools', 'task'), ('docs', 'docs'), ('statistics', 'statistics')]:
30
+ # 查找所有 Python 文件
31
+ for filename in os.listdir(dir_path):
32
+ # 读取文件内容
33
+ # 使用正则表达式查找 @register_tool 装饰器
34
+ pattern = r'@register_tool\([\'"]([^\'"]+)[\'"]\)'
35
+ matches = re.findall(pattern, content)
36
+ # 提取工具名称和描述
37
+ # 注册为占位符,等待懒加载
38
+ ```
39
+
40
+ ### verify_tools.py
41
+
42
+ ```python
43
+ def auto_discover_tool_modules():
44
+ """自动发现工具模块映射"""
45
+ # 扫描工具目录
46
+ # 查找 @register_tool 装饰器
47
+ # 建立工具名称到模块路径的映射
48
+ # 返回映射表供动态加载使用
49
+ ```
50
+
51
+ ## 📝 如何添加新工具
52
+
53
+ ### 步骤 1: 创建工具文件
54
+
55
+ 在合适的目录创建工具文件(例如:`aiecs/tools/task_tools/my_new_tool.py`)
56
+
57
+ ### 步骤 2: 添加装饰器
58
+
59
+ ```python
60
+ from aiecs.tools import register_tool
61
+ from aiecs.tools.base_tool import BaseTool
62
+
63
+ @register_tool("my_new_tool")
64
+ class MyNewTool(BaseTool):
65
+ """
66
+ 这是一个新工具的简短描述。
67
+
68
+ 这个描述会被自动提取并显示在工具列表中。
69
+ """
70
+
71
+ def my_method(self, param: str) -> str:
72
+ """执行某个操作"""
73
+ return f"Result: {param}"
74
+ ```
75
+
76
+ ### 步骤 3: 验证
77
+
78
+ 运行验证脚本查看新工具是否被发现:
79
+
80
+ ```bash
81
+ poetry run python -m aiecs.scripts.tools_develop.verify_tools
82
+ ```
83
+
84
+ 就这样!**无需修改任何其他文件**!
85
+
86
+ ## 🎯 支持的目录结构
87
+
88
+ ```
89
+ aiecs/tools/
90
+ ├── task_tools/ # 任务工具 (category: task)
91
+ │ ├── chart_tool.py # @register_tool("chart")
92
+ │ ├── pandas_tool.py # @register_tool("pandas")
93
+ │ └── ...
94
+ ├── docs/ # 文档工具 (category: docs)
95
+ │ ├── document_parser_tool.py # @register_tool("document_parser")
96
+ │ ├── document_writer_tool.py # @register_tool("document_writer")
97
+ │ └── ...
98
+ └── statistics/ # 统计工具 (category: statistics)
99
+ ├── data_loader_tool.py # @register_tool("data_loader")
100
+ ├── data_profiler_tool.py # @register_tool("data_profiler")
101
+ └── ...
102
+ ```
103
+
104
+ ## 🔍 描述提取规则
105
+
106
+ 系统会自动提取类文档字符串的**第一行**作为工具描述:
107
+
108
+ ```python
109
+ @register_tool("example")
110
+ class ExampleTool(BaseTool):
111
+ """
112
+ 这一行会被用作工具描述 ✅
113
+
114
+ 下面的内容不会被提取。
115
+ 可以写详细的文档说明。
116
+ """
117
+ ```
118
+
119
+ **建议**:
120
+ - 第一行保持简短(< 200 字符)
121
+ - 清晰描述工具的主要功能
122
+ - 避免使用多行描述
123
+
124
+ ## 📊 当前发现的工具统计
125
+
126
+ 截至最后扫描,系统发现了 **26 个工具**:
127
+
128
+ - **任务工具** (10个):chart, classifier, image, office, pandas, report, research, scraper, search, stats
129
+ - **文档工具** (7个):document_parser, document_writer, document_creator, document_layout, content_insertion, ai_document_orchestrator, ai_document_writer_orchestrator
130
+ - **数据统计工具** (9个):data_loader, data_profiler, data_transformer, data_visualizer, model_trainer, statistical_analyzer, ai_data_analysis_orchestrator, ai_insight_generator, ai_report_orchestrator
131
+
132
+ ## ⚡ 性能优化
133
+
134
+ ### 占位符机制
135
+ - 工具发现时创建轻量级占位符
136
+ - 不导入实际工具模块(避免重依赖)
137
+ - 只在实际使用时才加载工具
138
+
139
+ ### 懒加载
140
+ - `verify_tools.py` 只在用户选择工具时才加载模块
141
+ - 避免启动时加载所有工具
142
+ - 提高响应速度
143
+
144
+ ## 🧪 测试验证
145
+
146
+ ### 验证工具发现
147
+ ```bash
148
+ poetry run python -m aiecs.scripts.tools_develop.verify_tools
149
+ ```
150
+
151
+ ### 验证特定工具
152
+ 在交互模式中输入工具名称或序号:
153
+ ```
154
+ 👉 请选择工具 > pandas
155
+ 👉 请选择工具 > 7
156
+ ```
157
+
158
+ ### 验证描述提取
159
+ 检查工具列表中的描述是否正确提取自类文档字符串。
160
+
161
+ ## 🔄 兼容性
162
+
163
+ ### 向后兼容
164
+ - 现有工具无需修改
165
+ - 只要有 `@register_tool` 装饰器即可被发现
166
+ - 保持与现有代码的兼容性
167
+
168
+ ### 新增目录支持
169
+ 如果未来需要添加新的工具目录(如 `aiecs/tools/ml_tools/`),只需修改两处:
170
+
171
+ 1. **aiecs/tools/__init__.py**
172
+ ```python
173
+ tool_dirs = [
174
+ ('task_tools', 'task'),
175
+ ('docs', 'docs'),
176
+ ('statistics', 'statistics'),
177
+ ('ml_tools', 'ml'), # 新增
178
+ ]
179
+ ```
180
+
181
+ 2. **verify_tools.py**
182
+ ```python
183
+ tool_dirs = {
184
+ 'task_tools': 'aiecs.tools.task_tools',
185
+ 'docs': 'aiecs.tools.docs',
186
+ 'statistics': 'aiecs.tools.statistics',
187
+ 'ml_tools': 'aiecs.tools.ml_tools', # 新增
188
+ }
189
+ ```
190
+
191
+ ## ❓ 常见问题
192
+
193
+ ### Q: 工具没有被发现?
194
+ **A:** 检查以下几点:
195
+ 1. 文件是否在支持的目录中(task_tools/docs/statistics)
196
+ 2. 是否使用了 `@register_tool("name")` 装饰器
197
+ 3. 文件名是否以 `.py` 结尾且不是 `__init__.py`
198
+
199
+ ### Q: 描述显示不正确?
200
+ **A:** 检查类文档字符串:
201
+ 1. 文档字符串必须紧跟类定义
202
+ 2. 使用三引号 `"""`
203
+ 3. 确保第一行是简短描述
204
+
205
+ ### Q: 如何重命名工具?
206
+ **A:** 只需修改装饰器参数:
207
+ ```python
208
+ # 旧
209
+ @register_tool("old_name")
210
+
211
+ # 新
212
+ @register_tool("new_name")
213
+ ```
214
+
215
+ ### Q: 如何临时禁用工具?
216
+ **A:** 两种方法:
217
+ 1. 注释掉 `@register_tool` 装饰器
218
+ 2. 移动文件到其他目录
219
+
220
+ ## 🎉 优势总结
221
+
222
+ | 特性 | 手动维护 | 自动发现 |
223
+ |------|---------|---------|
224
+ | 添加工具 | 需修改配置文件 | 只需添加装饰器 ✅ |
225
+ | 删除工具 | 需修改配置文件 | 直接删除文件 ✅ |
226
+ | 维护成本 | 高 | 零 ✅ |
227
+ | 出错风险 | 容易遗漏 | 自动同步 ✅ |
228
+ | 描述准确性 | 可能不一致 | 直接提取 ✅ |
229
+
230
+ ---
231
+
232
+ **维护者**: AIECS Tools Team
233
+ **最后更新**: 2025-10-14
234
+
@@ -104,61 +104,113 @@ def validate_schema_quality(schema: Type[BaseModel], method: callable, method_na
104
104
  return issues
105
105
 
106
106
 
107
+ def find_manual_schema(tool_class: Type, method_name: str) -> Optional[Type[BaseModel]]:
108
+ """
109
+ 查找手动定义的 Schema(与 langchain_adapter 逻辑一致)
110
+
111
+ Args:
112
+ tool_class: 工具类
113
+ method_name: 方法名
114
+
115
+ Returns:
116
+ 找到的 Schema 类,如果没有则返回 None
117
+ """
118
+ schemas = {}
119
+
120
+ # 1. 检查类级别的 schemas
121
+ for attr_name in dir(tool_class):
122
+ attr = getattr(tool_class, attr_name)
123
+ if isinstance(attr, type) and issubclass(attr, BaseModel) and attr.__name__.endswith('Schema'):
124
+ # 标准化:移除 'Schema' 后缀,转小写,移除下划线
125
+ schema_base_name = attr.__name__.replace('Schema', '')
126
+ normalized_name = schema_base_name.replace('_', '').lower()
127
+ schemas[normalized_name] = attr
128
+
129
+ # 2. 检查模块级别的 schemas
130
+ import inspect
131
+ tool_module = inspect.getmodule(tool_class)
132
+ if tool_module:
133
+ for attr_name in dir(tool_module):
134
+ if attr_name.startswith('_'):
135
+ continue
136
+ attr = getattr(tool_module, attr_name)
137
+ if isinstance(attr, type) and issubclass(attr, BaseModel) and attr.__name__.endswith('Schema'):
138
+ schema_base_name = attr.__name__.replace('Schema', '')
139
+ normalized_name = schema_base_name.replace('_', '').lower()
140
+ if normalized_name not in schemas:
141
+ schemas[normalized_name] = attr
142
+
143
+ # 标准化方法名:移除下划线并转小写
144
+ normalized_method_name = method_name.replace('_', '').lower()
145
+
146
+ # 查找匹配的 schema
147
+ return schemas.get(normalized_method_name)
148
+
149
+
107
150
  def analyze_tool_schemas(tool_name: str, tool_class: Type) -> Dict[str, Any]:
108
- """分析工具的 Schema 生成情况"""
109
-
151
+ """分析工具的 Schema 生成情况(支持手动定义和自动生成)"""
152
+
110
153
  metrics = SchemaQualityMetrics()
111
154
  methods_info = []
112
-
155
+
113
156
  for method_name in dir(tool_class):
114
157
  # 跳过私有方法和特殊方法
115
158
  if method_name.startswith('_'):
116
159
  continue
117
-
160
+
118
161
  # 跳过基类方法
119
162
  if method_name in ['run', 'run_async', 'run_batch']:
120
163
  continue
121
-
164
+
122
165
  method = getattr(tool_class, method_name)
123
-
166
+
124
167
  # 跳过非方法属性
125
168
  if not callable(method) or isinstance(method, type):
126
169
  continue
127
-
128
- # 生成 Schema
129
- schema = generate_schema_from_method(method, method_name)
130
-
170
+
171
+ # 首先尝试查找手动定义的 Schema
172
+ manual_schema = find_manual_schema(tool_class, method_name)
173
+
174
+ if manual_schema:
175
+ schema = manual_schema
176
+ schema_type = 'manual'
177
+ else:
178
+ # 如果没有手动 Schema,则自动生成
179
+ schema = generate_schema_from_method(method, method_name)
180
+ schema_type = 'auto'
181
+
131
182
  method_info = {
132
183
  'name': method_name,
133
184
  'schema': schema,
185
+ 'schema_type': schema_type,
134
186
  'issues': []
135
187
  }
136
-
188
+
137
189
  if schema:
138
190
  metrics.add_method(True)
139
-
191
+
140
192
  # 验证质量
141
193
  issues = validate_schema_quality(schema, method, method_name)
142
194
  method_info['issues'] = issues
143
-
195
+
144
196
  # 统计字段
145
197
  for field_name, field_info in schema.model_fields.items():
146
198
  has_type = field_info.annotation is not None
147
199
  has_meaningful_desc = (
148
- field_info.description and
200
+ field_info.description and
149
201
  field_info.description != f"Parameter {field_name}"
150
202
  )
151
203
  metrics.add_field(has_type, has_meaningful_desc)
152
-
204
+
153
205
  # 记录问题
154
206
  for issue in issues:
155
207
  metrics.add_issue(f"{tool_name}.{method_name}: {issue}")
156
208
  else:
157
209
  metrics.add_method(False)
158
210
  method_info['issues'] = ['⚠️ 无法生成 Schema(可能是无参数方法)']
159
-
211
+
160
212
  methods_info.append(method_info)
161
-
213
+
162
214
  return {
163
215
  'metrics': metrics,
164
216
  'methods': methods_info
@@ -167,11 +219,15 @@ def analyze_tool_schemas(tool_name: str, tool_class: Type) -> Dict[str, Any]:
167
219
 
168
220
  def print_tool_report(tool_name: str, result: Dict, verbose: bool = False, show_examples: bool = False):
169
221
  """打印工具报告"""
170
-
222
+
171
223
  metrics = result['metrics']
172
224
  methods = result['methods']
173
225
  scores = metrics.get_scores()
174
-
226
+
227
+ # 统计手动和自动 schema
228
+ manual_schemas = [m for m in methods if m.get('schema_type') == 'manual']
229
+ auto_schemas = [m for m in methods if m.get('schema_type') == 'auto']
230
+
175
231
  # 状态图标
176
232
  overall = scores['overall_score']
177
233
  if overall >= 90:
@@ -186,10 +242,12 @@ def print_tool_report(tool_name: str, result: Dict, verbose: bool = False, show_
186
242
  else:
187
243
  status = "❌"
188
244
  grade = "D (需改进)"
189
-
245
+
190
246
  print(f"\n{status} {tool_name}")
191
247
  print(f" 方法数: {metrics.total_methods}")
192
248
  print(f" 成功生成 Schema: {metrics.schemas_generated} ({scores['generation_rate']:.1f}%)")
249
+ print(f" - 手动定义: {len(manual_schemas)} 个")
250
+ print(f" - 自动生成: {len(auto_schemas)} 个")
193
251
  print(f" 描述质量: {scores['description_quality']:.1f}%")
194
252
  print(f" 综合评分: {scores['overall_score']:.1f}% ({grade})")
195
253
 
@@ -215,7 +273,8 @@ def print_tool_report(tool_name: str, result: Dict, verbose: bool = False, show_
215
273
  print(f"\n 示例 Schema:")
216
274
  for method_info in methods_with_schema[:2]:
217
275
  schema = method_info['schema']
218
- print(f"\n {method_info['name']} {schema.__name__}")
276
+ schema_type_label = "🔧 手动定义" if method_info.get('schema_type') == 'manual' else "🤖 自动生成"
277
+ print(f"\n {method_info['name']} → {schema.__name__} [{schema_type_label}]")
219
278
  print(f" 描述: {schema.__doc__}")
220
279
  print(f" 字段:")
221
280
  for field_name, field_info in list(schema.model_fields.items())[:3]: