diff --git a/app/(chat)/api/chat/route.ts b/app/(chat)/api/chat/route.ts index 13e41177c..15429a18e 100644 --- a/app/(chat)/api/chat/route.ts +++ b/app/(chat)/api/chat/route.ts @@ -696,11 +696,7 @@ export async function POST(request: Request) { const needsRicherAutoReply = isImageTask && !smartAutoNeedsClarification && - ( - !smartAutoFriendlyMessage || - !smartAutoFriendlyMessage.includes("\n") || - smartAutoFriendlyMessage.replace(/\s+/g, "").length < 20 - ); + !smartAutoFriendlyMessage; if (needsRicherAutoReply) { smartAutoFriendlyMessage = buildAutoModeFallbackMessage({ diff --git a/lib/ai/auto-agent-graph.ts b/lib/ai/auto-agent-graph.ts index 354ec0ed8..da6054068 100644 --- a/lib/ai/auto-agent-graph.ts +++ b/lib/ai/auto-agent-graph.ts @@ -1,4 +1,5 @@ import { Annotation, StateGraph, START, END } from "@langchain/langgraph"; +import { generateText } from "ai"; import type { AnalysisResult } from "@/lib/ai/smart-analyzer"; import type { RouteResult } from "@/lib/ai/model-router"; @@ -47,38 +48,87 @@ function compactText(text: string, max = 48) { function buildStrategicFriendlyMessage( analysis: AnalysisResult, state: AutoAgentStateType, -): string | null { +): Promise { const fallbackQuestion = analysis.clarifyingQuestions?.[0]; if (analysis.needsClarification) { - return analysis.conversationalReply || fallbackQuestion || "我先确认一下,你希望我优先调整哪一部分?"; + return Promise.resolve( + analysis.conversationalReply || fallbackQuestion || "我先确认一下,你希望我优先调整哪一部分?" + ); } - if (analysis.intent === "image_gen") { - const demand = compactText(state.text); - return [ - "收到,我来帮你走自动模式生成方案。", - `- 需求理解:${demand}`, - "- 执行策略:先锁定主体与场景,再控制风格/光影/构图,最后输出可继续迭代的版本。", - "- 继续优化:你可以直接说“保留A,改B”,我会按最新要求快速迭代。", - ].join("\n"); - } + return generateAgentConversation(analysis, state); +} - if (analysis.intent === "image_edit") { - const sourceHint = state.hasImage - ? state.imageFromHistory - ? "我会基于你上一轮图片继续编辑。" - : "我会基于你刚上传的图片编辑。" - : "我会先按当前上下文进行编辑。"; - return [ - "收到,我来帮你精准编辑这张图。", - `- 执行基准:${sourceHint}`, - "- 处理方式:只改你提到的目标区域,其他主体、构图与风格尽量保持不变。", - "- 交付方式:先出一版结果,你再告诉我细调方向(如颜色、材质、氛围、细节)。", - ].join("\n"); - } +async function generateAgentConversation( + analysis: AnalysisResult, + state: AutoAgentStateType +): Promise { + try { + const { getEnabledAiModelsWithProvider } = await import("@/lib/db/queries"); + const { getLanguageModelById } = await import("./dynamic-provider"); + const allModels = await getEnabledAiModelsWithProvider(); - return analysis.conversationalReply || null; + const candidateModel = state.hasImage + ? allModels.find((m) => m.model.supportsVision && m.model.isEnabled) + : allModels.find((m) => m.model.isEnabled && !m.model.isSubModel); + + if (!candidateModel) { + return analysis.conversationalReply || null; + } + + const model = await getLanguageModelById(candidateModel.model.id); + if (!model) { + return analysis.conversationalReply || null; + } + + const history = state.historyMessages + .slice(-6) + .map((msg) => `${msg.role === "user" ? "用户" : "助手"}: ${compactText(msg.content, 120)}`) + .join("\n"); + + const imageInfo = state.hasImage + ? `用户本轮可用图片数量:${state.imageUrls.length || 1}。图片来源:${state.imageFromHistory ? "历史消息复用" : "本轮上传"}。` + : "用户本轮没有上传图片。"; + + const systemPrompt = `你是一个真实执行中的 AI 生图/修图 Agent。 +请根据用户需求和分析结果,给出“正在执行前”的简短汇报。 + +要求: +1) 不要说“我无法看到图片”;按系统提供的信息做合理分析。 +2) 必须看起来是本轮真实分析结果,避免空泛套话。 +3) 不暴露内部实现、模型路由、算法细节。 +4) 输出 4-7 行 Markdown,语气专业自然。 +5) 如果是图像任务,包含以下小节标题:需求理解、分析结论、执行计划、交付说明。 +6) 每一行尽量具体,不要重复。`; + + const prompt = [ + `【用户原始需求】${state.text || "(无文本)"}`, + `【意图分析】intent=${analysis.intent}; subIntent=${analysis.subIntent || "none"}; confidence=${analysis.confidence}`, + `【图片信息】${imageInfo}`, + state.context ? `【画布上下文】${compactText(state.context, 300)}` : "", + history ? `【最近对话】\n${history}` : "", + "请输出本轮执行前汇报:", + ] + .filter(Boolean) + .join("\n\n"); + + const { text } = await generateText({ + model, + system: systemPrompt, + prompt, + temperature: 0.35, + maxTokens: 420, + } as any); + + const cleaned = text.trim(); + if (cleaned.length < 10) { + return analysis.conversationalReply || null; + } + return cleaned; + } catch (error) { + return analysis.conversationalReply || null; + } } const analyzeNode = async (state: AutoAgentStateType) => { @@ -96,7 +146,7 @@ const analyzeNode = async (state: AutoAgentStateType) => { ? analysis.clarifyingQuestions?.[0] : undefined; - const strategicMessage = buildStrategicFriendlyMessage(analysis, state); + const strategicMessage = await buildStrategicFriendlyMessage(analysis, state); return { analysis,