싱글턴 종단 간 평가
싱글턴 종단 간 평가 (Single-Turn, E2E Evals)
싱글턴 유스케이스에 대해 종단 간(end-to-end) 테스트를 실행하는 방법을 배워볼게요. 종단 간 테스트는 LLM 애플리케이션을 블랙박스로 취급해 — 인풋을 넣고 최종 아웃풋을 평가해요. 단순한 파이프라인, RAG 시스템, 또는 중간 단계보다 최종 결과만 신경 쓸 때 이상적이에요.
출처: 문서
본문
개요
종단 간 테스트는 LLM 애플리케이션을 블랙박스로 취급해요 — 인풋을 제공하고 최종 아웃풋을 평가하죠. 이는 단순한 파이프라인, RAG 시스템, 또는 중간 단계보다 최종 결과만 신경 쓸 때 이상적이에요.
요구 사항 (Requirements):
종단 간 테스트는 기술적으로 컴포넌트 레벨 테스트의 부분집합이에요 — 전체 시스템을 단일 컴포넌트로 생각할 수 있거든요. 핵심 차이는 컴포넌트 레벨 테스트는 개별 부분(리트리버, 생성기, 툴)에 메트릭을 정의할 수 있게 하는 반면, 종단 간은 최종 아웃풋에만 집중한다는 점이에요.
동작 방식
- Confident AI에서 데이터셋 가져오기
- 데이터셋의 골든스를 순회하며, 각 골든스에 대해:
- 골든스 인풋으로 LLM 앱을 호출해 actual output, tools called 같은 테스트 케이스 파라미터 생성
- 골든스 필드를 테스트 케이스 파라미터로 매핑
- 테스트 케이스를 데이터셋에 다시 추가
- 테스트 케이스에 대한 평가 실행 (로컬 또는 Confident AI에서)
Confident AI에서 평가를 실행하는 방법은 다양해요
3단계를 실행하는 방법은 많아요. 로컬 평가의 경우:
evaluate()함수 사용- LLM 트레이싱으로
.evals_iterator()사용- CI/CD에서
deepeval test run사용원격 평가의 경우:
- Confident API 사용
evaluate()함수 사용
프로세스 전체에서 데이터가 어디로 흐르는지 시각적으로 보면:
로컬 메트릭 (Local Metrics)
sequenceDiagram
participant Your Code
participant Confident AI
participant LLM App
participant Metrics
Your Code->>Confident AI: Pull dataset
Confident AI-->>Your Code: List of goldens
loop For each golden
Your Code->>LLM App: Invoke with golden.input
LLM App-->>Your Code: actual_output
Your Code->>Your Code: Create test case (input + actual_output)
end
Your Code->>Metrics: Run evaluation locally
Metrics-->>Confident AI: Upload results & generate testing report
원격 메트릭 (Remote Metrics)
sequenceDiagram
participant Your Code
participant Confident AI
participant LLM App
Your Code->>Confident AI: Pull dataset
Confident AI-->>Your Code: List of goldens
loop For each golden
Your Code->>LLM App: Invoke with golden.input
LLM App-->>Your Code: actual_output
Your Code->>Your Code: Create test case (input + actual_output)
end
Your Code->>Confident AI: Send test cases to the Confident API
Confident AI->>Confident AI: Run metrics remotely
Confident AI-->>Your Code: Return testing report link
로컬에서 E2E 테스트 실행 (Run E2E Tests Locally)
로컬 평가는 Python deepeval 라이브러리를 사용할 때만 가능해요. TypeScript나 다른 언어를 사용한다면 원격 종단 간 평가 섹션으로 건너뛰세요.
이 섹션에서는 단순한 RAG 파이프라인인 이 mock LLM 앱을 사용할게요:
Mock LLM 앱 보기
from openai import OpenAI
def llm_app(query: str) -> str:
# Retriever for your vector db
def retriever(query: str) -> list[str]:
return ["List", "of", "text", "chunks"]
# Generator that combines retrieved context with user query
def generator(query: str, text_chunks: list[str]) -> str:
return OpenAI().chat.completions.create(
model="gpt-4o",
messages=[
{"role": "user", "content": query}
]
).choices[0].message.content
# Calls retriever then generator
return generator(query, retriever(query))
데이터셋 가져오기
데이터셋을 가져와요(아직 없다면 만들기):
from deepeval.dataset import EvaluationDataset
dataset = EvaluationDataset()
dataset.pull(alias="YOUR-DATASET-ALIAS")
골든스를 순회하며 테스트 케이스 생성
이 단계에서는 LLM 앱을 호출하는 네이티브 for-루프로 충분해요:
from deepeval.test_case import LLMTestCase
from deepeval.dataset import EvaluationDataset
dataset = EvaluationDataset()
dataset.pull(alias="YOUR-DATASET-ALIAS")
for golden in dataset.goldens:
test_case = LLMTestCase(
input=golden.input,
actual_output=llm_app(input)
)
dataset.add_test_case(test_case)
다른 테스트 케이스 파라미터(예:
retrieval_context)도 반환하고 싶다면 LLM 앱을 다시 작성해야 할 거예요. 이 문제는 다음 섹션에서 다룰게요.
evaluate()로 평가 실행
evaluate() 함수는 테스트 런을 만들고, 평가가 로컬에서 완료되면 데이터를 Confident AI에 업로드해요.
from deepeval.metrics import AnswerRelevancyMetric
from deepeval import evaluate
# Replace with your metrics
evaluate(test_cases=dataset.test_cases, metrics=[AnswerRelevancyMetric()])
완료 ✅. 새로 만들어진 공유 가능한 테스팅 리포트 링크가 보일 거예요.
evaluate()함수는 모든 테스트 케이스와 메트릭에 걸쳐 테스트 스위트를 실행해요- 각 메트릭은 모든 테스트 케이스에 적용돼요(예: 테스트 케이스 10개 × 메트릭 2개 = 평가 20개)
- 모든 메트릭이 통과해야 테스트 케이스가 통과해요
- 테스트 런의 통과율은 통과한 테스트 케이스의 비율이에요
deepeval은 기본적으로 브라우저를 자동으로 열어요. 이 동작을 끄려면CONFIDENT_BROWSER_OPEN=NO를 설정하세요.
싱글턴 테스팅 리포트
evaluate() 함수는 매우 비개입적(unopinionated)이고 비침습적(non-intrusive)이어서, 가벼운 LLM 평가 접근을 찾는 팀에게 좋아요. 하지만 다음을 의미하기도 해요:
- 테스트 케이스 필드를 매핑하기 위한 많은 ETL을 직접 처리해야 해요. 때로는 올바른 데이터를 반환하도록 LLM 앱을 다시 써야 하기도 하죠
- 가시성 없음 — 종단 간 평가라도 LLM 앱을 디버깅할 수 있으면 좋을 텐데요
다음 섹션에서는 이 ETL 지옥을 피하고 LLM 트레이스를 종단 간 테스트에 가져오는 방법을 보여드릴게요.
E2E 평가를 위한 LLM 트레이싱 (LLM Tracing for E2E Evals)
LLM 트레이싱은 테스트 케이스 구성과 관련된 모든 문제를 해결해줘요.
이 섹션의
@observe데코레이터는 DeepEval의 것이며, 로컬이나 CI에서 실행하는 코드 기반 평가를 위해 설계됐어요. 프로덕션에서 앱을 트레이싱하려면confident-trace를 대신 사용하세요 — LLM 트레이싱 퀵스타트를 참고하세요. 둘 다 같은 프로젝트로 데이터를 보내므로, 개발 시 트레이스와 프로덕션 트레이스가 나란히 존재해요.
LLM 트레이싱 설정
기존 LLM 앱에 몇 줄만 추가하면 돼요(위의 예시를 사용할게요):
from openai import OpenAI
from deepeval.tracing import observe, update_current_trace
@observe()
def llm_app(query: str) -> str:
@observe()
def retriever(query: str) -> list[str]:
chunks = ["List", "of", "text", "chunks"]
update_current_trace(retrieval_context=chunks)
return chunks
@observe()
def generator(query: str, text_chunks: list[str]) -> str:
res = OpenAI().chat.completions.create(model="gpt-4o", messages=[{"role": "user", "content": query}]
).choices[0].message.content
update_current_trace(input=query, output=res)
return res
return generator(query, retriever(query))
위 예시는 몇 개의 @observe 데코레이터만 추가해 LLM 앱을 트레이싱하는 방법을 보여줘요:
- 각
@observe데코레이터는 **스팬(span)**을 만들며, 이는 컴포넌트를 나타내요 - 반면 **트레이스(trace)**는 최상위
@observe데코레이터가 만들며, 많은 스팬/컴포넌트로 구성돼요 - 종단 간 테스트를 실행할 때 트레이싱된 앱 어디서든
update_current_trace함수를 호출해 테스트 케이스 파라미터를 설정할 수 있어요
지금은 LLM 트레이싱에 대해 모든 것을 배우려 애쓰지 않아도 돼요. 전용 LLM 트레이싱 섹션에서 자세히 다룰게요.
컴포넌트 레벨 테스트에 대한 다음 섹션에서는
update_current_trace함수를update_current_span으로 바꿔 컴포넌트 레벨에서 테스트 케이스를 구성할 거예요.
데이터셋 가져오기 및 골든스 순회
이전과 같은 방식으로 데이터셋을 가져오고 .evals_iterator()로 골든스를 순회해요. 골든스의 데이터(대부분 input)를 사용해 LLM 앱을 호출할 거예요:
from deepeval.metrics import AnswerRelevancyMetric
from deepeval.dataset import EvaluationDataset
dataset = EvaluationDataset()
dataset.pull(alias="YOUR-DATASET-ALIAS")
for golden in dataset.evals_iterator(metrics=[AnswerRelevancyMetric()]):
llm_app(golden.input) # Replace with your LLM app
완료 ✅. 새로 만들어진 공유 가능한 테스팅 리포트 링크가 보일 거예요. 이것이 말 그대로 종단 간 평가를 실행하는 전부예요, 게다가 Confident AI에 트레이싱이 포함된 전체 테스팅 리포트라는 추가 이점까지 있어요.
싱글턴 테스팅 리포트 (with Tracing)
for 루프를 비동기로 실행할 수도 있어요:
import asyncio from deepeval.metrics import AnswerRelevancyMetric from deepeval.dataset import EvaluationDataset dataset = EvaluationDataset() dataset.pull(alias="YOUR-DATASET-ALIAS") for golden in dataset.evals_iterator(metrics=[AnswerRelevancyMetric()]): task = asyncio.create_task(a_llm_app(golden.input)) dataset.evaluate(task)
원격에서 E2E 테스트 실행 (Run E2E Tests Remotely)
원격 종단 간 평가는 디버깅을 위한 추적성은 없지만 다음이 좋아요:
- 팀원이 코드를 거치지 않고 메트릭을 만들 수 있어요
- 어떤 언어든 Confident API를 통해 지원해요
이는 Confident API를 통해 가능해요.
메트릭 컬렉션 만들기
Project > Metric > Collections로 이동해요:
원격 평가용 메트릭 컬렉션
데이터셋 가져오고 테스트 케이스 구성
선택한 언어로 LLM 앱을 호출해 유효한 LLMTestCase 데이터 모델 목록을 구성해요.
Python
from deepeval.dataset import EvaluationDataset
from deepeval.test_case import LLMTestCase
dataset = EvaluationDataset()
dataset.pull(alias="YOUR-DATASET-ALIAS")
for golden in dataset.goldens:
test_case = LLMTestCase(input=golden.input, actual_output=llm_app(golden.input))
dataset.add_test_case(test_case)
TypeScript
import { EvaluationDataset, LLMTestCase, Golden } from "deepeval";
const dataset = new EvaluationDataset();
await dataset.pull({ alias: "YOUR-DATASET-ALIAS" });
for (const golden of dataset.goldens as Golden[]) {
const testCase = new LLMTestCase({
input: golden.input,
actualOutput: llmApp(golden.input),
});
dataset.addTestCase(testCase);
}
curl
Request (GET /v1/datasets/{alias}) — API reference
curl -X GET "https://api.confident-ai.com/v1/datasets/{alias}" \
-H "CONFIDENT_API_KEY: <PROJECT-API-KEY>"
import requests
response = requests.get(
"https://api.confident-ai.com/v1/datasets/{alias}",
headers={
"CONFIDENT_API_KEY": "<PROJECT-API-KEY>",
},
)
print(response.json())
const response = await fetch("https://api.confident-ai.com/v1/datasets/{alias}", {
method: "GET",
headers: {
"CONFIDENT_API_KEY": "<PROJECT-API-KEY>",
},
});
const data = await response.json();
console.log(data);
package main
import (
"fmt"
"io"
"net/http"
)
func main() {
req, err := http.NewRequest("GET", "https://api.confident-ai.com/v1/datasets/{alias}", nil)
if err != nil {
panic(err)
}
req.Header.Set("CONFIDENT_API_KEY", "<PROJECT-API-KEY>")
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
out, err := io.ReadAll(res.Body)
if err != nil {
panic(err)
}
fmt.Println(string(out))
}
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class Example {
public static void main(String[] args) throws Exception {
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.confident-ai.com/v1/datasets/{alias}"))
.header("CONFIDENT_API_KEY", "<PROJECT-API-KEY>")
.GET()
.build();
HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
}
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let response = reqwest::Client::new()
.get("https://api.confident-ai.com/v1/datasets/{alias}")
.header("CONFIDENT_API_KEY", "<PROJECT-API-KEY>")
.send()
.await?;
println!("{}", response.text().await?);
Ok(())
}
/v1/evaluate 엔드포인트 호출
Python
from deepeval import evaluate
evaluate(test_case=dataset.test_cases, metric_collection="YOUR-COLLECTION-NAME")
TypeScript
import { evaluate, EvaluationDataset, LLMTestCase } from "deepeval";
const dataset = new EvaluationDataset();
evaluate({
llmTestCases: dataset.testCases as LLMTestCase[],
metricCollection: "YOUR-COLLECTION-NAME",
});
curl
Request (POST /v1/evaluate) — API reference
curl -X POST "https://api.confident-ai.com/v1/evaluate" \
-H "CONFIDENT_API_KEY: <PROJECT-API-KEY>" \
-H "Content-Type: application/json" \
-d '{
"metricCollection": "Collection Name",
"llmTestCases": [
{
"input": "How tall is mount everest?",
"actualOutput": "No clue, pretty tall I guess?"
}
]
}'
import requests
response = requests.post(
"https://api.confident-ai.com/v1/evaluate",
headers={
"CONFIDENT_API_KEY": "<PROJECT-API-KEY>",
},
json={
"metricCollection": "Collection Name",
"llmTestCases": [
{
"input": "How tall is mount everest?",
"actualOutput": "No clue, pretty tall I guess?"
}
]
},
)
print(response.json())
const response = await fetch("https://api.confident-ai.com/v1/evaluate", {
method: "POST",
headers: {
"CONFIDENT_API_KEY": "<PROJECT-API-KEY>",
"Content-Type": "application/json",
},
body: JSON.stringify({
"metricCollection": "Collection Name",
"llmTestCases": [
{
"input": "How tall is mount everest?",
"actualOutput": "No clue, pretty tall I guess?"
}
]
}),
});
const data = await response.json();
console.log(data);
package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := `{
"metricCollection": "Collection Name",
"llmTestCases": [
{
"input": "How tall is mount everest?",
"actualOutput": "No clue, pretty tall I guess?"
}
]
}`
req, err := http.NewRequest("POST", "https://api.confident-ai.com/v1/evaluate", strings.NewReader(body))
if err != nil {
panic(err)
}
req.Header.Set("CONFIDENT_API_KEY", "<PROJECT-API-KEY>")
req.Header.Set("Content-Type", "application/json")
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
out, err := io.ReadAll(res.Body)
if err != nil {
panic(err)
}
fmt.Println(string(out))
}
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class Example {
public static void main(String[] args) throws Exception {
String body = """
{
"metricCollection": "Collection Name",
"llmTestCases": [
{
"input": "How tall is mount everest?",
"actualOutput": "No clue, pretty tall I guess?"
}
]
}""";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.confident-ai.com/v1/evaluate"))
.header("CONFIDENT_API_KEY", "<PROJECT-API-KEY>")
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(body))
.build();
HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
}
}
use serde_json::json;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let response = reqwest::Client::new()
.post("https://api.confident-ai.com/v1/evaluate")
.header("CONFIDENT_API_KEY", "<PROJECT-API-KEY>")
.json(&json!({
"metricCollection": "Collection Name",
"llmTestCases": [
{
"input": "How tall is mount everest?",
"actualOutput": "No clue, pretty tall I guess?"
}
]
}))
.send()
.await?;
println!("{}", response.text().await?);
Ok(())
}
고급 사용법 (Advanced Usage)
이제 싱글턴 종단 간 평가를 실행하는 법을 배웠으니, 함께 해야 할 몇 가지가 있어요.
프롬프트와 모델 기록 (Log prompts and models)
평가 중 LLM 앱에서 사용한 구성을 Confident AI에 알려주세요.
이는 Confident AI가 어떤 하이퍼파라미터가 사후적으로 더 잘 수행했는지 알려주는 데 도움이 돼요.
Python
evaluate() 함수의 hyperparameters 인자에 자유 형식 키-값 쌍을 추가하면 돼요:
from deepeval.prompt import Prompt
prompt = Prompt(alias="YOUR-PROMPT-ALIAS")
prompt.pull()
evaluate(
hyperparameters={
"Model": "YOUR-MODEL",
"Prompt Version": prompt # An instance of your Prompt
},
test_cases=[...],
metrics=[...]
)
Prompt인스턴스를 제공하는 것은 Confident AI에서 프롬프트 버전을 가져온 경우에만 동작해요.
TypeScript
evaluate() 함수의 hyperparameters 인자에 자유 형식 키-값 쌍을 추가하면 돼요:
evaluate({
hyperparameters: {
Model: "YOUR-MODEL",
"Prompt": prompt,
},
llmTestCases: [...],
metricCollection: "YOUR-COLLECTION-NAME",
});
curl
Request (POST /v1/evaluate) — API reference
curl -X POST "https://api.confident-ai.com/v1/evaluate" \
-H "CONFIDENT_API_KEY: <PROJECT-API-KEY>" \
-H "Content-Type: application/json" \
-d '{
"metricCollection": "Collection Name",
"llmTestCases": {
"input": "How tall is mount everest?",
"actualOutput": "No clue, pretty tall I guess?"
},
"hyperparameters": {
"model": "gpt-4o-mini",
"prompt-version": "ai_generation_v2"
}
}'
import requests
response = requests.post(
"https://api.confident-ai.com/v1/evaluate",
headers={
"CONFIDENT_API_KEY": "<PROJECT-API-KEY>",
},
json={
"metricCollection": "Collection Name",
"llmTestCases": {
"input": "How tall is mount everest?",
"actualOutput": "No clue, pretty tall I guess?"
},
"hyperparameters": {
"model": "gpt-4o-mini",
"prompt-version": "ai_generation_v2"
}
},
)
print(response.json())
const response = await fetch("https://api.confident-ai.com/v1/evaluate", {
method: "POST",
headers: {
"CONFIDENT_API_KEY": "<PROJECT-API-KEY>",
"Content-Type": "application/json",
},
body: JSON.stringify({
"metricCollection": "Collection Name",
"llmTestCases": {
"input": "How tall is mount everest?",
"actualOutput": "No clue, pretty tall I guess?"
},
"hyperparameters": {
"model": "gpt-4o-mini",
"prompt-version": "ai_generation_v2"
}
}),
});
const data = await response.json();
console.log(data);
package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := `{
"metricCollection": "Collection Name",
"llmTestCases": {
"input": "How tall is mount everest?",
"actualOutput": "No clue, pretty tall I guess?"
},
"hyperparameters": {
"model": "gpt-4o-mini",
"prompt-version": "ai_generation_v2"
}
}`
req, err := http.NewRequest("POST", "https://api.confident-ai.com/v1/evaluate", strings.NewReader(body))
if err != nil {
panic(err)
}
req.Header.Set("CONFIDENT_API_KEY", "<PROJECT-API-KEY>")
req.Header.Set("Content-Type", "application/json")
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
out, err := io.ReadAll(res.Body)
if err != nil {
panic(err)
}
fmt.Println(string(out))
}
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class Example {
public static void main(String[] args) throws Exception {
String body = """
{
"metricCollection": "Collection Name",
"llmTestCases": {
"input": "How tall is mount everest?",
"actualOutput": "No clue, pretty tall I guess?"
},
"hyperparameters": {
"model": "gpt-4o-mini",
"prompt-version": "ai_generation_v2"
}
}""";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.confident-ai.com/v1/evaluate"))
.header("CONFIDENT_API_KEY", "<PROJECT-API-KEY>")
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(body))
.build();
HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
}
}
use serde_json::json;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let response = reqwest::Client::new()
.post("https://api.confident-ai.com/v1/evaluate")
.header("CONFIDENT_API_KEY", "<PROJECT-API-KEY>")
.json(&json!({
"metricCollection": "Collection Name",
"llmTestCases": {
"input": "How tall is mount everest?",
"actualOutput": "No clue, pretty tall I guess?"
},
"hyperparameters": {
"model": "gpt-4o-mini",
"prompt-version": "ai_generation_v2"
}
}))
.send()
.await?;
println!("{}", response.text().await?);
Ok(())
}
테스트 런에 식별자 추가 (Add identifer to test runs)
identifer 인자는 테스트 런에 이름을 붙이게 해주는데, 플랫폼에서 회귀 테스트를 실행할 때 매우 유용해요.
Python
evaluate(
identifer="Any custom string",
test_cases=[...],
metrics=[...]
)
TypeScript
evaluate({
identifer: "Any custom string",
llmTestCases: [...],
metricCollection: "YOUR-COLLECTION-NAME",
});
curl
Request (POST /v1/evaluate) — API reference
curl -X POST "https://api.confident-ai.com/v1/evaluate" \
-H "CONFIDENT_API_KEY: <PROJECT-API-KEY>" \
-H "Content-Type: application/json" \
-d '{
"metricCollection": "Collection Name",
"llmTestCases": {
"input": "How tall is mount everest?",
"actualOutput": "No clue, pretty tall I guess?",
"name": "Your Test Case Name"
},
"identifier": "run-399-102"
}'
import requests
response = requests.post(
"https://api.confident-ai.com/v1/evaluate",
headers={
"CONFIDENT_API_KEY": "<PROJECT-API-KEY>",
},
json={
"metricCollection": "Collection Name",
"llmTestCases": {
"input": "How tall is mount everest?",
"actualOutput": "No clue, pretty tall I guess?",
"name": "Your Test Case Name"
},
"identifier": "run-399-102"
},
)
print(response.json())
const response = await fetch("https://api.confident-ai.com/v1/evaluate", {
method: "POST",
headers: {
"CONFIDENT_API_KEY": "<PROJECT-API-KEY>",
"Content-Type": "application/json",
},
body: JSON.stringify({
"metricCollection": "Collection Name",
"llmTestCases": {
"input": "How tall is mount everest?",
"actualOutput": "No clue, pretty tall I guess?",
"name": "Your Test Case Name"
},
"identifier": "run-399-102"
}),
});
const data = await response.json();
console.log(data);
package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := `{
"metricCollection": "Collection Name",
"llmTestCases": {
"input": "How tall is mount everest?",
"actualOutput": "No clue, pretty tall I guess?",
"name": "Your Test Case Name"
},
"identifier": "run-399-102"
}`
req, err := http.NewRequest("POST", "https://api.confident-ai.com/v1/evaluate", strings.NewReader(body))
if err != nil {
panic(err)
}
req.Header.Set("CONFIDENT_API_KEY", "<PROJECT-API-KEY>")
req.Header.Set("Content-Type", "application/json")
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
out, err := io.ReadAll(res.Body)
if err != nil {
panic(err)
}
fmt.Println(string(out))
}
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class Example {
public static void main(String[] args) throws Exception {
String body = """
{
"metricCollection": "Collection Name",
"llmTestCases": {
"input": "How tall is mount everest?",
"actualOutput": "No clue, pretty tall I guess?",
"name": "Your Test Case Name"
},
"identifier": "run-399-102"
}""";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.confident-ai.com/v1/evaluate"))
.header("CONFIDENT_API_KEY", "<PROJECT-API-KEY>")
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(body))
.build();
HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
}
}
use serde_json::json;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let response = reqwest::Client::new()
.post("https://api.confident-ai.com/v1/evaluate")
.header("CONFIDENT_API_KEY", "<PROJECT-API-KEY>")
.json(&json!({
"metricCollection": "Collection Name",
"llmTestCases": {
"input": "How tall is mount everest?",
"actualOutput": "No clue, pretty tall I guess?",
"name": "Your Test Case Name"
},
"identifier": "run-399-102"
}))
.send()
.await?;
println!("{}", response.text().await?);
Ok(())
}
테스트 케이스 이름 짓기 (Name test cases)
식별자와 비슷하게, 테스트 케이스에 이름을 붙이면 회귀 테스트 중 서로 다른 테스트 런에서 테스트 케이스를 검색하고 매칭할 수 있어요.
Python
evaluate(
test_cases=[LLMTestCase(name="Any custom string", ...)],
metric_collection="..."
)
TypeScript
evaluate({
llmTestCases: [new LLMTestCase({ name: "Any custom string", ... })],
metricCollection: "..."
});
curl
Request (POST /v1/evaluate) — API reference
curl -X POST "https://api.confident-ai.com/v1/evaluate" \
-H "CONFIDENT_API_KEY: <PROJECT-API-KEY>" \
-H "Content-Type: application/json" \
-d '{
"metricCollection": "Collection Name",
"llmTestCases": {
"input": "How tall is mount everest?",
"actualOutput": "No clue, pretty tall I guess?",
"name": "Your Test Case Name"
},
"identifier": "run-399-102"
}'
import requests
response = requests.post(
"https://api.confident-ai.com/v1/evaluate",
headers={
"CONFIDENT_API_KEY": "<PROJECT-API-KEY>",
},
json={
"metricCollection": "Collection Name",
"llmTestCases": {
"input": "How tall is mount everest?",
"actualOutput": "No clue, pretty tall I guess?",
"name": "Your Test Case Name"
},
"identifier": "run-399-102"
},
)
print(response.json())
const response = await fetch("https://api.confident-ai.com/v1/evaluate", {
method: "POST",
headers: {
"CONFIDENT_API_KEY": "<PROJECT-API-KEY>",
"Content-Type": "application/json",
},
body: JSON.stringify({
"metricCollection": "Collection Name",
"llmTestCases": {
"input": "How tall is mount everest?",
"actualOutput": "No clue, pretty tall I guess?",
"name": "Your Test Case Name"
},
"identifier": "run-399-102"
}),
});
const data = await response.json();
console.log(data);
package main
import (
"fmt"
"io"
"net/http"
"strings"
)
func main() {
body := `{
"metricCollection": "Collection Name",
"llmTestCases": {
"input": "How tall is mount everest?",
"actualOutput": "No clue, pretty tall I guess?",
"name": "Your Test Case Name"
},
"identifier": "run-399-102"
}`
req, err := http.NewRequest("POST", "https://api.confident-ai.com/v1/evaluate", strings.NewReader(body))
if err != nil {
panic(err)
}
req.Header.Set("CONFIDENT_API_KEY", "<PROJECT-API-KEY>")
req.Header.Set("Content-Type", "application/json")
res, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer res.Body.Close()
out, err := io.ReadAll(res.Body)
if err != nil {
panic(err)
}
fmt.Println(string(out))
}
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class Example {
public static void main(String[] args) throws Exception {
String body = """
{
"metricCollection": "Collection Name",
"llmTestCases": {
"input": "How tall is mount everest?",
"actualOutput": "No clue, pretty tall I guess?",
"name": "Your Test Case Name"
},
"identifier": "run-399-102"
}""";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.confident-ai.com/v1/evaluate"))
.header("CONFIDENT_API_KEY", "<PROJECT-API-KEY>")
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(body))
.build();
HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
}
}
use serde_json::json;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let response = reqwest::Client::new()
.post("https://api.confident-ai.com/v1/evaluate")
.header("CONFIDENT_API_KEY", "<PROJECT-API-KEY>")
.json(&json!({
"metricCollection": "Collection Name",
"llmTestCases": {
"input": "How tall is mount everest?",
"actualOutput": "No clue, pretty tall I guess?",
"name": "Your Test Case Name"
},
"identifier": "run-399-102"
}))
.send()
.await?;
println!("{}", response.text().await?);
Ok(())
}
기본적으로 Confident AI는 인풋 매칭을 기반으로 테스트 케이스를 매칭하므로, 회귀 테스트를 위해 테스트 케이스에 이름을 붙이는 것은 엄격히 필수는 아니에요.