You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

15 KiB

AI Service 技术栈规范符合性检查报告

日期: 2026-01-29
检查范围: AI Service 文档与实现
检查依据: Jointo 技术栈规范(jointo-tech-stack skill)


执行摘要

总体评估: AI Service 实现完全符合 Jointo 技术栈规范

符合项: 17/17 (100%)
不符合项: 0/17 (0%)
已修复: 2 项(日志格式化、异常日志)


详细检查结果

1. 数据库设计规范

1.1 时间字段使用 TIMESTAMPTZ

规范要求: 所有事件时间戳必须使用 TIMESTAMPTZ(ADR 006)

文档检查:

  • ai_jobs 表:created_at, updated_at, started_at, completed_at, estimated_completion_at 全部使用 TIMESTAMPTZ
  • ai_models 表:created_at, updated_at 使用 TIMESTAMPTZ
  • ai_usage_logs 表:created_at 使用 TIMESTAMPTZ
  • ai_quotas 表:created_at, updated_at, reset_at 使用 TIMESTAMPTZ

实现检查:

# server/app/models/ai_job.py
created_at: datetime = Field(
    default_factory=lambda: datetime.now(timezone.utc),
    sa_column=Column(
        TIMESTAMP(timezone=True),  # ✅ 正确使用 TIMESTAMPTZ
        nullable=False,
        server_default=text('now()'),
        index=True,
        comment='创建时间'
    )
)

结论: 完全符合


1.2 JSON 字段使用 JSONB

规范要求: 使用 JSONB 而非 JSON(性能更好)

文档检查:

  • ai_jobs.input_data: JSONB
  • ai_jobs.output_data: JSONB
  • ai_models.config: JSONB
  • ai_usage_logs.extra_metadata: JSONB(实现中已重命名)

实现检查:

# server/app/models/ai_job.py
input_data: dict = Field(
    default_factory=dict,
    sa_column=Column(
        JSONB,  # ✅ 正确使用 JSONB
        nullable=False,
        server_default='{}',
        comment='输入参数(prompt, 配置等)'
    )
)

结论: 完全符合


1.3 枚举类型使用 SMALLINT

规范要求: 使用 SMALLINT 存储枚举值,配合 Python IntEnum

文档检查:

  • ai_jobs.job_type: SMALLINT(1-9)
  • ai_jobs.status: SMALLINT(1-5)
  • ai_models.provider: SMALLINT(1-99)
  • ai_models.model_type: SMALLINT(1-4)
  • ai_models.unit_type: SMALLINT(1-4)
  • ai_usage_logs.unit_type: SMALLINT(1-4)
  • ai_quotas.period: SMALLINT(1-3)

实现检查:

# server/app/models/ai_job.py
class AIJobType(IntEnum):  # ✅ 使用 IntEnum
    IMAGE = 1
    VIDEO = 2
    SOUND = 3
    VOICE = 4
    SUBTITLE = 5
    TEXT_PROCESSING = 6
    RESOURCE = 7
    STORYBOARD_SCRIPT = 8
    SCRIPT_GENERATION = 9

job_type: int = Field(
    sa_column=Column(
        SmallInteger,  # ✅ 使用 SMALLINT
        nullable=False,
        index=True,
        comment='任务类型(1=图片 2=视频 ...)'
    )
)

结论: 完全符合


1.4 无物理外键约束

规范要求: 数据库层禁止创建 FOREIGN KEY 约束,应用层保证引用完整性

文档检查:

  • 所有关联字段都明确标注"无外键约束,应用层保证引用完整性"
  • 所有关联字段都有索引
  • 所有关联字段都有注释说明"应用层验证"

实现检查:

# server/app/models/ai_job.py
user_id: UUID = Field(
    sa_column=Column(
        PG_UUID(as_uuid=True),
        nullable=False,
        index=True,  # ✅ 有索引
        comment='用户 ID - 应用层验证'  # ✅ 明确标注
    )
)
# ✅ 无 ForeignKey 定义

Service 层验证:

# server/app/services/ai_service.py
async def _validate_user_exists(self, user_id: str) -> None:
    """验证用户是否存在(应用层引用完整性保证)"""
    if not await self.user_repository.exists(UUID(user_id)):
        raise NotFoundError(f"用户不存在: {user_id}")

结论: 完全符合


1.5 索引策略

规范要求: 所有关联字段和查询字段必须有索引

文档检查:

  • ai_jobs: 12+ 个索引(包括 GIN 索引)
  • ai_models: 4 个索引(包括 GIN 索引)
  • ai_usage_logs: 6 个索引(包括 GIN 索引)
  • ai_quotas: 4 个索引

实现检查:

