핵심 개념
Contexta는 Airflow처럼 머신러닝 혹은 딥러닝 프로젝트의 워크플로우를 실행하는 라이브러리가 아닙니다.
즉, 모델의 학습 · 추론 수행 · 평가 점수 개선에 직접적으로 개입하지 않습니다.
대신 이미 실행되는 워크플로우 속에서 향후에 등장할 결과를 다시 이해하는 데 필요한 근거를 남깁니다.
- 어떤
실행에서 값이 만들어졌는가 - 어느
단계에서 나온 결과인가 - 어떤 파일이나
배포와 연결되는가 - 그
기록을 신뢰해도 되는가
예를 들어 터미널에 다음 값만 출력되었다고 생각해 봅시다.
r2 = 0.453
이 숫자만으로는 다음 질문에 답하기 어렵습니다.
- 어떤 모델과 데이터로 계산한 값인가요?
- 학습 데이터 점수인가요, 테스트 데이터 평가 점수인가요?
- 어느
실행에서 나온 값인가요? - 같은 조건의 이전
실행보다 좋아졌나요? - 평가
기록이 빠짐없이 남았나요? - 이 점수를 만든 모델 파일은 어디에 있나요?
Contexta는 숫자 하나를 넘어 그 숫자가 속한 실행과 단계 · 결과물 · 완전성 그리고 이후 비교와 추적에 필요한 관계를 함께 남기도록 돕습니다.
이 문서에서는 그 구조를 설명합니다.
- 간단한 예제를 기준으로
workspace,project,run,stage,record같은 핵심 용어가 어디에 놓이는지 살펴봅니다. - 확장된 예제에서
batch,sample,deployment,lineage,provenance등의 개념이 어떤 질문에 답하는지 설명합니다.
이 문서에서 사용할 예제
이 문서에서는 시작하기에서 사용하는 간단한 머신러닝 작업을 기준으로 개념을 설명합니다.
목표 : diabetes 데이터를 이용해 질병 진행 수치를 예측
모델 : scikit-learn LinearRegression
학습 : train split으로 모델 학습
평가 : test split 예측 후 r2 계산
관측 결과 : evaluate 단계의 r2 metric 기록
실행되는 코드는 다음과 같습니다.
features, targets = load_diabetes(return_X_y=True)
train_x, test_x, train_y, test_y = train_test_split(
features, targets, test_size=0.2, random_state=42
)
model = LinearRegression()
ctx = Contexta(workspace=".contexta", config={"project_name": "getting-started"})
with ctx.run("training") as run:
with run.stage("train"):
model.fit(train_x, train_y)
with run.stage("evaluate") as stage:
score = r2_score(test_y, model.predict(test_x))
stage.metric("r2", score, unit="ratio")
예제는 다음과 같은 값을 출력합니다.
Captured run: run:getting-started.training
Measured r2: 0.453
중요한 점은 Contexta가 이 계산을 대신하지 않는다는 것입니다.
model.fit()과 model.predict()는 해당 모델의 코드가 직접 실행하며, Contexta는 그 실행 주변에서 관측 가능한 기록을 남깁니다.
한눈에 보는 전체 지도
위의 예제에서 각 개념은 다음 위치에 놓입니다.
.contexta/ # Workspace
└─ project: getting-started # Project
└─ run: training # Run
├─ stage: train # Stage
│ └─ model.fit(train_x, train_y) # 실제 ML 작업
└─ stage: evaluate # Stage
├─ model.predict(test_x) # 실제 ML 작업
├─ r2_score(test_y, predictions) # 실제 ML 작업
└─ metric: r2 = 0.453 # Record / Metric
├─ run_ref: ...training
├─ stage_ref: ...evaluate
├─ complete: yes
└─ degraded: no
첫 예제는 이 구조의 가장 작은 형태입니다.
워크플로우가 커질수록 아래 예시와 같이 같은 실행 안에 더 많은 증거를 연결할 수 있습니다.
run: training-candidate-v2
├─ stage: prepare
│ └─ event: diabetes dataset loaded
├─ stage: train
│ ├─ span: fit took 12 ms
│ └─ artifact: linear-regression.joblib
├─ stage: evaluate
│ ├─ metric: r2 = 0.501
│ ├─ metric: mae = 41.2
│ ├─ sample: patient-row-17 prediction error = 96.4
│ └─ report artifact: evaluation-summary.json
└─ deployment: staging/model-v2
└─ uses artifact: linear-regression.joblib
구분해야 할 것은 실제 작업과 그 작업을 설명하는 기록입니다.
model.fit()과model.predict()는 실제 결과를 만드는 코드입니다.- r2 metric, stage identifier, artifact 관계, degraded 상태는 그 결과를 나중에 다시 설명하기 위한 관측 정보입니다.
개념별 빠른 대응표
| Concept | 예제에서 확인 가능한 것 | 이를 통해 답할 수 있는 질문 |
|---|---|---|
| Workspace | .contexta/ | evidence는 어디에 저장되나요? |
| Project | getting-started | 관련 실행들을 어떤 범위로 묶나요? |
| Run | training | 이번에 학습/평가를 진행한 사항은 무엇인가요? |
| Stage | train, evaluate | 이 값은 어느 구간에서 생겼나요? |
| Operation | model.predict(test_x), r2_score(...) | 단계 안의 어느 세부 작업이 느리거나 실패했나요? |
| Record | r2 메트릭 기록 | 실행 중 실제로 관찰한 사실은 무엇인가요? |
| Event | dataset_loaded, checkpoint_saved | 실행 중 어떤 일이 일어났나요? |
| Metric | r2 = 0.453, mae = 41.2 | 성능이나 품질은 어땠나요? |
| Span | fit took 12 ms | 어디에서 시간이 걸렸나요? |
| Degraded state | capture_gap | 이 결과를 해석할 때 주의할 점이 있나요? |
| Batch | holdout-chunk-03 | 큰 평가 데이터를 어느 묶음에서 처리했나요? |
| Sample | patient-row-17 | 어떤 개별 입력에서 문제가 있었나요? |
| Artifact | linear-regression.joblib | 어느 실행이 이 파일을 만들었나요? |
| Deployment | staging/model-v2 | 실제 환경에는 어느 결과물이 올라갔나요? |
| Lineage | run → artifact → deployment | 결과물이 어디서 와서 어디에 사용되었나요? |
| Provenance | sklearn 버전, 데이터 split seed | 같은 결과를 어떻게 설명하거나 재현하나요? |
| Query | training 실행의 r2 조회 | 저장한 evidence를 어떻게 다시 읽나요? |
| Compare | baseline 0.453 vs candidate 0.501 | 새 시도가 더 좋아졌나요? |
| Diagnostics | 높은 점수지만 capture_gap 있음 | 무엇을 먼저 확인해야 하나요? |
| Report | 평가 비교 요약 문서 | 팀에게 어떤 결론과 근거를 보여주나요? |
| Recovery | 기록 백업 및 replay | evidence를 어떻게 보존하고 다시 사용하나요? |
저장되는 것과 해석되는 것
Contexta의 개념은 크게 세 층으로 나눠 보면 이해하기 쉽습니다.
첫째, 실행 구조는 증거가 놓일 주소입니다. project, run, stage, operation은 이것이 어떤 작업의 어느 위치에서 나온 값인지 설명합니다.
둘째, 관측 증거는 그 위치에서 실제로 남긴 사실에 대한 값입니다. metric, event, span, artifact, degraded state가 여기에 속합니다.
셋째, 조사 결과는 저장된 증거를 읽고 사람이 판단하기 좋게 정리한 결과입니다. query, compare, diagnostics, report가 여기에 속합니다.
| 구분 | 무엇인가요? | 이 사례의 예 |
|---|---|---|
| 실행 구조 | 작업의 위치를 나타내는 뼈대 | getting-started 프로젝트에서 training의 evaluate단계를 실행함. |
| 관측 증거 | 실행 중 직접 기록된 사실 | r2 = 0.453, 완료 상태, 모델 파일 |
| 조사 결과 | 저장된 증거를 읽고 만든 판단 자료 | 실행 비교, 진단, 평가 리포트 |
그리고 이 3개의 계층은 아래와 같은 구조를 가집니다.
[실행 구조]
Project → Run → Stage → Operation
│
▼
[관측 evidence]
Event / Metric / Span / Artifact / Degraded state
│
▼
[조사 결과]
Query / Compare / Diagnostics / Report
단순히 r2 = 0.453이라는 값만 저장하면 숫자는 남지만 의미가 불안정합니다.
반면 그 값이 training의 evaluate 단계에서 나왔다는 것까지 남긴다면, 이 평가 결과를 기반으로 다시 해석하고 다른 실행과 비교할 수 있습니다.
워크스페이스 (Workspace)
워크스페이스는 Contexta가 증거를 로컬에 저장하는 공간입니다.
기본적으로 다음의 폴더를 사용합니다.
.contexta/
앞선 예제를 실행하면, 다음과 같이 캡처 기록을 확인할 수 있습니다.
.contexta/
└─ cache/
└─ capture/
└─ record.jsonl
워크스페이스는 단순한 로그 폴더를 넘어, 같은 프로젝트에서 나오는 증거들을 함께 다루기 위한 저장 경계입니다.
로컬 기반이라는 점도 중요합니다. Contexta를 사용할 때는 별도의 외부 서비스를 먼저 준비하지 않아도 됩니다.
개발자는 자신의 워크플로우를 실행한 뒤 바로 로컬에 남은 증거를 확인할 수 있습니다.
동시에 로컬에 저장된 기록이므로 운영 작업의 대상도 분명해집니다.
| 워크스페이스가 없다면 | 워크스페이스가 있다면 |
|---|---|
터미널을 닫은 뒤 r2 출력이 어디서 나왔는지 추적하기 어렵습니다. | 해당 실행에 대한 기록을 다시 읽고 평가 단계와 연결할 수 있습니다. |
| 결과 파일과 실행 맥락을 수동으로 관리해야 합니다. | 기록, 아티팩트, 관계 정보를 한 공간에서 다룰 수 있습니다. |
| 이전 실행과 비교하기 위한 재료를 직접 모아야 합니다. | 저장된 증거들을 조회하고 비교하기 위한 입력값으로 사용할 수 있습니다. |
워크스페이스는 Contexta가 알아서 모델을 저장하는 비밀 폴더가 아닙니다. 사용자가 남기기로 한 Observability 증거가 보관되는 로컬 저장소입니다.
프로젝트 (Project)
프로젝트는 서로 비교하고 조사하고자 하는 실행들을 묶는 범위입니다. 프로젝트는 '폴더 이름' 이상의 역할을 합니다.
시간이 지날수록 실행 기록은 많아지는데, 모든 실행을 서로 비교할 수 있는 것은 아닙니다.
diabetes 진행 예측 모델을 개선하려는 실험의 결과와 이미지 분류 모델을 학습한 결과의 accuracy를 같은 후보군처럼 비교할 수 없기 때문입니다.
프로젝트는 이 실행들이 같은 문제 · 같은 기능 · 같은 평가 목적 · 같은 운영 책임 범위 안에 속한다는 경계를 제공합니다.
이 경계를 통해 실행 간 메트릭 비교, trend 확인, 리포트 생성, 배포 이력 추적 등이 의미를 가질 수 있습니다.
앞선 예제에서는 다음의 설정이 프로젝트 이름을 만듭니다.
ctx = Contexta(workspace=".contexta", config={"project_name": "getting-started"})
프로젝트 안에는 여러 실행이 쌓일 수 있습니다.
project: getting-started
├─ run: training-baseline
├─ run: training-feature-normalized
└─ run: training-new-split
| 상황 | 프로젝트로 묶는 이유 |
|---|---|
| 동일 데이터에 다른 모델을 시험함 | 후보 실행을 한 곳에서 비교하기 위해 |
| 동일 모델을 정기적으로 재학습함 | 시간에 따른 성능 변화를 추적하기 위해 |
| 하나의 평가 파이프라인을 반복 실행함 | 동일 목적의 증거와 리포트를 모으기 위해 |
프로젝트가 없다면 r2 = 0.453과 r2 = 0.501이 같은 문제에 대한 실험인지, 서로 무관한 값인지부터 사람이 다시 한 번 확인해야 합니다.
실행 (Run)
실행은 한 번 수행한 워크플로우의 기록 단위입니다.
앞선 예제에서는 아래의 부분에서 실행에 대한 코드를 볼 수 있습니다.
with ctx.run("training") as run:
...
그 결과로, 기록에는 다음과 같은 실행 식별자가 연결됩니다.
run:getting-started.training
실행은 단순히 Python 프로세스가 한 번 시작됐다는 뜻이 아닙니다.
향후에 실험을 관리하는 과정에서 성공 여부 · 결과값 · 산출물 · 완전성 등을 하나의 단위로 확인하고자 하는 논리적 작업입니다.
예를 들어 한 프로세스 안에서 여러 종류의 모델 후보를 평가한다면 후보마다 별도 실행으로 기록할 수 있습니다.
반대로 여러 내부 단계를 거치더라도, 하나의 실행으로 관리하고 싶다면 하나의 nightly batch를 하나의 실행으로 묶을 수 있습니다.
| 실행 | 실제로 수행한 일 | 기록할 수 있는 결과 |
|---|---|---|
training-baseline | 기본 feature로 LinearRegression 학습/평가 | r2 = 0.453, mae = 44.1 |
training-feature-normalized | 정규화 feature로 같은 모델 학습/평가 | r2 = 0.501, mae = 41.2 |
training-svm-candidate | SVM 후보 학습/평가 | r2, mae, 학습 시간 |
실행을 통해서 우리는 다음과 같은 질문에 답할 수 있습니다.
- 후보
실행중 어느 것이 가장 좋았나요? - 이번
실행의 평가 결과는 완전하게 기록되었나요? - 이 모델 파일은 어떤
실행에서 나왔나요?
Contexta에서 이루어지는 대부분의 조사 과정은 먼저 실행 정보를 찾고, 그 실행에 연결된 증거를 읽는 방식으로 진행됩니다.
단계 (Stage)
단계는 실행을 의미 있는 구간으로 나눈 것입니다.
앞선 예제에서는 2개의 단계가 존재합니다.
run: training
├─ stage: train
│ └─ model.fit(train_x, train_y)
└─ stage: evaluate
└─ r2_score(test_y, model.predict(test_x))
단계에서는 단순히 함수 이름을 기록하는 것이 아니라, 관찰자 입장에서 의미 있는 구간을 표시합니다.
대부분의 경우에는 prepare, train, evaluate, export처럼 워크플로우의 목적을 드러내는 이름을 사용하는 것이 바람직합니다.
단계가 존재하지 않는다면, 성격이 다른 여러 증거가 한 실행 안에서 뒤섞일 가능성이 높습니다.
- 학습
단계의 loss는 모델이 학습 데이터에 적응하는 과정을 보여줍니다. - 평가
단계의r2는 테스트 데이터에서의 일반화 성능을 보여 줍니다.
2개의 성능 지표는 모두 숫자지만 같은 의미로 비교할 수 없습니다.
앞선 예제를 다시 한 번 보면, r2 기록에는 다음처럼 평가 단계가 명시됩니다.
stage_execution_ref: stage:getting-started.training.evaluate
| 기록 | 해석 |
|---|---|
train / r2 = 0.92 | 학습 데이터에 잘 맞았다는 값일 수 있습니다. |
evaluate / r2 = 0.45 | 처음 보는 테스트 데이터에 대한 일반화 성능입니다. |
단계 정보 없는 r2 = 0.45 | 어떤 성능인지 판단하기 어렵습니다. |
단계는 숫자에 의미를 붙이는 가장 기본적인 실행 맥락입니다.
작업 (Operation)
작업은 단계 안에서 나뉘는 더 작은 단위입니다.
작은 예제에서는 train과 evaluate와 같은 단계만으로 충분합니다.
stage: evaluate
├─ operation: load-test-split
├─ operation: predict
├─ operation: calculate-r2
└─ operation: write-evaluation-report
하지만 위의 내용처럼 평가 단계가 커져서 데이터 로딩부터 예측, 점수 계산, 리포트 저장까지 모두 포함한다면 어떻게 될까요?
단계만으로는 병목이나 실패 위치를 찾기 어려울 것입니다. 이때 작업을 추가하면 조사 범위를 더 좁힐 수 있습니다.
| 문제가 보이는 현상 | 단계만 기록한 경우 | 작업까지 기록한 경우 |
|---|---|---|
| 평가 단계가 40초 걸림 | evaluate가 느렸다는 사실만 압니다. | predict가 38초 걸렸는지 확인할 수 있습니다. |
| 결과 리포트가 없음 | 평가 쪽 문제라는 것만 압니다. | write-evaluation-report 실패 여부를 좁혀 볼 수 있습니다. |
모든 함수 호출을 작업으로 기록할 필요는 없습니다. 작업은 성능 · 장애 · 비용 · 품질의 원인을 따로 묻고 싶은 경계에 배치하면 됩니다.
기록 (Record)
기록은 실행 과정에서 직접 관찰해서 남긴 증거입니다.
앞선 예제는 evaluate 단계에서 r2 metric 기록를 남깁니다. 중요한 부분은 다음과 같습니다.
{
"payload_type": "MetricRecord",
"payload": {
"envelope": {
"record_type": "metric",
"run_ref": "run:getting-started.training",
"stage_execution_ref": "stage:getting-started.training.evaluate",
"completeness_marker": "complete",
"degradation_marker": "none"
},
"payload": {
"metric_key": "r2",
"value": 0.4526027629719198,
"unit": "ratio"
}
},
"sink_name": "local-jsonl"
}
기록에는 값 자체와 그 값을 해석하기 위한 정보가 함께 들어갑니다.
값은 r2 = 0.4526...처럼 관측 결과를 담고, 참조 정보는 그 값이 어느 실행과 단계에 속하는지 알려 줍니다.
완전성 또는 불완전한 상태는 이 증거를 어느 정도 신뢰해도 되는지 설명합니다.
| 기록 조각 | 의미 |
|---|---|
MetricRecord | 측정값을 남긴 기록입니다. |
metric_key: r2 | 모델의 테스트 평가 품질을 측정한 지표입니다. |
value: 0.4526... | 이번 실행에서 실제 계산된 값입니다. |
run_ref | 어느 실행의 값인지 알려 줍니다. |
stage_execution_ref | 평가 단계에서 계산된 값임을 알려 줍니다. |
complete, none | 이 기록은 누락이나 저하 표시 없이 남았습니다. |
local-jsonl | 로컬 JSON Lines 저장 경로로 방출되었습니다. |
기록은 단순 로그를 위한 줄이 아닙니다. 향후에 찾아보거나 비교하거나 진단하거나 리포트를 만들기 위한 입력이 될 관측된 사실입니다.
이벤트 (Event)
이벤트는 실행 중 어떤 일이 발생했는가에 대한 정보를 남기는 기록입니다.
이벤트는 단순히 숫자 크기를 비교하는 상황보다는 실행의 흐름과 전환점을 설명할 때 유용합니다.
아래와 같은 상황에서는 메트릭보다 이벤트로 남기는 편이 더 분명합니다.
- 데이터셋이 로드되었는가?
- fallback 경로가 사용되었는가?
- checkpoint가 저장되었는가?
- validation이 중단되었는가?
앞에서 제시된 선형 회귀에서의 워크플로우를 조금 확장하면 다음의 이벤트가 유용할 수 있습니다.
| 이벤트 예 | 왜 남기나요? |
|---|---|
dataset_loaded: diabetes | 어떤 데이터를 대상으로 실행했는지 확인합니다. |
split_created: random_state=42 | 평가 데이터를 동일하게 분리된 게 맞는지 설명합니다. |
model_saved: linear-regression.joblib | 모델 파일이 생성된 시점을 찾습니다. |
validation_failed: missing_target_rows=2 | 점수가 의심스러운 이유를 남깁니다. |
모든 로그 메시지를 이벤트로 남길 필요는 없습니다. 나중에 판단에 영향을 줄 수 있는 상태 변화나 중요한 사건을 중심으로 기록하는 것이 좋습니다.
메트릭 (Metric)
메트릭은 비교 가능한 측정값입니다.
메트릭은 단순히 숫자를 넘어 같은 의미와 조건으로 반복해서 해석할 수 있어야 한다는 것이 중요합니다.
| 메트릭 | 예시 값 | 무엇을 알려 주나요? |
|---|---|---|
r2 | 0.453 | 예측이 테스트 정답의 변화를 얼마나 설명하는지 보여 줍니다. |
mae | 44.1 | 예측과 정답 차이의 평균 크기를 보여 줍니다. |
train_duration_ms | 12.0 | 학습 처리 시간 비교에 사용됩니다. |
artifact_size_bytes | 864 | 저장된 모델 산출물 크기 변화에 사용됩니다. |
r2, mae, latency처럼 일관된 이름, 단위, 관측 대상, 실행 단계가 존재해야 실행 간 변화가 의미를 갖습니다.
baseline run candidate run
r2 = 0.453 r2 = 0.501 +0.048
mae = 44.1 mae = 41.2 -2.9
메트릭은 중요한 증거지만, 그 자체로 의미가 있는 것은 아닙니다.
후보 모델의 r2가 높아도 처리 시간이 과도하게 늘었거나, 평가 기록이 불완전하거나, 배포할 아티팩트가 없으면 판단은 달라질 수 있습니다.
스팬 (Span)
스팬은 작업이 진행되는 구간에 대한 시작 시간부터 종료 시간까지의 시간 기록입니다.
스팬은 무엇을 수행했는지, 그리고 그 수행에 얼마나 시간이 들었는지를 함께 보여 줍니다.
stage: evaluate total: 43 ms
├─ span: predict 38 ms
└─ span: calculate-r2 5 ms
전체 구간에 대한 메트릭 하나만 남기면 실행이 느렸다는 사실은 알 수 있지만, 어느 내부 동작이 느렸는지는 알기 어렵습니다.
| 메트릭만 기록했다면 | 스팬도 기록했다면 |
|---|---|
후보 모델의 r2가 같다는 것만 압니다. | 품질은 같지만 predict가 느려졌다는 사실도 찾을 수 있습니다. |
머신러닝 혹은 딥러닝 워크플로우에서는 품질 뿐만 아니라 처리 시간도 중요한 판단 기준이 될 수 있습니다.
이런 식으로 스팬은 품질과 별도로 성능 회귀나 병목을 조사할 때 사용합니다.
불완전한 상태 (Degraded State)
높은 메트릭이 항상 믿을 만한 결과를 전제하지는 않습니다.
평가 중 일부 증거가 누락되었다면 Contexta는 그 사실을 숨기지 않고 불완전한 상태로 남길 수 있습니다.
이때, 불완전한 상태는 실행이 실패했다는 뜻이 아닙니다.
run: training-feature-normalized
├─ metric: r2 = 0.501
└─ degraded: capture_gap
└─ evaluation samples 17-20 were not captured
실행이 완료되어 메트릭과 아티팩트를 만들었더라도, 아래와 같은 상황이 생겼을 때 그 문제 상황을 인식할 수 있어야 합니다.
- 일부
샘플을 수집하지 못한 경우 - 입력해야 할 메타데이터가 빠진 경우
- 재생 과정에서 간극이 생긴 경우
| 보이는 것 | 성급한 결론 | 확인해야 하는 것 |
|---|---|---|
후보 점수 0.501이 baseline 0.453보다 높음 | 새 후보를 선택합니다. | 누락된 평가 항목이 점수 해석에 영향을 주는지 조사합니다. |
즉, 불완전한 상태는 실패 선언이 아니라 결과를 해석할 때 신뢰 범위를 함께 보여 주는 증거입니다.
배치 (Batch)
배치는 한 단계에서 처리하는 데이터 묶음입니다.
앞선 예제에서 진행한 작은 평가에서는 전체 테스트 split을 한 번에 예측하므로 배치를 따로 기록할 필요가 없습니다.
하지만 nightly prediction처럼 많은 입력을 처리한다면 배치 별 상태가 중요해질 수 있습니다.
run: nightly-inference-2026-05-26
└─ stage: predict
├─ batch: holdout-chunk-01 rows=1-1000 latency=1.2 s
├─ batch: holdout-chunk-02 rows=1001-2000 latency=1.3 s
└─ batch: holdout-chunk-03 rows=2001-3000 degraded=input_missing
전체 실행이 성공으로 끝나도 특정 청크에서 지연 시간이 튀었거나 데이터가 빠질 수 있습니다.
배치 기록은 이런 부분 장애나 편향된 처리 구간을 찾는 데 도움이 됩니다.
배치는 샘플과 다릅니다. 배치는 여러 항목을 함께 처리한 묶음이고, 샘플은 그 안의 개별 입력이나 결과입니다.
모든 샘플을 저장하기 어렵더라도 배치 별 처리량, 지연, 누락 상태를 남기면 운영 수준의 진단에 필요한 정보를 얻을 수 있습니다.
자세한 내용은 배치, 샘플 & 배포를 참고하세요.
샘플 (Sample)
샘플은 실행 중 관찰한 개별 입력 또는 결과이며, 집계용 메트릭 뒤에 숨어 있는 구체적인 실패를 보여 줍니다.
stage: evaluate
├─ metric: r2 = 0.501
├─ sample: patient-row-17 actual=202 predicted=105 abs_error=97
└─ sample: patient-row-42 actual=89 predicted=91 abs_error=2
전체 평균 오차(SE)나 전체 정확도는 모델의 전반적인 성능을 요약하지만, 어떤 입력에서 크게 실패했는지는 알려 주지 않습니다.
| 메트릭이 답하는 질문 | 샘플이 답하는 질문 |
|---|---|
| 전체적으로 모델이 얼마나 잘 맞나요? | 정확히 어떤 입력에서 크게 틀렸나요? |
샘플은 특히 조심해서 다뤄야 합니다.
실제 입출력에는 개인정보 · 민감 데이터 · 큰 페이로드가 포함될 수 있고, 모든 항목을 저장하면 비용과 검토량도 증가합니다.
따라서 오류가 큰 항목, 정책 검토 대상, 대표 샘플처럼 목적이 분명한 범위에서 사용하는 것이 좋습니다.
모든 샘플을 남기지 않아도 됩니다. 중요한 것은 무엇을 저장했고 무엇을 저장하지 않았는지 해석할 수 있게 남기는 것입니다.
아티팩트 (Artifact)
아티팩트는 실행이 만들어 낸 저장 가능한 결과물입니다.
앞선 예제에서는 메트릭만 기록하고 모델 파일을 저장하지 않습니다. 하지만, 실제 모델 후보를 전달하거나 배포하려면 보통 다음과 같은 아티팩트가 생깁니다.
run: training-feature-normalized
├─ artifact: linear-regression.joblib 학습된 모델 파일
├─ artifact: evaluation-summary.json r2, mae 결과 요약
└─ artifact: feature-config.json 사용된 전처리 설정
메트릭이 모델의 품질을 설명한다면, 아티팩트는 그 품질을 낸 구체적인 산출물을 가리킵니다.
특정 실행에서 좋은 점수가 기록되어도, 해당 모델의 체크포인트 · 전처리 설정 · 평가 출력 파일 등이 어떤 것인지 연결되지 않으면 결과를 검토하거나 전달하거나 재사용하기 어렵습니다.
| 파일만 폴더에 있다면 | 아티팩트로 연결되어 있다면 |
|---|---|
| 어느 실행이 만들었는지 파일명에 의존합니다. | 생성 실행과 단계까지 추적할 수 있습니다. |
| 점수와 모델 파일의 관계를 수동으로 기록합니다. | 평가 증거와 모델 파일을 함께 조사할 수 있습니다. |
실험 이후에 배포되는 것은 보통 메트릭 상의 숫자가 아니라, 모델 번들 · 체크포인트 · 프롬프트 템플릿 · 평가 보고서 같은 결과물입니다.
따라서 어떤 파일을 배포했는지와 그 파일을 선택하게 한 평가 기록은 무엇인지가 연결되는 기록에서 아티팩트가 필요합니다.
배포 (Deployment)
배포는 학습 실행의 결과물이 실제 사용 환경으로 이동하는 일을 나타냅니다.
학습 실행과 평가 메트릭이 잘 기록되어 있어도, 실제 스테이징 환경 또는 운영 환경에서 어느 아티팩트가 언제 적용되었는지 모르면 운영 상태와 실험 결과를 연결할 수 없습니다.
따라서 배포에 대한 증거는 가장 좋은 후보를 찾는 것이 아니라 실제로 사용된 후보가 무엇이었는지를 확인하게 합니다.
project: diabetes-progression
├─ run: training-feature-normalized
│ ├─ metric: r2 = 0.501
│ └─ artifact: linear-regression.joblib
└─ deployment: staging/model-v2
└─ deployed artifact: linear-regression.joblib
이러한 연결이 존재한다면, 운영 중 문제가 발견됐을 때 다음 질문에 답할 수 있습니다.
- 현재 스테이징 환경에서 사용 중인 모델은 어느 학습
실행에서 나왔나요? - 그 실행의 평가
메트릭은 무엇이었나요? - 당시 기록에
불완전한 상태가 있었나요?
이처럼 배포는 실험과 운영 사이의 추적 가능성을 유지하는 연결점입니다.
리니지 (Lineage)
리니지는 증거와 결과물이 이어지는 경로를 보여줍니다.
데이터 split
→ training-feature-normalized 실행
→ evaluation metric: r2 = 0.501
→ model artifact: linear-regression.joblib
→ staging/model-v2 배포
→ 운영 진단 또는 롤백 판단
모델의 아티팩트 중 하나를 보았을 때 아래와 같은 사항들을 따라갈 수 있어야 결과의 영향 범위를 이해할 수 있습니다.
- 그 파일이 어느
실행의 어느단계에서 나왔는가? - 어느
배포가 그것을 사용했는가? - 후속
리포트가 어느메트릭을 요약했는가?
| 질문 | 리니지를 따라 확인하는 경로 |
|---|---|
| 이 모델 파일은 어디서 나왔나요? | artifact → producing run |
| 현재 배포된 모델의 평가 점수는 무엇인가요? | deployment → artifact → run → metric |
| 문제가 있는 실행의 결과물이 어디에 쓰였나요? | run → artifact → downstream deployment |
리니지는 순방향과 역방향 모두에서 유용합니다.
- 좋은 후보
실행에서 출발해 어느 환경에 승격되었는지 확인할 수 있습니다. - 운영 환경 문제에서 출발해 원인이 된
아티팩트와 학습실행으로 역추적할 수 있습니다.
출처 (Provenance)
출처는 결과가 만들어진 조건을 설명합니다.
리니지가 '무엇이 무엇으로 이어졌는가'를 말한다면, 출처는 '어떤 조건에서 그 결과가 만들어졌는가'를 말합니다.
| 맥락 정보 | 이 사례의 예 | 왜 필요한가요? |
|---|---|---|
| 데이터셋 | sklearn.datasets.load_diabetes | 어떤 문제를 평가했는지 확인합니다. |
| split 조건 | test_size=0.2, random_state=42 | 동일한 평가 조건인지 확인합니다. |
| 모델 | LinearRegression | 어떤 알고리즘의 결과인지 확인합니다. |
| 코드/패키지 버전 | scikit-learn, Contexta 버전 | 나중에 결과 차이를 설명합니다. |
| 캡처 상태 | complete, degradation_marker=none | 기록 자체를 얼마나 신뢰할지 판단합니다. |
두 값이 같은 이름의 메트릭이라도 데이터, 코드, 환경, 설정이 다르면 공정하게 비교하기 어렵습니다.
lineage 무엇이 무엇으로 이어졌는가?
provenance 어떤 조건에서 그 결과가 만들어졌는가?
만약 test split이 변경되었거나 라이브러리 버전이 달라졌다면 메트릭의 변화가 모델 개선 때문인지 환경 변화 때문인지 분리하기 어렵습니다.
이처럼 출처는 결과를 설명하고 비교할 때 필요한 조건을 보존합니다.
조회 (Query)
조회는 저장된 증거를 나중에 다시 읽기 위해 수행하는 동작입니다.
수집하는 것이 기록을 남기는 '쓰기' 방향의 행동이라면, 조회는 이미 존재하는 기록에 대해 질문에 필요한 부분을 찾아서 읽는 조사 방향의 행동입니다.
증거가 단순히 저장되어 있기만 한다고 해서 충분하지 않습니다.
필요한 실행을 찾고, 그 실행의 단계와 메트릭을 읽고, 관련 아티팩트나 불완젇한 상태를 확인할 수 있어야 실제 검토에 사용할 수 있습니다.
위의 예제를 실행한 뒤에는 다음과 같은 조사 흐름을 생각할 수 있습니다.
| 찾고 싶은 것 | 확인하려는 내용 |
|---|---|
run:getting-started.training | 이 실행에 어떤 단계와 메트릭이 남았는지 |
stage:...evaluate | 평가 단계에서 어떤 값이 측정되었는지 |
metric_key: r2 | 실행별 평가 점수를 수집할 수 있는지 |
| 불완전한 상태의 기록 | 신뢰하기 전에 주의할 실행이 있는지 |
조회 단계에서는 아직 결론을 내리지 않아도 됩니다. 이 실행에서 무엇이 기록됐는지 정확하게 회수하는 것이 첫 역할입니다.
- 회수한
증거를 바탕으로실행간 차이를 계산하면비교가 됩니다. - 의심되는 신호를 해석하면
진단이 됩니다. - 사람이 읽을 수 있는 산출물로 정리하면
리포트가 됩니다.
비교 (Compare)
비교는 같은 프로젝트에 속한 실행들을 나란히 놓고 차이를 비교하는 기능입니다.
여기서의 비교는 단순히 숫자 간의 차를 구하는 작업이 아니며, 아래와 같은 상황일 때 그 의미를 가집니다.
- 두
실행이 같은 목적을 가지고 있는가? - 같은 종류의 증거를 남겼는가?
- 평가 조건이 비교 가능한가?
- 어느 한쪽의
레코드가불완전한 상태는 아닌가?
project: diabetes-progression
baseline candidate
run training-v1 training-v2
model LinearRegression LinearRegression + scaling
r2 0.453 0.501
mae 44.1 41.2
capture state complete complete
decision - candidate 검토 가능
비교 대상은 메트릭에만 한정되지 않습니다.
특정 단계가 새로 추가됐는지, 지연 시간이 늘었는지, 새 아티팩트가 만들어졌는지, 결과 리포트가 다른 결론을 내는지도 비교할 수 있습니다.
비교에서 중요한 점은 단순히 메트릭 차이만 보는 것이 아니라 동일한 평가 조건과 완전한 기록을 바탕으로 차이를 읽는 것입니다.
진단 (Diagnostics)
진단은 현재 저장되어 있는 증거에서 먼저 확인할 위험 신호를 찾는 기능입니다.
이때 진단은 사람이 읽을 모든 기록를 대신 읽고 자동으로 정답을 선언하는 것이 아닙니다.
저장된 증거가 많아질수록, 울는 어떤 실행과 단계를 우선적으로 확인해야 하는지 판단하기 어려워집니다.
이러한 상황에서 진단은 누락된 메트릭, 불완전한 상태, 예상하지 않은 관계, 오래된 아티팩트의 사용과 같이 먼저 확인해야 할 단서를 보여줍니다.
| 진단 신호 | 이 사례에서 뜻하는 것 | 다음 확인 |
|---|---|---|
| 평가 메트릭 없음 | 모델은 학습됐지만 성능 판단 근거가 없습니다. | evaluate 단계가 실행됐는지 확인 |
capture_gap | 일부 증거가 저장되지 않았습니다. | 누락 범위와 메트릭 신뢰성 확인 |
| 증거 없음 | 좋은 점수의 모델을 전달하거나 배포할 파일이 없습니다. | 저장 단계 또는 파일 연결 확인 |
| 배포가 오래된 아티팩트 사용 | 최신 후보가 실제 환경에 반영되지 않았습니다. | 배포 관계와 승인 기록 확인 |
예를 들어 평가 메트릭이 없다는 진단은 모델이 반드시 실패했다는 뜻이 아니라, 모델 선택을 뒷받침할 관측 근거가 현재 레코드에 없다는 뜻입니다.
사용자는 이를 보고 evaluate 단계가 실행되지 않았는지, 수집만 누락됐는지, 잘못된 실행을 보고 있는지 등을 확인할 수 있습니다.
리포트 (Report)
리포트는 저장된 증거를 리뷰 가능한 형식으로 정리한 결과물입니다.
원시 상태의 레코드를 직접 읽기 어려운 사람에게도 의사 결정을 위한 근거를 전달하는 계층이라고 할 수 있습니다.
여러 메트릭, 비교 결과, 아티팩트 위치, 완전성 상태를 하나의 검토 문맥으로 정리하면, 팀원이 JSONL 파일이나 내부 저장 구조를 직접 읽지 않고도 후보 승인 여부를 검토할 수 있습니다.
예를 들어 후보 모델을 검토하는 리포트에는 다음 정보가 담길 수 있습니다.
Evaluation Report: training-feature-normalized
Model LinearRegression + scaling
Evaluation stage evaluate
r2 0.501 (+0.048 vs baseline)
mae 41.2 (-2.9 vs baseline)
Capture status complete
Model artifact linear-regression.joblib
Recommendation staging 검토 대상으로 올릴 수 있음
리포트는 증거 원본이 아니기 때문에, 어느 실행과 레코드를 바탕으로 작성됐는지 추적할 수 있어야 합니다.
좋은 리포트는 결론만 제시하는 문서가 아니라, 필요할 때 근거 레코드와 아티팩트로 돌아갈 수 있는 입구입니다.
복구 (Recovery)
복구는 이미 저장된 증거를 보존하거나 다른 위치에서 다시 사용할 수 있게 하는 기능입니다.
Observability 데이터는 당장의 화면 확인에만 쓰이는 임시 출력이 아닙니다.
모델이 왜 선택되었는지, 특정 배포가 어떤 평가 근거를 가졌는지, 장애 당시 무엇이 기록되었는지 설명해야 할 시점은 보통 실행이 끝난 뒤입니다.
복구는 단순한 파일 복사보다 넓은 개념입니다.
- 백업은 조사 가능한 히스토리를 보존합니다.
- 복원은 그 히스토리를 다시 사용할 수 있게 합니다.
- 재생은 저장된
레코드를 다시 처리하거나, 다른 조사 흐름에서 활용하게 합니다.
| 상황 | 복구 작업이 필요한 이유 |
|---|---|
| 워크스페이스를 백업함 | 실험 기록과 평가 근거를 보존하기 위해 |
| 다른 환경에서 레코드를 재생함 | 같은 증거를 다시 조사하기 위해 |
| 손상 또는 이동 후 복원함 | 과거 실행과 배포 추적을 잃지 않기 위해 |
모델 아티팩트만 남고 그것을 선택한 메트릭과 리니지가 사라진다면 운영 판단의 근거 역시 사라집니다.
모델 자체뿐 아니라 모델을 선택한 근거도 복원할 수 있어야 합니다.
다음 읽을거리
- 시작하기: 위 최소 사례를 직접 실행합니다.
- 증거 캡처: workflow별 evidence 기록을 봅니다.
- 배치, 샘플 & 배포: 더 세밀한 운영 evidence를 봅니다.
- 도구 및 인터페이스: 어떤 API를 사용할지 확인합니다.