Function Calling(도구 호출)은 2026년 Agent의 기본 프로토콜입니다. 모델은 산문으로 API를 호출한 척하지 않고 합의된 schema의 JSON을 내며, 여러분의 코드가 날씨 조회·DB 질의·파일 수정·테스트를 실행합니다. 차이는 말솜씨가 아니라 schema 검증, 실행 감사, 부작용 격리입니다.
최종 업데이트 2026년 8월 18일. SDK 필드명은 바뀌어도 루프는 같습니다. 디스크를 바꾸는 도구는 Agent 파일 시스템 샌드박스와 함께. 세션을 넘는 설정은 다음 arguments가 아니라 Memory 계층에 둡니다.
자유 텍스트 프롬프트가 부족한 이유 (Why)
예전에는 “get_weather(city=Beijing)을 호출하라”고 쓰고 정규식으로 뽑았습니다. 데모는 통과하고 운영에서는 세 곳에서 깨집니다.
- 파싱 불안정 — 인사말, 인자 순서, 따옴표 누락으로 JSON.parse 실패.
- 타입 없음 — enum이 자유 텍스트가 되고 필수 필드가 사라지며 병렬 호출을 짝짓지 못함.
- 부작용과 대화 혼재 — 모델은 삭제했다고 주장하지만 미실행, 또는 실행했는데 결과를 모름.
Function Calling은 선택은 모델, 실행은 런타임에 둡니다. HTTP·SQL·shell은 모델 프로세스 안에서 일어나지 않습니다. CI와 같이 똑똑함보다 실행 경계가 먼저입니다.
Function Calling 3계층 (What)
“OpenAI tools를 붙였다”는 아키텍처가 아닙니다. 최소 세 층으로 나눕니다.
| 계층 | 역할 | 전형 | 소유 |
|---|---|---|---|
| L1 Schema | 이름, JSON Schema, 설명, 필수 | OpenAI tools[].function, Gemini functionDeclarations, Claude input_schema | 제품 |
| L2 Runtime | 검증, 비밀 주입, 타임아웃, 감사 | 자체 루프, LangGraph, Claude Code | 백엔드 / 로컬 Agent |
| L3 Transport | 도구 프로세스 발견과 연결 | HTTP, MCP stdio/SSE, 내부 RPC | 인프라 |
비대칭 결론: 벤더 API가 표준화하는 것은 L1 JSON 봉투뿐입니다. L2 인가와 L3 프로세스 격리는 직접 해야 합니다. MCP는 발견과 세션이지 자동 보안이 아닙니다.
루프는 아래와 같습니다. 모델은 API 키를 갖지 않습니다. 비밀은 런타임에만 있습니다.
┌──────────────┐ JSON tool request ┌──────────────────┐
│ LLM API │ ────────────────────────► │ Your runtime │
│ (OpenAI / │ name + arguments │ (Agent loop) │
│ Gemini / │ │ │
│ Claude) │ ◄──────────────────────── │ execute tool │
└──────────────┘ tool result JSON │ • HTTP APIs │
│ • DB / search │
│ • shell / MCP │
└────────┬─────────┘
│
▼
┌──────────────────┐
│ Policy + secrets │
│ allowlist, audit │
│ Cloud Mac / VPC │
└──────────────────┘비교: OpenAI vs Gemini vs Claude
| 면 | 진입 | 실행 | 컨텍스트 | 적합한 사람 |
|---|---|---|---|---|
| OpenAI tools | Chat Completions / Responses | 여러분이 실행. arguments는 종종 JSON 문자열 | 병렬 tool_calls[], strict 선택 | 기존 OpenAI SDK·호환 게이트웨이 |
| Gemini functionDeclarations | Gemini API / Vertex | 여러분이 실행. toolConfig.mode로 강제/금지 | 타입명은 대문자 OBJECT/STRING이 많음 | GCP, 모드 스위치가 필요한 제품 |
| Claude tool_use | Messages API / Claude Code | 여러분이 실행. input은 이미 객체 | content 블록: tool_use / tool_result | Anthropic, IDE Agent, MCP |
| MCP 도구 | 클라이언트 ↔ MCP 서버 | 서버 프로세스에서 실행. 모델은 JSON만 | 런타임에 도구 목록 발견 | 카탈로그 핫플러그 |
2026년 분기점은 “지원 여부”(세 곳 모두 지원)가 아니라 인자가 문자열인지 객체인지, 병렬 정렬, 실패 회신입니다. 게이트웨이는 내부 ToolCall{name, id, args}로 정규화해 하나의 L2로 보냅니다.
세 벤더 JSON (How)
같은 get_weather. 운영 description에는 경계를 적으세요(공개 기상만, 개인 위치 금지).
OpenAI: tools + tool_calls
요청에 tools를 붙입니다. 호출 시 tool_calls. arguments는 문자열화된 JSON이므로 parse 후 검증합니다.
{
"model": "gpt-4.1",
"messages": [{"role": "user", "content": "What's the weather in Beijing?"}],
"tools": [{
"type": "function",
"function": {
"name": "get_weather",
"description": "Current weather for a city",
"parameters": {
"type": "object",
"properties": {
"city": {"type": "string", "description": "City name"},
"unit": {"type": "string", "enum": ["celsius", "fahrenheit"]}
},
"required": ["city"]
}
}
}]
}{
"role": "assistant",
"tool_calls": [{
"id": "call_abc123",
"type": "function",
"function": {
"name": "get_weather",
"arguments": "{\"city\":\"Beijing\",\"unit\":\"celsius\"}"
}
}]
}실행 후 role: tool(또는 Responses 동등)로 tool_call_id를 맞추고 결과 문자열을 넣습니다.
Gemini: functionDeclarations + toolConfig
tools[].functionDeclarations에 선언. 타입은 대문자가 많습니다. mode는 AUTO / ANY / NONE. 제품 스위치이지 샌드박스가 아닙니다.
{
"contents": [{"role": "user", "parts": [{"text": "What's the weather in Beijing?"}]}],
"tools": [{
"functionDeclarations": [{
"name": "get_weather",
"description": "Current weather for a city",
"parameters": {
"type": "OBJECT",
"properties": {
"city": {"type": "STRING"},
"unit": {"type": "STRING", "enum": ["celsius", "fahrenheit"]}
},
"required": ["city"]
}
}]
}],
"toolConfig": {"functionCallingConfig": {"mode": "AUTO"}}
}모델은 functionCall part, 여러분은 functionResponse. OpenAI와 필드명을 같다고 가정하지 마세요.
Claude: tools + tool_use / tool_result
input_schema를 씁니다. 응답은 content 블록 배열. input은 객체지만 필드 누락은 있으므로 검증은 필수입니다.
{
"model": "claude-sonnet-4-6",
"max_tokens": 1024,
"tools": [{
"name": "get_weather",
"description": "Current weather for a city",
"input_schema": {
"type": "object",
"properties": {
"city": {"type": "string"},
"unit": {"type": "string", "enum": ["celsius", "fahrenheit"]}
},
"required": ["city"]
}
}],
"messages": [{"role": "user", "content": "What's the weather in Beijing?"}]
}{
"role": "assistant",
"content": [{
"type": "tool_use",
"id": "toolu_01XYZ",
"name": "get_weather",
"input": {"city": "Beijing", "unit": "celsius"}
}]
}{
"role": "user",
"content": [{
"type": "tool_result",
"tool_use_id": "toolu_01XYZ",
"content": "{\"temp_c\": 28, \"condition\": \"clear\"}"
}]
}Claude Code / Cursor는 MCP를 더합니다. 모델이 보는 것은 JSON Schema 도구 목록입니다. 전송이 바뀌어도 루프는 같습니다.
선택 매트릭스
| 당신이… | 선택 | 이유 |
|---|---|---|
| OpenAI 호환 게이트웨이 보유 | OpenAI tools 방언으로 통일 | 생태계가 가장 큼. adapter 한 번 |
| 주 스택이 GCP / Vertex | Gemini + mode | 번역이 적음. “이번 턴은 검색 필수”에 유리 |
| Claude Code 중심 | Claude tools + MCP | IDE 도구 카탈로그와 일치 |
| 세 벤더 동시 접속 | 내부 ToolCall + 벤더 adapter | 비즈니스 코드에 if-else를 흩뿌리지 말 것 |
| 파일 수정·명령 실행 | 원격 Mac + 경로 허용 목록 | 예쁜 JSON은 잘못된 rm을 막지 못함 |
| 읽기 전용 SaaS만 | 서버리스 + 시크릿 관리 | 전체 머신 불필요. 인자 허용 목록은 필요 |
추천 스택
A — 개인 최속(반나절) 단일 모델, 읽기 전용 도구 1–3개, extra 속성 거부, 비밀은 환경 변수, 로그는 해시만.
B — 소규모 팀 운영 내부 ToolCall, 도구별 타임아웃·한도, 쓰기는 Cloud Mac 세션. 기억은 Memory로 분리. 원격 Mac 자동화와 같은 폐기 규율.
C — 엔터프라이즈 카탈로그 심사, schema는 PR, VPC 안 MCP, 제약 없는 bash 금지.
흔한 오해
- 모델이 인증한다고 믿음 — 키는 런타임.
- OpenAI
arguments를 객체로 취급 — 먼저 parse. - 설명이 “만능 도우미” — 과호출.
- 병렬 tool_calls 무시 — 쓰기는 직렬화.
- 실패를 삼킴 — 구조화 에러를 반환.
- MCP = 보안 — 홈 디렉터리 root는 전체 디스크.
도입 7단계
- 도구 목록(부작용·타임아웃·데이터 위치).
- JSON Schema(필수, enum, additionalProperties 금지).
- 최소 루프(단일 도구).
- 검증과 비밀 격리, 감사.
- 두 번째 벤더 adapter로 내부 모델 증명.
- 쓰기 도구 샌드박스.
- 7일 관측 후 오호출이 많은 schema를 좁힘.
FAQ
JSON mode와 차이는?
JSON mode는 최종 답 형태. Function Calling은 중간 도구 요청이며 실행 후 여러 턴이 됩니다.
모델이 DB에 직접 가나요?
런타임이 임의 SQL 도구를 열지 않으면 아닙니다. 모델은 schema에 맞는 인자만 제안합니다.
세 벤더가 schema를 공유할 수 있나요?
코어는 공유하고 봉투만 바꿉니다. strict 동작은 회귀 테스트하세요.
Claude Code 도구가 Function Calling인가요?
같은 루프입니다. 카탈로그가 IDE/MCP에서 동적으로 온다는 점이 다릅니다.
도구 결과를 장기 기억에 넣나요?
원본 페이로드는 크니 요약해 Memory로. 도움말을 보세요.
정리
2026 Function Calling은 타입이 있는 RPC입니다. 세 벤더는 JSON 방언입니다. 보안은 L2 검증과 실행 호스트 격리입니다. 지금 write_file이 나오면 어느 머신의 어느 디렉터리에 떨어지는지 답할 수 없으면 쓰기 도구를 아직 붙이지 마세요. 읽기 API는 오늘. 코드 수정과 테스트는 폐기 가능한 Cloud Mac으로. 먼저 요금을 확인하세요.