`dspy.ReAct`로 프로그램에 도구 주기

dspy.ReAct로 프로그램에 도구 주기

시그니처만으로는 LM이 지식 밖의 구체적인 정보를 찍어 맞히기 어려울 때가 있어요. dspy.ReAct라는 모듈에 도구를 넘겨주면, 프로그램이 답을 쓰기 전에 검색으로 사실을 조사·근거(ground) 할 수 있게 됩니다. DSPy에서 도구는 그냥 Python 함수예요.

출처: 공식문서

도구로 프로그램을 근거에 세우기

우리의 하이쿠 작성기는 유능하지만, 불리는 지역에 관한 정보가 더 필요해요. 가을의 Bodega Bay에 대한 하이쿠를 요청받으면 LM은 날씨에 대해 그럴듯한 추측을 하지만, 때로는 틀리기도 하지요. 프로그램에 도구를 주면, 시를 쓰기 전에 참고 자료를 조사하고 근거를 세울 수 있습니다.

도구는 그냥 Python 함수다

DSPy 도구는 표준 Python 함수로, 타입 힌트가 붙은 파라미터와 독스트링을 가져요. DSPy는 함수의 이름·파라미터·독스트링을 읽어 LM으로 보낼 지시를 조립합니다.

예를 들어 에이전트가 wikipedia 라이브러리로 Wikipedia를 검색하게 하는 도구를 정의해 볼게요(따라 하려면 pip install wikipedia 실행).

import wikipedia

def wikipedia_search(query: str) -> list[str]:
    """Search Wikipedia for the given query and return a list of page titles."""
    return wikipedia.search(query)

dspy.ReAct 모듈은 이 도구를 이렇게 제시해요.

When selecting the next_tool_name and its next_tool_args, the tool must be one of:

(1) wikipedia_search, whose description is <desc>Search Wikipedia for the given query and return a list of page titles.</desc>. It takes arguments {'query': {'type': 'string'}}.
(2) finish, whose description is <desc>Marks the task as complete. That is, signals that all information for producing the outputs, i.e. `haiku`, are now available to be extracted.</desc>. It takes arguments {}.

DSPy가 함수 이름·독스트링·파라미터를 어떻게 모델에 제시하는지 주목하세요. 시그니처처럼 도구를 작성할 때도 이름 짓기에 신중해야 해요. wikipedia_search와 파라미터 query는 기능과 역할을 명확히 설명하는 좋은 이름입니다.

여기 우리가 정의하지 않은 도구가 하나 섞여 있어요. finishdspy.ReAct가 쓰는 특수 도구로, 모델이 작업을 끝냈을 때 호출합니다. dspy.ReAct가 이것은 자동으로 채워줘요.

Wikipedia를 쓰는 하이쿠 봇 정의하기

Wikipedia 검색에 더해, 에이전트가 특정 페이지를 가져올 도구도 필요해요.

def get_wikipedia_page(title: str) -> str:
    """Get the content of a Wikipedia page given its title."""
    return wikipedia.page(title).content

이 두 도구와 기존 HaikuBot 시그니처만 있으면 에이전트를 정의할 준비가 끝나요.

haiku_bot = dspy.ReAct(HaikuBot, tools=[wikipedia_search, get_wikipedia_page])
result = haiku_bot(location="Camp Meeker", mood="pensive", season="summer")
print(result.haiku)

haiku_bot을 호출하면 그것은:

  1. "Camp Meeker"를 Wikipedia에서 검색했고, "Camp Meeker, California"를 포함해 아홉 개의 관련 결과가 나왔어요.
  2. "Camp Meeker, California"의 페이지 콘텐츠를 가져왔어요.
  3. finish를 호출한 뒤 출력을 종합했지요.

위 코드는 이런 결과를 만들어요.

Redwood shadows breathe  
Summer creek whispers old tales  
Quiet mind lingers

result.reasoning을 출력하면 이렇게 나옵니다.

I gathered context about Camp Meeker, California—its redwood forest, Dutch Bill Creek, and the quiet summer atmosphere—from the Wikipedia page. I focused on a pensive mood and the summer season, weaving in imagery of towering trees and a gently flowing creek. The haiku follows the traditional 5‑7‑5 syllable structure, evoking the stillness and reflection of a summer day among the redwoods.

ReAct는 에이전틱 루프를 관리한다

ReAct는 테스트 시점(추론 시점)의 루프 전략이에요. 모델에게 도구 세트와 작업을 넘기면, dspy.ReAct 모듈은 모델이 도구를 사용해 추론한 뒤 행동하도록 지시합니다. 모델이 finish를 호출하면 DSPy는 루프를 멈추고 선언된 출력 필드를 만들기 위해 마지막 합성 패스를 한 번 실행해요.

모델이 루프를 몇 번 돌지는 스스로 정하지만, max_iters 파라미터로 횟수 상한을 정할 수 있어요.

haiku_bot = dspy.ReAct(HaikuBot, tools=[wikipedia_search, get_wikipedia_page], max_iters=4)

이 프로그램을 테스트하며 모델이 도구를 최대 8번 호출(Vermont 시럽 농업을 조사하면서)하는 실행과, 조사를 아예 건너뛰는 실행을 모두 봤어요.

ReAct 궤적(trajectory) 검사하기

ReAct의 반환 Prediction 인스턴스는 trajectory 필드를 지녀요. 각 생각(thought)·도구 호출·관찰(도구가 돌려준 것)을 순서대로 기록한 딕셔너리입니다. 에이전트가 의외의 동작을 하면 궤적이 가장 먼저 읽어야 할 것이에요.

이렇게 출력할 수 있습니다.

for step, value in result.trajectory.items():
    print(f"{step}: {value}")

도구 작성 패턴과 MCP 통합은 Tools and MCP, ReAct 루프의 실행 모델과 궤적 디버깅은 ReAct and ReActV2를 보세요.

실험적: ReActV2

dspy.ReActV2는 현재 ReAct 구현을 대체할 실험적인 구조화된 히스토리 버전이에요. DSPy 3.5에서 dspy.ReAct가 되며, 네이티브 멀티턴·병렬 도구 호출과 개선된 프롬프트 캐시 재사용을 가져옵니다. dspy.ReActV2 이름은 3.5 전반에 걸쳐 deprecated 호환 별칭으로 남고 3.6에서 제거될 예정이에요. The transition from ReAct to ReActV2를 참고하세요.

더 알아보기 (Learn more)