降低Agent追问并按Nano Banana三段式优化提示词

This commit is contained in:
Your Name 2026-02-14 10:41:07 +08:00
parent f0ede6f0c9
commit 31e4ca6407
3 changed files with 137 additions and 19 deletions

View File

@ -1397,6 +1397,31 @@ export async function POST(request: Request) {
const streamId = generateUUID();
await createStreamId({ streamId, chatId: id });
if (shouldRunAgentConversation && smartAutoNeedsClarification) {
const hasCurrentImageInput = message.parts.some((part: any) =>
part?.type === "file" || part?.type === "image" || part?.type === "image_url"
);
const hasHistoryImageInput = smartAutoHistoryImages.length > 0;
const latestUserText = message.parts
.filter((part): part is { type: "text"; text: string } => part.type === "text")
.map((part) => part.text)
.join(" ")
.trim();
if (hasCurrentImageInput || hasHistoryImageInput || latestUserText.length > 0) {
smartAutoNeedsClarification = false;
smartAutoClarificationQuestion = undefined;
if (
!smartAutoFriendlyMessage ||
/[??]$/.test(smartAutoFriendlyMessage.trim()) ||
/哪一张|哪个|请先确认/.test(smartAutoFriendlyMessage)
) {
smartAutoFriendlyMessage = "收到,我将按你的当前需求直接执行。";
}
console.log("[Smart Auto Mode] ✅ Force direct execution (skip clarification)");
}
}
if (shouldRunAgentConversation && smartAutoNeedsClarification) {
const clarificationMessage =
smartAutoClarificationQuestion ||

View File

@ -199,6 +199,12 @@ const LLM_OPTIMIZER_SYSTEM_PROMPT = `你是一个专业的AI图片编辑提示
"negativePrompt": "需要避免的效果"
}
## Nano Banana Pro 三段式模板(官方最佳实践)
optimizedPrompt 必须按以下结构输出:
目标:一句话说明最终要生成/修改的结果
约束:一句话说明必须保持不变和禁止项
细节:一句话补充构图、光线、材质、风格等关键细节
## 示例
用户请求:"把椅子颜色改成绿色"
@ -252,6 +258,10 @@ const IMAGE_GEN_OPTIMIZER_SYSTEM_PROMPT = `你是一个专业的图片生成提
4. negativePrompt 要包含:畸形、模糊、水印、文字错乱、额外主体、比例错误等。
5. 输出简洁可执行,不要解释过程。
6. 参数建议必须服务于“首图命中率”:人物全身/竖构图偏 9:16,横向场景偏 16:9,未明确时可用 auto。
7. 按 Nano Banana Pro 官方三段式写法组织提示词:
- 目标:一句话写清最终画面
- 约束:一句话写清必须保持不变与禁止项
- 细节:一句话补充风格/材质/光线/构图
`;
function parseOptimizerJson(responseText: string): {
@ -316,6 +326,33 @@ function sanitizeSuggestedParams(input?: {
return Object.keys(output).length > 0 ? output : undefined;
}
function ensureNanoBananaPromptStructure(prompt: string, intent: string): string {
const clean = prompt.replace(/\s+/g, " ").trim();
if (!clean) return prompt;
if (/目标[::].+约束[::].+细节[::]/s.test(clean)) {
return clean
.replace(/\s*目标[::]\s*/g, "目标:")
.replace(/\s*约束[::]\s*/g, "\n约束:")
.replace(/\s*细节[::]\s*/g, "\n细节:");
}
const fragments = clean
.split(/[。!?!?]/)
.map((item) => item.trim())
.filter(Boolean);
const goal = fragments[0] || clean;
const defaultConstraint =
intent === "image_edit"
? "仅修改用户要求的部分,保持构图、主体比例、背景和光影关系稳定"
: "保持主体比例与构图稳定,避免多余元素、变形和文字错误";
const constraint = fragments[1] || defaultConstraint;
const detail =
fragments.slice(2).join(",") ||
"材质真实、边缘清晰、光线自然、色彩准确,输出商业可用效果";
return `目标:${goal}\n约束:${constraint}\n细节:${detail}`;
}
function shouldKeepBackgroundAsIs(originalPrompt: string, subIntent?: string): boolean {
if (subIntent === "replace_background" || subIntent === "remove_background") {
return false;
@ -368,11 +405,12 @@ function enforceImageEditStability(params: {
function fallbackImageGenPrompt(originalPrompt: string): OptimizeResult {
const normalized = originalPrompt.replace(/\s+/g, " ").trim();
const optimizedPrompt = [
const basePrompt = [
"高质量图像生成:",
normalized,
"要求:主体清晰,构图平衡,光影自然,材质真实,细节丰富,整体风格统一。",
].join(" ");
const optimizedPrompt = ensureNanoBananaPromptStructure(basePrompt, "image_gen");
return {
originalPrompt,
@ -492,13 +530,19 @@ export async function optimizePromptWithLLM(params: {
const stabilized =
intent === "image_edit"
? enforceImageEditStability({
optimizedPrompt: parsedResult.optimizedPrompt || originalPrompt,
optimizedPrompt: ensureNanoBananaPromptStructure(
parsedResult.optimizedPrompt || originalPrompt,
intent
),
originalPrompt,
subIntent,
negativePrompt: parsedResult.negativePrompt || "模糊,低质量,变形,失真",
})
: {
optimizedPrompt: parsedResult.optimizedPrompt || originalPrompt,
optimizedPrompt: ensureNanoBananaPromptStructure(
parsedResult.optimizedPrompt || originalPrompt,
intent
),
negativePrompt: parsedResult.negativePrompt || "模糊,低质量,变形,失真",
};
return {
@ -548,9 +592,10 @@ export function optimizePrompt(params: {
// 如果没有子意图,返回通用优化
if (!subIntent) {
const basePrompt = `图片编辑:${originalPrompt}。要求:效果自然,画质清晰,细节完整。`;
return {
originalPrompt,
optimizedPrompt: `图片编辑:${originalPrompt}。要求:效果自然,画质清晰,细节完整。`,
optimizedPrompt: ensureNanoBananaPromptStructure(basePrompt, intent),
negativePrompt: "模糊,低质量,变形,水印,失真,不自然",
};
}
@ -605,6 +650,7 @@ export function optimizePrompt(params: {
if (originalPrompt.length > 10 && !optimizedPrompt.includes(originalPrompt)) {
optimizedPrompt = `${optimizedPrompt}\n\n用户补充要求:${originalPrompt}`;
}
optimizedPrompt = ensureNanoBananaPromptStructure(optimizedPrompt, intent);
// 生成友好的对话消息
let friendlyMessage = "";

View File

@ -23,6 +23,50 @@ export interface AnalysisResult {
conversationalReply?: string; // 🆕 自然对话回复
}
function inferDefaultImageEditSubIntent(text: string): AnalysisResult["subIntent"] {
const lowerText = text.toLowerCase();
if (/抠图|去背景|透明背景|去背|扣图|移除背景/.test(lowerText)) return "remove_background";
if (/换背景|改背景|背景换成|背景改成|白底|透明底/.test(lowerText)) return "replace_background";
if (/风格|卡通|动漫|油画|像素风|写实|插画/.test(lowerText)) return "style_transfer";
if (/颜色|调色|亮度|对比度|饱和度|改成.*色|换成.*色/.test(lowerText)) return "color_adjust";
if (/去除|消除|擦掉|删除|移除|p掉|重绘/.test(lowerText)) return "inpaint";
return "enhance";
}
function applyDirectExecutionPolicy(
result: AnalysisResult,
params: {
text: string;
hasImage: boolean;
imageUrls?: string[];
imageFromHistory?: boolean;
}
): AnalysisResult {
const hasUsableImage =
params.hasImage || Boolean(params.imageFromHistory) || (params.imageUrls?.length || 0) > 0;
if (!hasUsableImage) return result;
const compactText = params.text.replace(/\s+/g, "").trim();
const hasAnyRequestText = compactText.length > 0;
const normalizedIntent = result.intent === "chat" || result.intent === "vision" ? "image_edit" : result.intent;
const normalizedSubIntent =
normalizedIntent === "image_edit"
? result.subIntent || inferDefaultImageEditSubIntent(params.text)
: result.subIntent;
return {
...result,
intent: normalizedIntent,
subIntent: normalizedSubIntent,
confidence: Math.max(result.confidence, 0.72),
needsClarification: false,
clarifyingQuestions: [],
conversationalReply:
result.conversationalReply ||
(hasAnyRequestText ? "收到,我会按你的描述直接执行生成。" : "收到图片,我先按保真优化策略直接执行生成。"),
};
}
function normalizeIntentForImageContext(
result: AnalysisResult,
text: string,
@ -57,6 +101,7 @@ const ANALYZER_SYSTEM_PROMPT = `你是一个友好的AI图片编辑助手。用
1. 理解用户想要对图片做什么
2. 用自然、友好的语气回复用户,告诉他你理解了他的需求并会帮他处理
3. 同时输出结构化的意图分析结果
4. 默认直接执行,不要反问用户;只有在完全无图且需求为空时才允许澄清
## 意图分类
@ -102,7 +147,7 @@ const ANALYZER_SYSTEM_PROMPT = `你是一个友好的AI图片编辑助手。用
- conversationalReply 要自然、友好、简洁
- 可以加一些语气词让对话更亲切,如"好的"、"没问题"、"~"等
- 说明你理解了什么需求,让用户知道你在做什么
- 如果意图不明确,礼貌地询问用户想要什么效果
- 有图片时优先直接执行,不要提问
- 如果提供了画布上下文,仅用于理解,不要在 conversationalReply 中复述坐标或技术细节
## 示例
@ -127,9 +172,10 @@ const ANALYZER_SYSTEM_PROMPT = `你是一个友好的AI图片编辑助手。用
用户发了图片但没说要做什么:
{
"intent": "image_edit",
"confidence": 0.5,
"conversationalReply": "我看到你发了一张图片,你想对它做什么处理呢?比如抠图、换背景、变清晰?",
"needsClarification": true
"subIntent": "enhance",
"confidence": 0.72,
"conversationalReply": "收到图片,我先做保真优化并输出结果,你可以再继续细化要求~",
"needsClarification": false
}
连续对话场景 - 用户说"换成蓝色"(系统自动使用历史图片):
@ -146,9 +192,8 @@ const ANALYZER_SYSTEM_PROMPT = `你是一个友好的AI图片编辑助手。用
"intent": "image_edit",
"subIntent": "redo",
"confidence": 0.8,
"conversationalReply": "没问题,你想怎么调整呢?比如换个颜色、调整风格?",
"needsClarification": true,
"clarifyingQuestions": ["你具体想调整哪方面呢?"]
"conversationalReply": "没问题,我先按上一轮目标继续优化并给你一个更稳的版本~",
"needsClarification": false
}
连续对话场景 - 用户说"再清晰一点":
@ -191,7 +236,7 @@ export async function analyzeIntent(params: {
const quickResult = quickKeywordMatch(text, hasImage);
if (quickResult.confidence >= 0.9) {
console.log("[Smart Analyzer] Quick match result:", quickResult);
return quickResult;
return applyDirectExecutionPolicy(quickResult, { text, hasImage, imageUrls, imageFromHistory });
}
// 尝试使用 Qwen3 VL 进行深度分析(传入历史对话)
@ -199,7 +244,7 @@ export async function analyzeIntent(params: {
const llmResult = await analyzWithLLM(text, hasImage, imageUrls, historyMessages, context);
if (llmResult) {
console.log("[Smart Analyzer] LLM analysis result:", llmResult);
return llmResult;
return applyDirectExecutionPolicy(llmResult, { text, hasImage, imageUrls, imageFromHistory });
}
} catch (error) {
console.error("[Smart Analyzer] LLM analysis failed:", error);
@ -208,7 +253,7 @@ export async function analyzeIntent(params: {
// 回退到完整关键词分析
const fallbackResult = fallbackKeywordAnalysis(text, hasImage);
console.log("[Smart Analyzer] Fallback result:", fallbackResult);
return fallbackResult;
return applyDirectExecutionPolicy(fallbackResult, { text, hasImage, imageUrls, imageFromHistory });
}
/**
@ -461,9 +506,10 @@ export function fallbackKeywordAnalysis(
if (/修图|P图|改图|调图|处理.*图|编辑.*图|优化.*图/.test(lowerText)) {
return {
intent: "image_edit",
subIntent: inferDefaultImageEditSubIntent(text),
confidence: 0.8,
needsClarification: true,
conversationalReply: "我看到你想编辑这张图片,你具体想要做什么处理呢?比如抠图、换背景、变清晰?",
needsClarification: false,
conversationalReply: "收到,我先按你的需求直接执行图片优化。",
};
}
@ -479,9 +525,10 @@ export function fallbackKeywordAnalysis(
// 有图但意图不明确
return {
intent: "image_edit",
confidence: 0.5,
needsClarification: true,
conversationalReply: "我看到你发了一张图片,你想对它做什么处理呢?比如抠图、换背景、变清晰?",
subIntent: inferDefaultImageEditSubIntent(text),
confidence: 0.75,
needsClarification: false,
conversationalReply: "收到图片,我先按保真优化策略直接执行。",
};
}