10분 안에 PydanticAI 에이전트에 도구를 추가하는 방법

발행: (2026년 3월 16일 오전 06:01 GMT+9)
10 분 소요
원문: Dev.to

Source: Dev.to


PydanticAI 에이전트에 도구를 10분 만에 추가하는 방법

PydanticAI는 Pydantic 모델을 기반으로 하는 LLM(대형 언어 모델) 에이전트를 빠르게 만들 수 있게 해주는 라이브러리입니다. 이번 포스트에서는 이미 존재하는 에이전트에 새로운 도구(tool) 를 연결하는 과정을 단계별로 살펴보겠습니다. 코드는 최소한의 수정만으로 동작하도록 설계되었습니다.

1️⃣ 사전 준비

pip install pydantic-ai

Tip: 최신 버전을 사용하려면 pip install -U pydantic-ai 를 실행하세요.

2️⃣ 기본 에이전트 정의

아래 예시에서는 ChatAgent 라는 간단한 에이전트를 정의합니다. BaseModel 을 상속받아 입력과 출력 스키마를 선언합니다.

from pydantic import BaseModel
from pydantic_ai import Agent

class ChatInput(BaseModel):
    user_message: str

class ChatOutput(BaseModel):
    response: str

class ChatAgent(Agent):
    name = "ChatAgent"
    description = "일반적인 대화용 챗봇"
    input_schema = ChatInput
    output_schema = ChatOutput

3️⃣ 도구 정의

도구는 함수 형태로 구현하고, Tool 클래스를 상속받아 메타데이터를 지정합니다.

from pydantic_ai import Tool

class WeatherTool(Tool):
    name = "weather"
    description = "주어진 도시의 현재 날씨를 반환합니다."

    class Input(BaseModel):
        city: str

    class Output(BaseModel):
        temperature_celsius: float
        condition: str

    def run(self, input: Input) -> Output:
        # 여기서는 가짜 데이터를 반환합니다.
        return self.Output(
            temperature_celsius=22.5,
            condition="맑음"
        )

4️⃣ 에이전트에 도구 연결

add_tool 메서드를 사용해 에이전트 인스턴스에 도구를 등록합니다.

agent = ChatAgent()
weather_tool = WeatherTool()
agent.add_tool(weather_tool)

5️⃣ 실행 예시

result = agent.run(
    ChatInput(user_message="서울의 날씨가 궁금해요.")
)
print(result.response)

출력 예시:

현재 서울의 온도는 22.5°C이며, 날씨는 맑음입니다.

6️⃣ 여러 도구를 한 번에 추가하기

도구가 여러 개라면 리스트에 담아 add_tools 로 한 번에 등록할 수 있습니다.

class CurrencyTool(Tool):
    name = "currency"
    description = "환율 정보를 제공합니다."

    class Input(BaseModel):
        from_currency: str
        to_currency: str

    class Output(BaseModel):
        rate: float

    def run(self, input: Input) -> Output:
        # 실제 API 호출 대신 고정값 반환
        return self.Output(rate=0.85)

# 에이전트에 여러 도구 추가
agent.add_tools([weather_tool, CurrencyTool()])

7️⃣ 도구 사용 흐름 이해하기

  1. 프롬프트: 사용자가 질문을 입력합니다.
  2. LLM: 질문을 분석하고, 필요한 도구를 판단합니다.
  3. 도구 호출: 에이전트는 해당 도구를 실행하고 결과를 받아옵니다.
  4. 응답 생성: LLM이 도구 결과를 바탕으로 최종 응답을 작성합니다.

8️⃣ 디버깅 팁

  • agent.tools 를 출력해 현재 등록된 도구 목록을 확인하세요.
  • 도구의 입출력 스키마BaseModel 을 정확히 상속했는지 검증합니다.
  • run 메서드 내부에서 외부 API를 호출한다면 예외 처리를 반드시 추가하세요.

9️⃣ 마무리

PydanticAI는 타입 안전자동 검증을 제공하므로, 복잡한 도구 체인을 구성하더라도 코드가 깨지지 않고 안정적으로 동작합니다. 이번 튜토리얼을 통해 기본적인 도구 추가 방법을 익혔으니, 이제 여러분만의 맞춤형 에이전트를 만들어 보세요!


Happy coding! 🚀

코드

import httpx
from dataclasses import dataclass
from pydantic import BaseModel
from pydantic_ai import Agent, RunContext

@dataclass
class Deps:
    http_client: httpx.Client

class CityWeather(BaseModel):
    city: str
    temperature_f: float
    summary: str
    recommendation: str

agent = Agent(
    "openai:gpt-4o-mini",
    deps_type=Deps,
    output_type=CityWeather,
    instructions="You help users check weather conditions. Use the tools provided to fetch real data before answering.",
)

