메인 콘텐츠로 건너뛰기
이 노트북은 대화형 노트북입니다. 로컬에서 실행하거나 아래 링크를 사용하세요:

Service API를 사용하여 트레이스를 로깅하고 조회하기

이 가이드에서는 Weave Service API를 사용하여 트레이스를 로깅하는 방법을 설명합니다. 특히 Service API를 사용하여 다음 작업을 수행합니다:
  1. 간단한 LLM 호출 및 응답을 모의로 생성(mock)하고 Weave에 로깅합니다.
  2. 더 복잡한 LLM 호출 및 응답을 모의로 생성하고 Weave에 로깅합니다.
  3. 로깅된 트레이스에 대해 예시 조회 쿼리를 실행합니다.
로깅된 트레이스 보기 이 가이드의 코드를 실행할 때 생성되는 모든 Weave 트레이스는 Weave 프로젝트(team_id\project_id로 지정)에 있는 Traces 탭으로 이동한 후, 트레이스 이름을 선택하여 확인할 수 있습니다.
시작하기 전에 사전 준비 사항을 완료하십시오.

사전 준비: 변수와 엔드포인트 설정

다음 코드는 Service API에 액세스하는 데 사용할 URL 엔드포인트를 설정합니다: 또한 다음 변수를 설정해야 합니다:
  • project_id: 트레이스를 기록할 W&B 프로젝트 이름입니다.
  • team_id: 사용자의 W&B 팀 이름입니다.
  • wandb_token: 사용자의 W&B API key입니다.
import datetime
import json

import requests

# 헤더 및 URL
headers = {"Content-Type": "application/json"}
url_start = "https://trace.wandb.ai/call/start"
url_end = "https://trace.wandb.ai/call/end"
url_stream_query = "https://trace.wandb.ai/calls/stream_query"

# W&B 변수
team_id = ""
project_id = ""
wandb_token = ""

간단한 트레이스

다음 섹션에서는 간단한 트레이스를 생성하는 방법을 단계별로 설명합니다.
  1. 간단한 트레이스 시작하기
  2. 간단한 트레이스 종료하기

간단한 트레이스 시작하기

다음 코드는 예시 LLM 호출인 payload_start를 생성하고 url_start 엔드포인트를 사용해 Weave에 기록합니다. payload_start 객체는 OpenAI의 gpt-4oWhy is the sky blue?라는 질의를 보내는 호출을 모방합니다. 성공하면 이 코드는 트레이스가 시작되었음을 나타내는 메시지를 출력합니다:
Call started. ID: 01939cdc-38d2-7d61-940d-dcca0a56c575, Trace ID: 01939cdc-38d2-7d61-940d-dcd0e76c5f34
python
## ------------
## 트레이스 시작
## ------------
payload_start = {
    "start": {
        "project_id": f"{team_id}/{project_id}",
        "op_name": "simple_trace",
        "started_at": datetime.datetime.now().isoformat(),
        "inputs": {
            # 확장된 트레이스에서 채팅 UI를 생성하려면 이 "messages" 스타일을 사용하세요.
            "messages": [{"role": "user", "content": "Why is the sky blue?"}],
            "model": "gpt-4o",
        },
        "attributes": {},
    }
}
response = requests.post(
    url_start, headers=headers, json=payload_start, auth=("api", wandb_token)
)
if response.status_code == 200:
    data = response.json()
    call_id = data.get("id")
    trace_id = data.get("trace_id")
    print(f"Call started. ID: {call_id}, Trace ID: {trace_id}")
else:
    print("Start request failed with status:", response.status_code)
    print(response.text)
    exit()

간단한 trace 종료하기

간단한 trace를 완료하려면, 다음 코드는 예시 LLM 호출인 payload_end를 생성하고 url_end 엔드포인트를 사용해 Weave에 로깅합니다. payload_end 객체는 Why is the sky blue?라는 쿼리에 대해 OpenAI의 gpt-4o가 반환하는 응답을 모방합니다. 이 객체는 가격 요약 정보와 chat completion이 Weave Dashboard의 trace 뷰에 생성되도록 구성되어 있습니다. 성공하면, 이 코드는 trace가 완료되었음을 나타내는 메시지를 출력합니다:
Call ended.
python
## ------------
## End trace
## ------------
payload_end = {
    "end": {
        "project_id": f"{team_id}/{project_id}",
        "id": call_id,
        "ended_at": datetime.datetime.now().isoformat(),
        "output": {
            # 확장된 트레이스의 채팅 UI에 완성 내용을 추가하려면 이 "choices" 스타일을 사용하세요.
            "choices": [
                {
                    "message": {
                        "content": "It’s due to Rayleigh scattering, where shorter blue wavelengths of sunlight scatter in all directions."
                    }
                },
            ]
        },
        # 트레이스 테이블에서 가격 요약 정보를 생성하려면 다음과 같이 summary를 포맷하세요.
        "summary": {
            "usage": {
                "gpt-4o": {
                    "prompt_tokens": 10,
                    "completion_tokens": 20,
                    "total_tokens": 30,
                    "requests": 1,
                }
            }
        },
    }
}
response = requests.post(
    url_end, headers=headers, json=payload_end, auth=("api", wandb_token)
)
if response.status_code == 200:
    print("Call ended.")
