/*** 带重试的 LLM 调用执行器** 默认行为:重试时自动将错误信息反馈给 LLM,让它能够根据错误修正输出** @param model 可调用的模型(需要有 invoke 方法)* @param messages 初始消息数组* @param options 重试配置* @returns 执行结果** @example* const result = await withRetry(structuredModel, messages, {* maxRetries: 3,* onRetry: (attempt, error) => console.warn(`Retry ${attempt}:`, error.message)* });*/
export async function withRetry<T>(model: InvokableModel<T>,messages: any[],options: RetryOptions = {},
): Promise<T> {const {maxRetries = DEFAULT_MAX_RETRIES,onRetry,formatErrorFeedback = defaultErrorFeedback,} = options;let lastError: Error | null = null;let currentMessages = [...messages];for (let attempt = 1; attempt <= maxRetries; attempt++) {try {return await model.invoke(currentMessages);} catch (error) {lastError = error instanceof Error ? error : new Error(String(error));if (attempt < maxRetries) {onRetry?.(attempt, lastError);// 追加错误反馈消息用于下次重试currentMessages = [...messages,new HumanMessage(formatErrorFeedback(lastError)),];}}}throw lastError;
}
Usage
// ========== 3. AI 命名调用 ==========const structuredModel = getStructuredModel(SectionNamingOutputSchema);const messages = [new SystemMessage(getSectionNamingSystemPrompt()),new HumanMessage(getSectionNamingHumanPrompt(sectionsInfo)),];console.log("⏳ [SectionNamingNode] 正在调用 AI 命名...");let result: T_SectionNamingOutput;try {result = await withRetry(structuredModel, messages, {maxRetries: 2,onRetry: (attempt, error) => {console.warn(`⚠️ [SectionNamingNode] 命名重试 ${attempt}: ${error.message}`,);},});} catch (error) {console.error("❌ [SectionNamingNode] AI 命名失败:", error);// Fallback: 使用默认命名console.log("⚠️ [SectionNamingNode] 使用默认命名作为 fallback");result = {namedSections: sections.map((s, i) => ({index: s.index,componentName: `Section${i + 1}`,description: `页面第 ${i + 1} 区域,包含 ${s.totalBlocks} 个元素`,fileName: `Section${i + 1}`,})),};}
