feat: AI 추천 카테고리당 항목 수 제한 해제

- 프롬프트의 '3~6개씩' 제한 제거 → 카테고리별로 필요한 만큼 제안
- parseSuggestions 의 카테고리당 15개 슬라이스 캡 제거(응답 길이는 max_tokens 가 자연 제한)
- 항목이 늘어 잘리지 않도록 suggest max_tokens 3072 → 4096

런타임 재현: 동일 입력에서 필수8·관리6·보안8·부가6(총 28개)로 더 풍부하게 반환.
백엔드 build/lint 0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-21 12:32:35 +09:00
parent f8ae813c05
commit 0d47e989ba
+6 -6
View File
@@ -84,7 +84,7 @@ const SUGGEST_SYSTEM_PROMPT = [
'[규칙]',
'- 반드시 아래 JSON 형식으로만 응답하세요. 설명·인사·마크다운 코드펜스 없이 순수 JSON 만 출력합니다.',
'- 카테고리는 정확히 "필수 기능", "관리 기능", "보안 기능", "부가 기능" 4개를 이 순서대로 사용하세요. (다른 이름·추가/누락 카테고리 금지)',
'- 각 카테고리에 해당하는 항목을 3~6개씩 제안합니다. 적합한 항목이 없으면 빈 배열([])로 두세요.',
'- 각 카테고리에 필요한 항목을 충분히 제안하세요. 항목 수에 제한은 없습니다. 적합한 항목이 없으면 빈 배열([])로 두세요.',
'- 각 항목은 한국어로 간결한 한 문장(체크리스트 항목)으로 작성합니다.',
'- 업무·프로젝트 맥락에 구체적으로 맞추고 일반론은 피하세요.',
'',
@@ -203,12 +203,12 @@ export class AiService {
content,
].join('\n');
// 4개 카테고리 × 다수 항목의 구조화 JSON 이라 토큰 여유를 넉넉히 준다
// (1024 면 응답이 중간에 잘려 JSON 파싱이 실패할 수 있음)
// 4개 카테고리 × 항목 수 무제한의 구조화 JSON 이라 토큰 여유를 넉넉히 준다
// (부족하면 응답이 중간에 잘려 JSON 파싱이 실패할 수 있음)
const raw = await this.callClaude(
[{ role: 'user', content: userMsg }],
SUGGEST_SYSTEM_PROMPT,
3072,
4096,
);
return { groups: this.parseSuggestions(raw) };
}
@@ -242,11 +242,11 @@ export class AiService {
const category =
typeof obj.category === 'string' ? obj.category.trim() : '';
if (!category || !Array.isArray(obj.items)) continue;
// 카테고리당 항목 수 제한 없음 — 응답 길이는 max_tokens 가 자연 제한
const items = obj.items
.filter((x): x is string => typeof x === 'string')
.map((s) => s.trim())
.filter((s) => s.length > 0)
.slice(0, 15);
.filter((s) => s.length > 0);
if (items.length > 0) result.push({ category, items });
}
if (result.length === 0) {