도구와 MCP

도구와 MCP (Tools and MCP)

도구(tool)는 DSPy 프로그램이 언어 모델이 고른 Python 코드를 호출하게 해 줍니다. 모델은 이름, 설명, 인자 스키마를 보고, 도구를 선택하고 인자를 공급합니다. DSPy가 그 callable을 실행하고 결과를 프로그램이 쓸 수 있게 해요.

출처: 문서

본문

도구는 ReAct 전용 기능이 아니라 DSPy의 공유 기본 요소(primitive) 입니다. dspy.ReAct 와 dspy.ReActV2 는 에이전트 루프에서 도구를 쓰고, dspy.RLM 은 인터프리터 안에서 도구를 노출하며, dspy.Flex 는 최적화된 프로그램에 도구를 연결할 수 있고, 어댑터는 네이티브 공급자 함수 호출에 같은 도구 스키마를 씁니다. dspy.utils.mcp 는 원격 MCP 도구를 이 인터페이스로 브리지합니다.

이 페이지는 도구를 정의·감싸기·검증·임포트하고 싶을 때 읽으세요. 언제 호출할지를 결정하는 에이전트 루프는 ReAct와 ReActV2를 보세요.

도구 정의하기

DSPy 도구는 평범한 타입이 지정된 Python 함수로 시작할 수 있어요:

def search(query: str, limit: int = 5) -> list[str]:
    """Search the knowledge base for relevant passages."""
    return index.search(query, limit=limit)

tools= 를 받는 모듈들은 callable을 dspy.Tool 로 자동 변환합니다:

agent = dspy.ReAct("question -> answer", tools=[search])

메타데이터를 검사하거나 오버라이드해야 할 때는 함수를 명시적으로 감싸세요:

search_tool = dspy.Tool(
    search,
    name="search_docs",
    desc="Search the product documentation.",
)

좋은 이름, 설명, 파라미터 이름, 타입 힌트가 중요합니다. 그것들이 모델이 그 함수를 호출할지·어떻게 호출할지 결정할 때 쓰는 인터페이스이기 때문이에요.

dspy.Tool 이 동작하는 방식

스키마와 메타데이터는 추론된다

dspy.Tool 은 callable을 func 에 저장하고 함수 시그니처, 타입 힌트, docstring에서 name, desc, args, arg_types, arg_desc 를 파생합니다. Pydantic 주석은 JSON 스키마로 변환되고 로컬 $ref 경로는 해석되어 모델이 완전한 인자 모양을 받습니다. 명시적 생성자 값은 필드별로 추론을 오버라이드합니다.

인자는 실행 전에 검증된다

Tool.__call__(**kwargs) 와 Tool.acall(**kwargs) 는 인자를 JSON 스키마에 대해 검증하고 Pydantic으로 중첩된 주석 값을 강제 변환합니다. 동기 경로는 함수를 직접 호출하고, 비동기 경로는 코루틴 결과를 await하며 보통의 동기 함수도 받아들입니다.

동기 코드에서 비동기 도구를 호출하면 기본적으로 예외가 발생합니다. 런타임이 허용할 때만 변환에 옵트인하세요:

async_search_tool = dspy.Tool(async_search)

with dspy.context(allow_tool_async_sync_conversion=True):
    result = async_search_tool(query="DSPy")

변환이 명시적인 이유는 기존 이벤트 루프에서 비동기 도구를 구동하면 일부 환경에서 교착(deadlock)될 수 있기 때문입니다.

어댑터가 텍스트 또는 네이티브 포맷을 고른다

도구 자체는 공급자 중립(provider-neutral) 입니다. 어댑터가 그 스키마를 텍스트로 렌더링할지, 공급자의 네이티브 함수 호출 API로 보낼지 결정합니다. 예:

adapter = dspy.ChatAdapter(use_native_function_calling=True)

with dspy.context(adapter=adapter):
    result = agent(question="What changed in DSPy 3.3?")

