langchain / / 2025. 11. 8. 21:15

[LangChain v1.0] Context Engineering

출처: https://docs.langchain.com/oss/python/langchain/context-engineering

개요

신뢰할 수 있는 에이전트를 구축하는 것은 기능적인 프로토타입을 만드는 것 이상을 요구합니다. 기본적인 과제는 에이전트가 실제 시나리오에서 안정적으로 작동하도록 보장하는 것이며, LangChain의 아키텍처는 이를 구체적으로 다룹니다.

에이전트가 실패하는 이유

에이전트 실패는 일반적으로 두 가지 원인 중 하나에서 비롯됩니다:

  1. 불충분한 모델 기능
  2. 누락되었거나 부적절하게 포맷된 컨텍스트 정보

"대부분의 경우 - 실제로 에이전트가 신뢰할 수 없게 만드는 것은 두 번째 이유입니다." 해결책은 전략적 컨텍스트 엔지니어링을 포함합니다—LLM이 효과적으로 활용할 수 있는 형식으로 적절한 정보와 도구를 제공하는 것입니다.

컨텍스트 엔지니어링은 AI 엔지니어의 주요 책임입니다. LangChain의 에이전트 추상화는 이러한 중요한 관행을 촉진하기 위해 특별히 설계되었습니다.

에이전트 루프

에이전트는 반복되는 사이클을 통해 작동합니다:

  1. 모델 호출 - 프롬프트와 사용 가능한 도구로 LLM을 호출하고, 응답 또는 도구 실행 요청을 반환합니다
  2. 도구 실행 - 요청된 도구를 실행하고 결과를 반환합니다

이 루프는 모델이 완료를 결정할 때까지 계속됩니다.

제어할 수 있는 것

신뢰할 수 있는 에이전트 개발은 각 에이전트 루프 단계와 단계 간 작업을 관리해야 합니다:

컨텍스트 유형 제어 범위 지속성
모델 컨텍스트 지시사항, 메시지 히스토리, 도구, 응답 형식 일시적
도구 컨텍스트 도구 데이터 액세스 및 상태 수정 지속적
라이프사이클 컨텍스트 모델/도구 호출 사이의 작업 지속적

데이터 소스

에이전트는 세 가지 서로 다른 데이터 소스에 액세스합니다:

소스 대체 이름 범위 예시
Runtime Context 정적 구성 대화 범위 사용자 ID, API 키, 데이터베이스 연결, 권한
State 단기 메모리 대화 범위 메시지, 업로드된 파일, 인증 상태, 도구 결과
Store 장기 메모리 대화 간 사용자 선호도, 추출된 인사이트, 과거 데이터

구현 메커니즘

"LangChain 미들웨어는 LangChain을 사용하는 개발자에게 컨텍스트 엔지니어링을 실용적으로 만드는 내부 메커니즘입니다." 미들웨어는 개발자가 다음을 수행할 수 있도록 합니다:

  • 라이프사이클의 어느 시점에서든 컨텍스트 업데이트
  • 다른 라이프사이클 단계로 이동

모델 컨텍스트

이 카테고리는 각 모델 호출에 도달하는 정보를 제어합니다—지시사항, 사용 가능한 도구, 모델 선택 및 출력 사양을 포함합니다. 이러한 결정은 신뢰성과 운영 비용에 직접적인 영향을 미칩니다.

시스템 프롬프트

시스템 프롬프트는 LLM의 동작과 기능을 설정합니다. 다른 컨텍스트는 다른 지시사항을 요구합니다. 효과적인 에이전트는 메모리, 선호도 및 구성을 활용하여 현재 대화 상태에 적절한 가이드를 제공합니다.

상태 기반 프롬프트는 메시지 수 또는 대화 컨텍스트에 액세스합니다:

from langchain.agents import create_agent
from langchain.agents.middleware import dynamic_prompt, ModelRequest

@dynamic_prompt
def state_aware_prompt(request: ModelRequest) -> str:
    message_count = len(request.messages)
    base = "You are a helpful assistant."
    if message_count > 10:
        base += "\nThis is a long conversation - be extra concise."
    return base

agent = create_agent(
    model="gpt-4o",
    tools=[...],
    middleware=[state_aware_prompt]
)

Store 기반 프롬프트는 장기 사용자 선호도에 액세스합니다:

