from dotenv import load_dotenv
 
 
load_dotenv(".env", override=True)
 
%load_ext autoreload
%autoreload 2
The autoreload extension is already loaded. To reload it, use:
  %reload_ext autoreload

컨텍스트 오프로딩: 파일시스템

에이전트의 컨텍스트 윈도우는 복잡한 작업 중에 급속도로 증가할 수 있습니다. 평균적인 Manus 작업은 약 50번의 도구 호출을 사용하여 상당한 컨텍스트 누적을 만듭니다. 이러한 증가를 관리하기 위한 강력한 기법은 파일시스템 작업을 통한 컨텍스트 오프로딩입니다. 모든 도구 호출 결과와 중간 결과를 컨텍스트 윈도우에 직접 저장하는 대신, 에이전트는 정보를 전략적으로 파일에 저장하고 필요에 따라 가져올 수 있으며, 초점을 유지하면서도 중요한 정보에 대한 접근을 보존할 수 있습니다.

이 접근 방식은 ManusHugging Face Open Deep Research 같은 프로덕션 시스템에서 성공적으로 구현되었습니다. Anthropic의 다중 에이전트 연구 시스템은 또 다른 설득력 있는 예시로, 하위 에이전트들이 자신의 작업을 외부 시스템에 저장하고 조정자에게 경량의 참조만 전달합니다. 이렇게 하면 정보가 여러 에이전트를 거치면서 왜곡되는 “전화 게임” 효과를 방지하면서도, 새로운 하위 에이전트가 깨끗한 컨텍스트로 생성되고 필요할 때 메모리에서 연구 계획 같은 저장된 컨텍스트를 검색할 수 있게 합니다.

샌드박스 환경의 파일에 토큰 사용량이 많은 컨텍스트를 작성함으로써, 에이전트는 필요할 때 상세한 정보를 검색할 수 있는 능력을 유지하면서도 메모리를 효과적으로 관리할 수 있습니다. 이 패턴은 일반 조정자를 통한 필터링보다 전문화된 프롬프트가 더 좋은 결과를 생성하는 코드, 보고서, 데이터 시각화 같은 구조화된 출력에 특히 유용하며, 중간 결과가 지속적인 관심 없이 보존되어야 하는 장기 연구 작업에도 유용합니다.

파일 도구

우리의 구현은 LangGraph 상태 내에서 기존 파일시스템을 모의하는 가상 파일시스템 접근 방식을 사용합니다. 핵심 개념은 간단한 딕셔너리를 사용하는 것입니다. 키는 모의 파일 경로를 나타내고 값은 파일 콘텐츠를 포함합니다. 이 접근 방식은 단일 에이전트 대화 내에서 컨텍스트를 유지하기에 이상적인 단기적, 스레드별 지속성을 제공하지만, 서로 다른 대화 스레드 간에 지속되어야 하는 정보에는 적합하지 않습니다. 파일 작업은 LangGraph의 Command 타입을 활용하여 에이전트 상태를 업데이트하므로, 도구가 가상 파일시스템을 수정하고 에이전트 실행 전체에서 적절한 상태 관리를 유지할 수 있습니다.

가상 파일 시스템에서 작동하는 세 가지 파일 도구(ls, read_file, write_file)를 구축하게 됩니다.

사용법:

  • LLM이 컨텍스트에 보유하고 있는 정보를 지속시키려면, write_file로 파일에 작성합니다. 나중에 동일한 에이전트나 하위 에이전트가 read_file로 정보를 검색할 수 있습니다.
  • 도구 호출이 파일에 데이터를 작성하고 도구 호출 반환 메시지에서 파일명을 제공할 수 있습니다. LLM은 나중에 콘텐츠의 일부 또는 전체를 읽기로 결정하거나, 다른 도구를 적용하여 데이터를 처리할 수 있습니다.
  • ls를 사용하여 사용 가능한 파일을 나열합니다.

