퀵스타트 (Quickstart)

퀵스타트 (Quickstart)

이 퀵스타트에서는 LangGraph의 Graph API 또는 Functional API를 사용해서 계산기(calculator) 에이전트를 직접 만들어 봐요.

AI 코딩 어시스턴트를 쓰고 계신가요?

  • LangChain Docs MCP 서버를 설치하면 에이전트가 최신 LangChain 문서와 예제에 접근할 수 있어요.
  • LangChain Skills를 설치하면 LangChain 생태계 작업에서 에이전트 성능이 좋아져요.

에이전트를 노드와 엣지의 그래프로 정의하고 싶다면 Graph API를 써요. 하나의 함수로 정의하고 싶다면 Functional API를 쓰면 돼요. 개념적인 설명은 Graph API 개요Functional API 개요 문서를 참고하세요.

이 예제를 실행하려면 Claude(Anthropic) 계정을 만들고 API 키를 받은 다음, 터미널에 ANTHROPIC_API_KEY 환경 변수를 설정해야 해요. 사용 가능한 모든 프로바이더는 챗 모델 통합 문서에서 확인할 수 있어요. LangSmith Gateway를 쓰면 직접 키를 가져오거나 Gateway Credits로 프로바이더 키 없이 모델에 접근할 수도 있어요.

두 가지 접근 방식(Graph API / Functional API) 중 원하는 쪽을 골라 따라가면 돼요.


Graph API 사용하기

1. 도구와 모델 정의하기

이 예제에서는 Claude Sonnet 4.5 모델을 사용하고, 덧셈·곱셈·나눗셈을 수행하는 도구들을 정의할 거예요.

from langchain.tools import tool
from langchain.chat_models import init_chat_model


model = init_chat_model(
    "claude-sonnet-4-6",
    temperature=0
)


# Define tools
@tool
def multiply(a: int, b: int) -> int:
    """Multiply `a` and `b`.

    Args:
        a: First int
        b: Second int
    """
    return a * b


@tool
def add(a: int, b: int) -> int:
    """Adds `a` and `b`.

    Args:
        a: First int
        b: Second int
    """
    return a + b


@tool
def divide(a: int, b: int) -> float:
    """Divide `a` and `b`.

    Args:
        a: First int
        b: Second int
    """
    return a / b


# Augment the LLM with tools
tools = [add, multiply, divide]
tools_by_name = {tool.name: tool for tool in tools}
model_with_tools = model.bind_tools(tools)

2. 상태(state) 정의하기

그래프의 상태는 메시지와 LLM 호출 횟수를 저장하는 데 사용돼요.

상태는 에이전트 실행이 끝날 때까지 계속 유지(persists)돼요. Annotated 타입에 operator.add를 붙이면 새 메시지가 기존 리스트를 교체하지 않고 뒤에 추가되도록 보장해 줘요.

from langchain.messages import AnyMessage
from typing_extensions import TypedDict, Annotated
import operator


class MessagesState(TypedDict):
    messages: Annotated[list[AnyMessage], operator.add]
    llm_calls: int

3. 모델 노드 정의하기

모델 노드는 LLM을 호출하고, 도구를 호출할지 말지를 결정하는 역할을 해요.

from langchain.messages import SystemMessage


def llm_call(state: dict):
    """LLM decides whether to call a tool or not"""

    return {
        "messages": [
            model_with_tools.invoke(
                [
                    SystemMessage(
                        content="You are a helpful assistant tasked with performing arithmetic on a set of inputs."
                    )
                ]
                + state["messages"]
            )
        ],
        "llm_calls": state.get('llm_calls', 0) + 1
    }

4. 도구 노드 정의하기

도구 노드는 도구를 호출하고 그 결과를 돌려주는 역할을 해요.

from langchain.messages import ToolMessage


def tool_node(state: dict):
    """Performs the tool call"""

    result = []
    for tool_call in state["messages"][-1].tool_calls:
        tool = tools_by_name[tool_call["name"]]
        observation = tool.invoke(tool_call["args"])
        result.append(ToolMessage(content=observation, tool_call_id=tool_call["id"]))
    return {"messages": result}