from dataclasses import dataclass
from langchain.agents import create_agent
from langchain.agents.middleware import dynamic_prompt, ModelRequest
from langgraph.store.memory import InMemoryStore

@dataclass
class Context:
    user_id: str

@dynamic_prompt
def store_aware_prompt(request: ModelRequest) -> str:
    user_id = request.runtime.context.user_id
    store = request.runtime.store
    user_prefs = store.get(("preferences",), user_id)

    base = "You are a helpful assistant."
    if user_prefs:
        style = user_prefs.value.get("communication_style", "balanced")
        base += f"\nUser prefers {style} responses."
    return base

agent = create_agent(
    model="gpt-4o",
    tools=[...],
    middleware=[store_aware_prompt],
    context_schema=Context,
    store=InMemoryStore()
)

런타임 컨텍스트 프롬프트는 사용자 역할과 배포 환경을 통합합니다:

from dataclasses import dataclass
from langchain.agents import create_agent
from langchain.agents.middleware import dynamic_prompt, ModelRequest

@dataclass
class Context:
    user_role: str
    deployment_env: str

@dynamic_prompt
def context_aware_prompt(request: ModelRequest) -> str:
    user_role = request.runtime.context.user_role
    env = request.runtime.context.deployment_env

    base = "You are a helpful assistant."
    if user_role == "admin":
        base += "\nYou have admin access. You can perform all operations."
    elif user_role == "viewer":
        base += "\nYou have read-only access. Guide users to read operations only."

    if env == "production":
        base += "\nBe extra careful with any data modifications."
    return base

agent = create_agent(
    model="gpt-4o",
    tools=[...],
    middleware=[context_aware_prompt],
    context_schema=Context
)

메시지

메시지는 LLM에 전달되는 프롬프트를 구성합니다. 메시지 내용을 적절히 관리하면 모델이 효과적인 응답을 위한 적절한 정보를 받을 수 있습니다.

상태 기반 메시지 주입은 현재 세션의 파일 컨텍스트를 추가합니다:

from langchain.agents import create_agent
from langchain.agents.middleware import wrap_model_call, ModelRequest, ModelResponse
from typing import Callable

@wrap_model_call
def inject_file_context(
    request: ModelRequest,
    handler: Callable[[ModelRequest], ModelResponse]
) -> ModelResponse:
    uploaded_files = request.state.get("uploaded_files", [])

    if uploaded_files:
        file_descriptions = []
        for file in uploaded_files:
            file_descriptions.append(
                f"- {file['name']} ({file['type']}): {file['summary']}"
            )

        file_context = f"""Files you have access to in this conversation:
{chr(10).join(file_descriptions)}

Reference these files when answering questions."""

        messages = [
            *request.messages,
            {"role": "user", "content": file_context},
        ]
        request = request.override(messages=messages)

    return handler(request)

agent = create_agent(
    model="gpt-4o",
    tools=[...],
    middleware=[inject_file_context]
)

Store 기반 메시지 주입은 사용자 작성 스타일을 통합합니다:

from dataclasses import dataclass
from langchain.agents import create_agent
from langchain.agents.middleware import wrap_model_call, ModelRequest, ModelResponse
from typing import Callable
from langgraph.store.memory import InMemoryStore

@dataclass
class Context:
    user_id: str

@wrap_model_call
def inject_writing_style(
    request: ModelRequest,
    handler: Callable[[ModelRequest], ModelResponse]
) -> ModelResponse:
    user_id = request.runtime.context.user_id
    store = request.runtime.store
    writing_style = store.get(("writing_style",), user_id)

    if writing_style:
        style = writing_style.value
        style_context = f"""Your writing style:
- Tone: {style.get('tone', 'professional')}
- Typical greeting: "{style.get('greeting', 'Hi')}"
- Typical sign-off: "{style.get('sign_off', 'Best')}"
- Example email you've written:
{style.get('example_email', '')}"""

        messages = [
            *request.messages,
            {"role": "user", "content": style_context}
        ]
        request = request.override(messages=messages)

    return handler(request)

agent = create_agent(
    model="gpt-4o",
    tools=[...],
    middleware=[inject_writing_style],
    context_schema=Context,
    store=InMemoryStore()
)

런타임 컨텍스트 메시지 주입은 관할권에 따른 규정 준수 요구사항을 적용합니다:

from dataclasses import dataclass
from langchain.agents import create_agent
from langchain.agents.middleware import wrap_model_call, ModelRequest, ModelResponse
from typing import Callable

