vLLM 모델 해석 및 max_tokens 상한 보정
Some checks failed
Release Gate / gate (push) Has been cancelled

vLLM 연결 시 등록 모델 alias와 실제 모델 ID가 섞여 payload로 전달되던 경로를 보정해 RegisteredModel에서 실제 모델명을 우선 찾아 요청에 사용하도록 수정했다.

OpenAI-compatible 일반 대화와 도구 호출 모두 vLLM 서버 허용 범위를 넘지 않도록 max_tokens를 자동 보정하도록 통일했다.

검증: dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify\\ -p:IntermediateOutputPath=obj\\verify\\ (경고 0, 오류 0)
This commit is contained in:
2026-04-05 21:40:43 +09:00
parent 5765888229
commit 53afdb3472
4 changed files with 32 additions and 4 deletions

View File

@@ -225,7 +225,7 @@ public partial class LlmService
return new
{
model = activeModel,
max_tokens = Math.Max(llm.MaxContextTokens, 4096),
max_tokens = ResolveOpenAiCompatibleMaxTokens(),
temperature = llm.Temperature,
system = systemPrompt,
messages = msgs,
@@ -237,7 +237,7 @@ public partial class LlmService
return new
{
model = activeModel,
max_tokens = Math.Max(llm.MaxContextTokens, 4096),
max_tokens = ResolveOpenAiCompatibleMaxTokens(),
temperature = llm.Temperature,
messages = msgs,
tools = toolDefs,
@@ -661,7 +661,7 @@ public partial class LlmService
["tools"] = toolDefs,
["stream"] = false,
["temperature"] = ResolveTemperature(),
["max_tokens"] = llm.MaxContextTokens,
["max_tokens"] = ResolveOpenAiCompatibleMaxTokens(),
};
var effort = ResolveReasoningEffort();
if (!string.IsNullOrWhiteSpace(effort))

View File

@@ -249,10 +249,32 @@ public partial class LlmService : IDisposable
var llm = _settings.Settings.Llm;
var service = NormalizeServiceName(llm.Service);
if (service is "ollama" or "vllm" && !string.IsNullOrEmpty(llm.Model))
{
var registered = FindRegisteredModel(llm, service, llm.Model);
if (registered != null)
{
var registeredModelName = CryptoService.DecryptIfEnabled(registered.EncryptedModelName, llm.EncryptionEnabled);
if (!string.IsNullOrWhiteSpace(registeredModelName))
return registeredModelName;
}
return CryptoService.DecryptIfEnabled(llm.Model, llm.EncryptionEnabled);
}
return llm.Model;
}
private int ResolveOpenAiCompatibleMaxTokens()
{
var llm = _settings.Settings.Llm;
var requested = Math.Clamp(llm.MaxContextTokens, 1, 1_000_000);
var service = NormalizeServiceName(llm.Service);
if (service == "vllm")
return Math.Min(requested, 8192);
return requested;
}
/// <summary>
/// 현재 활성 모델에 매칭되는 RegisteredModel을 찾아 엔드포인트/API키를 반환합니다.
/// RegisteredModel에 전용 서버 정보가 있으면 그것을 사용하고, 없으면 기본 설정을 사용합니다.
@@ -648,7 +670,7 @@ public partial class LlmService : IDisposable
["messages"] = msgs,
["stream"] = stream,
["temperature"] = ResolveTemperature(),
["max_tokens"] = llm.MaxContextTokens
["max_tokens"] = ResolveOpenAiCompatibleMaxTokens()
};
var effort = ResolveReasoningEffort();
if (!string.IsNullOrWhiteSpace(effort))