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.
 

12 KiB

AI 对话系统完整实现

日期:2026-02-03
类型:功能实现
影响范围:后端服务、数据库
符合规范:jointo-tech-stack v1.0


概述

完整实现了 AI 对话系统的三个核心功能模块:

  1. AI 提示词系统服务 - 管理系统级 AI 提示词模板
  2. AI 对话记录服务 - 管理用户与 AI 的对话历史
  3. @ 提及与参考图系统 - 支持在对话中引用资源作为参考图

实现内容

1. AI 提示词系统服务

文件server/app/services/ai_prompt_system_service.py

功能

  • 提示词 CRUD 操作(创建、查询、更新、删除)
  • 提示词版本管理
  • Skills 配置管理(支持多个 skill 文件)
  • 默认提示词管理(每种类型只能有一个默认)
  • 提示词列表查询(支持类型、状态、名称过滤)

核心方法

- create_prompt()          # 创建提示词
- get_prompt_by_id()       # 获取提示词详情
- get_default_prompt()     # 获取默认提示词
- list_prompts()           # 获取提示词列表
- update_prompt()          # 更新提示词
- delete_prompt()          # 删除提示词(软删除)
- set_default()            # 设置为默认提示词

技术规范

  • UUID v7 主键(应用层生成)
  • %-formatting 日志
  • exc_info=True 错误日志
  • 应用层保证引用完整性

2. AI 对话记录服务

文件server/app/services/ai_conversation_service.py

功能

  • 对话会话管理(创建、查询、列表)
  • 消息管理(发送、列表)
  • 多态关联 + 标签系统(支持不同类型的 AI 生成任务)
  • @ 提及功能(解析、验证、构建)
  • AI 生成触发(支持参考图)

核心设计

多态关联模式

target_type: int  # 目标类型(分镜/角色/场景/道具/资源/音效/配音)
target_id: UUID   # 目标对象 ID
tag_id: UUID      # 标签 ID(可选,用于区分变体)
media_type: int   # 媒体类型(图片/视频/音频/3D模型/文本)

隔离策略

  • 类型隔离:分镜图对话 ≠ 分镜视频对话
  • 对象隔离:分镜A的对话 ≠ 分镜B的对话
  • 变体隔离:角色-张三-少年装扮 ≠ 角色-张三-成年装扮
  • 用户隔离:用户A的对话 ≠ 用户B的对话

核心方法

# 对话会话管理
- create_conversation()    # 创建对话会话
- get_conversation()       # 获取对话详情
- list_conversations()     # 获取对话列表

# 消息管理
- send_message()           # 发送消息(支持自动解析提及)
- list_messages()          # 获取消息列表

# @ 提及功能
- get_mentionable_resources()  # 获取可提及的资源列表
- _parse_mentions()            # 解析消息中的提及标记
- _validate_and_build_mention() # 验证并构建提及对象

# AI 生成触发
- trigger_ai_generation()  # 触发 AI 生成任务(支持参考图)

3. @ 提及与参考图系统

核心原则

前端职责

  • 提供 @ 自动补全,帮助用户快速输入
  • 插入标准格式的提及标记到文本
  • 高亮显示提及标记,提供视觉反馈
  • 只发送文本,不发送 mentions 数组

后端职责

  • 解析文本中的提及标记
  • 验证所有提及的资源
  • 构建 metadata(mentions + reference_images)
  • 存储消息到数据库

提及标记格式

@[显示名称](类型:元素ID:标签ID:资源ID)

示例

生成一张 @[张三-少年](character:019d1234...:019d1234...:019d1234...) 在 @[咖啡厅-白天](scene:019d1234...:019d1234...:019d1234...) 喝咖啡的图片

数据流程

  1. 用户输入 @ → 前端调用 API 获取可提及的资源列表
  2. 用户选择资源 → 前端插入标准格式的提及标记
  3. 用户发送消息 → 后端解析提及标记并验证资源
  4. 后端构建 metadata → 存储 mentions 和 reference_images
  5. 用户触发生成 → 后端提取参考图 URL 传递给 AI

