> ## Documentation Index
> Fetch the complete documentation index at: https://docs.coreweave.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 에이전트 트레이스하기

> Weave SDK를 사용하여 멀티턴 에이전트형 애플리케이션에 계측을 추가하고 Agents 탭에서 확인하세요.

export const AgentLensBanner = ({href}) => <Tip>
    <strong>This workflow is also available in CoreWeave Agent Lens.</strong> Agent Lens is the Forge experience built for tracing, monitoring, and analyzing AI agents, with automated insights into agent failures and user intents. It uses the same trace data as Weights & Biases Weave, so the traces you already send appear there with nothing to migrate.{' '}
    <a href={href || '/products/agent-lens'}>{href ? 'See how to do this in Agent Lens' : 'Learn about Agent Lens'}</a>.
  </Tip>;

<AgentLensBanner href="/ko/products/agent-lens/tracing/instrument" />

W\&B Weave SDK를 사용하여 멀티턴 에이전트형 애플리케이션에 계측을 추가하고 에이전트의 동작을 확인, 디버깅, 평가하는 방법을 알아보세요. 이 가이드는 에이전트를 구축하거나 통합하며 대화, 턴, LLM Call, 도구 실행을 체계적으로 파악하려는 개발자를 위한 문서입니다.

에이전트용 Weave SDK는 멀티턴 에이전트 대화의 전체 라이프사이클을 모델링합니다. 여기에는 여러 대화를 소유하는 에이전트, 턴을 묶는 대화, 각 사용자-에이전트 간 상호작용(턴), 턴 내의 LLM Call, LLM이 트리거하는 도구 실행이 포함됩니다. 트레이스는 Weave 프로젝트의 **Agents** 탭에 표시됩니다. 각 대화에는 중첩된 도구 Call, 토큰 사용량, 피드백이 포함된 멀티턴 타임라인이 표시됩니다.