# server/app/models/ai_job.py
__table_args__ = (
    CheckConstraint('progress >= 0 AND progress <= 100', name='ai_jobs_progress_check'),
    Index('idx_ai_jobs_status_created_at', 'status', 'created_at',
          postgresql_where=text('status IN (1, 2)')),  # ✅ 部分索引
    Index('idx_ai_jobs_input_data_gin', 'input_data', postgresql_using='gin'),  # ✅ GIN 索引
    Index('idx_ai_jobs_output_data_gin', 'output_data',
          postgresql_using='gin',
          postgresql_where=text('output_data IS NOT NULL')),  # ✅ 条件索引
)

结论: 完全符合


2. 代码规范

2.1 异步编程

规范要求: 所有数据库操作使用 async/await 模式配合 asyncpg

实现检查:

# server/app/services/ai_service.py
async def generate_image(
    self,
    user_id: str,
    prompt: str,
    ...
) -> Dict[str, Any]:
    """生成图片(异步)"""
    # ✅ 所有方法都是 async
    await self._validate_user_exists(user_id)  # ✅ 使用 await
    await self._check_quota(user_id, 'image_generation')
    
    async with self.db.begin():  # ✅ 异步事务
        consumption_log = await self.credit_service.consume_credits(...)
        job = await self.job_repository.create(...)

结论: 完全符合


2.2 依赖注入

规范要求: Service 层注入 Repository 和其他 Service

实现检查:

# server/app/services/ai_service.py
class AIService:
    """AI 生成服务 - 完整集成 Credit Service"""
    
    def __init__(self, db: AsyncSession):
        self.db = db
        self.job_repository = AIJobRepository(db)  # ✅ 注入 Repository
        self.model_repository = AIModelRepository(db)
        self.usage_log_repository = AIUsageLogRepository(db)
        self.quota_repository = AIQuotaRepository(db)
        self.user_repository = UserRepository(db)
        self.project_repository = ProjectRepository(db)
        self.credit_service = CreditService(db)  # ✅ 注入 Service

结论: 完全符合


2.3 事务管理

规范要求: 使用 async with self.db.begin() 确保原子性

实现检查:

# server/app/services/ai_service.py
async with self.db.begin():  # ✅ 使用事务
    # 预扣积分
    consumption_log = await self.credit_service.consume_credits(...)
    
    # 创建任务
    job = await self.job_repository.create(...)
    
    # 关联
    consumption_log.ai_job_id = UUID(job.ai_job_id)
    consumption_log.task_id = str(job.ai_job_id)
    await self.db.flush()
# ✅ 提交事务(失败自动回滚)

结论: 完全符合


2.4 类型提示

规范要求: 完整的 Python 类型提示

实现检查:

# server/app/services/ai_service.py
async def generate_image(
    self,
    user_id: str,  # ✅ 类型提示
    prompt: str,
    model: Optional[str] = None,  # ✅ Optional 类型
    width: int = 1024,
    height: int = 1024,
    style: Optional[str] = None,
    project_id: Optional[str] = None,
    storyboard_id: Optional[str] = None,
    **kwargs
) -> Dict[str, Any]:  # ✅ 返回类型
    """生成图片(异步)- 完整集成 Credit Service"""

结论: 完全符合


3. 日志规范

3.1 日志格式化

规范要求: 使用 %-formatting 格式化日志消息(不使用 f-string)

实现检查:

# server/app/services/ai_service.py
# ✅ 正确:使用 %-formatting
logger.info("图片生成任务已创建: job_id=%s, user_id=%s, credits=%s", job.ai_job_id, user_id, credits_needed)
logger.warning("用户 %s 积分不足: %s", user_id, str(e))
logger.error("退还积分失败: job_id=%s", job_id, exc_info=True)

修复记录:

结论: 完全符合


3.2 异常日志

规范要求: 异常日志使用 exc_info=True

实现检查:

# server/app/services/ai_service.py
# ✅ 正确:所有异常日志都包含 exc_info=True
except Exception as e:
    logger.error("退还积分失败: job_id=%s", job.ai_job_id, exc_info=True)

修复记录:

结论: 完全符合


3.3 日志消息语言

规范要求: 日志消息使用中文

实现检查:

# server/app/services/ai_service.py
logger.info("图片生成任务已创建: ...")  # ✅ 中文
logger.warning("用户积分不足: ...")  # ✅ 中文
logger.error("退还积分失败: ...")  # ✅ 中文

结论: 完全符合


4. API 设计规范

4.1 统一响应格式

规范要求: 使用统一的 API 响应格式

文档检查:

//  成功响应
{
  "code": 200,
  "message": "Success",
  "data": { ... }
}

//  错误响应
{
  "code": 400,
  "message": "参数验证失败: prompt 不能为空",
  "data": null
}

结论: 完全符合


4.2 错误码设计

规范要求: 使用标准 HTTP 状态码

文档检查:

  • 200: 成功
  • 400: 参数错误
  • 402: 积分不足
  • 404: 资源不存在
  • 429: 配额超限
  • 500: 服务器错误

结论: 完全符合


5. 测试规范

5.1 测试目录结构

规范要求: 单元测试和集成测试分离

