Tool Calling은 모델 기능이 아니라 애플리케이션 설계다

·4분 읽기
Tool Calling은 모델 기능이 아니라 애플리케이션 설계다

title: "Tool Calling은 모델 기능이 아니라 애플리케이션 설계다" slug: "spring-ai-2-tool-calling" status: "draft" series: "Spring AI 2.0 읽는 순서" order: 5 description: "Spring AI 2.0의 Tool Calling을 기준으로, 모델은 도구를 실행하는 것이 아니라 요청한다는 점과 안전한 도구 설계 원칙을 정리한 글." tags: ["Spring AI", "Tool Calling", "ChatClient", "Java", "LLM"] source_docs:

  • "downloads/spring-ai-reference-2.0-ko/api/tools.html"
  • "downloads/spring-ai-reference-2.0-ko/api/tools-migration.html"
  • "downloads/spring-ai-reference-2.0-ko/guides/dynamic-tool-search.html"

Tool Calling은 데모 영상에서 특히 화려해 보이는 기능이다.

모델이 검색도 하고, 일정도 만들고, 외부 API도 두드리는 모습을 보면 마치 모델이 애플리케이션을 직접 조종하는 것처럼 느껴진다. 하지만 Spring AI 문서를 따라가 보면 핵심은 훨씬 현실적이다.

모델은 도구를 실행하지 않는다. 어떤 도구를 어떤 인자로 써야 할지 요청할 뿐이다. 실제 실행, 권한 검증, 실패 처리, 결과 반영은 전부 애플리케이션 책임이다.

이 관점을 먼저 잡아야 Tool Calling을 과장 없이 이해할 수 있다.

왜 이 구분이 중요한가

Tool Calling을 “모델이 똑똑해지는 기능”으로만 보면 설계가 쉽게 흐려진다.

하지만 실제 서비스에서는 다음 질문이 먼저 나온다.

  • 어떤 도구를 모델에 공개할 것인가
  • 어떤 입력은 허용하고 어떤 입력은 막을 것인가
  • 읽기 전용 조회와 실제 액션을 어떻게 구분할 것인가
  • 결과를 모델에 그대로 넘길지, 정제해서 넘길지
  • 실패했을 때 재시도와 사용자 안내를 어떻게 할 것인가

즉 Tool Calling의 핵심은 모델 성능보다 애플리케이션 경계 설계에 있다.

Spring AI가 Tool Calling을 다루는 방식

Spring AI Tool Calling 기본 흐름
Spring AI는 도구 정의, 호출 결정, 실행 결과 주입을 하나의 애플리케이션 흐름으로 묶어 다룬다.

Spring AI 2.0 문서에서 눈에 띄는 변화는 예전 FunctionCallback 중심 감각에서, 더 명확한 ToolCallback API로 무게중심이 옮겨갔다는 점이다.

이 변화가 중요한 이유는 이름이 바뀌어서가 아니다. “함수 호출”이라는 느슨한 표현보다, 도구라는 명시적 계약으로 사고하게 만들기 때문이다.

문서 기준으로 보면 Spring AI는 크게 세 가지 방식으로 도구를 다룬다.

1) 메서드를 도구로 노출하는 방식

@Tool 같은 선언형 방식으로 기존 메서드를 도구처럼 공개할 수 있다.

이 접근의 장점은 분명하다.

  • 코드가 짧다.
  • 기존 서비스 메서드를 재사용하기 쉽다.
  • 도구 설명을 코드 가까이에 둘 수 있다.

처음 붙일 때 가장 이해하기 쉬운 방식이기도 하다.

2) MethodToolCallback / FunctionToolCallback로 프로그래밍 방식 구성

선언형만으로 부족할 때는 도구 정의와 실행 방식을 더 명시적으로 구성할 수 있다.

이 방식은 다음 상황에 잘 맞는다.

  • JSON 스키마를 세밀하게 통제하고 싶을 때
  • 도구 설명을 런타임에 조합해야 할 때
  • 여러 도구를 한곳에서 등록/필터링하고 싶을 때

즉 “도구가 몇 개 안 되는 간단한 앱”보다, 운영 중인 서비스에 점진적으로 AI 기능을 얹을 때 더 유용하다.

3) 동적 도구 검색

동적 도구 검색 기반 Tool Calling 흐름도
도구가 많아질수록 전체 목록을 항상 노출하기보다, 먼저 검색하고 필요한 정의만 문맥에 넣는 방식이 유리하다.

dynamic-tool-search 가이드에서 다루는 주제다. 모든 도구를 항상 모델에 다 보여 주는 대신, 현재 질문과 관련 있는 도구만 선택적으로 노출하는 방식이다.

이건 꽤 실무적이다.

도구가 늘어날수록 생기는 문제가 있기 때문이다.

  • 프롬프트가 길어진다.
  • 모델이 엉뚱한 도구를 고를 확률이 커진다.
  • 설명 토큰 비용이 커진다.
  • 보안상 필요 없는 도구까지 노출될 수 있다.

그래서 도구 카탈로그가 커지면, “전부 공개”보다 질문별로 도구 후보를 좁히는 설계가 더 낫다.

조회형 도구와 액션형 도구를 반드시 나눠야 한다

개인적으로 Tool Calling에서 가장 중요한 실무 원칙은 이것이다.

읽기 전용 도구와 실제 변경을 일으키는 도구를 한 덩어리로 다루지 말 것.

예를 들어 아래 둘은 위험도가 완전히 다르다.

  • 주문 상태 조회
  • 주문 취소 실행

모델은 둘 다 “적절해 보이면” 호출하려 할 수 있다. 하지만 애플리케이션은 달라야 한다.

