Agent에게 Tool을 열어줄 때 내가 세운 3가지 원칙

– 금융 도메인에서 Tool 권한을 설계하며 배운 것들

지난 글에서 Orchestrator와 Agent의 역할을 분리하는 이야기를 했다.

그 글 마지막에 이렇게 썼다.

“다음 글에서는 Agent에게 어떤 Tool을 어떻게 제한적으로 열어줬는지를 정리해보려 한다.”

이번 글은 그 이야기다.


1. Tool을 열어주는 순간, 통제권이 넘어간다

Agent에게 Tool을 주는 건 생각보다 무거운 결정이다.

LLM이 텍스트만 생성할 때는 최악의 경우가 “이상한 답변”이다.

하지만 Tool을 쥐어주는 순간 최악의 경우는 “실제 시스템에 영향을 미치는 행동”이 된다.

처음 멀티 에이전트를 설계할 때 나는 이 무게를 과소평가했다.

“Tool을 많이 주면 더 똑똑하게 동작하겠지”라고 생각했다.

결과는 정반대였다.


2. Tool을 많이 줄수록 예측이 어려워졌다

금융 데이터를 다루는 에이전트를 만들면서 처음에 이런 Tool들을 열어줬다.

  • 데이터베이스 읽기/쓰기
    • 파일 시스템 접근
      • 알림 발송 (Telegram, Slack)
  • – 외부 API 호출 (시세 조회, 뉴스 검색)

    Agent는 “필요하면 알아서 쓰겠지”라는 기대와 함께 모든 Tool에 접근할 수 있었다.

    문제는 금방 드러났다. 같은 질문에 어떤 때는 API를 3번 호출하고, 어떤 때는 10번 호출했다

    DB에 쓰기 작업이 예상치 못한 타이밍에 실행됐다

    알림이 중복으로 발송되거나, 아예 발송되지 않았다

    Agent가 Tool을 “잘” 쓰는 게 아니라 “자기 판단대로” 쓰고 있었다.

    그 판단이 매번 달랐다.


    3. Tool 권한 설계의 첫 번째 원칙: 기본은 금지

    여러 번 시행착오를 겪고 나서 정한 첫 번째 원칙이다.

    “Agent에게 Tool은 기본적으로 금지. 명시적으로 열어준 것만 허용.”

    처음에는 반대로 했다.

    모든 Tool을 열어두고 문제가 생기면 하나씩 막는 방식.

    이건 절대 따라잡을 수 없다.

    Agent는 창의적으로 Tool을 조합해서 예상 못한 행동을 만들어낸다.

    지금은 반대로 한다.

    Agent를 생성할 때 빈 Tool 목록으로 시작한다.

    그리고 그 Agent의 역할에 꼭 필요한 Tool만 하나씩 추가한다.

    # Before: 모든 Tool 허용tools = [api_tool, db_tool, file_tool, alert_tool]# After: 역할별 최소 Tool만 허용 analyst_tools = [api_read_tool] # 읽기만 writer_tools = [db_write_tool] # 쓰기만, 특정 테이블만

    이렇게 하면 Agent의 행동 범위가 명확해진다.

    “이 Agent는 이것만 할 수 있다”가 코드에서 바로 보인다.


    4. 두 번째 원칙: 읽기와 쓰기를 분리

    금융 도메인에서 특히 중요했던 원칙이다.

    “읽기 Tool과 쓰기 Tool을 같은 Agent에게 주지 않는다.”

    처음에는 하나의 Agent가 데이터를 조회하고, 분석하고, 결과를 저장했다.

    편해 보였다. 하지만 이 구조에서 Agent는 자기가 쓴 데이터를 다시 읽고

    그걸 기반으로 또 쓰는 루프에 빠졌다.

    잘못된 분석 결과가 DB에 저장되고, 그 결과를 다시 읽어서 더 잘못된 결론을 내렸다.

    지금은 역할을 분리한다.

    • Reader Agent: 데이터를 조회만 한다. 쓰기 Tool이 없다.

    • Analyzer Agent: Reader가 전달한 데이터를 분석한다. DB 접근이 없다.
    • Writer Agent: Orchestrator가 승인한 결과만 저장한다.

    Agent가 자기 행동의 결과를 직접 확인하고 수정하는 구조를 막는 게 핵심이다.


    5. 세 번째 원칙: 비용이 드는 Tool은 Orchestrator 승인 필수

    LLM은 비용 개념이 없다.

    외부 API 호출이 건당 얼마인지, 알림 발송이 무료인지 유료인지 모른다.

    처음에 Agent에게 뉴스 검색 API를 열어줬을 때 일어난 일이다.

    Agent는 “더 정확한 분석”을 위해 같은 키워드로 API를 수십 번 호출했다.

    하루 만에 API 비용이 예상의 10배가 나왔다.

    지금은 비용이 발생하는 Tool은 직접 호출을 막는다.

    # Agent가 직접 호출하지 않음 # 대신 "요청"만 생성 class NewsSearchRequest: keyword: str reason: str # 왜 필요한지

    # Orchestrator가 검토 후 실행 def approve_search(request: NewsSearchRequest) -> bool: if daily_api_count >= DAILY_LIMIT: return False if request.keyword in recent_searches: return False # 중복 방지 return True

    Agent는 “이 검색이 필요하다”는 요청을 생성할 뿐이다.실제 실행은 Orchestrator가 예산과 중복 여부를 확인한 후에 한다.


    6. Tool 권한 설계 후 달라진 것

    이 세 가지 원칙을 적용하고 나서 달라진 점이 있다.


    예측 가능성이 생겼다.


    Agent가 어떤 행동을 할 수 있는지 코드만 보면 안다.


    “이 Agent는 읽기만 한다” “이 Agent는 승인 없이 외부 호출을 못 한다”


    이게 명확하니까 디버깅도 쉬워졌다.


    문제가 생기면 “어떤 Tool이 잘못 사용됐는지”부터 확인한다.


    범위가 좁으니까 원인을 빨리 찾는다.


    비용이 통제됐다.


    API 호출 횟수, DB 쓰기 빈도가 예측 가능한 범위 안에 들어왔다.


    “오늘 API를 몇 번 호출할 것 같다”를 대략 예상할 수 있게 됐다.


    7. 지금 내가 쓰는 Tool 권한 체크리스트

    새 Agent를 만들 때 이 질문들을 먼저 던진다.1. 이 Agent의 역할에 꼭 필요한 Tool은 무엇인가?
    – 필요 없는 Tool은 처음부터 주지 않는다2. 이 Tool은 읽기인가, 쓰기인가?
    – 둘 다 필요하면 Agent를 분리한다3. 이 Tool은 비용이 발생하는가?
    – 발생하면 Orchestrator 승인 로직을 추가한다4. 이 Tool의 실행 결과를 Agent가 다시 읽을 수 있는가?
    – 가능하면 피드백 루프가 생기지 않는지 확인한다5. 이 Tool이 실패하면 어떻게 되는가?
    – 실패 시 행동을 코드로 정의한다 (재시도 횟수, fallback)


    마무리하며

    Agent에게 Tool을 주는 건 권한을 위임하는 것이다.위임에는 항상 범위가 필요하다.”알아서 잘 해줘”는 사람 사이에서도 잘 안 되는데, LLM에게는 더 안 된다.Tool 권한을 설계할 때 나는 이 질문을 계속 던진다.”이 Agent가 이 Tool을 잘못 쓰면 무슨 일이 생기는가?”그 답이 “별일 없다”가 아니면, 제한을 건다.


    다음 글에서는 이렇게 설계한 멀티 에이전트 시스템을 실제로 운영하면서 겪은

    모니터링과 디버깅 이야기를 정리해보려 한다.

    댓글 남기기