Skip to main content
CoreWeave Forge SDK로 멀티턴 에이전트형 애플리케이션을 계측하여 에이전트의 동작을 확인하고, 디버그하고, 평가하는 방법을 알아보세요. 이 가이드는 에이전트를 구축하거나 통합하는 개발자 중 대화, 턴, LLM Call, 도구 실행을 구조적으로 파악하려는 분을 대상으로 합니다. Agent Lens SDK는 멀티턴 에이전트 대화의 전체 라이프사이클을 모델링합니다. 여기에는 여러 대화를 소유하는 에이전트, 턴을 묶는 대화, 사용자와 에이전트 간의 각 주고받기(턴), 턴 내의 LLM Call, 그리고 LLM이 트리거하는 도구 실행이 포함됩니다. 트레이스는 CoreWeave Agent Lens 프로젝트의 Conversations 탭에 표시됩니다. 각 대화는 중첩된 도구 Call, 토큰 사용량, 피드백을 포함한 멀티턴 타임라인으로 표시됩니다. Agent Lens는 분산 트레이싱을 위한 개방형 표준인 OpenTelemetry (OTel)를 기반으로 구축되었습니다. 모든 턴, LLM Call, 도구 Call은 OTel span(하나의 오퍼레이션에 대한 구조화된 기록)을 생성합니다. 각 span에는 gen_ai.agent.name, gen_ai.conversation.id 같은 GenAI semantic-convention 속성이 태그로 지정됩니다.

시작하기 전에

먼저 Agent Lens SDK를 설치하고 프로젝트를 초기화하세요. 이 단계에서 entity와 프로젝트가 Agent Lens에 등록되므로 SDK가 span을 UI의 올바른 위치로 보낼 수 있습니다. SDK는 WANDB_API_KEY 환경 변수에서 API 키를 읽어 옵니다.
[YOUR-TEAM]은 Forge entity 이름으로, [YOUR-PROJECT]는 프로젝트 이름으로 바꾸세요. entity는 필수 항목입니다.
start_conversation(), start_turn(), start_llm(), start_tool(), start_subagent()를 호출하기 전에 먼저 tracing.init()을 호출하세요. init()이 실행되기 전이나 shutdown() 이후에는 트레이싱 함수가 아무 동작도 하지 않고 조용히 넘어갑니다. 따라서 계측 코드를 프로덕션 코드에 그대로 둔 채 설정으로 제어할 수 있습니다. 프로세스가 종료될 때 tracing.shutdown()을 호출하여 버퍼에 남아 있는 span을 플러시하세요. 이 함수는 atexit에도 등록되어 있습니다.

에이전트 데이터 모델

Agent Lens는 에이전트 동작을 일대다 관계의 계층 구조로 모델링합니다. 각 에이전트는 여러 대화를, 각 대화는 여러 턴을, 각 턴은 여러 LLM Call을 가질 수 있으며, 각 LLM Call은 여러 도구 Call을 트리거할 수 있습니다. 다음 다이어그램은 하나의 에이전트가 여러 대화로, 하나의 대화가 여러 턴으로 이어지는 계층 구조를 보여줍니다. 대화는 부모 span이 아니라 공유 conversation_id 속성을 기준으로 턴을 그룹화하므로, 각 턴은 자체 OTel 트레이스를 시작합니다. 이러한 설계 덕분에 분산 트레이싱과 병렬 실행이 가능합니다. 클라이언트는 서버 측 집계 없이 span을 OTel collector로 직접 전송합니다.
Claude Agent SDK나 Codex 같은 에이전트 SDK 또는 하니스와 Agent Lens를 통합하려면 에이전트 인테그레이션 선택을 참조하세요. 이러한 인테그레이션은 SDK 또는 하니스 세션을 기반으로 conversation_id를 설정하므로, 턴을 그룹화하기 위해 start_conversation()을 호출할 필요가 없습니다. 반면 LLM 공급자 SDK 인테그레이션(OpenAI, Anthropic, Google Gen AI)은 대화를 생성하지 않으며, Agent Lens는 대화 안에서 실행된 Call만 표시합니다. 따라서 이 페이지의 API를 사용해 해당 Call을 감싸는 대화와 턴을 열어야 합니다.

