feat: LLM 驱动的精准提示词优化
1. 使用 Qwen VL 根据历史对话动态优化提示词 2. 强调精准局部编辑,只修改用户指定的部分 3. 保护其他元素不被误改 4. 包含具体的编辑要求和避免项 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
7ed0dad3f6
commit
2f667cede8
@ -467,16 +467,17 @@ export async function POST(request: Request) {
|
||||
console.log("[Smart Auto Mode] 💬 Conversational reply:", smartAutoFriendlyMessage);
|
||||
}
|
||||
|
||||
// 3. 如果是图片编辑类意图,优化提示词
|
||||
// 3. 如果是图片编辑类意图,使用 LLM 深度优化提示词
|
||||
if (analysisResult.intent === "image_edit" && analysisResult.subIntent) {
|
||||
const { optimizePrompt } = await import("@/lib/ai/prompt-optimizer");
|
||||
const optimizedResult = optimizePrompt({
|
||||
const { optimizePromptWithLLM } = await import("@/lib/ai/prompt-optimizer");
|
||||
const optimizedResult = await optimizePromptWithLLM({
|
||||
originalPrompt: textContent,
|
||||
intent: analysisResult.intent,
|
||||
subIntent: analysisResult.subIntent,
|
||||
historyMessages, // 🆕 传入历史对话上下文
|
||||
});
|
||||
|
||||
console.log("[Smart Auto Mode] ✨ Prompt optimized:", {
|
||||
console.log("[Smart Auto Mode] ✨ Prompt optimized (LLM):", {
|
||||
original: textContent.substring(0, 50),
|
||||
optimized: optimizedResult.optimizedPrompt.substring(0, 100),
|
||||
});
|
||||
|
||||
@ -146,19 +146,177 @@ const EDIT_TEMPLATES: Record<
|
||||
|
||||
color_adjust: {
|
||||
template:
|
||||
"颜色调整:对图片进行{adjustment}处理。要求:保持自然效果,色彩协调,不过度调整。",
|
||||
negative: "色彩失真,过度调整,不自然,偏色严重",
|
||||
"颜色调整:{original_request}。要求:精准修改指定部分的颜色,保持其他区域不变,色彩过渡自然协调。",
|
||||
negative: "色彩失真,过度调整,不自然,偏色严重,其他区域被误改",
|
||||
extractors: {
|
||||
adjustment: /(?:调整|增加|减少|提高|降低)(.+?)(?:,|。|$| )/,
|
||||
// 匹配各种颜色修改表达方式
|
||||
target_color: /(?:改成|换成|变成|改为|换为|变为|调成|调整为)(.+?)(?:色|$)/,
|
||||
target_object: /(?:把|将)?(.+?)(?:的)?(?:颜色|色)/,
|
||||
},
|
||||
defaults: {
|
||||
adjustment: "色彩优化",
|
||||
original_request: "进行色彩优化处理",
|
||||
},
|
||||
// 特殊标记:使用原始请求
|
||||
useOriginalPrompt: true,
|
||||
},
|
||||
};
|
||||
|
||||
import { generateText } from "ai";
|
||||
|
||||
// 历史消息类型
|
||||
interface HistoryMessage {
|
||||
role: "user" | "assistant";
|
||||
content: string;
|
||||
}
|
||||
|
||||
// LLM 优化提示词的系统提示 - 专注于精准局部编辑
|
||||
const LLM_OPTIMIZER_SYSTEM_PROMPT = `你是一个专业的AI图片编辑提示词优化专家。本系统主要用于产品图片编辑,需要精准控制编辑范围。
|
||||
|
||||
## 核心原则:精准局部编辑
|
||||
1. **只修改用户指定的部分**:明确指出要修改的对象/区域
|
||||
2. **保护其他元素**:强调保持其他所有元素完全不变
|
||||
3. **细节要求**:包含颜色、材质、光影、位置等具体参数
|
||||
4. **自然过渡**:修改区域与周围环境自然融合
|
||||
|
||||
## 输出格式(严格JSON)
|
||||
{
|
||||
"optimizedPrompt": "精准的图片编辑指令",
|
||||
"negativePrompt": "需要避免的效果"
|
||||
}
|
||||
|
||||
## 示例
|
||||
|
||||
用户请求:"把椅子颜色改成绿色"
|
||||
{
|
||||
"optimizedPrompt": "【精准编辑】将图片中椅子的颜色改为绿色。具体要求:1.只修改椅子颜色,保持椅子的形状、材质纹理、光影反射完全不变;2.背景、地面、其他物品保持原样不做任何改动;3.绿色需自然协调,与原有光照环境匹配",
|
||||
"negativePrompt": "背景改变,其他物品变色,形状变形,材质改变,光影不自然,整体色调偏移"
|
||||
}
|
||||
|
||||
用户请求:"把背景换成白色"
|
||||
{
|
||||
"optimizedPrompt": "【精准编辑】将图片背景替换为纯白色(#FFFFFF)。具体要求:1.只替换背景区域,主体产品保持完全不变;2.主体边缘精准抠取,无残留背景色;3.保留主体自然投影效果",
|
||||
"negativePrompt": "主体被裁切,边缘锯齿,主体颜色改变,产品变形,细节丢失"
|
||||
}
|
||||
|
||||
用户请求:"把产品放大一点"
|
||||
{
|
||||
"optimizedPrompt": "【精准编辑】将图片中的产品主体等比例放大约20%。具体要求:1.保持产品清晰度和细节不丢失;2.保持产品比例不变形;3.背景自然填充延伸",
|
||||
"negativePrompt": "产品模糊,比例变形,画质下降,背景突兀"
|
||||
}
|
||||
|
||||
用户历史说"抠图",现在说"再清晰一点"
|
||||
{
|
||||
"optimizedPrompt": "【精准编辑】提升图片清晰度。具体要求:1.增强主体产品的锐度和细节;2.保持透明背景不变;3.不改变产品颜色和形状",
|
||||
"negativePrompt": "过度锐化,噪点增加,颜色失真,边缘光晕"
|
||||
}
|
||||
|
||||
## 关键要求
|
||||
- 必须使用【精准编辑】开头,明确这是局部编辑任务
|
||||
- 必须列出"具体要求"说明要改什么、不改什么
|
||||
- negativePrompt 必须包含"其他元素改变"相关描述
|
||||
- 结合对话历史理解用户的连续编辑意图`;
|
||||
|
||||
/**
|
||||
* 优化提示词
|
||||
* 🆕 使用 LLM 深度优化提示词(基于历史对话上下文)
|
||||
*/
|
||||
export async function optimizePromptWithLLM(params: {
|
||||
originalPrompt: string;
|
||||
intent: string;
|
||||
subIntent?: string;
|
||||
historyMessages?: HistoryMessage[];
|
||||
}): Promise<OptimizeResult> {
|
||||
const { originalPrompt, intent, subIntent, historyMessages } = params;
|
||||
|
||||
console.log("[Prompt Optimizer LLM] Input:", {
|
||||
originalPrompt,
|
||||
intent,
|
||||
subIntent,
|
||||
historyCount: historyMessages?.length || 0
|
||||
});
|
||||
|
||||
// 只对图片编辑类意图进行 LLM 优化
|
||||
if (intent !== "image_edit") {
|
||||
return {
|
||||
originalPrompt,
|
||||
optimizedPrompt: originalPrompt,
|
||||
negativePrompt: "模糊,低质量,变形,水印,失真",
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
// 动态导入避免循环依赖
|
||||
const { getEnabledAiModelsWithProvider } = await import("@/lib/db/queries");
|
||||
const { getLanguageModelById } = await import("./dynamic-provider");
|
||||
|
||||
// 获取千问3 VL 模型
|
||||
const allModels = await getEnabledAiModelsWithProvider();
|
||||
const qwenModel = allModels.find(
|
||||
(m) => m.provider.type === "alibaba" && m.model.supportsVision
|
||||
);
|
||||
|
||||
if (!qwenModel) {
|
||||
console.log("[Prompt Optimizer LLM] No Qwen3 VL model, falling back to template");
|
||||
return optimizePrompt({ originalPrompt, intent, subIntent });
|
||||
}
|
||||
|
||||
const model = await getLanguageModelById(qwenModel.model.id);
|
||||
if (!model) {
|
||||
console.log("[Prompt Optimizer LLM] Failed to get model, falling back to template");
|
||||
return optimizePrompt({ originalPrompt, intent, subIntent });
|
||||
}
|
||||
|
||||
// 构建包含历史上下文的消息
|
||||
let contextMessage = "";
|
||||
if (historyMessages && historyMessages.length > 0) {
|
||||
const recentHistory = historyMessages.slice(-6); // 最近3轮对话
|
||||
const historyText = recentHistory.map(msg =>
|
||||
`${msg.role === 'user' ? '用户' : 'AI'}: ${msg.content.substring(0, 150)}`
|
||||
).join('\n');
|
||||
contextMessage = `## 对话历史:\n${historyText}\n\n`;
|
||||
}
|
||||
|
||||
const userMessage = `${contextMessage}## 当前用户请求:\n"${originalPrompt}"\n\n## 识别的意图:${subIntent || '图片编辑'}\n\n请生成优化后的提示词:`;
|
||||
|
||||
console.log("[Prompt Optimizer LLM] Calling Qwen3 VL for prompt optimization");
|
||||
|
||||
const { text: responseText } = await generateText({
|
||||
model,
|
||||
system: LLM_OPTIMIZER_SYSTEM_PROMPT,
|
||||
prompt: userMessage,
|
||||
temperature: 0.2,
|
||||
maxTokens: 200,
|
||||
} as any);
|
||||
|
||||
// 解析 JSON 响应
|
||||
const jsonMatch = responseText.match(/\{[\s\S]*\}/);
|
||||
if (jsonMatch) {
|
||||
try {
|
||||
const result = JSON.parse(jsonMatch[0]);
|
||||
console.log("[Prompt Optimizer LLM] Result:", result);
|
||||
return {
|
||||
originalPrompt,
|
||||
optimizedPrompt: result.optimizedPrompt || originalPrompt,
|
||||
negativePrompt: result.negativePrompt || "模糊,低质量,变形,失真",
|
||||
friendlyMessage: FRIENDLY_MESSAGES[subIntent || ""]?.template,
|
||||
};
|
||||
} catch (e) {
|
||||
console.error("[Prompt Optimizer LLM] Failed to parse response:", e);
|
||||
}
|
||||
}
|
||||
|
||||
// 解析失败,回退到模板优化
|
||||
console.log("[Prompt Optimizer LLM] Parse failed, falling back to template");
|
||||
return optimizePrompt({ originalPrompt, intent, subIntent });
|
||||
|
||||
} catch (error) {
|
||||
console.error("[Prompt Optimizer LLM] Error:", error);
|
||||
// 出错时回退到模板优化
|
||||
return optimizePrompt({ originalPrompt, intent, subIntent });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 优化提示词(模板方式 - 作为回退)
|
||||
*/
|
||||
export function optimizePrompt(params: {
|
||||
originalPrompt: string;
|
||||
@ -187,7 +345,7 @@ export function optimizePrompt(params: {
|
||||
};
|
||||
}
|
||||
|
||||
const template = EDIT_TEMPLATES[subIntent];
|
||||
const template = EDIT_TEMPLATES[subIntent] as any;
|
||||
if (!template) {
|
||||
console.log("[Prompt Optimizer] No template for subIntent:", subIntent);
|
||||
return {
|
||||
@ -197,12 +355,25 @@ export function optimizePrompt(params: {
|
||||
};
|
||||
}
|
||||
|
||||
// 🆕 对于某些子意图,直接使用原始提示词(因为用户的描述更精准)
|
||||
// 例如:color_adjust - "把椅子颜色改成绿色" 比模板更精准
|
||||
if (template.useOriginalPrompt) {
|
||||
console.log("[Prompt Optimizer] Using original prompt for", subIntent);
|
||||
const optimizedPrompt = `${originalPrompt}。要求:精准执行用户要求,保持其他区域不变,效果自然协调。`;
|
||||
return {
|
||||
originalPrompt,
|
||||
optimizedPrompt,
|
||||
negativePrompt: template.negative,
|
||||
friendlyMessage: FRIENDLY_MESSAGES[subIntent]?.template,
|
||||
};
|
||||
}
|
||||
|
||||
// 使用模板生成优化后的提示词
|
||||
let optimizedPrompt = template.template;
|
||||
|
||||
// 从用户输入中提取参数并填充模板
|
||||
for (const [key, regex] of Object.entries(template.extractors)) {
|
||||
const match = originalPrompt.match(regex);
|
||||
const match = originalPrompt.match(regex as RegExp);
|
||||
let value = match ? match[1].trim() : template.defaults[key] || "";
|
||||
|
||||
// 清理提取的值
|
||||
@ -217,7 +388,7 @@ export function optimizePrompt(params: {
|
||||
|
||||
// 填充剩余的默认值
|
||||
for (const [key, defaultValue] of Object.entries(template.defaults)) {
|
||||
optimizedPrompt = optimizedPrompt.replace(`{${key}}`, defaultValue);
|
||||
optimizedPrompt = optimizedPrompt.replace(`{${key}}`, defaultValue as string);
|
||||
}
|
||||
|
||||
// 附加用户原始意图(如果优化后的提示词没有完全覆盖用户需求)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user