diff --git a/backend/src/modules/ai/ai.service.ts b/backend/src/modules/ai/ai.service.ts index 3e75b85..f7be484 100644 --- a/backend/src/modules/ai/ai.service.ts +++ b/backend/src/modules/ai/ai.service.ts @@ -203,9 +203,12 @@ export class AiService { content, ].join('\n'); + // 4개 카테고리 × 다수 항목의 구조화 JSON 이라 토큰 여유를 넉넉히 준다 + // (1024 면 응답이 중간에 잘려 JSON 파싱이 실패할 수 있음) const raw = await this.callClaude( [{ role: 'user', content: userMsg }], SUGGEST_SYSTEM_PROMPT, + 3072, ); return { groups: this.parseSuggestions(raw) }; } @@ -225,6 +228,9 @@ export class AiService { try { parsed = JSON.parse(text); } catch { + this.logger.warn( + `추천 JSON 파싱 실패(응답 잘림 가능) — 원본 ${raw.length}자: ${raw.slice(0, 300)}`, + ); throw this.suggestFailed(); } @@ -243,7 +249,12 @@ export class AiService { .slice(0, 15); if (items.length > 0) result.push({ category, items }); } - if (result.length === 0) throw this.suggestFailed(); + if (result.length === 0) { + this.logger.warn( + `추천 결과가 비어 있음 — 원본 ${raw.length}자: ${raw.slice(0, 300)}`, + ); + throw this.suggestFailed(); + } return result; } @@ -418,6 +429,7 @@ export class AiService { private async callClaude( messages: { role: 'user' | 'assistant'; content: string }[], system: string, + maxTokens: number = MAX_TOKENS, ): Promise { let response: Response; try { @@ -430,7 +442,7 @@ export class AiService { }, body: JSON.stringify({ model: this.model, - max_tokens: MAX_TOKENS, + max_tokens: maxTokens, system, messages, }),