feat: add AI review of server recommendations
- Server Expert AI now reviews recommendation results before showing to user - Changed flow: get recommendations first → AI reviews → show with comments - AI provides specific advice based on actual recommended specs - Reviews include: spec adequacy, bandwidth warnings, CDN suggestions Before: AI gave generic advice without seeing recommendations After: AI reviews actual results and gives contextual feedback Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -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';
|
||||
|
||||
Reference in New Issue
Block a user