읽기/쓰기 도구는 줄 구분 기호로 구분된 일반 텍스트(str.splitlines()함수로 파싱)를 기대합니다.

아래 프롬프트의 설명은 이들이 어떻게 작동하는지 자세히 설명합니다:

from src.deep_agents_from_scratch.prompts import LS_DESCRIPTION
from utils import show_prompt
 
 
show_prompt(LS_DESCRIPTION)
╭──────────────────────────────────────────────────── Prompt ─────────────────────────────────────────────────────╮
                                                                                                                 
  List all files in the virtual filesystem stored in agent state.                                                
                                                                                                                 
  Shows what files currently exist in agent memory. Use this to orient yourself before other file operations     
  and maintain awareness of your file organization.                                                              
                                                                                                                 
  No parameters required - simply call ls() to see all available files.                                          
                                                                                                                 
╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
from src.deep_agents_from_scratch.prompts import READ_FILE_DESCRIPTION
 
 
show_prompt(READ_FILE_DESCRIPTION)
╭──────────────────────────────────────────────────── Prompt ─────────────────────────────────────────────────────╮
                                                                                                                 
  Read content from a file in the virtual filesystem with optional pagination.                                   
                                                                                                                 
  This tool returns file content with line numbers (like `cat -n`) and supports reading large files in chunks    
  to avoid context overflow.                                                                                     
                                                                                                                 
  Parameters:                                                                                                    
  - file_path (required): Path to the file you want to read                                                      
  - offset (optional, default=0): Line number to start reading from                                              
  - limit (optional, default=2000): Maximum number of lines to read                                              
                                                                                                                 
  Essential before making any edits to understand existing content. Always read a file before editing it.        
                                                                                                                 
╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
from src.deep_agents_from_scratch.prompts import WRITE_FILE_DESCRIPTION
 
 
show_prompt(WRITE_FILE_DESCRIPTION)
╭──────────────────────────────────────────────────── Prompt ─────────────────────────────────────────────────────╮
                                                                                                                 
  Create a new file or completely overwrite an existing file in the virtual filesystem.                          
                                                                                                                 
  This tool creates new files or replaces entire file contents. Use for initial file creation or complete        
  rewrites. Files are stored persistently in agent state.                                                        
                                                                                                                 
  Parameters:                                                                                                    
  - file_path (required): Path where the file should be created/overwritten                                      
  - content (required): The complete content to write to the file                                                
                                                                                                                 
  Important: This replaces the entire file content.                                                              
                                                                                                                 
╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯

이제 아래에서 이러한 함수들을 구현해봅시다. 주목할 만한 두 가지 항목이 있습니다.

첫 번째는 @tool(description=PROMPT) 사용입니다. description="xyz"가 도구 데코레이터에 있을 때, “xyz”는 LLM으로 전송되고 docstring은 억제됩니다. 길이가 긴 설명을 별도의 프롬프트 파일에 두는 것이 종종 더 편리합니다. 이것은 도구의 작동 방식과 이 애플리케이션에서 어떻게 사용되어야 하는지 설명할 수 있는 공간을 제공합니다.

두 번째 항목은 에러 메시지입니다. 이 메시지들은 LLM을 대상으로 하며 인간 사용자를 대상으로 하지 않습니다. 에이전틱 시스템에서 LLM은 에러 메시지의 정보를 사용하여 작업을 재시도할 수 있습니다.

%%writefile ./src/deep_agents_from_scratch/file_tools.py
"""에이전트 상태 관리를 위한 가상 파일시스템 도구.
 
이 모듈은 에이전트 상태에 저장된 가상 파일시스템을 관리하기 위한 도구를 제공하며,
에이전트 상호작용 간에 컨텍스트 오프로딩 및 정보 지속성을 가능하게 합니다.
"""
 
from typing import Annotated
 
from langchain_core.messages import ToolMessage
from langchain_core.tools import InjectedToolCallId, tool
from langgraph.prebuilt import InjectedState
from langgraph.types import Command
 
