이 가이드의 끝에 다다르면 도구를 정의하고, OpenAI에 보내고, 모델이 반환하는 도구 호출을 읽고, 모델이 제공하는 구조화된 인수로 자신만의 함수를 실행할 수 있게 될 것입니다. 또한 엄격 모드와 병렬 호출을 켜고, Apidog를 사용하여 도구 측면을 확인하고 모의 처리하여, 프로덕션에 도달하기 전에 출력을 신뢰할 수 있도록 할 것입니다. 진실의 원천으로 OpenAI의 함수 호출 문서를 다른 탭에 열어두고, 더 높은 수준의 그림을 위해 OpenAI Agents SDK로 에이전트 구축에 대한 우리의 입문서를 참조하세요.
시작하기 전에 필요한 것
함수 호출(종종 도구 호출이라고도 함)은 모델이 코드 및 외부 시스템과 연결되는 방식입니다. 앱이 노출하는 함수를 설명하면, 모델은 사용자 요청을 읽고, 함수가 적절하다고 판단되면 해당 함수 이름과 인수가 포함된 JSON 객체를 반환합니다. 모델은 자체적으로 아무것도 실행하지 않습니다. 모델은 구조화된 요청을 사용자에게 전달하고, 사용자의 코드가 작업을 수행합니다.
구축할 때 이러한 분리된 점을 염두에 두어야 합니다. 모델은 의도를 파악하고 매개변수를 채웁니다. 실행 제어는 사용자에게 있습니다. "파리의 날씨를 알려줘"와 같은 메시지는 직접 파싱해야 하는 단락 대신 깔끔한 get_weather({"location": "Paris, France"}) 호출로 변환됩니다.
따라하려면 OpenAI API 키와 모델이 트리거할 수 있기를 원하는 자체 코드의 함수가 필요합니다. 미리 결정해야 할 한 가지 더: 어떤 엔드포인트를 사용할지입니다. 동일한 기능이 두 곳에서 작동합니다. 기존의 Chat Completions API도 이를 지원하고, Chat Completions와 Assistants API로 나뉘어 있던 것을 통합한 새로운 Responses API도 지원합니다. 형태는 약간 다르며, 아래 단계에서는 두 가지 모두 다룹니다.
1단계: 도구 정의
도구는 모델이 읽을 수 있는 함수 정의입니다. 이름, 설명, 그리고 인수에 대한 JSON 스키마를 제공합니다. 여기서 설명은 실제 작업을 수행합니다. 모델에게 언제 함수를 사용해야 할지 알려주므로, 레이블이 아닌 지침처럼 작성하십시오.
다음은 function 래퍼 아래에 함수가 있는 Chat Completions 형태의 도구 정의입니다.
{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get the current weather for a city. Use when the user asks about temperature or conditions.",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "City and country, e.g. Bogotá, Colombia"
},
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"]
}
},
"required": ["location"],
"additionalProperties": false
}
}
}
Responses API는 이를 평탄화합니다. name, description, parameters, strict 필드가 중첩된 function 키 없이 도구 객체의 최상위 수준에 위치합니다. 정보는 동일하지만 계층이 더 적습니다.
기존에 기본 서비스에 대한 OpenAPI 사양을 유지 관리하고 있다면, 매개변수 형태가 거의 직접적으로 이월됩니다. OpenAPI 사양에서 테스트 컬렉션 생성에 대한 저희의 안내서에서는 해당 스키마 작업이 두 배로 효과를 발휘하는 방법을 보여줍니다.
2단계: 첫 번째 요청 보내기
사용자 메시지와 함께 도구를 모델에 보냅니다. 이를 수행하는 전체 Chat Completions 요청은 다음과 같습니다.
curl https://api.openai.com/v1/chat/completions \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-4.1",
"messages": [
{"role": "user", "content": "What is the weather in Paris right now?"}
],
"tools": [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "Get the current weather for a city.",
"parameters": {
"type": "object",
"properties": {
"location": {"type": "string"}
},
"required": ["location"],
"additionalProperties": false
}
}
}
]
}'
tools 배열은 이 턴에서 노출하려는 모든 함수를 포함합니다. 모델은 사용자 메시지를 읽고, 적절한 도구가 있는지 결정한 다음 응답합니다. 도구를 선택하면, 산문 대신 도구 호출이 반환되며, 이는 다음 단계에서 읽게 될 내용입니다.
3단계: 모델이 반환하는 도구 호출 읽기
모델이 함수를 호출하기로 결정하면 텍스트를 반환하지 않습니다. 응답에서 읽을 수 있는 도구 호출을 반환합니다.
Chat Completions에서는 어시스턴트 메시지가 tool_calls 배열을 포함합니다. 각 항목에는 id, function 유형, 그리고 name과 arguments 문자열을 포함하는 function 객체가 있습니다.
{
"id": "call_12345xyz",
"type": "function",
"function": {
"name": "get_weather",
"arguments": "{\"location\":\"Paris, France\"}"
}
}
Responses API에서는 호출이 더 평탄한 형태로 output 배열에 나타납니다: function_call 유형, call_id, name, 그리고 arguments.
{
"type": "function_call",
"call_id": "call_12345xyz",
"name": "get_weather",
"arguments": "{\"location\":\"Paris, France\"}"
}
사람들을 헷갈리게 하는 한 가지 세부 사항은 arguments가 파싱된 객체가 아닌 JSON으로 인코딩된 문자열이라는 점입니다. 직접 파싱하고, 함수를 실행한 다음, 모델이 응답을 완료할 수 있도록 결과를 다시 보냅니다.
4단계: 모델에 결과 반환
함수를 실행한 후, 모델이 최종 답변을 생성할 수 있도록 결과를 다시 전달합니다. Chat Completions에서는 호출 id에 매핑된 tool 역할 메시지를 추가합니다. Responses API에서는 call_id에 매핑된 function_call_output 항목을 보냅니다. 어느 쪽이든 루프는 동일합니다: 모델이 요청하고, 사용자가 실행하고, 결과를 반환하면 모델이 응답합니다.
5단계: 병렬 호출 및 엄격 모드 추가
두 가지 설정이 이것이 얼마나 신뢰할 수 있고 얼마나 빠른지에 영향을 미치며, 기본 루프가 작동하면 이들을 추가합니다.
병렬 도구 호출. 기본적으로 모델은 한 번의 턴에 둘 이상의 도구 호출을 반환할 수 있습니다. 사용자가 세 도시에 대한 날씨를 요청하면, 세 개의 호출을 동시에 받아 함께 실행할 수 있습니다. 한 턴당 최대 하나의 호출만 강제하고 싶다면, parallel_tool_calls를 false로 설정하십시오.
엄격 모드. 함수 정의에 strict: true를 설정하면 모델의 인수가 최선의 노력 대신 JSON 스키마와 일치하도록 보장됩니다. OpenAI는 항상 이를 활성화할 것을 권장합니다. 엄격 모드에는 규칙이 있습니다: 모든 객체에는 additionalProperties: false가 필요하며, properties의 모든 필드는 required에 나타나야 합니다. 필드를 선택 사항으로 만들려면 required에서 제거하는 것이 아니라, 허용되는 유형 목록에 null을 추가해야 합니다.
| 설정 | 제어하는 내용 | 기본값 | 변경 시점 |
|---|---|---|---|
parallel_tool_calls |
한 턴에 여러 도구 호출이 반환될 수 있는지 여부 | true |
호출이 서로 의존하거나 순서대로 실행되어야 할 때 false로 설정 |
strict |
인수가 스키마와 일치하도록 강제되는지 여부 | 설정되지 않은 경우 최선 노력; 활성화 권장 | 방어 코드가 없는 파싱 호출에 대해 활성화 |
tool_choice |
모델이 어떤 함수를 호출할 수 있는지 여부 및 어떤 함수인지 | auto |
호출을 강제하려면 required, 비활성화하려면 none, 특정 함수를 지정하려면 이름을 지정 |
선택적 필드 규칙은 사람들을 당황하게 만듭니다. get_weather에서 unit이 선택 사항이라고 가정해 봅시다. 엄격 모드에서는 여전히 required에 unit을 나열한 다음, 스키마에서 null을 허용하도록 표시합니다. 예를 들어 "unit": {"type": ["string", "null"], "enum": ["celsius", "fahrenheit"]}`와 같이 말입니다. 이제 모델은 실제 단위를 전달하거나 명시적인 null을 전달할 수 있지만, 키를 생략할 수는 없습니다. 이러한 예측 가능성이 핵심입니다: 파싱 코드는 매번 어떤 키를 예상해야 하는지 정확히 알 수 있습니다.
엄격 모드는 잘못된 형식의 JSON을 줄여주지만, 값이 비즈니스적으로 합리적인지는 확인하지 않습니다. 위치는 스키마 상 유효할 수 있지만, 사용자가 서비스하지 않는 도시일 수도 있습니다. 이것이 테스트가 필요한 이유입니다.
Apidog에서 테스트하는 방법
모델은 도구 호출을 제공합니다. 이를 라이브 함수에 연결하기 전에 두 가지를 보장하고 싶을 것입니다: 인수가 예상하는 형태와 일치하는지, 그리고 함수가 호출할 하위 API가 가정하는 방식으로 작동하는지 여부입니다. Apidog는 이 두 가지 측면을 모두 다루며, 어느 쪽을 다루는지 정확히 아는 것이 중요합니다.

Apidog는 API 측면을 검증하고 모의 처리합니다. 애플리케이션의 함수를 실행하지는 않습니다. Apidog가 잘하는 것은 함수 주변의 계약입니다.
인수 구조 확인. 실제 도구 호출에서 arguments 문자열을 가져와 요청 본문으로 취급하고, Apidog에서 이에 대한 어설션을 실행합니다. location이 존재하고 문자열인지, 열거형 필드가 허용된 값만 포함하는지, 필수 필드가 있는지 확인합니다. JSONPath 표현식을 사용하면 페이로드에서 특정 필드를 쉽게 추출할 수 있으며, 더 깊은 구조적 검사를 위해서는 JSON 스키마에 대한 유효성 검사가 있습니다. 이는 엄격 모드에서 OpenAI에 제공한 스키마와 동일한 스키마를 반영합니다. 모델의 출력이 함수가 예상하는 동일한 스키마를 통과하면 루프가 완성된 것입니다.
함수가 호출할 하위 API 모의 처리. get_weather 함수는 아마도 날씨 제공자를 호출할 것입니다. 개발 중에는 해당 제공자가 속도 제한이 있거나, 유료이거나, 아직 구축되지 않았을 수 있습니다. Apidog에서 현실적인 날씨 페이로드를 반환하는 모의 API를 설정하고, 함수를 모의에 연결하여, 실제 서비스에 요청을 사용하지 않고 전체 호출 경로를 연습합니다. 라이브 API가 거의 온디맨드로 생성하지 않는 오류 사례를 포함하여 응답을 제어할 수 있으므로, 사용자가 발견하기 전에 코드가 시간 초과 또는 429 오류를 처리하는지 확인할 수 있습니다.
종합하면, 워크플로우는 다음과 같습니다: OpenAI에서 도구 호출을 캡처하고, Apidog에서 스키마에 대해 인수를 확인한 다음, 실제 API의 Apidog 모의에 대해 함수를 실행합니다. 라이브 호출을 소모하거나 엣지 케이스를 추측할 필요 없이 양쪽 끝에서 계약을 확인합니다.
자주 묻는 질문
함수 호출은 Chat Completions와 Responses API 모두에서 작동합니까? 예. 두 엔드포인트 모두 이를 지원합니다. Responses API는 이전에 Chat Completions와 Assistants API로 분할되었던 기능을 통합합니다. 주요 차이점은 형태입니다: Chat Completions는 function 키 아래에 함수를 중첩하고 tool_calls를 반환하는 반면, Responses API는 평탄한 도구 정의를 사용하고 output 배열에 function_call 항목을 반환합니다.
모델이 인수를 객체 대신 문자열로 반환하는 이유는 무엇입니까? arguments 필드는 JSON으로 인코딩된 텍스트입니다. 사용하기 전에 코드에서 파싱해야 합니다. 이는 두 API 모두에서 일관되므로, 맹목적으로 신뢰하기보다는 항상 JSON 파서를 통해 실행하고 결과를 검증하십시오. JSON 스키마 유효성 검사를 통해 이러한 인수를 실행하면, 잘못된 형식의 페이로드가 함수에 도달하기 전에 잡아낼 수 있습니다.
엄격 모드는 함수의 성공을 보장합니까? 아니요. 엄격 모드는 인수가 JSON 스키마와 일치하도록 보장하여 구조의 신뢰성을 높입니다. 하지만 값이 비즈니스 로직에 대해 올바른지는 확인하지 않으며, 함수를 실행하지도 않습니다. 값의 유효성 검사 및 하위 호출의 실패 처리는 여전히 직접 수행해야 합니다.
Apidog가 실제 함수를 실행할 수 있습니까? 아니요, 그리고 그렇게 시도하지도 않습니다. Apidog는 모델이 생성한 인수를 검증하고 함수가 의존하는 API를 모의 처리합니다. 애플리케이션은 여전히 자체 함수를 실행합니다. Apidog는 양쪽의 계약을 다루므로, 실시간 운영 전에 입력과 종속성을 신뢰할 수 있습니다.
마무리하며
이제 완전한 루프를 갖게 되었습니다: 도구를 명확하게 정의하고, 요청과 함께 보내고, tool_calls 또는 function_call 출력을 읽고, 결과를 반환한 다음, 엄격 모드를 켜고 병렬 호출이 도움이 되는지 해로운지 결정합니다. 프로덕션 전에 자신감을 가질 수 있도록 인수가 스키마와 일치하는지 확인하고 하위 API를 모의 처리하여 테스트로 마무리하십시오.
테스트 측면을 시도해보고 싶으신가요? Apidog를 다운로드하여 도구 호출 인수를 스키마에 대해 확인하고, 함수가 의존하는 API를 한 곳에서 모두 모의 처리해 보세요.