@dataclass
class Context:
    user_jurisdiction: str
    industry: str
    compliance_frameworks: list[str]

@wrap_model_call
def inject_compliance_rules(
    request: ModelRequest,
    handler: Callable[[ModelRequest], ModelResponse]
) -> ModelResponse:
    jurisdiction = request.runtime.context.user_jurisdiction
    industry = request.runtime.context.industry
    frameworks = request.runtime.context.compliance_frameworks

    rules = []
    if "GDPR" in frameworks:
        rules.append("- Must obtain explicit consent before processing personal data")
        rules.append("- Users have right to data deletion")
    if "HIPAA" in frameworks:
        rules.append("- Cannot share patient health information without authorization")
        rules.append("- Must use secure, encrypted communication")
    if industry == "finance":
        rules.append("- Cannot provide financial advice without proper disclaimers")

    if rules:
        compliance_context = f"""Compliance requirements for {jurisdiction}:
{chr(10).join(rules)}"""

        messages = [
            *request.messages,
            {"role": "user", "content": compliance_context}
        ]
        request = request.override(messages=messages)

    return handler(request)

agent = create_agent(
    model="gpt-4o",
    tools=[...],
    middleware=[inject_compliance_rules],
    context_schema=Context
)

중요한 구분: "위의 예제는 wrap_model_call을 사용하여 일시적인 업데이트를 만듭니다 - 상태에 저장되는 내용을 변경하지 않고 단일 호출에 대해 모델에 전송되는 메시지를 수정합니다."

도구

도구는 데이터베이스, API 및 외부 시스템과의 모델 상호작용을 가능하게 합니다. 도구 정의 품질은 모델이 작업을 효과적으로 완료할 수 있는지에 직접적인 영향을 미칩니다.

도구 정의하기

각 도구에는 명확한 이름, 설명, 인수 이름 및 인수 설명이 필요합니다. 이러한 요소는 적절한 도구 사용에 대한 모델의 추론을 안내합니다:

from langchain.tools import tool

@tool(parse_docstring=True)
def search_orders(
    user_id: str,
    status: str,
    limit: int = 10
) -> str:
    """Search for user orders by status.

    Use this when the user asks about order history or wants to check
    order status. Always filter by the provided status.

    Args:
        user_id: Unique identifier for the user
        status: Order status: 'pending', 'shipped', or 'delivered'
        limit: Maximum number of results to return
    """
    # Implementation here
    pass

도구 선택하기

모든 도구가 모든 상황에 적합한 것은 아닙니다. 과도한 도구는 모델을 압도하고 오류를 증가시키며, 불충분한 도구는 기능을 제한합니다. 동적 도구 선택은 인증, 권한, 기능 플래그 또는 대화 단계에 따라 사용 가능한 도구를 조정합니다.

상태 기반 도구 선택은 인증 후 고급 도구를 활성화합니다:

from langchain.agents import create_agent
from langchain.agents.middleware import wrap_model_call, ModelRequest, ModelResponse
from typing import Callable

@wrap_model_call
def state_based_tools(
    request: ModelRequest,
    handler: Callable[[ModelRequest], ModelResponse]
) -> ModelResponse:
    state = request.state
    is_authenticated = state.get("authenticated", False)
    message_count = len(state["messages"])

    if not is_authenticated:
        tools = [t for t in request.tools if t.name.startswith("public_")]
        request = request.override(tools=tools)
    elif message_count < 5:
        tools = [t for t in request.tools if t.name != "advanced_search"]
        request = request.override(tools=tools)

    return handler(request)

agent = create_agent(
    model="gpt-4o",
    tools=[public_search, private_search, advanced_search],
    middleware=[state_based_tools]
)

Store 기반 도구 선택은 사용자 선호도 및 기능 플래그에 따라 필터링합니다:

from dataclasses import dataclass
from langchain.agents import create_agent
from langchain.agents.middleware import wrap_model_call, ModelRequest, ModelResponse
from typing import Callable
from langgraph.store.memory import InMemoryStore

@dataclass
class Context:
    user_id: str

@wrap_model_call
def store_based_tools(
    request: ModelRequest,
    handler: Callable[[ModelRequest], ModelResponse]
) -> ModelResponse:
    user_id = request.runtime.context.user_id
    store = runtime.store
    feature_flags = store.get(("features",), user_id)

    if feature_flags:
        enabled_features = feature_flags.value.get("enabled_tools", [])
        tools = [t for t in request.tools if t.name in enabled_features]
        request = request.override(tools=tools)

    return handler(request)