4. 数据库迁移

文件server/alembic/versions/20260203_1600_create_ai_conversations_tables.py

创建的表

ai_conversations(AI 对话会话表)

CREATE TABLE ai_conversations (
    conversation_id UUID PRIMARY KEY,
    user_id UUID NOT NULL,
    project_id UUID,
    target_type SMALLINT NOT NULL,
    target_id UUID NOT NULL,
    tag_id UUID,
    media_type SMALLINT NOT NULL,
    title TEXT,
    status SMALLINT NOT NULL DEFAULT 1,
    message_count INTEGER NOT NULL DEFAULT 0,
    last_message_at TIMESTAMPTZ,
    metadata JSONB NOT NULL DEFAULT '{}',
    created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
    updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);

索引

  • idx_ai_conversations_user_id - 用户 ID
  • idx_ai_conversations_project_id - 项目 ID(部分索引)
  • idx_ai_conversations_target - 目标类型 + 目标 ID
  • idx_ai_conversations_target_tag - 目标类型 + 目标 ID + 标签 ID
  • idx_ai_conversations_tag_id - 标签 ID(部分索引)
  • idx_ai_conversations_media_type - 媒体类型
  • idx_ai_conversations_status - 会话状态
  • idx_ai_conversations_created_at - 创建时间
  • idx_ai_conversations_last_message_at - 最后消息时间(部分索引)
  • idx_ai_conversations_user_status - 用户 ID + 状态
  • idx_ai_conversations_user_target_tag_media - 复合索引
  • idx_ai_conversations_metadata_gin - JSONB GIN 索引

唯一约束

CREATE UNIQUE INDEX idx_ai_conversations_unique_active 
ON ai_conversations (user_id, target_type, target_id, tag_id, media_type) 
NULLS NOT DISTINCT
WHERE status = 1;

ai_conversation_messages(AI 对话消息表)

CREATE TABLE ai_conversation_messages (
    message_id UUID PRIMARY KEY,
    conversation_id UUID NOT NULL,
    user_id UUID NOT NULL,
    ai_job_id UUID,
    role SMALLINT NOT NULL,
    content TEXT NOT NULL,
    metadata JSONB NOT NULL DEFAULT '{}',
    order_index INTEGER NOT NULL,
    created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
    updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
);

索引

  • idx_ai_conversation_messages_conversation_id - 对话会话 ID
  • idx_ai_conversation_messages_user_id - 用户 ID
  • idx_ai_conversation_messages_ai_job_id - AI 任务 ID(部分索引)
  • idx_ai_conversation_messages_role - 消息角色
  • idx_ai_conversation_messages_created_at - 创建时间
  • idx_ai_conversation_messages_conversation_order - 对话 ID + 顺序
  • idx_ai_conversation_messages_metadata_gin - JSONB GIN 索引
  • idx_ai_conversation_messages_content_gin - 全文搜索索引

触发器

  • update_ai_conversations_updated_at - 自动更新 updated_at
  • update_ai_conversation_messages_updated_at - 自动更新 updated_at
  • update_conversation_stats_trigger - 自动更新会话统计(message_count、last_message_at)

技术栈合规性

符合 jointo-tech-stack 规范

  1. UUID v7 主键

    • 所有主键使用 UUID v7(应用层生成)
    • 使用 uuid7() 函数生成
  2. TIMESTAMPTZ 时间字段

    • 所有时间字段使用 TIMESTAMPTZ 类型
    • 符合 ADR 006 规范
  3. SMALLINT 枚举类型

    • 所有枚举字段使用 SMALLINT 存储
    • Python 使用 IntEnum 定义枚举
  4. 无物理外键约束

    • 数据库层不创建 FOREIGN KEY 约束
    • 应用层保证引用完整性
  5. 日志格式

    • 使用 %-formatting 格式化日志
    • 错误日志包含 exc_info=True
  6. 异步编程

    • 所有数据库操作使用 async/await
    • 使用 AsyncSession

使用场景

