수동 계측
수동 계측
어떤 OpenTelemetry SDK의 스팬이든 Confident AI로 내보내고, confident.* 속성을 직접 손으로 설정하고 싶을 때가 있어요. 수동 계측(manual instrumentation)은 confident-trace의 트레이싱 헬퍼를 거치지 않고, 원시 OpenTelemetry SDK로 스팬을 직접 만들어 Confident AI의 OTLP 엔드포인트로 내보내는 방식입니다.
출처: 문서
본문
개요
confident-trace는 OpenTelemetry 위에 만들어져 있어요. init()를 호출하면 Confident AI exporter가 이미 설정되고, 자동 통합과 트레이싱 헬퍼에서 나온 스팬은 기본적으로 OpenTelemetry 스팬으로 내보내집니다.
이 페이지는 OpenTelemetry SDK로 애플리케이션을 수동 계측할 때를 위한 것이에요. 예를 들면, 사용하는 언어가 confident-trace를 지원하지 않거나, 애플리케이션이 이미 자체 텔레메트리 파이프라인을 갖고 있거나, span·트레이스-컨텍스트 헬퍼보다 원시 OpenTelemetry tracer를 선호하는 경우죠. 같은 트레이스 안에서 수동 OpenTelemetry 스팬과 confident-trace 스팬을 섞어 쓸 수도 있어요.
지원되는 통합을 쓰고 있다면,
confident-trace부터 시작하세요. exporter를 설정하거나 원시 OpenTelemetry 속성을 손으로 넣을 필요가 없어요. Confident AI가gen_ai.*,confident.*, OpenInference, OpenLLMetry 속성을 어떻게 해석하는지는 OpenTelemetry 개요를 참고하세요.
Confident AI는 https://otel.confident-ai.com에서 OTLP 트레이스를 받아요. 원시 OpenTelemetry SDK로 트레이스를 내보내려면 아래 단계를 따라 OTLP exporter를 설정하세요.
설정에 신호별(signal-specific) 환경 변수가 필요하다면, 트레이스 엔드포인트를
https://otel.confident-ai.com/v1/traces로 설정하세요.
빠른 시작
아래 빠른 시작은 직접 만든 스팬을 Confident AI OTLP 엔드포인트로 내보내고, Observatory에서 확인할 수 있게 해 줍니다.
환경 변수 설정
먼저 CONFIDENT_API_KEY와 OTEL_EXPORTER_OTLP_ENDPOINT를 환경 변수로 설정합니다.
export CONFIDENT_API_KEY="confident_us..."
export OTEL_EXPORTER_OTLP_ENDPOINT="https://otel.confident-ai.com"
위 엔드포인트는 US 리전입니다. 데이터가 EU에 있다면
https://eu.otel.confident-ai.com으로, 자체 호스팅 중이라면 자신의otel.호스트로 설정하세요. 그렇지 않으면 트레이스가 다른 배포로 나가서 인증에 실패해요.
첫 LLM 애플리케이션 추적하기
Python
opentelemetry 의존성을 설치합니다.
pip install opentelemetry-api opentelemetry-sdk opentelemetry-exporter-otlp-proto-http
다음 코드를 실행합니다.
import json
import os
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
OTLP_ENDPOINT = os.getenv("OTEL_EXPORTER_OTLP_ENDPOINT")
CONFIDENT_API_KEY = os.getenv("CONFIDENT_API_KEY")
trace_provider = TracerProvider()
exporter = OTLPSpanExporter(
endpoint=f"{OTLP_ENDPOINT}/v1/traces",
headers={"x-confident-api-key": CONFIDENT_API_KEY},
)
span_processor = BatchSpanProcessor(span_exporter=exporter)
trace_provider.add_span_processor(span_processor)
tracer = trace_provider.get_tracer("application_tracer")
# Start a span
with tracer.start_as_current_span("confident-llm-span") as span:
# Set attributes
span.set_attribute("confident.trace.name", "example-trace")
span.set_attribute("confident.span.type", "llm")
span.set_attribute("gen_ai.request.model", "gpt-4o")
span.set_attribute("confident.span.input", json.dumps("What is the capital of France?"))
span.set_attribute("confident.span.output", json.dumps("Paris"))
trace_provider.force_flush()
print("Traces posted successfully to https://otel.confident-ai.com")
코드를 실행합니다.
python main.py
위 예제는 새로운 OpenTelemetry 트레이스 프로바이더를 만들고
OTLPSpanExporter를 설정해서, 스팬이 Confident AI OTLP 엔드포인트로만 내보내지게 합니다. 기존 OpenTelemetry 트레이스 프로바이더에OTLPSpanExporter를 설정하고 싶다면 아래 예제를 참고하세요.from opentelemetry import trace from opentelemetry.sdk.trace import TracerProvider from opentelemetry.sdk.trace.export import BatchSpanProcessor from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter OTLP_ENDPOINT = os.getenv("OTEL_EXPORTER_OTLP_ENDPOINT") CONFIDENT_API_KEY = os.getenv("CONFIDENT_API_KEY") # Setup OpenTelemetry if not isinstance(trace.get_tracer_provider(), TracerProvider): tracer_provider = TracerProvider() trace.set_tracer_provider(tracer_provider) else: tracer_provider = trace.get_tracer_provider() exporter = OTLPSpanExporter( endpoint=f"{OTLP_ENDPOINT}/v1/traces", headers={"x-confident-api-key": CONFIDENT_API_KEY}, ) span_processor = BatchSpanProcessor(span_exporter=exporter) tracer_provider.add_span_processor(span_processor) tracer = trace.get_tracer("application_tracer")
TypeScript
Node.js 의존성을 설치합니다.
npm init -y
npm install @opentelemetry/api @opentelemetry/sdk-trace-node @opentelemetry/sdk-trace-base @opentelemetry/exporter-trace-otlp-proto dotenv
TypeScript와 ts-node를 설치합니다.
npm install -D typescript ts-node @types/node
index.ts 파일을 만듭니다. 이 파일에는 LLM 스팬을 만드는 코드가 들어 있어요.
import * as opentelemetry from '@opentelemetry/api';
import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node';
import { BatchSpanProcessor } from '@opentelemetry/sdk-trace-base';
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-proto';
// Environment variables (similar to Python's os.getenv)
const OTLP_ENDPOINT = process.env.OTEL_EXPORTER_OTLP_ENDPOINT;
const CONFIDENT_API_KEY = process.env.CONFIDENT_API_KEY;
// Add validation for required environment variables
if (!OTLP_ENDPOINT) {
throw new Error('OTEL_EXPORTER_OTLP_ENDPOINT environment variable is required');
}
// Create OTLP exporter with HTTPS support
const otlpExporter = new OTLPTraceExporter({
url: `${OTLP_ENDPOINT}/v1/traces`,
headers: {
'x-confident-api-key': CONFIDENT_API_KEY || ''
},
});
// Set up the tracer provider with the batch span processor
const provider = new NodeTracerProvider({
spanProcessors: [new BatchSpanProcessor(otlpExporter)]
});
// Register the provider globally
opentelemetry.trace.setGlobalTracerProvider(provider);
// Create a tracer
const tracer = opentelemetry.trace.getTracer('confident-llm-tracer');
async function main() {
// Start a span
tracer.startActiveSpan('confident-llm-span-typescript', (span) => {
// Set attributes
span.setAttributes({
'confident.trace.name': 'example-trace',
'confident.span.type': 'llm',
'gen_ai.request.model': 'gpt-4o',
'confident.span.input': JSON.stringify('What is the capital of France?'),
'confident.span.output': JSON.stringify('Paris')
});
// Simulate some work here
console.log('Processing LLM request...');
// End the span
span.end();
});
// Shut down the provider to ensure traces are flushed before the script exits
await provider.shutdown();
console.log(`Trace posted successfully to ${OTLP_ENDPOINT}.`);
}
main().catch((error) => {
console.error('Error sending traces:', error);
process.exit(1);
});
기본 tsconfig.json 파일을 만듭니다.
{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"outDir": "./dist"
}
}
코드를 실행합니다.
npx ts-node index.ts
Go
Go(1.19 이상 권장)를 설치합니다.
환경 변수를 설정합니다.
export OTEL_EXPORTER_OTLP_ENDPOINT="https://otel.confident-ai.com"
export CONFIDENT_API_KEY="<your-confident-api-key>"
Go 모듈을 초기화합니다.
go mod init go-example
main.go 파일을 만듭니다.
package main
import (
"context"
"fmt"
"log"
"os"
"strconv"
"strings"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp"
"go.opentelemetry.io/otel/propagation"
sdktrace "go.opentelemetry.io/otel/sdk/trace"
)
func main() {
endpoint := strings.TrimRight(os.Getenv("OTEL_EXPORTER_OTLP_ENDPOINT"), "/") + "/v1/traces"
confidentApiKey := os.Getenv("CONFIDENT_API_KEY")
exporter, err := otlptracehttp.New(context.Background(),
otlptracehttp.WithEndpointURL(endpoint),
otlptracehttp.WithHeaders(map[string]string{"x-confident-api-key": confidentApiKey}),
)
if err != nil {
log.Fatalf("failed to create OTLP exporter: %v", err)
}
tp := sdktrace.NewTracerProvider(sdktrace.WithBatcher(exporter))
otel.SetTracerProvider(tp)
otel.SetTextMapPropagator(propagation.TraceContext{})
defer func() {
fmt.Println("Shutting down tracer provider...")
_ = tp.Shutdown(context.Background())
}()
_, span := otel.Tracer("example.com/otel-openai").Start(context.Background(), "chat gpt-4o")
defer func() {
span.End()
fmt.Println("Span ended - Trace posted successfully to:", endpoint)
}()
span.SetAttributes(
attribute.String("confident.span.type", "llm"),
attribute.String("gen_ai.request.model", "gpt-4o"),
attribute.String("confident.span.input", strconv.Quote("input")),
attribute.String("confident.span.output", strconv.Quote("output")),
)
}
의존성을 설치합니다.
go mod tidy
코드를 실행합니다.
go run main.go
Ruby
Gemfile 파일을 만듭니다. 이 파일에는 Ruby 애플리케이션의 의존성이 들어 있어요.
source 'https://rubygems.org'
gem 'opentelemetry-sdk'
gem 'opentelemetry-exporter-otlp'
의존성을 설치합니다.
bundle install
example.rb 파일을 만듭니다. 이 파일에는 LLM 스팬을 만드는 코드가 들어 있어요.
require 'json'
require 'opentelemetry/sdk'
require 'opentelemetry/exporter/otlp'
# Ensure OTLP endpoint and API key are set
OTLP_ENDPOINT = ENV.fetch('OTEL_EXPORTER_OTLP_ENDPOINT') { abort 'Set OTEL_EXPORTER_OTLP_ENDPOINT' }
CONFIDENT_API_KEY = ENV.fetch('CONFIDENT_API_KEY') { abort 'Set CONFIDENT_API_KEY' }
OpenTelemetry::SDK.configure do |c|
c.add_span_processor(
OpenTelemetry::SDK::Trace::Export::BatchSpanProcessor.new(
OpenTelemetry::Exporter::OTLP::Exporter.new(
endpoint: "#{OTLP_ENDPOINT}/v1/traces",
headers: { 'x-confident-api-key' => CONFIDENT_API_KEY },
)
)
)
end
tracer = OpenTelemetry.tracer_provider.tracer(__FILE__)
tracer.in_span('confident-llm-span-ruby') do |span|
span.set_attribute('confident.trace.name', 'example-trace')
span.set_attribute('confident.span.type', 'llm')
span.set_attribute('gen_ai.request.model', 'gpt-4o')
span.set_attribute('confident.span.input', 'What is the capital of France?'.to_json)
span.set_attribute('confident.span.output', 'Paris'.to_json)
puts 'Span created successfully!'
end
# Flush and allow time for HTTP export
OpenTelemetry.tracer_provider.shutdown
puts "Traces posted successfully to #{OTLP_ENDPOINT}."
sleep 2
코드를 실행합니다.
ruby example.rb
C#
새 콘솔 앱을 만듭니다.
dotnet new console -n ConfidentLLMExample
cd ConfidentLLMExample
필요한 NuGet 패키지를 추가합니다.
dotnet add package OpenTelemetry
dotnet add package OpenTelemetry.Exporter.OpenTelemetryProtocol
Program.cs 파일을 만듭니다. 이 파일에는 LLM 스팬을 만드는 코드가 들어 있어요.
using System;
using OpenTelemetry;
using OpenTelemetry.Trace;
using OpenTelemetry.Resources;
using OpenTelemetry.Exporter;
using System.Text.Json;
using System.Threading.Tasks;
class Program
{
static async Task Main(string[] args)
{
var otlpEndpoint = Environment.GetEnvironmentVariable("OTEL_EXPORTER_OTLP_ENDPOINT");
var confidentApiKey = Environment.GetEnvironmentVariable("CONFIDENT_API_KEY");
Console.WriteLine($"OTLP Endpoint: {otlpEndpoint}");
Console.WriteLine($"API Key configured: {!string.IsNullOrEmpty(confidentApiKey)}");
using var tracerProvider = Sdk.CreateTracerProviderBuilder()
.SetResourceBuilder(ResourceBuilder.CreateDefault()
.AddService("ConfidentLLMService"))
.AddSource("ConfidentLLMTracer")
.AddOtlpExporter(options =>
{
options.Endpoint = new Uri($"{otlpEndpoint}/v1/traces");
options.Headers = $"x-confident-api-key={confidentApiKey}";
options.Protocol = OtlpExportProtocol.HttpProtobuf;
// Add timeout and retry configuration
options.TimeoutMilliseconds = 30000;
})
.Build();
var tracer = tracerProvider.GetTracer("ConfidentLLMTracer");
Console.WriteLine("Starting span...");
using (var currentSpan = tracer.StartActiveSpan("confident-llm-span-csharp"))
{
currentSpan.SetAttribute("confident.trace.name", "example-trace");
currentSpan.SetAttribute("confident.span.type", "llm");
currentSpan.SetAttribute("gen_ai.request.model", "gpt-4o");
currentSpan.SetAttribute("confident.span.input", JsonSerializer.Serialize("What is the capital of France?"));
currentSpan.SetAttribute("confident.span.output", JsonSerializer.Serialize("Paris"));
Console.WriteLine("Span created with attributes. It will end after 5 seconds.");
await Task.Delay(5000);
}
Console.WriteLine("Span ended. Flushing traces...");
// Force flush traces before exiting
tracerProvider.ForceFlush();
// Wait a bit to ensure traces are sent
await Task.Delay(2000);
Console.WriteLine($"Trace posted successfully to {otlpEndpoint}.");
}
}
빌드하고 실행합니다.
dotnet run
🎉 축하합니다! 트레이스를 성공적으로 보냈어요. Confident AI에서 Observatory를 열어 확인해 보세요.
confident-trace를 사용하는 네이티브 Python 구현 보기
애플리케이션 언어가 confident-trace를 지원한다면, 위처럼 exporter를 손으로 만들 필요가 없어요. confident-trace는 내부적으로 OpenTelemetry이며 Confident AI용으로 미리 구성된 export 파이프라인을 제공합니다. init()가 프로바이더, exporter, 엔드포인트, API 키 헤더를 모두 설정해 주고, 이 페이지의 confident.* 속성도 일반 OpenTelemetry tracer로 만든 스팬에 동일하게 적용돼요.
confident-trace를 설치하고 CONFIDENT_API_KEY를 설정한 뒤:
import json
from confident_trace import init, shutdown
from opentelemetry import trace
init(instrumentations=())
tracer = trace.get_tracer("my-application")
try:
with tracer.start_as_current_span("request") as current:
current.set_attribute("confident.trace.name", "example-trace")
current.set_attribute("confident.span.type", "llm")
current.set_attribute("gen_ai.request.model", "gpt-4o")
current.set_attribute("confident.span.input", json.dumps("What is the capital of France?"))
current.set_attribute("confident.span.output", json.dumps("Paris"))
finally:
shutdown()
instrumentations=()는confident-trace의 자동 통합을 끕니다. 기존 OpenTelemetry instrumentor가 이미 필요한 스팬을 만들고 있다면 이걸 쓰세요. 그렇지 않으면 LLM 호출이 두 번씩 기록돼요.confident-trace가 OpenAI, LangChain 등을 대신 계측해 주길 원한다면 기본값을 그대로 두세요.
애플리케이션이 이미 TracerProvider를 갖고 있다면, init()가 새로 만들게 두는 대신 아래의 기존 OpenTelemetry 프로바이더를 참고하세요.
기존 OpenTelemetry 프로바이더
애플리케이션이 이미 TracerProvider를 갖고 있을 때 — 다른 옵저버빌리티 백엔드로 내보내거나 OpenTelemetry Collector를 돌리거나 — 두 번째 프로바이더는 필요 없어요. confident-trace는 이미 갖고 있는 프로바이더에 export 파이프라인을 추가하므로, sampler, 리소스 속성, 다른 스팬 프로세서가 유지되고, 애플리케이션이 프로바이더 수명 주기(flush·shutdown 포함)를 계속 책임집니다.
Python
init()에 프로바이더를 전달합니다.
from confident_trace import init
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
provider = TracerProvider()
trace.set_tracer_provider(provider) # so other libraries use it too
init(tracer_provider=provider)
init()의 나머지 — 자동 통합, CONFIDENT_API_KEY, CONFIDENT_OTEL_ENDPOINT, 샘플링 — 는 평소와 같이 동작해요. 유일한 차이는 스팬이 내 프로바이더를 거쳐 흐른다는 점뿐이에요.
TypeScript
프로바이더를 만들 때 Confident AI의 스팬 프로세서를 추가하고, init()은 호출하지 마세요.
import { NodeTracerProvider } from "@opentelemetry/sdk-trace-node";
import { createSpanProcessor } from "confident-trace/otel";
const provider = new NodeTracerProvider({
spanProcessors: [createSpanProcessor()],
});
provider.register();
// After all application work finishes:
await provider.shutdown();
init()을 쓸 때처럼 환경에 CONFIDENT_API_KEY(EU 리전이나 자체 호스팅이라면 CONFIDENT_OTEL_ENDPOINT도)를 설정하세요.
init()이 없으면 자동 계측도 없어요 —createSpanProcessor()는 export만 처리합니다. 필요한 프레임워크나 프로바이더 어댑터를 직접 연결하고(예제는 Vercel AI SDK와 OpenInference 페이지 참고), 애플리케이션을 실행하세요.
다른 전역 프로바이더가 이미 등록되어 있으면
init()은 비활성(inactive) 런타임을 반환해요 — 내 프로바이더와 전역 슬롯을 다투지는 않지만, 아무것도 내보내지 않아요. 트레이스가 안 보이는데 다른 SDK가 프로바이더를 등록하는 걸 안다면 바로 이 때문이에요. 그 프로바이더에createSpanProcessor()를 쓰세요.
confident-trace와 내 기존 tracer가 둘 다 OpenTelemetry를 말하기 때문에,span/withSpan으로 만든 스팬과 내tracer.startActiveSpan(...)로 만든 스팬은 같은 트레이스에 들어가 정상적으로 중첩돼요. 둘 중 하나를 고를 필요가 없어요.
Confident AI에서의 OTEL 이해하기
이 페이지의 나머지는 속성 레퍼런스입니다. 다루는 내용은 다음과 같아요.
- Confident AI의
confident.trace.*및confident.span.*속성 - LLM·툴 스팬에 대해 Confident AI가 읽는
gen_ai.*속성 - 환경 및 기타 리소스 수준 구성
OTLP 엔드포인트가 어떻게 동작하는지, Confident AI가 gen_ai.*, OpenInference, OpenLLMetry 스팬을 자체 데이터 모델에 어떻게 매핑하는지는 OpenTelemetry 개요를 참고하세요.
OTEL 엔드포인트
Confident AI는 OTLP 형식의 OpenTelemetry 트레이스를 받는 https://otel.confident-ai.com 엔드포인트를 제공합니다. Confident AI는 OpenTelemetry 엔드포인트에 대해 GRPC를 지원하지 않는다는 점을 유의하세요. HTTP를 사용하세요. EU 및 자체 호스팅 호스트는 리전 및 엔드포인트를 참고하세요.
속성
Confident AI는 GenAI 시맨틱 컨벤션을 따르면서, 그 위에 LLM 애플리케이션에 대한 추가 데이터를 포착하는 레이어를 더합니다. Confident AI는 confident.* 네임스페이스를 사용해 특정 속성을 llm tracing 데이터 모델에 매핑해요. 이 특정 속성들은 항상 gen_ai.* 컨벤션보다 우선하며, 애플리케이션을 수동 계측하는 모든 사용자에게 권장됩니다. 전체 우선순위 순서는 속성 우선순위에 문서화되어 있어요.
원시 OpenTelemetry SDK로 Confident AI 콘텐츠 속성을 설정할 때는
input,output,metadata,context,retrieval_context,expected_output,tools_called,expected_tools를 JSON 직렬화하세요.confident-trace헬퍼가 이 인코딩을 대신 처리합니다.
GenAI 시맨틱 컨벤션은 아직 개발 중이며 변경될 수 있어요.
환경
SDK를 구성할 때 환경을 OpenTelemetry 리소스 속성으로 설정합니다.
OTEL_RESOURCE_ATTRIBUTES="confident.trace.environment=production"
트레이스 수준 속성 매핑
이것들은 tracing features와 유사한 Confident AI 트레이스 고유의 속성입니다. 트레이스 수준 속성은 confident.trace.* 네임스페이스를 사용해 스팬 속성에 설정해요.
트레이스 수명 주기 동안 어떤 스팬에서든 트레이스 속성을 한 번 설정하는 것이 좋습니다. 여러 스팬에 설정하면 특정 속성의 값이 가장 최근 값으로 갱신돼요.
이름
트레이스 이름은 UI에 표시됩니다. UI 표시를 위해 마음대로 사용자 지정할 수 있어요. 다음 속성을 사용하세요.
"confident.trace.name"(str타입) — 트레이스 이름 갱신에 사용
with tracer.start_as_current_span("custom_span") as span:
span.set_attribute("confident.trace.name", "test_trace")
span.setAttributes({
"confident.trace.name": "example-trace",
});
span.SetAttributes(
attribute.String("confident.trace.name", "example-trace"),
)
span.set_attribute("confident.trace.name", "example-trace")
span.SetAttribute("confident.trace.name", "example-trace");
입력/출력
다음 속성을 사용해 런타임에 트레이스 입력과 출력을 설정할 수 있어요.
"confident.trace.input"(JSON 문자열) — 트레이스 입력 설정"confident.trace.output"(JSON 문자열) — 트레이스 출력 설정
아래 예제에서 input과 output은 이미 JSON 직렬화된 문자열입니다.
with tracer.start_as_current_span("custom_span") as span:
span.set_attribute("confident.trace.input", input)
span.set_attribute("confident.trace.output", output)
span.setAttributes({
"confident.trace.input": input,
"confident.trace.output": output,
});
span.SetAttributes(
attribute.String("confident.trace.input", input),
attribute.String("confident.trace.output", output),
)
span.set_attribute("confident.trace.input", input)
span.set_attribute("confident.trace.output", output)
span.SetAttribute("confident.trace.input", input);
span.SetAttribute("confident.trace.output", output);
테스트 케이스
온라인 평가는 Confident AI의 Evaluation Rules로 선택됩니다. confident.trace.* 속성을 사용해 트레이스에 테스트 케이스 매개변수를 설정해요.
import json
with tracer.start_as_current_span("confident_evaluation") as span:
input = "What is the capital of France?"
output = my_llm_app(input) # your LLM application
span.set_attribute('confident.trace.input', json.dumps(input))
span.set_attribute('confident.trace.output', json.dumps(output))
span.set_attribute('confident.trace.retrieval_context', json.dumps(["context1", "context2"]))
span.set_attribute('confident.trace.expected_output', json.dumps("Paris"))
span.setAttributes({
"confident.trace.input": JSON.stringify(input),
"confident.trace.output": JSON.stringify(output),
"confident.trace.retrieval_context": JSON.stringify(["context1", "context2"]),
"confident.trace.expected_output": JSON.stringify("Paris"),
});
span.SetAttributes(
attribute.String("confident.trace.input", `"What is the capital of France?"`),
attribute.String("confident.trace.output", `"Paris"`),
attribute.String("confident.trace.retrieval_context", `["context1","context2"]`),
attribute.String("confident.trace.expected_output", `"Paris"`),
)
span.set_attribute("confident.trace.input", input.to_json)
span.set_attribute("confident.trace.output", output.to_json)
span.set_attribute("confident.trace.retrieval_context", ["context1", "context2"].to_json)
span.set_attribute("confident.trace.expected_output", "Paris".to_json)
span.SetAttribute("confident.trace.input", JsonSerializer.Serialize(input));
span.SetAttribute("confident.trace.output", JsonSerializer.Serialize(output));
span.SetAttribute("confident.trace.retrieval_context", JsonSerializer.Serialize(new[] { "context1", "context2" }));
span.SetAttribute("confident.trace.expected_output", JsonSerializer.Serialize("Paris"));
LLM 테스트 케이스 속성 매핑:
"confident.trace.input"(JSON 문자열) — 테스트 케이스 입력 설정"confident.trace.output"(JSON 문자열) — 테스트 케이스 실제 출력 설정- [선택]
"confident.trace.expected_output"(JSON 문자열) — 기대 출력 설정 - [선택]
"confident.trace.context"(JSON 인코딩 문자열 배열) — 컨텍스트 설정 - [선택]
"confident.trace.retrieval_context"(JSON 인코딩 문자열 배열) — 검색 컨텍스트 설정 - [선택]
"confident.trace.tools_called"(JSON 인코딩 도구 배열) — 호출된 도구 설정 - [선택]
"confident.trace.expected_tools"(JSON 인코딩 도구 배열) — 기대 도구 설정
태그
태그는 관련 트레이스를 묶기 쉽게 해 주는 단순한 문자열 라벨이며, 스팬에는 적용할 수 없어요.
"confident.trace.tags"(list[str]타입) — 트레이스 태그 갱신에 사용
with tracer.start_as_current_span("custom_span") as span:
span.set_attribute("confident.trace.tags", ["tag1", "tag2"])
span.setAttributes({ "confident.trace.tags": ["tag1", "tag2"] });
span.SetAttributes(
attribute.StringSlice("confident.trace.tags", []string{"tag1", "tag2"}),
)
span.set_attribute('confident.trace.tags', ['tag1', 'tag2'])
currentSpan.SetAttribute("confident.trace.tags", new[] { "tag1", "tag2" });
메타데이터
트레이스에 메타데이터를 붙입니다. 이 정보는 observatory에서 트레이스를 필터링·그룹핑·분석하는 데 사용할 수 있어요.
"confident.trace.metadata"(str타입) — 트레이스 메타데이터 갱신에 사용
이 속성은 딕셔너리로 파싱되는 JSON 문자열이에요.
import json
with tracer.start_as_current_span("custom_span") as span:
span.set_attribute("confident.trace.metadata", json.dumps({"key": "value"}))
span.setAttributes({
"confident.trace.metadata": JSON.stringify({ key: "value" }),
});
attribute.String("confident.trace.metadata", `{"key": "value"}`)
span.set_attribute("confident.trace.metadata", '{"key":"value"}')
span.SetAttribute("confident.trace.metadata", "{\"key\":\"value\"}");
스레드 ID
Confident AI의 스레드는 하나 이상의 트레이스 모음이라, 전체 대화를 볼 수 있어요 — 채팅 앱, 에이전트, 다중 턴 상호작용에 딱 맞죠.
"confident.trace.thread.id"(문자열) — 스레드 ID 설정"confident.trace.thread.tags"(문자열 배열) — 스레드 태그 설정"confident.trace.thread.metadata"(JSON 객체 문자열) — 스레드 메타데이터 설정
confident.trace.thread_id는 레거시 ID 별칭으로 남아 있어요. 새로운 수동 계측에서는 구조화된 confident.trace.thread.* 속성을 사용하세요.
with tracer.start_as_current_span("custom_span") as span:
span.set_attribute("confident.trace.thread.id", "123")
span.setAttributes({
"confident.trace.thread.id": "123",
});
span.SetAttributes(
attribute.String("confident.trace.thread.id", "123"),
)
span.set_attribute("confident.trace.thread.id", "123")
span.SetAttribute("confident.trace.thread.id", "123");
사용자 ID
트레이스에 안정적인 ID와 (선택 사항) 표시 이름을 설정해 사용자를 추적합니다.
"confident.trace.user.id"(문자열) — 사용자 ID 설정"confident.trace.user.name"(문자열) — 사용자 표시 이름 설정
confident.trace.user_id는 레거시 ID 별칭으로 남아 있어요. 새로운 수동 계측에서는 구조화된 confident.trace.user.* 속성을 사용하세요. 둘 다 설정할 때는 ID가 일치해야 합니다.
with tracer.start_as_current_span("custom_span") as span:
span.set_attribute("confident.trace.user.id", "user-123")
span.set_attribute("confident.trace.user.name", "Marta")
span.setAttributes({
"confident.trace.user.id": "user-123",
"confident.trace.user.name": "Marta",
});
span.SetAttributes(
attribute.String("confident.trace.user.id", "user-123"),
attribute.String("confident.trace.user.name", "Marta"),
)
span.set_attribute("confident.trace.user.id", "user-123")
span.set_attribute("confident.trace.user.name", "Marta")
span.SetAttribute("confident.trace.user.id", "user-123");
span.SetAttribute("confident.trace.user.name", "Marta");
고객 ID
같은 계정, 조직, 테넌트에 속한 사용자를 묶으려면 고객을 사용하세요.
"confident.trace.customer.id"(문자열) — 고객 ID 설정"confident.trace.customer.name"(문자열) — 고객 표시 이름 설정
confident.trace.customer_id는 레거시 ID 별칭으로 남아 있어요. 새로운 수동 계측에서는 구조화된 confident.trace.customer.* 속성을 사용하세요. 둘 다 설정할 때는 ID가 일치해야 합니다.
with tracer.start_as_current_span("custom_span") as span:
span.set_attribute("confident.trace.customer.id", "customer-42")
span.set_attribute("confident.trace.customer.name", "Acme Corp")
span.setAttributes({
"confident.trace.customer.id": "customer-42",
"confident.trace.customer.name": "Acme Corp",
});
span.SetAttributes(
attribute.String("confident.trace.customer.id", "customer-42"),
attribute.String("confident.trace.customer.name", "Acme Corp"),
)
span.set_attribute("confident.trace.customer.id", "customer-42")
span.set_attribute("confident.trace.customer.name", "Acme Corp")
span.SetAttribute("confident.trace.customer.id", "customer-42");
span.SetAttribute("confident.trace.customer.name", "Acme Corp");
테스트 케이스 ID
AI Connections을 통한 단일 턴 평가에서 Confident AI는 엔드포인트에 testCaseId를 페이로드로 보내요. 이 값을 트레이스의 test_case_id 속성으로 전달하면 트레이스를 테스트 케이스에 연결할 수 있어요 — 평가 결과에서 전체 트레이스로 바로 클릭해 들어갈 수 있죠.
"confident.trace.test_case_id"(str타입) — 트레이스를 평가 결과의 테스트 케이스에 연결하는 데 사용
with tracer.start_as_current_span("custom_span") as span:
span.set_attribute("confident.trace.test_case_id", test_case_id)
span.setAttributes({
"confident.trace.test_case_id": testCaseId,
});
span.SetAttributes(
attribute.String("confident.trace.test_case_id", testCaseId),
)
span.set_attribute("confident.trace.test_case_id", test_case_id)
span.SetAttribute("confident.trace.test_case_id", testCaseId);
턴 ID
AI Connections을 통한 다중 턴 평가에서 Confident AI는 각 턴마다 페이로드에 turnId를 보내요. 이 값을 트레이스의 turn_id 속성으로 전달하면 각 턴의 트레이스를 대화의 특정 턴에 연결할 수 있어요.
"confident.trace.turn_id"(str타입) — 트레이스를 다중 턴 평가 결과의 특정 턴에 연결하는 데 사용
with tracer.start_as_current_span("custom_span") as span:
span.set_attribute("confident.trace.turn_id", turn_id)
span.setAttributes({
"confident.trace.turn_id": turnId,
});
span.SetAttributes(
attribute.String("confident.trace.turn_id", turnId),
)
span.set_attribute("confident.trace.turn_id", turn_id)
span.SetAttribute("confident.trace.turn_id", turnId);
스팬 수준 속성 매핑
이것들은 tracing features와 유사한 Confident AI 스팬 고유의 속성입니다. 스팬 수준 속성은 confident.span.* 네임스페이스를 사용해 스팬 속성에 설정해요.
이름
스팬 이름은 스팬이 시작될 때 제공되는 표준 OpenTelemetry 스팬 이름입니다(예: start_as_current_span("custom_span")의 "custom_span"). 별도의 confident.span.name 속성은 없어요.
입력/출력
다음 속성을 사용해 런타임에 스팬 입력과 출력을 설정할 수 있어요.
"confident.span.input"(JSON 문자열) — 스팬 입력 설정"confident.span.output"(JSON 문자열) — 스팬 출력 설정
아래 예제에서 input과 output은 이미 JSON 직렬화된 문자열입니다.
with tracer.start_as_current_span("custom_span") as span:
span.set_attribute("confident.span.input", input)
span.set_attribute("confident.span.output", output)
span.setAttributes({
"confident.span.input": input,
"confident.span.output": output,
});
span.SetAttributes(
attribute.String("confident.span.input", input),
attribute.String("confident.span.output", output),
)
span.set_attribute("confident.span.input", input)
span.set_attribute("confident.span.output", output)
span.SetAttribute("confident.span.input", input);
span.SetAttribute("confident.span.output", output);
테스트 케이스
온라인 평가는 Confident AI의 Evaluation Rules로 선택됩니다. confident.span.* 속성을 사용해 어떤 스팬에서든 테스트 케이스 매개변수를 설정해요.
import json
with tracer.start_as_current_span("confident_evaluation") as span:
input = "What is the capital of France?"
output = my_llm_app(input) # your LLM application
span.set_attribute('confident.span.input', json.dumps(input))
span.set_attribute('confident.span.output', json.dumps(output))
span.set_attribute('confident.span.retrieval_context', json.dumps(["context1", "context2"]))
span.set_attribute('confident.span.expected_output', json.dumps("Paris"))
span.setAttributes({
"confident.span.input": JSON.stringify(input),
"confident.span.output": JSON.stringify(output),
"confident.span.retrieval_context": JSON.stringify(["context1", "context2"]),
"confident.span.expected_output": JSON.stringify("Paris"),
});
span.SetAttributes(
attribute.String("confident.span.input", `"What is the capital of France?"`),
attribute.String("confident.span.output", `"Paris"`),
attribute.String("confident.span.retrieval_context", `["context1","context2"]`),
attribute.String("confident.span.expected_output", `"Paris"`),
)
span.set_attribute("confident.span.input", input.to_json)
span.set_attribute("confident.span.output", output.to_json)
span.set_attribute("confident.span.retrieval_context", ["context1", "context2"].to_json)
span.set_attribute("confident.span.expected_output", "Paris".to_json)
span.SetAttribute("confident.span.input", JsonSerializer.Serialize(input));
span.SetAttribute("confident.span.output", JsonSerializer.Serialize(output));
span.SetAttribute("confident.span.retrieval_context", JsonSerializer.Serialize(new[] { "context1", "context2" }));
span.SetAttribute("confident.span.expected_output", JsonSerializer.Serialize("Paris"));
LLM 테스트 케이스 속성 매핑:
"confident.span.input"(JSON 문자열) — 테스트 케이스 입력 설정"confident.span.output"(JSON 문자열) — 테스트 케이스 실제 출력 설정- [선택]
"confident.span.expected_output"(JSON 문자열) — 기대 출력 설정 - [선택]
"confident.span.context"(JSON 인코딩 문자열 배열) — 컨텍스트 설정 - [선택]
"confident.span.retrieval_context"(JSON 인코딩 문자열 배열) — 검색 컨텍스트 설정 - [선택]
"confident.span.tools_called"(JSON 인코딩 도구 배열) — 호출된 도구 설정 - [선택]
"confident.span.expected_tools"(JSON 인코딩 도구 배열) — 기대 도구 설정
메타데이터
스팬에 메타데이터를 붙일 수 있어요. 이 정보는 observatory에서 스팬을 필터링·그룹핑·분석하는 데 사용할 수 있어요.
"confident.span.metadata"(str타입) — 스팬 메타데이터 갱신에 사용
이 속성은 딕셔너리로 파싱되는 JSON 문자열이에요.
import json
with tracer.start_as_current_span("custom_span") as span:
span.set_attribute("confident.span.metadata", json.dumps({"key": "value"}))
span.setAttributes({
"confident.span.metadata": JSON.stringify({ key: "value" }),
});
span.SetAttributes(
attribute.String("confident.span.metadata", `{"key": "value"}`),
)
span.set_attribute("confident.span.metadata", '{"key":"value"}')
span.SetAttribute("confident.span.metadata", "{\"key\": \"value\"}");
유형별 속성
스팬 유형은 선택 사항이지만, LLM 애플리케이션에서 가장 흔한 컴포넌트 유형을 분류할 수 있게 해 줍니다. 기본 스팬 유형 4가지는 다음과 같아요.
llmagentretrievertool
다음 속성을 사용해 스팬 유형을 설정할 수 있어요.
"confident.span.type"(str타입) — 스팬 유형 갱신에 사용
with tracer.start_as_current_span("custom_span") as span:
span.set_attribute("confident.span.type", "llm")
span.setAttributes({
"confident.span.type": "llm",
});
span.SetAttributes(
attribute.String("confident.span.type", "llm"),
)
span.set_attribute("confident.span.type", "llm")
span.SetAttribute("confident.span.type", "llm");
특정 스팬 유형에 대한 스팬 수준 속성
유형별 데이터는 표준 gen_ai.* 시맨틱 컨벤션과 아래 나열된 Confident AI 속성의 조합을 사용합니다. confident.{span_type}.* 네임스페이스를 임의로 만들지 마세요 — 문서화된 속성만 인식돼요.
Custom
기본 스팬 유형입니다. 위에서 confident.span.* 네임스페이스로 사용한 모든 속성이 이 스팬 유형에 적용돼요.
LLM
LLM 스팬을 만들려면 confident.span.type을 llm로 설정하세요. 해당하는 고수준 트레이싱 API는 LLM 스팬을 참고하세요.
"gen_ai.request.model"(str타입) — 요청된 모델 기록"gen_ai.provider.name"(str타입) — 모델 프로바이더 기록"gen_ai.usage.input_tokens"(int타입) — 입력 토큰 사용량 기록"gen_ai.usage.output_tokens"(int타입) — 출력 토큰 사용량 기록- [선택]
"confident.llm.cost_per_input_token"(float타입) — 입력 토큰당 비용 갱신에 사용 - [선택]
"confident.llm.cost_per_output_token"(float타입) — 출력 토큰당 비용 갱신에 사용
LLM 스팬 유형에 대한 속성 설정 샘플 코드는 아래와 같아요.
with tracer.start_as_current_span("llm_span") as span:
span.set_attribute("confident.span.type", "llm")
span.set_attribute("gen_ai.request.model", "gpt-4o")
span.set_attribute("gen_ai.provider.name", "openai")
span.set_attribute("confident.span.input", json.dumps([
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": input}
]))
time.sleep(0.5)
span.set_attribute("confident.span.output", json.dumps("Hello world"))
span.setAttributes({
"confident.span.type": "llm",
"gen_ai.request.model": "gpt-4o",
"gen_ai.provider.name": "openai",
"confident.span.input": JSON.stringify([
{ role: "system", content: "You are a helpful assistant." },
{ role: "user", content: "What is the capital of France?" },
]),
"confident.span.output": JSON.stringify("Hello world"),
});
span.SetAttributes(
attribute.String("confident.span.type", "llm"),
attribute.String("gen_ai.request.model", "gpt-4o"),
attribute.String("gen_ai.provider.name", "openai"),
attribute.String("confident.span.input", `[{"role":"system","content":"You are a helpful assistant."},{"role":"user","content":"What is the capital of France?"}]`),
attribute.String("confident.span.output", `"Hello world"`),
)
span.set_attribute("confident.span.type", "llm")
span.set_attribute("gen_ai.request.model", "gpt-4o")
span.set_attribute("gen_ai.provider.name", "openai")
span.set_attribute("confident.span.input", [
{ role: "system", content: "You are a helpful assistant." },
{ role: "user", content: "What is the capital of France?" }
].to_json)
span.set_attribute("confident.span.output", "Hello world".to_json)
span.SetAttribute("confident.span.type", "llm");
span.SetAttribute("gen_ai.request.model", "gpt-4o");
span.SetAttribute("gen_ai.provider.name", "openai");
span.SetAttribute("confident.span.input", JsonSerializer.Serialize(new[] {
new { role = "system", content = "You are a helpful assistant." },
new { role = "user", content = "What is the capital of France?" }
}));
span.SetAttribute("confident.span.output", JsonSerializer.Serialize("Hello world"));
Agent
Agent 스팬을 만들려면 confident.span.type을 agent로 설정하세요. Agent 스팬은 위에서 설명한 공유 confident.span.* 필드를 사용하며 추가 유형별 속성은 없어요. Agent 스팬을 참고하세요.
Agent 스팬 유형에 대한 속성 설정 샘플 코드는 아래와 같아요.
with tracer.start_as_current_span("agent_span") as span:
span.set_attribute("confident.span.type", "agent")
span.set_attribute("confident.span.input", json.dumps({"input": "input"}))
span.set_attribute("confident.span.output", json.dumps({"output": "output"}))
span.setAttributes({
"confident.span.type": "agent",
"confident.span.input": JSON.stringify({ input: "input" }),
"confident.span.output": JSON.stringify({ output: "output" }),
});
span.SetAttributes(
attribute.String("confident.span.input", `{"input": "input"}`),
attribute.String("confident.span.output", `{"output": "output"}`),
attribute.String("confident.span.type", "agent"),
)
span.set_attribute("confident.span.type", "agent")
span.set_attribute("confident.span.input", { input: "input" }.to_json)
span.set_attribute("confident.span.output", { output: "output" }.to_json)
span.SetAttribute("confident.span.type", "agent");
span.SetAttribute("confident.span.input", JsonSerializer.Serialize(new { input = "input" }));
span.SetAttribute("confident.span.output", JsonSerializer.Serialize(new { output = "output" }));
Tool
Tool 스팬을 만들려면 confident.span.type을 tool로 설정하세요. 도구 이름은 표준 gen_ai.tool.name 속성으로 설정합니다. Tool 스팬을 참고하세요.
Tool 스팬 유형에 대한 속성 설정 샘플 코드는 아래와 같아요.
with tracer.start_as_current_span("tool_span") as span:
span.set_attribute("confident.span.type", "tool")
span.set_attribute("gen_ai.tool.name", "web_search")
span.set_attribute("confident.span.input", json.dumps({"input": "input"}))
span.set_attribute("confident.span.output", json.dumps({"output": "output"}))
span.setAttributes({
"confident.span.type": "tool",
"gen_ai.tool.name": "web_search",
"confident.span.input": JSON.stringify({ input: "input" }),
"confident.span.output": JSON.stringify({ output: "output" }),
});
span.SetAttributes(
attribute.String("gen_ai.tool.name", "web_search"),
attribute.String("confident.span.input", `{"input": "input"}`),
attribute.String("confident.span.output", `{"output": "output"}`),
attribute.String("confident.span.type", "tool"),
)
span.set_attribute("confident.span.type", "tool")
span.set_attribute("gen_ai.tool.name", "web_search")
span.set_attribute("confident.span.input", { input: "input" }.to_json)
span.set_attribute("confident.span.output", { output: "output" }.to_json)
span.SetAttribute("confident.span.type", "tool");
span.SetAttribute("gen_ai.tool.name", "web_search");
span.SetAttribute("confident.span.input", JsonSerializer.Serialize(new { input = "input" }));
span.SetAttribute("confident.span.output", JsonSerializer.Serialize(new { output = "output" }));
Retriever
Retriever 스팬을 만들려면 confident.span.type을 retriever로 설정하세요. 검색된 텍스트는 confident.span.retrieval_context로 기록합니다. Retriever 스팬을 참고하세요.
Retriever 스팬 유형에 대한 속성 설정 샘플 코드는 아래와 같아요.
with tracer.start_as_current_span("retriever_span") as span:
span.set_attribute("confident.span.type", "retriever")
span.set_attribute("confident.span.input", json.dumps("query"))
span.set_attribute("confident.span.retrieval_context", json.dumps(["chunk 1", "chunk 2"]))
span.setAttributes({
"confident.span.type": "retriever",
"confident.span.input": JSON.stringify("query"),
"confident.span.retrieval_context": JSON.stringify(["chunk 1", "chunk 2"]),
});
span.SetAttributes(
attribute.String("confident.span.input", `"query"`),
attribute.String("confident.span.retrieval_context", `["chunk 1","chunk 2"]`),
attribute.String("confident.span.type", "retriever"),
)
span.set_attribute("confident.span.type", "retriever")
span.set_attribute("confident.span.input", "query".to_json)
span.set_attribute("confident.span.retrieval_context", ["chunk 1", "chunk 2"].to_json)
span.SetAttribute("confident.span.input", JsonSerializer.Serialize("query"));
span.SetAttribute("confident.span.retrieval_context", JsonSerializer.Serialize(new[] { "chunk 1", "chunk 2" }));
더 알아보기
- 분산 추적 — 서비스 경계를 넘나드는 스팬 연결하기
- 트레이스 브로드캐스팅 — 같은 트레이스를 여러 목적지로 보내기
- 트레이스 포워딩 — Confident AI의 평가가 채워진 트레이스 받기