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.
19 KiB
19 KiB
Changelog: 发消息支持可选 AI 生成
日期: 2026-02-13
版本: v1.0
类型: 架构优化 (API 简化)
影响范围: POST /api/v1/ai-conversations/{conversation_id}/messages
📋 概述
将发消息和触发 AI 生成合并为一步操作,简化前端调用流程。
Before (两步操作)
// 步骤 1: 发送消息
const message = await POST('/conversations/{id}/messages', {
content: '生成一个日落场景'
});
// 步骤 2: 触发生成
const generation = await POST('/conversations/{id}/generate', {
messageId: message.messageId,
generationType: 'image',
modelId: 'dall-e-3',
aiParams: { ... }
});
After (一步操作)
// 一步完成
const response = await POST('/conversations/{id}/messages', {
content: '生成一个日落场景',
generate: { // ✅ 可选:触发 AI 生成
enabled: true,
generationType: 'image',
modelId: 'dall-e-3',
aiParams: { ... }
}
});
// response.data.message - 消息信息
// response.data.generation - AI 生成信息(如果触发)
🎯 改动目标
问题背景
原有流程需要两次 API 调用:
- ❌ 调用复杂:前端需要管理两次请求
- ❌ 状态同步:需要手动关联 messageId
- ❌ 错误处理:需要分别处理两个接口的错误
改进方案
将 AI 生成作为可选参数嵌入发消息接口:
- ✅ 一步完成:发消息 + 触发生成
- ✅ 向后兼容:
generate参数为可选 - ✅ 统一响应:返回消息 + 生成信息
🛠️ 技术实现
1. Schema 层改动
文件: server/app/schemas/ai_conversation_message.py
1.1 新增 GenerateConfig Schema
class GenerateConfig(BaseModel):
"""AI 生成配置(嵌入消息创建中)"""
model_config = ConfigDict(populate_by_name=True)
enabled: bool = Field(..., description="是否启用 AI 生成")
generation_type: str = Field(..., alias="generationType", description="生成类型(image/video)")
model_id: str = Field(..., alias="modelId", description="模型 ID")
ai_params: Dict[str, Any] = Field(..., alias="aiParams", description="AI 模型参数")
business_params: Optional[Dict[str, Any]] = Field(None, alias="businessParams", description="业务参数(可选)")
@field_validator('generation_type')
@classmethod
def validate_generation_type(cls, v: str) -> str:
"""验证生成类型"""
if v not in ['image', 'video']:
raise ValueError(f"不支持的生成类型: {v}")
return v
说明:
enabled: 是否启用 AI 生成(布尔值)generationType: 生成类型(image或video)modelId: 模型 IDaiParams: AI 模型参数(与 RFC 144 统一)businessParams: 业务参数(可选,通用字典)
1.2 更新 AIConversationMessageCreate Schema
class AIConversationMessageCreate(BaseModel):
"""创建消息请求(支持可选的 AI 生成)"""
content: str = Field(..., description="消息内容", min_length=1, max_length=10000)
generate: Optional[GenerateConfig] = Field(None, description="AI 生成配置(可选,会保存到 meta_data)") # ✅ 新增
model_config = ConfigDict(populate_by_name=True)
变化:
- 新增
generate字段(可选) - 类型为
GenerateConfigPydantic 对象 - ❌ 移除
meta_data字段(generate配置会自动保存到数据库meta_data)
1.3 新增 GenerationInfo Schema
class GenerationInfo(BaseModel):
"""AI 生成信息(嵌入消息响应中)"""
job_id: str = Field(..., alias="jobId", description="任务 ID")
task_id: str = Field(..., alias="taskId", description="Celery 任务 ID")
status: str = Field(..., description="任务状态")
estimated_credits: int = Field(..., alias="estimatedCredits", description="预估积分消耗")
reference_images_count: int = Field(0, alias="referenceImagesCount", description="参考图数量")
model_config = ConfigDict(populate_by_name=True)
1.4 更新 AIConversationMessageResponse Schema
class AIConversationMessageResponse(BaseModel):
"""消息响应(可能包含 AI 生成信息)"""
message_id: UUID = Field(..., description="消息 ID")
conversation_id: UUID = Field(..., description="对话会话 ID")
user_id: UUID = Field(..., description="用户 ID")
ai_job_id: Optional[UUID] = Field(None, description="关联的 AI 任务 ID")
role: int = Field(..., description="消息角色(1=用户 2=AI 3=系统)")
content: str = Field(..., description="消息内容")
meta_data: Dict[str, Any] = Field(default_factory=dict, description="额外元数据")
order_index: int = Field(..., description="消息顺序")
created_at: datetime = Field(..., description="创建时间")
updated_at: datetime = Field(..., description="更新时间")
# 新增:AI 生成信息(如果触发了生成)
generation: Optional[GenerationInfo] = Field(None, description="AI 生成信息(如果触发)") # ✅ 新增
model_config = ConfigDict(
from_attributes=True,
populate_by_name=True,
alias_generator=to_camel
)
变化:
- 新增
generation字段(可选) - 类型为
GenerationInfoPydantic 对象
2. Service 层改动
文件: server/app/services/ai_conversation_service.py
2.1 更新 send_message 方法签名
async def send_message(
self,
conversation_id: UUID,
user_id: UUID,
content: str,
generate_config: Optional[Dict[str, Any]] = None # ✅ 新增参数
) -> Dict[str, Any]:
"""发送用户消息(支持自动解析提及 + 可选触发 AI 生成)
Args:
conversation_id: 对话会话 ID
user_id: 用户 ID
content: 消息内容(可能包含提及标记)
generate_config: AI 生成配置(可选,会保存到 meta_data)
- enabled: 是否启用 AI 生成
- generation_type: 生成类型(image/video)
- model_id: 模型 ID
- ai_params: AI 模型参数
- business_params: 业务参数(可选)
Returns:
Dict 包含消息信息 + AI 生成信息(如果触发)
"""
2.2 构建 meta_data 逻辑(优化版)
# 解析提及标记(如果有)
mentions, reference_images = await self._parse_mentions(
content, user_id, conversation_id
)
# 构建 meta_data
message_meta_data = {}
# 如果提供了 generate_config
if generate_config:
# 合并提及信息到 business_params
business_params = generate_config.get('business_params') or {}
if mentions:
business_params['mentions'] = mentions
business_params['reference_images'] = reference_images
logger.info("解析到 %d 个提及,已添加到 business_params", len(mentions))
# 更新 generate_config
generate_config['business_params'] = business_params
# 保存 generate 配置到 meta_data
message_meta_data['generate'] = generate_config
logger.info("保存 generate 配置到 meta_data")
elif mentions:
# 如果没有 generate_config,但有提及,仍然保存提及信息
message_meta_data['mentions'] = mentions
message_meta_data['reference_images'] = reference_images
logger.info("解析到 %d 个提及", len(mentions))
关键设计:
- ✅ 提及信息归类到
business_params:当有generate时,mentions和reference_images保存在business_params中 - ✅ 向后兼容:如果仅有提及无
generate,提及信息仍然保存在meta_data顶层 - ✅
meta_data结构(有 generate):{ "generate": { "enabled": true, "generation_type": "image", "model_id": "dall-e-3", "ai_params": {...}, "business_params": { "mentions": [...], // ✅ 提及信息 "reference_images": [...], // ✅ 参考图列表 "customField": "value" // 其他业务参数 } } } - ✅
meta_data结构(仅提及):{ "mentions": [...], // ✅ 向后兼容 "reference_images": [...] }
2.3 在方法结尾添加生成逻辑
logger.info("用户消息已创建: message_id=%s", message.message_id)
# 准备返回结果
result = {
'message': message,
'generation': None # 默认无生成信息
}
# 如果提供了 generate_config 且启用了生成
if generate_config and generate_config.get('enabled'):
logger.info("触发 AI 生成: message_id=%s", message.message_id)
try:
# 调用 trigger_ai_generation
generation_result = await self.trigger_ai_generation(
conversation_id=conversation_id,
user_id=user_id,
message_id=message.message_id,
generation_type=generate_config['generation_type'],
model_id=generate_config['model_id'],
ai_params=generate_config['ai_params'],
business_params=generate_config.get('business_params')
)
result['generation'] = generation_result
logger.info("AI 生成已触发: job_id=%s", generation_result.get('jobId'))
except Exception as gen_error:
logger.error(
"触发 AI 生成失败: message_id=%s, 错误=%s",
message.message_id, str(gen_error),
exc_info=True
)
# 不抛出异常,允许消息创建成功
return result
关键设计:
- ✅ 容错处理:生成失败不影响消息创建
- ✅ 条件触发:只有
enabled=true时才触发 - ✅ 复用逻辑:调用已有的
trigger_ai_generation方法 - ✅ generate_config 已保存:此时
generate_config已在前面保存到message.meta_data['generate']
3. API Router 改动
文件: server/app/api/v1/ai_conversations.py
@router.post("/{conversation_id}/messages", response_model=SuccessResponse[AIConversationMessageResponse], summary="发送消息")
async def send_message(
conversation_id: UUID,
request: MessageCreateRequest,
current_user: User = Depends(get_current_user),
db: AsyncSession = Depends(get_db)
):
"""发送用户消息(支持可选的 AI 生成)
支持 @ 提及功能:
- 自动解析消息中的提及标记
- 验证所有提及的资源
- 构建 meta_data(mentions + reference_images)
支持可选 AI 生成(一步完成):
- 提供 `generate` 参数可在发消息后自动触发 AI 生成
- `generate` 配置会保存到消息的 `meta_data['generate']` 中
- 无需单独调用 `/generate` 接口
示例请求 1(仅发消息):
```json
{
"content": "帮我生成一个日落场景"
}
```
示例请求 2(发消息 + 触发生成):
```json
{
"content": "生成一个日落场景",
"generate": {
"enabled": true,
"generationType": "image",
"modelId": "dall-e-3",
"aiParams": {
"resolution": "1024",
"aspectRatio": "1:1"
}
}
}
```
"""
service = AIConversationService(db)
# 提取 generate_config
generate_config = None
if request.generate:
generate_config = {
'enabled': request.generate.enabled,
'generation_type': request.generate.generation_type,
'model_id': request.generate.model_id,
'ai_params': request.generate.ai_params,
'business_params': request.generate.business_params
}
result = await service.send_message(
conversation_id=conversation_id,
user_id=current_user.user_id,
content=request.content,
generate_config=generate_config # ✅ 传递 generate_config(会保存到 meta_data)
)
# 构建响应
message = result['message']
generation = result.get('generation')
# 使用 Pydantic schema 验证并序列化消息
message_response = AIConversationMessageResponse.model_validate(message)
# 如果有生成信息,添加到响应中
if generation:
from app.schemas.ai_conversation_message import GenerationInfo
message_response.generation = GenerationInfo(
job_id=generation['jobId'],
task_id=generation['taskId'],
status=generation['status'],
estimated_credits=generation.get('estimatedCredits', 0),
reference_images_count=generation.get('referenceImagesCount', 0)
)
return SuccessResponse(data=message_response)
关键变化:
- 提取
request.generate转换为generate_config字典 - 传递给 Service 层(会自动保存到
meta_data['generate']) - 构建响应时,如果有生成信息,附加到
message_response.generation
📊 对比总结
API 调用对比
Before (两步操作)
// 步骤 1: POST /conversations/{id}/messages
{
"content": "生成一个日落场景"
}
// 响应 1
{
"data": {
"messageId": "xxx",
"content": "生成一个日落场景",
...
}
}
// 步骤 2: POST /conversations/{id}/generate
{
"messageId": "xxx",
"generationType": "image",
"modelId": "dall-e-3",
"aiParams": { ... }
}
// 响应 2
{
"data": {
"jobId": "yyy",
"taskId": "zzz",
"status": "pending"
}
}
After (一步操作)
// 一步: POST /conversations/{id}/messages
{
"content": "生成一个日落场景",
"generate": { // ✅ 可选
"enabled": true,
"generationType": "image",
"modelId": "dall-e-3",
"aiParams": {
"resolution": "1024",
"aspectRatio": "1:1"
}
}
}
// 响应(合并)
{
"data": {
"messageId": "xxx",
"content": "生成一个日落场景",
"generation": { // ✅ 生成信息(如果触发)
"jobId": "yyy",
"taskId": "zzz",
"status": "pending",
"estimatedCredits": 10
},
...
}
}
🎯 改进效果
1. 简化前端调用
// Before (两步)
const message = await sendMessage({ content });
const generation = await triggerGeneration({ messageId, ... });
// After (一步)
const response = await sendMessage({
content,
generate: { enabled: true, ... }
});
2. 统一错误处理
try {
const response = await sendMessage({ content, generate });
// 一次处理消息 + 生成结果
} catch (error) {
// 统一错误处理
}
3. 自动关联
- ✅ Service 层自动关联
messageId - ✅ 无需前端手动管理 ID
4. 向后兼容
// 仅发消息(原有功能)
{
"content": "这是一条消息"
}
// 发消息 + 生成(新功能)
{
"content": "生成一个日落场景",
"generate": { ... }
}
🧪 验证测试
测试场景 1: 仅发消息(向后兼容)
curl -X POST http://localhost:8000/api/v1/ai-conversations/{id}/messages \
-H "Authorization: Bearer xxx" \
-H "Content-Type: application/json" \
-d '{
"content": "这是一条普通消息"
}'
预期结果:
{
"data": {
"messageId": "xxx",
"content": "这是一条普通消息",
"generation": null // ✅ 无生成信息
}
}
测试场景 2: 发消息 + 触发生成
curl -X POST http://localhost:8000/api/v1/ai-conversations/{id}/messages \
-H "Authorization: Bearer xxx" \
-H "Content-Type: application/json" \
-d '{
"content": "生成一个日落场景",
"generate": {
"enabled": true,
"generationType": "image",
"modelId": "dall-e-3",
"aiParams": {
"resolution": "1024",
"aspectRatio": "1:1"
}
}
}'
预期结果:
{
"data": {
"messageId": "xxx",
"content": "生成一个日落场景",
"generation": { // ✅ 包含生成信息
"jobId": "yyy",
"taskId": "zzz",
"status": "pending",
"estimatedCredits": 10,
"referenceImagesCount": 0
}
}
}
测试场景 3: 生成失败但消息成功
模拟生成失败(如模型不可用):
预期行为:
- ✅ 消息创建成功
- ✅
generation字段为null - ✅ 后台日志记录生成失败
📝 后续工作
优先级 1: 前端适配(高)
更新前端调用方式:
// API 类型定义
interface SendMessageRequest {
content: string;
metaData?: Record<string, any>;
generate?: {
enabled: boolean;
generationType: 'image' | 'video';
modelId: string;
aiParams: Record<string, any>;
businessParams?: Record<string, any>;
};
}
// 使用示例
const sendMessageWithGeneration = async () => {
const response = await api.post(`/conversations/${id}/messages`, {
content: '生成一个日落场景',
generate: {
enabled: true,
generationType: 'image',
modelId: 'dall-e-3',
aiParams: {
resolution: '1024',
aspectRatio: '1:1'
}
}
});
// response.data.message - 消息信息
// response.data.generation - AI 生成信息(可能为 null)
};
优先级 2: 废弃旧接口(低)
考虑废弃单独的 POST /{conversation_id}/generate 接口:
- ⚠️ 标记为
@deprecated - ⚠️ 在文档中说明使用新方式
- ⚠️ 保留向后兼容(可选)
优先级 3: 监控和日志(中)
增加指标监控:
- 📊 发消息并触发生成的比例
- 📊 生成失败但消息成功的次数
- 📊 平均响应时间
🔗 相关文档
- Conversation Params Separation
- Parameter Mapper Refactor
- RFC 144: AI Models Capability Configuration
📌 影响范围
破坏性变更 (Breaking Changes)
- ✅ 无破坏性变更:
generate参数为可选,完全向后兼容
建议迁移策略
渐进式迁移(推荐)
- Phase 1:前端继续使用两步操作(无需修改)
- Phase 2:新功能使用一步操作
- Phase 3:逐步迁移旧代码到新方式
直接迁移
前端直接适配新接口,简化代码逻辑。
✅ 验证清单
- Schema 定义(
GenerateConfig,GenerationInfo, 更新请求/响应 Schema) - Service 层方法签名更新
- Service 层生成触发逻辑
- API Router 更新
- Python 语法检查通过
- Docker 服务重启成功
- 前端适配新格式
- 端到端测试
- 监控指标添加
最新更新: 2026-02-13
版本: v1.0
状态: ✅ 已完成(待前端适配)