agent = create_agent(
    model="gpt-4o",
    tools=[search_tool, analysis_tool, export_tool],
    middleware=[store_based_tools],
    context_schema=Context,
    store=InMemoryStore()
)

런타임 컨텍스트 도구 선택은 사용자 역할 권한에 따라 도구를 제한합니다:

from dataclasses import dataclass
from langchain.agents import create_agent
from langchain.agents.middleware import wrap_model_call, ModelRequest, ModelResponse
from typing import Callable

@dataclass
class Context:
    user_role: str

@wrap_model_call
def context_based_tools(
    request: ModelRequest,
    handler: Callable[[ModelRequest], ModelResponse]
) -> ModelResponse:
    user_role = request.runtime.context.user_role

    if user_role == "admin":
        pass
    elif user_role == "editor":
        tools = [t for t in request.tools if t.name != "delete_data"]
        request = request.override(tools=tools)
    else:
        tools = [t for t in request.tools if t.name.startswith("read_")]
        request = request.override(tools=tools)

    return handler(request)

agent = create_agent(
    model="gpt-4o",
    tools=[read_data, write_data, delete_data],
    middleware=[context_based_tools],
    context_schema=Context
)

모델

다른 모델은 다양한 강점, 비용 및 컨텍스트 윈도우 크기를 제공합니다. 특정 작업에 적합한 모델을 선택하는 것(실행 중에 변경될 수 있음)은 성능을 최적화합니다.

상태 기반 모델 선택은 대화 길이에 따라 다른 모델을 사용합니다:

from langchain.agents import create_agent
from langchain.agents.middleware import wrap_model_call, ModelRequest, ModelResponse
from langchain.chat_models import init_chat_model
from typing import Callable

large_model = init_chat_model("claude-sonnet-4-5-20250929")
standard_model = init_chat_model("gpt-4o")
efficient_model = init_chat_model("gpt-4o-mini")

@wrap_model_call
def state_based_model(
    request: ModelRequest,
    handler: Callable[[ModelRequest], ModelResponse]
) -> ModelResponse:
    message_count = len(request.messages)

    if message_count > 20:
        model = large_model
    elif message_count > 10:
        model = standard_model
    else:
        model = efficient_model

    request = request.override(model=model)
    return handler(request)

agent = create_agent(
    model="gpt-4o-mini",
    tools=[...],
    middleware=[state_based_model]
)

Store 기반 모델 선택은 사용자 선호도를 적용합니다:

from dataclasses import dataclass
from langchain.agents import create_agent
from langchain.agents.middleware import wrap_model_call, ModelRequest, ModelResponse
from langchain.chat_models import init_chat_model
from typing import Callable
from langgraph.store.memory import InMemoryStore

@dataclass
class Context:
    user_id: str

MODEL_MAP = {
    "gpt-4o": init_chat_model("gpt-4o"),
    "gpt-4o-mini": init_chat_model("gpt-4o-mini"),
    "claude-sonnet": init_chat_model("claude-sonnet-4-5-20250929"),
}

@wrap_model_call
def store_based_model(
    request: ModelRequest,
    handler: Callable[[ModelRequest], ModelResponse]
) -> ModelResponse:
    user_id = request.runtime.context.user_id
    store = request.runtime.store
    user_prefs = store.get(("preferences",), user_id)

    if user_prefs:
        preferred_model = user_prefs.value.get("preferred_model")
        if preferred_model and preferred_model in MODEL_MAP:
            request = request.override(model=MODEL_MAP[preferred_model])

    return handler(request)

agent = create_agent(
    model="gpt-4o",
    tools=[...],
    middleware=[store_based_model],
    context_schema=Context,
    store=InMemoryStore()
)

런타임 컨텍스트 모델 선택은 비용 제한 및 환경 요인을 적용합니다:

from dataclasses import dataclass
from langchain.agents import create_agent
from langchain.agents.middleware import wrap_model_call, ModelRequest, ModelResponse
from langchain.chat_models import init_chat_model
from typing import Callable

@dataclass
class Context:
    cost_tier: str
    environment: str

premium_model = init_chat_model("claude-sonnet-4-5-20250929")
standard_model = init_chat_model("gpt-4o")
budget_model = init_chat_model("gpt-4o-mini")

