ai-chatbot/docs/smart-auto-implementation-guide.md
Your Name 8763e8d53f
Some checks failed
Lint / build (20) (push) Has been cancelled
Playwright Tests / test (push) Has been cancelled
feat: 智能图片编辑系统 - 意图分析、提示词优化、模型路由
新增智能自动模式功能:
- smart-analyzer.ts: 智能意图分析器,识别抠图/换背景/增强等8种子意图
- prompt-optimizer.ts: 提示词优化器,将简单输入转为专业提示词
- model-router.ts: 智能模型路由器,根据意图选择最佳模型
- 修改route.ts集成新模块,替换原有关键词匹配逻辑

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-01-31 23:15:11 +08:00

24 KiB
Raw Permalink Blame History

智能图片编辑 - 实施开发指南

版本: v1.0 日期: 2025-01-31 目标: 在聊天对话框中实现智能图片编辑功能


一、核心流程

用户在对话框中发送 [图片 + 文字]
           │
           ▼
┌──────────────────────────────────────────────────────────────┐
│  POST /api/chat                                              │
│  ┌─────────────────────────────────────────────────────────┐ │
│  │ 1. 提取用户消息                                          │ │
│  │    - 图片 URL (from message.parts where type='file')    │ │
│  │    - 文字内容 (from message.parts where type='text')    │ │
│  └─────────────────────────────────────────────────────────┘ │
│                          │                                   │
│                          ▼                                   │
│  ┌─────────────────────────────────────────────────────────┐ │
│  │ 2. 智能意图分析 (如果 modelId === 'auto')                 │ │
│  │    - 调用 Qwen3 VL 分析用户意图                          │ │
│  │    - 返回: intent, subIntent, confidence                │ │
│  └─────────────────────────────────────────────────────────┘ │
│                          │                                   │
│                          ▼                                   │
│  ┌─────────────────────────────────────────────────────────┐ │
│  │ 3. 提示词优化 (仅图片编辑类意图)                          │ │
│  │    - 根据子意图选择模板                                   │ │
│  │    - 填充用户参数,生成专业提示词                         │ │
│  │    - 添加负面提示词                                      │ │
│  └─────────────────────────────────────────────────────────┘ │
│                          │                                   │
│                          ▼                                   │
│  ┌─────────────────────────────────────────────────────────┐ │
│  │ 4. 模型路由                                              │ │
│  │    - 根据意图选择最佳模型                                 │ │
│  │    - 图片编辑 → alibaba-image                           │ │
│  │    - 视觉理解 → alibaba (Qwen3 VL)                      │ │
│  └─────────────────────────────────────────────────────────┘ │
│                          │                                   │
│                          ▼                                   │
│  ┌─────────────────────────────────────────────────────────┐ │
│  │ 5. 调用对应模型生成                                      │ │
│  │    - 使用优化后的提示词                                   │ │
│  │    - 传入用户图片                                        │ │
│  └─────────────────────────────────────────────────────────┘ │
│                          │                                   │
│                          ▼                                   │
│  ┌─────────────────────────────────────────────────────────┐ │
│  │ 6. 返回结果到对话框                                      │ │
│  │    - 编辑后的图片 (Markdown格式)                         │ │
│  │    - 保存到数据库                                        │ │
│  └─────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────┘

二、需要修改/创建的文件

2.1 新建文件

文件路径 作用
lib/ai/smart-analyzer.ts 智能意图分析器
lib/ai/prompt-optimizer.ts 提示词优化器
lib/ai/model-router.ts 智能模型路由器

2.2 修改文件

文件路径 修改内容
app/(chat)/api/chat/route.ts Auto Mode 逻辑替换

三、详细代码实现

3.1 创建 lib/ai/smart-analyzer.ts

/**
 * 智能意图分析器
 * 使用 Qwen3 VL 分析用户输入,识别图片编辑意图
 */

import { generateText } from "ai";
import { getLanguageModelById } from "./dynamic-provider";
import { getEnabledAiModelsWithProvider } from "@/lib/db/queries";