Weave는 분산 트레이싱을 위한 개방형 표준인 [OpenTelemetry (OTel)](https://opentelemetry.io/docs/concepts/)을 기반으로 구축되었습니다. 모든 턴, LLM Call, 도구 Call은 OTel *span*(하나의 오퍼레이션에 대한 구조화된 기록)을 생성합니다. 각 span에는 `gen_ai.agent.name`, `gen_ai.conversation.id` 등의 [GenAI 의미 규약](https://opentelemetry.io/docs/specs/semconv/gen-ai/) 속성이 태그로 지정됩니다.

`@weave.op` 데코레이터를 사용하여 개별 함수를 Op으로 트레이싱하는 경우에는 [LLM 애플리케이션 트레이싱](/ko/products/wandb/weave/guides/tracking/tracing)을 참조하세요.

<h2 id="before-you-begin">
  시작하기 전에
</h2>

시작하려면 `weave` 패키지를 설치하고 프로젝트를 초기화하세요. 이 단계에서는 SDK가 span을 UI의 올바른 위치로 전송할 수 있도록 팀과 프로젝트를 Weave에 등록합니다.

<Tabs>
  <Tab title="Python">
    ```bash lines theme={"system"}
    pip install weave
    ```

    `[YOUR-TEAM]`을 CoreWeave Forge 팀 이름으로, `[YOUR-PROJECT]`를 Weights & Biases 프로젝트 이름으로 바꾸세요.

    ```python lines theme={"system"}
    import weave

    weave.init("[YOUR-TEAM]/[YOUR-PROJECT]")
    ```

    `start_conversation()`, `start_turn()`, `start_llm()`, `start_tool()`, `start_subagent()`를 호출하기 전에 `weave.init()`을 호출하세요. 트레이싱이 비활성화되어 있거나 초기화 호출이 없으면 모든 에이전트 트레이싱 함수는 별도의 알림 없이 아무 작업도 수행하지 않으므로, 프로덕션 코드에 계측을 남겨 두고 설정을 통해 제어할 수 있습니다.
  </Tab>

  <Tab title="TypeScript">
    ```bash lines theme={"system"}
    npm install weave
    ```

    `[YOUR-TEAM]`을 CoreWeave Forge 팀 이름으로, `[YOUR-PROJECT]`를 Weights & Biases 프로젝트 이름으로 바꾸세요.

    ```typescript lines twoslash theme={"system"}
    // @noErrors
    import * as weave from 'weave';

    await weave.init('[YOUR-TEAM]/[YOUR-PROJECT]');
    ```

    `startConversation()`, `startTurn()`, `startLLM()`, `startTool()`, `startSubagent()`를 호출하기 전에 `weave.init()`을 호출하세요. 트레이싱이 비활성화되어 있거나 초기화 호출이 없으면 모든 에이전트 트레이싱 함수는 별도의 알림 없이 아무 작업도 수행하지 않으므로, 프로덕션 코드에 계측을 남겨 두고 설정을 통해 제어할 수 있습니다.
  </Tab>
</Tabs>

<h2 id="the-agent-data-model">
  에이전트 데이터 모델
</h2>

Weave는 에이전트의 동작을 일대다 관계의 계층 구조로 모델링합니다. 각 에이전트에는 여러 대화가, 각 대화에는 여러 턴이, 각 턴에는 여러 LLM Call이 포함될 수 있으며, 각 LLM Call은 여러 도구 Call을 트리거할 수 있습니다.

| 개념 | Weave SDK 클래스 | OTel span 유형 | 설명 | 레퍼런스 페이지 |
| - | - | - | - | - |
| 에이전트 | *(클래스 없음)* | *(span 없음, `agent_name` 속성으로 그룹화됨)* | Agents 탭에서 하나 이상의 대화를 포함하는 에이전트형 애플리케이션입니다. | |
| 대화 | `Conversation` | *(span 없음, 턴은 `conversation_id` 속성으로 그룹화됨)* | 하나 이상의 턴을 포함하는 대화 또는 run입니다. | [Python](/ko/products/wandb/weave/reference/python-sdk#class-conversation) <br /> [TypeScript](/ko/products/wandb/weave/reference/typescript-sdk/interfaces/conversation) |
| 턴 | `Turn` | `invoke_agent` | 하나의 사용자 메시지와 에이전트의 전체 응답입니다. | [Python](/ko/products/wandb/weave/reference/python-sdk#class-turn) <br /> [TypeScript](/ko/products/wandb/weave/reference/typescript-sdk/interfaces/turn) |
| LLM Call | `LLM` | `chat` | 언어 모델 API에 대한 한 번의 호출입니다. | [Python](/ko/products/wandb/weave/reference/python-sdk#class-llm) <br /> [TypeScript](/ko/products/wandb/weave/reference/typescript-sdk/interfaces/llm) |
| 도구 Call | `Tool` | `execute_tool` | LLM 응답에 의해 트리거되는 한 번의 도구 Call입니다. | [Python](/ko/products/wandb/weave/reference/python-sdk#class-tool) <br /> [TypeScript](/ko/products/wandb/weave/reference/typescript-sdk/interfaces/tool) |
| 하위 에이전트 호출 | `SubAgent` | `invoke_agent` | 중첩된 에이전트 호출로, 일반적으로 한 에이전트가 다른 에이전트에 작업을 위임할 때 발생합니다. | [Python](/ko/products/wandb/weave/reference/python-sdk#class-subagent) <br /> [TypeScript](/ko/products/wandb/weave/reference/typescript-sdk/interfaces/subagent) |

다음 다이어그램은 하나의 에이전트가 여러 대화를 포함하고, 하나의 대화가 여러 턴을 포함하는 등의 관계를 보여줍니다.

```mermaid theme={"system"}
flowchart TB
    Agent["에이전트<br/>agent_name"]

    Agent --> S1 & S2

    S1["대화 1<br/>conversation_id<br/>(OTel span 없음)"]
    S2["대화 2<br/>conversation_id<br/>(OTel span 없음)"]

    S1 --> T1 & T2
    S2 --> T3

    T1["턴 1<br/>invoke_agent<br/>(루트 span, 자체 트레이스)"]
    T2["턴 2<br/>invoke_agent<br/>(루트 span, 자체 트레이스)"]
    T3["턴 1<br/>invoke_agent<br/>(루트 span, 자체 트레이스)"]

    T1 --> L1 & L2
    L1["LLM Call<br/>chat"]
    L2["LLM Call<br/>chat"]

    L1 --> Tool1["도구 Call<br/>execute_tool"]

    classDef agent fill:#DE72FF33,stroke:#454B52,stroke-width:2px
    classDef conversation fill:#FFD95C33,stroke:#454B52,stroke-width:2px
    classDef turn fill:#00CDDB33,stroke:#454B52,stroke-width:2px
    classDef llm fill:#FFCBAD33,stroke:#454B52,stroke-width:2px
    classDef tool fill:#f4f4f5,stroke:#454B52,stroke-width:2px

    class Agent agent
    class S1,S2 conversation
    class T1,T2,T3 turn
    class L1,L2 llm
    class Tool1 tool
```

대화는 상위 span이 아닌 공통 `conversation_id` 속성으로 턴을 그룹화하므로 각 턴은 자체 OTel 트레이스를 시작합니다. 이 설계는 분산 트레이싱과 병렬 실행을 지원합니다. 클라이언트는 서버 측 집계 없이 span을 OTel 수집기로 직접 전송합니다.

<Tip>
  Weave를 Claude Agent SDK나 Codex와 같은 SDK 또는 하니스와 통합하려면 [에이전트 인테그레이션 선택](/ko/products/wandb/weave/agent-integration-quickstart)을 참조하세요. Weave는 빠른 인테그레이션을 위해 여러 에이전트 구축 SDK와 에이전트 하니스를 자동 패치합니다.
</Tip>

<h2 id="agent-tracing-apis">
  에이전트 트레이싱 API
</h2>

다음 섹션에서는 각 최상위 트레이싱 함수와 해당 함수가 받는 인수를 설명합니다. 이 함수들을 사용하여 이전 섹션에서 설명한 데이터 모델의 대화, 턴, LLM Call, 도구 Call 계층을 계측하세요.

Weave는 다음과 같은 최상위 함수를 제공합니다. 각 함수가 반환하는 객체는 컨텍스트 관리자로 사용할 수 있으며(Python에서는 `with`, TypeScript에서는 `try/finally` 사용), `.end()`를 호출하여 수동으로 종료할 수도 있습니다.

<h3 id="start-a-conversation">
  대화 시작
</h3>

`start_conversation()`(Python) 또는 `startConversation()`(TypeScript)은 모든 하위 span에 `conversation_id` 속성을 부여하여 Agents 탭에서 턴을 그룹화합니다. `conversation_id` / `conversationId`를 전달하는 경우, 대화가 유지되는 동안 동일한 값을 사용해야 합니다. 기존 대화에 새 턴을 추가하려면 같은 ID를 재사용하세요. 생략하면 SDK가 UUID를 자동으로 생성합니다.

활성 대화는 컨텍스트(Python의 `ContextVar` 또는 Node.js의 `AsyncLocalStorage`)에 저장되므로, 동일한 비동기 컨텍스트에서 실행되는 코드는 대화 객체를 명시적으로 전달하지 않고도 `weave.get_current_conversation()` / `weave.getCurrentConversation()`으로 대화를 조회할 수 있습니다.

<Tabs>
  <Tab title="Python">
    ```python lines theme={"system"}
    conversation = weave.start_conversation(
        agent_name="my-agent",    # 선택: UI에서 에이전트를 식별합니다. 생략하면 대화가 이름이 지정된 에이전트 아래에 그룹화되지 않습니다.
        conversation_id="",       # 선택: 턴을 그룹화하는 고정 ID입니다. 비어 있으면 자동으로 생성됩니다.
        model="",                 # 선택: 이 대화의 턴에 사용할 기본 모델입니다.
        conversation_name="",     # 선택: UI에 표시되는, 사람이 읽기 쉬운 레이블입니다.
        include_content=True,     # 선택: span에서 메시지 본문을 제외하려면 False로 설정하세요.
        continue_parent_trace=False,  # 선택: 새 OTel 트레이스를 시작하는 대신 기존 트레이스에 연결합니다.
    )
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript lines twoslash theme={"system"}
    // @noErrors
    const conversation = weave.startConversation({
      agentName: 'my-agent',  // 선택: UI에서 에이전트를 식별합니다. 생략하면 대화가 이름이 지정된 에이전트 아래에 그룹화되지 않습니다.
      conversationId: '',     // 선택: 턴을 그룹화하는 고정 ID입니다. 비어 있으면 자동으로 생성됩니다.
      model: '',              // 선택: 이 대화의 턴에 사용할 기본 모델입니다.
    });
    ```
  </Tab>
</Tabs>

<h3 id="start-a-turn">
  턴 시작하기
</h3>

`start_turn()`(Python)과 `startTurn()`(TypeScript)은 새 `invoke_agent` span을 생성하며, 이 span은 새 OTel 트레이스의 루트가 됩니다. Weave는 이 span을 사용하여 타임라인 뷰에서 사용자와 에이전트 간의 완결된 교환 하나를 표시합니다.

두 가지 방법으로 호출할 수 있습니다.

* **최상위 함수로 호출** (`weave.start_turn(...)` / `weave.startTurn(...)`): 아래 예시에서 사용하는 방식입니다. 컨텍스트에서 활성 대화를 찾아 해당 대화 ID를 상속합니다. 활성 대화가 없으면 턴은 `conversation_id` 없이 생성되며 다른 턴과 그룹화되지 않습니다.
* **인스턴스 방법으로 호출**: 참조를 보유한 대화 객체에서 호출합니다(`conversation.start_turn(...)` / `conversation.startTurn(...)`). 컨텍스트 관리자 블록 내부처럼 범위 안에 명시적인 대화 객체가 있을 때 유용합니다. 아래의 "컨텍스트 관리자 또는 try-finally 패턴" 예시가 이 형식을 사용합니다. 두 SDK의 `Conversation`, `Turn`, `LLM`, `Tool`, `SubAgent` 레퍼런스 페이지로 바로 가는 링크는 위의 데이터 모델 table을 참조하세요.

<Tabs>
  <Tab title="Python">
    ```python lines theme={"system"}
    turn = weave.start_turn(
        user_message="What is the weather in Tokyo?",  # 사용자의 입력 텍스트입니다.
        agent_name="my-agent",   # 선택: 대화 수준의 에이전트 이름을 재정의합니다.
        model="gpt-4o",          # 선택: 이 턴에 사용할 모델입니다.
    )
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript lines twoslash theme={"system"}
    // @noErrors
    const turn = weave.startTurn({
      agentName: 'my-agent',  // 선택: 대화 수준의 에이전트 이름을 재정의합니다.
      model: 'gpt-4o',        // 선택: 이 턴에 사용할 모델입니다.
    });
    ```
  </Tab>
</Tabs>

<h3 id="start-an-llm-call">
  LLM Call 시작
</h3>

`start_llm()` / `startLLM()`은 현재 턴 아래에 중첩된 `chat` span을 생성합니다. Weave는 이 span을 사용하여 Agents 뷰에 토큰 사용량, 모델 이름, 입력 및 출력 메시지, 추론을 표시합니다.

<Tabs>
  <Tab title="Python">
    ```python lines theme={"system"}
    llm = weave.start_llm(
        model="gpt-4o",             # 모델 식별자입니다.
        provider_name="openai",     # 선택: 공급자 이름(예: "openai", "anthropic"). 아래 참고 사항을 확인하세요.
        system_instructions=["Be concise."],  # 선택: system 프롬프트 문자열입니다.
    )
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript lines twoslash theme={"system"}
    // @noErrors
    const llm = weave.startLLM({
      model: 'gpt-4o',          // 모델 식별자입니다.
      providerName: 'openai',   // 선택: 공급자 이름(예: "openai", "anthropic"). 아래 참고 사항을 확인하세요.
    });
    ```
  </Tab>
</Tabs>

LLM Call이 완료되면 `llm` 객체가 닫히기 전에 응답 데이터를 객체에 부여하세요.

<Tabs>
  <Tab title="Python">
    ```python lines theme={"system"}
    with weave.start_llm(model="gpt-4o", provider_name="openai") as llm:
        response = openai_client.chat.completions.create(...)
        llm.input_messages = [Message(role="user", content="...")]
        llm.output_messages = [Message(role="assistant", content=response.choices[0].message.content)]
        llm.usage = Usage(
            input_tokens=response.usage.prompt_tokens,
            output_tokens=response.usage.completion_tokens,
        )
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript lines twoslash theme={"system"}
    // @noErrors
    const llm = weave.startLLM({ model: 'gpt-4o', providerName: 'openai' });
    try {
      const response = await openaiClient.chat.completions.create({ ... });
      llm.record({
        inputMessages: [{ role: 'user', content: '...' }],
        outputMessages: [{ role: 'assistant', content: response.choices[0].message.content ?? '' }],
        usage: {
          inputTokens: response.usage?.prompt_tokens,
          outputTokens: response.usage?.completion_tokens,
        },
      });
    } finally {
      llm.end();
    }
    ```

    `llm.record()`를 사용하면 `inputMessages`, `outputMessages`, `usage`, `reasoning`을 한 번의 호출로 간편하게 부여할 수 있습니다. 원하는 경우 각 속성을 개별적으로 설정해도 됩니다. Python SDK에서도 동일한 방법을 `llm.record(...)`로 제공하며, 키워드 인수는 snake\_case를 사용합니다.
  </Tab>
</Tabs>

`provider_name` / `providerName`은 명시적으로 전달해야 합니다. Weave는 모델 문자열에서 공급자를 추론하지 않습니다.

<h3 id="start-a-tool-call">
  도구 Call 시작
</h3>

`start_tool()` / `startTool()`은 `execute_tool` span을 생성합니다. 이 span은 컨텍스트에서 활성 상태인 OTel span의 하위 span이 됩니다(일반적으로 도구 Call을 생성한 LLM Call의 `chat` span).

<Tabs>
  <Tab title="Python">
    ```python lines theme={"system"}
    tool = weave.start_tool(
        name="get_weather",                  # LLM에 선언된 도구 이름.
        arguments='{"city": "Tokyo"}',       # 도구 인수의 JSON string.
        tool_call_id="call_abc123",          # 선택: LLM 응답의 도구 Call ID.
    )
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript lines twoslash theme={"system"}
    // @noErrors
    const tool = weave.startTool({
      name: 'get_weather',            // LLM에 선언된 도구 이름.
      args: '{"city": "Tokyo"}',      // 선택: 도구 인수의 JSON string.
      toolCallId: 'call_abc123',      // 선택: LLM 응답의 도구 Call ID.
    });
    ```
  </Tab>
</Tabs>

종료하기 전에 도구 결과를 부여하세요:

<Tabs>
  <Tab title="Python">
    ```python lines theme={"system"}
    with weave.start_tool(name="get_weather", arguments='{"city": "Tokyo"}') as tool:
        result = get_weather_api("Tokyo")
        tool.result = result  # dict, 목록 또는 string을 허용합니다. 자동으로 JSON 인코딩됩니다.
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript lines twoslash theme={"system"}
    // @noErrors
    const tool = weave.startTool({ name: 'get_weather', args: '{"city": "Tokyo"}' });
    try {
      tool.result = await getWeatherApi('Tokyo');
    } finally {
      tool.end();
    }
    ```
  </Tab>
</Tabs>

<h2 id="usage-patterns-for-agent-tracing">
  에이전트 트레이싱 사용 패턴
</h2>

다음 섹션에서는 에이전트 코드 구조에 따라 이러한 함수를 조합하는 방법을 설명합니다.

다음 예시에서는 Weave SDK의 두 가지 유형을 사용합니다.

* `Message` ([Python](/ko/products/wandb/weave/reference/python-sdk#class-message) · [TypeScript](/ko/products/wandb/weave/reference/typescript-sdk/interfaces/message))는 대화의 단일 항목인 사용자 입력, assistant 응답, system 프롬프트 또는 도구 결과를 나타냅니다. 메시지 목록을 `llm.input_messages` / `llm.inputMessages`에 부여하여 모델이 받은 내용을 기록하고, `llm.output_messages` / `llm.outputMessages`에 부여하여 모델이 생성한 내용을 기록하세요.
* `Usage` ([Python](/ko/products/wandb/weave/reference/python-sdk#class-usage) · [TypeScript](/ko/products/wandb/weave/reference/typescript-sdk/interfaces/usage))는 LLM 응답의 토큰 수를 캡처하며 `llm.usage`에 부여됩니다.

Weave는 이 두 유형을 사용하여 각 LLM Call의 입력, 출력 및 토큰 사용량을 Agents 뷰에 표시합니다.

<h3 id="context-manager-or-try-finally-pattern">
  컨텍스트 관리자 또는 try-finally 패턴
</h3>

대부분의 에이전트에서는 Python의 컨텍스트 관리자 패턴이나 TypeScript의 try-finally 패턴을 사용하세요. 예외가 발생하더라도 블록이 끝나면 span이 닫히고 전송됩니다.

Weave는 활성 대화, 턴, LLM Call을 컨텍스트에 저장하므로, 블록 내에서 호출되는 모든 함수는 부모에 대한 명시적 참조 없이 `start_llm()` / `startLLM()` 또는 `start_tool()` / `startTool()`을 호출할 수 있습니다. 코드가 동일한 비동기 컨텍스트에서 실행되는 한 모듈 경계를 넘어도 작동합니다. 호출 스택의 어느 위치에서든 활성 객체를 조회하려면 `weave.get_current_conversation()` / `weave.getCurrentConversation()`, `weave.get_current_turn()` / `weave.getCurrentTurn()`, `weave.get_current_llm()` / `weave.getCurrentLLM()`을 사용하세요.

<Tabs>
  <Tab title="Python">
    ```python lines highlight="13,14,17,25,29" theme={"system"}
    import weave
    from weave.conversation import Message, Usage

    # 자리표시자 함수: 직접 구현한 함수로 교체하세요.
    def call_openai(*args, **kwargs):
        pass  # LLM 클라이언트 호출로 교체하세요.

    def get_weather_api(city: str) -> str:
        return "24°C, sunny"  # 날씨 API 호출로 교체하세요.

    weave.init("[YOUR-TEAM]/[YOUR-PROJECT]")

    with weave.start_conversation(agent_name="weather-bot") as conversation:
        with conversation.start_turn(user_message="What is the weather in Tokyo?") as turn:

            # 첫 번째 LLM Call: 도구 Call을 반환합니다.
            with weave.start_llm(model="gpt-4o", provider_name="openai") as llm:
                response = call_openai(...)
                llm.input_messages = [Message(role="user", content="What is the weather?")]
                llm.think("User wants weather data, I should call get_weather.")
                llm.output("Let me check the weather for you.")
                llm.usage = Usage(input_tokens=100, output_tokens=20)

                # 도구 Call: 이를 요청한 LLM Call의 하위 호출입니다.
                with weave.start_tool(name="get_weather", arguments='{"city":"Tokyo"}') as tool:
                    tool.result = get_weather_api("Tokyo")  # "24°C, sunny"를 반환합니다.

            # 두 번째 LLM Call: 최종 답변을 종합합니다.
            with weave.start_llm(model="gpt-4o", provider_name="openai") as llm:
                llm.input_messages = [Message(role="user", content="What is the weather?")]
                llm.output("It is 24°C and sunny in Tokyo today.")
                llm.usage = Usage(input_tokens=150, output_tokens=30)
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript lines highlight="11,13,16,24,35" twoslash theme={"system"}
    // @noErrors
    import * as weave from 'weave';
    import type { Message, Usage } from 'weave';

    // 자리표시자 함수: 직접 구현한 함수로 교체하세요.
    async function getWeatherApi(city: string): Promise<string> {
      return '24°C, sunny';  // 날씨 API 호출로 교체하세요.
    }

    await weave.init('[YOUR-TEAM]/[YOUR-PROJECT]');

    const conversation = weave.startConversation({ agentName: 'weather-bot' });
    try {
      const turn = conversation.startTurn({ agentName: 'weather-bot' });
      try {
        // 첫 번째 LLM Call: 도구 Call을 반환합니다.
        const llm = weave.startLLM({ model: 'gpt-4o', providerName: 'openai' });
        try {
          llm.inputMessages = [{ role: 'user', content: 'What is the weather?' }];
          llm.think('User wants weather data, I should call get_weather.');
          llm.output('Let me check the weather for you.');
          llm.usage = { inputTokens: 100, outputTokens: 20 };

          // 도구 Call: 이를 요청한 LLM Call의 하위 호출입니다.
          const tool = weave.startTool({ name: 'get_weather', args: '{"city":"Tokyo"}' });
          try {
            tool.result = await getWeatherApi('Tokyo');  // "24°C, sunny"를 반환합니다.
          } finally {
            tool.end();
          }
        } finally {
          llm.end();
        }

        // 두 번째 LLM Call: 최종 답변을 종합합니다.
        const llm2 = weave.startLLM({ model: 'gpt-4o', providerName: 'openai' });
        try {
          llm2.inputMessages = [{ role: 'user', content: 'What is the weather?' }];
          llm2.output('It is 24°C and sunny in Tokyo today.');
          llm2.usage = { inputTokens: 150, outputTokens: 30 };
        } finally {
          llm2.end();
        }
      } finally {
        turn.end();
      }
    } finally {
      conversation.end();
    }
    ```
  </Tab>
</Tabs>

<h3 id="manual-start-and-end-pattern">
  수동 시작 및 종료 패턴
</h3>

`with` 블록이나 `try/finally`를 사용할 수 없는 경우에는 `.end()`를 명시적으로 사용하세요. 예를 들어, 서로 다른 함수 호출에서 span을 열고 닫거나 코루틴 외부에서 비동기 라이프사이클을 관리하는 경우가 이에 해당합니다. span이 닫히고 수집기로 플러시되도록 생성한 모든 객체에서 `.end()`를 직접 호출해야 합니다.

<Tabs>
  <Tab title="Python">
    ```python lines highlight="1,2,4,9,15" theme={"system"}
    conversation = weave.start_conversation(agent_name="weather-bot")
    turn = conversation.start_turn(user_message="What is the weather?")

    llm = weave.start_llm(model="gpt-4o", provider_name="openai")
    llm.input_messages = [Message(role="user", content="What is the weather?")]
    llm.output("Let me check.")
    llm.usage = Usage(input_tokens=100, output_tokens=20)

    tool = weave.start_tool(name="get_weather", arguments='{"city": "Tokyo"}')
    tool.result = "24°C, sunny"
    tool.end()   # end()는 멱등적이므로 여러 번 호출해도 안전합니다.

    llm.end()

    llm2 = weave.start_llm(model="gpt-4o", provider_name="openai")
    llm2.output("It is 24°C and sunny in Tokyo.")
    llm2.usage = Usage(input_tokens=150, output_tokens=30)
    llm2.end()

    turn.end()
    conversation.end()
    ```
  </Tab>

  <Tab title="TypeScript">
    ```typescript lines highlight="1,2,4,9,15" twoslash theme={"system"}
    // @noErrors
    const conversation = weave.startConversation({ agentName: 'weather-bot' });
    const turn = conversation.startTurn({ agentName: 'weather-bot' });

    const llm = weave.startLLM({ model: 'gpt-4o', providerName: 'openai' });
    llm.inputMessages = [{ role: 'user', content: 'What is the weather?' }];
    llm.output('Let me check.');
    llm.usage = { inputTokens: 100, outputTokens: 20 };

    const tool = weave.startTool({ name: 'get_weather', args: '{"city": "Tokyo"}' });
    tool.result = '24°C, sunny';
    tool.end();  // end()는 멱등적이므로 여러 번 호출해도 안전합니다.

    llm.end();

    const llm2 = weave.startLLM({ model: 'gpt-4o', providerName: 'openai' });
    llm2.output('It is 24°C and sunny in Tokyo.');
    llm2.usage = { inputTokens: 150, outputTokens: 30 };
    llm2.end();

    turn.end();
    conversation.end();
    ```
  </Tab>
</Tabs>

<h2 id="semantic-conventions">
  의미 규약
</h2>

Weave SDK는 [GenAI 의미 규약](https://opentelemetry.io/docs/specs/semconv/gen-ai/gen-ai-spans/)과 [GenAI 에이전트 span 규약](https://opentelemetry.io/docs/specs/semconv/gen-ai/gen-ai-agent-spans/)을 준수하는 OTel span을 생성합니다. Weave는 모든 OTel span을 수용하고, 모든 속성을 저장하며, 이를 쿼리할 수 있도록 합니다. Weave의 트레이싱 객체와 함께 표준 OTel span API를 사용하여 span에 임의의 속성을 추가할 수 있습니다.

<h2 id="how-data-appears-in-the-weights-biases-ui">
  Weights & Biases UI에서 데이터가 표시되는 방식
</h2>

앞서 설명한 패턴으로 에이전트에 계측을 추가하고 실행하면, 트레이스가 `https://forge.coreweave.com/wandb/[YOUR-TEAM]/[YOUR-PROJECT]/weave/agents`에 있는 Weave 프로젝트의 **Agents** 탭에 표시됩니다.

* **Conversations 탭**에는 모든 대화가 턴 활동 미니맵과 함께 표시됩니다.
* 대화를 클릭하면 **대화 상세 뷰**가 열리며, 모든 턴, LLM Call, 도구 실행, 토큰 수, 연결된 피드백이 표시됩니다.

Weave에서 Agents 데이터를 보는 방법에 대한 자세한 내용은 [에이전트 활동 보기](/ko/products/wandb/weave/guides/tracking/view-agent-activity)를 참조하세요.


## Related topics

- [W&B Weave](/ko/products/wandb/weave.md)
