에이전트 메모리 관리하기

에이전트 메모리 관리하기

출처: Manage your agent's memory - Hugging Face smolagents 공식 문서

결국 에이전트는 아주 단순한 구성 요소로 설명할 수 있어요. 툴이 있고, 프롬프트가 있죠. 그리고 무엇보다 중요한 건, 과거의 계획·실행·오류의 이력인 지난 단계들의 메모리가 있다는 점입니다. 이 글은 에이전트의 메모리를 재생하거나, 필요에 따라 동적으로 바꾸는 방법을 다룹니다.

에이전트 메모리 재생하기

지난 에이전트 실행을 들여다볼 수 있는 기능을 몇 가지 준비했어요.

계측 가이드에서 설명한 것처럼 에이전트 실행을 계측해, 특정 단계를 확대/축소해서 볼 수 있는 멋진 UI로 띄울 수도 있습니다.

agent.replay()를 쓰는 방법도 있어요. 이렇게요.

에이전트를 실행한 뒤에:

from smolagents import InferenceClientModel, CodeAgent

agent = CodeAgent(tools=[], model=InferenceClientModel(), verbosity_level=0)

result = agent.run("What's the 20th Fibonacci number?")

마지막 실행을 재생하고 싶다면 그냥 이렇게 쓰면 됩니다.

agent.replay()

에이전트 메모리 동적으로 바꾸기

많은 고급 사용 사례는 에이전트 메모리의 동적 수정을 요구합니다.

에이전트 메모리에 이렇게 접근할 수 있어요.

from smolagents import ActionStep

system_prompt_step = agent.memory.system_prompt
print("The system prompt given to the agent was:")
print(system_prompt_step.system_prompt)

task_step = agent.memory.steps[0]
print("\n\nThe first task step was:")
print(task_step.task)

for step in agent.memory.steps:
    if isinstance(step, ActionStep):
        if step.error is not None:
            print(f"\nStep {step.step_number} got this error:\n{step.error}\n")
        else:
            print(f"\nStep {step.step_number} got these observations:\n{step.observations}\n")

agent.memory.get_full_steps()를 쓰면 전체 단계를 딕셔너리로 얻을 수 있어요.

또한 스텝 콜백(step callbacks) 을 써서 에이전트 메모리를 동적으로 바꿀 수도 있습니다.

스텝 콜백은 인자로 agent 자체에 접근할 수 있어서, 위에서 본 것처럼 어느 메모리 단계에든 접근하고 필요하면 수정할 수 있어요. 예를 들어, 웹 브라우저 에이전트가 각 단계에서 찍은 스크린샷을 관찰한다고 해 봅시다. 가장 최신 스크린샷만 기록하고, 오래된 단계의 이미지는 토큰 비용을 아끼기 위해 제거하고 싶어요.

이런 식으로 해 볼 수 있습니다.

참고: 이 코드는 간결함을 위해 일부 import와 객체 정의를 빼서 완전하지 않아요. 전체 동작 코드는 원본 스크립트에서 확인하세요.

import helium
from PIL import Image
from io import BytesIO
from time import sleep

def update_screenshot(memory_step: ActionStep, agent: CodeAgent) -> None:
    sleep(1.0)  # Let JavaScript animations happen before taking the screenshot
    driver = helium.get_driver()
    latest_step = memory_step.step_number
    for previous_memory_step in agent.memory.steps:  # Remove previous screenshots from logs for lean processing
        if isinstance(previous_memory_step, ActionStep) and previous_memory_step.step_number <= latest_step - 2:
            previous_memory_step.observations_images = None
    png_bytes = driver.get_screenshot_as_png()
    image = Image.open(BytesIO(png_bytes))
    memory_step.observations_images = [image.copy()]

그런 다음 에이전트 초기화 시 step_callbacks 인자에 이 함수를 넘겨주면 됩니다.

CodeAgent(
    tools=[WebSearchTool(), go_back, close_popups, search_item_ctrl_f],
    model=model,
    additional_authorized_imports=["helium"],
    step_callbacks=[update_screenshot],
    max_steps=20,
    verbosity_level=2,
)

전체 동작 예제는 비전 웹 브라우저 코드를 확인하세요.

에이전트를 한 단계씩 실행하기

며칠이 걸리는 툴 호출이 있을 때 유용해요. 에이전트를 단계별로 실행할 수 있고, 각 단계에서 메모리를 갱신할 수도 있습니다.

from smolagents import InferenceClientModel, CodeAgent, ActionStep, TaskStep

agent = CodeAgent(tools=[], model=InferenceClientModel(), verbosity_level=1)
agent.python_executor.send_tools({**agent.tools})
print(agent.memory.system_prompt)

task = "What is the 20th Fibonacci number?"

# You could modify the memory as needed here by inputting the memory of another agent.
# agent.memory.steps = previous_agent.memory.steps

# Let's start a new task!
agent.memory.steps.append(TaskStep(task=task, task_images=[]))

final_answer = None
step_number = 1
while final_answer is None and step_number <= 10:
    memory_step = ActionStep(
        step_number=step_number,
        observations_images=[],
    )
    # Run one step.
    final_answer = agent.step(memory_step)
    agent.memory.steps.append(memory_step)
    step_number += 1

    # Change the memory as you please!
    # For instance to update the latest step:
    # agent.memory.steps[-1] = ...

print("The final answer is:", final_answer)

더 알아보기 (Learn more)