// 分析结果类型
export interface AnalysisResult {
  intent: "image_edit" | "vision" | "image_gen" | "video_gen" | "chat";
  subIntent?: string;
  confidence: number;
  optimizedPrompt?: string;
  negativePrompt?: string;
  suggestedModel?: string;
  needsClarification?: boolean;
  clarifyingQuestions?: string[];
}

// 系统提示词 - 针对图片编辑场景优化
const ANALYZER_SYSTEM_PROMPT = `你是一个专业的图片编辑意图分析专家。请分析用户的请求,判断其意图类型。

## 意图分类(按优先级)

### 1. image_edit - 图片编辑(最高优先级,需要用户上传了图片)
子意图:
- remove_background: 抠图、去背景、透明背景、去除背景
- replace_background: 换背景、改背景、白底、场景替换、背景换成
- enhance: 变清晰、高清、锐化、降噪、提升质量、修复
- extend: 扩展、拓展、延伸、outpainting、扩图
- inpaint: 去除XX、消除、擦掉、修改XX部分、局部修改、P掉
- style_transfer: 风格化、卡通化、动漫风、油画风、改风格
- resize: 缩放、放大、缩小、调整尺寸、裁剪
- color_adjust: 调色、调整颜色、亮度、对比度、饱和度

### 2. vision - 图片理解(需要用户上传了图片)
触发词:看、识别、分析、描述、这是什么、有什么

### 3. image_gen - 图片生成(不需要上传图片)
触发词:画、绘制、生成图片、创建、设计

### 4. video_gen - 视频生成
触发词:视频、动画、动起来

### 5. chat - 普通对话(默认)

## 输出格式(严格JSON)
{
  "intent": "image_edit",
  "subIntent": "replace_background",
  "confidence": 0.95,
  "optimizedPrompt": "优化后的提示词",
  "negativePrompt": "需要避免的内容",
  "needsClarification": false,
  "clarifyingQuestions": []
}

## 特殊规则
1. 如果用户上传了图片且有编辑类关键词 → image_edit
2. 如果用户上传了图片但意图不明确 → needsClarification: true,并提供澄清问题
3. 如果用户要求编辑但没上传图片 → needsClarification: true,提示"请上传图片"`;

/**
 * 分析用户意图
 */
export async function analyzeIntent(params: {
  text: string;
  hasImage: boolean;
  imageUrls?: string[];
}): Promise<AnalysisResult> {
  const { text, hasImage, imageUrls } = params;

  // 获取千问3 VL 模型
  const allModels = await getEnabledAiModelsWithProvider();
  const qwenModel = allModels.find(
    (m) => m.provider.type === "alibaba" && m.model.supportsVision
  );

  // 如果没有可用的分析模型,使用回退逻辑
  if (!qwenModel) {
    console.log("[Smart Analyzer] No Qwen3 VL model found, using fallback");
    return fallbackKeywordAnalysis(text, hasImage);
  }

  try {
    const model = await getLanguageModelById(qwenModel.model.id);
    if (!model) {
      return fallbackKeywordAnalysis(text, hasImage);
    }

    // 构建用户消息
    const userMessage = hasImage
      ? `用户上传了图片,请求内容:"${text}"`
      : `用户请求(无图片):"${text}"`;

    console.log("[Smart Analyzer] Analyzing with Qwen3 VL:", userMessage);

    // 调用模型分析
    const { text: responseText } = await generateText({
      model,
      system: ANALYZER_SYSTEM_PROMPT,
      prompt: userMessage,
      temperature: 0.1, // 低温度保证稳定输出
      maxTokens: 500,
    });

    // 解析JSON响应
    const jsonMatch = responseText.match(/\{[\s\S]*\}/);
    if (jsonMatch) {
      const result = JSON.parse(jsonMatch[0]) as AnalysisResult;
      console.log("[Smart Analyzer] Analysis result:", result);
      return result;
    }
  } catch (error) {
    console.error("[Smart Analyzer] Error:", error);
  }

  // 出错时使用回退逻辑
  return fallbackKeywordAnalysis(text, hasImage);
}

