LLM의 도구 호출(Tool Calling) 이해하기 – REST 및 Spring AI를 활용한 단계별 예제
요약
LLM의 도구 호출(Tool Calling) 원리를 REST API와 Spring AI를 통해 단계별로 설명합니다. 모델이 함수 인자를 추출하고 실행 결과를 다시 전달받아 최종 응답을 생성하는 전체 워크플로우를 다룹니다.
핵심 포인트
- 도구 호출의 개념과 작동 원리 이해
- REST API를 이용한 단계별 데이터 흐름 분석
- Spring AI를 활용한 도구 호출 구현 단순화 방법
LLM의 도구/함수 호출(Tool/Function Calling) 이해하기 (REST 및 Spring AI 단계별 예제)
| 원시 REST(raw REST)부터 우아한 Spring AI 어노테이션(annotations)까지, OpenAI 스타일의 도구 호출을 구현하는 방법을 배워보세요. 실제 코드, 다이어그램 및 엔드 투 엔드(end-to-end) 흐름을 포함합니다.
🧠 LLM 도구 호출(Tool Calling)이란 무엇인가?
LLM은 대화에는 뛰어나지만, 여러분의 데이터에 대해서는 알지 못합니다.
LLM은 여러분의 재고, API, 또는 시스템이 어떻게 작동하는지 알지 못합니다. 하지만 만약 LLM이 여러분의 함수를 호출하거나, 실시간 SQL을 실행하거나, 내부 서비스를 트리거할 수 있다면 어떨까요?
그것이 바로 도구 호출(tool calling)이 가능하게 하는 것입니다. 이 블로그에서는 다음 내용을 다룹니다:
- 🔧 LLM 도구 호출이 작동하는 방식 (원시 REST를 통한 단계별 과정)
- 📊 다단계 추론(multi-step reasoning)을 처리하는 방식
- ✅ 그리고 Spring AI가 이 모든 것을 어떻게 단순화하는지
🔧 도구 호출(Tool Calling)이란 무엇인가?
도구 호출(이전에는 "함수 호출 (function calling)"으로 불림)을 통해 LLM은 다음과 같이 말할 수 있습니다:
"직접 답변할 수는 없지만, 이 인자(arguments)들을 사용하여 이 함수를 호출하고 싶습니다."
여러분이 함수를 실행하고 그 결과를 다시 보내면, 모델은 이를 최종 응답에 포함시킵니다.
🛠 REST API를 통한 도구 호출 (단계별 과정)
사용자가 다음과 같이 질문한다고 가정해 봅시다:
"AirPods Pro 재고가 있나요?"
📤 1단계: 프롬프트(Prompt) + 도구 정의(Tool Definitions) 전송
이는 LLM 제공업체의 chat/completions 엔드포인트(endpoint)로 보내는 POST 요청입니다:
{
"model": "your-model-id",
"messages": [
{ "role": "user", "content": "Do you have AirPods Pro in stock?" }
],
"tools": [
{
"type": "function",
"function": {
"name": "findProductByName",
"description": "Finds a product by name or description",
"parameters": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "Product name or keyword"
}
},
"required": ["name"]
}
}
}
],
"tool_choice": "auto"
}
🧠 2단계: 모델의 도구 호출 응답
{
"choices": [
{
"message": {
"tool_calls": [
{
"id": "abc123",
"function": {
"name": "findProductByName",
"arguments": "{"name":"AirPods Pro"}"
},
"type": "function"
}
]
}
}
]
}
✅ 모델은 여러분이 findProductByName 함수를 실행하기를 원합니다.
🏃 단계 3: 함수 실행 (Execute the Function)
예제 Java 로직:
List<Product> result = productService.findByName("AirPods Pro");
이를 JSON으로 직렬화합니다:
`{
"name": "AirPods Pro",
"price": 249,
"stock": 5
}`
📥 단계 4: 도구 결과 전송 (Send Tool Result Back)
{
"messages": [
{
"role": "user",
"content": "AirPods Pro 재고가 있나요?"
},
{
"role": "assistant",
"tool_calls": [
{
"id": "abc123",
"function": {
"name": "findProductByName",
"arguments": "{\"name\":\"AirPods Pro\"}"
}
}
],
{
"role": "tool",
"tool_call_id": "abc123",
"content": "{\"name\":\"AirPods Pro\",\"price\":249,\"stock\":5}"
}
],
"tool_choice": "auto",
"tools": [ /* 동일한 도구 정의 */ ]
}
💬 단계 5: 모델의 최종 답변 (Final Answer from the Model)
{
"choices": [
{
"message": {
"content": "네, AirPods Pro 재고가 있으며 가격은 $249이고 5개가 있습니다."
}
}
]
}
🎉 이것이 완전한 도구 호출 루프입니다.
🖼️ 다이어그램: 단일 도구 호출 (Single Tool Call)
LLM은 하나의 도구를 선택하고 매개변수와 함께 함수를 호출합니다.
⚡ 다중 도구 호출 (Multi-Tool Calls) — “AirPods 또는 Galaxy Buds?”
모델이 여러 요구사항을 식별하면, 이를 병렬로 여러 도구 호출을 반환합니다.
🧠 순차적 추론 (Sequential Reasoning) — 동적 SQL 생성 (Dynamic SQL Generation)
모델은 단계별로 추론합니다: 테이블 목록화, 스키마 가져오기, 그리고 SQL 실행.
😩 수동으로 처리하기 어려운 점은 무엇일까요?
- JSON 스키마 작성
- 각 호출에 대한
tool_call_id추적 - 모든 인자 구문 분석 및 바인딩 - 응답 직렬화 (Serialize responses back)
- 다중 도구 오케스트레이션 처리
- 대화 기록 유지
- 라우팅을 위한 시스템 프롬프트 주입
- 오류 포착 및 재시도 깔끔하게 처리
유연하지만, 무겁고 취약합니다.
✅ Spring AI — 동일 프로토콜, 제로 글루 코드 (Zero Glue Code)
Spring AI는 동일한 REST 프로토콜을 사용하지만, 여러분이 직접 코드를 작성할 필요가 없습니다.
👇 이것만 작성하세요:
@Tool(description = "이름 또는 설명으로 제품 찾기")
public String findProductByName(
@ToolParam(description = "제품 이름", required = true)
String name
) {
List<Product> products = productService.findByName(name);
return new ObjectMapper().writeValueAsString(products);
}
컨트롤러에서:
@PostMapping("/chat")
public ChatBotResponse chatWithInventory(@RequestBody ChatBotRequest req) {
Prompt prompt = new Prompt(List.of(new UserMessage(req.question())));
String answer = ChatClient.builder(llmModel)
.defaultTools(productTools)
.build()
.prompt(prompt)
.call()
.content();
return new ChatBotResponse(req.question(), answer);
}
✅ Spring AI가 처리해주는 것들
- ✅ 도구 스키마 생성 (Tool schema generation)
- ✅ 인자 바인딩 (Argument binding)
- ✅
tool_call_id매핑 - ✅ 메시지 상태 관리 (Message state management)
- ✅ 병렬 도구 오케스트레이션 (Parallel tool orchestration)
- ✅ 순차적 도구 라우팅 (Sequential tool routing)
- ✅ Spring Boot DI, 유효성 검사 및 관찰 가능성 (observability)
- ✅ OpenAI, Mistral, Gemini 등과 호환
여러분은 비즈니스 로직을 작성하는 데만 집중하세요. Spring AI가 나머지 모든 것을 연결해줍니다.
🔌 보너스: MCP를 통한 도구 호출 — 추가 코드 불필요
도구가 단순한 채팅을 넘어 다른 에이전트나 프론트엔드 클라이언트 내부에서 작동해야 하나요?
Spring AI가 이를 손쉽게 만듭니다. MCP 서버 스타터만 추가하세요:
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-mcp-server-spring-boot-starter</artifactId>
</dependency>✅ 정의하는 모든 @Tool 메서드가 추가 코드 없이 MCP를 준수하는 엔드포인트가 됩니다. MCP 서버 설정에서 작은 구성(예: type: stdio 또는 type: sse)만 추가하면 됩니다.
YAML도, 코드 생성(codegen)도, 새로운 어노테이션도 필요 없습니다.
이를 통해 Model Context Protocol (MCP)을 사용하는 모든 클라이언트나 플랫폼과 즉각적인 상호 운용성을 확보할 수 있습니다.
🔁 대부분의 프레임워크(Python 포함)에서 MCP 도구와 LLM 도구는 별도로 정의됩니다. ✅ Spring AI에서는 @Tool 메서드가 둘 다이므로 중복이나 추가 연결 작업이 필요 없습니다.
대부분의 다른 프레임워크는 LLM 도구와 상호 운용 가능한 MCP 도구를 분리하여 취급합니다. — Spring AI가 이를 네이티브하게 연결해줍니다.
📘 더 깊게 파고들기 — 책에서 전체 예제 확인하기
본 블로그는 다음 장을 기반으로 합니다:
도구 호출 (Tool Calling) in:
확인할 수 있는 내용:
- 🔍 완전한 REST 우선 (REST-first) 도구 호출 (Tool Calling) 구현
- 🧱 로우 레벨 (Raw) 요청/응답 (request/response) 처리
- 🧠 시스템 프롬프트 라우팅 (system prompt routing)을 활용한 SQL 체이닝 (SQL chaining)
- ✅ 깔끔한
@Tool로직을 활용한 Spring AI 추상화 (abstraction) - 🧪 소스 코드가 포함된 세 가지 전체 예제
AI 자동 생성 콘텐츠
본 콘텐츠는 HN Claude Code Search의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기