from .prompts import (
    LS_DESCRIPTION,
    READ_FILE_DESCRIPTION,
    WRITE_FILE_DESCRIPTION,
)
from .state import DeepAgentState
 
 
@tool(description=LS_DESCRIPTION)
def ls(state: Annotated[DeepAgentState, InjectedState]) -> list[str]:
    """가상 파일시스템의 모든 파일을 나열합니다."""
    return list(state.get("files", {}).keys())
 
 
@tool(description=READ_FILE_DESCRIPTION, parse_docstring=True)
def read_file(
    file_path: str,
    state: Annotated[DeepAgentState, InjectedState],
    offset: int = 0,
    limit: int = 2000,
) -> str:
    """선택적 오프셋 및 한도를 사용하여 가상 파일시스템에서 파일 콘텐츠를 읽습니다.
 
    인수:
        file_path: 읽을 파일의 경로
        state: 가상 파일시스템을 포함하는 에이전트 상태 (도구 노드에서 주입됨)
        offset: 읽기를 시작할 줄 번호 (기본값: 0)
        limit: 읽을 최대 줄 수 (기본값: 2000)
 
    반환값:
        줄 번호가 포함된 형식화된 파일 콘텐츠, 또는 파일을 찾을 수 없으면 에러 메시지
    """
    files = state.get("files", {})
    if file_path not in files:
        return f"에러: 파일 '{file_path}'을(를) 찾을 수 없습니다"
 
    content = files[file_path]
    if not content:
        return "시스템 알림: 파일이 존재하지만 콘텐츠가 비어있습니다"
 
    lines = content.splitlines()
    start_idx = offset
    end_idx = min(start_idx + limit, len(lines))
 
    if start_idx >= len(lines):
        return f"에러: 줄 오프셋 {offset}이(가) 파일 길이({len(lines)}줄)를 초과합니다"
 
    result_lines = []
    for i in range(start_idx, end_idx):
        line_content = lines[i][:2000]  # 긴 줄 자르기
        result_lines.append(f"{i + 1:6d}\t{line_content}")
 
    return "\n".join(result_lines)
 
 
@tool(description=WRITE_FILE_DESCRIPTION, parse_docstring=True)
def write_file(
    file_path: str,
    content: str,
    state: Annotated[DeepAgentState, InjectedState],
    tool_call_id: Annotated[str, InjectedToolCallId],
) -> Command:
    """가상 파일시스템의 파일에 콘텐츠를 작성합니다.
 
    인수:
        file_path: 파일을 생성/업데이트할 경로
        content: 파일에 작성할 콘텐츠
        state: 가상 파일시스템을 포함하는 에이전트 상태 (도구 노드에서 주입됨)
        tool_call_id: 메시지 응답을 위한 도구 호출 식별자 (도구 노드에서 주입됨)
 
    반환값:
        새 파일 콘텐츠로 에이전트 상태를 업데이트하는 Command
    """
    files = state.get("files", {})
    files[file_path] = content
    return Command(
        update={
            "files": files,
            "messages": [
                ToolMessage(
                    f"파일 {file_path}을(를) 업데이트했습니다",
                    tool_call_id=tool_call_id,
                )
            ],
        }
    )
Overwriting ./src/deep_agents_from_scratch/file_tools.py

상태와 리듀서 다시 살펴보기

이전 노트북에서 파일 상태와 리듀서를 정의했지만 설명하지 않았습니다. 여기서 설명하겠습니다. DeepAgentState에서 files는 키와 값을 가진 딕셔너리로 정의됩니다. 위에서 언급했듯이 키는 파일명이고 값은 파일의 콘텐츠입니다. write_fileCommand가 실행될 때 file_reducer를 사용하여 파일들이 상태에 추가됩니다. 이 리듀서에서 left는 상태의 기존 파일들이고 right는 새로운 값들입니다. 마지막 명령문은 새로운 값들이 기존 값들을 덮어쓰도록 합니다: {**left, **right}, 파이썬은 먼저 left를 언팩하고 나서 right를 언팩합니다. right의 모든 중복 키는 left의 이전 값들을 덮어씁니다.

