LLM은 여러분의 코드에 직접 접근하지 않습니다. 대신 요청을 전달할 뿐이며, 함수를 실행하는 것은 여러분입니다. 이 단순한 사실은 “모델이 마법처럼 내 Python 루틴을 호출한다”는 신화를 뒤집으며, 개발자들이 디버깅과 보안을 다시 생각하게 만듭니다.

디스패치 루프(dispatch loop), 단계별 과정

언어 모델(LLM)이 도구가 필요할 때, 다음과 같은 결정론적 시퀀스를 따릅니다:

  1. 계획(Planning) – 모델이 작업이 필요하다고 결정합니다 (예: “결제 환불”).
  2. 요청 생성(Generating a request) – 도구의 이름과 인수를 포함한 구조화된 텍스트(주로 JSON)를 출력합니다.
  3. 파싱(Parsing) – 애플리케이션이나 지원 프레임워크가 해당 텍스트를 읽습니다.
  4. 매칭(Matching) – 프레임워크가 노출된 실제 함수 레지스트리에서 해당 이름을 찾습니다.
  5. 검증(Validating) – 인수가 함수의 스키마와 일치하는지, 호출자가 권한을 가지고 있는지 확인합니다.
  6. 실행(Executing) – 매칭된 함수가 사용자의 환경에서 실행되어 작업을 수행합니다.
  7. 반환(Returning) – 결과가 패키징되어 추가 추론을 위해 모델로 다시 전송됩니다.

LLM은 기획자, 프레임워크는 디스패처(dispatcher), 그리고 함수는 실제로 데이터나 자금을 움직이는 작업자로 생각하십시오.

'마법'이라는 신화가 지속되는 이유

대부분의 개발자는 함수 호출처럼 보이는 모델 출력의 한 줄을 보고 모델이 직접 작업을 수행했다고 가정합니다. 제공업체의 문서에 등장하는 “tool calling”이라는 용어는 마치 모델이 코드를 직접 호출하는 것처럼 들립니다.

실제로 모델은 호출을 설명하는 텍스트를 생성할 뿐입니다. 조회, 타입 체크, 권한 강제, 에러 처리와 같은 힘든 작업은 여러분의 프로세스가 담당합니다.

내부 구현을 숨겨주는 프레임워크

PydanticAILangChain과 같은 라이브러리는 비즈니스 로직에 집중할 수 있도록 이 루프를 추상화합니다. 이들은 자동으로 다음을 수행합니다:

  • 스키마(예: Pydantic 모델)를 기준으로 인수를 검증합니다.
  • 사용자가 도구를 트리거할 수 있는지 확인하여 권한을 강제합니다.
  • 도구가 에러를 반환할 경우 모델로 다시 돌아가 실패 시 재시도합니다.
  • 연속적인 도구 호출 횟수를 제한하여 제어 불능의 루프(runaway loops)를 방지합니다.
  • 도구 결과를 대화에 결합하여 대화 상태를 유지합니다.

이러한 도우미를 사용하더라도 패턴은 동일합니다. 모델은 결코 코드를 실행하지 않습니다.

제공업체의 네이티브 도구 호출(tool-calling) 지원

일부 제공업체는 도구 정의와 요청 형식을 표준화한 “네이티브” 도구 호출 인터페이스를 제공합니다. 이는 통합을 원활하게 하지만 디스패치 단계를 제거하지는 않습니다. 요청된 작업을 실제로 실행하는 코드는 여전히 여러분이 작성(또는 임포트)해야 합니다.

문제의 이름을 바꾸면 디버깅이 쉬워집니다

“혼란에 빠진 에이전트”를 탓하는 대신, 문제가 “모델 응답에 도구 호출이 포함되지 않았다”라고 말하십시오. 이 차이는 매우 중요합니다:

  • 도구 호출 없음 (No tool call) – 모델이 직접 답변했거나 올바른 형식의 요청을 생성하는 데 실패했습니다.
  • 잘못된 형식의 요청 (Malformed request) – JSON 문법이 틀렸거나 필수 필드가 누락되어 디스패처가 요청을 거부했습니다.
  • 검증 실패 (Validation failure) – 인수가 스키마와 일치하지 않아 실행 전에 에러가 발생했습니다.

실패를 범주화하면 루프의 각 단계를 로그로 남기고 어디서 문제가 발생했는지 정확히 찾아낼 수 있습니다.

신뢰할 수 있는 파이프라인을 위한 실무 팁

  • 모델 출력을 신뢰할 수 없는 입력값으로 취급하십시오. 부수 효과(side-effect)를 일으키는 코드를 호출하기 전에 모든 요청을 결정론적인 검증 과정을 거치게 하십시오.
  • 원시 요청(raw request)과 각 검증 단계의 결과를 로그로 남기십시오. 이는 문제가 발생했을 때 재현 가능한 추적 경로를 만들어 줍니다.
  • 연속적인 도구 호출에 명시적인 제한을 설정하십시오. 제어 불능의 루프는 리소스를 고갈시키거나 속도 제한(rate limits)에 걸릴 수 있습니다.
  • 각 함수를 try/except 블록으로 감싸십시오. 모델이 이해할 수 있는 구조화된 에러 객체를 반환하여 재시도나 우아한 폴백(fallback)을 유도하십시오.
  • 권한 확인을 비즈니스 로직과 분리하십시오. 특히 “사용자 삭제”와 같은 권한이 필요한 작업의 경우, 함수가 실행되기 전에 호출자의 권한을 확인하십시오.
  • 스키마 기반 정의(예: Pydantic 모델)를 사용하십시오. 이를 통해 프레임워크가 모델이 따라야 할 JSON 스키마를 자동으로 생성할 수 있습니다.

향후 주목해야 할 점

제공업체들이 네이티브 도구 호출 API를 개선함에 따라, 요청 형식에 대한 더 엄격한 규약과 더 풍부한 에러 코드가 등장할 것입니다. 이러한 변화는 검증을 더 쉽게 만들고 개발자가 더 강력한 보안 울타리를 구축할 수 있게 해줄 것입니다. 많은 라이브러리가 최신 제공업체 기능을 위한 내장 지원을 추가하고 있으므로 라이브러리 업데이트를 계속 주시하십시오.

핵심 요약

LLM은 정교한 텍스트 생성기일 뿐, 실행기가 아닙니다. 작업을 수행하는 유일한 권한은 여전히 귀하의 코드에 있으며, 직접 구축하거나 가져온 디스패처(dispatcher)는 해당 작업을 검증, 승인 및 실행하는 게이트키퍼(gatekeeper) 역할을 합니다. 워크플로우를 재정의하면 '마법'이라는 환상을 제거하고, 디버깅을 명확히 하며, 모든 운영 시스템에 필요한 보안 규율을 확립할 수 있습니다.