else:
    print("End request failed with status:", response.status_code)
    print(response.text)

복잡한 트레이스

다음 섹션에서는 여러 단계의 RAG 조회와 유사하게, 자식 스팬이 포함된 보다 복잡한 트레이스를 생성하는 방법을 단계별로 안내합니다.
  1. 복잡한 트레이스 시작하기
  2. RAG 문서 조회를 위한 자식 스팬 추가하기
  3. LLM completion 호출을 위한 자식 스팬 추가하기
  4. 복잡한 트레이스 종료하기

복잡한 트레이스 시작하기

아래 코드는 여러 개의 span으로 구성된 더 복잡한 트레이스를 생성하는 방법을 보여줍니다. 예시로는 Retrieval-Augmented Generation (RAG) 문서 조회 후 이어지는 LLM 호출이 있습니다. 첫 번째 단계에서는 전체 작업을 나타내는 상위 트레이스(payload_parent_start)를 초기화합니다. 여기에서 작업은 사용자 질의 Can you summarize the key points of this document?를 처리하는 것입니다. payload_parent_start 객체는 여러 단계로 이루어진 워크플로의 첫 단계를 나타내며, url_start 엔드포인트를 사용해 Weave에 해당 작업을 로깅합니다. 성공하면, 이 코드는 상위 호출이 로깅되었음을 나타내는 메시지를 출력합니다:
Parent call started. ID: 01939d26-0844-7c43-94bb-cdc471b6d65f, Trace ID: 01939d26-0844-7c43-94bb-cdd97dc296c8
python
## ------------
## 트레이스 시작 (parent)
## ------------

# Parent call: 시작
payload_parent_start = {
    "start": {
        "project_id": f"{team_id}/{project_id}",
        "op_name": "complex_trace",
        "started_at": datetime.datetime.now().isoformat(),
        "inputs": {"question": "Can you summarize the key points of this document?"},
        "attributes": {},
    }
}
response = requests.post(
    url_start, headers=headers, json=payload_parent_start, auth=("api", wandb_token)
)
if response.status_code == 200:
    data = response.json()
    parent_call_id = data.get("id")
    trace_id = data.get("trace_id")
    print(f"부모 호출이 시작되었습니다. ID: {parent_call_id}, Trace ID: {trace_id}")
else:
    print("부모 시작 요청이 실패했습니다. 상태 코드:", response.status_code)
    print(response.text)
    exit()

RAG 문서 조회를 위한 자식 span 추가

다음 코드는 이전 단계에서 시작한 복합 부모 trace에 자식 span을 추가하는 방법을 보여줍니다. 이 단계에서는 전체 워크플로 내에서 RAG 문서 조회 하위 작업을 모델링합니다. 자식 trace는 payload_child_start 객체로 시작되며, 여기에는 다음이 포함됩니다:
  • trace_id: 이 자식 span을 부모 trace에 연결합니다.
  • parent_id: 자식 span을 부모 작업과 연관시킵니다.
  • inputs: 검색 쿼리를 로깅합니다. 예: "This is a search query of the documents I'm looking for."
url_start 엔드포인트 호출에 성공하면 코드는 자식 호출이 시작되고 완료되었음을 나타내는 메시지를 출력합니다:
자식 호출이 시작되었습니다. ID: 01939d32-23d6-75f2-9128-36a4a806f179
자식 호출이 종료되었습니다.
python
## ------------
## 자식 스팬:
## 예시. RAG 문서 조회
## ------------

# 자식 호출: 시작
payload_child_start = {
    "start": {
        "project_id": f"{team_id}/{project_id}",
        "op_name": "rag_document_lookup",
        "trace_id": trace_id,
        "parent_id": parent_call_id,
        "started_at": datetime.datetime.now().isoformat(),
        "inputs": {
            "document_search": "This is a search query of the documents I'm looking for."
        },
        "attributes": {},
    }
}
response = requests.post(
    url_start, headers=headers, json=payload_child_start, auth=("api", wandb_token)
)
if response.status_code == 200:
    data = response.json()
    child_call_id = data.get("id")
    print(f"자식 호출이 시작되었습니다. ID: {child_call_id}")
