Tool calling(함수 호출)은 모델이 함수를 직접 실행하는 기능이 아니다. 모델은 JSON 형태의 호출 요청을 만들고, 애플리케이션이 이를 검증·실행한 뒤 결과를 돌려준다. 이 책임 분리를 지키면 Claude·GPT·오픈웨이트 모델처럼 프로바이더를 바꿔도 같은 실행 루프를 재사용할 수 있다.
전체 루프
- 애플리케이션이 JSON Schema로 도구의 이름과 입력을 보낸다.
- 모델이
tool_calls와 JSON 문자열 인자를 반환한다. - 애플리케이션이 각 인자를 파싱·검증해 실제 함수를 실행한다.
tool_call_id와 결과를 메시지에 추가하고 모델에 다시 보낸다.
여러 호출이 한 응답에 올 수 있으므로 한 개만 온다고 가정하면 안 된다. 모델이 도구를 지원하지 않거나 도구 호출 없이 답할 수도 있으므로 종료 조건도 필요하다.
최소 Python 구현
import json
def get_weather(location, unit="celsius"):
# 실제 서비스에서는 인증·입력 검증·오류 처리를 포함한다.
return {"location": location, "temperature": 18, "unit": unit}
def run_tool_loop(client, model, user_message, tools):
messages = [{"role": "user", "content": user_message}]
while True:
response = client.chat.completions.create(
model=model, messages=messages, tools=tools
)
message = response.choices[0].message
if not message.tool_calls:
return message.content
messages.append(message)
for call in message.tool_calls:
args = json.loads(call.function.arguments)
result = get_weather(**args)
messages.append({
"role": "tool",
"tool_call_id": call.id,
"content": json.dumps(result),
})운영에서 꼭 추가할 것
| 항목 | 이유 |
|---|---|
| 서버 측 입력 검증 | 모델이 만든 JSON도 신뢰할 수 없는 외부 입력이다 |
| 도구별 권한·승인 | 결제·삭제·외부 전송처럼 부작용이 있는 호출을 막는다 |
| 타임아웃·재시도·호출 한도 | 무한 루프와 비용 폭증을 방지한다 |
| 결과 최소화·비밀 마스킹 | 도구 출력이 다음 모델 컨텍스트로 흘러가는 것을 통제한다 |
| 모델별 지원 확인 | 스키마·병렬 호출·스트리밍 지원이 모델마다 다르다 |
누구에게 적합한가
- 멀티모델 앱 개발자: 모델 문자열만 교체하는 공통 실행 계층이 필요할 때
- 에이전트 개발자: 검색·DB·업무 API를 모델의 요청으로 연결할 때
- 플랫폼 팀: 도구 실행 권한과 감사 로그를 애플리케이션에서 통제할 때
관련 문서
- mcp — 에이전트와 외부 시스템을 연결하는 표준 프로토콜
- agent-harness — 도구·권한·피드백 루프를 포함한 실행 환경 설계
- outlines-tips-structured-generation — JSON 같은 구조화 출력을 토큰 단계에서 제어하는 방법
참고 자료
- Tool Calling Across Any Model: Write the Loop Once, Swap the Model String — OpenRouter (2026-08-12)