본문 바로가기

AI Agent

Vercel이 툴을 줄여서 성능을 올린 방법 — AI 에이전트 툴 설계 가이드

반응형

AI 에이전트를 만들 때 흔히 하는 실수가 있어요.

"툴을 많이 줄수록 에이전트가 더 잘하겠지."

Vercel AI SDK 팀이 정확히 이 생각으로 접근했다가 반대 결과를 경험했어요. 툴을 계속 추가했더니 어느 순간부터 오히려 성능이 떨어졌고, 툴을 80%까지 줄였더니 성능이 올라갔습니다.

이번 글에서는 왜 이런 일이 생기는지, 그리고 툴을 어떻게 설계해야 하는지 정리해 드릴게요.


왜 툴이 많으면 성능이 떨어지나

이유 1: 선택 비용 (Choice Overhead)

모델이 툴을 고를 때마다 의사결정을 해야 해요. 툴이 5개면 "이 중에 뭘 써야 하지?"가 간단한 문제지만, 툴이 50개면 모델이 정의를 전부 읽고 비교하고 선택해야 합니다. 이 과정에서 추론 토큰이 낭비되고, 잘못된 툴을 고를 확률도 올라가요.

인간도 마찬가지예요. 메뉴판이 3개짜리 식당에서는 빠르게 고르지만, 100개짜리 메뉴판 앞에서는 결정 피로가 생기죠. 이걸 **선택 역설(Paradox of Choice)**이라고 해요. 선택지가 많을수록 오히려 결정의 질이 떨어지는 현상인데, 모델에서도 동일하게 나타납니다.

Anthropic이 직접 밝힌 내용도 같은 방향이에요.

"가장 성공적인 구현은 복잡한 프레임워크가 아니라 단순하고 조합 가능한 패턴을 사용했다."

이유 2: 컨텍스트 오염 (Context Pollution)

툴 정의는 시스템 프롬프트에 들어가요. MCP 서버 하나를 연결하면 그 서버가 제공하는 툴 정의 전체가 매 요청마다 컨텍스트에 붙어요. 툴 3개짜리 서버도 정의만 수백 토큰이에요. 서버 5개면 작업 시작 전에 이미 컨텍스트의 상당 부분이 툴 정의로 채워집니다.

Amazon이 수천 개의 에이전트를 구축하면서 발견한 문제도 이거예요.

"잘못 정의된 툴 스키마와 부정확한 설명은 관련 없는 API 호출로 이어져 컨텍스트 창을 불필요하게 확장하고, 추론 지연을 증가시키며, 중복 LLM 호출로 비용을 올린다."

이게 문제인 이유는 모델의 어텐션이 분산되기 때문이에요. "지금 실제로 중요한 정보"와 "혹시 쓸 수도 있는 툴 정의"가 같은 컨텍스트 안에 섞이면, 모델이 실제 태스크에 집중하기가 어려워져요.

이유 3: 기능 중복과 모호성 (Overlap Ambiguity)

툴이 많아질수록 비슷한 기능을 하는 툴이 생겨요. search_file이랑 find_in_codebase가 둘 다 있으면 모델은 어느 걸 써야 할지 매번 고민합니다. 정의가 명확하게 분리돼 있어도 경계선이 흐릿하면 할루시네이션처럼 잘못된 툴 선택이 빈번해져요.

Amazon이 이 문제를 해결하기 위해 조직 전체에 툴 스키마 표준을 만들고 거버넌스 프레임워크를 도입한 이유가 여기 있어요. 툴 정의를 아무나 마음대로 만들면 중복과 모호성이 쌓이거든요.

이유 4: 에러 전파 표면적 증가

툴이 많을수록 잘못 호출될 수 있는 경우의 수가 늘어요. 파라미터를 잘못 넘기거나, 없는 툴을 호출하거나, 툴 체인이 꼬이는 일이 늘어납니다. 에러가 나면 모델이 에러 메시지를 해석하고 재시도하는 데 또 토큰이 쓰여요.

에러 하나가 다음 단계로 전파되면 연쇄 실패가 일어나고, 이 과정에서 토큰 소비와 지연이 기하급수적으로 늘어납니다.


Claude Code의 해법 — 온디맨드 스킬 로딩

Claude Code는 이 문제를 온디맨드 로드 방식으로 풀었어요.

세션 시작 시에는 스킬 이름과 한 줄 설명만 컨텍스트에 넣어요. 실제 스킬 내용 — 구체적인 툴 정의, 사용 방법, 예시 — 은 그 스킬이 필요해질 때 파일에서 읽어서 로드합니다.