5. 종료 로직 정의하기

조건부 엣지 함수는 LLM이 도구 호출을 했는지에 따라 도구 노드로 갈지, 끝낼지를 라우팅해 줘요.

from typing import Literal
from langgraph.graph import StateGraph, START, END


def should_continue(state: MessagesState) -> Literal["tool_node", END]:
    """Decide if we should continue the loop or stop based upon whether the LLM made a tool call"""

    messages = state["messages"]
    last_message = messages[-1]

    # If the LLM makes a tool call, then perform an action
    if last_message.tool_calls:
        return "tool_node"

    # Otherwise, we stop (reply to the user)
    return END

6. 에이전트 빌드하고 컴파일하기

에이전트는 StateGraph 클래스로 빌드하고, compile 메서드로 컴파일해요.

# Build workflow
agent_builder = StateGraph(MessagesState)

# Add nodes
agent_builder.add_node("llm_call", llm_call)
agent_builder.add_node("tool_node", tool_node)

# Add edges to connect nodes
agent_builder.add_edge(START, "llm_call")
agent_builder.add_conditional_edges(
    "llm_call",
    should_continue,
    ["tool_node", END]
)
agent_builder.add_edge("tool_node", "llm_call")

# Compile the agent
agent = agent_builder.compile()

# Show the agent
from IPython.display import Image, display
display(Image(agent.get_graph(xray=True).draw_mermaid_png()))

# Invoke
from langchain.messages import HumanMessage
messages = [HumanMessage(content="Add 3 and 4.")]
messages = agent.invoke({"messages": messages})
for m in messages["messages"]:
    m.pretty_print()

에이전트를 LangSmith로 추적(trace)하고 디버깅할 수 있어요. 시작하려면 tracing quickstart를 따라 하세요. 운영(production)으로 넘어갈 준비가 되면 Deploy 문서에서 호스팅 옵션을 확인하세요. 또한 LangSmith Engine 설정을 추천하는데, 이건 트레이스를 모니터링하고 문제를 감지하며 수정 방안을 제안해 줘요.

축하해요! 이제 LangGraph Graph API로 첫 번째 에이전트를 만들었어요.

# Step 1: Define tools and model

from langchain.tools import tool
from langchain.chat_models import init_chat_model


model = init_chat_model(
    "claude-sonnet-4-6",
    temperature=0
)


# Define tools
@tool
def multiply(a: int, b: int) -> int:
    """Multiply `a` and `b`.

    Args:
        a: First int
        b: Second int
    """
    return a * b


@tool
def add(a: int, b: int) -> int:
    """Adds `a` and `b`.

    Args:
        a: First int
        b: Second int
    """
    return a + b


@tool
def divide(a: int, b: int) -> float:
    """Divide `a` and `b`.

    Args:
        a: First int
        b: Second int
    """
    return a / b


# Augment the LLM with tools
tools = [add, multiply, divide]
tools_by_name = {tool.name: tool for tool in tools}
model_with_tools = model.bind_tools(tools)

# Step 2: Define state

from langchain.messages import AnyMessage
from typing_extensions import TypedDict, Annotated
import operator


class MessagesState(TypedDict):
    messages: Annotated[list[AnyMessage], operator.add]
    llm_calls: int

# Step 3: Define model node
from langchain.messages import SystemMessage


def llm_call(state: MessagesState):
    """LLM decides whether to call a tool or not"""

    return {
        "messages": [
            model_with_tools.invoke(
                [
                    SystemMessage(
                        content="You are a helpful assistant tasked with performing arithmetic on a set of inputs."
                    )
                ]
                + state["messages"]
            )
        ],
        "llm_calls": state.get('llm_calls', 0) + 1
    }


# Step 4: Define tool node

from langchain.messages import ToolMessage


