<CourseFloatingBanner 
  classNames="absolute z-10 right-0 top-0"
  notebooks={[
    {label: "Google Colab", value: "https://colab.research.google.com/#fileId=https://huggingface.co/agents-course/notebooks/blob/main/unit2/smolagents/vision_agents.ipynb"},
]}
askForHelpUrl="http://hf.co/join/discord" />

# smolagents로 비전 에이전트 만들기

<Tip warning={true}>
이 섹션의 예제는 강력한 VLM(비전-언어 모델) API가 필요합니다. 우리는 GPT-4o API로 테스트했습니다.  
하지만 <a href="./why_use_smolagents">Why use smolagents</a>에서는 smolagents와 Hugging Face에서 지원하는 대체 솔루션도 다루고 있습니다. 다른 옵션을 탐색하고 싶다면 해당 섹션을 참고하세요.
</Tip>

에이전트에 시각적 능력을 부여하는 것은 텍스트 처리 이상의 실제 문제를 해결하는 데 매우 중요합니다. 웹 브라우징이나 문서 이해 등 많은 실제 과제는 풍부한 시각 정보를 분석해야 합니다. 다행히도, `smolagents`는 비전-언어 모델(VLM)을 내장 지원하여 에이전트가 이미지를 효과적으로 처리하고 해석할 수 있게 해줍니다.  

이 예시에서, Wayne Manor의 집사 Alfred는 파티에 참석하는 손님들의 신원을 확인하는 임무를 맡았습니다. Alfred는 모든 손님을 알지 못할 수 있으므로, 손님의 외모에 대한 시각 정보를 검색해 신원을 확인하는 에이전트를 사용할 수 있습니다. 이를 통해 Alfred는 입장 허가 여부를 현명하게 결정할 수 있습니다. 예시를 함께 만들어봅시다!


## 에이전트 실행 시작 시 이미지 제공하기

<Tip>
코드는 <a href="https://huggingface.co/agents-course/notebooks/blob/main/unit2/smolagents/vision_agents.ipynb" target="_blank">이 노트북</a>에서 따라할 수 있습니다. Google Colab에서 실행할 수 있습니다.
</Tip>

이 방식에서는 이미지를 에이전트 실행 시점에 `task_images`로 전달합니다. 에이전트는 이 이미지를 전체 실행 과정에서 활용합니다.  

예를 들어, Alfred는 이전 파티에서 손님들의 이름과 함께 저장된 이미지 데이터셋을 가지고 있습니다. 새로운 방문객의 이미지를 받아, 기존 데이터셋과 비교해 입장 허가 여부를 결정할 수 있습니다.  

이번에는 한 손님이 입장하려고 하는데, Alfred는 이 손님이 Wonder Woman으로 위장한 Joker일 수 있다고 의심합니다. Alfred는 신원을 확인해 원치 않는 인물이 입장하지 못하도록 해야 합니다.  

예시를 만들어봅시다. 우선 이미지를 불러옵니다. 여기서는 위키피디아 이미지를 사용하지만, 실제로는 다양한 활용이 가능합니다!

```python
from PIL import Image
import requests
from io import BytesIO

image_urls = [
    "https://upload.wikimedia.org/wikipedia/commons/e/e8/The_Joker_at_Wax_Museum_Plus.jpg", # Joker 이미지
    "https://upload.wikimedia.org/wikipedia/en/9/98/Joker_%28DC_Comics_character%29.jpg" # Joker 이미지
]

images = []
for url in image_urls:
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36" 
    }
    response = requests.get(url,headers=headers)
    image = Image.open(BytesIO(response.content)).convert("RGB")
    images.append(image)
```

이제 이미지를 준비했으니, 에이전트가 손님이 Wonder Woman인지 Joker인지 판별해줍니다.

```python
from smolagents import CodeAgent, OpenAIServerModel

model = OpenAIServerModel(model_id="gpt-4o")

# 에이전트 인스턴스화
agent = CodeAgent(
    tools=[],
    model=model,
    max_steps=20,
    verbosity_level=2
)

response = agent.run(
    """
    이 사진 속 만화 캐릭터의 의상과 메이크업을 묘사해 주세요.
    손님이 The Joker인지 Wonder Woman인지 알려주세요.
    """,
    images=images
)
```

실행 결과는 다음과 같습니다(실행 환경에 따라 다를 수 있습니다):

