다중 에이전트 시스템 조율하기

다중 에이전트 시스템 조율하기 🤖🤝🤖

이 노트북에서는 다중 에이전트 웹 브라우저, 즉 여러 에이전트가 협력해 웹을 활용해 문제를 해결하는 에이전트 시스템을 만들어 볼 거예요!

단순한 계층 구조로 만들 거예요:

              +----------------+
              | Manager agent  |
              +----------------+
                       |
        _______________|______________
       |                              |
Code Interpreter            +------------------+
    tool                    | Web Search agent |
                            +------------------+
                               |            |
                        Web Search tool     |
                                   Visit webpage tool

자, 이 시스템을 구성해 봅시다.

아래 줄을 실행해 필요한 의존성을 설치하세요:

!pip install 'smolagents[toolkit]' --upgrade -q

Inference Providers를 호출하려면 HF에 로그인해야 해요:

from huggingface_hub import login

login()

⚡️ 우리 에이전트는 Qwen/Qwen3-Next-80B-A3B-Thinking 모델을 HF의 Inference API를 쓰는 InferenceClientModel 클래스로 구동할 거예요. Inference API는 어떤 OS 모델이든 빠르고 쉽게 실행할 수 있게 해줘요.

[!TIP] Inference Providers는 서버리스 인퍼런스 파트너들이 지원하는 수백 개의 모델에 접근을 제공해요. 지원되는 프로바이더 목록은 여기에서 확인할 수 있어요.

model_id = "Qwen/Qwen3-Next-80B-A3B-Thinking"

🔍 웹 검색 도구 만들기

웹 브라우징에는 이미 내장 WebSearchTool 도구를 써서 Google 검색에 준하는 기능을 낼 수 있어요.

하지만 WebSearchTool이 찾아낸 페이지 안을 들여다볼 수도 있어야 해요. 그러려면 라이브러리의 내장 VisitWebpageTool을 가져와 쓸 수도 있지만, 여기서는 어떻게 만드는지 보여드리기 위해 직접 다시 만들어 볼게요.

그래서 markdownify를 사용해 VisitWebpageTool 도구를 처음부터 만들어 봅시다.

import re
import requests
from markdownify import markdownify
from requests.exceptions import RequestException
from smolagents import tool

@tool
def visit_webpage(url: str) -> str:
    """Visits a webpage at the given URL and returns its content as a markdown string.

    Args:
        url: The URL of the webpage to visit.

    Returns:
        The content of the webpage converted to Markdown, or an error message if the request fails.
    """
    try:
        # Send a GET request to the URL
        response = requests.get(url)
        response.raise_for_status()  # Raise an exception for bad status codes

        # Convert the HTML content to Markdown
        markdown_content = markdownify(response.text).strip()

        # Remove multiple line breaks
        markdown_content = re.sub(r"\n{3,}", "\n\n", markdown_content)

        return markdown_content

    except RequestException as e:
        return f"Error fetching the webpage: {str(e)}"
    except Exception as e:
        return f"An unexpected error occurred: {str(e)}"

좋아요, 이제 도구를 초기화하고 테스트해 봅시다!

print(visit_webpage("https://en.wikipedia.org/wiki/Hugging_Face")[:500])

다중 에이전트 시스템 만들기 🤖🤝🤖

이제 searchvisit_webpage 도구가 모두 있으니, 이걸로 웹 에이전트를 만들 수 있어요.

이 에이전트에는 어떤 설정을 고를까요?

  • 웹 브라우징은 병렬 도구 호출이 필요 없는 단일 타임라인 작업이라 JSON 도구 호출이 잘 맞아요. 그래서 ToolCallingAgent를 선택할게요.
  • 또 웹 검색은 정답을 찾기 전에 많은 페이지를 탐색해야 하는 경우가 있으니, max_steps를 10으로 늘려 두는 편이 좋아요.
from smolagents import (
    CodeAgent,
    ToolCallingAgent,
    InferenceClientModel,
    WebSearchTool,
)

model = InferenceClientModel(model_id=model_id)

web_agent = ToolCallingAgent(
    tools=[WebSearchTool(), visit_webpage],
    model=model,
    max_steps=10,
    name="web_search_agent",
    description="Runs web searches for you.",
)

이 에이전트에 namedescription 속성을 준 것을 주목하세요. 이 두 속성은 매니저 에이전트가 이 에이전트를 호출할 수 있게 하려면 반드시 있어야 해요.

그런 다음 매니저 에이전트를 만들고, 초기화할 때 managed_agents 인자에 우리의 관리 에이전트를 넘겨요.

이 에이전트는 플래닝과 사고를 담당하는 쪽이니 고급 추론이 유리할 거예요. 그래서 CodeAgent가 잘 맞아요.

또, 현재 연도를 묻고 추가 데이터 계산을 하는 질문을 하고 싶으니, 에이전트가 이 패키지들을 필요로 할 경우를 대비해 additional_authorized_imports=["time", "numpy", "pandas"]를 추가해 둘게요.

manager_agent = CodeAgent(
    tools=[],
    model=model,
    managed_agents=[web_agent],
    additional_authorized_imports=["time", "numpy", "pandas"],
)

이것으로 끝이에요! 이제 시스템을 실행해 봅시다! 계산과 리서치가 모두 필요한 질문을 골라볼게요:

answer = manager_agent.run("If LLM training continues to scale up at the current rhythm until 2030, what would be the electric power in GW required to power the biggest training runs by 2030? What would that correspond to, compared to some countries? Please provide a source for any numbers used.")

그 결과로 이런 리포트를 받았어요:

Based on current growth projections and energy consumption estimates, if LLM trainings continue to scale up at the 
current rhythm until 2030:

1. The electric power required to power the biggest training runs by 2030 would be approximately 303.74 GW, which 
translates to about 2,660,762 GWh/year.

2. Comparing this to countries' electricity consumption:
   - It would be equivalent to about 34% of China's total electricity consumption.
   - It would exceed the total electricity consumption of India (184%), Russia (267%), and Japan (291%).
   - It would be nearly 9 times the electricity consumption of countries like Italy or Mexico.

3. Source of numbers:
   - The initial estimate of 5 GW for future LLM training comes from AWS CEO Matt Garman.
   - The growth projection used a CAGR of 79.80% from market research by Springs.
   - Country electricity consumption data is from the U.S. Energy Information Administration, primarily for the year 
2021.

스케일링 가설이 계속 성립한다면 우리는 꽤 거대한 발전소가 필요할 것 같네요.

우리 에이전트들은 작업을 해결하기 위해 효율적으로 협력하는 데 성공했어요! ✅

💡 이 조율 구조는 더 많은 에이전트로 쉽게 확장할 수 있어요. 하나는 코드 실행, 하나는 웹 검색, 하나는 파일 로딩을 담당하는 식으로요...