@wrap_model_call
def context_based_model(
    request: ModelRequest,
    handler: Callable[[ModelRequest], ModelResponse]
) -> ModelResponse:
    cost_tier = request.runtime.context.cost_tier
    environment = request.runtime.context.environment

    if environment == "production" and cost_tier == "premium":
        model = premium_model
    elif cost_tier == "budget":
        model = budget_model
    else:
        model = standard_model

    request = request.override(model=model)
    return handler(request)

agent = create_agent(
    model="gpt-4o",
    tools=[...],
    middleware=[context_based_model],
    context_schema=Context
)

응답 형식

구조화된 출력은 비구조화된 텍스트를 검증된 구조화된 데이터로 변환합니다. 특정 필드를 추출하거나 다운스트림 시스템을 위한 데이터를 반환할 때 비구조화된 응답은 불충분합니다.

"응답 형식으로 스키마를 제공하면 모델의 최종 응답이 해당 스키마를 준수하도록 보장됩니다."

형식 정의하기

스키마 정의는 모델을 안내합니다. 필드 이름, 타입 및 설명은 정확한 출력 형식 요구사항을 지정합니다:

from pydantic import BaseModel, Field

class CustomerSupportTicket(BaseModel):
    """Structured ticket information extracted from customer message."""

    category: str = Field(
        description="Issue category: 'billing', 'technical', 'account', or 'product'"
    )
    priority: str = Field(
        description="Urgency level: 'low', 'medium', 'high', or 'critical'"
    )
    summary: str = Field(
        description="One-sentence summary of the customer's issue"
    )
    customer_sentiment: str = Field(
        description="Customer's emotional tone: 'frustrated', 'neutral', or 'satisfied'"
    )

형식 선택하기

동적 형식 선택은 사용자 선호도, 대화 단계 또는 역할에 따라 스키마를 조정합니다—초기에는 간단한 형식을 반환하고 복잡성이 증가함에 따라 세부 형식을 반환합니다.

상태 기반 출력 형식 선택은 대화 상태에 따라 구조화된 출력을 구성합니다:

from langchain.agents import create_agent
from langchain.agents.middleware import wrap_model_call, ModelRequest, ModelResponse
from pydantic import BaseModel, Field
from typing import Callable

class SimpleResponse(BaseModel):
    """Simple response for early conversation."""
    answer: str = Field(description="A brief answer")

class DetailedResponse(BaseModel):
    """Detailed response for established conversation."""
    answer: str = Field(description="A detailed answer")
    reasoning: str = Field(description="Explanation of reasoning")
    confidence: float = Field(description="Confidence score 0-1")

@wrap_model_call
def state_based_output(
    request: ModelRequest,
    handler: Callable[[ModelRequest], ModelResponse]
) -> ModelResponse:
    message_count = len(request.messages)

    if message_count < 3:
        request = request.override(response_format=SimpleResponse)
    else:
        request = request.override(response_format=DetailedResponse)

    return handler(request)

agent = create_agent(
    model="gpt-4o",
    tools=[...],
    middleware=[state_based_output]
)

Store 기반 출력 형식 선택은 사용자 응답 스타일 선호도를 적용합니다:

from dataclasses import dataclass
from langchain.agents import create_agent
from langchain.agents.middleware import wrap_model_call, ModelRequest, ModelResponse
from pydantic import BaseModel, Field
from typing import Callable
from langgraph.store.memory import InMemoryStore

@dataclass
class Context:
    user_id: str

class VerboseResponse(BaseModel):
    """Verbose response with details."""
    answer: str = Field(description="Detailed answer")
    sources: list[str] = Field(description="Sources used")

class ConciseResponse(BaseModel):
    """Concise response."""
    answer: str = Field(description="Brief answer")

@wrap_model_call
def store_based_output(
    request: ModelRequest,
    handler: Callable[[ModelRequest], ModelResponse]
) -> ModelResponse:
    user_id = request.runtime.context.user_id
    store = request.runtime.store
    user_prefs = store.get(("preferences",), user_id)

    if user_prefs:
        style = user_prefs.value.get("response_style", "concise")
        if style == "verbose":
            request = request.override(response_format=VerboseResponse)
        else:
            request = request.override(response_format=ConciseResponse)

    return handler(request)