else:
    print("자식 시작 요청이 실패했습니다. 상태 코드:", response.status_code)
    print(response.text)
    exit()

# 자식 호출: 종료
payload_child_end = {
    "end": {
        "project_id": f"{team_id}/{project_id}",
        "id": child_call_id,
        "ended_at": datetime.datetime.now().isoformat(),
        "output": {
            "document_results": "This will be the RAG'd document text which will be returned from the search query."
        },
        "summary": {},
    }
}
response = requests.post(
    url_end, headers=headers, json=payload_child_end, auth=("api", wandb_token)
)
if response.status_code == 200:
    print("자식 호출이 종료되었습니다.")
else:
    print("자식 종료 요청이 실패했습니다. 상태 코드:", response.status_code)
    print(response.text)

LLM completion 호출에 대한 자식 span 추가

다음 코드는 복잡한 상위 trace에 또 다른 자식 span을 추가하는 방법을 보여주며, 이는 이전 RAG 작업에서 가져온 문서 컨텍스트를 기반으로 한 LLM completion 호출을 나타냅니다. 이 단계는 문서 컨텍스트를 활용한 AI의 응답 생성을 모델링합니다. LLM completion trace는 다음을 포함하는 payload_child_start 객체로 시작합니다:
  • trace_id: 이 자식 span을 상위 trace에 연결합니다.
  • parent_id: 자식 span을 전체 워크플로와 연결합니다.
  • inputs: 사용자 질의와 추가된 문서 컨텍스트를 포함해 LLM에 대한 입력 메시지를 기록합니다.
  • model: 작업에 사용된 모델을 지정합니다 (gpt-4o).
성공하면, 코드는 LLM 자식 span trace가 시작되고 종료되었음을 나타내는 메시지를 출력합니다:
Child call started. ID: 0245acdf-83a9-4c90-90df-dcb2b89f234a
작업이 완료되면 payload_child_end 객체가 output 필드에 LLM이 생성한 응답을 기록하여 트레이스를 종료합니다. 사용량 요약 정보도 함께 기록됩니다. 성공하면 코드는 LLM 자식 스팬 트레이스가 시작되고 종료되었음을 나타내는 메시지를 출력합니다:
Child call started. ID: 0245acdf-83a9-4c90-90df-dcb2b89f234a
Child call ended.
python
## ------------
## Child span:
## LLM completion call 생성
## ------------

# Child call: 시작
payload_child_start = {
    "start": {
        "project_id": f"{team_id}/{project_id}",
        "op_name": "llm_completion",
        "trace_id": trace_id,
        "parent_id": parent_call_id,
        "started_at": datetime.datetime.now().isoformat(),
        "inputs": {
            "messages": [
                {
                    "role": "user",
                    "content": "With the following document context, could you help me answer:\n Can you summarize the key points of this document?\n [+ appended document context]",
                }
            ],
            "model": "gpt-4o",
        },
        "attributes": {},
    }
}
response = requests.post(
    url_start, headers=headers, json=payload_child_start, auth=("api", wandb_token)
)
if response.status_code == 200:
    data = response.json()
    child_call_id = data.get("id")
    print(f"Child call started. ID: {child_call_id}")
else:
    print("Child start request failed with status:", response.status_code)
    print(response.text)
    exit()

# Child call: 종료
payload_child_end = {
    "end": {
        "project_id": f"{team_id}/{project_id}",
        "id": child_call_id,
        "ended_at": datetime.datetime.now().isoformat(),
        "output": {
            "choices": [
                {"message": {"content": "This is the response generated by the LLM."}},
            ]
        },
        "summary": {
            "usage": {
                "gpt-4o": {
                    "prompt_tokens": 10,
                    "completion_tokens": 20,
                    "total_tokens": 30,
                    "requests": 1,
                }
            }
        },
    }
}
response = requests.post(
    url_end, headers=headers, json=payload_child_end, auth=("api", wandb_token)
)
if response.status_code == 200:
    print("Child call ended.")
else:
    print("Child end request failed with status:", response.status_code)
    print(response.text)

복잡한 트레이스 종료