/**
 * 回退方案:关键词匹配
 */
function fallbackKeywordAnalysis(
  text: string,
  hasImage: boolean
): AnalysisResult {
  const lowerText = text.toLowerCase();

  // 图片编辑关键词检测
  if (hasImage) {
    // 抠图/去背景
    if (/抠图|去背景|透明背景|去背|扣图/.test(lowerText)) {
      return {
        intent: "image_edit",
        subIntent: "remove_background",
        confidence: 0.9,
      };
    }

    // 换背景
    if (/换背景|白底|改背景|背景换成|纯色背景/.test(lowerText)) {
      return {
        intent: "image_edit",
        subIntent: "replace_background",
        confidence: 0.9,
      };
    }

    // 图片增强
    if (/变清晰|高清|锐化|降噪|提升质量|修复/.test(lowerText)) {
      return {
        intent: "image_edit",
        subIntent: "enhance",
        confidence: 0.9,
      };
    }

    // 图像拓展
    if (/扩展|拓展|延伸|扩图/.test(lowerText)) {
      return {
        intent: "image_edit",
        subIntent: "extend",
        confidence: 0.9,
      };
    }

    // 局部修改
    if (/去除|消除|擦掉|P掉|修改.*部分/.test(lowerText)) {
      return {
        intent: "image_edit",
        subIntent: "inpaint",
        confidence: 0.9,
      };
    }

    // 风格迁移
    if (/风格|卡通化|动漫风|油画风/.test(lowerText)) {
      return {
        intent: "image_edit",
        subIntent: "style_transfer",
        confidence: 0.9,
      };
    }

    // 视觉理解
    if (/看|识别|分析|描述|这是什么|有什么/.test(lowerText)) {
      return { intent: "vision", confidence: 0.8 };
    }

    // 有图但意图不明确
    return {
      intent: "image_edit",
      confidence: 0.5,
      needsClarification: true,
      clarifyingQuestions: [
        "您想对这张图片做什么处理?(抠图/换背景/变清晰/其他)",
      ],
    };
  }

  // 无图情况
  if (/画|绘制|生成图|创建.*图/.test(lowerText)) {
    return { intent: "image_gen", confidence: 0.8 };
  }

  if (/视频|动画|动起来/.test(lowerText)) {
    return { intent: "video_gen", confidence: 0.8 };
  }

  // 默认对话
  return { intent: "chat", confidence: 0.7 };
}

export { fallbackKeywordAnalysis };

3.2 创建 lib/ai/prompt-optimizer.ts

/**
 * 提示词优化器
 * 将用户简单输入转换为专业的图片编辑提示词
 */

// 优化结果类型
export interface OptimizeResult {
  originalPrompt: string;
  optimizedPrompt: string;
  negativePrompt: string;
}

// 图片编辑子意图的提示词模板
const EDIT_TEMPLATES: Record<
  string,
  {
    template: string;
    negative: string;
    extractors: Record<string, RegExp>;
  }