에이전트 트레이싱 API

다음 섹션에서는 각 최상위 트레이싱 함수와 각 함수가 받는 인수를 설명합니다. 이 함수들을 사용하여 이전 섹션에서 설명한 데이터 모델의 대화, 턴, LLM Call, 도구 Call 계층을 계측하세요. Agent Lens는 다음과 같은 최상위 함수를 제공합니다. 각 함수가 반환하는 객체는 컨텍스트 관리자로 사용할 수 있으며(Python에서는 with, TypeScript에서는 try/finally 사용), .end()를 호출하여 수동으로 닫을 수도 있습니다.

대화 시작하기

start_conversation()(Python) 또는 startConversation()(TypeScript)은 모든 하위 span에 conversation_id 속성을 지정하여 턴이 Conversations 탭에서 그룹화되도록 합니다. conversation_id / conversationId를 전달하는 경우, 이 값은 대화가 유지되는 동안 변경되지 않아야 합니다. 기존 대화에 새 턴을 추가하려면 같은 ID를 재사용하세요. 이 값을 생략하면 SDK가 UUID를 자동으로 생성합니다. 활성 대화는 컨텍스트(Python ContextVar 또는 Node.js AsyncLocalStorage)에 저장됩니다. 따라서 동일한 비동기 컨텍스트에서 실행되는 코드라면 대화 객체를 명시적으로 전달하지 않아도 tracing.get_current_conversation() / tracing.getCurrentConversation()으로 활성 대화를 가져올 수 있습니다.

턴 시작하기

start_turn()(Python)과 startTurn()(TypeScript)은 새 OTel 트레이스의 루트가 되는 새 invoke_agent span을 생성합니다. Agent Lens는 이 span을 사용해 타임라인 뷰에서 사용자와 에이전트 간의 주고받기 한 번을 온전하게 나타냅니다.
두 가지 방식으로 호출할 수 있습니다.
  • 최상위 함수로 호출 (tracing.start_turn(...) / tracing.startTurn(...)): 아래 예시에서 사용하는 방식입니다. 컨텍스트에서 활성 대화를 찾아 해당 대화 ID를 상속합니다. 활성 대화가 없으면 턴이 conversation_id 없이 생성되며 다른 턴과 그룹화되지 않습니다.
  • 인스턴스 메서드로 호출: 참조를 가지고 있는 대화 객체에서 호출합니다(conversation.start_turn(...) / conversation.startTurn(...) ). 컨텍스트 관리자 블록 내부처럼 범위 내에 명시적인 대화 객체가 있을 때 유용합니다. 이 가이드 뒷부분의 “컨텍스트 관리자 또는 try-finally 패턴” 예시가 이 방식을 사용합니다. 두 SDK의 Conversation, Turn, LLM, Tool, SubAgent 레퍼런스 페이지로 바로 가는 링크는 앞서 소개한 데이터 모델 table을 참조하세요.

LLM Call 시작하기

start_llm() / startLLM()은 현재 턴 아래에 중첩된 chat span을 생성합니다. Agent Lens는 이 span을 사용해 UI에 토큰 사용량, 모델 이름, 입력 및 출력 메시지, 추론을 표시합니다.
LLM Call이 완료되면 llm 객체가 닫히기 전에 응답 데이터를 이 객체에 할당하세요.
provider_name / providerName은 명시적으로 전달하세요. Agent Lens는 모델 문자열에서 공급자를 추론하지 않습니다.

도구 Call 시작하기

start_tool() / startTool()은 execute_tool span을 생성합니다. 이 span은 컨텍스트에서 현재 활성 상태인 OTel span(일반적으로 해당 도구 Call을 생성한 LLM Call의 chat span)의 하위 span이 됩니다.
span을 종료하기 전에 도구 결과를 할당하세요.

에이전트 트레이싱 사용 패턴

