OpenAI Function Calling으로 챗봇에 외부 API 연동하기
배경
사내 고객 지원팀에서 반복적인 문의 처리를 자동화하고 싶다는 요청이 들어왔다. ChatGPT API로 간단한 챗봇을 만들었지만, 실시간 정보 조회나 DB 검색이 필요한 질문은 처리할 수 없었다.
6월에 공개된 Function Calling 기능을 이제서야 적용해봤는데, 생각보다 구조가 직관적이었다.
Function Calling 기본 구조
const functions = [
{
name: "get_order_status",
description: "주문 번호로 배송 상태를 조회한다",
parameters: {
type: "object",
properties: {
order_id: {
type: "string",
description: "주문 번호 (예: ORD-12345)"
}
},
required: ["order_id"]
}
}
];
const response = await openai.chat.completions.create({
model: "gpt-3.5-turbo-0613",
messages: [{role: "user", content: "ORD-12345 어디쯤 왔나요?"}],
functions: functions,
function_call: "auto"
});
GPT가 함수 호출이 필요하다고 판단하면 function_call 필드에 함수명과 인자를 JSON으로 반환한다. 실제 함수 실행은 서버에서 처리하고, 결과를 다시 GPT에 전달하는 방식이다.
실제 구현 시 주의점
1. Function description이 핵심이다
처음엔 description을 대충 썼더니 GPT가 엉뚱한 함수를 호출했다. "배송 상태 조회"보다 "주문 번호로 현재 배송 위치와 예상 도착 시간을 조회"처럼 구체적으로 작성해야 정확도가 올라갔다.
2. 에러 처리가 중요하다
if (response.choices[0].finish_reason === "function_call") {
const functionCall = response.choices[0].message.function_call;
const args = JSON.parse(functionCall.arguments);
// 실제 함수 실행
const result = await executeFunction(functionCall.name, args);
// 결과를 다시 GPT에 전달
const secondResponse = await openai.chat.completions.create({
model: "gpt-3.5-turbo-0613",
messages: [
...previousMessages,
response.choices[0].message,
{role: "function", name: functionCall.name, content: JSON.stringify(result)}
]
});
}
API 호출 실패나 잘못된 인자 처리를 위한 예외 처리를 빼먹으면 챗봇이 멈춘다.
3. 비용이 예상보다 높다
Function definitions도 토큰을 소비한다. 10개 함수를 등록하니 요청당 기본 500토큰이 사용됐다. 자주 쓰는 함수만 동적으로 로드하는 방식으로 개선했다.
결과
주문 조회, 환불 절차 안내, 재고 확인 등 5개 함수를 연동했더니 고객 지원팀 문의의 40% 정도를 자동 처리할 수 있게 됐다. 다만 복잡한 멀티스텝 처리는 아직 사람 손이 필요하다.
프로덕션 배포 전에 로그를 충분히 쌓아서 오작동 케이스를 찾는 게 중요할 것 같다.