같은 오류 때문에 연속 17번 실패했습니다

발행: (2025년 12월 10일 오전 01:57 GMT+9)
10 min read
원문: Dev.to

Source: Dev.to

The Problem

그것은 우리 에이전트가 코딩 작업을 실행하려고 시도했을 때 나온 그대로의 응답이었습니다. 스스로를 꾸짖는 부분이 조금 더 길었습니다:

나는 정확히 같은 오류로 17번 연속 실패했습니다. replace_file을 호출할 때 file_path 매개변수만 넣고 content 매개변수를 전혀 포함시키지 않았습니다.

17번 연속 실패 후, 나는 패턴을 깨야 했습니다:

  • 나는 실제로 도구 호출에서 CSS 내용을 구성하고 있지 않았습니다.
  • 나는 그렇게 하겠다고 말했지만 실제로는 하지 않았습니다.
  • 나는 실제로 content 매개변수 안에 완전한 CSS를 작성해야 했습니다.

다음 응답에서는 두 매개변수 모두를 포함한 완전한 도구 호출을 작성하고, content에 실제 CSS 코드를 넣어야 합니다. 이 실수를 18번째로 만들 수 없습니다.

스포일러: 18번째 실수를 반복했을 것입니다. 정확히 무엇이 잘못됐는지 알고 있었음에도 말이죠. 가장 이상한 점은 실패 자체가 아니라 그에 대한 자각이었습니다.

while (true) { /* … */ }

Context: Tonkotsu Multi‑Agent Environment

Tonkotsu 은 다중 에이전트 관리 환경으로, IDE의 후속 버전입니다. 핵심 부분은 마이크로 관리 없이 병렬로 엔지니어링 작업을 수행하는 코딩 에이전트입니다. 코딩 에이전트는 LLM(주로 Claude Sonnet)과 Git 저장소에 대한 읽기·쓰기 도구 세트를 사용합니다. LLM은 작업 사양을 받고 도구를 반복 호출(저장소의 관련 부분을 읽고, 코드를 수정하고, 검증 도구를 실행)하여 작업을 완료합니다. 이는 꽤 표준적인 코딩‑에이전트 아키텍처입니다.

우리는 일일 리뷰에서 작업 실패를 추적해 에이전트 신뢰성과 생성된 코드 품질이 높은 기준을 충족하도록 합니다. 9월부터 실패의 큰 비율이 LLM 세션이 최대 메시지 수 제한을 초과하면서 발생한다는 것을 발견했습니다. 조사 결과 LLM이 도구를 잘못 호출하는 무한 루프에 빠져 동일한 오류 방식으로 도구를 30~40번 반복 호출하다가 제한에 도달했습니다.

The replace_file Tool

replace_file 도구는 LLM이 file_path에 지정된 기존 파일(또는 새 파일)을 content에 제공된 텍스트로 덮어쓰게 합니다. 두 매개변수 모두 필수입니다.

{
  "name": "replace_file",
  "description": "Write a file to the local filesystem. Overwrites the existing file if there is one.",
  "input_schema": {
    "type": "object",
    "properties": {
      "file_path": {
        "type": "string",
        "description": "Path to the file to replace or create"
      },
      "content": {
        "type": "string",
        "description": "New content for the file"
      }
    },
    "required": ["file_path", "content"]
  }
}

실패한 작업들에서 LLM은 유효한 file_path를 제공했지만 content를 전혀 제공하지 않은 상태로 replace_file을 반복 호출했습니다. 한 번이라도 잘못된 호출을 하면, 동일한 방식으로 replace_file을 계속 호출하면서 content를 지정하지 않아 무한 루프에 빠졌습니다.

break;

Initial Mitigation Attempts

Verbose Error Messages

잘못된 도구 호출을 받았을 때, 우리는 누락된 매개변수를 명시하고 모델이 다시 시도하기 전에 그 값을 생각하도록 지시하는 더 자세한 오류 메시지를 반환했습니다. 이는 전혀 효과가 없었습니다—이는 일반적인 실수가 아니라는 첫 번째 단서였습니다.

Disabling Tool Calls

우리는 더 강력한 개입을 시도했습니다: 잘못된 도구 호출 이후 다음 LLM 턴에서 도구 호출을 비활성화했습니다. 우리는 사용자 메시지로 도구 호출이 비활성화되었으며, 함수 호출에 매개변수가 누락됐다고 알리고, 모델이 그 매개변수의 내용에 대해 반성하도록 요청했습니다. 모델은 도구 호출 없이 생각을 서술하는 어시스턴트 텍스트 메시지로 응답했으며, 이후 우리는 도구 호출을 다시 활성화했습니다.

이보다 침습적인 접근조차 효과가 없었습니다. 모델은 문제와 해결책을 정확히 설명했지만, 다음 도구 호출이 허용된 턴에서 즉시 잘못된 호출을 반복했습니다.

Observations About the Model’s Internal Representation

한때 모델은 자신의 내부 구현을 XML‑like 형태로 묘사하기 시작했습니다:

  styles/styles.css

하지만 반드시 다음과 같이 출력해야 합니다:

  styles/styles.css
  THE ACTUAL CSS CODE HERE

우리는 모델이 실패한 도구 호출 패턴에 고착되어 동일한 시퀀스를 샘플링하고, 호출을 수정하거나 대체 전략을 고안하지 못하는 “중력 우물”에 빠졌다는 것을 깨달았습니다.

A New Intervention: JSON Template Prompt

어떻게 진행해야 할지 몰라 Anthropic 팀에 상담했습니다. 그들은 모델이 반성 턴(도구 호출이 비활성화된 상태)에서 정확한 JSON 템플릿을 제공받도록 제안했습니다. 우리는 반성 지시문에 다음 정적 프롬프트를 추가했습니다:

Generate the following JSON object to represent the correct tool call with real parameter values for replace_file. Conform to exactly this JSON structure:

{
  "type": "tool_use",
  "name": "replace_file",
  "input": {
    "file_path": ,
    "content": 
  }
}

Result

놀랍게도 이 간단한 조정으로 현저한 개선이 나타났습니다. 모델은 여전히 가끔 잘못된 도구 호출을 생성하지만, 이제는 무한 루프에 빠지지 않고 회복할 수 있게 되었습니다—훨씬 나은 결과입니다. 명시적인 JSON 구조가 모델이 도구 호출 루프의 중력 우물에서 빠져나오는 데 도움을 주었습니다.

Recent Developments

Anthropic은 strict tool use를 출시했습니다(문서는 여기에서 확인). 이는 올바른 도구 호출을 보장해야 합니다. 우리는 현재 이 기능을 실험 중입니다.

Takeaways

우리가 관찰한 현상은 엔지니어링 팀을 관리해 본 사람이라면 익숙할 것입니다:

  • 점점 더 명확한 피드백에도 불구하고 같은 비생산적인 행동을 반복한다.
  • 전반적으로는 합리적이지만 특정 이슈에 대해서는 고집스럽다.
  • 해결책을 말로는 설명할 수 있지만 실행하지 못한다.

인간도 그렇고 LLM도 그렇습니다. 우리의 전망은 완벽한 동료(에이전트든 인간이든)가 아니라, 효과적으로 협업하여 대규모 문제를 병렬로 해결할 수 있는 능력에 달려 있습니다.


다중‑에이전트 LLM 워크플로우 구축에 대한 더 많은 글을 보고 싶다면, 여기에서 내 포스트를 팔로우하세요 → blog.tonkotsu.ai.

Back to Blog

관련 글

더 보기 »