```python
    {
        'Costume and Makeup - First Image': (
            '보라색 코트와 노란색 셔츠 위에 보라색 실크 크라바트 또는 타이.',
            '흰색 얼굴 분장, 과장된 이목구비, 진한 눈썹, 파란 아이섀도, 빨간 입술로 넓은 미소.'
        ),
        'Costume and Makeup - Second Image': (
            '꽃이 달린 어두운 정장, 손에 트럼프 카드를 들고 있음.',
            '창백한 피부, 초록색 머리, 과장된 미소의 빨간 입술.'
        ),
        'Character Identity': '이 캐릭터는 만화에서 묘사된 The Joker와 유사합니다.'
    }
```

이처럼, 결과를 통해 손님이 다른 인물로 위장했음을 알 수 있으므로, Alfred는 Joker의 입장을 막을 수 있습니다!

## 동적 검색으로 이미지 제공하기

<Tip>
코드는 <a href="https://huggingface.co/agents-course/notebooks/blob/main/unit2/smolagents/vision_web_browser.py" target="_blank">이 Python 파일</a>에서 따라할 수 있습니다.
</Tip>

이전 방식도 유용하지만, 데이터베이스에 손님이 없는 경우에는 외부에서 이미지를 동적으로 검색해야 할 수 있습니다. 예를 들어, 웹을 탐색하며 손님에 대한 이미지를 찾아 신원을 확인하는 방식입니다.

이 방식에서는 에이전트 실행 중에 이미지를 동적으로 메모리에 추가합니다. smolagents의 에이전트는 `MultiStepAgent` 클래스를 기반으로 하며, 이는 ReAct 프레임워크의 추상화입니다. 이 클래스는 다양한 변수와 지식을 여러 단계에 걸쳐 기록하는 구조적 사이클로 동작합니다:

1. **SystemPromptStep:** 시스템 프롬프트 저장
2. **TaskStep:** 사용자 쿼리 및 입력 기록
3. **ActionStep:** 에이전트의 액션 및 결과 로그 기록

이 구조적 접근법 덕분에, 에이전트는 시각 정보를 동적으로 통합하고, 변화하는 작업에 적응적으로 대응할 수 있습니다. 아래 다이어그램은 이러한 동적 워크플로우와 각 단계가 에이전트 라이프사이클에서 어떻게 통합되는지 보여줍니다. 브라우징 중에는 에이전트가 스크린샷을 찍어 `observation_images`에 저장할 수 있습니다.

![Dynamic image retrieval](https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/blog/smolagents-can-see/diagram_adding_vlms_smolagents.png)

이제 필요성을 이해했으니, 전체 예시를 만들어봅시다. 이번에는 Alfred가 손님 신원 확인 과정을 완전히 통제하고 싶어 하므로, 웹을 탐색하며 정보를 찾는 것이 적합합니다. 이를 위해 Selenium과 Helium 등 브라우저 자동화 도구가 필요합니다. 아래 명령어로 필요한 패키지를 설치하세요:

```bash
pip install "smolagents[all]" helium selenium python-dotenv
```

에이전트에는 웹 브라우징을 위한 `search_item_ctrl_f`, `go_back`, `close_popups` 등 도구가 필요합니다. 이 도구들은 실제 사용자가 웹을 탐색하는 것처럼 동작하게 해줍니다.

```python
@tool
def search_item_ctrl_f(text: str, nth_result: int = 1) -> str:
    """
    현재 페이지에서 Ctrl + F로 텍스트를 검색하고 n번째 결과로 이동합니다.
    Args:
        text: 검색할 텍스트
        nth_result: 몇 번째 결과로 이동할지(기본값: 1)
    """
    elements = driver.find_elements(By.XPATH, f"//*[contains(text(), '{text}')]")
    if nth_result > len(elements):
        raise Exception(f"{nth_result}번째 결과를 찾을 수 없습니다. (총 {len(elements)}개 일치)")
    result = f"'{text}'에 대해 {len(elements)}개 일치."
    elem = elements[nth_result - 1]
    driver.execute_script("arguments[0].scrollIntoView(true);", elem)
    result += f"{len(elements)}개 중 {nth_result}번째 요소로 포커스 이동"
    return result


@tool
def go_back() -> None:
    """이전 페이지로 이동합니다."""
    driver.back()


@tool
def close_popups() -> str:
    """
    페이지의 모달 또는 팝업을 닫습니다. 팝업 창을 닫을 때 사용하세요! 쿠키 배너에는 동작하지 않습니다.
    """
    webdriver.ActionChains(driver).send_keys(Keys.ESCAPE).perform()
```

