ZORGAX 디버깅: Open WebUI부터 Ollama까지 AI 에이전트 툴 호출 루프 추적기
요약
본 글은 AI 에이전트(ZORGAX)가 툴 호출 루프에 빠지는 문제를 디버깅한 과정을 다룹니다. Open WebUI와 Ollama 환경을 비교하며, 빈 결과를 받았음에도 불구하고 에이전트가 툴 호출을 반복하는 현상을 추적했습니다. 최종적으로 적절한 툴 호출 반복 제한(tool-call iterations) 설정을 추가하여 이 문제를 해결할 수 있었습니다.
핵심 포인트
- AI 에이전트는 단순히 도구 호출 이상의 제어 흐름 이해가 필요합니다.
- Open WebUI와 Ollama 환경 간의 동작 차이를 비교하며 문제 원인을 분석했습니다.
- 디버깅 과정에서 Open WebUI의 툴 호출 반복 제한 설정을 발견하고 이를 최적화했습니다.
ZORGAX 디버깅: Open WebUI에서 Ollama까지 AI 에이전트 툴 호출 루프를 추적한 방법
재현 가능한 테스트와 기여자들을 위한 공개 초대를 담은, 증거 기반의 디버깅 이야기입니다.
AI 에이전트를 구축하는 것은 단순히 언어 모델이 도구를 호출하게 만드는 것 이상입니다. 모델이 언제 멈춰야 하는지 아는 것도 중요합니다.
MyZubster 생태계 내 로컬 DevOps AI 에이전트인 ZORGAX를 개발하던 중, 저는 툴 호출 문제를 발견했습니다. 어떤 자동화 기능들이 활성화되어 있는지 물었을 때, ZORGAX는 도구가 성공적인 빈 결과를 반환했음에도 불구하고 list_automations를 반복적으로 호출했습니다.
기대했던 동작은 간단했습니다:
list_automations호출.{"automations":[],"total":0}수신.- 사용자에게 자동화 기능이 활성화되어 있지 않다고 알림.
- 중지.
하지만 Open WebUI 통합에서는 때때로 인터럽트될 때까지 툴 호출을 반복했습니다.
저희는 Qwen2.5 3B에서 파생된 커스텀 ZORGAX 모델, Ollama, Open WebUI, Docker 및 임시 HTTP 진단 프록시를 사용하여 이 문제를 조사했습니다.
발견한 내용은 다음과 같습니다.
1. 첫 번째 단서: 직접 Ollama 사용 시 문제 없음
첫 실험에서는 Open WebUI를 우회했습니다.
어시스턴트 툴 호출과 일치하는 툴 결과를 포함하여 합성 대화를 Ollama의 /api/chat 엔드포인트로 전송했습니다.
결과는 우리가 원했던 것과 정확히 같았습니다:
Content: Non ci sono automazioni attive al momento.
Tool calls: []
Done: True
ZORGAX는 빈 결과를 이해하고 툴을 다시 호출하지 않은 채 최종 답변을 생성했습니다.
이것은 유용했지만, Open WebUI가 잘못되었다는 것을 증명하지는 못했습니다. 직접 테스트는 단순화된 시스템 프롬프트와 툴 스키마를 사용했기 때문입니다. 우리는 실제 통합 경로를 비교해야 했습니다.
2. Open WebUI를 통해 툴 결과 추적하기
이전 Coder Legion 아티클의 한 댓글 작성자가 더 정밀한 조사를 제안했습니다: 첫 번째 list_automations 결과 직후 요청을 포착하여 작동하는 Ollama 컨트롤과 비교하는 것이었습니다.
그것은 저희 디버깅의 방향을 바꾸어 놓았습니다.
우리는 설치된 Open WebUI 소스 코드를 검사하여 해당 툴 호출(tool-call) 지속 흐름을 파악했습니다.
미들웨어는 툴 실행 출력을 대화 메시지로 변환하며, 여기에는 어시스턴트의 tool_calls와 일치하는 role: tool 메시지가 포함됩니다.
단순히 소스 코드 검사에만 의존하기보다는, 무해한 테스트 환경(fixture)을 사용하여 실제 convert_output_to_messages() 함수를 추출하고 실행했습니다.
테스트 결과는 다음과 같습니다:
[
{
"role": "assistant",
...
변환 테스트는 성공적으로 완료되었습니다.
이는 우리가 격리된 빈 결과(empty-result) 케이스에 대해 이 함수가 기본적인 실패를 겪지 않았음을 의미할 뿐입니다. 모든 후속 네트워크 요청이 동일한 구조를 유지할 것이라는 것을 입증하지는 못했습니다.
3. 안전 제한 추가하기
또한, 조사했던 Open WebUI 빌드에는 기본적으로 256회의 툴 호출 반복(tool-call iterations) 제한이 있다는 것을 발견했습니다.
디버깅 목적으로는 이 수치가 필요 이상으로 높았습니다.
저희 테스트 환경에서는 다음과 같이 설정했습니다:
environment:
CHAT_RESPONSE_MAX_TOOL_CALL_ITERATIONS: "3"
설정을 적용한 후, 격리된 Open WebUI 실험을 통해 반복 호출이 재현되었고 다음 메시지와 함께 중단되었습니다:
Tool-call iteration limit reached (3)
이는 근본적인 원인 해결책이라기보다는 안전성 개선 조치였습니다. 단일 반복(iteration) 안에 여러 개의 툴 호출이 포함될 수 있으므로, 이 제한을 개별 호출의 정확한 상한선으로 해석해서는 안 됩니다.
4. 임시 진단 환경 구축하기
저희는 메인 MyZubster 인터페이스를 수정하는 대신 별도의 Open WebUI 인스턴스를 생성했습니다.
그리고 무해한 커스텀 툴을 추가했습니다:
"""
title: ZORGAX Automation Test
description: Safe automation-listing test fixture.
...
이 함수는 실제 자동화 목록을 읽거나, 데이터베이스를 건드리거나, 관리자 작업을 수행하는 일이 전혀 없습니다.
이러한 격리(isolation)가 중요합니다. 운영 툴을 가진 에이전트를 디버깅한다고 해서 프로덕션 인프라에 위험을 초래할 필요는 없기 때문입니다.
5. 실제 Ollama 요청 포착하기
다음으로, 진단용 Open WebUI 인스턴스와 Ollama 사이에 임시 HTTP 프록시를 도입했습니다.
프록시는 구조적 메타데이터(모델 이름, 메시지 역할, 툴 호출 ID, 툴 이름, 빈 결과 고정값 존재 여부)만 기록하면서 요청을 전달했습니다.
저희는 대화 프롬프트 전체와 인증 데이터를 저장하는 것을 의도적으로 피했습니다.
가장 흥미로운 관찰은 포착된 하나의 요청이 모델에 약 35개의 내장 툴을 노출했다는 점이었습니다.
이는 list_automations만 노출했던 성공적인 직접 Ollama 테스트와 상당히 달랐습니다.
하지만 이것만으로는 툴의 개수가 루프를 유발했다고 증명할 수는 없었습니다.
저희는 더 좁은 실험이 필요했습니다.
6. 성공적인 엔드투엔드(end-to-end) 실험
저희는 ZORGAX Diagnostic을 단일 사용자 정의 툴을 사용하도록 구성하고 관련 없는 내장 기능을 비활성화했습니다.
그런 다음 다음과 같이 요청했습니다:
Controlla quali automazioni sono attive usando
list_automations. Se non ce ne sono, dimmelo. (어떤 자동화가 활성화되어 있는지list_automations을 사용하여 확인하세요. 없다면 알려주세요.)
ZORGAX는 시뮬레이션된 툴을 호출하고 더 이상 활성화된 자동화가 없다고 응답했습니다.
더 중요한 것은, 프록시가 다음 내용을 포착했다는 것입니다:
Request 7
Model: zorgax:latest
Tools: [list_automations]
...
어시스턴트의 호출 식별자와 툴 결과가 보존되었고, 빈 결과가 Ollama로 향하는 다음 요청에 도달했습니다.
이러한 통제된 구성에서는 전체 상호작용이 작동했습니다.
이것이 저희가 가장 중요하게 확인한 발견입니다: Open WebUI는 성공적인 빈 툴 결과를 Ollama까지 전달하여 ZORGAX로부터 최종 응답을 얻을 수 있습니다.
7. 우리가 아직 증명하지 못한 것
너무 많은 툴을 노출하는 것이 원래의 루프를 유발했다고 결론짓기 쉽습니다.
하지만 이는 성급한 결론일 것입니다.
성공적이었던 실험과 실패했던 실험 모두 모든 변수를 일정하게 유지하지 않았습니다. 툴 가용성이 달랐고, 프롬프트 지침, 함수 스키마, 모델 매개변수, 샘플링 동작을 포함한 다른 요인들도 결과에 영향을 미칠 수 있습니다.
따라서 저희는 결정적인 설명이 아닌 강력한 디버깅 단서를 얻었습니다.
다음 목표는 모델 버전, 프롬프트, 툴 스키마 및 생성 옵션을 동일하게 유지한 상태에서 변수 하나씩만 변경하며 통제된 A/B 비교를 수행하는 것입니다.
또한 다음 세 가지 중요한 경우를 구별할 수 있는 회귀 테스트(regression tests)도 필요합니다:
- 툴이 성공적으로 빈 결과(empty result)를 반환하는 경우.
- 툴이 전송 또는 실행 오류(transport or execution error)로 실패하는 경우.
- 모델이 유효하지 않은 툴 인자(tool arguments)를 생성하는 경우.
빈 결과는 유효한 정보입니다. 오류와는 다릅니다.
8. 커뮤니티에 조사 내용 공개하기
저희는 이제 이 조사를 public MyZubster GitHub 저장소에 게시했습니다.
기술 재현 가이드(Technical reproduction guide):
기여자 조사 이슈(Contributor investigation issue):
[https://github.com/MyZubster-Ecosystem/myzubster/issues/1577]
기여 가이드라인(Contribution guidelines):
[https://github.com/MyZubster-Ecosystem/myzubster/blob/main/CONTRIBUTING.md]
기여자들은 자체 기계에서 문제를 재현하거나, 테스트용 데이터를 개선하고, 정제된 HTTP 페이로드(sanitized HTTP payloads)를 비교하거나, 회귀 테스트를 추가하거나, 관찰 가능성 및 오류 처리(observability and error handling)에 대한 변경 사항을 제안할 수 있습니다.
MyZubster VPS나 어떠한 프로덕션 자격 증명(production credentials)도 접근할 필요가 없습니다.
명확한 증거를 바탕으로 한 작고 집중적인 기여를 환영합니다.
9. 더 큰 교훈
툴 호출 루프는 단순히 “호출을 반복하지 마라”와 같은 추가 지침을 추가한다고 해서 항상 해결되는 문제는 아닙니다.
더 신뢰할 수 있는 접근 방식은 전체 시퀀스(sequence)를 검사하는 것입니다:
User request
↓
Assistant tool call
...
각 경계는 올바른 컨텍스트를 보존해야 합니다.
이번 조사를 통해 우리는 세 가지 질문을 분리하여 다루는 법을 배웠습니다:
툴이 실행되었는가?
결과가 다음 모델 요청에 도달했는가?
모델이 이를 받은 후 올바른 결정을 내렸는가?
이러한 질문들을 개별적으로 테스트해야만 잘못된 구성 요소를 탓하지 않고 에이전트 루프의 원인을 좁힐 수 있습니다.
ZORGAX의 다음 계획은 무엇인가?
ZORGAX는 모니터링, 진단 및 신중하게 권한을 부여받은 인프라 작업을 위한 믿을 수 있는 로컬 DevOps 어시스턴트가 되는 것을 목표로 합니다.
성공적인 단일 도구 실험은 중요한 이정표이지만, 원래의 루프 조사 작업은 여전히 진행 중입니다.
저희는 다른 사람들이 증거를 재현하고, 저희의 가정을 검증하며, 더 신뢰할 수 있는 에이전트를 구축하는 데 도움을 줄 수 있도록 그 작업을 공개적으로 계속 진행할 예정입니다.
Ollama, Open WebUI, Qwen 또는 로컬 AI 에이전트와 함께 작업하는 분이라면 언제든지 조사에 참여해 주십시오.
공개적으로 개발하고. 증거로 테스트하며. 인간의 통제를 유지하십시오.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기