fix: Server Expert AI JSON parsing and numeric type conversion
- Add response_format: { type: 'json_object' } for review mode to force JSON response
- Convert expectedDau and expectedConcurrent from string to number before API call
- Add enhanced KV session debugging with key names in logs
Fixes:
- AI returning plain text instead of JSON in review mode
- 400 error from recommend API due to string values in expected_users
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -25,17 +25,18 @@ export async function getServerSession(
|
||||
): Promise<ServerSession | null> {
|
||||
try {
|
||||
const key = `${SESSION_KEY_PREFIX}${userId}`;
|
||||
logger.info('세션 조회 시도', { userId, key });
|
||||
const data = await kv.get(key, 'json');
|
||||
|
||||
if (!data) {
|
||||
logger.info('세션 없음', { userId });
|
||||
logger.info('세션 없음', { userId, key });
|
||||
return null;
|
||||
}
|
||||
|
||||
logger.info('세션 조회 성공', { userId, status: (data as ServerSession).status });
|
||||
logger.info('세션 조회 성공', { userId, key, status: (data as ServerSession).status });
|
||||
return data as ServerSession;
|
||||
} catch (error) {
|
||||
logger.error('세션 조회 실패', error as Error, { userId });
|
||||
logger.error('세션 조회 실패', error as Error, { userId, key: `${SESSION_KEY_PREFIX}${userId}` });
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -49,13 +50,16 @@ export async function saveServerSession(
|
||||
const key = `${SESSION_KEY_PREFIX}${userId}`;
|
||||
session.updatedAt = Date.now();
|
||||
|
||||
await kv.put(key, JSON.stringify(session), {
|
||||
const sessionData = JSON.stringify(session);
|
||||
logger.info('세션 저장 시도', { userId, key, status: session.status, dataLength: sessionData.length });
|
||||
|
||||
await kv.put(key, sessionData, {
|
||||
expirationTtl: SESSION_TTL,
|
||||
});
|
||||
|
||||
logger.info('세션 저장 성공', { userId, status: session.status });
|
||||
logger.info('세션 저장 성공', { userId, key, status: session.status });
|
||||
} catch (error) {
|
||||
logger.error('세션 저장 실패', error as Error, { userId });
|
||||
logger.error('세션 저장 실패', error as Error, { userId, key: `${SESSION_KEY_PREFIX}${userId}` });
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
@@ -370,20 +374,31 @@ ${JSON.stringify(session.collectedInfo, null, 2)}
|
||||
|
||||
// Loop to handle tool calls
|
||||
while (toolCallCount < MAX_TOOL_CALLS) {
|
||||
// 검토 모드에서는 도구 없이 JSON 응답만 요청
|
||||
const requestBody = isReviewMode
|
||||
? {
|
||||
model: 'gpt-4o-mini',
|
||||
messages,
|
||||
response_format: { type: 'json_object' },
|
||||
max_tokens: 500,
|
||||
temperature: 0.5,
|
||||
}
|
||||
: {
|
||||
model: 'gpt-4o-mini',
|
||||
messages,
|
||||
tools: serverExpertTools,
|
||||
tool_choice: 'auto',
|
||||
max_tokens: 800,
|
||||
temperature: 0.7,
|
||||
};
|
||||
|
||||
const response = await fetch(getOpenAIUrl(env), {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${env.OPENAI_API_KEY}`,
|
||||
},
|
||||
body: JSON.stringify({
|
||||
model: 'gpt-4o-mini',
|
||||
messages,
|
||||
tools: serverExpertTools,
|
||||
tool_choice: 'auto',
|
||||
max_tokens: 800,
|
||||
temperature: 0.7,
|
||||
}),
|
||||
body: JSON.stringify(requestBody),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
@@ -570,11 +585,14 @@ export async function processServerConsultation(
|
||||
|
||||
// 동시접속자 우선 사용, 없으면 scale 기반 추론
|
||||
let expectedUsers = 10; // Default
|
||||
if (session.collectedInfo.expectedConcurrent) {
|
||||
expectedUsers = session.collectedInfo.expectedConcurrent;
|
||||
} else if (session.collectedInfo.expectedDau) {
|
||||
const concurrent = Number(session.collectedInfo.expectedConcurrent) || 0;
|
||||
const dau = Number(session.collectedInfo.expectedDau) || 0;
|
||||
|
||||
if (concurrent > 0) {
|
||||
expectedUsers = concurrent;
|
||||
} else if (dau > 0) {
|
||||
// DAU가 있으면 10% 비율로 동시접속자 계산
|
||||
expectedUsers = Math.ceil(session.collectedInfo.expectedDau * 0.1);
|
||||
expectedUsers = Math.ceil(dau * 0.1);
|
||||
} else if (session.collectedInfo.scale) {
|
||||
expectedUsers = inferExpectedUsers(session.collectedInfo.scale);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user