# Schema Tools 系统概要设计说明书
## 1. 项目概述
### 1.1 项目目标
扩展现有的training模块,新增自动化数据库逆向工程功能,将PostgreSQL数据库结构转换为vanna.ai格式的训练数据(DDL和MD文档)。
### 1.2 核心功能
- 自动连接PostgreSQL数据库
- 批量处理表清单
- 生成带中文注释的DDL文件
- 生成详细的MD格式说明文档
- LLM辅助的智能注释生成和枚举检测
- 并发处理提高效率
- 完整的错误处理和日志记录
- **新增**: Question-SQL训练数据生成功能
## 2. 系统架构
### 2.1 整体架构
```
schema_tools/ # 独立的schema工具模块
├── __init__.py # 模块入口
├── config.py # 配置文件
├── training_data_agent.py # 主AI Agent
├── qs_agent.py # Question-SQL生成Agent (新增)
├── qs_generator.py # Question-SQL命令行入口 (新增)
├── sql_validation_agent.py # SQL验证Agent (新增)
├── sql_validator.py # SQL验证命令行入口 (新增)
├── schema_workflow_orchestrator.py # 端到端工作流编排器 (新增)
├── tools/ # Agent工具集
│ ├── __init__.py
│ ├── base.py # 基础工具类和注册机制
│ ├── database_inspector.py # 数据库元数据检查工具
│ ├── data_sampler.py # 数据采样工具
│ ├── comment_generator.py # LLM注释生成工具
│ ├── ddl_generator.py # DDL格式生成工具
│ └── doc_generator.py # MD文档生成工具
├── validators/ # 验证器模块 (新增)
│ ├── __init__.py
│ ├── file_count_validator.py # 文件数量验证器
│ └── sql_validator.py # SQL验证器核心模块
├── analyzers/ # 分析器模块 (新增)
│ ├── __init__.py
│ ├── md_analyzer.py # MD文件分析器
│ └── theme_extractor.py # 主题提取器
├── prompts/ # 提示词和业务词典
│ ├── table_comment_template.txt
│ ├── field_comment_template.txt
│ ├── enum_detection_template.txt
│ ├── business_context.txt
│ └── business_dictionary.txt
├── utils/ # 工具函数
│ ├── __init__.py
│ ├── table_parser.py # 表清单解析器
│ ├── logger.py # 日志管理
│ └── file_utils.py # 文件操作工具
└── __main__.py # 命令行入口
```
### 2.2 核心组件
#### 2.2.1 主AI Agent
- **类名**: `SchemaTrainingDataAgent`
- **职责**: 整体流程控制、工具调度、并发管理
- **特点**: 单一Agent管理多工具的架构
#### 2.2.2 Question-SQL生成Agent(新增)
- **类名**: `QuestionSQLGenerationAgent`
- **职责**: 生成Question-SQL训练数据对
- **特点**: 独立的功能模块,可在DDL/MD生成后单独执行
#### 2.2.3 SQL验证Agent(新增)
- **类名**: `SQLValidationAgent`
- **职责**: 验证Question-SQL对中的SQL语句有效性,自动修复错误SQL
- **特点**: 支持并发验证、LLM自动修复、原文件自动修改
#### 2.2.4 工作流编排器(新增)
- **类名**: `SchemaWorkflowOrchestrator`
- **职责**: 端到端执行完整的Schema处理流程
- **特点**: 统一管理DDL/MD生成、Question-SQL生成、SQL验证三个步骤
#### 2.2.5 Agent工具集(基于装饰器注册)
1. **DatabaseInspectorTool**: 获取表元数据
2. **DataSamplerTool**: 采样表数据
3. **CommentGeneratorTool**: LLM生成注释和枚举建议
4. **DDLGeneratorTool**: 生成DDL格式文件
5. **DocGeneratorTool**: 生成MD文档
#### 2.2.6 验证器和分析器(新增)
1. **FileCountValidator**: 验证DDL和MD文件数量
2. **SQLValidator**: 验证SQL语句有效性,支持LLM自动修复
3. **MDFileAnalyzer**: 读取和分析MD文件内容
4. **ThemeExtractor**: 使用LLM提取业务分析主题
## 3. 详细设计
### 3.1 DDL/MD生成流程
```mermaid
graph TD
A[开始处理表] --> B[DatabaseInspectorTool]
B --> C[DataSamplerTool]
C --> D[CommentGeneratorTool
生成注释+枚举建议]
D --> E[验证枚举字段
SELECT DISTINCT]
E --> F[DDLGeneratorTool]
F --> G[DocGeneratorTool]
G --> H[写入文件]
H --> I[记录日志]
I --> J[完成]
```
### 3.2 Question-SQL生成流程(新增)
```mermaid
graph TD
A[开始] --> B[FileCountValidator
验证文件数量]
B --> C{验证通过?}
C -->|否| D[报错退出]
C -->|是| E[MDFileAnalyzer
读取所有MD文件]
E --> F[ThemeExtractor
提取分析主题]
F --> G[处理每个主题]
G --> H[生成Question-SQL对]
H --> I[保存JSON文件]
I --> J[完成]
```
### 3.3 SQL验证和修复流程(新增)
```mermaid
graph TD
A[开始] --> B[读取Question-SQL文件]
B --> C[提取SQL语句]
C --> D[批量验证SQL]
D --> E{有失败的SQL?}
E -->|否| F[生成验证报告]
E -->|是| G{启用LLM修复?}
G -->|否| H[仅生成报告]
G -->|是| I[LLM修复失败SQL]
I --> J[重新验证修复后SQL]
J --> K{启用文件修改?}
K -->|否| F
K -->|是| L[创建备份文件]
L --> M[更新原文件]
M --> N[生成修改日志]
N --> F
F --> O[完成]
H --> F
```
### 3.4 端到端工作流编排流程(新增)
```mermaid
graph TD
A[开始] --> B[步骤1: DDL/MD生成]
B --> C{成功?}
C -->|否| D[生成错误报告]
C -->|是| E[步骤2: Question-SQL生成]
E --> F{成功?}
F -->|否| D
F -->|是| G{启用SQL验证?}
G -->|否| H[生成最终报告]
G -->|是| I[步骤3: SQL验证和修复]
I --> J{成功?}
J -->|否| D
J -->|是| H
H --> K[完成]
D --> K
```
### 3.5 模块间接口规范
#### 3.5.1 统一数据结构定义
```python
from dataclasses import dataclass
from typing import List, Dict, Optional, Any
@dataclass
class FieldInfo:
"""字段信息标准结构"""
name: str
type: str
nullable: bool
default_value: Optional[str]
comment: Optional[str]
is_primary_key: bool = False
is_foreign_key: bool = False
is_enum: bool = False
enum_values: Optional[List[str]] = None
@dataclass
class TableMetadata:
"""表元数据标准结构"""
schema_name: str
table_name: str
full_name: str # schema.table_name
comment: Optional[str]
fields: List[FieldInfo]
sample_data: List[Dict[str, Any]]
row_count: Optional[int]
@dataclass
class ProcessingResult:
"""工具处理结果标准结构"""
success: bool
data: Optional[Any]
error_message: Optional[str]
warnings: List[str] = None
```
#### 3.5.2 工具接口规范
```python
class BaseTool:
async def execute(self, input_data: Dict[str, Any], context: Dict[str, Any]) -> ProcessingResult:
"""
统一工具执行接口
Args:
input_data: 输入数据字典
context: 全局上下文
Returns:
ProcessingResult: 标准化处理结果
"""
pass
```
### 3.6 可插拔处理链设计
#### 3.6.1 Pipeline配置
```python
# 支持灵活的处理链配置
PROCESSING_PIPELINES = {
"full": [ # 完整处理链
"database_inspector",
"data_sampler",
"comment_generator",
"ddl_generator",
"doc_generator"
],
"ddl_only": [ # 仅生成DDL
"database_inspector",
"data_sampler",
"comment_generator",
"ddl_generator"
],
"analysis_only": [ # 仅分析不生成文件
"database_inspector",
"data_sampler",
"comment_generator"
]
}
```
#### 3.3.2 Pipeline执行器
```python
class PipelineExecutor:
def __init__(self, pipeline_name: str):
self.steps = PROCESSING_PIPELINES[pipeline_name]
self.tools = {name: ToolRegistry.get_tool(name) for name in self.steps}
async def execute(self, table_metadata: TableMetadata, context: Dict) -> Dict[str, ProcessingResult]:
"""按配置的处理链执行工具"""
results = {}
current_data = {"table_metadata": table_metadata}
for step_name in self.steps:
result = await self.tools[step_name].execute(current_data, context)
results[step_name] = result
if result.success:
current_data[f"{step_name}_result"] = result.data
else:
# 根据配置决定是否继续
if not SCHEMA_TOOLS_CONFIG["continue_on_error"]:
break
return results
```
### 3.4 并发处理策略
#### 3.4.1 表级并发
- 最大并发表数: 可配置(默认1个,避免LLM并发问题)
- 使用asyncio.Semaphore控制并发数
- 单表内工具串行执行
#### 3.4.2 工具执行顺序
1. `DatabaseInspectorTool` → 获取表结构元数据
2. `DataSamplerTool` → 采样20条数据
3. `CommentGeneratorTool` → LLM生成注释和枚举建议
4. 枚举字段验证 → SELECT DISTINCT确认枚举值
5. `DDLGeneratorTool` → 生成DDL文件
6. `DocGeneratorTool` → 基于DDL结果生成MD文档
### 3.3 LLM集成设计
#### 3.3.1 LLM实例复用
```python
# 复用现有vanna实例,支持qwen/deepseek/ollama
from core.vanna_llm_factory import create_vanna_instance
vn = create_vanna_instance()
```
#### 3.3.2 智能注释生成
**输入**: 表元数据 + 20条样例数据 + 业务上下文 **输出**: 中文注释 + 枚举字段建议 **特点**: 一次LLM调用完成注释生成和枚举检测
#### 3.3.3 枚举检测策略
1. **规则预筛选**: ENUM类型、VARCHAR+关键词
2. **LLM智能判断**: 基于字段名、注释、样例数据
3. **数据验证**: SELECT DISTINCT确认实际枚举值
### 3.4 工具注册机制
#### 3.4.1 装饰器注册
```python
@ToolRegistry.register("database_inspector")
class DatabaseInspectorTool(BaseTool):
needs_llm = False # 是否需要LLM实例
```
#### 3.4.2 自动依赖注入
- 自动为需要LLM的工具注入vanna实例
- 确保所有工具使用相同的LLM配置
### 3.5 数据流设计
#### 3.5.1 工具间数据传递
- 方案B: 工具间直接传递数据
- DDLGeneratorTool的结果作为DocGeneratorTool的输入
- 通过input_data字典传递中间结果
#### 3.5.2 上下文管理
```python
context = {
'business_context': '高速公路服务区管理系统',
'table_name': 'bss_service_area',
'output_dir': 'training/generated_data',
'vn': vanna_instance
}
```
## 4. 配置设计
### 4.1 配置文件结构
```python
# schema_tools/config.py
SCHEMA_TOOLS_CONFIG = {
# 核心配置
"default_db_connection": None,
"default_business_context": "数据库管理系统",
"output_directory": "training/generated_data",
# 处理链配置
"default_pipeline": "full", # full, ddl_only, analysis_only
"available_pipelines": {
"full": ["database_inspector", "data_sampler", "comment_generator", "ddl_generator", "doc_generator"],
"ddl_only": ["database_inspector", "data_sampler", "comment_generator", "ddl_generator"],
"analysis_only": ["database_inspector", "data_sampler", "comment_generator"]
},
# 数据处理配置
"sample_data_limit": 20,
"enum_detection_sample_limit": 5000,
"enum_max_distinct_values": 20,
"enum_varchar_keywords": ["性别", "状态", "类型", "级别", "方向", "品类"],
"large_table_threshold": 1000000, # 大表阈值
# 并发配置
"max_concurrent_tables": 1, # 建议保持1,避免LLM并发调用问题
# LLM配置
"use_app_config_llm": True,
"comment_generation_timeout": 30,
"max_llm_retries": 3,
# 系统表过滤配置
"filter_system_tables": True,
"custom_system_prefixes": [], # 用户自定义的系统表前缀
"custom_system_schemas": [], # 用户自定义的系统schema
# 权限与安全配置
"check_permissions": True,
"require_select_permission": True,
"allow_readonly_database": True,
# 错误处理配置
"continue_on_error": True,
"max_table_failures": 5,
"skip_large_tables": False, # 是否跳过超大表
"max_table_size": 10000000, # 最大表行数限制
# 文件配置
"ddl_file_suffix": ".ddl",
"doc_file_suffix": "_detail.md",
"log_file": "schema_tools.log",
"create_subdirectories": False, # 不创建子目录,所有文件放在output目录下
# 输出格式配置
"include_sample_data_in_comments": True, # 注释中是否包含示例数据
"max_comment_length": 500, # 最大注释长度
"include_field_statistics": True, # 是否包含字段统计信息
# Question-SQL生成配置(新增)
"qs_generation": {
"max_tables": 20, # 最大表数量限制
"theme_count": 5, # LLM生成的主题数量
"questions_per_theme": 10, # 每个主题生成的问题数
"max_concurrent_themes": 1, # 并行处理的主题数量(建议保持1)
"continue_on_theme_error": True, # 主题生成失败是否继续
"save_intermediate": True, # 是否保存中间结果
"output_file_prefix": "qs", # 输出文件前缀
},
# SQL验证配置(新增)
"sql_validation": {
"reuse_connection_pool": True, # 复用现有连接池
"max_concurrent_validations": 5, # 并发验证数
"validation_timeout": 30, # 单个验证超时(秒)
"batch_size": 10, # 批处理大小
"continue_on_error": True, # 错误时是否继续
"save_validation_report": True, # 保存验证报告
"save_detailed_json_report": False, # 保存详细JSON报告(可选)
"readonly_mode": True, # 启用只读模式
"max_retry_count": 2, # 验证失败重试次数
"report_file_prefix": "sql_validation", # 报告文件前缀
# SQL修复配置
"enable_sql_repair": False, # 启用SQL修复功能(默认禁用)
"llm_repair_timeout": 120, # LLM修复超时时间(秒)
"repair_batch_size": 2, # 修复批处理大小
# 文件修改配置
"modify_original_file": False, # 是否修改原始JSON文件(默认禁用)
}
}
```
### 4.2 配置优先级
```
命令行参数 > schema_tools/config.py > app_config.py默认值
```
### 4.3 多Schema场景处理
#### 4.3.1 文件命名防冲突机制
```python
def generate_safe_filename(schema_name: str, table_name: str, suffix: str) -> str:
"""
生成安全的文件名,避免冲突
规则:
- public.table_name → table_name.ddl
- schema.table_name → schema__table_name.ddl
- 特殊字符替换: . → __, - → _, 空格 → _
"""
if schema_name.lower() == 'public':
safe_name = table_name
else:
safe_name = f"{schema_name}__{table_name}"
# 替换特殊字符
safe_name = safe_name.replace('.', '__').replace('-', '_').replace(' ', '_')
return f"{safe_name}{suffix}"
# 示例:
# public.users → users.ddl
# hr.employees → hr__employees.ddl
# sales.order-items → sales__order_items.ddl
```
#### 4.3.2 输出目录结构
```
training/generated_data/
├── users.ddl # public.users
├── hr__employees.ddl # hr.employees
├── sales__order_items.ddl # sales.order-items
├── users_detail.md # 对应的MD文档
├── hr__employees_detail.md
├── sales__order_items_detail.md
├── qs_highway_db_20240101_pair.json # Question-SQL对文件
├── metadata.txt # 主题元数据
├── sql_validation_20240101_summary.txt # SQL验证报告
└── logs/
└── schema_tools.log
```
**注意**: 配置已更新为不创建ddl/和docs/子目录,所有文件直接放在output目录下。
#### 4.3.3 重名检测与处理
```python
class FileNameManager:
def __init__(self, output_dir: str):
self.output_dir = output_dir
self.used_names = set()
def get_unique_filename(self, schema_name: str, table_name: str, suffix: str) -> str:
"""确保文件名唯一性"""
base_name = generate_safe_filename(schema_name, table_name, suffix)
if base_name not in self.used_names:
self.used_names.add(base_name)
return base_name
# 如果重名,添加数字后缀
counter = 1
while True:
name_parts = base_name.rsplit('.', 1)
if len(name_parts) == 2:
unique_name = f"{name_parts[0]}_{counter}.{name_parts[1]}"
else:
unique_name = f"{base_name}_{counter}"
if unique_name not in self.used_names:
self.used_names.add(unique_name)
return unique_name
counter += 1
```
### 4.4 边界情况处理
#### 4.4.1 系统表过滤
```python
class SystemTableFilter:
"""系统表过滤器"""
# PostgreSQL系统表前缀
PG_SYSTEM_PREFIXES = [
'pg_', 'information_schema', 'sql_', 'cardinal_number',
'character_data', 'sql_identifier', 'time_stamp', 'yes_or_no'
]
# 系统schema
SYSTEM_SCHEMAS = [
'information_schema', 'pg_catalog', 'pg_toast',
'pg_temp_1', 'pg_toast_temp_1'
]
@classmethod
def is_system_table(cls, schema_name: str, table_name: str) -> bool:
"""判断是否为系统表"""
# 检查系统schema
if schema_name.lower() in cls.SYSTEM_SCHEMAS:
return True
# 检查表名前缀
table_lower = table_name.lower()
return any(table_lower.startswith(prefix) for prefix in cls.PG_SYSTEM_PREFIXES)
@classmethod
def filter_user_tables(cls, table_list: List[str]) -> List[str]:
"""过滤出用户表"""
user_tables = []
filtered_count = 0
for table_spec in table_list:
if '.' in table_spec:
schema, table = table_spec.split('.', 1)
else:
schema, table = 'public', table_spec
if not cls.is_system_table(schema, table):
user_tables.append(table_spec)
else:
filtered_count += 1
logging.info(f"过滤系统表: {table_spec}")
logging.info(f"过滤了 {filtered_count} 个系统表,保留 {len(user_tables)} 个用户表")
return user_tables
```
#### 4.4.2 数据库权限检查
```python
class DatabasePermissionChecker:
"""数据库权限检查器"""
def __init__(self, db_inspector):
self.db_inspector = db_inspector
async def check_permissions(self) -> Dict[str, bool]:
"""检查数据库权限"""
permissions = {
'connect': False,
'select_metadata': False,
'select_data': False,
'is_readonly': False
}
try:
# 检查连接权限
await self.db_inspector.test_connection()
permissions['connect'] = True
# 检查元数据查询权限
await self.db_inspector.get_schemas()
permissions['select_metadata'] = True
# 检查数据查询权限(测试一个已知表)
try:
await self.db_inspector.execute_query("SELECT 1 LIMIT 1")
permissions['select_data'] = True
except Exception as e:
logging.warning(f"数据查询权限受限: {e}")
# 检查是否为只读库(尝试创建临时表)
try:
await self.db_inspector.execute_query("CREATE TEMP TABLE test_write_permission (id int)")
await self.db_inspector.execute_query("DROP TABLE test_write_permission")
except Exception:
permissions['is_readonly'] = True
logging.info("检测到只读数据库,这是正常的")
except Exception as e:
logging.error(f"权限检查失败: {e}")
return permissions
```
#### 4.4.3 大表处理策略
```python
class LargeTableHandler:
"""大表处理策略"""
@staticmethod
async def get_smart_sample(db_inspector, table_name: str, limit: int = 20) -> List[Dict]:
"""智能采样策略"""
# 1. 先检查表大小
row_count = await db_inspector.get_table_row_count(table_name)
if row_count <= limit * 10: # 小表,直接采样
return await db_inspector.sample_table_data(table_name, limit)
# 2. 大表使用分层采样
logging.info(f"表 {table_name} 有 {row_count} 行,使用智能采样")
# 前N行 + 随机中间N行 + 后N行
samples_per_section = limit // 3
samples = []
# 前N行
front_samples = await db_inspector.execute_query(
f"SELECT * FROM {table_name} LIMIT {samples_per_section}"
)
samples.extend(front_samples)
# 随机中间N行
if row_count > samples_per_section * 2:
middle_samples = await db_inspector.execute_query(f"""
SELECT * FROM {table_name}
TABLESAMPLE SYSTEM(1)
LIMIT {samples_per_section}
""")
samples.extend(middle_samples)
# 后N行
remaining = limit - len(samples)
if remaining > 0:
tail_samples = await db_inspector.execute_query(f"""
SELECT * FROM (
SELECT * FROM {table_name}
ORDER BY CTID DESC
LIMIT {remaining}
) sub ORDER BY CTID
""")
samples.extend(tail_samples)
return samples[:limit]
```
#### 4.4.4 异常表结构处理
```python
class TableStructureValidator:
"""表结构验证器"""
@staticmethod
def validate_table_structure(table_metadata: TableMetadata) -> List[str]:
"""验证表结构,返回警告信息"""
warnings = []
# 检查是否有字段
if not table_metadata.fields:
warnings.append("表没有字段定义")
return warnings
# 检查是否有主键
has_primary_key = any(field.is_primary_key for field in table_metadata.fields)
if not has_primary_key:
warnings.append("表没有主键")
# 检查字段名是否合规
for field in table_metadata.fields:
if not field.name or field.name.strip() == '':
warnings.append(f"发现空字段名")
# 检查特殊字符
if any(char in field.name for char in [' ', '-', '.']):
warnings.append(f"字段名包含特殊字符: {field.name}")
# 检查超大字段数量
if len(table_metadata.fields) > 100:
warnings.append(f"表字段数量过多: {len(table_metadata.fields)} 个字段")
return warnings
```
## 5. 错误处理与日志
### 5.1 错误处理策略
#### 5.1.1 表级错误处理
- 某表处理失败 → 记录错误,继续下一表
- 失败表数超过阈值 → 警告但继续执行
#### 5.1.2 工具级错误处理
- `DatabaseInspectorTool`失败 → 跳过该表
- `CommentGeneratorTool`失败 → 使用原始注释
- `EnumDetectorTool`失败 → 跳过枚举检测
- 所有失败都记录到日志
#### 5.1.3 LLM调用错误处理
- 超时/失败 → 自动重试(最大3次)
- 重试失败 → 使用原始注释或默认注释
### 5.2 日志设计
#### 5.2.1 日志级别
- **INFO**: 正常处理流程
- **WARNING**: 可恢复错误(使用默认值、重试成功)
- **ERROR**: 影响结果的错误(表处理失败、工具异常)
#### 5.2.2 日志输出
- **控制台**: 进度信息和关键错误
- **文件**: 详细执行日志(schema_tools.log)
- **格式**: 文本格式,包含时间戳、级别、消息
## 6. 文件格式设计
### 6.1 DDL文件格式
```sql
-- 中文名: 服务区基础信息表
-- 描述: 记录高速公路服务区的基础属性,包括服务区编码、名称、方向、公司归属、地理位置、服务类型和状态,是业务分析与服务区定位的核心表。
create table bss_service_area (
id varchar(32) not null, -- 服务区唯一标识(主键,UUID)
version integer not null, -- 版本号
service_area_name varchar(255), -- 服务区名称
service_area_no varchar(255), -- 服务区编码(业务唯一标识)
service_area_type varchar(50), -- 服务区类型(枚举:信息化服务区、智能化服务区)
primary key (id)
);
```
### 6.2 MD文档格式
```markdown
## bss_service_area(服务区基础信息表)
bss_service_area 表记录高速公路服务区的基础属性...
字段列表:
- id (varchar(32)) - 服务区唯一标识(主键,UUID) [示例: 0271d68ef93de9684b7ad8c7aae600b6]
- service_area_type (varchar(50)) - 服务区类型(枚举:信息化服务区、智能化服务区)[示例: 信息化服务区]
字段补充说明:
- service_area_type 为枚举字段,包含两个取值:信息化服务区、智能化服务区。
```
### 6.3 Question-SQL文件格式(新增)
```json
[
{
"question": "按服务区统计每日营收趋势(最近30天)?",
"sql": "SELECT service_name AS 服务区, oper_date AS 营业日期, SUM(pay_sum) AS 每日营收 FROM bss_business_day_data WHERE oper_date >= CURRENT_DATE - INTERVAL '30 day' AND delete_ts IS NULL GROUP BY service_name, oper_date ORDER BY 营业日期 ASC NULLS LAST;"
},
{
"question": "按月统计服务区营收趋势?",
"sql": "SELECT service_name AS 服务区, DATE_TRUNC('month', oper_date) AS 月份, SUM(pay_sum) AS 月营收 FROM bss_business_day_data WHERE delete_ts IS NULL GROUP BY service_name, 月份 ORDER BY 月份 ASC NULLS LAST;"
}
]
```
## 7. 使用方式
### 7.1 命令行方式
#### 7.1.1 生成DDL和MD文档
```bash
# 基本使用
python -m schema_tools \
--db-connection "postgresql://user:pass@localhost:5432/dbname" \
--table-list tables.txt \
--business-context "高速公路服务区管理系统"
# 指定处理链
python -m schema_tools \
--db-connection "postgresql://user:pass@localhost:5432/dbname" \
--table-list tables.txt \
--pipeline ddl_only \
--business-context "高速公路服务区管理系统"
# 高级参数
python -m schema_tools \
--db-connection "postgresql://user:pass@localhost:5432/dbname" \
--table-list tables.txt \
--business-context-file business_context.txt \
--output-dir custom_output \
--max-concurrent 5 \
--pipeline full \
--no-filter-system-tables
# 权限检查模式
python -m schema_tools \
--db-connection "postgresql://user:pass@localhost:5432/dbname" \
--check-permissions-only
```
#### 7.1.2 生成Question-SQL训练数据(新增)
```bash
# 基本使用(在生成DDL/MD文件后执行)
python -m schema_tools.qs_generator \
--output-dir ./output \
--table-list ./schema_tools/tables.txt \
--business-context "高速公路服务区管理系统" \
--db-name highway_db
# 启用详细日志
python -m schema_tools.qs_generator \
--output-dir ./output \
--table-list ./tables.txt \
--business-context "电商系统" \
--db-name ecommerce_db \
--verbose
```
### 7.2 编程方式
```python
from schema_tools import SchemaTrainingDataAgent
# 基本使用
agent = SchemaTrainingDataAgent(
db_connection="postgresql://user:pass@localhost:5432/dbname",
table_list_file="tables.txt",
business_context="高速公路服务区管理系统"
)
await agent.generate_training_data()
# 指定处理链
agent = SchemaTrainingDataAgent(
db_connection="postgresql://user:pass@localhost:5432/dbname",
table_list_file="tables.txt",
business_context="高速公路服务区管理系统",
pipeline="ddl_only"
)
await agent.generate_training_data()
# 权限检查
permissions = await agent.check_database_permissions()
if permissions['select_data']:
await agent.generate_training_data()
else:
print("数据库权限不足")
```
### 7.3 表清单文件格式
```text
bss_service_area
bss_branch
public.bss_company
highway.bss_car_day_count
```
## 8. 扩展性设计
### 8.1 数据库适配
- 当前支持: PostgreSQL
- 预留扩展: MySQL适配接口
- 设计原则: 数据库特定代码隔离在DatabaseInspectorTool中
### 8.2 LLM模型适配
- 当前支持: qwen/deepseek/ollama
- 复用现有vanna配置,自动适配不同模型
- 提示词模板支持不同模型的特点
### 8.3 输出格式扩展
- 当前: DDL + MD
- 预留: JSON格式、Excel格式等
## 9. 性能考虑
### 9.1 并发控制
- 表级并发: 控制数据库连接数
- LLM调用: 避免过于频繁的API调用
- 内存管理: 及时释放大数据集
### 9.2 数据采样优化
- 限制采样数量避免大表性能问题
- 智能采样策略(如分页采样)
### 9.3 缓存策略
- 表元数据缓存(单次运行内)
- LLM结果缓存(避免重复调用)
## 10. 测试策略
### 10.1 单元测试
#### 10.1.1 工具测试
- **DatabaseInspectorTool**: Mock数据库连接,测试元数据提取
- **CommentGeneratorTool**: Mock LLM调用,测试注释生成逻辑
- **DDLGeneratorTool**: 测试DDL格式生成的正确性
- **DocGeneratorTool**: 测试MD文档格式和内容
#### 10.1.2 边界条件测试
- **文件名冲突**: 测试多schema重名表的文件名生成
- **系统表过滤**: 测试各种系统表的正确过滤
- **大表处理**: 测试智能采样策略
- **权限异常**: 测试只读库、权限不足等场景
#### 10.1.3 数据结构测试
- **TableMetadata**: 测试各种表结构的正确解析
- **FieldInfo**: 测试枚举字段检测逻辑
- **ProcessingResult**: 测试错误处理和结果传递
### 10.2 集成测试
#### 10.2.1 完整流程测试
- **标准流程**: 正常表的完整处理链测试
- **Pipeline测试**: 不同处理链配置的正确执行
- **并发测试**: 多表并发处理的稳定性
#### 10.2.2 数据库适配测试
- **不同PostgreSQL版本**: 9.6, 10, 11, 12, 13, 14, 15
- **不同schema配置**: public, 多schema, 复杂层级
- **特殊表结构**: 无主键表、超多字段表、复杂数据类型
#### 10.2.3 LLM集成测试
- **不同模型**: qwen, deepseek, ollama各版本
- **网络异常**: 超时、重试、降级处理
- **Token限制**: 超长输入的分段处理
#### 10.2.4 错误场景测试
- **网络中断**: 数据库连接中断恢复
- **权限变化**: 运行中权限被收回
- **磁盘空间**: 输出目录空间不足
- **内存限制**: 大量表并发处理
### 10.3 性能测试
#### 10.3.1 规模测试
- **小规模**: 10个表,验证基本功能
- **中规模**: 100个表,验证并发效率
- **大规模**: 1000+个表,验证内存和稳定性
#### 10.3.2 压力测试
- **长时间运行**: 24小时连续处理
- **资源限制**: 低内存、低CPU环境
- **高并发**: 最大并发数的边界测试
#### 10.3.3 性能基准
- **处理速度**: 平均每表处理时间
- **资源消耗**: 内存、CPU、网络使用率
- **LLM调用**: API调用频率和响应时间
### 10.4 用户验收测试
#### 10.4.1 功能验收
- **输出质量**: DDL和MD文档的正确性和可读性
- **中文注释**: 翻译质量和业务相关性
- **枚举检测**: 准确率和误报率
- **错误处理**: 异常情况的友好提示
#### 10.4.2 易用性测试
- **命令行接口**: 参数的直观性和错误提示
- **配置文件**: 配置项的完整性和说明
- **日志输出**: 进度显示和错误定位
#### 10.4.3 兼容性测试
- **操作系统**: Windows, Linux, macOS
- **Python版本**: 3.8, 3.9, 3.10, 3.11
- **依赖版本**: 各关键依赖库的版本兼容性
### 10.5 测试环境配置
#### 10.5.1 测试数据准备
```sql
-- 创建测试schema和表
CREATE SCHEMA test_schema;
CREATE SCHEMA hr;
-- 标准表(有主键、外键、注释)
CREATE TABLE test_schema.standard_table (
id SERIAL PRIMARY KEY,
name VARCHAR(100) NOT NULL COMMENT '姓名',
status VARCHAR(20) DEFAULT 'active' COMMENT '状态'
);
-- 枚举字段表
CREATE TABLE test_schema.enum_table (
id SERIAL PRIMARY KEY,
gender VARCHAR(10), -- 性别: 男/女
education VARCHAR(20), -- 学历: 本科/硕士/博士
type INTEGER -- 类型: 1,2,3
);
-- 无主键表
CREATE TABLE test_schema.no_pk_table (
col1 VARCHAR(50),
col2 INTEGER
);
-- 大字段表
CREATE TABLE test_schema.wide_table (
id SERIAL PRIMARY KEY
-- 动态生成100个字段
);
```
#### 10.5.2 Mock数据配置
```python
# 测试用的Mock LLM响应
MOCK_LLM_RESPONSES = {
"table_comment": {
"standard_table": "标准测试表,用于验证基本功能",
"enum_table": "枚举字段测试表,包含多种枚举类型字段"
},
"field_comments": {
"gender": "性别字段,枚举值:男、女",
"education": "教育程度,枚举值:本科、硕士、博士"
},
"enum_suggestions": {
"gender": ["男", "女"],
"education": ["本科", "硕士", "博士"],
"type": ["1", "2", "3"]
}
}
```
#### 10.5.3 CI/CD集成
```yaml
# .github/workflows/test.yml
name: Schema Tools Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:13
env:
POSTGRES_PASSWORD: postgres
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: 3.9
- name: Install dependencies
run: |
pip install -r requirements.txt
pip install pytest pytest-asyncio
- name: Setup test database
run: |
python tests/setup_test_db.py
- name: Run unit tests
run: pytest tests/unit/
- name: Run integration tests
run: pytest tests/integration/
- name: Run performance tests
run: pytest tests/performance/ --benchmark-only
```