> = {
  remove_background: {
    template:
      "去除图片背景,保留主体完整,输出透明背景PNG格式,边缘处理平滑自然,保留细节(如发丝、毛发)",
    negative: "残留背景,毛边,边缘模糊,主体不完整,锯齿",
    extractors: {},
  },

  replace_background: {
    template:
      "将图片背景替换为{background},保持主体完整清晰,光影自然协调,边缘过渡平滑,保留主体阴影",
    negative: "残留原背景,边缘不自然,光影不协调,透视错误,主体变形",
    extractors: {
      background: /(?:换成|改成|替换为|变成|换为)(.+?)(?:背景|底|$)/,
    },
  },

  enhance: {
    template:
      "提升图片整体清晰度和质量,保持自然色彩不失真,去除噪点,增强细节,适度锐化",
    negative: "过度锐化,色彩失真,噪点增加,伪影,画质下降",
    extractors: {},
  },

  extend: {
    template:
      "向{direction}方向扩展图片{amount},保持原有风格和色调一致,光影过渡自然,无明显接缝",
    negative: "风格不一致,明显接缝,透视错误,内容突变",
    extractors: {
      direction: /向?(上|下|左|右|四周)/,
      amount: /(\d+%?)/,
    },
  },

  inpaint: {
    template:
      "去除/修改图片中的{target},用周围环境自然填充,保持整体风格一致,无修复痕迹",
    negative: "明显修复痕迹,风格不一致,内容错误,边缘不自然",
    extractors: {
      target: /(?:去除|消除|擦掉|删除|P掉)(.+?)(?:,|。|$)/,
    },
  },

  style_transfer: {
    template:
      "将图片转换为{style}风格,保持主体可识别性,色彩风格协调,整体效果自然",
    negative: "主体变形,特征丢失,风格不统一,色彩异常",
    extractors: {
      style: /(?:转换为|变成|改成)(.+?)(?:风格|$)/,
    },
  },

  resize: {
    template: "调整图片尺寸为{size},保持画质清晰,比例协调",
    negative: "画质损失,比例失调,模糊",
    extractors: {
      size: /(\d+[x×]\d+|\d+%)/,
    },
  },

  color_adjust: {
    template: "调整图片{adjustment},保持自然效果,色彩协调",
    negative: "色彩失真,过度调整,不自然",
    extractors: {
      adjustment: /(?:调整|增加|减少|提高|降低)(.+?)(?:,|。|$)/,
    },
  },
};

/**
 * 优化提示词
 */
export function optimizePrompt(params: {
  originalPrompt: string;
  intent: string;
  subIntent?: string;
}): OptimizeResult {
  const { originalPrompt, intent, subIntent } = params;

  // 只对图片编辑类意图进行优化
  if (intent !== "image_edit" || !subIntent) {
    return {
      originalPrompt,
      optimizedPrompt: originalPrompt,
      negativePrompt: "模糊,低质量,变形,水印",
    };
  }

  const template = EDIT_TEMPLATES[subIntent];
  if (!template) {
    return {
      originalPrompt,
      optimizedPrompt: originalPrompt,
      negativePrompt: "模糊,低质量,变形,水印",
    };
  }

  // 使用模板生成优化后的提示词
  let optimizedPrompt = template.template;

  // 从用户输入中提取参数并填充模板
  for (const [key, regex] of Object.entries(template.extractors)) {
    const match = originalPrompt.match(regex);
    const value = match ? match[1].trim() : getDefaultValue(key);
    optimizedPrompt = optimizedPrompt.replace(`{${key}}`, value);
  }

  // 附加用户原始意图
  optimizedPrompt = `${optimizedPrompt}。\n\n用户原始要求:${originalPrompt}`;

  console.log("[Prompt Optimizer] Optimized:", {
    original: originalPrompt,
    optimized: optimizedPrompt,
    negative: template.negative,
  });

  return {
    originalPrompt,
    optimizedPrompt,
    negativePrompt: template.negative,
  };
}

/**
 * 获取参数默认值
 */
function getDefaultValue(key: string): string {
  const defaults: Record<string, string> = {
    background: "纯白色",
    direction: "四周",
    amount: "50%",
    target: "指定区域",
    style: "卡通",
    size: "原尺寸",
    adjustment: "颜色",
  };
  return defaults[key] || "默认";
}

3.3 创建 lib/ai/model-router.ts

/**
 * 智能模型路由器
 * 根据用户意图选择最佳模型
 */

import { getEnabledAiModelsWithProvider } from "@/lib/db/queries";

// 路由结果类型
export interface RouteResult {
  id: string;
  displayName: string;
  providerType: string;
  reason: string;
}

// 意图到模型的映射配置
const INTENT_MODEL_MAP: Record<
  string,
  {
    providerTypes: string[];
    requireVision?: boolean;
    requireImageGen?: boolean;
  }