场景1:分镜基础图片生成对话(无标签)

# 创建对话会话
conversation = await ai_conversation_service.create_conversation(
    user_id=user_id,
    target_type=TargetType.STORYBOARD,
    target_id=storyboard_id,
    tag_id=None,  # 无标签(基础图片)
    media_type=MediaType.IMAGE,
    project_id=project_id
)

场景2:分镜正面角度图片生成对话(有标签)

# 创建对话会话
conversation = await ai_conversation_service.create_conversation(
    user_id=user_id,
    target_type=TargetType.STORYBOARD,
    target_id=storyboard_id,
    tag_id=angle_tag_id,  # 正面角度标签
    media_type=MediaType.IMAGE,
    project_id=project_id
)

场景3:角色少年装扮图片生成对话

# 创建对话会话
conversation = await ai_conversation_service.create_conversation(
    user_id=user_id,
    target_type=TargetType.CHARACTER,
    target_id=character_id,
    tag_id=costume_tag_id,  # 少年装扮标签
    media_type=MediaType.IMAGE,
    project_id=project_id
)

场景4:发送带提及的消息

# 发送消息(包含提及标记)
message = await ai_conversation_service.send_message(
    conversation_id=conversation_id,
    user_id=user_id,
    content="生成一张 @[张三-少年](character:019d1234...:019d1234...:019d1234...) 在 @[咖啡厅-白天](scene:019d1234...:019d1234...:019d1234...) 喝咖啡的图片"
)

# 后端自动解析提及标记,构建 metadata
# message.metadata = {
#     'mentions': [...],
#     'reference_images': [url1, url2]
# }

场景5:触发 AI 生成(使用参考图)

# 触发 AI 生成
result = await ai_conversation_service.trigger_ai_generation(
    conversation_id=conversation_id,
    user_id=user_id,
    message_id=message_id,
    generation_type='image',
    params={
        'prompt': '生成一张张三在咖啡厅喝咖啡的图片',
        'model': 'stable_diffusion',
        'width': 1024,
        'height': 1024
    }
)

# 后端自动从消息的 metadata 中提取参考图 URL
# 传递给 AI Service 进行生成

相关文档


后续工作

待实现功能

  1. AI Service 集成

    • 实现 AI Service 的 generate_image() 方法
    • 支持参考图传递给 AI 提供商
    • 实现 Stable Diffusion ControlNet 集成
    • 实现 Midjourney --cref 参数集成
  2. 前端实现

    • 实现 MentionInput 组件
    • 实现 MentionAutocomplete 组件
    • 实现提及标记的高亮显示
    • 实现键盘交互(↑↓ 选择、Enter 确认、ESC 取消)
  3. API 路由

    • 实现 AI 对话相关的 API 路由
    • 实现 AI 提示词相关的 API 路由(管理员专用)
  4. 测试

    • 编写单元测试
    • 编写集成测试
    • 编写 E2E 测试

优化建议

  1. 性能优化

    • 资源列表缓存(使用 Redis)
    • 图片懒加载
    • 搜索防抖
    • 虚拟滚动
  2. 安全优化

    • 权限验证增强
    • XSS 防护
    • 参考图 URL 验证
  3. 用户体验优化

    • 实时反馈
    • 错误提示优化
    • 加载状态优化

总结

本次实现完成了 AI 对话系统的三个核心功能模块,包括:

  1. AI 提示词系统服务(完整实现)
  2. AI 对话记录服务(完整实现)
  3. @ 提及与参考图系统(完整实现)
  4. 数据库迁移(完整实现)

所有实现均符合 jointo-tech-stack 规范,包括:

  • UUID v7 主键
  • TIMESTAMPTZ 时间字段
  • SMALLINT 枚举类型
  • 无物理外键约束
  • %-formatting 日志
  • 异步编程

系统已具备完整的对话管理、提及解析、参考图提取功能,为后续的 AI Service 集成和前端实现奠定了坚实的基础。


文档版本:v1.0
创建日期:2026-02-03
作者:Jointo AI Team