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

# OpenTelemetry spans를 Agents 뷰로 보내기

> Weave SDK 없이도 모든 OpenTelemetry 파이프라인에서 Weave agents 엔드포인트로 OTLP 트레이스 데이터를 보낼 수 있습니다.

W\&B Weave 에이전트 관측성은 [OpenTelemetry (OTel)](https://opentelemetry.io/docs/concepts/)을 기반으로 합니다. Weave는 span을 **Agents** 뷰로 수집하는 전용 OTLP 엔드포인트를 제공합니다. 에이전트가 이미 OTel span을 내보내고 있다면 Weave SDK를 설치하지 않아도 기존 OTel 파이프라인이 해당 엔드포인트를 가리키도록 설정해 Weave로 보낼 수 있습니다.

이 페이지에서는 엔드포인트에 인증하고 span을 보내는 방법을 설명합니다.

<div id="authentication">
  ## 인증
</div>

다음 엔드포인트로 spans를 전송할 수 있습니다:

* **경로**: `/agents/otel/v1/traces`
* **방법**: `POST`
* **콘텐츠 유형**: `application/x-protobuf`
* **기본 URL**: Multi-tenant Cloud의 경우 `https://trace.wandb.ai`

이 엔드포인트는 OTLP protobuf payload만 허용합니다. `opentelemetry-exporter-otlp-proto-http` (Python) 또는 `@opentelemetry/exporter-trace-otlp-proto` (TypeScript)와 같은 protobuf HTTP 익스포터를 사용하세요. 이 엔드포인트는 `gzip` 및 `deflate` 콘텐츠 인코딩도 허용합니다.

엔드포인트에 인증하려면 다음 값 중 하나를 사용해 `OTLPSpanExporter` 설정에 [W\&B API 키](https://wandb.ai/settings)를 설정하세요:

* `wandb-api-key`: 값으로 W\&B API 키를 지정합니다.
* `Authorization`: 사용자 이름으로 `api`를, 비밀번호로 W\&B API 키를 사용하는 HTTP Basic 인증입니다. 이 형식은 익스포터 또는 collector가 표준 authorization 헤더만 지원하는 경우에 유용합니다.

<div id="project-routing">
  ## 프로젝트 라우팅
</div>

Weave는 OTel 리소스 속성 또는 요청 헤더를 사용해 span을 프로젝트로 라우팅합니다.

* **리소스 속성**(권장): `TracerProvider` 리소스에서 `wandb.entity`는 담당 W\&B 팀 또는 사용자 이름으로, `wandb.project`는 프로젝트 이름으로 설정하세요.
* **`project_id` 헤더**: 값을 `[YOUR-TEAM]/[YOUR-PROJECT]`로 설정하세요.

둘 다 있으면 리소스 속성이 우선합니다. entity와 프로젝트 없이 들어오는 span은 무시됩니다.

<div id="shape-spans-for-the-agents-view">
  ## Agents 뷰용 span 구성하기
</div>

Weave는 모든 OTel span을 허용하고 해당 span의 모든 속성을 저장하지만, Agents 뷰에서는 [OTel GenAI semantic conventions](https://opentelemetry.io/docs/specs/semconv/gen-ai/gen-ai-agent-spans/)을 따르는 span을 렌더링합니다. 각 span에 `gen_ai.operation.name`을 설정하여 Weave에 해당 span이 무엇을 나타내는지 알려 주세요.

| `gen_ai.operation.name` | 나타내는 항목               | 렌더링 형식        |
| ----------------------- | --------------------- | ------------- |
| `invoke_agent`          | 하나의 완전한 사용자-에이전트 상호작용 | 하나의 턴         |
| `chat`                  | 언어 모델 API에 대한 한 번의 호출 | 턴 내의 LLM Call |
| `execute_tool`          | 하나의 도구 실행             | 도구 Call       |

그룹화는 다음 두 속성으로 제어됩니다.

* `gen_ai.conversation.id`: 여러 턴을 하나의 대화로 그룹화합니다. 대화가 유지되는 동안에는 안정적인 ID를 사용하세요.
* `gen_ai.agent.name`: Agents 탭에서 대화를 이름 있는 에이전트 아래로 그룹화합니다.

`gen_ai.request.model`, `gen_ai.usage.input_tokens`, `gen_ai.usage.output_tokens`와 같은 다른 GenAI semantic-convention 속성은 모델 이름과 token 수를 표시해 렌더링 정보를 더 풍부하게 해 주지만, 선택 사항입니다. 이러한 span이 매핑되는 에이전트 데이터 모델은 [Trace your agents](/ko/weave/guides/tracking/trace-agents#the-agent-data-model)에서 확인하세요.

<div id="configure-with-environment-variables-only">
  ## 환경 변수만 사용해 구성하기
</div>

애플리케이션 또는 collector가 표준 OTel 익스포터 환경 변수를 읽는 경우, 코드를 전혀 변경하지 않고도 다음 변수를 설정해 spans를 Weave로 라우팅할 수 있습니다:

```bash lines theme={null}
export OTEL_EXPORTER_OTLP_TRACES_ENDPOINT="https://trace.wandb.ai/agents/otel/v1/traces"
export OTEL_EXPORTER_OTLP_TRACES_HEADERS="wandb-api-key=$WANDB_API_KEY"
export OTEL_RESOURCE_ATTRIBUTES="wandb.entity=[YOUR-TEAM],wandb.project=[YOUR-PROJECT]"
```

<div id="example-emit-agent-spans-without-the-weave-sdk">
  ## 예시: Weave SDK 없이 에이전트 spans 내보내기
</div>

다음 예시는 OTel 패키지만 사용해 최소한의 에이전트 턴을 계측합니다. 턴용 `invoke_agent` span, LLM Call용 `chat` span, 도구 Call용 `execute_tool` span을 내보낸 다음, 이를 Weave Agents 엔드포인트로 익스포트합니다.

먼저, 필요한 의존성을 설치하세요:

<CodeGroup>
  ```bash Python theme={null}
  pip install opentelemetry-sdk opentelemetry-exporter-otlp-proto-http
  ```

  ```bash TypeScript theme={null}
  npm install @opentelemetry/api @opentelemetry/sdk-trace-node @opentelemetry/sdk-trace-base @opentelemetry/resources @opentelemetry/exporter-trace-otlp-proto
  ```
</CodeGroup>

그런 다음 아래 코드에서 `WANDB_API_KEY`, `ENTITY`, `PROJECT` 값을 설정한 후 실행하세요:

<CodeGroup>
  ```python Python lines highlight="8,9,14" theme={null}
  import os
  from opentelemetry import trace
  from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
  from opentelemetry.sdk import trace as trace_sdk
  from opentelemetry.sdk.resources import Resource
  from opentelemetry.sdk.trace.export import BatchSpanProcessor

  ENTITY = "[YOUR-TEAM]"
  PROJECT = "[YOUR-PROJECT]"

  WEAVE_AGENTS_OTLP_ENDPOINT = "https://trace.wandb.ai/agents/otel/v1/traces"

  # https://wandb.ai/settings 에서 API 키를 생성하세요.
  WANDB_API_KEY = [YOUR-WANDB-API-KEY]

  exporter = OTLPSpanExporter(
      endpoint=WEAVE_AGENTS_OTLP_ENDPOINT,
      headers={"wandb-api-key": WANDB_API_KEY},
  )

  tracer_provider = trace_sdk.TracerProvider(resource=Resource({
      "wandb.entity": ENTITY,
      "wandb.project": PROJECT,
  }))
  tracer_provider.add_span_processor(BatchSpanProcessor(exporter))
  trace.set_tracer_provider(tracer_provider)

  tracer = trace.get_tracer("my-agent")

  CONVERSATION_ID = "conversation-001"

  # 한 번의 턴: 사용자가 질문하면 에이전트가 도구를 호출한 후 답변합니다.
  with tracer.start_as_current_span("invoke_agent my-agent") as turn:
      turn.set_attribute("gen_ai.operation.name", "invoke_agent")
      turn.set_attribute("gen_ai.agent.name", "my-agent")
      turn.set_attribute("gen_ai.conversation.id", CONVERSATION_ID)

      with tracer.start_as_current_span("chat gpt-4o") as llm:
          llm.set_attribute("gen_ai.operation.name", "chat")
          llm.set_attribute("gen_ai.conversation.id", CONVERSATION_ID)
          llm.set_attribute("gen_ai.request.model", "gpt-4o")
          # 실제 LLM Call로 교체하고 토큰 사용량을 기록하세요.
          llm.set_attribute("gen_ai.usage.input_tokens", 100)
          llm.set_attribute("gen_ai.usage.output_tokens", 20)

          with tracer.start_as_current_span("execute_tool get_weather") as tool:
              tool.set_attribute("gen_ai.operation.name", "execute_tool")
              tool.set_attribute("gen_ai.conversation.id", CONVERSATION_ID)
              tool.set_attribute("gen_ai.tool.name", "get_weather")
              # 실제 도구 실행으로 교체하세요.

  tracer_provider.shutdown()  # 종료 전 대기 중인 모든 span을 플러시합니다.
  ```

  ```typescript TypeScript lines highlight="7,8,13" theme={null}
  import { trace } from "@opentelemetry/api";
  import { NodeTracerProvider } from "@opentelemetry/sdk-trace-node";
  import { BatchSpanProcessor } from "@opentelemetry/sdk-trace-base";
  import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-proto";
  import { Resource } from "@opentelemetry/resources";

  const ENTITY = "[YOUR-TEAM]";
  const PROJECT = "[YOUR-PROJECT]";

  const WEAVE_AGENTS_OTLP_ENDPOINT = "https://trace.wandb.ai/agents/otel/v1/traces";

  // https://wandb.ai/settings 에서 API 키를 생성하세요.
  const WANDB_API_KEY = [YOUR-WANDB-API-KEY]!;

  const exporter = new OTLPTraceExporter({
    url: WEAVE_AGENTS_OTLP_ENDPOINT,
    headers: { "wandb-api-key": WANDB_API_KEY },
  });

  const provider = new NodeTracerProvider({
    resource: new Resource({
      "wandb.entity": ENTITY,
      "wandb.project": PROJECT,
    }),
    spanProcessors: [new BatchSpanProcessor(exporter)],
  });

  provider.register();

  const tracer = trace.getTracer("my-agent");

  const CONVERSATION_ID = "conversation-001";

  // 한 번의 turn: 사용자가 질문하면 에이전트가 도구를 호출한 후 답변합니다.
  tracer.startActiveSpan("invoke_agent my-agent", (turn) => {
    turn.setAttribute("gen_ai.operation.name", "invoke_agent");
    turn.setAttribute("gen_ai.agent.name", "my-agent");
    turn.setAttribute("gen_ai.conversation.id", CONVERSATION_ID);

    tracer.startActiveSpan("chat gpt-4o", (llm) => {
      llm.setAttribute("gen_ai.operation.name", "chat");
      llm.setAttribute("gen_ai.conversation.id", CONVERSATION_ID);
      llm.setAttribute("gen_ai.request.model", "gpt-4o");
      // 실제 LLM Call로 교체하고 토큰 사용량을 기록하세요.
      llm.setAttribute("gen_ai.usage.input_tokens", 100);
      llm.setAttribute("gen_ai.usage.output_tokens", 20);

      tracer.startActiveSpan("execute_tool get_weather", (tool) => {
        tool.setAttribute("gen_ai.operation.name", "execute_tool");
        tool.setAttribute("gen_ai.conversation.id", CONVERSATION_ID);
        tool.setAttribute("gen_ai.tool.name", "get_weather");
        // 실제 도구 실행으로 교체하세요.
        tool.end();
      });

      llm.end();
    });

    turn.end();
  });

  await provider.shutdown(); // 종료 전에 대기 중인 모든 span을 플러시합니다.
  ```
</CodeGroup>

같은 대화에 턴을 더 추가하려면 동일한 `gen_ai.conversation.id`를 사용해 `invoke_agent` span을 더 emit하세요. 각 턴은 자체 트레이스의 루트 span이므로 턴끼리 부모 span을 공유할 필요가 없습니다.

애플리케이션이 span을 내보낸 후 Weave 프로젝트의 **Agents** 탭을 여세요.
