우와한 개발자

[Spring AI] Tool Calling이란? — 함수 호출, JSON 스펙, @Tool, @ToolParam

by 우와한개발자

1. Tool Calling (Function Calling,함수 호출)

  • LLM이 단순히 텍스트를 생성하는 것을 넘어 외부 함수나 API를 호출할 수 있도록 하는 기능
  • 개발자가 함수를 미리 정의해두면 AI가 대화 맥락을 보고 스스로 판단해서 적절한 함수를 선택하고 호출한다
  • 개발자가 if/else로 직접 분기하지 않아도 된다
  • LLM은 답변은 만들 수 있지만 메일 발송, 예약, DB 조회 같은 실제 행동은 직접 못한다
  • 모델이 필요한 도구를 선택하고 정해진 JSON 형식으로 호출하게 하기 위해 등장했다

 

2. 동작 흐름

1) 전체 흐름

1. 개발자가 함수 정의 (JSON 스펙)
        ↓
2. 사용자 질문 + 함수 목록을 API에 전송
        ↓
3. AI가 판단: "이 질문엔 함수 호출이 필요한가?"
        ↓ (필요하다고 판단 시)
4. AI가 함수명 + 매개변수를 추출해서 반환
        ↓
5. 개발자 코드에서 실제 함수 실행
        ↓
6. 실행 결과를 다시 AI에 전달
        ↓
7. AI가 결과를 자연어로 최종 응답

 

2) AI가 판단하는 3가지 경우

상황 AI의 행동 예시
함수 호출이 필요 없을 때 텍스트로 바로 답변 "파이썬이 뭐야?" → 바로 설명
함수 호출이 필요할 때 함수명 + 인자를 반환 (직접 실행 X) "서울 날씨 알려줘" → get_weather("Seoul") 호출 요청
여러 함수가 동시에 필요할 때 여러 함수를 한 번에 요청 (Parallel Tool Calling) "서울이랑 도쿄 날씨 비교해줘" → get_weather("Seoul"), get_weather("Tokyo") 동시 호출 요청
  • AI는 함수를 직접 실행하지 않는다.
  • 어떤 함수를 어떤 값으로 호출할지 알려줄 뿐이고 실제 실행은 개발자 몫이다

 

3. 함수 정의

1) JSON 스펙

  • Tool Calling은 함수를 JSON 형식으로 정의해서 AI에 전달한다
  • AI는 name과 description을 읽고 언제 어떤 함수를 호출할지 판단한다
  • parameters에는 함수 호출에 필요한 매개변수와 설명을 정의한다
{
  "name": "get_weather",
  "description": "특정 도시의 현재 날씨를 가져온다",
  "parameters": {
    "type": "object",
    "properties": {
      "city": {
        "type": "string",
        "description": "날씨를 조회할 도시 이름"
      }
    },
    "required": ["city"]
  }
}

 

2) Spring AI — @Tool 어노테이션

  • Spring AI에서는 JSON 스펙을 직접 작성하지 않고 @Tool, @ToolParam 어노테이션으로 대체한다
  • Spring AI가 어노테이션을 읽어 JSON 스펙으로 자동 변환해서 AI에 전달한다
@Tool(name = "getWeather",
      description = "도시의 이름을 기반으로 현재 날씨 정보를 조회합니다.")
public WeatherResponse getWeather(
        @ToolParam(description = "날씨를 조회할 도시 이름을 영어로 작성하세요(예: Seoul, Tokyo)")
        String city) {
    // 외부 API 호출 로직
    return new WeatherResponse(city, weather, temperature);
}
  • @Tool : 메서드를 Tool로 등록. name과 description을 지정
  • @ToolParam : 매개변수 설명을 지정. AI가 어떤 값을 넣어야 할지 판단하는 근거가 된다

 

3) ChatClient에 등록

  • 정의한 Tool을 ChatClient에 등록하면 이후 모든 요청에서 AI가 Tool 호출 여부를 판단한다
ChatClient.builder(chatModel)
    .defaultTools(weatherTool)  // Tool 등록
    .build();

 

4. 주의사항

1) AI는 함수를 직접 실행하지 않는다

  • AI가 반환하는 것은 함수명과 매개변수뿐이다
  • 실제 실행은 개발자 코드에서 처리하고 결과를 다시 AI에 전달해야 한다

 

2) Lombok @RequiredArgsConstructor와 @Qualifier 충돌

  • @RequiredArgsConstructor는 Lombok이 생성자를 자동 생성할 때 필드에 붙은 @Qualifier를 생성자 파라미터에 복사하지 않는다
  • @Primary가 붙은 Bean이 의도치 않게 주입될 수 있다
  • 생성자를 직접 작성해서 @Qualifier를 명시해야 한다
public ChatService(
    @Qualifier("openAiChatClient") ChatClient openAiChatClient,
    @Qualifier("ollamaChatClient") ChatClient ollamaChatClient
) {
    this.openAiChatClient = openAiChatClient;
    this.ollamaChatClient = ollamaChatClient;
}

 

3) description 품질이 호출 정확도를 결정한다

  • AI는 description을 읽고 함수 호출 여부를 판단한다
  • 설명이 모호하면 불필요한 함수가 호출되거나 필요한 함수가 호출되지 않을 수 있다

 

4) 주요 활용 사례

  • 실시간 데이터 조회 : 날씨, 주가, 환율 등 LLM이 모르는 최신 정보
  • DB / API 연동 : 사용자 계정 조회, 주문 내역 검색
  • 복잡한 계산 : 날짜 계산, 통계 처리 등 LLM이 잘 틀리는 수치 연산
  • 외부 서비스 실행 : 이메일 발송, 캘린더 등록, 결제 처리

블로그의 정보

우와한개발자 님의 블로그

우와한개발자

활동하기