Agent Observability 설정
Agent Observability를 아직 설정하지 않은 경우 다음을 수행합니다.
Agent Observability Python SDK를 설치합니다.
pip install ddtrace>=4.3.0
Agent Observability를 활성화합니다.
from ddtrace.llmobs import LLMObs
LLMObs.enable(
api_key="<YOUR_API_KEY>", # defaults to DD_API_KEY environment variable
app_key="<YOUR_APP_KEY>", # defaults to DD_APP_KEY environment variable
site="datadoghq.com", # defaults to DD_SITE environment variable
project_name="<YOUR_PROJECT>" # defaults to DD_LLMOBS_PROJECT_NAME environment variable, or "default-project" if the environment variable is not set
)
api_key 및 app_key값을 모두 제공해야 합니다.
APM 트레이스 연계
실험 스팬을 APM 트레이스와 연계하려면 Datadog Agent를 통해 Agent Observability를 실행하고 agentless_enabled를 False(기본값)로 유지하세요. Agent는 트레이스 데이터를 APM으로 전달하며, 이를 통해 실험과 APM 트레이스를 연계할 수 있습니다.
LLMObs.enable(
api_key="<YOUR_API_KEY>",
app_key="<YOUR_APP_KEY>",
site="datadoghq.com",
agentless_enabled=False, # default — required for APM Trace correlation
project_name="<YOUR_PROJECT>",
)
Agent 없이 실행하는 경우(예: 노트북 또는 CI 환경) agentless_enabled=True를 설정할 수 있지만, Agent 없이 실행한 실험 스팬에 대해서는 해당 APM 스팬이 생성되지 않습니다.
프로젝트 생성
_프로젝트_는 LLM 실험의 핵심 구성 단위입니다. 모든 데이터 세트와 실험은 프로젝트에 포함됩니다.
LLMObs.enable에 아직 존재하지 않는 프로젝트 이름을 지정하여 Datadog 콘솔, API 또는 SDK에서 수동으로 프로젝트를 생성할 수 있습니다.
LLMObs.enable(
...
project_name="<YOUR_PROJECT>" # defaults to DD_LLMOBS_PROJECT_NAME environment variable, or "default-project" if the environment variable is not set
)
데이터 세트 생성
_데이터 세트_는 Agent를 테스트하기 위한 시나리오를 구성하는 입력, 예상 출력 및 _메타데이터_의 모음입니다. 각 데이터 세트는 _프로젝트_와 연결됩니다.
- input(필수): Agent가 작업에서 액세스할 수 있는 모든 정보를 나타냅니다.
- expected output(필요시): _정답_이라고도 하며, Agent가 출력해야 하는 이상적인 답변을 나타냅니다. _expected output_을 사용하여 앱의 실제 출력과 평가하려는 중간 결과를 저장할 수 있습니다.
- metadata(필요시): 레코드를 분류하고 추가 분석에 사용할 수 있는 유용한 정보가 포함됩니다. 예시: 주제, 태그, 설명, 메모
CSV 파일로 데이터세트를 생성하려면 LLMObs.create_dataset_from_csv()를 사용하세요.
# Create dataset from CSV
dataset = LLMObs.create_dataset_from_csv(
csv_path="questions.csv",
dataset_name="capitals-of-the-world",
project_name="capitals-project", # Optional: defaults to the project name from LLMObs.enable
description="Geography quiz dataset", # Optional: Dataset description
input_data_columns=["question", "category"], # Columns to use as input
expected_output_columns=["answer"], # Optional: Columns to use as expected output
metadata_columns=["difficulty"], # Optional: Additional columns as metadata
csv_delimiter="," # Optional: Defaults to comma
)
# Example "questions.csv":
# question,category,answer,difficulty
# What is the capital of Japan?,geography,Tokyo,medium
# What is the capital of Brazil?,geography,Brasília,medium
데이터 세트를 수동으로 생성하는 방법, 데이터 세트를 검색 및 관리하는 방법, Datadog이 데이터 세트 버전을 유지하는 방법 등 데이터 세트에 대한 자세한 내용은 데이터 세트을 참조하세요.
실험 생성
_실험_을 사용하면 데이터 세트의 시나리오를 대상으로 Agent를 실행하고 평가자를 사용하여 예상 출력 대비 성능을 측정함으로써 LLM 애플리케이션을 체계적으로 테스트할 수 있습니다. 그런 다음 서로 다른 앱 구성의 성능을 나란히 비교할 수 있습니다.
task: 평가하려는 핵심 워크플로를 정의합니다. 단일 LLM 호출부터 여러 LLM 호출 및 RAG 단계를 포함하는 보다 복잡한 흐름까지 다양할 수 있습니다. 작업은 데이터 세트의 모든 레코드에 대해 순차적으로 실행됩니다.
evaluator: 각 레코드에서 실행되어 모델 또는 Agent의 성능을 측정하는 함수입니다. 평가자를 사용하면 출력을 예상 출력 또는 원래 입력과 비교할 수 있습니다.
summary evaluators: 실험의 모든 데이터(입력, 출력, 예상 출력, 평가자 결과)에 대해 실행되는 선택적 함수입니다. 요약 평가자를 사용하면 데이터 세트 전반에서 정밀도, 재현율 및 정확도와 같은 고급 메트릭을 계산할 수 있습니다.
실험을 생성하려면 다음 단계를 따르세요.
1. 데이터 세트를 로드합니다.
from ddtrace.llmobs import LLMObs
from typing import Dict, Any, Optional, List
dataset = LLMObs.pull_dataset("capitals-of-the-world")
2. 단일 데이터 세트 레코드를 처리하는 작업 함수를 정의합니다.
def task(input_data: Dict[str, Any], config: Optional[Dict[str, Any]] = None) -> str:
question = input_data["question"]
# Your LLM or processing logic here
return "Beijing" if "China" in question else "Unknown"
작업은 input_data로 null이 아닌 모든 데이터 유형(문자열, 숫자, 부울, 객체, 배열)을 사용할 수 있습니다. 평가자에서 사용하는 출력은 데이터 유형에 제한이 없습니다.
이 예시에서는 문자열을 생성하지만, 중간 처리 정보를 저장하고 평가자에서 비교할 수 있도록 출력으로 dict을 생성할 수도 있습니다.
필요시, 작업 함수에 데이터 세트 레코드의 메타데이터를 수신하기 위한 세 번째 metadata 파라미터를 추가할 수 있습니다.
def task(input_data: Dict[str, Any], config: Optional[Dict[str, Any]] = None, metadata: Optional[Dict[str, Any]] = None) -> str:
difficulty = metadata.get("difficulty", "unknown") if metadata else "unknown"
question = input_data["question"]
return "Beijing" if "China" in question else "Unknown"
프로덕션에서 사용하는 동일한 트레이싱 데코레이터를 사용하여 실험 작업의 다양한 부분(워크플로, 도구 호출 등)을 추적할 수 있습니다.
지원되는 프레임워크(OpenAI, Amazon Bedrock 등)를 사용하는 경우, Agent Observability가 LLM 프레임워크 및 라이브러리에 대한 호출을 자동으로 추적하고 관련 정보를 추가하여 LLM 애플리케이션에서 발생하는 호출을 기본적으로 관찰할 수 있습니다.
실험에서 OpenTelemetry 스팬 사용
애플리케이션에서 OpenTelemetry 계측을 사용하는 경우, 실험 작업 내에서 OTel 스팬을 생성할 수 있습니다. DD_TRACE_OTEL_ENABLED=1를 사용하면 ddtrace가 OpenTelemetry TracerProvider로 작동하므로, OTel 스팬이 자동으로 실험 스팬의 하위 스팬으로 표시됩니다.
import json
from opentelemetry import trace
tracer = trace.get_tracer(__name__)
def task(input_data: Dict[str, Any], config: Optional[Dict[str, Any]] = None) -> str:
question = input_data["question"]
# OTel gen_ai span — automatically becomes a child of the experiment span
with tracer.start_as_current_span("my-llm-call") as span:
span.set_attribute("gen_ai.operation.name", "chat")
span.set_attribute("gen_ai.system", "openai")
span.set_attribute("gen_ai.request.model", "gpt-4o")
span.set_attribute("gen_ai.usage.input_tokens", 25)
span.set_attribute("gen_ai.usage.output_tokens", 8)
span.set_attribute(
"gen_ai.input.messages",
json.dumps([{"role": "user", "parts": [{"type": "text", "content": question}]}]),
)
result = call_my_llm(question)
span.set_attribute(
"gen_ai.output.messages",
json.dumps([{"role": "assistant", "parts": [{"type": "text", "content": result}]}]),
)
return result
이를 활성화하려면 DD_TRACE_OTEL_ENABLED 환경 변수를 설정하세요.
DD_TRACE_OTEL_ENABLED=1 python my_experiment.py
3. 평가자를 정의합니다.
평가자는 모델이나 Agent가 각 레코드에서 얼마나 잘 수행되는지 측정합니다. 두 가지 방법으로 평가자를 정의할 수 있습니다.
- 함수 기반:
input_data, output_data 및 expected_output을 별도의 인수로 받는 함수를 정의합니다. 간단한 로직을 사용하는 일회성 평가자에 가장 적합합니다. - 클래스 기반:
BaseEvaluator를 상속하여 사용자 지정 구성이 가능한 재사용 가능한 평가자로 사용합니다. 클래스 기반 평가자는 전체 스팬 컨텍스트가 포함된 EvaluatorContext 객체를 받습니다.
전체 데이터 모델 참조 및 모범 사례를 포함하여 평가자 구축에 대한 자세한 내용은 평가 개발자 가이드를 참조하세요.
Datadog은 다음과 같은 평가자 반환 유형을 지원합니다.
- 불리언: true 또는 false를 반환합니다.
- 점수: 숫자 값(float)을 반환합니다.
- 범주형: 레이블이 지정된 범주(string)를 반환합니다.
- json: 구조화된 데이터(dict)를 반환합니다.
다음과 같이 반환할 수도 있습니다.
EvaluatorResult를 사용하여 reasoning, assessment("pass" 또는 "fail"), metadata 및 tags와 같은 더 풍부한 평가 데이터를 수집합니다.MultiEvaluatorResult를 사용하여 하나의 평가자 호출에서 이름이 지정된 여러 메트릭을 반환합니다. 자세한 내용과 예시는 평가 개발자 가이드를 참조하세요.
함수 기반 평가자
def exact_match(input_data: Dict[str, Any], output_data: str, expected_output: str) -> bool:
return output_data == expected_output
def overlap(input_data: Dict[str, Any], output_data: str, expected_output: str) -> float:
expected_output_set = set(expected_output)
output_set = set(output_data)
intersection = len(output_set.intersection(expected_output_set))
union = len(output_set.union(expected_output_set))
return intersection / union
def fake_llm_as_a_judge(input_data: Dict[str, Any], output_data: str, expected_output: str) -> EvaluatorResult:
fake_llm_call = "excellent"
return EvaluatorResult(
value=fake_llm_call,
reasoning="the model explains itself",
assessment="pass", # or fail
tags={"task": "judge_llm_call"},
)
# Return multiple metrics from one evaluator call
from ddtrace.llmobs import MultiEvaluatorResult
def multi_metric_evaluator(input_data, output_data, expected_output):
correct = output_data == expected_output
return MultiEvaluatorResult(
{
"correct": EvaluatorResult(value=correct, assessment="pass" if correct else "fail"),
"length": len(str(output_data)),
}
)
# Emitted as: multi_metric_evaluator-correct, multi_metric_evaluator-length
클래스 기반 평가자
from ddtrace.llmobs import BaseEvaluator, EvaluatorContext, EvaluatorResult
class SemanticSimilarityEvaluator(BaseEvaluator):
def __init__(self, threshold: float = 0.8):
super().__init__(name="semantic_similarity")
self.threshold = threshold
def evaluate(self, context: EvaluatorContext) -> EvaluatorResult:
score = compute_similarity(context.output_data, context.expected_output)
return EvaluatorResult(
value=score,
reasoning=f"Similarity score: {score:.2f}",
assessment="pass" if score >= self.threshold else "fail",
)
4. (필요시) 요약 평가자를 정의합니다.
요약 평가자는 모든 레코드 수준 평가자가 완료된 후 실행되며, 집계된 결과를 받아 평균 또는 통과율과 같은 데이터 세트 수준의 통계를 계산합니다. 레코드 수준 평가자와 마찬가지로 요약 평가자는 함수 또는 클래스로 정의할 수 있습니다.
BaseSummaryEvaluator를 사용하는 클래스 기반 접근 방식에 대한 자세한 내용은 평가 개발자 가이드를 참조하세요.
함수 기반 요약 평가자
def num_exact_matches(inputs, outputs, expected_outputs, evaluators_results):
return evaluators_results["exact_match"].count(True)
요약 평가자 함수는 inputs로 null이 아닌 모든 데이터 유형(문자열, 숫자, 부울, 객체, 배열)의 목록을 받을 수 있으며, outputs와 expected_outputs는 모든 유형을 포함하는 목록일 수 있습니다. evaluators_results는 평가자 함수의 이름을 키로 하는 평가자 결과 목록을 담은 사전입니다. 예를 들어, 위 코드 조각에서 요약 평가자 num_exact_matches는 exact_match 평가자의 결과(부울 목록)를 사용하여 정확히 일치하는 항목의 개수를 제공합니다.
클래스 기반 요약 평가자
from ddtrace.llmobs import BaseSummaryEvaluator, SummaryEvaluatorContext
class AverageScoreEvaluator(BaseSummaryEvaluator):
def __init__(self, target_evaluator: str):
super().__init__(name="average_score")
self.target_evaluator = target_evaluator
def evaluate(self, context: SummaryEvaluatorContext):
scores = context.evaluation_results.get(self.target_evaluator, [])
if not scores:
return None
return sum(scores) / len(scores)
Datadog은 다음과 같은 요약 평가자 반환 유형을 지원합니다.
- 불리언: true 또는 false를 반환합니다.
- 점수: 숫자 값(float)을 반환합니다.
- 범주형: 레이블이 지정된 범주(string)를 반환합니다.
- json: 구조화된 데이터(dict)를 반환합니다.
5. 실험을 생성 및 실행합니다.
experiment = LLMObs.experiment(
name="capital-cities-test",
task=task,
dataset=dataset,
evaluators=[exact_match, overlap, fake_llm_as_a_judge],
summary_evaluators=[num_exact_matches], # optional
description="Testing capital cities knowledge",
config={
"model_name": "gpt-4",
"version": "1.0"
},
)
# Run the experiment
results = experiment.run() # Run on all dataset records
# Process results
for result in results.get("rows", []):
print(f"Record {result['idx']}")
print(f"Input: {result['input']}")
print(f"Output: {result['output']}")
print(f"Score: {result['evaluations']['evaluator']['value']}")
if result['error']['message']:
print(f"Error: {result['error']['message']}")
실험의 실행 속도를 높이려면 병렬 처리를 활성화할 수 있습니다.
results = experiment.run(jobs=4)
데이터의 특정 부분에서 파이프라인을 테스트하려면 다음을 사용하세요.
results = experiment.run(sample_size=10)
오류 발생 시 실험 실행을 중지하려면 다음을 사용하세요.
results = experiment.run(raise_errors=True)
6. Datadog에서 실험 결과를 검토합니다.
print(f"View experiment: {experiment.url}")
Agent Observability 설정
Agent Observability를 아직 설정하지 않은 경우 다음을 수행합니다.
Agent Observability Node.js SDK를 설치합니다.
API 키, 애플리케이션 키 및 Datadog 사이트를 설정합니다.
export DD_API_KEY="<YOUR_API_KEY>"
export DD_APP_KEY="<YOUR_APP_KEY>"
export DD_SITE=<span class="js-region-param region-param" data-region-param="dd_site"></span>
Initialize the tracer with the ML application and Experiments project names:
const tracer = require('dd-trace').init({
llmobs: {
mlApp: 'capitals-app',
projectName: 'capitals-project'
}
})
두 항목을 모두 제공해야 합니다. DD_API_KEY 및 DD_APP_KEY값을 모두 제공해야 합니다.
프로젝트 생성
프로젝트에는 데이터 세트와 실험이 포함됩니다. SDK는 구성된 실험 프로젝트 이름을 사용하며
프로젝트가 존재하지 않으면 생성합니다.
트레이서 초기화 중에 llmobs.projectName을 설정합니다. DD_LLMOBS_PROJECT_NAME도 설정할 수 있습니다. 두 값 모두 설정되지 않은 경우,
SDK는 default-project를 사용합니다.
데이터 세트 생성
tracer.llmobs.experiments API를 사용하여 데이터 세트를 생성합니다.
const { experiments } = tracer.llmobs
const dataset = experiments.createDataset('capitals-of-the-world', {
description: 'Questions and expected capital cities',
records: [
{
inputData: { question: 'What is the capital of China?' },
expectedOutput: 'Beijing',
metadata: { difficulty: 'medium' }
},
{
inputData: { question: 'What is the capital of Japan?' },
expectedOutput: 'Tokyo',
metadata: { difficulty: 'medium' }
}
]
})
실험이 시작되면 SDK가 데이터 세트를 푸시합니다. 기존 데이터 세트를 사용하려면 다음을 호출하세요.
await experiments.pullDataset('<DATASET_NAME>').
실험 생성
실험은 각 데이터 세트 레코드에 대해 태스크를 실행하고 각 결과를 평가합니다.
1. 태스크 정의
태스크는 레코드 입력을 수신합니다. 또한 실험 구성 및 선택 사항인 레코드 메타데이터를 수신할 수 있습니다.
function task (inputData) {
const { question } = inputData
// Add the LLM or agent call to evaluate.
return question.includes('China') ? 'Beijing' : 'Tokyo'
}
태스크 내에서 지원되는 Node.js 통합을 호출하면
실험 스팬의 하위 스팬으로 트레이싱됩니다.
2. 평가자 정의
평가자는 레코드 입력, 태스크 출력 및 예상 출력을 수신합니다. 불리언, 숫자, 문자열 또는 JSON을 반환하여
해당 평가 메트릭을 생성합니다.
function exactMatch (_inputData, outputData, expectedOutput) {
return outputData === expectedOutput
}
3. 실험 생성 및 실행
async function runExperiment () {
const experiment = experiments.experiment({
name: 'capital-cities-test',
dataset,
task,
evaluators: {
exact_match: exactMatch
},
description: 'Testing capital cities knowledge',
config: {
modelName: 'gpt-4',
version: '1.0'
}
})
const result = await experiment.run()
console.log(`View experiment: ${result.url}`)
}
runExperiment().catch((error) => {
console.error(error)
process.exitCode = 1
})
결과에는 각 레코드 출력, 평가자 점수, 오류 및 Datadog의 실험 URL이 포함됩니다.