AX Agent 진행 시간·글로우 경로 정리 및 최근 로컬 변경 일괄 반영
- AX Agent 스트리밍 경과 시간을 공용 helper로 통일해 비정상적인 수천만 시간 표시를 방지함 - 채팅 입력창 글로우를 런처와 같은 표시/숨김 중심의 얇은 외곽 글로우로 정리하고 런처 글로우 설정은 일반 설정에 유지함 - README와 DEVELOPMENT 문서를 2026-04-08 12:02 (KST) 기준으로 갱신하고 Release 빌드 경고 0 / 오류 0을 확인함
This commit is contained in:
@@ -539,14 +539,15 @@ public partial class AgentLoopService
|
||||
sendMessages = [.. messages, new ChatMessage
|
||||
{
|
||||
Role = "user",
|
||||
Content = "[TOOL_REQUIRED] 지금 즉시 도구를 1개 이상 호출하세요. 텍스트만 반환하면 거부됩니다. " +
|
||||
"Call at least one tool RIGHT NOW. Text-only response is rejected."
|
||||
Content = "[TOOL_REQUIRED] 지금 즉시 <tool_call> 형식으로 도구를 호출하세요. 텍스트만 반환하면 거부됩니다.\n" +
|
||||
"Output format:\n<tool_call>\n{\"name\": \"TOOL_NAME\", \"arguments\": {\"param\": \"value\"}}\n</tool_call>"
|
||||
}];
|
||||
}
|
||||
|
||||
// 워크플로우 상세 로그: LLM 요청
|
||||
llmCallSw.Restart();
|
||||
var (_, currentModel) = _llm.GetCurrentModelInfo();
|
||||
WorkflowLogService.SetCallContext(_conversationId, _currentRunId, iteration);
|
||||
WorkflowLogService.LogLlmRequest(_conversationId, _currentRunId, iteration,
|
||||
currentModel, sendMessages.Count, activeTools.Count, forceFirst);
|
||||
var streamedTextPreview = new StringBuilder();
|
||||
@@ -807,17 +808,14 @@ public partial class AgentLoopService
|
||||
"[System:ToolCallRequired] " +
|
||||
"⚠ 경고: 이전 응답에서 도구를 호출하지 않았습니다. " +
|
||||
"텍스트 설명만 반환하는 것은 허용되지 않습니다. " +
|
||||
"지금 즉시 도구를 1개 이상 호출하세요. " +
|
||||
"할 말이 있다면 도구 호출 이후에 하세요 — 도구 호출 전 설명 금지. " +
|
||||
"한 응답에서 여러 도구를 동시에 호출할 수 있고, 그렇게 해야 합니다. " +
|
||||
$"지금 사용 가능한 도구: {activeToolPreview}",
|
||||
"지금 즉시 아래 형식으로 도구를 호출하세요:\n" +
|
||||
"<tool_call>\n{\"name\": \"TOOL_NAME\", \"arguments\": {\"param\": \"value\"}}\n</tool_call>\n" +
|
||||
$"사용 가능한 도구: {activeToolPreview}",
|
||||
_ =>
|
||||
"[System:ToolCallRequired] " +
|
||||
"🚨 최종 경고: 도구를 계속 호출하지 않고 있습니다. 이것이 마지막 기회입니다. " +
|
||||
"지금 응답은 반드시 도구 호출만 포함해야 합니다. 텍스트는 한 글자도 쓰지 마세요. " +
|
||||
"작업을 완료하려면 도구를 호출하는 것 외에 다른 방법이 없습니다. " +
|
||||
"도구 이름을 모른다면 아래 목록에서 골라 즉시 호출하세요. " +
|
||||
"여러 도구를 한꺼번에 호출할 수 있습니다 — 지금 그렇게 하세요. " +
|
||||
"텍스트는 한 글자도 쓰지 마세요. 반드시 아래 형식으로 도구를 호출하세요:\n" +
|
||||
"<tool_call>\n{\"name\": \"TOOL_NAME\", \"arguments\": {\"param\": \"value\"}}\n</tool_call>\n" +
|
||||
$"반드시 사용해야 할 도구 목록: {activeToolPreview}"
|
||||
};
|
||||
messages.Add(new ChatMessage { Role = "user", Content = recoveryContent });
|
||||
@@ -850,15 +848,13 @@ public partial class AgentLoopService
|
||||
{
|
||||
1 =>
|
||||
"[System:ToolCallRequired] 계획을 세웠지만 도구를 호출하지 않았습니다. " +
|
||||
"계획은 이미 수립되었으므로 지금 당장 실행 단계로 넘어가세요. " +
|
||||
"텍스트 설명 없이 계획의 첫 번째 단계를 도구(tool call)로 즉시 실행하세요. " +
|
||||
"한 응답에서 여러 도구를 동시에 호출할 수 있습니다. " +
|
||||
"지금 당장 실행하세요. 아래 형식으로 도구를 호출하세요:\n" +
|
||||
"<tool_call>\n{\"name\": \"TOOL_NAME\", \"arguments\": {\"param\": \"value\"}}\n</tool_call>\n" +
|
||||
$"사용 가능한 도구: {planToolList}",
|
||||
_ =>
|
||||
"[System:ToolCallRequired] 🚨 도구 호출 없이 계획만 반복하고 있습니다. " +
|
||||
"이제 계획 설명은 완전히 금지됩니다. 오직 도구 호출만 하세요. " +
|
||||
"지금 이 응답에 텍스트를 포함하지 마세요. 도구만 호출하세요. " +
|
||||
"독립적인 작업은 한 번에 여러 도구를 병렬 호출하세요. " +
|
||||
"텍스트를 한 글자도 쓰지 마세요. 오직 아래 형식의 도구 호출만 출력하세요:\n" +
|
||||
"<tool_call>\n{\"name\": \"TOOL_NAME\", \"arguments\": {\"param\": \"value\"}}\n</tool_call>\n" +
|
||||
$"사용 가능한 도구: {planToolList}"
|
||||
};
|
||||
messages.Add(new ChatMessage { Role = "user", Content = planRecoveryContent });
|
||||
@@ -884,7 +880,8 @@ public partial class AgentLoopService
|
||||
messages.Add(new ChatMessage { Role = "user",
|
||||
Content = "html_create 도구를 호출하지 않았습니다. " +
|
||||
"document_plan 결과의 body 골격을 바탕으로 각 섹션에 충분한 내용을 채워서 " +
|
||||
"html_create 도구를 지금 즉시 호출하세요. 설명 없이 도구 호출만 하세요." });
|
||||
"지금 즉시 아래 형식으로 호출하세요:\n" +
|
||||
"<tool_call>\n{\"name\": \"html_create\", \"arguments\": {\"file_name\": \"...\", \"html_body\": \"...\"}}\n</tool_call>" });
|
||||
EmitEvent(AgentEventType.Thinking, "", $"html_create 미호출 재시도 {postDocumentPlanRetry}/{documentPlanRetryMax}...");
|
||||
continue; // 루프 재시작
|
||||
}
|
||||
@@ -1475,6 +1472,26 @@ public partial class AgentLoopService
|
||||
{
|
||||
failedToolHistogram.TryGetValue(effectiveCall.ToolName, out var failedCount);
|
||||
failedToolHistogram[effectiveCall.ToolName] = failedCount + 1;
|
||||
|
||||
// 같은 도구가 5회 이상 실패하면 해당 도구를 포기하고 LLM에 알림
|
||||
if (failedCount + 1 >= 5)
|
||||
{
|
||||
var abortMsg = $"도구 '{effectiveCall.ToolName}'이(가) {failedCount + 1}회 실패했습니다. 이 도구를 더 이상 호출하지 마세요. 다른 방법을 시도하거나 사용자에게 결과를 보고하세요.";
|
||||
EmitEvent(AgentEventType.Error, effectiveCall.ToolName, abortMsg);
|
||||
messages.Add(LlmService.CreateToolResultMessage(
|
||||
effectiveCall.ToolId, effectiveCall.ToolName, abortMsg));
|
||||
messages.Add(new ChatMessage { Role = "user", Content = abortMsg });
|
||||
continue;
|
||||
}
|
||||
|
||||
// 전체 실패 횟수가 총 도구 호출의 60% 이상이면 조기 중단
|
||||
var totalFails = failedToolHistogram.Values.Sum();
|
||||
if (totalToolCalls > 6 && totalFails > totalToolCalls * 0.6)
|
||||
{
|
||||
EmitEvent(AgentEventType.Error, "",
|
||||
$"전체 도구 호출 중 실패율이 높아 작업을 중단합니다 (실패 {totalFails}/{totalToolCalls})");
|
||||
return $"도구 실행 실패율이 높아 작업을 중단했습니다. {totalFails}개 실패 / {totalToolCalls}개 호출. 요청을 다시 시도하거나 작업 방식을 변경해 주세요.";
|
||||
}
|
||||
}
|
||||
|
||||
// UI 스레드가 이벤트를 렌더링할 시간 확보
|
||||
|
||||
Reference in New Issue
Block a user