세션 시작 시 컨텍스트 (가벼움):
- docx: Word 문서 생성/편집
- pdf: PDF 읽기/변환
- browser: 웹 자동화

→ 사용자가 "Word 문서 만들어줘" 요청
→ 그때서야 docx SKILL.md 전체를 읽어 로드
→ 나머지 스킬은 존재만 알고 있는 상태 유지

이렇게 하면 실제 작업에 필요한 툴만 컨텍스트에 들어오고, 나머지는 존재만 알고 있는 상태로 유지돼요. 컨텍스트 효율과 툴 활용 가능성을 동시에 잡는 구조입니다.


좋은 툴 설계의 4가지 원칙

원칙 1: 단일 책임

툴 하나가 하나의 일만 해야 해요. read_and_search_and_edit_file 같은 복합 툴은 모델이 언제 써야 하는지 판단하기 어려워요.

❌ edit_and_commit_file(path, content, message)
✅ edit_file(path, content)
✅ git_commit(message)

작업을 쪼개면 모델이 각 단계를 명확하게 선택하고 실행할 수 있어요.

원칙 2: 명확한 경계

두 툴이 하는 일이 10%라도 겹치면 모델이 혼란스러워해요. 툴을 정의할 때 "이 툴은 X를 하고 Y는 하지 않는다"를 명시적으로 써줘야 해요.

# 나쁜 예
search_file: "파일에서 내용을 검색합니다"
find_in_codebase: "코드베이스에서 내용을 찾습니다"

# 좋은 예
grep_file: "단일 파일 내에서 정규식으로 텍스트를 검색합니다. 디렉토리 검색 불가."
search_codebase: "전체 코드베이스에서 파일명이나 내용으로 검색합니다. 단일 파일 검색은 grep_file을 사용하세요."

원칙 3: 실패 메시지가 다음 행동을 안내해야 함

툴이 실패했을 때 그냥 "error"가 아니라 모델이 스스로 복구할 수 있게 안내해야 해요.

❌ {"error": "File not found"}

✅ {
    "error": "파일을 찾을 수 없습니다.",
    "suggestion": "먼저 glob 툴로 경로를 확인해보세요. 예: glob('**/*.py')"
   }

좋은 에러 메시지는 모델이 다음 스텝을 스스로 결정하게 만들어서 재시도 토큰 낭비를 줄입니다.

원칙 4: 파라미터 최소화

파라미터가 많을수록 모델이 틀릴 확률이 올라가요. 선택적 파라미터는 가능하면 합리적인 기본값으로 처리하고, 모델한테는 꼭 필요한 것만 넘기게 해요.

❌ search(query, max_results, offset, sort_by, filter_date, include_metadata)

✅ search(query)
   # max_results=10, sort_by="relevance" 는 기본값으로

Amazon도 같은 결론을 내렸어요. 복잡한 파라미터 구조는 에이전트 런타임에서 잘못된 API 호출로 이어지고, 이게 컨텍스트를 불필요하게 확장한다고요.


정리 — 툴 설계 체크리스트

새 툴을 추가하기 전에 이 질문들을 먼저 해보세요.

□ 이 툴이 하는 일을 한 문장으로 명확하게 설명할 수 있나?
□ 기존 툴과 기능이 겹치는 부분이 없나?
□ 파라미터를 줄일 수 없나? 기본값으로 처리할 수 있는 게 있나?
□ 실패했을 때 모델이 다음 행동을 알 수 있는 에러 메시지를 반환하나?
□ 이 툴이 없으면 정말 안 되나? 기존 툴로 해결 안 되나?

마지막 질문이 제일 중요해요. 툴을 추가하는 건 쉽지만, 한 번 추가하면 컨텍스트에 계속 올라타거든요.


마무리

Anthropic이 수십 팀의 에이전트 구축 경험에서 내린 결론은 명확해요.

"가장 성공적인 구현은 복잡한 프레임워크나 특수 라이브러리가 아니라, 단순하고 조합 가능한 패턴을 사용했다."

툴 설계에서도 같은 원칙이 적용됩니다. 툴이 많다고 에이전트가 똑똑해지지 않아요. 필요한 툴만 명확하게 정의하고, 나머지는 과감하게 덜어내는 것이 프로덕션 수준의 에이전트를 만드는 핵심입니다. 😄


 

반응형