fix: proactive context compression for LM Studio small models - compress BEFORE fetch not after error
This commit is contained in:
+70
-3
@@ -2022,16 +2022,83 @@ export class AgentExecutor {
|
||||
|
||||
for (const candidateModel of modelCandidates) {
|
||||
for (const variant of messageVariants) {
|
||||
// 실제 전송할 메시지 (n_ctx 재시도 시 수정됨)
|
||||
// 실제 전송할 메시지
|
||||
let finalMessages = variant.messages;
|
||||
|
||||
// ── LM Studio 선제적 컨텍스트 압축 ──
|
||||
// 소형 모델(4B 등)은 GPU 메모리 부족으로 n_ctx가 설정값보다 크게 줄어들 수 있고,
|
||||
// 이때 LM Studio는 에러 대신 200 OK + 빈 스트림을 반환하여 재시도 불가.
|
||||
// 따라서 전송 전에 선제적으로 메시지를 n_ctx에 맞게 압축합니다.
|
||||
if (engine === 'lmstudio') {
|
||||
const totalCharsRaw = finalMessages.reduce((acc, m) => acc + String(m.content || '').length, 0);
|
||||
const estimatedTokensRaw = Math.ceil(totalCharsRaw / 4);
|
||||
const LM_CTX_SAFE_LIMIT = 3500; // 4096 n_ctx 기준 안전 마진
|
||||
|
||||
if (estimatedTokensRaw > LM_CTX_SAFE_LIMIT) {
|
||||
logInfo('LM Studio proactive compression triggered.', {
|
||||
estimatedTokens: estimatedTokensRaw,
|
||||
limit: LM_CTX_SAFE_LIMIT,
|
||||
originalMessageCount: finalMessages.length
|
||||
});
|
||||
|
||||
// 1. system 메시지에서 [CONTEXT] 이후 부분을 우선 제거
|
||||
const sysIdx = finalMessages.findIndex(m => m.role === 'system');
|
||||
if (sysIdx >= 0) {
|
||||
const sysContent = String(finalMessages[sysIdx].content || '');
|
||||
const contextSplit = sysContent.indexOf('[CONTEXT]');
|
||||
if (contextSplit > 0) {
|
||||
// [CONTEXT] 이전까지만 유지 (기본 시스템 프롬프트 + 핵심 지시)
|
||||
const trimmedSys = sysContent.slice(0, contextSplit).trimEnd();
|
||||
finalMessages = finalMessages.map((m, i) =>
|
||||
i === sysIdx ? { ...m, content: trimmedSys + '\n[Context omitted: model context limit]' } : m
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 그래도 크면 시스템 프롬프트를 max 글자로 강제 잘라냄
|
||||
const afterTrimChars = finalMessages.reduce((acc, m) => acc + String(m.content || '').length, 0);
|
||||
const afterTrimTokens = Math.ceil(afterTrimChars / 4);
|
||||
if (afterTrimTokens > LM_CTX_SAFE_LIMIT && sysIdx >= 0) {
|
||||
// 유저 메시지 토큰 계산
|
||||
const nonSysTokens = finalMessages
|
||||
.filter((_, i) => i !== sysIdx)
|
||||
.reduce((acc, m) => acc + String(m.content || '').length, 0) / 4;
|
||||
const maxSysChars = Math.max(2000, (LM_CTX_SAFE_LIMIT - Math.ceil(nonSysTokens) - 512)) * 4;
|
||||
const sysContent = String(finalMessages[sysIdx].content || '');
|
||||
if (sysContent.length > maxSysChars) {
|
||||
finalMessages = finalMessages.map((m, i) =>
|
||||
i === sysIdx ? { ...m, content: sysContent.slice(0, maxSysChars) + '\n[Truncated for model context limit]' } : m
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 히스토리 메시지 정리: system + 마지막 user만 유지
|
||||
const finalCheck = finalMessages.reduce((acc, m) => acc + String(m.content || '').length, 0) / 4;
|
||||
if (finalCheck > LM_CTX_SAFE_LIMIT) {
|
||||
const sysMsg = finalMessages.find(m => m.role === 'system');
|
||||
const lastUserMsg = [...finalMessages].reverse().find(m => m.role === 'user');
|
||||
finalMessages = [
|
||||
...(sysMsg ? [sysMsg] : []),
|
||||
...(lastUserMsg ? [lastUserMsg] : [])
|
||||
];
|
||||
}
|
||||
|
||||
logInfo('LM Studio compression result.', {
|
||||
originalTokens: estimatedTokensRaw,
|
||||
compressedTokens: Math.ceil(finalMessages.reduce((a, m) => a + String(m.content || '').length, 0) / 4),
|
||||
messageCount: finalMessages.length
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const totalChars = finalMessages.reduce((acc, m) => acc + String(m.content || '').length, 0);
|
||||
const estimatedTokens = Math.ceil(totalChars / 4);
|
||||
const streamBody = {
|
||||
model: candidateModel,
|
||||
messages: finalMessages,
|
||||
messages: finalMessages.map(m => ({ role: m.role, content: m.content })),
|
||||
stream: true,
|
||||
...(engine === 'lmstudio'
|
||||
? { max_tokens: 4096, temperature }
|
||||
? { max_tokens: Math.min(4096, Math.max(256, 3500 - estimatedTokens)), temperature }
|
||||
: { options: { num_ctx: 32768, num_predict: 4096, temperature } }),
|
||||
};
|
||||
logInfo('AI streaming request started.', {
|
||||
|
||||
Reference in New Issue
Block a user