agent = create_agent(
    model="gpt-4o",
    tools=[...],
    middleware=[store_based_output],
    context_schema=Context,
    store=InMemoryStore()
)

런타임 컨텍스트 출력 형식 선택은 사용자 역할 및 환경에 따라 조정합니다:

from dataclasses import dataclass
from langchain.agents import create_agent
from langchain.agents.middleware import wrap_model_call, ModelRequest, ModelResponse
from pydantic import BaseModel, Field
from typing import Callable

@dataclass
class Context:
    user_role: str
    environment: str

class AdminResponse(BaseModel):
    """Response with technical details for admins."""
    answer: str = Field(description="Answer")
    debug_info: dict = Field(description="Debug information")
    system_status: str = Field(description="System status")

class UserResponse(BaseModel):
    """Simple response for regular users."""
    answer: str = Field(description="Answer")

@wrap_model_call
def context_based_output(
    request: ModelRequest,
    handler: Callable[[ModelRequest], ModelResponse]
) -> ModelResponse:
    user_role = request.runtime.context.user_role
    environment = request.runtime.context.environment

    if user_role == "admin" and environment == "production":
        request = request.override(response_format=AdminResponse)
    else:
        request = request.override(response_format=UserResponse)

    return handler(request)

agent = create_agent(
    model="gpt-4o",
    tools=[...],
    middleware=[context_based_output],
    context_schema=Context
)

도구 컨텍스트

도구는 컨텍스트를 명확하게 읽고 쓰기합니다. LLM 매개변수를 받고 결과를 반환하는 것 외에도, 도구는 작업 완료를 가능하게 하는 중요한 정보를 가져옵니다.

읽기

실제 도구는 LLM 매개변수 이상을 요구합니다. 데이터베이스 쿼리를 위한 사용자 ID, 외부 서비스를 위한 API 키 또는 의사결정을 위한 세션 상태가 필요합니다. 도구는 state, store 및 런타임 컨텍스트에서 읽습니다.

State 읽기는 현재 세션 정보를 확인합니다:

from langchain.tools import tool, ToolRuntime
from langchain.agents import create_agent

@tool
def check_authentication(
    runtime: ToolRuntime
) -> str:
    """Check if user is authenticated."""
    current_state = runtime.state
    is_authenticated = current_state.get("authenticated", False)

    if is_authenticated:
        return "User is authenticated"
    else:
        return "User is not authenticated"

agent = create_agent(
    model="gpt-4o",
    tools=[check_authentication]
)

Store 읽기는 지속된 사용자 선호도에 액세스합니다:

from dataclasses import dataclass
from langchain.tools import tool, ToolRuntime
from langchain.agents import create_agent
from langgraph.store.memory import InMemoryStore

@dataclass
class Context:
    user_id: str

@tool
def get_preference(
    preference_key: str,
    runtime: ToolRuntime[Context]
) -> str:
    """Get user preference from Store."""
    user_id = runtime.context.user_id
    store = runtime.store
    existing_prefs = store.get(("preferences",), user_id)

    if existing_prefs:
        value = existing_prefs.value.get(preference_key)
        return f"{preference_key}: {value}" if value else f"No preference set for {preference_key}"
    else:
        return "No preferences found"

agent = create_agent(
    model="gpt-4o",
    tools=[get_preference],
    context_schema=Context,
    store=InMemoryStore()
)

런타임 컨텍스트 읽기는 API 키 및 사용자 ID와 같은 구성에 액세스합니다:

from dataclasses import dataclass
from langchain.tools import tool, ToolRuntime
from langchain.agents import create_agent

@dataclass
class Context:
    user_id: str
    api_key: str
    db_connection: str

@tool
def fetch_user_data(
    query: str,
    runtime: ToolRuntime[Context]
) -> str:
    """Fetch data using Runtime Context configuration."""
    user_id = runtime.context.user_id
    api_key = runtime.context.api_key
    db_connection = runtime.context.db_connection

    results = perform_database_query(db_connection, query, api_key)
    return f"Found {len(results)} results for user {user_id}"

agent = create_agent(
    model="gpt-4o",
    tools=[fetch_user_data],
    context_schema=Context
)

result = agent.invoke(
    {"messages": [{"role": "user", "content": "Get my data"}]},
    context=Context(
        user_id="user_123",
        api_key="sk-...",
        db_connection="postgresql://..."
    )
)

쓰기

