# Gemini CLI 마스터하기(심화): v24 - 안전한 외부 도구 연동: `ToolSchema`와 `Guarded Actions` 이전 단계에서는 동적 프롬프트 템플릿 엔진을 커스터마이징하여 Gemini 에이전트의 '지능'과 '페르소나'를 조절하는 방법을 배웠습니다. 이제 에이전트가 외부 세계와 직접 상호작용하는 '손발'을 어떻게 정교하고 안전하게 제어하고 확장하는지에 대해 알아보겠습니다. 바로 LLM 기반 '도구 사용(Tool Use)' 또는 '함수 호출(Function Calling)' 기능의 핵심인 **`ToolSchema`와 `Guarded Actions`**에 대한 탐구입니다. --- ## 1. LLM 도구 사용(Function Calling)의 중요성 대규모 언어 모델(LLM)은 뛰어난 언어 이해 및 생성 능력을 가지고 있지만, 학습 데이터에 없는 최신 정보를 가져오거나, 외부 시스템에서 실제 액션을 수행하는 데는 한계가 있습니다. '도구 사용' 기능은 이러한 LLM의 한계를 넘어서게 해줍니다. * **정보 검색:** 실시간 데이터(예: 현재 날씨, 주식 가격), 사내 데이터베이스, 특정 웹사이트에서 정보를 가져올 수 있습니다. * **실제 액션 수행:** 이메일 전송, 캘린더 이벤트 생성, 데이터베이스 변경, 시스템 명령 실행 등 실제 세계에 영향을 미치는 작업을 수행할 수 있습니다. * **정확성 및 신뢰성 향상:** 검색된 최신 정보를 바탕으로 답변을 생성하여 '환각(Hallucination)'을 줄이고 답변의 신뢰도를 높입니다. 하지만 LLM에게 아무런 제어 없이 외부 도구 사용을 허용하는 것은 큰 위험을 초래할 수 있습니다. (예: 잘못된 명령어 실행, 민감한 정보 유출) `Guarded Actions`는 이러한 위험을 최소화하며 안전한 도구 연동을 가능하게 합니다. ## 2. `ToolSchema`: 도구의 명세 정의 에이전트가 어떤 도구를 사용할지, 어떻게 사용해야 할지 알려주는 것이 `ToolSchema`입니다. `ToolSchema`는 도구의 메타데이터를 정의하여 LLM이 사용자의 자연어 요청을 분석하고, 가장 적절한 도구를 선택하며, 필요한 인자(argument)를 올바른 형식으로 추출할 수 있도록 돕습니다. ```python # ToolSchema 스니펫 (예시) class ToolSchema: def __init__(self, name: str, description: str, parameters: dict): self.name = name self.description = description self.parameters = parameters # JSON Schema 형식으로 인자 명세 ``` * **`name`:** 도구의 고유한 이름 (예: `send_email`, `query_database`) * **`description`:** 도구가 어떤 기능을 수행하는지 자연어로 설명합니다. 이 설명은 LLM이 도구를 선택하는 데 중요한 단서가 됩니다. * **`parameters`:** 도구 실행에 필요한 인자들의 명세입니다. 일반적으로 JSON Schema 형식을 따르며, 각 인자의 이름, 타입, 설명, 필수 여부 등을 정의합니다. **LLM의 역할:** LLM은 `ToolSchema`를 보고, 사용자의 "이메일을 보내줘"라는 요청을 `send_email` 도구를 호출해야 하는 것으로 판단하고, "누구에게?", "제목은?", "내용은?"과 같은 인자를 추출합니다. ## 3. `GuardedAction`: 안전한 도구 실행의 핵심 `GuardedAction`은 외부 도구의 실행을 감싸는(wrap) 메커니즘으로, **안전성, 신뢰성, 자원 관리**를 보장하는 핵심 요소입니다. `GuardedAction`은 실제 도구의 기능을 수행하는 `func` 외에 `prepare`와 `cleanup`이라는 명시적인 단계들을 가집니다. ```python # GuardedAction 스니펫 (예시) class GuardedAction: def __init__(self, name: str, func: Callable, prepare_func: Callable = None, cleanup_func: Callable = None): self.name = name self.func = func # 실제 도구의 기능 (Callable) self.prepare_func = prepare_func # func 실행 전 준비 작업 (Callable) self.cleanup_func = cleanup_func # func 실행 후 정리 작업 (Callable) ``` * **`prepare_func` (준비 작업):** * **실행 시점:** `func`가 실행되기 *전에* 반드시 실행됩니다. * **역할:** 도구 실행에 필요한 사전 조건 검사, 자원 할당(예: 데이터베이스 연결, 파일 핸들 획득), 입력 유효성 검사, 잠금(lock) 획득 등 안전하고 성공적인 `func` 실행을 위한 모든 준비 작업을 수행합니다. `prepare_func`가 실패하면 `func`는 실행되지 않습니다. * **`func` (실제 작업):** * **실행 시점:** `prepare_func`가 성공적으로 완료된 *후에만* 실행됩니다. * **역할:** 도구의 핵심 기능을 수행합니다. (예: SQL 쿼리 실행, 이메일 전송) * **`cleanup_func` (정리 작업):** * **실행 시점:** `prepare_func` 또는 `func` 실행이 완료되거나 실패한 *후에 항상* 실행됩니다. (try-finally 블록처럼 작동) * **역할:** 할당된 자원 해제(예: 데이터베이스 연결 종료, 파일 핸들 닫기), 상태 초기화, 로깅, 오류 처리 등 모든 사후 정리 작업을 수행합니다. 이는 도구 실행의 성공 여부와 관계없이 반드시 실행되어야 하는 작업입니다. **`GuardedAction`의 이점:** * **자원 누수 방지:** `cleanup_func`를 통해 할당된 자원이 항상 해제됨을 보장합니다. * **안정적인 실행:** `prepare_func`가 유효성 검사를 수행하여 잘못된 입력이나 상태에서 도구가 실행되는 것을 방지합니다. * **강력한 오류 처리:** `func` 실행 중 오류가 발생하더라도 `cleanup_func`는 정상적으로 실행되어 일관된 상태를 유지합니다. ## 4. `CallableInvoker`: 도구 호출 메커니즘 (간략히) `CallableInvoker`는 LLM이 선택한 `ToolSchema`와 추출된 인자를 바탕으로, 해당 `GuardedAction`을 실제로 실행하는 역할을 담당하는 컴포넌트입니다. `prepare_func`, `func`, `cleanup_func`의 실행 흐름을 관리하고, 그 결과를 다시 LLM에 전달하여 최종 답변을 생성하도록 합니다. ## 5. 요약 `ToolSchema`는 에이전트가 어떤 도구를 사용할지 '지능적으로' 선택할 수 있도록 돕는 도구의 '설명서'이며, `GuardedAction`은 그 선택된 도구를 '안전하고 신뢰성 있게' 실행할 수 있도록 보장하는 '실행 프레임워크'입니다. 이 두 가지 핵심 개념이 결합되어 Gemini CLI 에이전트는 외부 세계와 복잡하고 의미 있는 상호작용을 수행할 수 있게 됩니다. 이제 `ToolSchema`와 `Guarded Actions`의 개념을 이해했으니, 다음 최종 단계에서는 이 모든 지식을 종합하여 **나만의 'K8s 상태 모니터링' Guarded Action 도구를 직접 만들고 에이전트에 연동**하는 실전 예제를 통해, Gemini CLI의 확장성을 직접 경험해 보겠습니다.