diff --git a/src/server-agent.ts b/src/server-agent.ts index ee30231..037bda3 100644 --- a/src/server-agent.ts +++ b/src/server-agent.ts @@ -191,11 +191,38 @@ interface OpenAIAPIResponse { }>; } +// RecommendResponse 타입 (server-tool.ts와 동일) +interface RecommendResponse { + recommendations: Array<{ + server: { + instance_name: string; + vcpu: number; + memory_gb: number; + storage_gb: number; + transfer_tb: number; + monthly_price: number; + provider_name: string; + region_code: string; + region_name: string; + }; + score: number; + estimated_capacity?: { + max_concurrent_users?: number; + }; + bandwidth_analysis?: { + estimated_monthly_tb?: number; + overage_tb?: number; + overage_cost_krw?: number; + }; + }>; +} + // OpenAI 호출 (서버 전문가 AI with Function Calling) async function callServerExpertAI( env: Env, session: ServerSession, - userMessage: string + userMessage: string, + recommendationData?: RecommendResponse ): Promise<{ action: 'question' | 'recommend'; message: string; collectedInfo: ServerSession['collectedInfo'] }> { if (!env.OPENAI_API_KEY) { throw new Error('OPENAI_API_KEY not configured'); @@ -209,7 +236,42 @@ async function callServerExpertAI( content: m.content, })); - const systemPrompt = `당신은 30년 경력의 시니어 클라우드 아키텍트입니다. + // 검토 모드: 추천 결과가 있을 때 + const isReviewMode = !!recommendationData; + + const systemPrompt = isReviewMode + ? `당신은 Cloud Orchestrator가 추천한 서버를 검토하는 30년 경력의 시니어 클라우드 아키텍트입니다. + +## 전문성 (30년 경력) +- 서버 엔지니어: Linux, Windows Server, 가상화, 컨테이너 마스터 +- 네트워크 엔지니어: 로드밸런싱, CDN, DNS, 보안 설계 전문 +- 클라우드 아키텍트: 모든 클라우드 플랫폼 경험 +- 수천 개의 서버 구축 경험 + +## 검토 대상 추천 결과 +${JSON.stringify(recommendationData?.recommendations, null, 2)} + +## 사용자 요구사항 +- 용도: ${session.collectedInfo.useCase || '웹 서비스'} +- 규모: ${session.collectedInfo.scale === 'business' ? '사업용' : '개인용'} +${session.collectedInfo.budgetLimit ? `- 예산: ${session.collectedInfo.budgetLimit}원` : ''} + +## 검토 작업 +다음을 검토하고 간결하게 2-3문장으로 코멘트해주세요: +1. 추천된 서버가 용도와 규모에 적합한지 +2. 스펙이 충분한지 (RAM, CPU, 스토리지) +3. 대역폭 경고(overage)가 있다면 언급 +4. 더 적합한 스펙이 필요하다면 제안 + +## 응답 형식 (반드시 JSON만 반환) +{ + "action": "recommend", + "message": "검토 코멘트 (자연스럽고 친근한 어조, 2-3문장)", + "collectedInfo": ${JSON.stringify(session.collectedInfo)} +} + +중요: 검토 코멘트만 작성하세요. 추천 결과 나열은 하지 마세요.` + : `당신은 30년 경력의 시니어 클라우드 아키텍트입니다. ## 전문성 (30년 경력) - 서버 엔지니어: Linux, Windows Server, 가상화, 컨테이너 마스터 @@ -466,7 +528,7 @@ export async function processServerConsultation( session.status = 'recommending'; await saveServerSession(env.SESSION_KV, session.telegramUserId, session); - // Call recommendation API + // 1. Call recommendation API (추천 먼저 받기) logger.info('추천 API 호출', { collectedInfo: session.collectedInfo }); const { executeServerAction, getRecommendationData } = await import('./tools/server-tool'); @@ -516,10 +578,11 @@ export async function processServerConsultation( createdAt: Date.now() }; - // Mark session as selecting (사용자 선택 대기) - session.status = 'selecting'; - await saveServerSession(env.SESSION_KV, session.telegramUserId, session); + // 2. AI에게 추천 결과 전달하여 검토 요청 + logger.info('AI 검토 요청', { recommendationCount: recommendationData.recommendations.length }); + const reviewResult = await callServerExpertAI(env, session, userMessage, recommendationData); + // 3. 포맷팅된 추천 결과 생성 const formattedRecommendation = await executeServerAction( 'recommend', { @@ -534,7 +597,12 @@ export async function processServerConsultation( session.telegramUserId ); - return `${aiResult.message}\n\n${formattedRecommendation}\n\n💡 원하는 서버 번호를 선택해주세요 (예: 1번)`; + // Mark session as selecting (사용자 선택 대기) + session.status = 'selecting'; + await saveServerSession(env.SESSION_KV, session.telegramUserId, session); + + // 4. AI 검토 코멘트 + 추천 결과 함께 반환 + return `${reviewResult.message}\n\n${formattedRecommendation}\n\n💡 원하는 서버 번호를 선택해주세요 (예: 1번)`; } else { // 추천 결과 없음 - 세션 삭제 session.status = 'completed';