우리는 가상 파일시스템과 이를 작업할 도구를 가지고 있습니다. 이를 시도해보기 위해 간단한 연구 에이전트를 구축해봅시다. 에이전트는 사용자의 요청을 저장한 다음 사용자의 질문에 답하기 전에 다시 읽을 것입니다!

이 간단한 접근 방식이 장기 실행 에이전트 궤적과 함께 매우 유용하다는 점에 주목하세요! 이 간단한 예에서는 모든 정보가 쉽게 컨텍스트에 유지되지만, 장기 실행 에이전트의 경우 컨텍스트 콘텐츠를 압축하거나 제거할 수 있습니다. 압축 이전에 정보를 저장하고 필요할 때 검색하는 것은 스마트한 컨텍스트 엔지니어링입니다.

# 파일 사용 지침
FILE_USAGE_INSTRUCTIONS = """가상 파일시스템에 접근하여 컨텍스트를 유지하고 저장할 수 있습니다.
 
## 워크플로우 프로세스
1. **방향 설정**: 작업을 시작하기 전에 ls()를 사용하여 기존 파일 확인
2. **저장**: write_file()을 사용하여 사용자의 요청을 저장하여 나중을 위해 보관
3. **읽기**: 소스 수집이 완료되면 저장된 파일을 읽고 이를 사용하여 사용자의 질문에 직접 답변합니다."""
 
# 간단한 연구 지침 추가
SIMPLE_RESEARCH_INSTRUCTIONS = """중요: web_search 도구에 대한 단일 호출만 수행하고 도구에서 제공한 결과를 사용하여 사용자의 질문에 답변하세요."""
 
# 전체 프롬프트
INSTRUCTIONS = (
    FILE_USAGE_INSTRUCTIONS + "\n\n" + "=" * 80 + "\n\n" + SIMPLE_RESEARCH_INSTRUCTIONS
)
show_prompt(INSTRUCTIONS)
╭──────────────────────────────────────────────────── Prompt ─────────────────────────────────────────────────────╮
                                                                                                                 
  가상 파일시스템에 접근하여 컨텍스트를 유지하고 저장할 수 있습니다.                                             
                                                                                                                 
  ## 워크플로우 프로세스                                                                                         
  1. **방향 설정**: 작업을 시작하기 전에 ls()를 사용하여 기존 파일 확인                                          
  2. **저장**: write_file()을 사용하여 사용자의 요청을 저장하여 나중을 위해 보관                                 
  3. **읽기**: 소스 수집이 완료되면 저장된 파일을 읽고 이를 사용하여 사용자의 질문에 직접 답변합니다.            
                                                                                                                 
  ================================================================================                               
                                                                                                                 
  중요: web_search 도구에 대한 단일 호출만 수행하고 도구에서 제공한 결과를 사용하여 사용자의 질문에 답변하세요.  
                                                                                                                 
╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
from IPython.display import Image
from langchain_core.tools import tool
from src.deep_agents_from_scratch.file_tools import ls, read_file, write_file
from src.deep_agents_from_scratch.state import DeepAgentState
 
