Open-Source AI Cookbook documentation

다중 에이전트 계층 구조에서 여러 에이전트가 협업하도록 하기

Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

Open In Colab

다중 에이전트 계층 구조에서 여러 에이전트가 협업하도록 하기

작성자: Aymeric Roucher, 번역: 김하림

이 튜토리얼은 고급 수준이므로, 시작하기 전에 이 에이전트 쿡북에서 다루는 기본 개념을 알고가는 것이 좋습니다!

우리는 이 노트북에서 다중 에이전트 웹 브라우저를 만들 것입니다. 여러 에이전트가 웹을 사용하여 문제를 해결하기 위해 협업하는 에이전트 시스템입니다!

이 시스템은 간단한 계층 구조로 되어있습니다. 여기서 ManagedAgent 객체를 사용하여 웹 검색 에이전트를 관리합니다. 이 구조를 통해 웹 검색 에이전트의 기능을 효과적으로 제어하고 조정할 수 있습니다.

              +-----------------+
              |   관리자 에이전트   |
              +-----------------+
                       |
        _______________|______________
       |                              |
  코드 인터프리터        +--------------------------------+
      도구            |         관리되는 에이전트           |
                     |      +------------------+      |
                     |      |   웹 검색 에이전트   |      |
                     |      +------------------+      |
                     |         |            |         |
                     |    웹 검색 도구         |         |
                     |               웹페이지 방문 도구    |
                     +--------------------------------+                     

환경 구성부터 시작해보겠습니다.

다음 명령어를 실행하여 필요한 패키지를 설치하세요.

!pip install markdownify duckduckgo-search "transformers[agents]" --upgrade -q

Hugging Face Hub API를 사용하기 위해서는 로그인이 필요합니다.

아래 코드를 실행하여 로그인해주세요.

from huggingface_hub import notebook_login

notebook_login()

⚡️ 우리의 에이전트는 Qwen/Qwen2.5-72B-Instruct 모델을 사용합니다. 이 모델은 HfApiEngine 클래스를 통해 Hugging Face의 Inference API로 호출됩니다. Inference API를 활용하면 다양한 오픈 소스 모델을 빠르고 쉽게 실행할 수 있습니다.

Note: Inference API는 다양한 기준에 따라 모델을 호스팅하며, 배포된 모델은 사전 통지 없이 업데이트되거나 교체될 수 있으므로 여기에서 자세한 내용을 확인해보세요.

역주: 이 노트북을 실행하려면 Hugging Face에서 발급받은 HF_TOKEN을 Google Colab의 보안 변수(Secrets)로 등록해야 합니다. 또한, 여기서 사용되는 모델들은 Hugging Face의 Pro 구독이 필요합니다. 무료 계정으로는 접근이 제한될 수 있으니 주의해 주세요.

model = "Qwen/Qwen2.5-72B-Instruct"

🔍 웹 검색 도구 만들기

웹 브라우징을 위해 우리는 기존에 있는 DuckDuckGoSearchTool 도구를 사용할 것입니다. 이 도구는 Google 검색과 비슷한 기능을 제공합니다.

그러나 DuckDuckGoSearchTool이 찾은 웹페이지의 내용을 자세히 볼 수 있는 기능도 필요합니다. 이를 위해 라이브러리에 있는 VisitWebpageTool을 사용할 수도 있지만, 우리는 이 도구를 직접 만들어보며 그 과정을 이해해 보려고 합니다.

그래서 markdownify를 사용하여 VisitWebpageTool 도구를 처음부터 만들어 보도록 하겠습니다.

import re
import requests
from markdownify import markdownify as md
from requests.exceptions import RequestException
from transformers.agents import tool
from urllib.parse import unquote


@tool
def visit_webpage(url: str) -> str:
    """주어진 URL 웹페이지를 방문하고 그 내용을 마크다운 문자열로 반환합니다.

    Args:
        url: 방문할 웹페이지의 URL

    Returns:
        마크다운으로 변환된 웹페이지 내용, 또는 요청 실패 시 오류 메시지
    """
    try:
        # URL로 GET 요청 보내기
        response = requests.get(url)
        response.raise_for_status()  # 잘못된 상태 코드에 대한 예외 처리

        # HTML 내용을 마크다운으로 변환하기
        markdown_content = md(response.text).strip()

        # 중복된 개행 문자 제거하기
        markdown_content = re.sub(r"\n{3,}", "\n\n", markdown_content)

        # URL 디코딩하기
        markdown_content = re.sub(r"\((.*?)\)", lambda m: "(" + unquote(m.group(1)) + ")", markdown_content)

        return markdown_content

    except RequestException as e:
        return f"웹페이지 가져오기 오류: {str(e)}"
    except Exception as e:
        return f"예상치 못한 오류 발생: {str(e)}"

이제, 우리의 도구를 테스트해봅시다!

역주: 한글이 포함된 URL의 디코딩을 처리하기 위해 코드를 추가하였습니다.

