# 技术债务重构实施文档 > 本文档记录技术债务改进的具体实施过程 --- ## 实施计划 | # | 改进项 | 状态 | 完成时间 | |---|-------|------|---------| | 1 | 数据库访问改接口 | ✅ 完成 | 2024-12-08 | | 2 | 图片传输改 URL | ✅ 完成 | 2024-12-08 | | 3 | 放弃 ppid | ✅ 完成 | 2024-12-08 | | 4 | Prompt Registry | ✅ 完成 | 2024-12-08 | | 5 | 依赖注入统一 | ✅ 完成 | 2024-12-08 | --- ## 1. 数据库访问改接口 ### 目标 Python 端不再直接连接数据库,所有数据由 Java 端通过 HTTP 接口传递。 ### 改动前架构 ``` ┌─────────────┐ ┌─────────────┐ │ Java 端 │ │ Python 端 │ └──────┬──────┘ └──────┬──────┘ │ │ │ 各自连接 │ 各自连接 ▼ ▼ ┌─────────────────────────┐ │ MySQL │ └─────────────────────────┘ ``` ### 改动后架构 ``` ┌─────────────┐ ┌─────────────┐ │ Java 端 │ ──── HTTP ────────>│ Python 端 │ └──────┬──────┘ (完整数据) └─────────────┘ │ │ │ 唯一数据源 │ 无数据库访问 ▼ │ ┌─────────────────────────┐ │ │ MySQL │ X └─────────────────────────┘ ``` ### 新的接口协议 Java 端调用 Python 端时,传递完整数据: ```json { "engine": "topic_generate", "params": { "num_topics": 5, "month": "2024-12", // 直接传完整对象,而不是 ID "scenic_spot": { "id": 1, "name": "天津冒险湾", "description": "主题乐园...", "location": "天津市" }, "product": { "id": 10, "name": "门票套餐", "price": 299, "description": "..." }, "style": { "id": 5, "name": "攻略风", "description": "实用性强..." }, "audience": { "id": 3, "name": "亲子家庭", "description": "..." } } } ``` ### 实施步骤 1. [x] 定义新的参数 Schema 2. [x] 创建 V2 引擎接收完整对象 3. [x] V2 引擎不访问数据库 4. [ ] 更新 Java 端调用方式 (待 Java 端配合) ### 已创建文件 - `domain/aigc/engines/topic_generate_v2.py` - 选题生成 V2 - `domain/aigc/engines/content_generate_v2.py` - 内容生成 V2 - `domain/aigc/engines/poster_generate_v2.py` - 海报生成 V2 --- ## 2. 图片传输改 URL ### 目标 不再传递 Base64,改为传递图片 URL 或路径。 ### 新的接口协议 ```json { "engine": "poster_generate", "params": { "template_id": "vibrant", // 方式1: S3 URL "image_urls": [ "https://s3.xxx.com/bucket/image1.jpg", "https://s3.xxx.com/bucket/image2.jpg" ], // 方式2: 本地路径 (如果共享存储) "image_paths": [ "/data/images/123.jpg" ], // 方式3: 素材 ID (Python 自行获取) "material_ids": [123, 456] } } ``` ### 实施步骤 1. [x] 修改引擎支持 URL 下载 2. [x] 添加图片下载工具 (aiohttp) 3. [ ] 更新 Java 端传参方式 (待 Java 端配合) ### 已实现 `PosterGenerateEngineV2` 支持三种图片来源: - `image_urls` - 从 URL 下载 (推荐) - `image_paths` - 从本地路径读取 - `images_base64` - Base64 (兼容旧接口) --- ## 3. 放弃 ppid ### 目标 不再使用 ppid,Java 端直接传递解析后的完整数据。 ### 改动 - 移除 Python 端的 `resolve_ppid()` 逻辑 - 移除 `ProductPackageRepository` - 引擎参数 Schema 中移除 `ppid` ### 实施步骤 1. [x] V2 引擎不包含 ppid 参数 2. [x] V2 引擎不访问 ProductPackageRepository 3. [x] 参数 Schema 只接收完整对象 ### 说明 V2 引擎的参数 Schema 中没有 `ppid`,只接收: - `scenic_spot` - 完整景区对象 - `product` - 完整产品对象 - `style` - 完整风格对象 - `audience` - 完整受众对象 Java 端需要在调用前解析 ppid 并传递完整数据。 --- ## 4. Prompt Registry ### 目标 集中管理 Prompt,支持版本化。 ### 目录结构 ``` prompts/ ├── topic_generate/ │ └── v1.0.0.yaml ├── content_generate/ │ └── v1.0.0.yaml └── content_judge/ └── v1.0.0.yaml ``` ### 实施步骤 1. [x] 创建 `domain/prompt/` 模块 2. [x] 实现 `PromptRegistry` 类 3. [x] 迁移现有 prompt 到 YAML 4. [x] V2 引擎使用新 Registry ### 已创建文件 **模块:** - `domain/prompt/__init__.py` - `domain/prompt/registry.py` - PromptRegistry 实现 **Prompt 配置:** - `prompts/topic_generate/v1.0.0.yaml` - `prompts/content_generate/v1.0.0.yaml` - `prompts/content_judge/v1.0.0.yaml` ### 使用示例 ```python from domain.prompt import PromptRegistry registry = PromptRegistry('prompts') # 渲染 prompt system, user = registry.render( 'content_generate', context={'style_content': '...', 'demand_content': '...', ...}, version='latest' ) # 获取模型参数 config = registry.get('content_generate') params = config.get_model_params() # {'temperature': 0.3, ...} ``` --- ## 5. 依赖注入统一 ### 目标 统一使用容器模式管理依赖。 ### 实施步骤 1. [x] 创建 `Container` 类 2. [x] 实现服务注册和获取 3. [ ] 逐步迁移现有依赖获取方式 (渐进式) ### 已创建文件 - `domain/container.py` - Container 实现 ### 使用示例 ```python from domain.container import Container, get_service, inject # 方式1: 直接获取 from core.config import ConfigManager config = Container.get(ConfigManager) # 方式2: 便捷函数 from domain import get_service config = get_service(ConfigManager) # 方式3: 装饰器注入 @inject(ConfigManager, AIAgent) def my_function(config, agent, other_param): ... ``` ### 说明 Container 采用渐进式迁移策略: - 新代码使用 Container - 旧代码保持不变,逐步迁移 - V2 引擎内部使用延迟加载,兼容两种方式 --- ## 变更日志 | 日期 | 改动 | 文件 | |-----|------|------| | 2024-12-08 | 创建实施文档 | docs/REFACTORING_IMPLEMENTATION.md | | 2024-12-08 | 创建 PromptRegistry | domain/prompt/registry.py | | 2024-12-08 | 创建 Container | domain/container.py | | 2024-12-08 | 创建 V2 引擎 | domain/aigc/engines/*_v2.py | | 2024-12-08 | 迁移 Prompt 到 YAML | prompts/*.yaml | --- ## 新旧引擎对比 | 特性 | V1 引擎 | V2 引擎 | |-----|--------|--------| | 数据库访问 | ✅ 直接访问 | ❌ 不访问 | | ppid 支持 | ✅ 自动解析 | ❌ 不支持 | | 图片传输 | Base64 | URL/路径/Base64 | | Prompt 管理 | 文件模板 | PromptRegistry | | 依赖注入 | 延迟加载 | Container | ## Java 端调用示例 ### V1 引擎 (旧) ```json { "engine": "topic_generate", "params": { "ppid": 12345, "num_topics": 5 } } ``` ### V2 引擎 (新) ```json { "engine": "topic_generate_v2", "params": { "num_topics": 5, "month": "2024-12", "scenic_spot": { "id": 1, "name": "天津冒险湾", "description": "..." }, "product": { "id": 10, "name": "门票套餐", "price": 299 } } } ``` --- ## 待办事项 - [ ] Java 端更新调用方式,使用 V2 引擎 - [ ] 验证 V2 引擎功能正确性 - [ ] 清理 V1 引擎中的数据库访问代码 (可选) - [ ] 删除 Python 端的 database_service.py (待确认无其他依赖) - [ ] 两端协调 ppid 废弃方案 --- ## 6-12 问题改进记录 ### 6. 临时文件清理 创建清理脚本 `scripts/cleanup_temp_files.py`: ```bash # 预览要删除的文件 python scripts/cleanup_temp_files.py --dry-run # 清理 7 天前的临时文件 python scripts/cleanup_temp_files.py --days 7 # 清理指定目录 python scripts/cleanup_temp_files.py --dir result --days 3 ``` ### 7. 统一配置 创建 `core/unified_config.py`: ```python from core import get_unified_config config = get_unified_config() # 获取配置值 db_host = config.get("database.host") # 获取配置组 db_config = config.database ai_config = config.ai_model ``` 支持环境变量覆盖: - `DATABASE_HOST`, `DATABASE_PORT`, `DATABASE_USER`, `DATABASE_PASSWORD` - `AI_MODEL_API_KEY`, `AI_MODEL_BASE_URL` ### 8. 统一异常 创建 `core/exceptions.py`,定义标准异常类: | 异常类 | 用途 | HTTP 状态码 | |-------|------|------------| | `ValidationError` | 参数验证失败 | 400 | | `ResourceNotFoundError` | 资源未找到 | 404 | | `EngineError` | 引擎执行错误 | 500 | | `AIError` | AI 服务错误 | 502 | | `AIRateLimitError` | AI 限流 | 429 | ### 10. 重复目录统一 `core/document/` 重定向到 `document/`,保持兼容性。 ### 12. 日志配置 创建 `core/logging_config.py`: ```python from core import setup_logging, get_logger # 初始化日志 setup_logging(level="INFO", log_dir="logs") # 获取日志器 logger = get_logger(__name__) ``` 特性: - 控制台 + 文件输出 - 日志滚动 (10MB/文件,保留5个) - 错误日志单独文件 - 第三方库日志静默 --- ## Prompt 查询 API 新增 V2 接口: | 接口 | 方法 | 说明 | |-----|------|------| | `/prompt/v2/list` | GET | 列出所有 prompt | | `/prompt/v2/{name}` | GET | 获取 prompt 详情 | | `/prompt/v2/{name}/versions` | GET | 列出版本 | | `/prompt/v2/{name}/preview` | GET | 预览原始模板 | | `/prompt/v2/render` | POST | 渲染 prompt | ### 已迁移的 Prompt | 名称 | 版本 | 说明 | |-----|------|------| | topic_generate | v1.0.0 | 选题生成 | | content_generate | v1.0.0 | 内容生成 | | content_judge | v1.0.0 | 内容审核 | | poster_generate | v1.0.0 | 海报文案 | | integration | v1.0.0 | 资料整理 | | style/gonglue | v1.0.0 | 攻略风风格 | | style/tuijian | v1.0.0 | 极力推荐风风格 | | audience/qinzi | v1.0.0 | 亲子向人群 | | audience/zhoubianyou | v1.0.0 | 周边游人群 | | audience/gaoshe | v1.0.0 | 高奢酒店人群 | --- ## V1 引擎废弃说明 V1 引擎已废弃,V2 引擎现在使用默认名称: | 旧 engine_id | 新 engine_id | 说明 | |-------------|-------------|------| | topic_generate_v2 | topic_generate | 选题生成 | | content_generate_v2 | content_generate | 内容生成 | | poster_generate_v2 | poster_generate | 海报生成 | **Java 端直接使用 `topic_generate`、`content_generate`、`poster_generate` 即可。** --- ## 后端对接文档 详见 [API_INTEGRATION.md](./API_INTEGRATION.md)