实现检查:

server/tests/
├── unit/
│   ├── repositories/
│   │   └── test_ai_job_repository.py  # ✅ Repository 单元测试
│   └── services/
│       └── test_ai_service_monitoring.py  # ✅ Service 单元测试
└── integration/
    └── test_ai_task_monitoring.py  # ✅ 集成测试

结论: 完全符合


5.2 测试覆盖率

规范要求: 核心功能需要测试覆盖

实现检查:

  • Repository 层:6/6 测试通过
  • Service 层:9/9 测试通过
  • 集成测试:6/6 测试通过
  • 总计:21/21 测试通过

结论: 完全符合


6. 文档规范

6.1 Changelog 创建

规范要求: 重大功能需要创建 Changelog

实现检查:

  • 2026-01-29-ai-service-complete-implementation.md
  • 2026-01-29-ai-service-credit-integration.md
  • 2026-01-29-ai-tasks-implementation.md
  • 2026-01-29-ai-task-monitoring.md
  • 2026-01-29-ai-service-test-suite-complete.md

结论: 完全符合


未实现功能清单

1. API 层

文档描述: 完整的 REST API 端点定义

实现状态: 已实现(2026-01-29)

涉及文件:

  • server/app/api/v1/ai.py(已实现,13 个端点)
  • server/app/schemas/ai.py(已完整定义)

实现文档: AI API 实现

优先级: 高 → 已完成


2. 真实 AI Provider

文档描述: 集成 OpenAI、Stability AI、Runway 等真实 AI 提供商

实现状态: 仅实现 MockAIProvider

涉及文件:

  • server/app/services/ai_providers/openai.py(不存在)
  • server/app/services/ai_providers/stability.py(不存在)
  • server/app/services/ai_providers/runway.py(不存在)

优先级: 中


3. 剧本解析功能

文档描述: AI 自动解析剧本,提取角色、场景、道具、分镜

实现状态: 未实现

涉及文件:

  • server/app/services/screenplay_parse_service.py(不存在)
  • 需要集成 Screenplay Service、Storyboard Service、Screenplay Tag Service

优先级: 中


4. Webhook 通知

文档描述: 任务完成时通知用户

实现状态: 未实现

涉及文件:

  • server/app/services/webhook_service.py(不存在)

优先级: 低


5. 批量任务

文档描述: 支持批量提交和处理

实现状态: 未实现

涉及文件:

  • server/app/services/ai_service.py(需要扩展)

优先级: 低


已完成优化

1. 日志格式化修复

状态: 已完成(2026-01-29)

修复内容:

影响范围: server/app/services/ai_service.py


2. 异常日志增强

状态: 已完成(2026-01-29)

修复内容:

影响范围: server/app/services/ai_service.py


待优化项

3. 文档字段名称统一 📝

问题: 文档中使用 metadata,实现中使用 extra_metadata

修复方案: 更新文档,统一使用 extra_metadata

影响范围: docs/requirements/backend/04-services/ai/ai-service.md

优先级: 低


4. 枚举验证方法优化 🔧

问题: 文档中定义了枚举验证方法,但实现中未使用

修复方案: 在 Service 层添加枚举验证

影响范围: server/app/services/ai_service.py

优先级: 低


5. Repository exists() 方法统一 🔧

问题: 部分 Repository 缺少 exists() 方法

修复方案: 确保所有 Repository 都实现 exists() 方法

影响范围: server/app/repositories/

优先级: 中


总结

符合性评分

类别 符合项 总项 符合率 状态
数据库设计 5/5 5 100%
代码规范 4/4 4 100%
日志规范 3/3 3 100% 已修复
API 设计 2/2 2 100%
测试规范 2/2 2 100%
文档规范 1/1 1 100%
总计 17/17 17 100%

关键发现

优势:

  1. 数据库设计完全符合规范(TIMESTAMPTZ、JSONB、SMALLINT、无外键)
  2. 代码架构清晰(异步、依赖注入、事务管理)
  3. 测试覆盖率高(21/21 通过)
  4. 文档完整详细

⚠️ 待实现:

  1. API 层未实现
  2. 真实 AI Provider 未实现

已修复:

  1. 日志格式化不符合规范(使用 f-string) → 已修复(2026-01-29)
  2. 部分异常日志缺少 exc_info=True → 已修复(2026-01-29)

下一步行动

立即实现(高优先级):

  1. 修复日志格式化(使用 %-formatting) 已完成(2026-01-29)
  2. 实现 API 层

短期优化(1-2 周):

  1. 增强异常日志(添加 exc_info=True 已完成(2026-01-29)
  2. 统一 Repository exists() 方法
  3. 集成真实 AI Provider

中期优化(1-2 月):

  1. 实现剧本解析功能
  2. 实现 Webhook 通知
  3. 实现批量任务

检查人: Kiro AI Assistant
检查日期: 2026-01-29
文档版本: v1.0