from langchain.agents import create_agent
from langchain.chat_models import init_chat_model
 
 
# 모의 검색 결과
search_result = """Model Context Protocol(MCP)는 Anthropic에서 개발한 공개 표준 프로토콜로,
AI 모델과 도구, 데이터베이스 및 기타 서비스와 같은 외부 시스템 간의 원활한 통합을 가능하게 합니다.
표준화된 통신 계층 역할을 하며, AI 모델이 다양한 소스의 데이터에 일관되고 효율적인 방식으로
접근하고 활용할 수 있도록 합니다. 기본적으로 MCP는 데이터 교환을 위한 통일된 언어를 제공하여
AI 어시스턴트를 외부 서비스에 연결하는 프로세스를 단순화합니다. """
 
 
# 모의 검색 도구
@tool(parse_docstring=True)
def web_search(
    query: str,
):
    """특정 주제에 대해 웹을 검색합니다.
 
    이 도구는 웹 검색을 수행하고 주어진 쿼리에 대한
    관련 결과를 반환합니다. 인터넷에서 어떤 주제에 대한 정보를 수집해야 할 때
    사용합니다.
 
    Args:
        query: 검색 쿼리 문자열입니다. 찾고 있는 정보에 대해 구체적이고 명확하게 작성하세요.
 
    Returns:
        검색 엔진의 검색 결과입니다.
 
    Example:
        web_search("의료 분야의 머신러닝 애플리케이션")
    """
    return search_result
 
 
# create_react_agent를 직접 사용하여 에이전트 생성
model = init_chat_model(model="anthropic:claude-sonnet-4-20250514", temperature=0.0)
tools = [ls, read_file, write_file, web_search]
 
# 시스템 프롬프트로 에이전트 생성
agent = create_agent(
    model,
    tools,
    system_prompt=INSTRUCTIONS,
    state_schema=DeepAgentState,
)
 
# 에이전트 표시
display(Image(agent.get_graph(xray=True).draw_mermaid_png()))

상태에 files이 없고 사용자의 연구 요청을 포함하여 그래프를 시작합니다.

from typing import Any
 
from utils import format_messages
 
 
inputs: Any = {
    "messages": [
        {
            "role": "user",
            "content": "Model Context Protocol (MCP)에 대한 개요를 제시해주세요.",
        }
    ],
    "files": {},
}
result = agent.invoke(inputs)
format_messages(result["messages"])
╭─────────────────────────────────────────────────── 🧑 Human ────────────────────────────────────────────────────╮
 Model Context Protocol (MCP)에 대한 개요를 제시해주세요.                                                        
╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
╭───────────────────────────────────────────────────── 📝 AI ─────────────────────────────────────────────────────╮
 먼저 기존 파일들을 확인하고, MCP에 대한 정보를 검색해서 개요를 제공해드리겠습니다.                              
                                                                                                                 
 🔧 Tool Call: ls                                                                                                
    Args: {}                                                                                                     
    ID: toolu_016mv9cNfXKjRS64ceSBcNvi                                                                           
╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
╭──────────────────────────────────────────────── 🔧 Tool Output ─────────────────────────────────────────────────╮
                                                                                                                 
╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
╭───────────────────────────────────────────────────── 📝 AI ─────────────────────────────────────────────────────╮
                                                                                                                 
 🔧 Tool Call: web_search                                                                                        
    Args: {                                                                                                      
   "query": "Model Context Protocol MCP overview architecture features"                                          
 }                                                                                                               
    ID: toolu_01PSRywCw94HpL3AH5K2r4wP                                                                           
╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
╭──────────────────────────────────────────────── 🔧 Tool Output ─────────────────────────────────────────────────╮
 Model Context Protocol(MCP)는 Anthropic에서 개발한 공개 표준 프로토콜로,                                        
 AI 모델과 도구, 데이터베이스 및 기타 서비스와 같은 외부 시스템 간의 원활한 통합을 가능하게 합니다.              
 표준화된 통신 계층 역할을 하며, AI 모델이 다양한 소스의 데이터에 일관되고 효율적인 방식으로                     
 접근하고 활용할 수 있도록 합니다. 기본적으로 MCP는 데이터 교환을 위한 통일된 언어를 제공하여                    
 AI 어시스턴트를 외부 서비스에 연결하는 프로세스를 단순화합니다.                                                 
╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
╭───────────────────────────────────────────────────── 📝 AI ─────────────────────────────────────────────────────╮
                                                                                                                 
 🔧 Tool Call: write_file                                                                                        
    Args: {                                                                                                      
   "file_path": "mcp_overview.md",                                                                               
   "content": "# Model Context Protocol (MCP) 개요\n\n## 정의\nModel Context Protocol(MCP)는 Anthropic에서       
 개발한 공개 표준 프로토콜로, AI 모델과 도구, 데이터베이스 및 기타 서비스와 같은 외부 시스템 간의 원활한 통합을  
 가능하게 합니다.\n\n## 주요 특징\n- **표준화된 통신 계층**: AI 모델이 다양한 소스의 데이터에 일관되고 효율적인  
 방식으로 접근할 수 있도록 함\n- **통일된 언어 제공**: 데이터 교환을 위한 표준화된 방식을 제공\n- **연결         
 프로세스 단순화**: AI 어시스턴트를 외부 서비스에 연결하는 과정을 간소화\n\n## 목적\nMCP는 AI 모델과 외부 시스템 
 간의 상호작용을 표준화하여, 개발자들이 더 쉽게 AI 애플리케이션을 구축하고 통합할 수 있도록 돕는 것을 목표로     
 합니다."                                                                                                        
 }                                                                                                               
    ID: toolu_01PmEZDvXrBm6kFWwvyC1B1g                                                                           
╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
╭──────────────────────────────────────────────── 🔧 Tool Output ─────────────────────────────────────────────────╮
 파일 mcp_overview.md을(를) 업데이트했습니다                                                                     
╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
╭───────────────────────────────────────────────────── 📝 AI ─────────────────────────────────────────────────────╮
 # Model Context Protocol (MCP) 개요                                                                             
                                                                                                                 
 **Model Context Protocol(MCP)**는 Anthropic에서 개발한 공개 표준 프로토콜로, AI 모델과 외부 시스템 간의 통합을  
 혁신적으로 개선하는 기술입니다.                                                                                 
                                                                                                                 
 ## 🎯 핵심 개념                                                                                                 
                                                                                                                 
 MCP는 AI 모델이 다양한 외부 리소스(도구, 데이터베이스, 서비스 등)와 소통할 수 있도록 하는 **표준화된 통신       
 계층**입니다. 마치 서로 다른 언어를 사용하는 시스템들 사이의 번역기 역할을 한다고 볼 수 있습니다.               
                                                                                                                 
 ## 🔧 주요 특징                                                                                                 
                                                                                                                 
 ### 1. **표준화된 인터페이스**                                                                                  
 - AI 모델과 외부 시스템 간의 일관된 통신 방식 제공                                                              
 - 다양한 데이터 소스에 효율적으로 접근 가능                                                                     
                                                                                                                 
 ### 2. **통합 프로세스 단순화**                                                                                 
 - 복잡한 연결 과정을 간소화                                                                                     
 - 개발자가 AI 애플리케이션을 더 쉽게 구축할 수 있도록 지원                                                      
                                                                                                                 
 ### 3. **확장성과 유연성**                                                                                      
 - 다양한 외부 서비스와의 호환성                                                                                 
 - 새로운 도구나 서비스 추가 시 표준화된 방식으로 통합 가능                                                      
                                                                                                                 
 ## 💡 실용적 가치                                                                                               
                                                                                                                 
 MCP는 AI 생태계에서 **상호 운용성**을 크게 향상시키며, 개발자들이 AI 모델의 기능을 외부 시스템과 연결할 때      
 발생하는 복잡성을 해결합니다. 이를 통해 더 강력하고 실용적인 AI 애플리케이션 개발이 가능해집니다.               
                                                                                                                 
 이 프로토콜은 AI 기술의 실제 활용도를 높이고, 다양한 시스템 간의 원활한 데이터 교환을 통해 AI의 실용성을 크게   
 확장시키는 중요한 기술적 진보라고 할 수 있습니다.                                                               
╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