> = {
  // 图片编辑:优先 alibaba-image(灵魂4.5)
  image_edit: {
    providerTypes: ["alibaba-image", "gemini"],
    requireVision: true,
    requireImageGen: true,
  },

  // 视觉理解:优先千问3 VL(成本低效果好)
  vision: {
    providerTypes: ["alibaba", "gemini"],
    requireVision: true,
  },

  // 图片生成
  image_gen: {
    providerTypes: ["alibaba-image", "gemini", "volcano-vision"],
    requireImageGen: true,
  },

  // 视频生成
  video_gen: {
    providerTypes: ["volcano-video", "qianwen-video"],
  },

  // 普通对话
  chat: {
    providerTypes: ["alibaba", "openai"],
  },
};

/**
 * 路由到最佳模型
 */
export async function routeToModel(params: {
  intent: string;
  subIntent?: string;
  hasImage: boolean;
}): Promise<RouteResult> {
  const { intent, subIntent, hasImage } = params;

  console.log("[Model Router] Routing for intent:", intent, subIntent);

  // 获取所有可用模型
  const allModels = await getEnabledAiModelsWithProvider();

  // 获取意图对应的配置
  const config = INTENT_MODEL_MAP[intent] || INTENT_MODEL_MAP["chat"];

  // 按优先级查找匹配的模型
  for (const providerType of config.providerTypes) {
    const candidates = allModels.filter((m) => {
      // 匹配 provider 类型
      if (m.provider.type !== providerType) return false;

      // 检查能力要求
      if (config.requireVision && !m.model.supportsVision) return false;
      if (config.requireImageGen && !m.model.supportsImageGen) return false;

      // 排除子模型
      if (m.model.isSubModel) return false;

      // 必须启用
      if (!m.model.isEnabled) return false;

      return true;
    });

    if (candidates.length > 0) {
      // 优先选择默认模型
      const defaultModel = candidates.find((c) => c.model.isDefault);
      const selected = defaultModel || candidates[0];

      const result: RouteResult = {
        id: selected.model.id,
        displayName: selected.model.displayName,
        providerType: selected.provider.type,
        reason: `${intent}${subIntent ? `/${subIntent}` : ""} → ${selected.model.displayName}`,
      };

      console.log("[Model Router] Selected:", result);
      return result;
    }
  }

  // 兜底:返回任意可用模型
  const fallback =
    allModels.find((m) => !m.model.isSubModel && m.model.isEnabled) ||
    allModels[0];

  console.log("[Model Router] Using fallback model:", fallback.model.displayName);

  return {
    id: fallback.model.id,
    displayName: fallback.model.displayName,
    providerType: fallback.provider.type,
    reason: "fallback",
  };
}

3.4 修改 app/(chat)/api/chat/route.ts

在现有的 Auto Mode 逻辑位置(约第 334-422 行),替换为以下代码:

// ========== Smart Auto Mode Logic ==========
if (finalModelId === "auto") {
  console.log("[Smart Auto Mode] Starting intelligent analysis...");

  // 1. 提取用户消息内容
  const lastUserMessage = message;
  const textContent = lastUserMessage.parts
    .filter((p) => p.type === "text")
    .map((p) => (p as { type: "text"; text: string }).text)
    .join(" ");

  const hasImage = lastUserMessage.parts.some(
    (p) => p.type === "file" || p.type === "image" || p.type === "image_url"
  );

  const imageUrls = lastUserMessage.parts
    .filter((p): p is { type: "file"; url: string } => p.type === "file")
    .map((p) => p.url);

  // 2. 调用智能分析器
  const { analyzeIntent } = await import("@/lib/ai/smart-analyzer");
  const analysisResult = await analyzeIntent({
    text: textContent,
    hasImage,
    imageUrls,
  });

  console.log("[Smart Auto Mode] Analysis result:", analysisResult);

  // 3. 如果需要澄清,返回澄清问题(可选功能)
  if (analysisResult.needsClarification && analysisResult.clarifyingQuestions) {
    console.log("[Smart Auto Mode] Needs clarification, but proceeding with best guess...");
    // 暂时不中断流程,继续使用最佳猜测
  }

  // 4. 如果是图片编辑类意图,优化提示词
  if (analysisResult.intent === "image_edit" && analysisResult.subIntent) {
    const { optimizePrompt } = await import("@/lib/ai/prompt-optimizer");
    const optimizedResult = optimizePrompt({
      originalPrompt: textContent,
      intent: analysisResult.intent,
      subIntent: analysisResult.subIntent,
    });

    console.log("[Smart Auto Mode] Prompt optimized");

    // 替换消息中的文本为优化后的提示词
    message.parts = message.parts.map((part) => {
      if (part.type === "text") {
        return {
          ...part,
          text: optimizedResult.optimizedPrompt,
        };
      }
      return part;
    });

    // 如果模型支持负面提示词,可以在 imageParams 中传递
    // requestBody.imageParams = {
    //   ...requestBody.imageParams,
    //   negativePrompt: optimizedResult.negativePrompt,
    // };
  }

  // 5. 路由到最佳模型
  const { routeToModel } = await import("@/lib/ai/model-router");
  const routeResult = await routeToModel({
    intent: analysisResult.intent,
    subIntent: analysisResult.subIntent,
    hasImage,
  });

  finalModelId = routeResult.id;
  console.log(`[Smart Auto Mode] ✅ Routed to: ${routeResult.displayName} (${routeResult.reason})`);
}
// ========== End Smart Auto Mode Logic ==========

四、测试场景

4.1 图片编辑场景测试

用户输入 预期意图 预期模型
[图片] + "帮我把背景换成白色" replace_background alibaba-image
[图片] + "抠图" remove_background alibaba-image
[图片] + "变清晰一点" enhance alibaba-image
[图片] + "把右边的人P掉" inpaint alibaba-image
[图片] + "转成卡通风格" style_transfer alibaba-image

4.2 非编辑场景测试

用户输入 预期意图 预期模型
[图片] + "这是什么?" vision alibaba (Qwen3 VL)
"画一个可爱的猫" image_gen alibaba-image
"你好" chat alibaba (Qwen3 VL)

五、开发步骤

Phase 1: 基础实现 (1-2天)

  1. 创建 lib/ai/smart-analyzer.ts - 使用关键词匹配作为主逻辑
  2. 创建 lib/ai/prompt-optimizer.ts - 实现模板化提示词优化
  3. 创建 lib/ai/model-router.ts - 实现基于意图的模型路由
  4. 修改 app/(chat)/api/chat/route.ts - 集成新模块

Phase 2: 智能升级 (2-3天)

  1. 在 smart-analyzer.ts 中集成 Qwen3 VL 进行意图分析
  2. 测试各种边界情况
  3. 优化提示词模板

Phase 3: 反馈优化 (可选)

  1. 添加用户反馈机制
  2. 记录用户偏好
  3. 持续优化模型路由策略

六、注意事项

  1. 保持向后兼容:如果智能分析失败,自动回退到关键词匹配
  2. 性能考虑:Qwen3 分析会增加约 1-2 秒延迟,考虑是否需要
  3. 错误处理:所有新模块都需要完善的 try-catch
  4. 日志记录:添加详细日志便于调试

七、文件结构

lib/
└── ai/
    ├── smart-analyzer.ts     # 智能意图分析器
    ├── prompt-optimizer.ts   # 提示词优化器
    ├── model-router.ts       # 智能模型路由器
    ├── dynamic-provider.ts   # 现有模型提供器
    └── providers/            # 现有模型提供商
        ├── alibaba-image.ts
        ├── gemini-image.ts
        └── ...

app/
└── (chat)/
    └── api/
        └── chat/
            └── route.ts      # 修改 Auto Mode 逻辑