또한, 스크린샷 저장 기능도 필요합니다. 이 기능은 브라우저의 스크린샷을 찍어 `step_log.observations_images = [image.copy()]`에 저장합니다. 이를 통해 에이전트가 탐색 중 이미지를 동적으로 저장하고 활용할 수 있습니다.

```python
def save_screenshot(step_log: ActionStep, agent: CodeAgent) -> None:
    sleep(1.0)  # 자바스크립트 애니메이션 대기
    driver = helium.get_driver()
    current_step = step_log.step_number
    if driver is not None:
        for step_logs in agent.logs:  # 이전 스크린샷 정리
            if isinstance(step_log, ActionStep) and step_log.step_number <= current_step - 2:
                step_logs.observations_images = None
        png_bytes = driver.get_screenshot_as_png()
        image = Image.open(BytesIO(png_bytes))
        print(f"브라우저 스크린샷 캡처: {image.size} 픽셀")
        step_log.observations_images = [image.copy()]

    # 현재 URL 정보 업데이트
    url_info = f"현재 url: {driver.current_url}"
    step_log.observations = url_info if step_logs.observations is None else step_log.observations + "\n" + url_info
    return
```

이 함수는 `step_callback`으로 에이전트에 전달되어, 각 단계가 끝날 때마다 실행됩니다. 이를 통해 에이전트는 탐색 과정에서 스크린샷을 동적으로 저장할 수 있습니다.

이제, 브라우저를 탐색하며 시각 정보를 활용하는 비전 에이전트를 만들어봅시다. 앞서 만든 도구들과 `DuckDuckGoSearchTool`을 함께 사용합니다. 이 도구는 손님 신원 확인에 필요한 정보를 웹에서 검색하는 데 도움을 줍니다.

```python
from smolagents import CodeAgent, OpenAIServerModel, DuckDuckGoSearchTool
model = OpenAIServerModel(model_id="gpt-4o")

agent = CodeAgent(
    tools=[DuckDuckGoSearchTool(), go_back, close_popups, search_item_ctrl_f],
    model=model,
    additional_authorized_imports=["helium"],
    step_callbacks=[save_screenshot],
    max_steps=20,
    verbosity_level=2,
)
```

이제 Alfred는 손님 신원 확인을 위해 다음과 같이 에이전트를 실행할 수 있습니다:

```python
agent.run("""
나는 Wayne Manor의 집사 Alfred로, 파티에 참석하는 손님의 신원을 확인하는 임무를 맡고 있습니다. 한 슈퍼히어로가 Wonder Woman이라고 주장하며 입장하려고 하는데, 정말 그녀가 맞는지 확인해야 합니다.

Wonder Woman의 이미지를 검색해 시각적 특징을 자세히 설명해 주세요. 또한, Wikipedia에서 그녀의 외모에 대한 주요 정보를 찾아주세요. 이 정보를 바탕으로 입장 허가 여부를 결정하겠습니다.
""" + helium_instructions)
```

여기서 `helium_instructions`는 탐색을 제어하는 특수 프롬프트로, 에이전트가 올바른 순서로 웹을 탐색하도록 유도합니다.

아래 영상에서 실제 동작을 확인할 수 있습니다:

<iframe width="560" height="315" src="https://www.youtube.com/embed/rObJel7-OLc?si=TnNwQ8rqXqun_pqE" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>

최종 출력 예시는 다음과 같습니다:

```python
Final answer: Wonder Woman은 일반적으로 빨간색과 금색의 상의, 파란색 별무늬 하의, 금색 티아라, 은색 팔찌, 황금 올가미를 착용한 모습으로 묘사됩니다. 그녀는 Themyscira의 공주이자, 인간 세계에서는 Diana Prince로 알려져 있습니다.
```

이렇게 해서, 파티 입장 손님 신원 확인을 위한 비전 에이전트를 완성했습니다! 이제 Alfred는 올바른 손님만 입장할 수 있도록 완벽하게 준비할 수 있습니다. Wayne Manor에서 멋진 파티를 즐기세요!


## 추가 자료

- [We just gave sight to smolagents](https://huggingface.co/blog/smolagents-can-see) - 비전 에이전트 기능을 소개하는 블로그
- [Web Browser Automation with Agents 🤖🌐](https://huggingface.co/docs/smolagents/examples/web_browser) - 웹 브라우저를 활용한 에이전트 예시
- [Web Browser Vision Agent Example](https://github.com/huggingface/smolagents/blob/main/src/smolagents/vision_web_browser.py) - 웹 브라우저 비전 에이전트 예시
