다중 에이전트 계층 구조에서 여러 에이전트가 협업하도록 하기
작성자: 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/위키백과:질문방) [![](
다중 에이전트 시스템 구축하기 🤖🤝🤖
이제 search
와 visit_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