From 7bf2f2e1ad1fa6119a75e0cbce5182e7aaa88f30 Mon Sep 17 00:00:00 2001 From: "qichi.liang" Date: Wed, 20 May 2026 18:25:45 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20AI=20=E9=A2=84=E6=B5=8B=E5=A4=B1?= =?UTF-8?q?=E8=B4=A5=E6=97=B6=E6=98=BE=E7=A4=BA=E6=98=8E=E7=A1=AE=E9=94=99?= =?UTF-8?q?=E8=AF=AF=E5=8E=9F=E5=9B=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Real 模式下无 API Key 时提示「未配置 AI API Key」 - SSE 错误端点返回真实错误消息而非通用提示 --- backend/src/routes/ai.ts | 8 ++++---- backend/src/services/ai/index.ts | 4 ++++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/backend/src/routes/ai.ts b/backend/src/routes/ai.ts index a8d96fc..bd414ce 100644 --- a/backend/src/routes/ai.ts +++ b/backend/src/routes/ai.ts @@ -17,8 +17,8 @@ async function predictFormula(request: FastifyRequest<{ Body: { ingredients: Arr try { const result = await aiService.predictMetrics(ingredients) reply.raw.write(`data: ${JSON.stringify({ type: 'result', content: result })}\n\n`) - } catch { - reply.raw.write(`data: ${JSON.stringify({ type: 'error', content: '预测失败' })}\n\n`) + } catch (err) { + reply.raw.write(`data: ${JSON.stringify({ type: 'error', content: (err as Error).message })}\n\n`) } reply.raw.end() } @@ -44,8 +44,8 @@ async function exploreFormula(request: FastifyRequest<{ Body: { for (const option of parsed) { reply.raw.write(`data: ${JSON.stringify({ type: 'option', option })}\n\n`) } - } catch { - reply.raw.write(`data: ${JSON.stringify({ type: 'error', content: '推演失败' })}\n\n`) + } catch (err) { + reply.raw.write(`data: ${JSON.stringify({ type: 'error', content: (err as Error).message })}\n\n`) } reply.raw.write(`data: ${JSON.stringify({ type: 'done' })}\n\n`) reply.raw.end() diff --git a/backend/src/services/ai/index.ts b/backend/src/services/ai/index.ts index 52344fd..564fd28 100644 --- a/backend/src/services/ai/index.ts +++ b/backend/src/services/ai/index.ts @@ -136,6 +136,10 @@ export class AIService { return MOCK_RESPONSES[capability] ?? '{}' } + if (Object.keys(this.providers).length === 0) { + throw new Error('未配置 AI API Key,请在设置中配置或切换到 Mock 模式') + } + await this.rateLimiter.acquire() const { provider, model } = this.selectProvider(opts.model)