@agent.tool
def get_coordinates(ctx: RunContext[Deps], city: str) -> str:
    """Get latitude and longitude for a city."""
    response = ctx.deps.http_client.get(
        "https://geocoding-api.open-meteo.com/v1/search",
        params={"name": city, "count": 1},
    )
    data = response.json()
    if not data.get("results"):
        return f"City '{city}' not found."
    result = data["results"][0]
    return f"{result['name']}: lat={result['latitude']}, lon={result['longitude']}"

@agent.tool
def get_weather(ctx: RunContext[Deps], latitude: float, longitude: float) -> str:
    """Get current weather for coordinates."""
    response = ctx.deps.http_client.get(
        "https://api.open-meteo.com/v1/forecast",
        params={
            "latitude": latitude,
            "longitude": longitude,
            "current": "temperature_2m,wind_speed_10m",
            "temperature_unit": "fahrenheit",
        },
    )
    data = response.json()["current"]
    return f"Temperature: {data['temperature_2m']}F, Wind: {data['wind_speed_10m']} km/h"

result = agent.run_sync(
    "What's the weather like in Tokyo?",
    deps=Deps(http_client=httpx.Client()),
)

print(result.output.city)
print(f"{result.output.temperature_f}F")
print(result.output.summary)
print(result.output.recommendation)

설치 및 실행

pip install pydantic-ai httpx
export OPENAI_API_KEY="sk-..."
python weather_agent.py

작동 방식

데이터 클래스로 의존성을 정의합니다.
Deps 클래스는 HTTP 클라이언트를 보유합니다. PydanticAI는 RunContext를 통해 이를 모든 도구 호출에 주입합니다—전역 변수도, 싱글톤도 없습니다. 테스트용으로 모의(mock) 클라이언트를 교체하면 도구가 동일하게 동작합니다.

Pydantic 모델로 출력 타입을 설정합니다.
CityWeather는 에이전트 응답의 정확한 형태를 정의합니다. PydanticAI는 LLM이 이 스키마에 맞는 데이터를 반환하도록 강제하여, 문자열을 파싱할 필요 없이 타입이 지정된 Python 객체를 받게 됩니다.

@agent.tool 로 도구를 등록합니다.
데코레이터가 붙은 각 함수는 LLM이 호출할 수 있는 도구가 됩니다. 함수 시그니처는 도구의 매개변수 스키마가 되고, docstring은 도구 설명이 됩니다—모델이 언제 호출해야 하는지 명확히 알 수 있도록 작성하세요.

에이전트가 도구를 자동으로 연결합니다.
예를 들어 “도쿄 날씨가 어때?”라고 물으면 에이전트는 먼저 get_coordinates를 호출해 위도/경도를 얻고, 그 좌표를 사용해 get_weather를 호출합니다. 이 오케스트레이션 로직을 직접 작성하지 않아도—LLM이 도구 설명을 기반으로 순서를 파악합니다.

당신이 보게 될 내용

Tokyo
58.4F
가벼운 바람과 함께 온화하고 차분한 날씨.
가벼운 재킷을 입기에 적합한 날씨 -- 도시를 걸어 다니기에 편안합니다.

응답은 검증된 CityWeather 객체입니다. .city, .temperature_f, .summary, 그리고 .recommendation에 직접 접근하세요—JSON 파싱이나 문자열 추출이 필요 없습니다.

Key Details

  • Docstrings는 중요합니다. LLM은 도구의 docstring을 사용하여 언제 호출할지 결정합니다. “Get latitude and longitude for a city”와 같은 명확한 설명은 모델을 올바르게 안내합니다.
  • Type hints는 스키마를 구동합니다. city: strlatitude: float가 도구의 JSON 스키마가 됩니다. PydanticAI는 함수가 실행되기 전에 LLM의 인수를 검증합니다—추가 타입‑체크 코드는 필요 없습니다.
  • Dependencies는 도구를 테스트 가능하게 유지합니다. get_weather 내부에서 HTTP 클라이언트를 생성하는 대신, ctx.deps를 통해 클라이언트를 받습니다. 테스트에서는 고정된 응답을 반환하는 모크 클라이언트를 전달하면 됩니다. 이 패턴은 FastAPI 개발자에게 익숙합니다.

더 나아가기

  • Agent() 생성자에 retries=3을 추가하여 검증 실패 시 자동 재시도를 수행합니다.
  • 동시 API 호출을 위해 httpx.AsyncClient와 함께 async 도구 함수를 사용합니다.
  • 실시간 스트리밍 응답을 위해 agent.run_stream()와 결합합니다.

AI Agent Quick Tips 시리즈의 다른 게시물을 확인하세요:

도구 오케스트레이션, 스케줄링, 메모리가 필요하지만 인프라 작업을 원하지 않는 에이전트를 구축하고 있나요? Nebula가 이를 처리해 주어 도구에 집중할 수 있습니다.

0 조회
Back to Blog

관련 글

더 보기 »

트라비고

Gemini와 함께 말하는 속도만큼 빠르게 여행하세요! 라이브 에이전트가 몰입형 스토리텔링 및 3D 내비게이션과 만나는 곳. 이 프로젝트는 Gemini Live Ag...에 진입하기 위해 만들어졌습니다.