2025-12-08 14:58:35 +08:00
|
|
|
|
# 技术债务分析报告
|
|
|
|
|
|
|
|
|
|
|
|
> 本文档总结了 TravelContentCreator 项目中的主要技术债务,为后续重构提供参考。
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 1. 数据库双端访问问题
|
|
|
|
|
|
|
|
|
|
|
|
### 现状
|
|
|
|
|
|
|
|
|
|
|
|
Python 端和 Java 端**同时直接访问同一个数据库**,各自维护独立的连接池和查询逻辑。
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
┌─────────────────┐ ┌─────────────────┐
|
|
|
|
|
|
│ Java 后端 │ │ Python AIGC │
|
|
|
|
|
|
│ (zwy_picture) │ │ (TravelContent) │
|
|
|
|
|
|
└────────┬────────┘ └────────┬────────┘
|
|
|
|
|
|
│ │
|
|
|
|
|
|
│ 独立连接池 │ 独立连接池
|
|
|
|
|
|
│ 独立 ORM │ 独立 SQL
|
|
|
|
|
|
▼ ▼
|
|
|
|
|
|
┌─────────────────────────────────┐
|
|
|
|
|
|
│ MySQL (travel_content) │
|
|
|
|
|
|
└─────────────────────────────────┘
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 问题
|
|
|
|
|
|
|
|
|
|
|
|
| 问题 | 影响 |
|
|
|
|
|
|
|-----|------|
|
|
|
|
|
|
| **数据一致性风险** | 两端可能读到不同状态的数据 |
|
|
|
|
|
|
| **连接池资源浪费** | 两套连接池,占用更多连接数 |
|
|
|
|
|
|
| **Schema 同步困难** | 表结构变更需要同时修改两端代码 |
|
|
|
|
|
|
| **事务边界模糊** | 跨服务操作无法保证事务一致性 |
|
|
|
|
|
|
| **代码重复** | 相同的查询逻辑在两端各写一遍 |
|
|
|
|
|
|
|
|
|
|
|
|
### 涉及文件
|
|
|
|
|
|
|
|
|
|
|
|
**Python 端:**
|
|
|
|
|
|
- `api/services/database_service.py` - 独立的数据库服务
|
|
|
|
|
|
- `api/services/prompt_service.py` - 也有自己的连接池
|
|
|
|
|
|
- `infrastructure/database/connection.py` - 新架构的连接管理
|
|
|
|
|
|
|
|
|
|
|
|
**Java 端:**
|
|
|
|
|
|
- `ProductPackageService` - 套餐查询
|
|
|
|
|
|
- `MaterialService` - 素材查询
|
|
|
|
|
|
- 各种 Mapper/Repository
|
|
|
|
|
|
|
|
|
|
|
|
### 建议方案
|
|
|
|
|
|
|
|
|
|
|
|
**方案 A: Python 作为纯算法服务**
|
|
|
|
|
|
```
|
|
|
|
|
|
Java 后端 ──HTTP──> Python AIGC
|
|
|
|
|
|
│ │
|
|
|
|
|
|
│ │ (无数据库访问)
|
|
|
|
|
|
▼ │
|
|
|
|
|
|
MySQL <──────────────┘
|
|
|
|
|
|
```
|
|
|
|
|
|
- Python 只接收 Java 传来的完整数据
|
|
|
|
|
|
- 所有数据库操作由 Java 统一管理
|
|
|
|
|
|
- Python 变成无状态的计算服务
|
|
|
|
|
|
|
|
|
|
|
|
**方案 B: 数据库访问层抽象**
|
|
|
|
|
|
- 创建统一的数据访问 API (REST/gRPC)
|
|
|
|
|
|
- 两端通过 API 访问数据,不直接连数据库
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 2. 图片 Base64 传输问题
|
|
|
|
|
|
|
|
|
|
|
|
### 现状
|
|
|
|
|
|
|
|
|
|
|
|
Java 端从 S3 下载图片 → 转 Base64 → HTTP 传给 Python → Python 解码 → 处理
|
|
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
|
# poster.py L266
|
|
|
|
|
|
image_bytes = base64.b64decode(first_image_base64)
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
```java
|
|
|
|
|
|
// PosterGenerateServiceImpl.java L327
|
|
|
|
|
|
String base64Image = Base64.getEncoder().encodeToString(imageBytes);
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 问题
|
|
|
|
|
|
|
|
|
|
|
|
| 问题 | 影响 |
|
|
|
|
|
|
|-----|------|
|
|
|
|
|
|
| **带宽浪费** | Base64 编码增加 33% 数据量 |
|
|
|
|
|
|
| **内存压力** | 大图片需要完整加载到内存 |
|
|
|
|
|
|
| **延迟增加** | 编解码耗时 + 传输耗时 |
|
|
|
|
|
|
| **HTTP 请求体过大** | 多图场景可能超过限制 |
|
|
|
|
|
|
| **重复传输** | 同一图片可能被多次传输 |
|
|
|
|
|
|
|
|
|
|
|
|
### 数据示例
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
原始图片: 2MB
|
|
|
|
|
|
Base64 后: 2.67MB (+33%)
|
|
|
|
|
|
HTTP 传输: 2.67MB
|
|
|
|
|
|
Python 解码: 2MB 内存占用
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 建议方案
|
|
|
|
|
|
|
|
|
|
|
|
**方案 A: URL 引用模式**
|
|
|
|
|
|
```
|
|
|
|
|
|
Java 端: 上传图片到 S3,返回 URL
|
|
|
|
|
|
Python 端: 直接从 S3/CDN 下载
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**方案 B: 共享存储**
|
|
|
|
|
|
```
|
|
|
|
|
|
Java 端: 保存图片到共享目录 /data/images/{id}.png
|
|
|
|
|
|
Python 端: 直接读取文件路径
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**方案 C: 图片 ID 引用**
|
|
|
|
|
|
```json
|
|
|
|
|
|
{
|
|
|
|
|
|
"image_ids": [123, 456],
|
|
|
|
|
|
"image_source": "s3"
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
Python 端根据 ID 自行获取图片
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 3. ppid / sid / pid 混乱问题
|
|
|
|
|
|
|
|
|
|
|
|
### 现状
|
|
|
|
|
|
|
|
|
|
|
|
系统中存在多种 ID 体系,命名不一致,转换逻辑分散:
|
|
|
|
|
|
|
|
|
|
|
|
| 缩写 | 全称 | 说明 |
|
|
|
|
|
|
|-----|------|------|
|
|
|
|
|
|
| `ppid` | Product Package ID | 套餐 ID (Java 端主用) |
|
|
|
|
|
|
| `pid` | Product ID | 产品 ID |
|
|
|
|
|
|
| `sid` | Scenic Spot ID | 景区 ID |
|
|
|
|
|
|
| `scenic_spot_id` | - | Python 端用的景区 ID |
|
|
|
|
|
|
| `product_id` | - | Python 端用的产品 ID |
|
|
|
|
|
|
|
|
|
|
|
|
### 问题
|
|
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
|
# topic_generate.py - 需要手动解析 ppid
|
|
|
|
|
|
if ppid and (not scenic_spot_id or not product_id):
|
|
|
|
|
|
resolved = await self.db.resolve_ppid(ppid)
|
|
|
|
|
|
scenic_spot_id = resolved.get('scenic_spot_id')
|
|
|
|
|
|
product_id = resolved.get('product_id')
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
```java
|
|
|
|
|
|
// AigcCompatibilityServiceImpl.java - Java 端也要解析
|
|
|
|
|
|
OriginalIds originalIds = getOriginalIdsByPackageId(packageId);
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
| 问题 | 影响 |
|
|
|
|
|
|
|-----|------|
|
|
|
|
|
|
| **命名不一致** | `ppid` vs `packageId` vs `product_package_id` |
|
|
|
|
|
|
| **解析逻辑重复** | Java 和 Python 各自实现一遍 |
|
|
|
|
|
|
| **参数传递混乱** | 有时传 ppid,有时传 sid+pid |
|
|
|
|
|
|
| **向后兼容负担** | 需要同时支持多种参数格式 |
|
|
|
|
|
|
|
|
|
|
|
|
### 涉及文件
|
|
|
|
|
|
|
|
|
|
|
|
- `domain/aigc/engines/*.py` - 每个引擎都要处理 ppid
|
|
|
|
|
|
- `infrastructure/database/repositories/product_package_repository.py`
|
|
|
|
|
|
- `AigcCompatibilityServiceImpl.java`
|
|
|
|
|
|
|
|
|
|
|
|
### 建议方案
|
|
|
|
|
|
|
|
|
|
|
|
**统一入口点:**
|
|
|
|
|
|
```
|
|
|
|
|
|
前端/调用方 ──ppid──> Java 后端 ──解析──> sid + pid ──> Python
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
- 所有 ppid 解析在 Java 端完成
|
|
|
|
|
|
- Python 端只接收已解析的 `scenic_spot_id` 和 `product_id`
|
|
|
|
|
|
- 消除 Python 端的 ppid 解析逻辑
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 4. Prompt 拼接方式问题
|
|
|
|
|
|
|
|
|
|
|
|
### 现状
|
|
|
|
|
|
|
|
|
|
|
|
Prompt 构建分散在多个地方,使用字符串拼接和模板文件混合:
|
|
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
|
# prompt_builder.py L84-90
|
|
|
|
|
|
user_prompt = template.build_user_prompt(
|
|
|
|
|
|
style_content=style_content,
|
|
|
|
|
|
demand_content=demand_content,
|
|
|
|
|
|
object_content=object_content,
|
|
|
|
|
|
product_content=product_content,
|
|
|
|
|
|
refer_content=refer_content
|
|
|
|
|
|
)
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
|
# prompts.py L64-72
|
|
|
|
|
|
def build_user_prompt(self, **kwargs) -> str:
|
|
|
|
|
|
return self.user_template.format(**kwargs)
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 问题
|
|
|
|
|
|
|
|
|
|
|
|
| 问题 | 影响 |
|
|
|
|
|
|
|-----|------|
|
|
|
|
|
|
| **模板文件分散** | 模板在 `prompts/` 目录,配置在 `config/` |
|
|
|
|
|
|
| **变量命名不统一** | `style_content` vs `style` vs `styleName` |
|
|
|
|
|
|
| **难以调试** | 最终 prompt 难以追踪 |
|
|
|
|
|
|
| **版本管理困难** | prompt 变更难以追踪和回滚 |
|
|
|
|
|
|
| **缺乏验证** | 缺少 prompt 有效性检查 |
|
|
|
|
|
|
|
|
|
|
|
|
### 涉及文件
|
|
|
|
|
|
|
|
|
|
|
|
- `utils/prompts.py` - 基础模板类
|
|
|
|
|
|
- `api/services/prompt_builder.py` - 内容 prompt 构建
|
|
|
|
|
|
- `api/services/prompt_service.py` - prompt 服务
|
|
|
|
|
|
- `prompts/*.txt` - 模板文件
|
|
|
|
|
|
|
|
|
|
|
|
### 建议方案
|
|
|
|
|
|
|
|
|
|
|
|
**方案 A: 集中式 Prompt 管理**
|
|
|
|
|
|
```python
|
|
|
|
|
|
class PromptRegistry:
|
|
|
|
|
|
def get_prompt(self, name: str, version: str = "latest") -> PromptTemplate:
|
|
|
|
|
|
"""从数据库或配置中心获取 prompt"""
|
|
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
def render(self, name: str, context: dict) -> str:
|
|
|
|
|
|
"""渲染 prompt"""
|
|
|
|
|
|
pass
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**方案 B: Prompt 配置化**
|
|
|
|
|
|
```yaml
|
|
|
|
|
|
# prompts.yaml
|
|
|
|
|
|
topic_generate:
|
|
|
|
|
|
version: "1.2.0"
|
|
|
|
|
|
system: |
|
|
|
|
|
|
你是一个旅游营销专家...
|
|
|
|
|
|
user: |
|
|
|
|
|
|
请为 {scenic_spot} 生成 {num_topics} 个选题...
|
|
|
|
|
|
variables:
|
|
|
|
|
|
- scenic_spot: required
|
|
|
|
|
|
- num_topics: default=5
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 5. 工具使用方式问题
|
|
|
|
|
|
|
|
|
|
|
|
### 现状
|
|
|
|
|
|
|
|
|
|
|
|
各种工具类和服务的使用方式不统一:
|
|
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
|
# 方式1: 全局单例
|
|
|
|
|
|
from api.dependencies import get_ai_agent, get_config
|
|
|
|
|
|
|
|
|
|
|
|
# 方式2: 构造函数注入
|
|
|
|
|
|
class TopicGenerator:
|
|
|
|
|
|
def __init__(self, ai_agent: AIAgent, config_manager: ConfigManager):
|
|
|
|
|
|
|
|
|
|
|
|
# 方式3: 延迟加载
|
|
|
|
|
|
def _get_tweet_service(self):
|
|
|
|
|
|
if self._tweet_service:
|
|
|
|
|
|
return self._tweet_service
|
|
|
|
|
|
from api.services.tweet import TweetService
|
|
|
|
|
|
self._tweet_service = TweetService(...)
|
|
|
|
|
|
|
|
|
|
|
|
# 方式4: 直接实例化
|
|
|
|
|
|
db_service = DatabaseService(config_manager)
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 问题
|
|
|
|
|
|
|
|
|
|
|
|
| 问题 | 影响 |
|
|
|
|
|
|
|-----|------|
|
|
|
|
|
|
| **依赖注入不一致** | 有的用单例,有的用构造函数 |
|
|
|
|
|
|
| **循环导入风险** | 延迟导入是为了避免循环依赖 |
|
|
|
|
|
|
| **测试困难** | 难以 mock 依赖 |
|
|
|
|
|
|
| **生命周期不清晰** | 不知道对象何时创建/销毁 |
|
|
|
|
|
|
| **资源泄漏风险** | 多个实例可能创建多个连接池 |
|
|
|
|
|
|
|
|
|
|
|
|
### 涉及文件
|
|
|
|
|
|
|
|
|
|
|
|
- `api/dependencies.py` - 依赖获取
|
|
|
|
|
|
- `domain/aigc/shared/component_factory.py` - 组件工厂
|
|
|
|
|
|
- 各个 Engine 类的 `_get_xxx_service()` 方法
|
|
|
|
|
|
|
|
|
|
|
|
### 建议方案
|
|
|
|
|
|
|
|
|
|
|
|
**统一依赖注入容器:**
|
|
|
|
|
|
```python
|
|
|
|
|
|
class Container:
|
|
|
|
|
|
_instances = {}
|
|
|
|
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
|
|
def get(cls, service_class: Type[T]) -> T:
|
|
|
|
|
|
if service_class not in cls._instances:
|
|
|
|
|
|
cls._instances[service_class] = cls._create(service_class)
|
|
|
|
|
|
return cls._instances[service_class]
|
|
|
|
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
|
|
def _create(cls, service_class):
|
|
|
|
|
|
# 根据类型创建实例,自动解析依赖
|
|
|
|
|
|
pass
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**或使用现有框架:**
|
|
|
|
|
|
- `dependency-injector` 库
|
|
|
|
|
|
- FastAPI 的 `Depends` 系统
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 总结:优先级建议
|
|
|
|
|
|
|
|
|
|
|
|
| 优先级 | 问题 | 原因 |
|
|
|
|
|
|
|-------|------|------|
|
|
|
|
|
|
| 🔴 高 | 数据库双端访问 | 数据一致性风险最大 |
|
|
|
|
|
|
| 🔴 高 | ppid 混乱 | 影响所有 AIGC 调用 |
|
|
|
|
|
|
| 🟡 中 | 图片 Base64 传输 | 性能问题,但功能正常 |
|
|
|
|
|
|
| 🟡 中 | Prompt 拼接 | 维护困难,但不影响功能 |
|
|
|
|
|
|
| 🟢 低 | 工具使用方式 | 代码质量问题,可渐进改进 |
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 6. 临时文件堆积问题
|
|
|
|
|
|
|
|
|
|
|
|
### 现状
|
|
|
|
|
|
|
|
|
|
|
|
每次 API 请求都会在 `result/` 目录下创建新的子目录,保存中间产物:
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
$ du -sh result/
|
|
|
|
|
|
943M result/
|
|
|
|
|
|
|
|
|
|
|
|
$ ls -1 result/ | wc -l
|
|
|
|
|
|
6931
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**6931 个目录,占用 943MB 磁盘空间!**
|
|
|
|
|
|
|
|
|
|
|
|
### 问题
|
|
|
|
|
|
|
|
|
|
|
|
| 问题 | 影响 |
|
|
|
|
|
|
|-----|------|
|
|
|
|
|
|
| **磁盘空间浪费** | 近 1GB 的临时文件 |
|
|
|
|
|
|
| **无清理机制** | 文件只增不减 |
|
|
|
|
|
|
| **目录数量过多** | 影响文件系统性能 |
|
|
|
|
|
|
| **敏感信息泄露风险** | prompt、生成内容可能包含敏感数据 |
|
|
|
|
|
|
|
|
|
|
|
|
### 涉及文件
|
|
|
|
|
|
|
|
|
|
|
|
- `utils/file_io.py` - `OutputManager` 类
|
|
|
|
|
|
- 每次请求创建: `result/api_request-{timestamp}-{uuid}/`
|
|
|
|
|
|
|
|
|
|
|
|
### 建议方案
|
|
|
|
|
|
|
|
|
|
|
|
1. **定期清理**: 添加定时任务清理 7 天前的目录
|
|
|
|
|
|
2. **按需保存**: 只在调试模式下保存中间产物
|
|
|
|
|
|
3. **内存缓存**: 中间结果保存在内存,不落盘
|
|
|
|
|
|
4. **统一存储**: 重要结果上传到 S3,本地只做临时缓存
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 7. 配置分散问题
|
|
|
|
|
|
|
|
|
|
|
|
### 现状
|
|
|
|
|
|
|
|
|
|
|
|
配置文件分散在多个 JSON 文件中:
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
config/
|
|
|
|
|
|
├── ai_model.json # AI 模型配置
|
|
|
|
|
|
├── content_gen.json # 内容生成配置 (含 prompt 路径)
|
|
|
|
|
|
├── topic_gen.json # 选题生成配置 (含 prompt 路径)
|
|
|
|
|
|
├── poster_gen.json # 海报生成配置
|
|
|
|
|
|
├── database.json # 数据库配置
|
|
|
|
|
|
├── paths.json # 路径配置
|
|
|
|
|
|
├── resource.json # 资源配置
|
|
|
|
|
|
├── system.json # 系统配置
|
|
|
|
|
|
└── cookies.json # Cookie 配置
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 问题
|
|
|
|
|
|
|
|
|
|
|
|
| 问题 | 影响 |
|
|
|
|
|
|
|-----|------|
|
|
|
|
|
|
| **配置分散** | 9 个配置文件,难以统一管理 |
|
|
|
|
|
|
| **路径嵌套** | 配置中引用其他配置路径 |
|
|
|
|
|
|
| **环境切换困难** | 没有 dev/prod 环境区分 |
|
|
|
|
|
|
| **敏感信息明文** | 数据库密码、API Key 明文存储 |
|
|
|
|
|
|
|
|
|
|
|
|
### 建议方案
|
|
|
|
|
|
|
|
|
|
|
|
1. **环境变量优先**: 敏感信息从环境变量读取
|
|
|
|
|
|
2. **配置合并**: 合并为 `config.yaml` + 环境覆盖
|
|
|
|
|
|
3. **配置中心**: 使用 Consul/Nacos 等配置中心
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 8. 错误处理不一致
|
|
|
|
|
|
|
|
|
|
|
|
### 现状
|
|
|
|
|
|
|
|
|
|
|
|
不同模块的错误处理方式不统一:
|
|
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
|
# 方式1: 返回 None
|
|
|
|
|
|
if not topics:
|
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
|
|
# 方式2: 返回错误字典
|
|
|
|
|
|
return {"error": str(e)}
|
|
|
|
|
|
|
|
|
|
|
|
# 方式3: 抛出异常
|
|
|
|
|
|
raise ValueError(f"生成海报失败: {str(e)}")
|
|
|
|
|
|
|
|
|
|
|
|
# 方式4: 返回元组
|
|
|
|
|
|
return str(uuid.uuid4()), []
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 问题
|
|
|
|
|
|
|
|
|
|
|
|
| 问题 | 影响 |
|
|
|
|
|
|
|-----|------|
|
|
|
|
|
|
| **调用方难以处理** | 需要检查多种错误格式 |
|
|
|
|
|
|
| **错误信息丢失** | 有些地方只返回 None |
|
|
|
|
|
|
| **日志不统一** | 有的记录,有的不记录 |
|
|
|
|
|
|
| **没有错误码** | 难以区分错误类型 |
|
|
|
|
|
|
|
|
|
|
|
|
### 建议方案
|
|
|
|
|
|
|
|
|
|
|
|
统一使用 `Result` 模式:
|
|
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
|
@dataclass
|
|
|
|
|
|
class Result(Generic[T]):
|
|
|
|
|
|
success: bool
|
|
|
|
|
|
data: Optional[T] = None
|
|
|
|
|
|
error: Optional[str] = None
|
|
|
|
|
|
error_code: Optional[str] = None
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 4. Prompt 管理方案 (详细设计)
|
|
|
|
|
|
|
|
|
|
|
|
### 当前问题分析
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
config/content_gen.json
|
|
|
|
|
|
└── "content_system_prompt": "resource/prompt/generateContent/system.txt"
|
|
|
|
|
|
│
|
|
|
|
|
|
▼
|
|
|
|
|
|
resource/prompt/generateContent/system.txt (87 行硬编码的 prompt)
|
|
|
|
|
|
│
|
|
|
|
|
|
▼
|
|
|
|
|
|
utils/prompts.py PromptTemplate.format(**kwargs)
|
|
|
|
|
|
│
|
|
|
|
|
|
▼
|
|
|
|
|
|
api/services/prompt_builder.py 拼接变量
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**问题:**
|
|
|
|
|
|
1. Prompt 内容硬编码在 `.txt` 文件中
|
|
|
|
|
|
2. 变量占位符 `{style_content}` 与代码强耦合
|
|
|
|
|
|
3. 无版本管理,修改后无法回滚
|
|
|
|
|
|
4. 无 A/B 测试能力
|
|
|
|
|
|
5. 无效果追踪
|
|
|
|
|
|
|
|
|
|
|
|
### 推荐方案: YAML + 版本化 Prompt Registry
|
|
|
|
|
|
|
|
|
|
|
|
#### 目录结构
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
prompts/
|
|
|
|
|
|
├── registry.yaml # Prompt 注册表
|
|
|
|
|
|
├── topic_generate/
|
|
|
|
|
|
│ ├── v1.0.0.yaml # 版本化的 prompt
|
|
|
|
|
|
│ ├── v1.1.0.yaml
|
|
|
|
|
|
│ └── latest -> v1.1.0.yaml # 软链接
|
|
|
|
|
|
├── content_generate/
|
|
|
|
|
|
│ ├── v1.0.0.yaml
|
|
|
|
|
|
│ └── latest -> v1.0.0.yaml
|
|
|
|
|
|
└── content_judge/
|
|
|
|
|
|
└── v1.0.0.yaml
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
#### Prompt 定义格式 (YAML)
|
|
|
|
|
|
|
|
|
|
|
|
```yaml
|
|
|
|
|
|
# prompts/content_generate/v1.0.0.yaml
|
|
|
|
|
|
meta:
|
|
|
|
|
|
name: content_generate
|
|
|
|
|
|
version: "1.0.0"
|
|
|
|
|
|
description: "小红书风格内容生成"
|
|
|
|
|
|
author: "team"
|
|
|
|
|
|
created_at: "2024-12-08"
|
|
|
|
|
|
|
|
|
|
|
|
# 模型参数
|
|
|
|
|
|
model:
|
|
|
|
|
|
temperature: 0.3
|
|
|
|
|
|
top_p: 0.5
|
|
|
|
|
|
presence_penalty: 1.2
|
|
|
|
|
|
|
|
|
|
|
|
# 变量定义 (带类型和默认值)
|
|
|
|
|
|
variables:
|
|
|
|
|
|
style_content:
|
|
|
|
|
|
type: string
|
|
|
|
|
|
required: true
|
|
|
|
|
|
description: "风格描述"
|
|
|
|
|
|
demand_content:
|
|
|
|
|
|
type: string
|
|
|
|
|
|
required: true
|
|
|
|
|
|
description: "受众需求"
|
|
|
|
|
|
object_content:
|
|
|
|
|
|
type: string
|
|
|
|
|
|
required: true
|
|
|
|
|
|
description: "景区/产品信息"
|
|
|
|
|
|
product_content:
|
|
|
|
|
|
type: string
|
|
|
|
|
|
required: false
|
|
|
|
|
|
default: ""
|
|
|
|
|
|
description: "产品详情"
|
|
|
|
|
|
refer_content:
|
|
|
|
|
|
type: string
|
|
|
|
|
|
required: false
|
|
|
|
|
|
default: ""
|
|
|
|
|
|
description: "参考范文"
|
|
|
|
|
|
|
|
|
|
|
|
# System Prompt
|
|
|
|
|
|
system: |
|
|
|
|
|
|
你是景区小红书爆款文案策划,你将根据要求创作爆款文案。
|
|
|
|
|
|
|
|
|
|
|
|
## 标题创作规则
|
|
|
|
|
|
1. 必加1个emoji,标题字数18字以内
|
|
|
|
|
|
2. 有网感,结合所在地
|
|
|
|
|
|
3. 标题必须结合给出的标题参考格式进行高相似度仿写
|
|
|
|
|
|
|
|
|
|
|
|
## 正文创作规则
|
|
|
|
|
|
1. 以"你"这种有人味的人称代词视角创作
|
|
|
|
|
|
2. 不要出现"宝子们""姐妹们"这些很假的称呼
|
|
|
|
|
|
3. 直击用户痛点,有场景感
|
|
|
|
|
|
4. 分段+分点论述,巧用emoji
|
|
|
|
|
|
|
|
|
|
|
|
## 输出格式
|
|
|
|
|
|
```json
|
|
|
|
|
|
{
|
|
|
|
|
|
"title": "标题内容",
|
|
|
|
|
|
"content": "正文内容",
|
|
|
|
|
|
"tag": "#标签1 #标签2 ..."
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
# User Prompt (使用 Jinja2 模板语法)
|
|
|
|
|
|
user: |
|
|
|
|
|
|
请根据以下材料创作一篇小红书文案:
|
|
|
|
|
|
|
|
|
|
|
|
【风格要求】
|
|
|
|
|
|
{{ style_content }}
|
|
|
|
|
|
|
|
|
|
|
|
【目标受众】
|
|
|
|
|
|
{{ demand_content }}
|
|
|
|
|
|
|
|
|
|
|
|
【景区/产品信息】
|
|
|
|
|
|
{{ object_content }}
|
|
|
|
|
|
|
|
|
|
|
|
{% if product_content %}
|
|
|
|
|
|
【产品详情】
|
|
|
|
|
|
{{ product_content }}
|
|
|
|
|
|
{% endif %}
|
|
|
|
|
|
|
|
|
|
|
|
{% if refer_content %}
|
|
|
|
|
|
【参考范文】
|
|
|
|
|
|
{{ refer_content }}
|
|
|
|
|
|
{% endif %}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
#### Prompt Registry 实现
|
|
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
|
# domain/prompt/registry.py
|
|
|
|
|
|
|
|
|
|
|
|
from pathlib import Path
|
|
|
|
|
|
from typing import Dict, Any, Optional
|
|
|
|
|
|
import yaml
|
|
|
|
|
|
from jinja2 import Template
|
|
|
|
|
|
from dataclasses import dataclass
|
|
|
|
|
|
|
|
|
|
|
|
@dataclass
|
|
|
|
|
|
class PromptConfig:
|
|
|
|
|
|
"""Prompt 配置"""
|
|
|
|
|
|
name: str
|
|
|
|
|
|
version: str
|
|
|
|
|
|
system: str
|
|
|
|
|
|
user: str
|
|
|
|
|
|
variables: Dict[str, Any]
|
|
|
|
|
|
model: Dict[str, float]
|
|
|
|
|
|
|
|
|
|
|
|
class PromptRegistry:
|
|
|
|
|
|
"""
|
|
|
|
|
|
Prompt 注册表
|
|
|
|
|
|
|
|
|
|
|
|
功能:
|
|
|
|
|
|
1. 加载和缓存 prompt 配置
|
|
|
|
|
|
2. 版本管理 (latest, v1.0.0, v1.1.0)
|
|
|
|
|
|
3. 变量验证
|
|
|
|
|
|
4. 模板渲染
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
def __init__(self, prompts_dir: str = "prompts"):
|
|
|
|
|
|
self.prompts_dir = Path(prompts_dir)
|
|
|
|
|
|
self._cache: Dict[str, PromptConfig] = {}
|
|
|
|
|
|
|
|
|
|
|
|
def get(self, name: str, version: str = "latest") -> PromptConfig:
|
|
|
|
|
|
"""
|
|
|
|
|
|
获取 prompt 配置
|
|
|
|
|
|
|
|
|
|
|
|
Args:
|
|
|
|
|
|
name: prompt 名称 (如 "content_generate")
|
|
|
|
|
|
version: 版本号 (如 "v1.0.0" 或 "latest")
|
|
|
|
|
|
"""
|
|
|
|
|
|
cache_key = f"{name}:{version}"
|
|
|
|
|
|
|
|
|
|
|
|
if cache_key not in self._cache:
|
|
|
|
|
|
self._cache[cache_key] = self._load(name, version)
|
|
|
|
|
|
|
|
|
|
|
|
return self._cache[cache_key]
|
|
|
|
|
|
|
|
|
|
|
|
def render(self, name: str, context: Dict[str, Any],
|
|
|
|
|
|
version: str = "latest") -> tuple[str, str]:
|
|
|
|
|
|
"""
|
|
|
|
|
|
渲染 prompt
|
|
|
|
|
|
|
|
|
|
|
|
Returns:
|
|
|
|
|
|
(system_prompt, user_prompt)
|
|
|
|
|
|
"""
|
|
|
|
|
|
config = self.get(name, version)
|
|
|
|
|
|
|
|
|
|
|
|
# 验证必填变量
|
|
|
|
|
|
self._validate_variables(config, context)
|
|
|
|
|
|
|
|
|
|
|
|
# 渲染模板
|
|
|
|
|
|
system = config.system # system 通常不需要变量
|
|
|
|
|
|
user = Template(config.user).render(**context)
|
|
|
|
|
|
|
|
|
|
|
|
return system, user
|
|
|
|
|
|
|
|
|
|
|
|
def _load(self, name: str, version: str) -> PromptConfig:
|
|
|
|
|
|
"""加载 prompt 配置文件"""
|
|
|
|
|
|
if version == "latest":
|
|
|
|
|
|
# 读取 latest 软链接指向的文件
|
|
|
|
|
|
prompt_path = self.prompts_dir / name / "latest.yaml"
|
|
|
|
|
|
if prompt_path.is_symlink():
|
|
|
|
|
|
prompt_path = prompt_path.resolve()
|
|
|
|
|
|
elif not prompt_path.exists():
|
|
|
|
|
|
# 找最新版本
|
|
|
|
|
|
versions = sorted(
|
|
|
|
|
|
(self.prompts_dir / name).glob("v*.yaml"),
|
|
|
|
|
|
reverse=True
|
|
|
|
|
|
)
|
|
|
|
|
|
if versions:
|
|
|
|
|
|
prompt_path = versions[0]
|
|
|
|
|
|
else:
|
|
|
|
|
|
prompt_path = self.prompts_dir / name / f"{version}.yaml"
|
|
|
|
|
|
|
|
|
|
|
|
if not prompt_path.exists():
|
|
|
|
|
|
raise FileNotFoundError(f"Prompt not found: {name}:{version}")
|
|
|
|
|
|
|
|
|
|
|
|
with open(prompt_path, 'r', encoding='utf-8') as f:
|
|
|
|
|
|
data = yaml.safe_load(f)
|
|
|
|
|
|
|
|
|
|
|
|
return PromptConfig(
|
|
|
|
|
|
name=data['meta']['name'],
|
|
|
|
|
|
version=data['meta']['version'],
|
|
|
|
|
|
system=data['system'],
|
|
|
|
|
|
user=data['user'],
|
|
|
|
|
|
variables=data.get('variables', {}),
|
|
|
|
|
|
model=data.get('model', {})
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
def _validate_variables(self, config: PromptConfig, context: Dict[str, Any]):
|
|
|
|
|
|
"""验证变量"""
|
|
|
|
|
|
for var_name, var_config in config.variables.items():
|
|
|
|
|
|
if var_config.get('required', False) and var_name not in context:
|
|
|
|
|
|
raise ValueError(f"Missing required variable: {var_name}")
|
|
|
|
|
|
|
|
|
|
|
|
def list_versions(self, name: str) -> list[str]:
|
|
|
|
|
|
"""列出所有版本"""
|
|
|
|
|
|
prompt_dir = self.prompts_dir / name
|
|
|
|
|
|
if not prompt_dir.exists():
|
|
|
|
|
|
return []
|
|
|
|
|
|
|
|
|
|
|
|
versions = []
|
|
|
|
|
|
for f in prompt_dir.glob("v*.yaml"):
|
|
|
|
|
|
versions.append(f.stem)
|
|
|
|
|
|
return sorted(versions, reverse=True)
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
#### 使用示例
|
|
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
|
# 使用新的 Prompt Registry
|
|
|
|
|
|
registry = PromptRegistry("prompts")
|
|
|
|
|
|
|
|
|
|
|
|
# 渲染 prompt
|
|
|
|
|
|
system, user = registry.render(
|
|
|
|
|
|
name="content_generate",
|
|
|
|
|
|
context={
|
|
|
|
|
|
"style_content": "攻略风格,实用性强",
|
|
|
|
|
|
"demand_content": "亲子家庭,周末出游",
|
|
|
|
|
|
"object_content": "天津冒险湾主题乐园...",
|
|
|
|
|
|
"product_content": "门票299元/人",
|
|
|
|
|
|
},
|
|
|
|
|
|
version="latest" # 或指定 "v1.0.0"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
# 获取模型参数
|
|
|
|
|
|
config = registry.get("content_generate")
|
|
|
|
|
|
model_params = config.model # {"temperature": 0.3, ...}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
#### 优势
|
|
|
|
|
|
|
|
|
|
|
|
| 特性 | 说明 |
|
|
|
|
|
|
|-----|------|
|
|
|
|
|
|
| **版本管理** | 每个版本独立文件,可回滚 |
|
|
|
|
|
|
| **变量验证** | 自动检查必填变量 |
|
|
|
|
|
|
| **模板语法** | Jinja2 支持条件、循环 |
|
|
|
|
|
|
| **模型参数绑定** | prompt 和模型参数一起管理 |
|
|
|
|
|
|
| **缓存** | 加载后缓存,避免重复 IO |
|
|
|
|
|
|
| **A/B 测试** | 可指定不同版本测试效果 |
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 下一步行动
|
|
|
|
|
|
|
|
|
|
|
|
### 已确认的改进方向
|
|
|
|
|
|
|
|
|
|
|
|
| # | 问题 | 方案 |
|
|
|
|
|
|
|---|------|------|
|
|
|
|
|
|
| 1 | 数据库双端访问 | Python 不访问数据库,改为接口传输 |
|
|
|
|
|
|
| 2 | 图片 Base64 传输 | 改为 URL/路径引用 |
|
|
|
|
|
|
| 3 | ppid 混乱 | 放弃 ppid,Java 直接传完整数据 |
|
|
|
|
|
|
| 4 | Prompt 管理 | YAML + 版本化 Registry |
|
|
|
|
|
|
| 5 | 依赖注入 | 统一容器模式 |
|
|
|
|
|
|
| 6 | 临时文件堆积 | 添加清理机制 |
|
|
|
|
|
|
| 7 | 配置分散 | 合并 + 环境变量 |
|
|
|
|
|
|
| 8 | 错误处理不一致 | 统一 Result 模式 |
|
|
|
|
|
|
|
|
|
|
|
|
### 优先级排序
|
|
|
|
|
|
|
|
|
|
|
|
1. **🔴 高优先级** (影响架构)
|
|
|
|
|
|
- 数据库访问改接口
|
|
|
|
|
|
- 图片传输改 URL
|
|
|
|
|
|
- 放弃 ppid
|
|
|
|
|
|
|
|
|
|
|
|
2. **🟡 中优先级** (影响维护)
|
|
|
|
|
|
- Prompt Registry
|
|
|
|
|
|
- 错误处理统一
|
|
|
|
|
|
- 临时文件清理
|
|
|
|
|
|
|
|
|
|
|
|
3. **🟢 低优先级** (代码质量)
|
|
|
|
|
|
- 依赖注入优化
|
|
|
|
|
|
- 配置合并
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 9. 巨型文件问题
|
|
|
|
|
|
|
|
|
|
|
|
### 现状
|
|
|
|
|
|
|
|
|
|
|
|
部分文件代码量过大,难以维护:
|
|
|
|
|
|
|
|
|
|
|
|
| 文件 | 行数 | 问题 |
|
|
|
|
|
|
|-----|------|------|
|
|
|
|
|
|
| `demo_refactored_templates.py` | 4219 | 示例/废弃代码? |
|
|
|
|
|
|
| `poster_template.py` | 3421 | 根目录下的模板文件 |
|
|
|
|
|
|
| `api/services/poster.py` | 3031 | 海报服务,职责过多 |
|
|
|
|
|
|
| `poster/templates/vibrant_template.py` | 1756 | 单个模板文件过大 |
|
|
|
|
|
|
| `api/services/database_service.py` | 1054 | 数据库服务 |
|
|
|
|
|
|
| `core/xhs_spider/apis/xhs_pc_apis.py` | 1019 | 小红书 API |
|
|
|
|
|
|
|
|
|
|
|
|
### 问题
|
|
|
|
|
|
|
|
|
|
|
|
| 问题 | 影响 |
|
|
|
|
|
|
|-----|------|
|
|
|
|
|
|
| **难以理解** | 3000+ 行代码难以阅读 |
|
|
|
|
|
|
| **难以测试** | 职责混杂,难以单元测试 |
|
|
|
|
|
|
| **合并冲突** | 多人修改同一文件容易冲突 |
|
|
|
|
|
|
| **废弃代码** | 根目录下的 `poster_template.py` 和 `demo_*.py` 可能是废弃代码 |
|
|
|
|
|
|
|
|
|
|
|
|
### 建议方案
|
|
|
|
|
|
|
|
|
|
|
|
1. **拆分大文件**: `poster.py` 拆分为多个模块 (已在新架构中完成)
|
|
|
|
|
|
2. **清理废弃代码**: 删除根目录下的 `poster_template.py`, `demo_*.py`
|
|
|
|
|
|
3. **单一职责**: 每个类/模块只做一件事
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 10. 重复代码问题
|
|
|
|
|
|
|
|
|
|
|
|
### 现状
|
|
|
|
|
|
|
|
|
|
|
|
存在多处重复或相似的代码:
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
# 目录重复
|
|
|
|
|
|
/root/TravelContentCreator/document/ # 旧位置
|
|
|
|
|
|
/root/TravelContentCreator/core/document/ # 新位置 (重复)
|
|
|
|
|
|
|
|
|
|
|
|
# 文件重复
|
|
|
|
|
|
./document/content_transformer.py
|
|
|
|
|
|
./core/document/content_transformer.py
|
|
|
|
|
|
|
|
|
|
|
|
./document/content_integrator.py
|
|
|
|
|
|
./core/document/content_integrator.py
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 问题
|
|
|
|
|
|
|
|
|
|
|
|
| 问题 | 影响 |
|
|
|
|
|
|
|-----|------|
|
|
|
|
|
|
| **不知道用哪个** | 两个位置都有相同文件 |
|
|
|
|
|
|
| **修改遗漏** | 改了一个忘了另一个 |
|
|
|
|
|
|
| **导入混乱** | `from document.xxx` vs `from core.document.xxx` |
|
|
|
|
|
|
|
|
|
|
|
|
### 建议方案
|
|
|
|
|
|
|
|
|
|
|
|
1. 确定唯一位置
|
|
|
|
|
|
2. 删除重复目录
|
|
|
|
|
|
3. 更新所有 import
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 11. API 路由分散问题
|
|
|
|
|
|
|
|
|
|
|
|
### 现状
|
|
|
|
|
|
|
|
|
|
|
|
API 路由分散在多个文件中,功能有重叠:
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
api/routers/
|
|
|
|
|
|
├── aigc.py # 新的统一 AIGC API
|
|
|
|
|
|
├── tweet.py # 旧的选题/内容 API (470 行)
|
|
|
|
|
|
├── poster.py # 旧的海报 API
|
|
|
|
|
|
├── data.py # 数据查询 API
|
|
|
|
|
|
├── document.py # 文档处理 API
|
|
|
|
|
|
├── integration.py # 集成 API
|
|
|
|
|
|
├── content_integration.py # 内容集成 API
|
|
|
|
|
|
└── prompt.py # 提示词 API
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 问题
|
|
|
|
|
|
|
|
|
|
|
|
| 问题 | 影响 |
|
|
|
|
|
|
|-----|------|
|
|
|
|
|
|
| **功能重叠** | `aigc.py` 和 `tweet.py`/`poster.py` 功能重复 |
|
|
|
|
|
|
| **命名不一致** | `tweet` vs `content`, `integration` vs `content_integration` |
|
|
|
|
|
|
| **API 版本混乱** | 没有清晰的 v1/v2 区分 |
|
|
|
|
|
|
|
|
|
|
|
|
### 建议方案
|
|
|
|
|
|
|
|
|
|
|
|
1. 统一使用 `/api/v2/aigc/*` 作为新入口
|
|
|
|
|
|
2. 旧 API 标记为 deprecated
|
|
|
|
|
|
3. 逐步迁移后删除旧路由
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 12. 日志配置问题
|
|
|
|
|
|
|
|
|
|
|
|
### 现状
|
|
|
|
|
|
|
|
|
|
|
|
每个文件都单独配置 logger:
|
|
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
|
# 几乎每个 .py 文件都有这行
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
但没有统一的日志配置:
|
|
|
|
|
|
- 日志格式不统一
|
|
|
|
|
|
- 日志级别分散控制
|
|
|
|
|
|
- 没有日志轮转
|
|
|
|
|
|
- 没有结构化日志
|
|
|
|
|
|
|
|
|
|
|
|
### 建议方案
|
|
|
|
|
|
|
|
|
|
|
|
```python
|
|
|
|
|
|
# 统一日志配置
|
|
|
|
|
|
LOGGING_CONFIG = {
|
|
|
|
|
|
"version": 1,
|
|
|
|
|
|
"formatters": {
|
|
|
|
|
|
"default": {
|
|
|
|
|
|
"format": "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
|
|
|
|
|
},
|
|
|
|
|
|
"json": {
|
|
|
|
|
|
"class": "pythonjsonlogger.jsonlogger.JsonFormatter"
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
"handlers": {
|
|
|
|
|
|
"console": {"class": "logging.StreamHandler", "formatter": "default"},
|
|
|
|
|
|
"file": {"class": "logging.handlers.RotatingFileHandler", ...}
|
|
|
|
|
|
},
|
|
|
|
|
|
"root": {"level": "INFO", "handlers": ["console", "file"]}
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 完整问题清单
|
|
|
|
|
|
|
|
|
|
|
|
| # | 问题 | 严重程度 | 状态 |
|
|
|
|
|
|
|---|------|---------|------|
|
|
|
|
|
|
| 1 | 数据库双端访问 | 🔴 高 | ✅ V2 引擎已解决 |
|
|
|
|
|
|
| 2 | 图片 Base64 传输 | 🟡 中 | ✅ V2 引擎支持 URL |
|
2025-12-09 21:16:44 +08:00
|
|
|
|
| 3 | ppid 混乱 | 🔴 高 | ✅ 已废弃,Java 端传完整对象 |
|
2025-12-08 14:58:35 +08:00
|
|
|
|
| 4 | Prompt 管理分散 | 🟡 中 | ✅ PromptRegistry 已实现 |
|
|
|
|
|
|
| 5 | 依赖注入不统一 | 🟢 低 | ✅ Container 已实现 |
|
2025-12-09 21:16:44 +08:00
|
|
|
|
| 6 | 临时文件堆积 | 🟡 中 | ✅ 清理脚本已创建 |
|
|
|
|
|
|
| 7 | 配置分散 | 🟢 低 | ✅ UnifiedConfig 已实现 |
|
|
|
|
|
|
| 8 | 错误处理不一致 | 🟡 中 | ✅ 统一异常类已定义 |
|
2025-12-08 14:58:35 +08:00
|
|
|
|
| 9 | 巨型文件 | 🟡 中 | 部分已拆分 |
|
2025-12-09 21:16:44 +08:00
|
|
|
|
| 10 | 重复代码/目录 | 🟡 中 | ✅ document 已统一 |
|
2025-12-08 14:58:35 +08:00
|
|
|
|
| 11 | API 路由分散 | 🟢 低 | 新架构已统一 |
|
2025-12-09 21:16:44 +08:00
|
|
|
|
| 12 | 日志配置缺失 | 🟢 低 | ✅ logging_config 已实现 |
|
2025-12-08 14:58:35 +08:00
|
|
|
|
|
|
|
|
|
|
> 详细实施记录见 [REFACTORING_IMPLEMENTATION.md](./REFACTORING_IMPLEMENTATION.md)
|