에이전트를 붙여놓고 며칠 돌리다 보면 꼭 나오는 에러가 있다. AI_InvalidToolArgumentsError. 모델이 툴을 부르긴 했는데, 인자가 스키마랑 안 맞는 거다.
내 경우엔 날짜를 받는 툴이었다. Zod로 z.string().datetime()을 걸어놨는데 모델이 "2026년 9월 20일"처럼 사람이 읽는 형식으로 보내거나, JSON을 만들다 말아서 닫는 중괄호가 빠진 채로 오기도 했다. 한 번 이러면 generateText가 그냥 예외를 던지고, 멀티스텝 루프가 통째로 멈춘다. 잘 돌던 대화가 인자 하나 때문에 죽는 게 영 아까웠다.
실패한 호출을 버리지 말고 고친다
Vercel AI SDK에는 이걸 위한 훅이 있다. experimental_repairToolCall. 툴 호출이 파싱·검증에 실패하면 예외를 던지기 전에 이 함수가 먼저 불린다. 여기서 고친 호출을 돌려주면 그걸로 다시 시도하고, null을 돌려주면 원래대로 에러가 난다.
가장 간단한 방법은 모델한테 다시 물어보는 거다. "이 스키마에 맞게 인자만 다시 만들어줘" 하고 던지면 된다.
import { generateText, generateObject, NoSuchToolError } from 'ai';
import { anthropic } from '@ai-sdk/anthropic';
import { z } from 'zod';
const result = await generateText({
model: anthropic('claude-sonnet-5'),
tools: { /* ... */ },
prompt: '다음 주 월요일 오전 회의 잡아줘',
experimental_repairToolCall: async ({
toolCall,
tools,
inputSchema,
error,
}) => {
// 아예 없는 툴을 부른 거면 고칠 방법이 없다
if (NoSuchToolError.isInstance(error)) return null;
const tool = tools[toolCall.toolName];
// 스키마를 다시 보여주고 인자만 재생성시킨다
const { object: repaired } = await generateObject({
model: anthropic('claude-sonnet-5'),
schema: tool.inputSchema,
prompt: [
`툴 "${toolCall.toolName}"을 아래 잘못된 인자로 호출했다:`,
JSON.stringify(toolCall.input),
`에러: ${error.message}`,
'스키마에 맞게 인자를 다시 만들어라.',
].join('\n'),
});
return { ...toolCall, input: JSON.stringify(repaired) };
},
});
generateObject로 재생성하면 이번엔 스키마가 강제되니까 형식이 어긋날 일이 거의 없다. 날짜 예시도 "2026-09-22T09:00:00Z"처럼 제대로 나온다.
굳이 모델을 다시 안 불러도 된다
에러 패턴이 뻔하면 코드로 그냥 고쳐도 된다. 예를 들어 모델이 인자를 한 겹 더 감싸서 { "input": { ... } }로 보내는 버릇이 있으면, 안쪽만 꺼내서 돌려주면 끝이다. 이건 API 호출이 안 붙으니 비용도 지연도 없다.
정리
experimental_repairToolCall은 이름 그대로 실험 단계라 인터페이스가 바뀔 수 있다. 그래도 프로덕션 에이전트에 하나 깔아두면 "인자 오타 한 방에 대화 죽는" 사고를 크게 줄여준다. 고칠 수 있으면 재생성, 애매하면 null로 원래 에러 흐름에 맡기기 — 이 두 갈래만 잡아두면 충분하다.