에이전트 툴 호출은 AI가 함수 호출을 결정하는 풀 방식이고, 웹훅은 외부 이벤트가 발생할 때 전달되는 푸시 방식입니다. 둘이 비교되는 이유는 결국 둘 다 여러분의 백엔드에 도달하기 때문입니다. 하지만 두 가지는 반대 방향으로 동작하며, 이를 혼동하면 잘못된 아키텍처와 잘못된 보안이 함께 생겨납니다. 구분 전체가 한 줄에 들어갑니다. 웹훅은 바깥 세상 → 여러분의 시스템(푸시, 이벤트 트리거, 결정적)이고, 툴 호출은 여러분의 AI → 바깥 세상(풀, 모델 트리거, 확률적)입니다.
핵심 요약
| 축 | 웹훅 | 에이전트 툴 호출 |
|---|---|---|
| 방향 | 바깥 세상 → 여러분의 시스템 | 여러분의 AI → 바깥 세상 |
| 트리거 | 이벤트가 발생함 | 모델이 결정함 |
| 방식 | 푸시 | 풀 / 온디맨드 |
| 결정성 | 결정적 | 확률적 |
| 보안 태세 | 인바운드를 검증 | 아웃바운드를 제한 |
두 가지 방향
같은 백엔드에 양쪽 방향에서 도달합니다. 한쪽은 검증되고, 다른 쪽은 제한됩니다:
// JavaScript — Cloud Code: the same backend, reached two ways
// INBOUND — a webhook: the world tells your system something happened.
// Deterministic. You VERIFY the sender before trusting it.
Parse.Cloud.define('paymentWebhook', async (req) => {
verifyHmac(req.params, process.env.WEBHOOK_SECRET); // trust, then act
await markPaid(req.params.orderId);
return { received: true };
});
// OUTBOUND — an agent tool: your AI decides to do something.
// Probabilistic. You CONSTRAIN what it may do (runs under the user's ACLs).
Parse.Cloud.define('refundOrder', async (req) => {
const asUser = { sessionToken: req.user.getSessionToken() };
const order = await new Parse.Query('Order').get(req.params.orderId, asUser);
order.set('status', 'refunded');
await order.save(null, asUser); // ACLs decide if this agent-driven call is allowed
return { refunded: order.id };
}); // Flutter / Dart — Back4app Flutter SDK
// Both directions ultimately hit the same backend functions.
// A webhook arrives when an EVENT fires (push, deterministic);
// a tool call fires when the MODEL decides (pull, probabilistic).
final result = await ParseCloudFunction('runAgent')
.execute(parameters: {'goal': 'refund my last order'});
print(result.result);
// The agent PULLED the refundOrder tool. A payment provider would have
// PUSHED a webhook to paymentWebhook. Same endpoint style — opposite trigger. // iOS / Swift — Back4app Swift SDK
// Both directions ultimately hit the same backend functions.
// A webhook arrives when an EVENT fires (push, deterministic);
// a tool call fires when the MODEL decides (pull, probabilistic).
let result: [String: Any] = try await Cloud.run(
name: "runAgent", parameters: ["goal": "refund my last order"])
print(result)
// The agent PULLED the refundOrder tool. A payment provider would have
// PUSHED a webhook to paymentWebhook. Same endpoint style — opposite trigger. // Android / Kotlin — Back4app Android SDK
// Both directions ultimately hit the same backend functions.
// A webhook arrives when an EVENT fires (push, deterministic);
// a tool call fires when the MODEL decides (pull, probabilistic).
val result = ParseCloud.callFunction<Map<String, Any>>(
"runAgent", mapOf("goal" to "refund my last order"))
println(result)
// The agent PULLED the refundOrder tool. A payment provider would have
// PUSHED a webhook to paymentWebhook. Same endpoint style — opposite trigger. 툴 호출의 실체
웹훅 쪽은 웹훅 항목이 다루므로, 여기서는 이 글이 맡은 나머지 절반을 설명합니다. 툴 호출은 AI 에이전트가 행동하는 방식입니다. 요청에 툴 정의(이름, 설명, 타입이 지정된 JSON 스키마)를 함께 보내면, 모델은 대화를 바탕으로 추론한 뒤 산문으로 답하는 대신 툴 이름과 인수를 담은 구조화된 호출을 내보냅니다. 여러분의 코드가 이를 실행하고, 그 결과를 다음 추론 단계를 위해 다시 넘깁니다. 어디서나 강조되는 요점은 이것입니다(Fowler의 해설이 명확한 참고 자료입니다). 모델은 함수를 절대 실행하지 않습니다. 툴 설명을 근거로 호출을 요청하기로 결정할 뿐이며, 그래서 툴 설명에는 진지한 공을 들일 가치가 있습니다. “함수 호출”(function calling, 이전 용어)과 “툴 호출”(tool calling, 더 넓은 용어)은 사실상 같은 메커니즘을 가리킵니다.
결정성: 구축 방식을 바꾸는 축
테스트 방식을 재편하는 차이이자, 어떤 비교 글도 분명하게 말하지 않는 차이입니다. 웹훅은 결정적입니다. 이벤트 X는 예측 가능한 페이로드로 같은 콜백을 발생시키므로, 고정된 입력으로 핸들러를 단위 테스트하고 하나의 출력을 단언합니다. 툴 호출은 확률적입니다. 같은 사용자 목표가 특정 툴을 트리거할 수도, 하지 않을 수도 있고, 실행할 때마다 다른 인수를 넘길 수도 있습니다. 단언할 정답 출력이 하나로 정해져 있지 않으므로, 에이전트는 많은 실행에 걸쳐 올바르게 행동하는 빈도를 측정하며 통계적으로 평가합니다. 웹훅 연동은 테스트가 통과하면 “완료”이고, 에이전트 연동은 성공률이 여러분이 정한 기준을 넘으면 “완료”인 이유가 여기에 있습니다. 푸시 vs. 풀은 기억하기 쉬운 구분이고, 결정적 vs. 확률적은 결과를 좌우하는 구분입니다.
보안: 웹훅 vs. 툴 호출, 들어오는 것은 검증하고 나가는 것은 제한
방향이 정반대의 방어를 요구하며, 이를 거꾸로 적용하는 것이 위험의 전부입니다.
| 웹훅(인바운드) | 툴 호출(아웃바운드) | |
|---|---|---|
| 위협 | 발신자를 사칭한 누군가가 위조한 이벤트 | 해서는 안 될 행동을 하는 조작된 모델 |
| 신뢰하지 않는 대상 | 발신자 | 모델의 판단 |
| 방어 | 검증: HMAC 서명, 재전송 방어, 시크릿 회전 | 제한: 최소 권한 범위, 되돌릴 수 없는 작업에 관문 |
| 강제 수단 | 서명 확인(webhooks.fyi) | 사용자 권한으로 실행되는 서버 측 권한 검사 |
들어오는 것은 검증하고, 나가는 것은 제한합니다. 서명 검증을 건너뛰는 웹훅 핸들러는 인증 없는 쓰기 엔드포인트이고, 과도하게 넓은 자격 증명을 가진 에이전트 툴은 프롬프트 인젝션 한 번이면 터질 혼동된 대리인(confused deputy) 사고입니다. 둘은 반대 방향에서 같은 방식으로 실패합니다. 시스템이 신뢰해서는 안 될 호출을 신뢰한 것입니다.
둘은 조합됩니다
둘은 경쟁자가 아니라 하나의 루프를 이루는 단계입니다. 인바운드 웹훅이 에이전트를 깨우고(지원 티켓 도착, 결제 완료), 에이전트가 이에 대응해 툴을 호출하며, 그 툴 호출 중 하나가 또 다른 시스템으로 아웃바운드 웹훅을 트리거합니다. 백엔드 개발자에게 깔끔한 멘탈 모델은 이렇습니다. 둘 다 결국 여러분의 API와 함수에 도달하며, 차이는 누가 방아쇠를 당겼는가(외부 이벤트인가, 모델인가)와 호출이 결정적이었는가뿐입니다. 엔드포인트는 한 번 설계하고, 어느 방향에서 도달할 수 있는지에 따라 보호하면 됩니다.
일반적인 사용 사례
- 이벤트 반응 – 결제 완료, 코드 푸시, 폼 제출: 검증된 웹훅.
- 자율적 행동 – 범위가 지정된 툴을 호출해 목표를 해결하는 에이전트: 제한된 툴 호출.
- 이벤트로 깨어나는 에이전트 – 에이전트 루프를 시작하는 입구로서의 웹훅: 둘의 조합.
- 재사용 가능한 툴 표면 – 여러 에이전트가 하나의 툴 집합을 공유: MCP로 표준화.
- 결정적 예약 작업 – 타이머에 따라 직접 통제하는 조회: 웹훅도 툴도 아닌 일반 API 호출.
무엇이 필요할까? 결정 매트릭스
| 상황 | 선택할 것 |
|---|---|
| 다른 곳에서 이벤트가 일어났고, 반응해야 함 | 웹훅 |
| AI가 런타임에 결정하고 행동해야 함 | 에이전트 툴 호출 |
| 자체 백엔드에 대한 모델 주도 행동 | 툴 호출 → 범위가 지정된 함수 |
| 여러 모델/에이전트가 재사용하는 많은 툴 | 툴 호출 위의 MCP |
| 예약된 결정적 조회 | 일반 API 호출 또는 폴링 |
| 이벤트가 에이전트를 시작해야 함 | 에이전트를 깨우는 웹훅, 즉 둘 다 |
한계와 트레이드오프
- 이 비교는 공유된 엔드포인트를 가립니다. 둘 다 같은 백엔드 함수에 도달합니다. 이를 잊으면 자물쇠 두 개를 단 문 하나면 될 곳에 보안 모델 두 개가 생깁니다.
- 확률적 호출은 보장하기 어렵습니다. 이벤트가 웹훅을 발생시킨다고 약속할 수 있는 것처럼 에이전트가 툴을 호출한다고 약속할 수는 없습니다. 모델이 행동하지 않는 경우와 잘못 행동하는 경우를 모두 대비해야 합니다.
- 검증과 제한은 서로 바꿔 쓸 수 없습니다. 툴 호출의 서명을 확인하거나 웹훅의 권한 범위를 좁히는 것은 그 방향에 맞지 않는 위협을 해결하는 일입니다. 방어는 방향에 맞춰야 합니다.
- 조합은 실패 지점을 늘립니다. 웹훅이 에이전트를 깨우고, 에이전트가 툴을 호출하고, 그 툴이 웹훅을 발생시키는 구조는 강력하지만 깨질 곳이 네 군데입니다. 체인 전체에 걸친 상관관계 ID와 멱등성은 선택 사항이 아닙니다.
- “내 API에 도달했다”는 사실은 신뢰에 대해 아무것도 알려 주지 않습니다. 같은 호출이 검증된 이벤트에서 오면 안전하고, 조작된 모델에서 오면 위험합니다. 방어의 기준은 요청의 형태가 아니라 출처입니다.
Back4app에서의 양방향 처리
Back4app은 관리형 데이터베이스, 자동 생성되는 REST 및 GraphQL API, 인증, 파일 스토리지, Cloud Code 서버리스 함수를 결합한 오픈소스 Backend as a Service(BaaS) 플랫폼입니다. 두 방향 모두 같은 구성 요소인 Cloud Code 함수에 도달하며, 코드 탭에서 보듯 바로 그 때문에 이 플랫폼에서는 두 가지 방어가 자연스럽습니다. 인바운드 쪽에서 함수는 웹훅 수신기입니다. 서버 측 시크릿으로 HMAC을 검증한 뒤 행동합니다. 아웃바운드 쪽에서 같은 함수는 에이전트 툴입니다. 호출한 사용자의 세션으로 실행되므로 ACL과 클래스 수준 권한이 모델 주도 호출이 건드릴 수 있는 범위를 제한하고, 탈취된 에이전트도 사용자 본인의 권한을 넘어설 수 없습니다. 밀려 들어오는 것은 검증하고, 에이전트가 가져가는 것은 제한합니다. 백엔드 하나, 둘 다 강제하는 장소 하나이며, 에이전트가 늘어나면 MCP가 툴 표면을 표준화합니다.
자주 묻는 질문
에이전트 툴 호출이란 무엇입니까?
AI 에이전트가 함수를 호출하는 메커니즘입니다. 툴 설명이 주어지면 모델은 툴 이름과 인수를 담은 구조화된 JSON 호출을 내보내고, 여러분의 코드가 이를 실행한 뒤, 그 결과를 모델에 다시 넘겨 추론을 이어 가게 합니다. 호출할지, 무엇을 호출할지, 어떤 인수로 호출할지는 모델이 결정하지만, 툴을 직접 실행하는 일은 절대 없습니다.
툴 호출은 웹훅과 어떻게 다릅니까?
방향과 트리거가 다릅니다. 툴 호출은 여러분의 AI가 런타임에 무언가를 호출하기로 결정하는 것으로, 풀 방식이며 필요할 때 모델이 트리거합니다. 웹훅은 외부 시스템이 이벤트가 발생했다고 여러분에게 알리는 것으로, 푸시 방식이며 이벤트가 트리거합니다. 방향이 정반대입니다. 하나는 여러분의 시스템이 밖으로 손을 뻗는 것이고, 다른 하나는 바깥 세상이 안으로 들어오는 것입니다.
툴 호출은 API 호출입니까?
사실상 모델이 API 호출을 요청하는 것입니다. 모델은 의도와 인수를 만들고, 실제 호출은 애플리케이션이 합니다. 툴 호출이란 API를 모델이 이해하고 호출할 수 있는 스키마로 감싸는 것입니다. 엔드포인트는 사람인 개발자가 호출하는 것과 같으며, 다만 여러분의 코드 대신 모델의 추론이 호출을 트리거할 뿐입니다.
웹훅과 툴 호출은 대안 관계입니까, 보완 관계입니까?
보완 관계입니다. 서로 반대 방향으로 동작하며 조합됩니다. 흔한 패턴은 이렇습니다. 인바운드 웹훅이 에이전트를 깨우고, 에이전트가 행동하기 위해 툴을 호출하며, 그 툴 호출 중 하나가 또 다른 아웃바운드 웹훅을 트리거합니다. 맡는 일은 다르지만, 같은 루프 안에 함께 있는 경우가 많습니다.
웹훅은 결정적이고 툴 호출은 확률적입니까?
그렇습니다. 그리고 이것이 실무에 가장 큰 영향을 주는 구분입니다. 이벤트 X는 언제나 같은 방식으로 웹훅을 발생시키므로, 고정된 페이로드로 핸들러를 단위 테스트할 수 있습니다. 모델은 툴을 호출할 수도 있고 호출하지 않을 수도 있으며, 다른 인수를 넘길 수도 있습니다. 그래서 에이전트는 하나의 출력을 단언하는 대신 많은 실행에 걸쳐 통계적으로 평가합니다.
보안 측면의 차이는 무엇입니까?
여기서도 방향입니다. 웹훅에서는 들어오는 것을 검증합니다. 발신자를 신뢰하지 않으므로 HMAC 서명을 확인하고 재전송(replay) 공격을 막습니다. 툴 호출에서는 나가는 것을 제한합니다. 모델의 판단을 완전히 신뢰하지 않으므로 자격 증명의 범위를 최소 권한으로 좁히고, 되돌릴 수 없는 작업에는 관문을 둡니다. 들어오는 것은 검증하고, 나가는 것은 제한합니다.
MCP는 어디에 해당합니까?
Model Context Protocol은 툴 호출, 즉 에이전트가 여러 모델과 앱에 걸쳐 툴을 발견하고 호출하는 방식을 표준화합니다. 이 비교에서 MCP는 웹훅 쪽이 아니라 툴 호출 쪽에 있습니다. MCP는 이벤트가 안으로 들어오는 것이 아니라, 에이전트가 툴을 향해 밖으로 손을 뻗는 것에 관한 프로토콜입니다.
각각은 언제 사용해야 합니까?
다른 곳에서 이벤트가 일어나 여기에 반응해야 한다면 웹훅입니다. AI가 런타임에 결정하고 행동해야 한다면 툴 호출입니다. 직접 통제하는 예약된 결정적 조회라면 일반 API 호출이나 폴링입니다. 여러 에이전트가 재사용하는 툴이 많다면 MCP로 표준화하는 것이 좋습니다.