def tool_node(state: MessagesState):
    """Performs the tool call"""

    result = []
    for tool_call in state["messages"][-1].tool_calls:
        tool = tools_by_name[tool_call["name"]]
        observation = tool.invoke(tool_call["args"])
        result.append(ToolMessage(content=observation, tool_call_id=tool_call["id"]))
    return {"messages": result}

# Step 5: Define logic to determine whether to end

from typing import Literal
from langgraph.graph import StateGraph, START, END


# Conditional edge function to route to the tool node or end based upon whether the LLM made a tool call
def should_continue(state: MessagesState) -> Literal["tool_node", END]:
    """Decide if we should continue the loop or stop based upon whether the LLM made a tool call"""

    messages = state["messages"]
    last_message = messages[-1]

    # If the LLM makes a tool call, then perform an action
    if last_message.tool_calls:
        return "tool_node"

    # Otherwise, we stop (reply to the user)
    return END

# Step 6: Build agent

# Build workflow
agent_builder = StateGraph(MessagesState)

# Add nodes
agent_builder.add_node("llm_call", llm_call)
agent_builder.add_node("tool_node", tool_node)

# Add edges to connect nodes
agent_builder.add_edge(START, "llm_call")
agent_builder.add_conditional_edges(
    "llm_call",
    should_continue,
    ["tool_node", END]
)
agent_builder.add_edge("tool_node", "llm_call")

# Compile the agent
agent = agent_builder.compile()


from IPython.display import Image, display
# Show the agent
display(Image(agent.get_graph(xray=True).draw_mermaid_png()))

# Invoke
from langchain.messages import HumanMessage
messages = [HumanMessage(content="Add 3 and 4.")]
messages = agent.invoke({"messages": messages})
for m in messages["messages"]:
    m.pretty_print()

Functional API 사용하기

1. 도구와 모델 정의하기

이 예제에서는 Claude Sonnet 4.5 모델을 사용하고, 덧셈·곱셈·나눗셈 도구를 정의해요.

from langchain.tools import tool
from langchain.chat_models import init_chat_model


model = init_chat_model(
    "claude-sonnet-4-6",
    temperature=0
)


# Define tools
@tool
def multiply(a: int, b: int) -> int:
    """Multiply `a` and `b`.

    Args:
        a: First int
        b: Second int
    """
    return a * b


@tool
def add(a: int, b: int) -> int:
    """Adds `a` and `b`.

    Args:
        a: First int
        b: Second int
    """
    return a + b


@tool
def divide(a: int, b: int) -> float:
    """Divide `a` and `b`.

    Args:
        a: First int
        b: Second int
    """
    return a / b


# Augment the LLM with tools
tools = [add, multiply, divide]
tools_by_name = {tool.name: tool for tool in tools}
model_with_tools = model.bind_tools(tools)

from langgraph.graph import add_messages
from langchain.messages import (
    SystemMessage,
    HumanMessage,
    ToolCall,
)
from langchain_core.messages import BaseMessage
from langgraph.func import entrypoint, task

2. 모델 노드 정의하기

모델 노드는 LLM을 호출하고, 도구를 호출할지 말지를 결정하는 역할을 해요.

@task 데코레이터는 함수를 에이전트의 일부로 실행할 수 있는 태스크로 표시해 줘요. 태스크는 entrypoint 함수 안에서 동기적으로 또는 비동기적으로 호출할 수 있어요.

@task
def call_llm(messages: list[BaseMessage]):
    """LLM decides whether to call a tool or not"""
    return model_with_tools.invoke(
        [
            SystemMessage(
                content="You are a helpful assistant tasked with performing arithmetic on a set of inputs."
            )
        ]
        + messages
    )

3. 도구 노드 정의하기

도구 노드는 도구를 호출하고 그 결과를 돌려주는 역할을 해요.

@task
def call_tool(tool_call: ToolCall):
    """Performs the tool call"""
    tool = tools_by_name[tool_call["name"]]
    return tool.invoke(tool_call)

4. 에이전트 정의하기

