feat: distinguish DAU from concurrent users in Server Expert AI
- Add expectedDau and expectedConcurrent fields to ServerSession - Update system prompts to explain DAU vs concurrent users concept - AI now asks for clarification when users mention visitor counts - Use concurrent users (5-10% of DAU) for server recommendations - Update inference rules: personal=10, business=50 concurrent users Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -162,10 +162,12 @@ function inferTechStack(useCase: string): string[] {
|
||||
}
|
||||
|
||||
// Expected users inference from scale
|
||||
// Returns concurrent users (not DAU)
|
||||
function inferExpectedUsers(scale: string): number {
|
||||
if (scale === 'personal') return 100;
|
||||
if (scale === 'business') return 500;
|
||||
return 100; // Default to personal
|
||||
// DAU → 동시접속자 변환 (5-10% 비율 적용)
|
||||
if (scale === 'personal') return 10; // DAU 100명 → 동접 10명
|
||||
if (scale === 'business') return 50; // DAU 500명 → 동접 50명
|
||||
return 10; // Default to personal
|
||||
}
|
||||
|
||||
// OpenAI API 응답 타입
|
||||
@@ -254,14 +256,22 @@ ${JSON.stringify(recommendationData?.recommendations, null, 2)}
|
||||
## 사용자 요구사항
|
||||
- 용도: ${session.collectedInfo.useCase || '웹 서비스'}
|
||||
- 규모: ${session.collectedInfo.scale === 'business' ? '사업용' : '개인용'}
|
||||
${session.collectedInfo.expectedDau ? `- 일일 방문자(DAU): ${session.collectedInfo.expectedDau}명` : ''}
|
||||
${session.collectedInfo.expectedConcurrent ? `- 동시접속자: ${session.collectedInfo.expectedConcurrent}명` : ''}
|
||||
${session.collectedInfo.budgetLimit ? `- 예산: ${session.collectedInfo.budgetLimit}원` : ''}
|
||||
|
||||
## 사용자 수 관련 참고사항
|
||||
- DAU(일일 활성 사용자)와 동시접속자는 다른 개념입니다
|
||||
- 일반적으로 동시접속자는 DAU의 5-10% 수준입니다
|
||||
- 서버 스펙은 동시접속자 기준으로 계산됩니다
|
||||
|
||||
## 검토 작업
|
||||
다음을 검토하고 간결하게 2-3문장으로 코멘트해주세요:
|
||||
1. 추천된 서버가 용도와 규모에 적합한지
|
||||
2. 스펙이 충분한지 (RAM, CPU, 스토리지)
|
||||
3. 대역폭 경고(overage)가 있다면 언급
|
||||
4. 더 적합한 스펙이 필요하다면 제안
|
||||
3. DAU/동시접속자 기준이 적절한지
|
||||
4. 대역폭 경고(overage)가 있다면 언급
|
||||
5. 더 적합한 스펙이 필요하다면 제안
|
||||
|
||||
## 응답 형식 (반드시 JSON만 반환)
|
||||
{
|
||||
@@ -300,21 +310,35 @@ ${session.collectedInfo.budgetLimit ? `- 예산: ${session.collectedInfo.budgetL
|
||||
## 대화 흐름
|
||||
1. 용도 파악: "어떤 서비스를 운영하실 건가요? (예: 블로그, 쇼핑몰, 커뮤니티)"
|
||||
2. 규모 파악: "개인용인가요, 사업용인가요?"
|
||||
3. 정보가 충분하면 즉시 추천 (추가 질문 없이)
|
||||
3. 사용자 수 확인 (필요 시): "방문자나 사용자 수는 어느 정도 예상하시나요?"
|
||||
4. 정보가 충분하면 즉시 추천 (추가 질문 없이)
|
||||
|
||||
## 핵심 규칙 (반드시 준수)
|
||||
- 기술 스택, 동시접속자 수, 트래픽 패턴은 절대 묻지 않음 (30년 경험으로 알아서 추론)
|
||||
- 기술 스택, 트래픽 패턴은 절대 묻지 않음 (30년 경험으로 알아서 추론)
|
||||
- 사용자 수를 언급하면 DAU인지 동시접속자인지 반드시 한 번 확인
|
||||
- "방문자 1000명", "유저 500명" 등 언급 시 → "말씀하신 방문자는 일일 방문자(DAU)인가요, 동시접속자인가요?"
|
||||
- DAU와 동시접속자를 구분해서 설명: "일반적으로 동시접속자는 일일 방문자의 5-10% 정도입니다"
|
||||
- "모르겠어요", "아무거나", "글쎄요" → 즉시 action="recommend" (기본값: 개인용 웹서비스)
|
||||
- 용도+규모 한번에 말하면 → 즉시 action="recommend"
|
||||
- 용도만 말해도 → 개인용으로 가정하고 action="recommend" 가능
|
||||
- 질문은 최대 2번까지, 그 이후는 무조건 action="recommend"
|
||||
|
||||
## 사용자 수 관련 용어 정리
|
||||
- **DAU (일일 활성 사용자)**: 하루 동안 서비스를 사용하는 전체 사용자 수
|
||||
- **동시접속자 (Concurrent Users)**: 같은 시간에 동시에 접속해 있는 사용자 수
|
||||
- **중요**: 서버 스펙은 동시접속자를 기준으로 계산해야 합니다
|
||||
- **일반 공식**: 동시접속자 = DAU × 5-10%
|
||||
|
||||
예시:
|
||||
- "하루 방문자 1000명" → DAU 1000명 → 동시접속자 50-100명
|
||||
- "동시 접속 100명" → 그대로 동시접속자 100명 사용
|
||||
|
||||
## 추론 규칙 (30년 경험 기반)
|
||||
- 블로그 → WordPress, 1GB RAM이면 충분
|
||||
- 쇼핑몰 → 2GB+ RAM, DB 분리 고려
|
||||
- 블로그 → WordPress, 1GB RAM이면 충분, DAU 100명 (동시접속자 10명)
|
||||
- 쇼핑몰 → 2GB+ RAM, DB 분리 고려, DAU 500명 (동시접속자 50명)
|
||||
- 커뮤니티 → PHP+MySQL, 트래픽에 따라 2~4GB
|
||||
- 게임서버 → 고사양 CPU, 낮은 레이턴시 리전
|
||||
- 규모: personal→100명, business→500명
|
||||
- 규모: personal→DAU 100명 (동접 10명), business→DAU 500명 (동접 50명)
|
||||
|
||||
## 현재 수집된 정보
|
||||
${JSON.stringify(session.collectedInfo, null, 2)}
|
||||
@@ -325,7 +349,9 @@ ${JSON.stringify(session.collectedInfo, null, 2)}
|
||||
"message": "사용자에게 보여줄 메시지 (도구에서 얻은 정보를 자연스럽게 포함)",
|
||||
"collectedInfo": {
|
||||
"useCase": "용도 (없으면 '웹서비스')",
|
||||
"scale": "personal 또는 business (없으면 'personal')"
|
||||
"scale": "personal 또는 business (없으면 'personal')",
|
||||
"expectedDau": "일일 방문자 수 (사용자가 명시한 경우)",
|
||||
"expectedConcurrent": "동시접속자 수 (사용자가 명시하거나 DAU에서 계산)"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -537,9 +563,16 @@ export async function processServerConsultation(
|
||||
? inferTechStack(session.collectedInfo.useCase)
|
||||
: ['web'];
|
||||
|
||||
const expectedUsers = session.collectedInfo.scale
|
||||
? inferExpectedUsers(session.collectedInfo.scale)
|
||||
: 100;
|
||||
// 동시접속자 우선 사용, 없으면 scale 기반 추론
|
||||
let expectedUsers = 10; // Default
|
||||
if (session.collectedInfo.expectedConcurrent) {
|
||||
expectedUsers = session.collectedInfo.expectedConcurrent;
|
||||
} else if (session.collectedInfo.expectedDau) {
|
||||
// DAU가 있으면 10% 비율로 동시접속자 계산
|
||||
expectedUsers = Math.ceil(session.collectedInfo.expectedDau * 0.1);
|
||||
} else if (session.collectedInfo.scale) {
|
||||
expectedUsers = inferExpectedUsers(session.collectedInfo.scale);
|
||||
}
|
||||
|
||||
const recommendationData = await getRecommendationData(
|
||||
{
|
||||
|
||||
@@ -230,6 +230,8 @@ export interface ServerSession {
|
||||
scale?: 'personal' | 'business';
|
||||
budgetLimit?: number;
|
||||
regionPreference?: string[];
|
||||
expectedDau?: number; // 일일 활성 사용자 (Daily Active Users)
|
||||
expectedConcurrent?: number; // 동시접속자 (Concurrent Users)
|
||||
};
|
||||
messages: Array<{ role: 'user' | 'assistant'; content: string }>;
|
||||
createdAt: number;
|
||||
|
||||
Reference in New Issue
Block a user