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

Service API를 사용해 트레이스를 로깅하고 쿼리하기

다음 가이드에서는 Weave Service API를 사용해 트레이스를 로깅하는 방법을 알아봅니다. 구체적으로는 Service API로 다음 작업을 수행합니다.
  1. 단순한 LLM call과 response의 mock을 만들어 Weave에 로깅합니다.
  2. 더 복잡한 LLM call과 response의 mock을 만들어 Weave에 로깅합니다.
  3. 로깅된 트레이스에 대해 샘플 lookup 쿼리를 실행합니다.
로깅된 트레이스 보기 이 가이드의 코드를 실행하면 생성되는 모든 Weave 트레이스는 Weave 프로젝트(team_id\project_id로 지정)의 Traces 탭으로 이동한 다음 트레이스 이름을 선택해 확인할 수 있습니다.
시작하기 전에 사전 요구 사항을 완료하세요.

사전 요구 사항: 변수 및 엔드포인트 설정

다음 코드는 Service API에 액세스하는 데 사용할 URL 엔드포인트를 설정합니다. 또한 다음 변수를 설정해야 합니다.
  • project_id: 트레이스를 로깅할 W&B 프로젝트의 이름입니다.
  • team_id: W&B 팀 이름입니다.
  • wandb_token: W&B API 키입니다.
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 call인 payload_start를 생성하고 url_start 엔드포인트를 사용해 Weave에 로깅합니다. payload_start 객체는 쿼리 Why is the sky blue?로 OpenAI의 gpt-4o를 호출하는 call을 모사합니다. 성공하면 이 코드는 트레이스가 시작되었음을 알리는 메시지를 출력합니다:
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()

단순한 트레이스 종료

단순한 트레이스를 완료하려면, 다음 코드는 샘플 LLM call payload_end를 생성한 뒤 url_end 엔드포인트를 사용해 이를 Weave에 로깅합니다. payload_end 객체는 쿼리 Why is the sky blue?에 대한 OpenAI’s gpt-4o의 응답을 모방합니다. 이 객체는 Weave 대시보드의 트레이스 뷰에서 가격 요약 정보와 chat completion이 생성되도록 형식이 맞춰져 있습니다. 성공하면 이 코드는 트레이스가 완료되었음을 알리는 메시지를 출력합니다:
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 조회와 유사하게, 하위 span이 있는 더 복잡한 트레이스를 만드는 방법을 안내합니다.
  1. 복잡한 트레이스 시작하기
  2. RAG 문서 조회용 하위 span 추가
  3. LLM completion call용 하위 span 추가
  4. 복잡한 트레이스 종료하기

복잡한 트레이스 시작

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

# 부모 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"부모 call이 시작되었습니다. ID: {parent_call_id}, Trace ID: {trace_id}")
else:
    print("부모 시작 요청이 실패했습니다. 상태 코드:", response.status_code)
    print(response.text)
    exit()

RAG 문서 조회용 하위 span 추가

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

# 자식 call: 시작
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"자식 call이 시작되었습니다. ID: {child_call_id}")
else:
    print("자식 시작 요청이 실패했습니다. 상태 코드:", response.status_code)
    print(response.text)
    exit()

# 자식 call: 종료
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("자식 call이 종료되었습니다.")
else:
    print("자식 종료 요청이 실패했습니다. 상태 코드:", response.status_code)
    print(response.text)

LLM completion call에 대한 하위 span 추가

다음 코드는 복합 부모 트레이스에 또 다른 하위 span을 추가해 LLM completion call을 나타내는 방법을 보여줍니다. 이 step은 이전 RAG 오퍼레이션에서 조회한 문서 컨텍스트를 기반으로 AI의 응답 생성 과정을 모델링합니다. LLM completion 트레이스는 payload_child_start 객체로 시작되며, 여기에는 다음이 포함됩니다:
  • trace_id: 이 하위 span을 부모 트레이스에 연결합니다.
  • parent_id: 이 하위 span을 상위 워크플로에 연결합니다.
  • inputs: 사용자 쿼리와 추가된 문서 컨텍스트를 포함한 LLM 입력 메시지를 log합니다.
  • model: 오퍼레이션에 사용된 모델(gpt-4o)을 지정합니다.
성공하면 코드는 LLM 하위 span 트레이스가 시작되고 종료되었음을 나타내는 메시지를 출력합니다:
Child call started. ID: 0245acdf-83a9-4c90-90df-dcb2b89f234a
오퍼레이션이 완료되면 payload_child_end 객체가 output 필드에 LLM이 생성한 응답을 로깅하면서 트레이스를 종료합니다. 사용 요약 정보도 함께 로깅됩니다. 성공하면 코드는 LLM child span 트레이스가 시작되고 종료되었음을 알리는 메시지를 출력합니다:
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": "다음 문서 컨텍스트를 바탕으로 질문에 답해 주시겠어요?\n 이 문서의 핵심 내용을 요약해 주세요.\n [+ 추가된 문서 컨텍스트]",
                }
            ],
            "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 시작됨. ID: {child_call_id}")
else:
    print("Child 시작 요청 실패. 상태 코드:", 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": "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 종료됨.")
else:
    print("Child 종료 요청 실패. 상태 코드:", response.status_code)
    print(response.text)

복잡한 트레이스 종료

다음 코드는 상위 트레이스를 최종 완료하여 전체 워크플로가 끝났음을 표시하는 방법을 보여줍니다. 이 step에서는 모든 하위 span(예: RAG 조회 및 LLM 응답 생성)의 결과를 집계하고 최종 출력과 메타데이터를 로깅합니다. 트레이스는 payload_parent_end 객체로 완료되며, 여기에는 다음이 포함됩니다.
  • id: 최초 상위 트레이스 시작 시의 parent_call_id
  • output: 전체 워크플로의 최종 출력을 나타냅니다.
  • summary: 전체 워크플로의 사용 데이터를 통합합니다.
  • prompt_tokens: 모든 프롬프트에 사용된 총 토큰 수입니다.
  • completion_tokens: 모든 응답에서 생성된 총 토큰 수입니다.
  • total_tokens: 워크플로 전체의 총 토큰 수입니다.
  • requests: 수행된 총 요청 수입니다(이 경우 1).
성공하면 코드에서 다음을 출력합니다.
Parent call ended.
python
## ------------
## 트레이스 종료
## ------------

# 상위 call: 종료
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": "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)

조회 쿼리 실행

다음 코드는 앞선 예제에서 생성한 트레이스를 조회하는 방법을 보여주며, inputs.model 필드가 gpt-4o인 트레이스만 필터링합니다. query_payload 객체에는 다음이 포함됩니다:
  • project_id: 조회할 팀과 프로젝트를 식별합니다.
  • filter: 쿼리가 트레이스 루트(최상위 트레이스)만 반환하도록 합니다.
  • query: $expr Operator를 사용해 필터 로직을 정의합니다.
    • $getField: inputs.model 필드를 조회합니다.
    • $literal: inputs.model"gpt-4o"인 트레이스와 일치시킵니다.
  • limit: 쿼리 결과를 10,000개로 제한합니다.
  • offset: 첫 번째 결과부터 쿼리를 시작합니다.
  • sort_by: started_at 타임스탬프를 기준으로 결과를 내림차순 정렬합니다.
  • include_feedback: 결과에서 피드백 데이터를 제외합니다.
쿼리가 성공하면 응답에는 쿼리 매개변수와 일치하는 트레이스 데이터가 포함됩니다:
{'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("쿼리 성공!")
    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"쿼리 실패, 상태 코드: {response.status_code}")
    print(response.text)