도구 결과는 에이전트가 작업을 완료하는 데 도움을 줍니다. 도구는 모델에 결과를 반환하고 에이전트 메모리를 업데이트하여 향후 단계를 위한 중요한 컨텍스트를 사용할 수 있게 합니다.

State 쓰기는 Command를 통해 세션별 정보를 추적합니다:

from langchain.tools import tool, ToolRuntime
from langchain.agents import create_agent
from langgraph.types import Command

@tool
def authenticate_user(
    password: str,
    runtime: ToolRuntime
) -> Command:
    """Authenticate user and update State."""
    if password == "correct":
        return Command(
            update={"authenticated": True},
        )
    else:
        return Command(update={"authenticated": False})

agent = create_agent(
    model="gpt-4o",
    tools=[authenticate_user]
)

Store 쓰기는 세션 간 데이터를 지속합니다:

from dataclasses import dataclass
from langchain.tools import tool, ToolRuntime
from langchain.agents import create_agent
from langgraph.store.memory import InMemoryStore

@dataclass
class Context:
    user_id: str

@tool
def save_preference(
    preference_key: str,
    preference_value: str,
    runtime: ToolRuntime[Context]
) -> str:
    """Save user preference to Store."""
    user_id = runtime.context.user_id
    store = runtime.store
    existing_prefs = store.get(("preferences",), user_id)

    prefs = existing_prefs.value if existing_prefs else {}
    prefs[preference_key] = preference_value

    store.put(("preferences",), user_id, prefs)
    return f"Saved preference: {preference_key} = {preference_value}"

agent = create_agent(
    model="gpt-4o",
    tools=[save_preference],
    context_schema=Context,
    store=InMemoryStore()
)

라이프사이클 컨텍스트

라이프사이클 컨텍스트는 단계 간 작업을 제어합니다—데이터 흐름을 가로채서 요약, 가드레일 및 로깅을 구현합니다.

미들웨어는 구현 메커니즘을 제공하며, 개발자가 다음을 수행할 수 있도록 합니다:

  1. 컨텍스트 업데이트 - state/store를 지속적으로 수정하고, 대화 히스토리를 업데이트하고, 인사이트를 저장합니다
  2. 라이프사이클 점프 - 컨텍스트에 따라 다른 에이전트 사이클 단계로 이동합니다

예시: 요약

한 가지 빈번한 패턴은 대화 히스토리가 길이 제한을 초과할 때 자동으로 압축하는 것입니다. 일시적인 메시지 자르기와 달리 요약은 상태를 지속적으로 업데이트합니다—향후 턴을 위해 저장된 요약으로 오래된 메시지를 영구적으로 대체합니다.

LangChain은 내장 미들웨어를 제공합니다:

from langchain.agents import create_agent
from langchain.agents.middleware import SummarizationMiddleware

agent = create_agent(
    model="gpt-4o",
    tools=[...],
    middleware=[
        SummarizationMiddleware(
            model="gpt-4o-mini",
            max_tokens_before_summary=4000,
            messages_to_keep=20,
        ),
    ],
)

대화가 토큰 제한을 초과하면 SummarizationMiddleware가 자동으로:

  1. 별도의 LLM 호출을 통해 오래된 메시지를 요약합니다
  2. State에서 요약 메시지로 영구적으로 대체합니다
  3. 최근 메시지는 그대로 유지합니다

요약된 히스토리는 지속됩니다—향후 턴은 원본 메시지 대신 요약을 봅니다.

모범 사례

  1. 간단하게 시작 - 정적 프롬프트/도구로 시작하고, 필요할 때만 동적 요소를 추가하세요
  2. 점진적으로 테스트 - 반복할 때마다 하나의 컨텍스트 엔지니어링 기능을 추가하세요
  3. 성능 모니터링 - 모델 호출, 토큰 사용량 및 지연 시간을 추적하세요
  4. 내장 미들웨어 사용 - SummarizationMiddleware, LLMToolSelectorMiddleware 등을 활용하세요
  5. 컨텍스트 전략 문서화 - 어떤 컨텍스트가 전달되는지와 그 근거를 명확히 하세요
  6. 일시적 vs 지속적 이해 - 모델 컨텍스트 변경은 일시적이며, 라이프사이클 변경은 지속됩니다

Langchain v1.0

반응형
  • 네이버 블로그 공유
  • 네이버 밴드 공유
  • 페이스북 공유
  • 카카오스토리 공유