Vercel AI SDK에서 인간의 승인을 통한 위험한 도구 호출 제어하기
요약
Vercel AI SDK를 사용하여 환불이나 이메일 발송과 같이 되돌릴 수 없는 위험한 도구 호출을 인간의 승인 단계로 제어하는 방법을 설명합니다. 도구의 execute 함수 내에서 상태를 폴링하여 승인이 완료될 때까지 실행을 일시 중지하는 패턴을 다룹니다.
핵심 포인트
- 위험한 도구 호출 시 인간의 승인(Human-in-the-loop) 단계를 도입하여 안전성 확보
- 도구의 execute 함수 내에서 비동기 대기(await)를 통해 실행 흐름 제어 가능
- 승인 대기 중 모델의 추론을 일시 중지하여 잘못된 부수 효과 방지
- 서버리스 환경의 타임아웃 문제를 고려한 내구성 있는 워크플로우 설계 필요
Vercel AI SDK에서 위험한 도구 호출 (tool calls)을 인간의 승인 단계 뒤로 배치하여 제어하세요 — 검토자가 초안을 먼저 승인, 수정 또는 거절할 때까지 실행을 일시 중지합니다.
게이트(Gate)가 위치해야 할 곳
ai 패키지는 generateText 또는 streamText에 전달된 일반 비동기 함수 (async functions)로서 도구 (tools)를 실행합니다. 대부분의 도구는 조회(lookup)나 읽기 전용 API 호출처럼 관리 없이 실행되어도 안전합니다. 하지만 환불 처리, 이메일 발송, 고객에게 메시지 게시와 같이 되돌릴 수 없는 방식으로 외부 세계에 영향을 미치는 소수의 도구들이 있습니다. 바로 이러한 도구들이 실행을 일시 중지할 가치가 있는 것들입니다.
이를 위해 특별한 SDK 기능이 필요하지는 않습니다. 도구의 execute 함수는 인간의 결정이 내려질 때까지 대기하는 호출을 포함하여 무엇이든 await 할 수 있습니다. 부수 효과 (side effect)가 execute 호출 전이 아니라 execute 내부에서 발생하기만 한다면, 도구 호출 자체가 게이트 역할을 하게 됩니다.
시나리오: 고객 지원 편지함의 환불 처리
고객 지원 분류 에이전트 (support-triage agent)가 들어오는 티켓을 읽고, 고객이 환불을 받을 자격이 명확하다고 판단되면 Stripe 환불을 실행합니다. 환불은 LLM이 스스로 승인하도록 해서는 안 되는 전형적인 작업입니다. 잘못된 결제 ID (charge ID), 잘못된 금액, 또는 모델을 설득하여 환불을 받아내려는 고객 등은 모두 실제 발생 가능한 실패 사례입니다.
import { generateText, tool, stepCountIs } from 'ai'
import { openai } from '@ai-sdk/openai'
import { z } from 'zod'
...
실제로 실행을 차단하는 방식
generateText는 대화를 계속하기 위해 결과를 사용하기 전, 각 도구의 execute 함수가 완료되기를 기다립니다(await). issueRefund 내부에서 pushAndAwait는 상태가 pending을 벗어날 때까지 GET /v1/actions/:id를 폴링 (polling)합니다. 함수가 반환되지 않으므로 모델은 추론할 도구 결과가 없으며, 인간이 결정할 때까지 stripe.refunds.create에는 도달하지 않습니다. 거절하거나 만료되게 두면 if (poll.status !== 'approved') 분기문이 조기에 반환되어 환불 호출이 완전히 건너뛰어집니다.
이것은 issueRefund가 에이전트가 stripe.refunds.create에 도달할 수 있는 유일한 경로일 때만 유효합니다. 만약 코드베이스의 다른 곳에서 다른 도구(tool)나 직접적인 Stripe 키를 통해 환불을 트리거할 수 있다면, 이 게이트(gate)는 해당 경로를 통하는 경우만을 방어합니다.
다단계 루프(Multi-step loops)와 stopWhen
stopWhen: stepCountIs(5)는 모델이 한 번의 generateText 호출 내에서 수행할 수 있는 도구 호출(tool-call) 라운드 수를 제한합니다. execute 내부의 각 폴링(poll)은 몇 초에서 expires_in 전체 시간 범위까지 걸릴 수 있으므로, 단일 게이트 도구 호출이 실행의 실제 경과 시간(wall-clock time)을 대부분 차지할 수 있습니다. 이는 버그가 아니라 의도된 동작입니다. 만약 에이전트가 자체적인 타임아웃을 가진 요청 핸들러(예: Vercel 서버리스 함수) 내에서 실행된다면, Impri의 타임아웃이 만료되기 전에 해당 핸들러의 타임아웃에 먼저 걸릴 수 있습니다. 몇 시간 동안 대기할 수 있는 승인(approval)의 경우, 대기 시간이 무관한 타임아웃에 의해 종료되지 않도록 HTTP 핸들러 대신 내구성이 있는 워커(durable worker)나 큐 소비자(queue consumer)에서 에이전트를 실행하십시오.
다음 단계
- Quickstart — API 키를 발급받고 첫 번째 액션(action)을 실행해 보세요
- TypeScript SDK — 가공되지 않은
fetch호출 대신 타입이 지정된 클라이언트를 사용하세요 - AI 에이전트에 인간의 승인을 추가하는 방법 — 이 페이지의 기반이 되는 push → poll → execute 패턴에 대해 알아보세요
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기