Function Calling은 LLM(Large Language Model)이 단순한 자연어 응답을 넘어서 정의된 함수의 입력값을 예측하고 이를 호출하는 구조다. OpenAI 기준으로는 함수의 시그니처(JSON Schema 기반)를 사전에 LLM에 제공하면 LLM이 그에 맞는 파라미터를 추론해 결과값을 JSON 형태로 반환해준다.
즉, 사람이 명령을 내리면 LLM이 “이건 이런 함수를 호출하면 되겠네”라고 판단하고 적절한 파라미터를 구성해주는 구조다. 이후 실제 함수 호출은 백엔드에서 수행하고 결과를 다시 사용자에게 전달한다.
LLM은 자연어 이해에는 뛰어나지만 외부 시스템과의 직접적인 통신이나 계산은 수행하지 못한다.
예를 들어 다음과 같은 작업은 LLM이 혼자서 수행할 수 없다.
이때 Function Calling을 통해 LLM이 할 줄 모르는 일은 외부 함수에 위임하고 그 함수가 결과를 반환하면 다시 GPT가 자연어로 응답을 만들어주는 구조가 완성된다.
[1] 함수 시그니처 등록
→ name, description, parameters(JSON Schema)
[2] 사용자의 자연어 입력
[3] LLM이 호출해야 할 함수 판단 + 인자 예측
→ {"name": "getWeather", "arguments": { "location": "서울" }}
[4] 백엔드에서 실제 함수 실행
→ getWeather("서울") → "맑고 기온은 25도입니다"
[5] GPT에게 결과 전달 → 사용자 응답 생성
→ "오늘 서울은 맑고 기온은 25도입니다."
Function Calling은 다양한 실전 시나리오에서 활용될 수 있다. 대표적인 유스케이스는 다음과 같다:
LLM이 외부 API 또는 사내 지식 기반을 호출함으로써 단순한 문답 수준이 아닌 복잡한 컨텍스트 기반 응답을 생성할 수 있다. 예를 들어, “이번 주말에 비 와?”라는 질문에 날씨 API를 호출해 정확한 정보를 제공하거나 “OO상품 가격 알려줘”라는 요청에 내부 시스템 API를 통해 응답할 수 있다.
사용자가 작성한 문장에서 명명된 엔티티(NER), 감정(Positive/Negative), 키워드 등을 추출하여 JSON으로 구조화할 수 있다. 예: “이 제품 너무 별로예요” -> { sentiment: "negative", keywords: ["제품"] }
.
“12%의 이자를 3년 동안 계산해줘”처럼 GPT 혼자 처리하기 어려운 수학 로직을 외부 계산기 함수로 위임하고 결과만 응답으로 생성하는 방식으로 고급 계산도 가능하다.
GPT가 받은 자연어를 기준으로 실제 API 호출을 수행하는 구조를 설계할 수 있다. 예를 들어 “뉴욕의 환율 알려줘” -> getExchangeRate({ base: "USD", target: "KRW" })
처럼 외부 API를 연동하여 자동 호출하게 한다.
사용자의 질문에 따라 뉴스 기사 본문에서 주요 키워드, 관련 기사, 요약 정보 등을 추출하여 구조화된 데이터를 반환할 수 있다. GPT는 그 결과를 바탕으로 사용자에게 간결한 자연어 응답을 제공한다.
{
"name": "getWeather",
"description": "도시의 현재 날씨를 조회합니다",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "도시 이름 (예: Seoul)"
}
},
"required": ["location"]
}
}
GPT에게 함수 정의(functions
)와 유저 메시지를 함께 전달하면 LLM이 자동으로 적절한 함수와 파라미터를 판단한다.
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setBearerAuth(OPENAI_API_KEY);
headers.setContentType(MediaType.APPLICATION_JSON);
// 요청 메시지와 함수 스키마 포함
Map<String, Object> requestBody = Map.of(
"model", "gpt-4-0613",
"messages", List.of(
Map.of("role", "user", "content", "서울의 날씨 알려줘")
),
"functions", List.of(functionSchemaMap), // JSON Schema로 정의한 함수 목록
"function_call", "auto" // GPT가 적절한 함수 자동 선택
);
HttpEntity<Map<String, Object>> request = new HttpEntity<>(requestBody, headers);
ResponseEntity<Map> response = restTemplate.postForEntity(OPENAI_URL, request, Map.class);
GPT 응답 중 function_call
객체를 꺼내고 JSON 형식의 arguments를 파싱하여 실제 Java 메서드로 연결한다.
Map functionCall = (Map) ((Map)((List) response.getBody().get("choices")).get(0)).get("message");
String functionName = (String) functionCall.get("name");
String argumentsJson = (String) functionCall.get("arguments");
// JSON → 자바 Map 변환
ObjectMapper objectMapper = new ObjectMapper();
Map<String, String> args = objectMapper.readValue(argumentsJson, new TypeReference<>() {});
String location = args.get("location");
// 실제 함수 실행
String weather = weatherService.getWeather(location);
함수 실행 결과를 GPT에게 function
역할로 전달하면 GPT가 최종 사용자에게 보여줄 자연어 응답을 생성한다.
Map<String, Object> secondRequestBody = Map.of(
"model", "gpt-4-0613",
"messages", List.of(
Map.of("role", "user", "content", "서울의 날씨 알려줘"), // 원래 질문
Map.of("role", "function", "name", "getWeather", "content", weather) // 함수 실행 결과
)
);
HttpEntity<Map<String, Object>> secondRequest = new HttpEntity<>(secondRequestBody, headers);
ResponseEntity<Map> secondResponse = restTemplate.postForEntity(OPENAI_URL, secondRequest, Map.class);
// 최종 자연어 응답 추출
String finalMessage = (String) ((Map)((List) secondResponse.getBody().get("choices")).get(0)).get("message").get("content");
Function Calling은 LLM이 기존의 텍스트 생성기 역할을 넘어서 진짜 어플리케이션의 핵심 로직과 연결될 수 있는 통로라는 점에서 굉장히 인상 깊었다. 사용자의 입력을 받아 단순 응답을 출력하는 기존 방식보다 LLM이 상황에 따라 어떤 함수를 호출해야 할지 스스로 판단하게 만들 수 있다는 점에서 “자연어 -> 명령어”의 진정한 추상화가 가능해진 셈이다.
Java 백엔드 입장에서 보았을 때는 이 구조가 결국 비즈니스 로직을 LLM의 흐름에 맞게 오케스트레이션하는 작업이기 때문에 API의 유연성과 데이터 구조의 명확성이 중요하다고 느꼈다. 특히, JSON Schema를 LLM이 인지할 수 있도록 설계하고, 실제 함수 실행 -> 후처리 -> 응답 연결까지 책임 있게 처리해주는 아키텍처 구성 능력이 요구된다.
추천 시스템, 대화형 UI, 문서 요약기, 고객 지원 챗봇 등 다양한 도메인에서 LLM을 기능적으로 통합하고자 할 때 Function Calling은 핵심 키워드가 될 것이며 Java 기반의 기존 시스템과 연결하는 구체적인 방식은 앞으로도 많은 실험이 필요하겠지만 충분히 강력하고 실용적인 도구라고 느꼈다.
참고