> ## Documentation Index
> Fetch the complete documentation index at: https://wb-21fd5541-sdk-testing-latest.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# 퀵스타트: 에이전트 트레이스하기

> Weave SDK로 멀티턴 에이전트를 트레이스하세요. Session, 턴, LLM Call, 도구 Call이 프로젝트의 Agents 뷰에 표시됩니다.

<Note>
  Weave for Agents는 공개 프리뷰 상태입니다. 정식 출시 전에 특성, API 및 Agents 뷰 UI가 변경될 수 있습니다.
</Note>

[Colab에서 사용해 보기](https://colab.research.google.com/github/wandb/docs/blob/main/weave/cookbooks/source/agents-quickstart.ipynb) · [GitHub 원본](https://github.com/wandb/docs/blob/main/weave/cookbooks/source/agents-quickstart.ipynb)

Weave SDK를 사용하면 널리 사용되는 SDK나 맞춤형 하니스로 구축한 에이전트를 트레이스할 수 있습니다. 이 퀵스타트에서는 OpenTelemetry span을 생성하고 캡처할 수 있도록, 맞춤형 멀티턴 에이전트에 Weave를 수동으로 통합하는 방법을 보여줍니다. 에이전트용 Weave의 개념을 이해하려면 [에이전트 트레이싱](/ko/weave/guides/tracking/trace-agents)을 참조하세요.

Claude Agent SDK나 Codex와 같은 SDK 또는 하니스에 Weave를 통합하려는 경우 [에이전트 인테그레이션 트레이싱](/ko/weave/guides/tracking/trace-agent-integrations)을 참조하세요. Weave는 빠르게 통합할 수 있도록 여러 에이전트 구축 SDK와 에이전트 하니스에 자동으로 패치됩니다.

<div id="what-youll-learn">
  ## 학습할 내용
</div>

이 퀵스타트를 마치면 Weave와 호환되는 OTel spans를 생성하는 멀티턴 에이전트를 실제로 구현하게 됩니다. 또한 Weave가 Session, 턴, LLM Call, 도구 Call을 에이전트 코드에 어떻게 매핑하는지 이해하게 되므로, 같은 패턴을 여러분의 맞춤형 에이전트에도 적용할 수 있습니다.

이 가이드의 코드는 Wikipedia에서 정보를 찾아볼 수 있는 간단한 리서치 에이전트를 설정합니다. 이 에이전트는 세 가지 질문(세 번의 턴)을 하고, 답을 찾기 위해 언제 Wikipedia를 검색할지 LLM이 선택합니다. Weave는 모든 단계(대화, 각 질문, 각 AI 응답, 각 Wikipedia 조회)를 기록하므로 Weave Agents 뷰에서 실제로 어떤 일이 일어났는지 확인할 수 있습니다.

이 가이드에서는 다음 방법을 설명합니다.

* `weave.init()`로 에이전트 트레이싱을 위해 Weave를 초기화합니다.
* `start_session` / `startSession` 및 `start_turn` / `startTurn`으로 Session과 턴을 시작합니다.
* `start_llm` / `startLLM`으로 LLM Call을 래핑하고 사용량을 기록합니다.
* `start_tool` / `startTool`로 도구 실행을 래핑하고 결과를 기록합니다.
* 결과로 생성된 Session, 턴, 도구 Call을 Agents 뷰에서 확인합니다.

<div id="how-the-weave-sdk-works-with-agents">
  ## Weave SDK가 에이전트와 함께 작동하는 방식
</div>

Weave SDK에는 에이전트를 위한 범용 OTel 수집 시스템이 포함되어 있습니다. 즉, Weave는 에이전트 코드의 모든 OTel span에서 정보를 캡처할 수 있습니다. 하지만 에이전트의 트레이스를 Weave UI의 Agents 뷰에 표시하려면, Weave가 다음 span을 별도로 처리해야 합니다.

| 개념                   | Python                     | TypeScript                | OTel span         |
| -------------------- | -------------------------- | ------------------------- | ----------------- |
| 하나의 대화               | `weave.start_session(...)` | `weave.startSession(...)` | (span 없음, 턴을 그룹화) |
| 사용자/에이전트 간 한 번의 상호작용 | `weave.start_turn(...)`    | `weave.startTurn(...)`    | `invoke_agent`    |
| 한 번의 LLM API 호출      | `weave.start_llm(...)`     | `weave.startLLM(...)`     | `chat`            |
| 한 번의 도구 실행           | `weave.start_tool(...)`    | `weave.startTool(...)`    | `execute_tool`    |

Python에서는 네 함수 모두 컨텍스트 관리자(`with weave.start_*(...) as obj:`)로 동작합니다. 블록을 벗어날 때 예외 발생 여부와 관계없이 span을 종료하고 속성을 플러시합니다. TypeScript에서는 반환된 각 객체에 대해 `.end()`를 호출하세요. 예외가 발생해도 정리되도록 `try { ... } finally { obj.end(); }`를 사용하세요.

`gen_ai.usage.*` 및 `gen_ai.agent.name`과 같은 다른 [GenAI semantic-convention attributes](https://opentelemetry.io/docs/specs/semconv/gen-ai/gen-ai-agent-spans/)를 지정하면 추가 정보가 표시되지만, 이는 선택 사항입니다.

<div id="prerequisites">
  ## 사전 요구 사항
</div>

* W\&B 계정 및 [API 키](https://wandb.ai/authorize).
* OpenAI API 키.
* Python 3.10+ (Python 예시 실행용).
* Node.js 18+ (TypeScript 예시 실행용, 내장 `fetch`가 필요합니다).

<div id="install-packages">
  ## 패키지 설치
</div>

다음 패키지를 개발 환경에 설치하세요:

<CodeGroup>
  ```bash Python theme={null}
  pip install weave openai requests
  ```

  ```bash TypeScript theme={null}
  npm install weave openai
  ```
</CodeGroup>

<div id="initialize-weave">
  ## Weave 초기화
</div>

`weave.init()`는 W\&B에 인증하고 에이전트 span을 **Agents** 뷰로 전송하는 OTel 익스포터를 구성합니다. 팀에 프로젝트가 아직 없으면 Weave가 처음 데이터를 기록할 때 해당 프로젝트를 생성합니다.

<CodeGroup>
  ```python lines Python theme={null}
  import getpass
  import os

  os.environ["WANDB_API_KEY"] = getpass.getpass("Enter your W&B API key: ")
  os.environ["OPENAI_API_KEY"] = getpass.getpass("Enter your OpenAI API key: ")

  TEAM = input("Enter your W&B team name: ")
  PROJECT = input("Enter your W&B project name: ")

  import weave
  weave.init(f"{TEAM}/{PROJECT}")
  ```

  ```typescript lines highlight="4" TypeScript twoslash theme={null}
  // @noErrors
  // 이 프로젝트를 실행하기 전에 환경에서 WANDB_API_KEY, OPENAI_API_KEY를 설정하세요
  import * as weave from 'weave';

  await weave.init(`[YOUR-TEAM]/[YOUR-PROJECT]`);
  ```
</CodeGroup>

<div id="define-a-tool">
  ## 도구 정의하기
</div>

다음 코드는 에이전트의 Wikipedia 검색 도구와 함께, 도구를 언제 어떻게 사용할지 지정하는 OpenAI 도구 스키마를 정의합니다.

<CodeGroup>
  ```python lines Python theme={null}
  import json
  import requests

  def wikipedia_search(query: str) -> str:
      r = requests.get(
          "https://en.wikipedia.org/w/api.php",
          params={
              "action": "query", "generator": "search", "gsrsearch": query, "gsrlimit": 1,
              "prop": "extracts", "exintro": True, "explaintext": True, "format": "json",
          },
          headers={"User-Agent": "weave-demo"},
      ).json()
      return next(iter(r["query"]["pages"].values()))["extract"]

  wikipedia_tool_schema = {
      "type": "function",
      "function": {
          "name": "wikipedia_search",
          "description": "Search Wikipedia for a topic and return its intro paragraph.",
          "parameters": {
              "type": "object",
              "properties": {"query": {"type": "string"}},
              "required": ["query"],
          },
      },
  }
  ```

  ```typescript lines TypeScript twoslash theme={null}
  // @noErrors
  async function wikipediaSearch(query: string): Promise<string> {
    const url = new URL('https://en.wikipedia.org/w/api.php');
    url.search = new URLSearchParams({
      action: 'query',
      generator: 'search',
      gsrsearch: query,
      gsrlimit: '1',
      prop: 'extracts',
      exintro: 'true',
      explaintext: 'true',
      format: 'json',
    }).toString();
    const res = await fetch(url, { headers: { 'User-Agent': 'weave-demo' } });
    const data = (await res.json()) as {
      query: { pages: Record<string, { extract: string }> };
    };
    return Object.values(data.query.pages)[0].extract;
  }

  const wikipediaToolSchema = {
    type: 'function' as const,
    function: {
      name: 'wikipedia_search',
      description: 'Search Wikipedia for a topic and return its intro paragraph.',
      parameters: {
        type: 'object',
        properties: { query: { type: 'string' } },
        required: ['query'],
      },
    },
  };
  ```
</CodeGroup>

<div id="run-a-traced-multi-turn-agent">
  ## 트레이스된 멀티턴 에이전트 실행
</div>

도구와 Weave 초기화가 준비되면, 다음 단계는 이를 완전한 에이전트 루프로 결합하는 것입니다. 이 루프는 Session, 턴, LLM Call, 도구 Call이 서로 어떻게 중첩되는지 보여줍니다.

다음 예시는 하나의 Session에서 세 개의 턴을 실행합니다. 각 턴은 다음과 같습니다.

1. `chat` span을 열고 LLM이 도구를 Call할지 선택하도록 합니다.
2. LLM이 도구를 요청하면, 해당 Call을 감싸는 `execute_tool` span을 열고 결과를 다시 LLM에 전달합니다.
3. 최종 응답을 생성하기 위해 두 번째 `chat` span을 엽니다.

<CodeGroup>
  ```python lines highlight="9,11,17,29,42,46,53" Python theme={null}
  from openai import OpenAI

  openai_client = OpenAI()
  MODEL = "gpt-4o-mini"

  def run_turn(history, user_message):
      history.append({"role": "user", "content": user_message})

      with weave.start_turn(user_message=user_message, model=MODEL):
          # LLM call 1: 모델이 도구 사용 여부를 결정할 수 있습니다.
          with weave.start_llm(model=MODEL, provider_name="openai") as llm:
              resp = openai_client.chat.completions.create(
                  model=MODEL, messages=history, tools=[wikipedia_tool_schema],
              )
              msg = resp.choices[0].message
              llm.output(msg.content or "")
              llm.usage = weave.Usage(
                  input_tokens=resp.usage.prompt_tokens,
                  output_tokens=resp.usage.completion_tokens,
              )
              history.append(msg.model_dump(exclude_none=True))

          # 도구가 요청되지 않은 경우, 첫 번째 LLM 응답이 최종 답변입니다.
          if not msg.tool_calls:
              return msg.content

          # 요청된 각 도구 Call을 실행합니다.
          for tc in msg.tool_calls:
              with weave.start_tool(
                  name=tc.function.name,
                  arguments=tc.function.arguments,
                  tool_call_id=tc.id,
              ) as tool:
                  tool.result = wikipedia_search(**json.loads(tc.function.arguments))
                  history.append({
                      "role": "tool",
                      "tool_call_id": tc.id,
                      "content": tool.result,
                  })

          # LLM call 2: 최종 답변을 생성합니다.
          with weave.start_llm(model=MODEL, provider_name="openai") as llm:
              resp = openai_client.chat.completions.create(model=MODEL, messages=history)
              msg = resp.choices[0].message
              llm.output(msg.content)
              llm.usage = weave.Usage(
                  input_tokens=resp.usage.prompt_tokens,
                  output_tokens=resp.usage.completion_tokens,
              )
              history.append({"role": "assistant", "content": msg.content})
              return msg.content

  with weave.start_session(agent_name="research-bot") as session:
      history = []
      for question in [
          "Who founded Anthropic?",
          "What is Claude (the AI assistant)?",
          "Summarize what we discussed in one sentence.",
      ]:
          print(f"USER: {question}")
          print(f"AGENT: {run_turn(history, question)}\n")
  ```

  ```typescript lines highlight="10,13,39,54,76" TypeScript twoslash theme={null}
  // @noErrors
  import OpenAI from 'openai';

  const openaiClient = new OpenAI();
  const MODEL = 'gpt-4o-mini';

  // history is a list of OpenAI chat messages; typed loosely for brevity.
  async function runTurn(history: any[], userMessage: string): Promise<string | null> {
    history.push({ role: 'user', content: userMessage });

    const turn = weave.startTurn({ userMessage, model: MODEL });
    try {
      // LLM call 1 — 모델이 도구 사용 여부를 결정할 수 있습니다.
      const llm1 = weave.startLLM({ model: MODEL, providerName: 'openai' });
      let msg;
      try {
        const resp = await openaiClient.chat.completions.create({
          model: MODEL,
          messages: history,
          tools: [wikipediaToolSchema],
        });
        msg = resp.choices[0].message;
        llm1.output(msg.content ?? '');
        llm1.usage = {
          inputTokens: resp.usage?.prompt_tokens,
          outputTokens: resp.usage?.completion_tokens,
        };
        history.push(msg);
      } finally {
        llm1.end();
      }

      // 도구가 요청되지 않은 경우, 첫 번째 LLM 응답이 최종 답변입니다.
      if (!msg.tool_calls?.length) {
        return msg.content ?? null;
      }

      // 요청된 각 도구 Call을 실행합니다.
      for (const tc of msg.tool_calls) {
        const tool = weave.startTool({
          name: tc.function.name,
          args: tc.function.arguments,
          toolCallId: tc.id,
        });
        try {
          const { query } = JSON.parse(tc.function.arguments);
          tool.result = await wikipediaSearch(query);
          history.push({ role: 'tool', tool_call_id: tc.id, content: tool.result });
        } finally {
          tool.end();
        }
      }

      // LLM call 2 — 최종 답변을 종합합니다.
      const llm2 = weave.startLLM({ model: MODEL, providerName: 'openai' });
      try {
        const resp = await openaiClient.chat.completions.create({
          model: MODEL,
          messages: history,
        });
        const msg2 = resp.choices[0].message;
        llm2.output(msg2.content ?? '');
        llm2.usage = {
          inputTokens: resp.usage?.prompt_tokens,
          outputTokens: resp.usage?.completion_tokens,
        };
        history.push({ role: 'assistant', content: msg2.content });
        return msg2.content ?? null;
      } finally {
        llm2.end();
      }
    } finally {
      turn.end();
    }
  }

  const session = weave.startSession({ agentName: 'research-bot' });
  try {
    const history: any[] = [];
    for (const question of [
      'Who founded Anthropic?',
      'What is Claude (the AI assistant)?',
      'Summarize what we discussed in one sentence.',
    ]) {
      console.log(`USER: ${question}`);
      console.log(`AGENT: ${await runTurn(history, question)}\n`);
    }
  } finally {
    session.end();
  }
  ```
</CodeGroup>

<div id="see-your-agent-traces-in-the-agents-view">
  ## Agents 뷰에서 에이전트 트레이스를 확인하세요
</div>

`weave.init()`가 실행되면 프로젝트 링크가 출력되며, 여기에서 다음을 확인할 수 있습니다.

* **Agents** 탭에 `research-bot`용 행 1개.
* 세 개의 턴이 포함된 Session 1개.
* 각 턴(`invoke_agent`)에는 두 개의 `chat` span과 그 안에 중첩된 `execute_tool` span이 포함됨.
* 각 `chat`의 token 수, 지연 시간, 모델, 전체 메시지 교환 내용.

아무 턴이나 클릭하면 입력, 출력, 도구 인수, 도구 결과를 자세히 살펴볼 수 있습니다.

<div id="next-steps">
  ## 다음 단계
</div>

* [Weave로 에이전트를 트레이스하는 방법](/ko/weave/guides/tracking/trace-agents)과 Weave SDK에서 사용 가능한 특성과 옵션을 알아보세요.
* 에이전트에 Weave를 통합하는 더 많은 옵션은 [에이전트 인테그레이션 트레이싱](/ko/weave/guides/tracking/trace-agent-integrations)을 참조하세요.
