IBM vLLM 도구 호출 스트리밍과 모델 프로파일 기반 실행 정책 강화
Some checks failed
Release Gate / gate (push) Has been cancelled

- IBM 배포형 도구 호출 바디에 프로파일 기반 tool temperature를 적용하고 tool_call_strict 프로파일에서 더 직접적인 tool-only 지시를 추가함
- IBM 경로가 tool_choice를 거부할 때 tool_choice만 제거한 대체 강제 재시도 경로를 추가함
- OpenAI/vLLM tool-use 응답을 SSE로 수신하고 delta.tool_calls를 부분 조립해 도구 호출을 더 빨리 감지하도록 변경함
- read-only 도구 조기 실행과 결과 재사용 경로를 도입해 Cowork/Code 도구 착수 속도를 개선함
- README와 DEVELOPMENT 문서를 2026-04-08 11:14(KST) 기준으로 갱신함

검증
- 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-08 16:48:11 +09:00
parent a2c952879d
commit 90ef3400f6
20 changed files with 1231 additions and 241 deletions

View File

@@ -287,6 +287,22 @@ public sealed class AxAgentExecutionEngine
&& !string.Equals(t, "Resumed", StringComparison.OrdinalIgnoreCase)
&& !string.Equals(t, "SessionStart", StringComparison.OrdinalIgnoreCase);
// 완료 메시지로 표시하면 안 되는 Thinking 이벤트 요약 패턴 (내부 진행 상태 문자열)
static bool IsInternalStatusSummary(string? summary)
{
if (string.IsNullOrWhiteSpace(summary)) return false;
return summary.StartsWith("LLM에 요청 중", StringComparison.OrdinalIgnoreCase)
|| summary.StartsWith("도구 미호출 루프", StringComparison.OrdinalIgnoreCase)
|| summary.StartsWith("강제 실행 유도", StringComparison.OrdinalIgnoreCase)
|| summary.StartsWith("읽기 전용 도구", StringComparison.OrdinalIgnoreCase)
|| summary.StartsWith("병렬 실행", StringComparison.OrdinalIgnoreCase)
|| summary.StartsWith("Self-Reflection", StringComparison.OrdinalIgnoreCase)
|| summary.StartsWith("일시적 LLM 오류", StringComparison.OrdinalIgnoreCase)
|| summary.StartsWith("컨텍스트 한도 초과", StringComparison.OrdinalIgnoreCase)
|| summary.Contains("반복 ") && summary.Contains('/')
|| summary.Contains("[System:");
}
var completionLine = runTab switch
{
"Cowork" => "코워크 작업이 완료되었습니다.",
@@ -310,9 +326,11 @@ public sealed class AxAgentExecutionEngine
: fileLine;
}
// 파일 없으면 가장 최근 의미 있는 이벤트 요약 사용
// 파일 없으면 가장 최근 의미 있는 이벤트 요약 사용 (내부 상태 문자열 제외)
var latestSummary = conversation.ExecutionEvents?
.Where(evt => !string.IsNullOrWhiteSpace(evt.Summary) && IsSignificantEventType(evt.Type))
.Where(evt => !string.IsNullOrWhiteSpace(evt.Summary)
&& IsSignificantEventType(evt.Type)
&& !IsInternalStatusSummary(evt.Summary))
.OrderByDescending(evt => evt.Timestamp)
.Select(evt => evt.Summary.Trim())
.FirstOrDefault();