>>> print(visit_webpage("https://ko.wikipedia.org/wiki/Hugging_Face")[:500])
허깅 페이스 \- 위키백과, 우리 모두의 백과사전

[본문으로 이동](#bodyContent)

주 메뉴

주 메뉴
사이드바로 이동
숨기기

 둘러보기
 

* [대문](/wiki/위키백과:대문 "대문으로 가기 [z]")
* [최근 바뀜](/wiki/특수:최근바뀜 "위키의 최근 바뀐 목록 [r]")
* [요즘 화제](/wiki/포털:요즘_화제 "최근의 소식 알아 보기")
* [임의의 문서로](/wiki/특수:임의문서 "무작위로 선택된 문서 불러오기 [x]")

 사용자 모임
 

* [사랑방](/wiki/위키백과:사랑방)
* [사용자 모임](/wiki/위키백과:사용자_모임 "위키백과 참여자를 위한 토론/대화 공간입니다.")
* [관리 요청](/wiki/위키백과:요청)

 편집 안내
 

* [소개](/wiki/도움말:소개)
* [도움말](/wiki/위키백과:도움말 "도움말")
* [정책과 지침](/wiki/위키백과:정책과_지침)
* [질문방](/wiki/위키백과:질문방)

[![](

다중 에이전트 시스템 구축하기 🤖🤝🤖

이제 searchvisit_webpage 도구를 모두 갖추었으니, 이를 이용해 웹 에이전트를 만들 수 있습니다.

이 에이전트를 어떻게 구성하는 것이 좋을까요?

  • 웹 브라우징은 병렬 도구 호출이 필요 없는 단일 타임라인 작업이므로, JSON 도구 호출이 적합합니다. 따라서 ReactJsonAgent를 선택합니다.
  • 또한, 웹 검색은 때때로 정확한 답변을 찾기 위해 여러 페이지를 탐색해야 할 수 있으므로, max_iterations를 10으로 늘리는 것이 좋습니다.
from transformers.agents import (
    ReactCodeAgent,
    ReactJsonAgent,
    HfApiEngine,
    ManagedAgent,
)
from transformers.agents.search import DuckDuckGoSearchTool

llm_engine = HfApiEngine(model)

web_agent = ReactJsonAgent(
    tools=[DuckDuckGoSearchTool(), visit_webpage],
    llm_engine=llm_engine,
    max_iterations=10,
)

그런 다음 이 웹 검색 에이전트를 ManagedAgent로 감싸줍니다. 이렇게 하면 상위의 관리자 에이전트가 이 에이전트를 쉽게 제어할 수 있습니다.

managed_web_agent = ManagedAgent(
    agent=web_agent,
    name="search",
    description="Runs web searches for you. Give it your query as an argument.",
)

이제 관리자 에이전트를 생성합니다. 이때 managed_agents 매개변수에 우리가 만든 관리 받는 에이전트를 전달합니다.

관리자 에이전트는 전체적인 계획 수립과 복잡한 사고를 담당해야 하므로, 고급 추론 능력이 필요합니다. 이런 이유로 ReactCodeAgent를 사용하는 것이 가장 적합할 것 같습니다.

마지막으로, 현재 연도와 관련된 질문을 처리하기 위해 additional_authorized_imports=["time", "datetime"]을 설정에 추가합니다. 이렇게 하면 에이전트가 시간과 관련 정보를 다룰 수 있게 됩니다.

manager_agent = ReactCodeAgent(
    tools=[],
    llm_engine=llm_engine,
    managed_agents=[managed_web_agent],
    additional_authorized_imports=["time", "datetime"],
)

이것으로 모든 준비가 끝났습니다! 이제 우리의 시스템을 실행해봅시다. 계산이 필요한 질문을 던져보겠습니다.

manager_agent.run("Stripe는 몇 년 전에 설립되었나요?")

이렇게 에이전트들이 협력하여 과제를 해결했습니다! ✅

💡 이 시스템은 쉽게 더 많은 에이전트로 확장될 수 있습니다. 예를 들어, 한 에이전트는 코드 실행을 담당하고, 다른 에이전트는 웹 검색을, 또 다른 에이전트는 파일 로딩을 처리하는 식으로 말이죠.

🤔💭 더 나아가 복잡한 트리 구조의 계층을 생각해볼 수도 있습니다. 최고 경영자(CEO) 에이전트가 여러 중간 관리자를 관리하고, 각 중간 관리자는 다시 여러 부하 직원을 관리하는 구조를 만들 수 있죠.

심지어 더 많은 중간 관리 계층을 추가하고, 매일 여러 번의 회의를 하고, 스크럼 마스터와 함께 애자일 방식을 도입할 수도 있습니다. 그리고 각 새로운 구성 요소는 충분한 마찰을 추가하여 결국 아무 일도 완수되지 않도록 할 수 있겠죠… 음, 잠깐만요. 그건 아니겠네요. 우리의 단순한 구조를 유지하는 것이 좋겠습니다.

< > Update on GitHub