런타임

런타임 (Runtime)

에이전트를 만들다 보면 "도구 안에서 사용자 ID나 DB 연결 같은 값을 어떻게 전달하지?" 하는 고민이 생겨요. 전역 상태를 쓰거나 하드코딩하는 대신, LangChain은 이 문제를 우아하게 해결하는 런타임(runtime) 컨텍스트를 제공합니다. LangChain의 create_agent는 내부적으로 LangGraph의 런타임 위에서 실행되는데, 이 페이지에서는 그 런타임 정보를 어떻게 활용하는지 설명할게요.

출처: LangChain 공식 문서 — Runtime

개요 (Overview)

LangGraph는 Runtime 객체를 노출하며, 여기에 다음 정보가 담겨 있어요.

  1. Context: 에이전트 호출을 위한 사용자 id, DB 연결 등과 같은 정적 정보나 의존성
  2. Store: 장기 기억(long-term memory)에 쓰이는 BaseStore 인스턴스
  3. Stream writer: "custom" 스트림 모드로 정보를 스트리밍하는 데 쓰는 객체
  4. Execution info: 현재 실행의 신원과 재시도 정보(thread ID, run ID, 시도 횟수)
  5. Server info: LangGraph Server에서 실행할 때의 서버별 메타데이터(assistant ID, graph ID, 인증된 사용자)

런타임 컨텍스트는 도구와 미들웨어를 위한 의존성 주입(dependency injection) 을 제공해요. 값을 하드코딩하거나 전역 상태를 쓰는 대신, 에이전트를 호출할 때 런타임 의존성(DB 연결, 사용자 ID, 설정 등)을 주입할 수 있죠. 이렇게 하면 도구를 더 테스트하기 쉽고, 재사용 가능하며, 유연하게 만들 수 있어요.

런타임 정보는 도구(tools) 안에서도, 미들웨어(middleware) 안에서도 접근할 수 있어요.

접근 (Access)

create_agent로 에이전트를 만들 때 context_schema를 지정하면 에이전트 Runtime에 저장되는 context의 구조를 정의할 수 있어요. 에이전트를 호출할 때는 실행에 필요한 설정과 함께 context 인자를 넘기면 됩니다.

from dataclasses import dataclass

from langchain.agents import create_agent

@dataclass
class Context:
    user_name: str

agent = create_agent(
    model="gpt-5-nano",
    tools=[...],
    context_schema=Context
)

agent.invoke(
    {"messages": [{"role": "user", "content": "What's my name?"}]},
    context=Context(user_name="John Smith")
)

도구 안에서 (Inside tools)

도구 안에서 런타임 정보에 접근하면 다음을 할 수 있어요.

  • 컨텍스트 접근
  • 장기 기억 읽기/쓰기
  • 커스텀 스트림에 쓰기 (예: 도구 진행 상황/업데이트)

도구 안에서 Runtime 객체에 접근하려면 ToolRuntime 파라미터를 쓰세요.

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

@dataclass
class Context:
    user_id: str

@tool
def fetch_user_email_preferences(runtime: ToolRuntime[Context]) -> str:
    """Fetch the user's email preferences from the store."""
    user_id = runtime.context.user_id

    preferences: str = "The user prefers you to write a brief and polite email."
    if runtime.store:
        if memory := runtime.store.get(("users",), user_id):
            preferences = memory.value["preferences"]

    return preferences

도구 안의 실행·서버 정보 (Execution info and server info inside tools)

runtime.execution_info로 실행 신원(thread ID, run ID)에, LangGraph Server에서 실행할 때는 runtime.server_info로 서버별 메타데이터(assistant ID, 인증된 사용자)에 접근할 수 있어요.

from langchain.tools import tool, ToolRuntime

@tool
def context_aware_tool(runtime: ToolRuntime) -> str:
    """A tool that uses execution and server info."""
    # Access thread and run IDs
    info = runtime.execution_info
    print(f"Thread: {info.thread_id}, Run: {info.run_id}")

    # Access server info (only available on LangGraph Server)
    server = runtime.server_info
    if server is not None:
        print(f"Assistant: {server.assistant_id}")
        if server.user is not None:
            print(f"User: {server.user.identity}")

    return "done"

server_info는 LangGraph Server에서 실행하지 않을 때(예: 로컬 개발 중) None이에요.

runtime.execution_inforuntime.server_info를 쓰려면 deepagents>=0.5.0(또는 langgraph>=1.1.5)이 필요해요.

미들웨어 안에서 (Inside middleware)

미들웨어 안에서 런타임 정보에 접근하면 사용자 컨텍스트에 기반해 동적 프롬프트를 만들고, 메시지를 수정하며, 에이전트 동작을 제어할 수 있어요. 노드 스타일 훅(node-style hooks)에서는 Runtime 파라미터로, 랩 스타일 훅(wrap-style hooks)에서는 ModelRequest 파라미터 안에서 Runtime 객체를 쓸 수 있어요.

from dataclasses import dataclass

from langchain.messages import AnyMessage
from langchain.agents import create_agent, AgentState
from langchain.agents.middleware import dynamic_prompt, ModelRequest, before_model, after_model
from langgraph.runtime import Runtime

@dataclass
class Context:
    user_name: str

# Dynamic prompts
@dynamic_prompt
def dynamic_system_prompt(request: ModelRequest) -> str:
    user_name = request.runtime.context.user_name
    system_prompt = f"You are a helpful assistant. Address the user as {user_name}."
    return system_prompt

# Before model hook
@before_model
def log_before_model(state: AgentState, runtime: Runtime[Context]) -> dict | None:
    print(f"Processing request for user: {runtime.context.user_name}")
    return None

# After model hook
@after_model
def log_after_model(state: AgentState, runtime: Runtime[Context]) -> dict | None:
    print(f"Completed request for user: {runtime.context.user_name}")
    return None

agent = create_agent(
    model="gpt-5-nano",
    tools=[...],
    middleware=[dynamic_system_prompt, log_before_model, log_after_model],
    context_schema=Context
)

agent.invoke(
    {"messages": [{"role": "user", "content": "What's my name?"}]},
    context=Context(user_name="John Smith")
)

미들웨어 안의 실행·서버 정보 (Execution info and server info inside middleware)

미들웨어 훅도 runtime.execution_inforuntime.server_info에 접근할 수 있어요.

from langchain.agents import AgentState
from langchain.agents.middleware import before_model
from langgraph.runtime import Runtime

@before_model
def auth_gate(state: AgentState, runtime: Runtime) -> dict | None:
    """Block unauthenticated users when running on LangGraph Server."""
    server = runtime.server_info
    if server is not None and server.user is None:
        raise ValueError("Authentication required")
    print(f"Thread: {runtime.execution_info.thread_id}")
    return None

이를 위해선 deepagents>=0.5.0(또는 langgraph>=1.1.5)이 필요해요.

더 알아보기 (Learn more)