조회형 도구

  • 검색
  • 상태 조회
  • 문서 검색
  • 내부 메타데이터 확인

이런 도구는 상대적으로 안전하다. 물론 개인정보나 권한 필터는 여전히 중요하지만, 기본적으로는 관측 성격이 강하다.

액션형 도구

  • 결제 취소
  • 일정 생성/삭제
  • 워크플로우 실행
  • 티켓 상태 변경

이런 도구는 호출 전 검증이 훨씬 엄격해야 한다.

예를 들면 이런 장치가 필요하다.

  • 필수 파라미터 검증
  • 사용자 권한 확인
  • idempotency 고려
  • 감사 로그 기록
  • 필요 시 사용자 확인 단계 추가

Tool Calling이 멋져 보인다고 해서 이 구분을 흐리면, 나중에 운영 리스크가 크게 커진다.

JSON Schema가 중요한 이유

도구 스키마와 실행 문맥
도구 설명과 입력 스키마가 명확할수록 모델이 잘못된 인자를 만들 가능성이 줄어든다.

Spring AI 문서에서 Tool Definition, JSON Schema, Result Conversion이 별도 섹션으로 나오는 이유도 여기 있다.

도구 호출은 결국 모델에게 “이 도구는 이런 입력을 받는다”는 계약을 설명하는 일이다. 스키마가 흐리면 다음 문제가 생긴다.

  • 모델이 엉뚱한 필드를 만든다.
  • 값 타입이 흔들린다.
  • 필수값이 빠진다.
  • 애매한 문자열이 들어온다.

그래서 도구 설계에서는 메서드 시그니처보다 입력 계약을 얼마나 명확히 설명하는가가 더 중요할 때가 많다.

returnDirect는 언제 유용한가

returnDirect 동작 방식
후속 모델 정리를 생략하고 바로 사용자에게 전달하는 응답은 `returnDirect`로 단순하게 처리할 수 있다.

문서에는 Return Direct 개념도 나온다. 어떤 도구 결과는 다시 모델이 장황하게 재서술하는 것보다, 도구 결과를 거의 그대로 사용자에게 돌려주는 편이 나을 수 있다.

예를 들면 이런 경우다.

  • 계산 결과
  • 구조화된 조회 결과
  • 내부 시스템이 이미 검증한 짧은 응답

반대로 설명이나 요약이 필요한 결과라면 모델을 한 번 더 거치는 편이 낫다.

즉 도구 결과는 항상 “모델이 다시 말하게 해야 한다”가 아니라, 도구 결과 자체가 최종 응답이 될 수 있는지도 판단해야 한다.

Tool Calling을 붙일 때 추천하는 최소 구조

Spring AI로 처음 Tool Calling을 붙인다면, 개인적으로는 이렇게 가는 편이 가장 안전하다.

1단계: 조회형 도구 1~2개만 붙인다

  • 날씨 조회
  • 주문 상태 조회
  • 내부 문서 검색

처음부터 상태 변경 도구를 넣지 않는 편이 좋다.

2단계: 입력 스키마를 최대한 좁힌다

  • 자유 입력을 줄인다.
  • enum이나 필수값을 명확히 둔다.
  • 날짜/ID 형식을 엄격히 검증한다.

3단계: 실행 로그를 남긴다

  • 어떤 도구가 선택됐는지
  • 어떤 인자가 들어왔는지
  • 실제로 성공했는지
  • 모델에 어떤 결과를 다시 넘겼는지

이 기록이 있어야 나중에 “왜 이런 답이 나왔는지”를 추적할 수 있다.

4단계: 그다음에 동적 도구 검색을 검토한다

도구 수가 커질 때만 붙여도 늦지 않다.

ChatClient와의 연결을 어떻게 보면 좋은가

Spring AI에서 Tool Calling은 별도 세계가 아니라 결국 ChatClient 흐름 안에 들어간다. 그래서 앞서 다룬 ChatClient 글과 자연스럽게 이어진다.

즉 구조는 보통 이렇게 읽으면 된다.

  • ChatClient가 대화 호출의 중심이다.
  • Advisors가 호출 전후 흐름을 감싼다.
  • Tool Calling은 모델이 외부 기능을 요청하는 경로다.
  • 애플리케이션은 그 요청을 실제 실행 가능한 도메인 작업으로 바꾼다.

이 시점부터는 “모델을 호출하는 앱”이 아니라, 모델이 애플리케이션 기능을 선택적으로 사용하게 하는 앱으로 성격이 바뀐다.

한 문장으로 정리하면

Spring AI의 Tool Calling은 모델에 마법 같은 실행 권한을 주는 기능이 아니라, 모델의 추론과 애플리케이션의 제어를 안전하게 연결하는 계약 계층이다.

그래서 중요한 것은 도구 개수를 늘리는 일이 아니라,

  • 도구 공개 범위를 줄이고
  • 입력 계약을 명확히 하고
  • 조회와 액션을 분리하고
  • 실행 로그와 권한 검증을 붙이는 것

이다.

마무리

Tool Calling은 분명 강력하다. 하지만 그 힘은 “모델이 다 해 준다”에서 나오지 않는다. 오히려 반대다. 애플리케이션이 해야 할 책임을 더 분명하게 구분해 주기 때문에 강력하다.

Spring AI 2.0 문서를 읽으면서 얻는 가장 실용적인 교훈도 여기 있다.

  • 모델은 도구를 요청한다.
  • 애플리케이션이 도구를 통제한다.
  • 안전성과 예측 가능성은 애플리케이션 설계에서 나온다.

다음 글에서는 이 흐름을 한 단계 더 넓게 보면서, 왜 Advisors를 이해해야 Spring AI 전체 설계가 보이기 시작하는지 정리해 보겠다.