에이전트는 @entrypoint 함수로 빌드해요.

Functional API에서는 노드와 엣지를 명시적으로 정의하는 대신, 하나의 함수 안에 평범한 제어 흐름 로직(반복문, 조건문)을 그대로 작성하면 돼요.

@entrypoint()
def agent(messages: list[BaseMessage]):
    model_response = call_llm(messages).result()

    while True:
        if not model_response.tool_calls:
            break

        # Execute tools
        tool_result_futures = [
            call_tool(tool_call) for tool_call in model_response.tool_calls
        ]
        tool_results = [fut.result() for fut in tool_result_futures]
        messages = add_messages(messages, [model_response, *tool_results])
        model_response = call_llm(messages).result()

    messages = add_messages(messages, model_response)
    return messages

# Invoke
messages = [HumanMessage(content="Add 3 and 4.")]
stream = agent.stream_events(messages, version="v3")
for snapshot in stream.values:
    print(snapshot)
    print("\n")

에이전트를 LangSmith로 추적하고 디버깅할 수 있어요. 시작하려면 tracing quickstart를 따라 하세요. 운영으로 넘어갈 준비가 되면 Deploy 문서에서 호스팅 옵션을 확인하세요. 또한 LangSmith Engine 설정을 추천하는데, 이건 트레이스를 모니터링하고 문제를 감지하며 수정 방안을 제안해 줘요.

축하해요! 이제 LangGraph Functional API로 첫 번째 에이전트를 만들었어요.

# Step 1: Define tools and model

from langchain.tools import tool
from langchain.chat_models import init_chat_model


model = init_chat_model(
    "claude-sonnet-4-6",
    temperature=0
)


# Define tools
@tool
def multiply(a: int, b: int) -> int:
    """Multiply `a` and `b`.

    Args:
        a: First int
        b: Second int
    """
    return a * b


@tool
def add(a: int, b: int) -> int:
    """Adds `a` and `b`.

    Args:
        a: First int
        b: Second int
    """
    return a + b


@tool
def divide(a: int, b: int) -> float:
    """Divide `a` and `b`.

    Args:
        a: First int
        b: Second int
    """
    return a / b


# Augment the LLM with tools
tools = [add, multiply, divide]
tools_by_name = {tool.name: tool for tool in tools}
model_with_tools = model.bind_tools(tools)

from langgraph.graph import add_messages
from langchain.messages import (
    SystemMessage,
    HumanMessage,
    ToolCall,
)
from langchain_core.messages import BaseMessage
from langgraph.func import entrypoint, task


# Step 2: Define model node

@task
def call_llm(messages: list[BaseMessage]):
    """LLM decides whether to call a tool or not"""
    return model_with_tools.invoke(
        [
            SystemMessage(
                content="You are a helpful assistant tasked with performing arithmetic on a set of inputs."
            )
        ]
        + messages
    )


# Step 3: Define tool node

@task
def call_tool(tool_call: ToolCall):
    """Performs the tool call"""
    tool = tools_by_name[tool_call["name"]]
    return tool.invoke(tool_call)


# Step 4: Define agent

@entrypoint()
def agent(messages: list[BaseMessage]):
    model_response = call_llm(messages).result()

    while True:
        if not model_response.tool_calls:
            break

        # Execute tools
        tool_result_futures = [
            call_tool(tool_call) for tool_call in model_response.tool_calls
        ]
        tool_results = [fut.result() for fut in tool_result_futures]
        messages = add_messages(messages, [model_response, *tool_results])
        model_response = call_llm(messages).result()

    messages = add_messages(messages, model_response)
    return messages

# Invoke
messages = [HumanMessage(content="Add 3 and 4.")]
stream = agent.stream_events(messages, version="v3")
for snapshot in stream.values:
    print(snapshot)
    print("\n")

이 문서들을 MCP로 연결하면 Claude, VSCode 등에서 실시간 답변을 받을 수 있어요.

GitHub에서 이 페이지 수정 또는 이슈 등록