
AI 에이전트에게 실제로 작동하는 도구 사용(Tool Use) 능력을 부여하는 방법
요약
AI 에이전트가 프로덕션 환경에서 도구 호출(Tool Use) 시 발생하는 환각과 오류를 방지하기 위한 설계 원칙을 다룹니다. 모델의 추론 능력에 의존하기보다 스키마 검증과 결과 확인 등 시스템적 규율을 통해 신뢰성을 확보하는 방법을 제시합니다.
핵심 포인트
- 도구 호출 시 발생하는 인자(Argument) 환각을 방지하기 위한 스키마 검증 필요
- 모델의 출력을 신뢰할 수 없는 입력으로 취급하고 실행 전 검증할 것
- 범용적인 API보다는 좁고 단일 작업에 특화된 도구 설계 권장
- 에이전트의 안정성을 위해 도구 호출과 실행 사이에 체크포인트 구축
당신의 AI 에이전트가 데모에서는 잘 작동하다가 프로덕션(Production) 환경에서 망가지는 데에는 한 가지 이유가 있으며, 그것은 모델의 추론(Reasoning) 문제인 경우가 거의 없습니다. 바로 도구 호출(Tool calls) 때문입니다. 모델은 올바른 도구를 선택하지만, 환각(Hallucination)된 인자(Argument)를 전달하거나, 조용히 실패한 도구 결과값을 신뢰해 버립니다. 신뢰할 수 있는 도구 사용(Tool use)은 더 똑똑한 모델을 만드는 것이 아닙니다. 그것은 하나의 규율(Discipline)입니다. 모델이 수행하는 모든 도구 호출을 신뢰할 수 없는 입력(Untrusted input)으로 취급하십시오. 실행하기 전에 스키마(Schema)를 통해 검증하고, 에이전트가 그 결과를 믿기 전에 결과값을 확인하십시오.
저는 도구 호출이 업무의 전부인 에이전트를 운영하고 있습니다. 이 에이전트는 게시물을 올리고, 이메일을 보내고, git을 푸시하고, 브라우저를 제어하며, 대부분 인간의 감시 없이 작동합니다. 여기서 그럴듯하지만 틀린 호출은 채팅창에서의 어깨 으쓱함 정도로 끝나지 않습니다. 잘못된 사람에게 보내지는 실제 이메일이 됩니다. 따라서 이 문제는 제 일상의 전부이며, 아래의 해결책은 불안정한 데모를 제가 계속 실행해 둘 수 있는 무언가로 바꾸어 놓았습니다.
데모에서는 아무도 잡아내지 못하는 실패
전형적인 도구 사용(Tool-use) 버그는 모델이 채우지 말았어야 할 빈칸을 채워버리는 것입니다. "다음 주에 Sarah와 회의를 예약해줘"와 같은 요청을 예로 들어봅시다. 모델은 어떤 Sarah인지, 어떤 시간대인지, 혹은 어떤 30분 단위의 시간대인지 알지 못하므로 추측을 합니다. 챗봇(Chatbot)에서는 그 추측이 보이지 않습니다. 하지만 동일한 모델을 send_calendar_invite 도구에 연결하면, 그 추측은 그녀의 시간으로 새벽 3시에 잘못된 Sarah에게 보내는 실제 초대장이 됩니다.
모델이 멍청하게 행동하는 것이 아닙니다. 모델은 올바른 도구를 선택했습니다. 도구 주변의 시스템이 신뢰해서는 안 될 값을 그대로 믿어버린 것입니다. 그것이 바로 간극이며, "모델이 도구를 호출하고 싶어 함"과 "에이전트가 결과에 따라 행동함" 사이에 네 가지 저렴한 체크포인트(Checkpoints)를 두어 이 간극을 메울 수 있습니다.
1. 모델이 오용할 수 없는 도구 설계하기
신뢰성 측면에서는 광범위한 API 래퍼(Wrappers)보다 좁고 단일 작업에 특화된 도구가 더 효과적입니다. 범용적인 도구는 모델에게 너무 많은 자유를 주지만, 좁은 범위의 도구는 환각(Hallucinate)을 일으킬 여지를 거의 남기지 않습니다.
// 광범위하고 위험함: 모델이 SQL을 작성하면, 당신은 모델이 지어낸 것이 무엇이든 실행하게 됩니다.
queryDatabase(sql: string): Row[]
...
queryDatabase는 잘못된 추측 하나로 테이블을 삭제(drop)하게 만들 수 있습니다. 반면 getInvoiceById는 오직 하나의 ID로 하나의 송장(invoice)만 가져올 수 있습니다. 당신이 노출하는 모든 도구는 확신에 찬 실수(confident mistake)가 발생할 수 있는 공격 표면(attack surface)이 되므로, 각 도구를 지루할 정도로 구체적으로 유지하십시오.
2. 실행 전 인자(arguments)를 검증하십시오
제공자(Provider)의 구조화된 출력(structured outputs) (OpenAI의 JSON schema 모드, Anthropic의 도구 사용 (tool use))은 인자의 **형태 (shape)**를 보장할 뿐, 값의 **정확성 (correctness)**을 보장하지는 않습니다. 형식이 잘 갖춰진 JSON이라도 "invite bob@typo"라고 말하거나 지속 시간을 900분으로 설정할 수 있습니다. 따라서 인자를 직접 검증해야 하며, 인자가 파싱(parse)되더라도 신뢰할 수 없는 입력(untrusted input)으로 취급하십시오.
import { z } from "zod";
// 스키마(schema)는 계약입니다. 모델의 인자는 스키마를 통과할 때까지 신뢰할 수 없습니다.
...
Python에서의 동일한 관문은 Pydantic 모델입니다. try/except 구문 내부에서 검증하고, 예외(exception)를 발생시키는 대신 에러 문자열을 반환하여 모델이 그 이유를 전달받을 수 있도록 하십시오:
from pydantic import BaseModel, EmailStr, ValidationError, conint
class SendInvite(BaseModel):
...
중요한 조치는 체크(check)가 아니라 반환(return)입니다. 발생한 예외는 실행을 중단시킵니다. 반면 구조화된 { ok: false, error }는 모델에게 다시 전달되며, 모델은 그 이유를 바탕으로 재시도(retry)를 수행합니다 (위 다이어그램의 재시도 경로(retry lane) 참조).
3. 실행 자체를 보호하십시오
유효한 도구 호출(tool call)이라 할지라도, 두 번 실행되거나 되돌릴 수 없는 경우 피해를 줄 수 있습니다. 따라서 쓰기(write) 작업은 멱등성(idempotent)을 갖게 하고, 되돌릴 수 없는 모든 작업 앞에는 확인 관문(confirmation gate)을 두십시오.
const seen = new Set<string>();
async function guardedExecute(call: ToolCall) {
...
여기서 사용된 Set은 예시를 위한 것입니다. 실제 운영 환경(production)에서는 키가 Redis나 데이터베이스에 저장되므로, 재시작하거나 두 번째 워커(worker)가 실행되더라도 이를 확인할 수 있습니다. 에이전트는 끊임없이 재시도하며(네트워크 타임아웃이 발생하면 모델이 다시 시도함), 지속 가능한 멱등성 키(idempotency key)가 없다면 초대장을 두 번 보내게 됩니다. 모든 쓰기 작업에 안정적인 키를 부여하고, 되돌릴 수 없는 작업에는 게이트(gate)를 설치하며, 모든 도구의 자격 증명(credentials)을 해당 작업의 범위로 제한하십시오.
4. 결과를 검증하라, 신뢰하지 말고
도구가 success: true를 반환하는 것은 주장일 뿐, 증거가 아닙니다. 에이전트가 그 결과에 따라 행동하기 전에 반드시 신뢰할 수 있는 원천(source of truth)을 통해 결과를 검증하십시오. 도구 호출(tool-call) 실패는 연쇄적으로 발생하기 때문입니다. 하나의 잘못된 결과는 이후의 모든 단계를 조용히 오염시킵니다.
async function callWithVerify(propose, maxTries = 3) {
let lastError = "";
for (let attempt = 0; attempt < maxTries; attempt++) {
...
초대 기능의 경우, sourceOfTruthHas는 캘린더 API를 다시 읽어 이벤트가 존재하는지 확인합니다. git push의 경우, 원격 저장소(remote)를 쿼리합니다. 규칙은 유능한 엔지니어들이 이미 지키고 있는 것과 같습니다. 원천을 직접 읽을 수 있다면, 자기 보고(self-report)로부터 사실을 도출하지 마십시오. 제한된 재시도 루프(capped retry loop)는 혼란에 빠진 모델이 사용자의 토큰 예산을 무한정 소모하는 것을 방지합니다.
핵심 요약 (The takeaway)
신뢰할 수 있는 도구 사용은 더 큰 모델이 아니라, 네 가지 저렴한 습관에서 나옵니다:
- 좁은 범위의 도구 (Narrow tools): 환각(hallucination)을 일으킬 여지를 최소화합니다.
- 검증된 인자 (Validated arguments): 신뢰할 수 없는 입력으로 취급하며, 실패 원인을 다시 전달합니다.
- 보호된 실행 (Guarded execution): 멱등성 쓰기(idempotent writes), 되돌릴 수 없는 작업에 대한 게이트 설치, 최소 권한 자격 증명(least-privilege credentials).
- 검증된 결과 (Verified results): 도구 자체의 "성공"이 아니라, 신뢰할 수 있는 원천(source of truth)을 대조하여 확인합니다.
모델은 제안하고, 당신의 코드가 결정합니다. 모든 도구에 이 네 가지 체크포인트를 적용하면, 데모에서 실수를 연발하던 모델도 실제로 계속 실행해 둘 수 있는 에이전트가 됩니다.
저는 앱과 도구를 구축하는 astraedus.dev에서의 실제 업무를 바탕으로 이 글을 작성했습니다. 무언가를 구축하고 계시거나, 이와 같은 문제로 어려움을 겪고 계신가요? astraedus.dev 또는 theagentthatcould@gmail.com으로 연락해 주세요.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기