네이티브 호출이 활성이고 LM이 지원하면, 어댑터는 각 도구를 Tool.format_as_litellm_function_call() 로 변환하고 결과 설명자들을 LM 요청에 보냅니다. 그렇지 않으면 DSPy의 일반 어댑터-포맷 필드에 도구 선택을 유지합니다. 같은 Tool 이 두 모드에서 모두 동작합니다.

구조화된 도구 호출과 결과

dspy.ToolCalls 는 어떤 공급자의 와이어 형식과 무관하게 모델이 요청한 호출을 나타냅니다. 각 ToolCalls.ToolCall 은 선택적 공급자 호출 ID, 도구 이름, 인자 사전을 지닙니다:

calls = dspy.ToolCalls.from_dict_list([
    {"name": "search", "args": {"query": "DSPy tools"}},
])

검증기는 DSPy의 {name, args} 모양과 흔한 공급자 스타일의 함수 호출 모양을 받아들입니다. 어댑터가 공급자 경계에서 변환을 처리하므로, 애플리케이션 코드는 DSPy 표현을 계속 사용할 수 있습니다.

도구 결과는 ToolCallResults 에서 ID, 이름, 값, 오류 플래그로 호출과 짝지어집니다. 이 짝지음은 어댑터가 네이티브 어시스턴트 도구 호출 뒤의 일치하는 공급자 tool 메시지를 재생할 수 있게 합니다. 또한 에이전트가 알 수 없는 도구나 실행 예외를 결과로 모델에 보고할 수 있게 하여, 실패한 턴을 잃어버리지 않게 합니다.

MCP 도구

MCP 서버는 JSON 스키마로 도구를 게시합니다. dspy.Tool.from_mcp_tool(session, tool) 은 살아있는 mcp.ClientSession 과 MCP 도구 정의를 DSPy 도구로 브리지하는 정식 경로입니다:

dspy_tool = dspy.Tool.from_mcp_tool(session, mcp_tool)

그 브리지는:

  1. MCP 입력 스키마를 DSPy의 args, arg_types, arg_desc 로 변환합니다.
  2. session.call_tool(...) 을 호출하는 비동기 callable을 만듭니다.
  3. MCP 텍스트 콘텐츠를 문자열이나 리스트로 언팩하고 비-텍스트 콘텐츠는 보존합니다.
  4. MCP 응답에 isError=True 가 있으면 실행 오류를 던집니다.

브리지는 MCP SDK v1의 camelCase 결과 필드와 v2의 snake_case 대체물을 모두 지원하며, 텍스트·비-텍스트 결과 동작은 바꾸지 않습니다. result_mode="structured" 를 넘기면 가능할 때 structuredContent 를 반환하고, 없으면 기본 변환으로 폴백합니다.

MCP 도구는 mcp.ClientSession 이 비동기이므로 비동기입니다. acall 같은 모듈의 비동기 진입점을 쓰거나, 적절할 때 async-to-sync 변환을 명시적으로 활성화하세요.

Tool.from_langchain(tool) 은 LangChain BaseTool 객체에 대한 동일한 브리지를 제공합니다.

API 살펴보기

dspy.Tool(func, name=None, desc=None, args=None, arg_types=None, arg_desc=None) callable을 감싸고 명시적으로 공급되지 않은 메타데이터를 추론합니다.

Tool.__call__(**kwargs) / Tool.acall(**kwargs) 동기 또는 비동기 진입점을 통해 도구 인자를 검증·강제 변환·실행합니다.

Tool.format_as_litellm_function_call() → dict 어댑터가 네이티브 호출에 쓰는 OpenAI/LiteLLM 스타일 함수 설명자를 반환합니다.

Tool.from_mcp_tool(session, tool, *, result_mode="text") → Tool 원격 MCP 도구를 비동기 DSPy 도구로 감쌉니다. result_mode="structured" 로 설정하면 가능할 때 구조화된 MCP 결과를 반환합니다.

Tool.from_langchain(tool) → Tool LangChain 도구를 같은 DSPy 인터페이스로 감쌉니다.

dspy.ToolCalls(tool_calls=[...]) 하나 이상의 요청된 호출을 공급자 중립 형태로 저장합니다.

크로스링크

더 알아보기 (Learn more)