다음 섹션에서는 에이전트 코드의 구조에 따라 이러한 함수를 조합하는 방법을 설명합니다. 다음 예시에서는 Agent Lens SDK의 두 가지 유형을 사용합니다.
  • Message (Python · TypeScript)는 대화의 단일 항목을 나타내며, 사용자 입력, assistant 응답, system 프롬프트, 도구 결과가 이에 해당합니다. 모델이 받은 내용을 기록하려면 메시지 목록을 llm.input_messages / llm.inputMessages에 부여하고, 모델이 생성한 내용을 기록하려면 llm.output_messages / llm.outputMessages에 부여하세요.
  • Usage (Python · TypeScript)는 LLM 응답의 토큰 수를 캡처하며, llm.usage에 부여됩니다.
Agent Lens는 이 두 유형을 사용하여 각 LLM Call의 입력, 출력, 토큰 사용량을 UI에 표시합니다.

컨텍스트 관리자 또는 try-finally 패턴

대부분의 에이전트에서는 Python의 컨텍스트 관리자 패턴이나 TypeScript의 try-finally 패턴을 사용하세요. 예외가 발생하더라도 블록이 끝나면 span이 닫히고 전송됩니다. Agent Lens는 활성 대화, 턴, LLM Call을 컨텍스트에 저장합니다. 따라서 블록 안에서 호출되는 함수는 부모에 대한 명시적인 참조 없이도 start_llm() / startLLM() 또는 start_tool() / startTool()을 호출할 수 있습니다. 코드가 동일한 비동기 컨텍스트에서 실행되기만 하면 모듈 경계를 넘어서도 동작합니다. 호출 스택의 어느 위치에서든 활성 객체를 가져오려면 tracing.get_current_conversation() / tracing.getCurrentConversation(), tracing.get_current_turn() / tracing.getCurrentTurn(), tracing.get_current_llm() / tracing.getCurrentLLM()을 사용하세요.

수동 시작 및 종료 패턴

with 블록이나 try/finally를 사용할 수 없는 경우에는 .end()를 명시적으로 호출하세요. 예를 들어 서로 다른 함수 호출에서 span을 열고 닫거나, 코루틴 외부에서 비동기 라이프사이클을 관리하는 경우가 여기에 해당합니다. span이 제대로 닫히고 collector로 플러시되려면 생성한 모든 객체에 대해 직접 .end()를 호출해야 합니다. TypeScript에서는 턴이나 대화를 종료하면 아직 열려 있는 하위 항목도 모두 함께 닫힙니다.

시맨틱 규칙

Agent Lens SDK는 GenAI 시맨틱 규칙 및 GenAI 에이전트 span 규칙을 준수하는 OTel span을 내보냅니다. Agent Lens는 어떤 OTel span이든 수신하여 모든 속성을 저장하고, 이를 쿼리할 수 있게 합니다. 모든 Agent Lens 트레이싱 객체에서 set_attributes() / setAttributes()를 사용하면 span에 임의의 속성을 추가할 수 있습니다. 자세한 내용은 에이전트 span에 속성 설정하기를 참조하세요. SDK는 자체 비공개 OpenTelemetry 트레이서 프로바이더를 사용합니다. 이 프로바이더는 Agent Lens를 통해 생성된 span만 내보내며, 애플리케이션의 전역 프로바이더를 대체하거나 관련 없는 계측에서 생성된 span을 내보내지 않습니다.

Agent Lens UI에서 데이터가 표시되는 방식

앞서 설명한 패턴으로 에이전트를 계측하고 실행하면 https://에 있는 Agent Lens 프로젝트의 Conversations 탭에 트레이스가 표시됩니다.
  • Conversations 탭에는 모든 대화가 턴 활동 미니맵과 함께 표시됩니다.
  • Conversation 상세 뷰는 대화를 클릭하면 열리며, 해당 대화의 모든 턴과 LLM Call, 도구 실행, 토큰 수, 연결된 피드백을 보여 줍니다.
Agent Lens에서 캡처된 데이터를 확인하는 방법은 에이전트 활동 보기를 참조하세요.
마지막 수정일 2026년 9월 30일