다음 코드는 부모 트레이스를 마무리하여 전체 워크플로우가 완료되었음을 표시하는 방법을 보여줍니다. 이 단계에서는 모든 자식 스팬(예: RAG 조회 및 LLM 응답 생성)의 결과를 집계하고 최종 출력과 메타데이터를 로깅합니다. 트레이스는 다음을 포함하는 payload_parent_end 객체를 사용해 최종 상태로 마무리합니다:
  • id: 초기 부모 트레이스를 시작할 때 사용된 parent_call_id.
  • output: 전체 워크플로우의 최종 출력을 나타냅니다.
  • summary: 전체 워크플로우에 대한 사용량 데이터를 통합합니다.
  • prompt_tokens: 모든 프롬프트에 사용된 토큰의 총합.
  • completion_tokens: 모든 응답에서 생성된 토큰의 총합.
  • total_tokens: 워크플로우 전체의 토큰 총합.
  • requests: 수행된 요청의 총 개수(이 예에서는 1).
성공 시 코드는 다음을 출력합니다:
부모 호출이 종료되었습니다.
python
## ------------
## 트레이스 종료
## ------------

# 부모 호출: 종료
payload_parent_end = {
    "end": {
        "project_id": f"{team_id}/{project_id}",
        "id": parent_call_id,
        "ended_at": datetime.datetime.now().isoformat(),
        "output": {
            "choices": [
                {"message": {"content": "This is the response generated by the LLM."}},
            ]
        },
        "summary": {
            "usage": {
                "gpt-4o": {
                    "prompt_tokens": 10,
                    "completion_tokens": 20,
                    "total_tokens": 30,
                    "requests": 1,
                }
            }
        },
    }
}
response = requests.post(
    url_end, headers=headers, json=payload_parent_end, auth=("api", wandb_token)
)
if response.status_code == 200:
    print("Parent call ended.")
else:
    print("Parent end request failed with status:", response.status_code)
    print(response.text)

조회 쿼리 실행하기

아래 코드는 이전 예제에서 생성한 trace를 조회하는 방법을 보여주며, inputs.model 필드가 gpt-4o와 동일한 trace만 필터링합니다. query_payload 객체에는 다음이 포함됩니다:
  • project_id: 조회할 팀과 프로젝트를 식별합니다.
  • filter: 쿼리가 trace root(최상위 trace)만 반환하도록 보장합니다.
  • query: $expr 연산자를 사용해 필터 로직을 정의합니다:
    • $getField: inputs.model 필드를 조회합니다.
    • $literal: inputs.model"gpt-4o"인 trace와 매칭합니다.
  • limit: 쿼리 결과를 최대 10,000개로 제한합니다.
  • offset: 첫 번째 결과부터 쿼리를 시작합니다.
  • sort_by: 결과를 started_at 타임스탬프 기준으로 내림차순 정렬합니다.
  • include_feedback: 결과에서 피드백 데이터를 제외합니다.
쿼리가 성공하면, 응답에는 쿼리 파라미터와 일치하는 trace 데이터가 포함됩니다.
{'id': '01939cf3-541f-76d3-ade3-50cfae068b39', 'project_id': 'cool-new-team/uncategorized', 'op_name': 'simple_trace', 'display_name': None, 'trace_id': '01939cf3-541f-76d3-ade3-50d5cfabe2db', 'parent_id': None, 'started_at': '2024-12-06T17:10:12.590000Z', 'attributes': {}, 'inputs': {'messages': [{'role': 'user', 'content': 'Why is the sky blue?'}], 'model': 'gpt-4o'}, 'ended_at': '2024-12-06T17:47:08.553000Z', 'exception': None, 'output': {'choices': [{'message': {'content': 'It’s due to Rayleigh scattering, where shorter blue wavelengths of sunlight scatter in all directions.'}}]}, 'summary': {'usage': {'gpt-4o': {'prompt_tokens': 10, 'completion_tokens': 20, 'requests': 1, 'total_tokens': 30}}, 'weave': {'status': 'success', 'trace_name': 'simple_trace', 'latency_ms': 2215963}}, 'wb_user_id': 'VXNlcjoyMDk5Njc0', 'wb_run_id': None, 'deleted_at': None}
python
query_payload = {
    "project_id": f"{team_id}/{project_id}",
    "filter": {"trace_roots_only": True},
    "query": {
        "$expr": {"$eq": [{"$getField": "inputs.model"}, {"$literal": "gpt-4o"}]}
    },
    "limit": 10000,
    "offset": 0,
    "sort_by": [{"field": "started_at", "direction": "desc"}],
    "include_feedback": False,
}
response = requests.post(
    url_stream_query, headers=headers, json=query_payload, auth=("api", wandb_token)
)
if response.status_code == 200:
    print("Query successful!")
    try:
        data = response.json()
        print(data)
    except json.JSONDecodeError as e:
        # 대체 디코딩
        json_objects = response.text.strip().split("\n")
        parsed_data = [json.loads(obj) for obj in json_objects]
        print(parsed_data)
else:
    print(f"Query failed with status code: {response.status_code}")
    print(response.text)