---
title: "@homeagent-config ML 파이프라인 도구세트 운영전략"
url: "https://notes.junghanacs.com/notes/20260209T183036"
author: "Junghan Kim"
date: "2026-02-09T18:30:00+09:00"
lastmod: "2026-02-12T00:00:00+09:00"
tags: ["mlops","nixos","pipeline"]
description: "ML 파인튜닝 파이프라인을 운영 인프라 관점에서 설계하기 위한 도구세트 전략을 정리한 노트이다."
---

> [!abstract] 이 노트에 대하여
> 
> NixOS GPU 클러스터에서 HomeAgent용 ML 파인튜닝과 양자화, 엣지 배포를 어떻게 운영할지 도구 선택 중심으로 정리한다. 알고리즘보다 운영 인프라에 초점을 둔 노트다.

## 히스토리

-   [2026-03-11 Wed 10:43] @junghan — temporal 관점에서 하나 더 맥락을 강화하려고 한다. 별도 문서를 만들어야 할 것 같은데?
-   [2026-02-12 Thu 17:30] 업데이트

## HomeAgent ML 파이프라인 도구세트 운영전략

NixOS GPU 클러스터에서 ML 파인튜닝 파이프라인을 운영하기 위한 도구세트 결정 과정. 알고리즘이 아닌 **운영 인프라 관점** — 도구 선택, 에이전트 협업, 상태 모니터링에 집중한다.

### 배경: 왜 이 파이프라인이 필요한가

HomeAgent는 엣지 NPU(Hailo-8/10H)에서 동작하는 Constitutional AI 에이전트다. 클라우드 API 호출 없이 오프라인에서 자율 판단해야 하므로, 로컬 GPU 클러스터에서 파인튜닝 → 양자화 → 엣지 배포하는 파이프라인이 필요하다.

```text
파인튜닝 파이프라인 (gpu-03, 6단계 ~1시간):

데이터 준비 → QLoRA 학습 → LoRA 병합 → 평가 → ONNX 변환 → HEF 양자화
 (CPU ~5분)  (GPU ~30min)  (GPU ~5분) (GPU ~10분)  (CPU/GPU)  (CPU ~10분)
                                                        │
                                                        ↓ SCP / NFS
                                                  RPi5 + Hailo-8 추론
```

Phase 1: Qwen3-0.6B × 2개 (Intent + Summary), Hailo-8 Phase 2: Qwen3-1.5B 통합 모델, Hailo-10H

### 현재 인프라 상태 (2026-02-09)

| 구성요소               | 상태                  | 위치                | 비고                     |
|--------------------|---------------------|-------------------|------------------------|
| 파인튜닝 Python 환경   | tuning.nix 완료 (17패키지) | gpu-03              | NixOS 25.11 네이티브     |
| QLoRA 검증             | test-qlora.py 성공    | gpu-03              | Qwen3-0.6B, ~4GB VRAM    |
| wandb                  | 설치됨 (미연결)       | gpu-03 tuning.nix   | report_to="none" 상태    |
| Temporal Server 1.29.3 | 가동중 (Docker)       | storage-01:7233     | helloworld 검증 완료     |
| Temporal UI 2.45.0     | 가동중 (Docker)       | storage-01:8233     | 웹 모니터링              |
| Doltgres 0.54.10       | 가동중 (Docker)       | storage-01:5434     | Git-like 버전관리 PostgreSQL |
| NFS _storage/models_   | 마운트됨 (10G)        | storage-01 → gpu-03 | 모델 아티팩트            |
| 이슈 트래킹            | br (JSONL + git)      | 로컬                | 에이전트 협업용          |

핵심: **도구는 이미 가동중인데 배선이 안 된 상태.** Temporal과 Doltgres는 원래 Tuya IoT 알림톡 브릿지용으로 배포됐지만, ML 파이프라인에도 재활용할 수 있다.

### 풀어야 할 3가지 질문

1.  학습 실험 추적 — wandb (SaaS) vs MLflow (self-host)
2.  파이프라인 오케스트레이션 — Temporal vs 수동 스크립트
3.  데이터셋/모델 버전 관리 — Doltgres vs DVC vs git-lfs

### Q1 확정: 실험 트래킹 → wandb SaaS

#### 문제

파인튜닝을 반복하면 하이퍼파라미터, loss 곡선, GPU 사용률을 비교해야 한다. "v3가 왜 v2보다 나은가?"를 나중에 재현할 수 있어야 한다.

#### 비교

| 기준               | wandb SaaS             | MLflow (NixOS 셀프호스팅)           |
|------------------|------------------------|--------------------------------|
| 설정 비용          | `report_to`"wandb"= 1줄 | 서비스 구성, 포트, 스토리지         |
| HF transformers 통합 | 네이티브               | `report_to`"mlflow"=                |
| 대시보드           | wandb.ai 즉시 사용     | <http://gpu-03:5000> 구축 필요      |
| 데이터 프라이버시  | 클라우드 의존          | 완전 자체 호스팅                    |
| NixOS 패키지       | tuning.nix에 이미 있음 | mlflow-server 있으나 버그 보고 (GH#330746) |
| 비용               | 무료 (퍼블릭)          | 무료                                |

#### 결정: wandb SaaS로 시작

근거:

-   tuning.nix에 **이미 설치되어 있고**, 코드 1줄 변경으로 즉시 활성화
-   Phase 1 데이터(홈 Intent JSON)는 민감하지 않음
-   노트북에서 wandb.ai 접속만으로 실시간 대시보드

전환 계획:

-   Phase 2 Constitutional 데이터가 민감해지면 → MLflow 셀프호스팅 또는 wandb 셀프호스팅
-   MLflow는 nixpkgs에 패키지가 있으므로 전환 부담 낮음

적용 방법:

```python
# test-qlora.py → train-intent.py 변경점
training_args = TrainingArguments(
    report_to="wandb",           # "none" → "wandb"
    run_name="intent-v1-qlora-r16",
)
```

```bash
# 최초 1회
ssh gpu-03 "wandb login"
```

### Q2 확정: 파이프라인 오케스트레이션 → Temporal Python Worker

#### 문제

6단계 선형 파이프라인을 어떻게 실행하고, 실패를 관리하고, 진행상황을 모니터링하는가. 특히 AI 에이전트(Claude)가 학습을 트리거하고 결과를 확인할 수 있어야 한다.

#### 비교

| 기준    | 수동 스크립트    | Temporal            |
|-------|------------|---------------------|
| 설정 비용 | 0 (ssh + python) | Worker 배포 필요    |
| 장애 복구 | 처음부터 재실행 (~1시간) | 중단점 복구 (~10분) |
| 모니터링 | stdout + wandb   | Temporal UI + wandb |
| 에이전트 협업 | ssh 명령 직접 실행 | API로 워크플로우 트리거/조회 |
| 확장성  | 단일 스크립트 한계 | 멀티노드, 분기, 스케줄링 |
| 서버 인프라 | 불필요           | 이미 storage-01에 가동중 |

#### 조사 결과: Temporal Python SDK

-   **v1.22.0** (2026-02-03), GA, 프로덕션 검증 완료
-   OpenAI, Descript 등에서 ML 파이프라인에 실사용 중
-   Python 3.10-3.14 지원, async/threaded/multiprocess Activity 모두 지원
-   **GPU Task Queue**: gpu-03에 Python Worker를 띄우고, GPU Activity를 전용 큐로 라우팅
-   **Heartbeat**: 장시간 학습(30min+) 중 진행상황 보고 → Worker 죽으면 감지 후 재시도

#### 결정: Temporal Python Worker

근거:

-   Temporal Server가 **이미 storage-01에서 가동중** — Worker만 추가하면 됨
-   "순수 스크립트 + 실패 시 처음부터"보다 "Activity 단위 재시도"가 실용적
-   Temporal UI(8233)에서 파이프라인 진행상황을 노트북에서 바로 확인 가능
-   Claude가 Temporal API로 워크플로우 트리거/상태조회 가능 → 에이전트 협업의 핵심
-   Python SDK가 GA이므로 tuning.nix 환경과 자연스럽게 통합

아키텍처:

```text
┌─ storage-01 ─────────────────────────────────────┐
│  Temporal Server (Docker)                         │
│    └─ gRPC: 192.168.165.141:7233                  │
│    └─ UI: http://192.168.165.141:8233             │
│  Doltgres (Docker)                                │
│    └─ PostgreSQL: 192.168.165.141:5434            │
└──────────┬────────────────────────────────────────┘
           │ gRPC (Worker가 Server를 폴링)
           ↓
┌─ gpu-03 ─────────────────────────────────────────┐
│  Temporal Python Worker                           │
│    └─ TaskQueue: "gpu-training"                   │
│    └─ Activity: prepare_dataset (CPU)             │
│    └─ Activity: train_qlora (GPU, heartbeat)      │
│    └─ Activity: merge_lora (GPU)                  │
│    └─ Activity: evaluate (GPU)                    │
│    └─ Activity: export_onnx (CPU/GPU)             │
│    └─ Activity: quantize_hef (CPU)                │
└──────────────────────────────────────────────────┘
```

Workflow 예시 (Python):

```python
@workflow.defn
class QLoRAPipeline:
    @workflow.run
    async def run(self, config: PipelineConfig) -> PipelineResult:
        # 1. Doltgres에서 데이터셋 로드
        dataset = await workflow.execute_activity(
            prepare_dataset, config,
            start_to_close_timeout=timedelta(minutes=10),
        )
        # 2. QLoRA 학습 (장시간, heartbeat 필수)
        model = await workflow.execute_activity(
            train_qlora, config,
            task_queue="gpu-training",
            start_to_close_timeout=timedelta(hours=1),
            heartbeat_timeout=timedelta(minutes=5),
            retry_policy=RetryPolicy(maximum_attempts=3),
        )
        # 3~6. 후속 단계...
        return PipelineResult(metrics=metrics, artifact_path=path)
```

Heartbeat 패턴 (30분 학습):

```python
@activity.defn
async def train_qlora(config: QLoRAConfig) -> TrainResult:
    trainer = setup_trainer(config)
    for epoch in range(config.num_epochs):
        for step, batch in enumerate(trainer.dataloader):
            loss = trainer.train_step(batch)
            if step % 100 == 0:
                activity.heartbeat(f"epoch={epoch}, step={step}, loss={loss:.4f}")
    return TrainResult(model_path=trainer.save())
```

### Q3 확정: 데이터셋 버전 관리 → Doltgres + NFS

#### 문제

학습 데이터셋의 변경 이력을 추적하고, 실험 간 "어떤 샘플이 바뀌었는지"를 알아야 한다. 모델 바이너리(1-2GB)는 별도 관리가 필요하다.

#### 아티팩트별 관리 전략

| 아티팩트     | 크기              | 관리 도구            | 근거                    |
|----------|-----------------|------------------|-----------------------|
| Intent 데이터셋 | &lt; 5MB (500+ 행) | **Doltgres**         | SQL 쿼리 + row-level diff |
| Summary 데이터셋 | &lt; 5MB (300+ 행) | **Doltgres**         | 동일                    |
| LoRA 어댑터  | ~50MB             | NFS                  | 재생성 가능             |
| 병합 모델 (FP16) | ~1.2GB            | NFS                  | 재생성 가능             |
| ONNX 모델    | ~1.5GB            | NFS                  | 재생성 가능             |
| HEF 파일     | ~수 MB            | homeagent-config git | 최종 산출물             |

#### 비교: Doltgres vs DVC vs git-lfs

| 기준    | Doltgres             | DVC                       | git-lfs     |
|-------|----------------------|---------------------------|-------------|
| 데이터 모델 | SQL 테이블 (관계형)  | 파일 (모든 형식)          | 파일 (모든 형식) |
| Diff 단위 | **행 단위 (row-level)** | 파일 단위                 | 파일 단위   |
| 브랜칭  | SQL로 브랜치/머지    | Git 브랜치 활용           | Git 브랜치 활용 |
| 쿼리    | 완전한 SQL           | 불가                      | 불가        |
| 비정형 데이터 | 부적합               | 적합                      | 적합        |
| 생태계  | 독자적 (성장중)      | **lakeFS에 인수됨 (2025-11)** | GitHub 네이티브 |
| 현재 상태 | **이미 가동중**      | 별도 설치 필요            | 별도 설치 필요 |

#### 조사 결과: Doltgres

-   **v0.54.10**, Beta (1.0 목표 2026 Q2), PostgreSQL 호환
-   **Prolly Tree** 스토리지: Git의 Merkle Tree와 유사한 구조로 효율적 diff/merge
-   Python 통합: `psycopg2`, `SQLAlchemy` 등 표준 PostgreSQL 드라이버 그대로 사용
-   **Flock Safety** 사례: Dolt를 ML Feature Store로 프로덕션 사용 (버전 관리 + 브랜치 격리)
-   **DVC 대비 핵심 장점**: 행 단위 diff, SQL 쿼리, 시간 여행(time-travel) 쿼리

주의사항:

-   CLI 없음 — 모든 버전 관리 조작이 SQL 함수를 통해야 함
-   파일로 저장하지 않음 — 학습 프레임워크가 JSONL을 기대하면 변환 필요
-   500-1000행 규모에서는 변환 오버헤드 무시 가능

#### 결정: Doltgres (데이터셋) + NFS (아티팩트)

근거:

-   storage-01에 **이미 가동중** — 추가 인프라 불필요
-   홈 Intent/Summary 데이터셋은 구조화된 JSON → SQL 테이블로 자연스럽게 매핑
-   `dolt_diff_training_samples` 로 "v1에서 v2로 어떤 샘플이 바뀌었나" 추적 가능
-   DVC는 lakeFS에 인수되어 생태계 불확실 → 신규 도입에 리스크

Doltgres 테이블 설계:

```sql
CREATE TABLE intent_samples (
    id SERIAL PRIMARY KEY,
    instruction TEXT NOT NULL,
    input TEXT,
    output TEXT NOT NULL,
    category VARCHAR(50),
    quality_score FLOAT,
    meta JSONB,              -- 실험용 유연 필드 (스키마 변경 없이 확장)
    created_at TIMESTAMP DEFAULT NOW()
);
```

`meta JSONB` 컬럼의 역할:

-   핵심 필드(instruction, output)는 고정 컬럼 → row-level diff의 대상
-   실험적 필드(context, difficulty, source 등)는 `meta` 에 → 스키마 변경 없이 빠른 실험
-   예: `INSERT INTO intent_samples (..., meta) VALUES (..., '{"source": "manual", "difficulty": "hard"}')`

브랜치/디프/커밋 워크플로우:

```sql
-- 실험 브랜치 생성
SELECT dolt_branch('experiment/intent-v2');
SELECT dolt_checkout('experiment/intent-v2');

-- 샘플 추가/수정
INSERT INTO intent_samples (instruction, output) VALUES (...);

-- 커밋
SELECT dolt_add('-A');
SELECT dolt_commit('-m', 'Add 50 new intent samples for edge cases');

-- v1 vs v2 diff (행 단위!)
SELECT diff_type, from_instruction, to_instruction, from_output, to_output
FROM dolt_commit_diff_intent_samples
WHERE from_commit = HASHOF('experiment/intent-v1')
  AND to_commit = HASHOF('experiment/intent-v2');

-- 학습 스크립트에서 데이터 로드
-- Python: engine = create_engine("postgresql+psycopg2://...:{port}/ml_datasets/experiment/intent-v2")
```

학습 스크립트에서 Doltgres → JSONL 변환:

```python
import pandas as pd
from sqlalchemy import create_engine
import json

engine = create_engine(
    "postgresql+psycopg2://postgres@192.168.165.141:5434/ml_datasets"
)
df = pd.read_sql(
    "SELECT instruction, input, output FROM intent_samples WHERE quality_score > 0.8",
    engine,
)
# HuggingFace datasets 형식으로 변환
records = df.to_dict(orient='records')
```

### 확정: 미래 아키텍처

```text
┌─ 노트북 (ThinkPad P16s) ─────────────────────────────────────┐
│                                                                │
│  Temporal UI (8233) → 파이프라인 진행상황 모니터링              │
│  wandb.ai           → 학습 메트릭 (loss, GPU, 하이퍼파라미터)  │
│  br ready           → 이슈 확인                                │
│  Claude Code        → br + Temporal API 트리거 + 결과 해석     │
│                                                                │
└────────────────────────────────────────────────────────────────┘
         │ ssh / https / gRPC
         ↓
┌─ storage-01 (Docker) ─────────────────────────────────────────┐
│                                                                │
│  Temporal Server 1.29.3  → 파이프라인 오케스트레이션            │
│    └─ gRPC: 192.168.165.141:7233                               │
│    └─ UI: http://192.168.165.141:8233                          │
│                                                                │
│  Doltgres 0.54.10        → 데이터셋 버전 관리                  │
│    └─ PostgreSQL: 192.168.165.141:5434                         │
│    └─ branch: main, experiment/intent-v1, v2...                │
│    └─ row-level diff: "어떤 샘플이 바뀌었나"                   │
│                                                                │
│  /storage/models/tuning/ → 모델 아티팩트 (NFS)                │
│                                                                │
└───────────────────────────────┬────────────────────────────────┘
                                │ gRPC (Worker 폴링) + NFS (10G)
                                ↓
┌─ gpu-03 (파인튜닝 전용, RTX 5080 16GB) ──────────────────────┐
│                                                                │
│  tuning.nix: Python 17패키지 (NixOS 25.11 네이티브)           │
│                                                                │
│  Temporal Python Worker                                        │
│    └─ TaskQueue: "gpu-training"                                │
│    └─ Doltgres SQL → JSONL 변환 (Activity 1)                  │
│    └─ QLoRA 학습 + wandb 기록 (Activity 2, heartbeat)         │
│    └─ LoRA 병합 (Activity 3)                                   │
│    └─ 평가 → Doltgres에 결과 기록 (Activity 4)                │
│    └─ ONNX 변환 (Activity 5)                                   │
│    └─ HEF 양자화 (Activity 6)                                  │
│                                                                │
│  wandb: report_to="wandb" (학습 메트릭 자동 기록)             │
│                                                                │
└────────────────────────────────────────────────────────────────┘
                                │ SCP / NFS
                                ↓
                    ┌───────────────────────┐
                    │  RPi5 + Hailo-8       │
                    │  HEF 추론 검증        │
                    └───────────────────────┘
```

### 재현성 공식

```text
재현 = flake.lock (환경)
     + Doltgres commit hash (데이터셋)
     + git commit (코드)
     + wandb run ID (하이퍼파라미터 + 메트릭)
```

이 4가지를 기록하면 "정확히 같은 환경에서, 같은 데이터로, 같은 코드와 설정으로" 학습을 재현할 수 있다. Docker 없이, NixOS 네이티브 + 기존 인프라만으로.

### 리스크 대응 (Gemini 검토 반영, 2026-02-09)

Gemini의 피어 리뷰에서 지적된 3가지 리스크와 대응 전략. 총평: "이력서 주도 개발이 아니라, 자산 최적화 주도 개발(Asset-Optimization Driven Development)"

#### 리스크 1: 스키마 경직성

문제: JSON 파일은 필드 추가가 자유롭지만, RDBMS는 ALTER TABLE이 필요. 초기 실험에서 데이터셋 구조가 자주 바뀔 수 있다.

대응: **하이브리드 스키마** — 핵심 필드는 고정 컬럼(SQL diff 대상), 실험 필드는 `meta JSONB` 컬럼. 테이블 설계에 이미 반영 완료.

#### 리스크 2: Beta 소프트웨어 의존

문제: Doltgres 0.54.10은 Beta. 데이터 깨짐, 커넥션 끊김, 락 등의 가능성.

대응: **JSONL 탈출구** — Temporal 워크플로우의 마지막 단계 또는 별도 Cron으로 Doltgres 데이터를 NFS에 JSONL 백업.

```python
# 백업 Activity 예시
@activity.defn
async def backup_to_jsonl():
    engine = create_engine("postgresql+psycopg2://postgres@192.168.165.141:5434/ml_datasets")
    df = pd.read_sql("SELECT * FROM intent_samples", engine)
    backup_path = f"/storage/backup/doltgres/intent_samples_{datetime.now():%Y%m%d}.jsonl"
    df.to_json(backup_path, orient='records', lines=True, force_ascii=False)
```

핵심: Doltgres가 깨져도 JSONL + git으로 즉시 폴백 가능. 이 폴백 경로가 있기 때문에 Beta 소프트웨어를 시도할 수 있다.

#### 리스크 3: 디버깅 복잡도

문제: NixOS + Python Worker + 원격 DB + 비동기 워크플로우 조합은 디버깅이 어렵고 노트북에서 재현하기 까다롭다.

대응: **Local Mode 개발 가이드**

```text
[개발 시] 노트북 → storage-01 Temporal Server + Doltgres에 직접 연결
  - Worker를 노트북에서 실행 (GPU 없이 CPU 모드로 테스트)
  - Temporal Server: 192.168.165.141:7233 (사내망)
  - Doltgres: 192.168.165.141:5434 (사내망)
  - 소규모 데이터(10행)로 파이프라인 전체 흐름 검증

[배포 시] gpu-03에 Worker 배포 → GPU TaskQueue 폴링
  - 실제 학습은 gpu-03에서만 실행
```

Worker가 어디서 실행되든 Temporal Server에 붙기만 하면 되는 구조이므로, 노트북에서 개발 → gpu-03에서 실행의 전환이 단순하다.

### 미개척 영역에 대한 메모

Temporal + Doltgres 조합은 **2026-02 현재 아무도 공개적으로 시도하지 않은 패턴** 이다.

유사 사례:

-   Dolt + Metaflow (Netflix 워크플로우 엔진) — 공식 통합
-   Dolt + Flyte (Kubernetes ML 오케스트레이터) — 데이터 리니지 통합
-   Flock Safety + Hosted Dolt — ML Feature Store로 프로덕션 사용
-   Temporal + OpenAI Agents SDK — AI 에이전트 오케스트레이션

우리 조합이 독특한 점:

-   NixOS 네이티브 환경에서 재현성 보장
-   소규모 (단일 GPU, 500행 데이터셋) 에서 시작하는 현실적 접근
-   에이전트(Claude) 협업이 설계에 포함됨
-   이미 가동중인 인프라를 재활용

안 되더라도 시도하는 것에 가치가 있다:

-   실패하면 순수 Python 스크립트 + git JSONL로 폴백 가능 (~1일 전환)
-   성공하면 row-level 데이터 리니지 + durable execution을 확보

### Phase 전환 가이드

| 조건                         | 전환                                        |
|----------------------------|-------------------------------------------|
| Phase 2 민감 데이터          | wandb SaaS → MLflow 셀프호스팅              |
| 데이터셋 10만+ 행            | Doltgres 단독 → Doltgres + DVC (비정형)     |
| 멀티노드 학습 (gpu-01+02+03) | 단일 Worker → 멀티 Worker (TaskQueue 분리)  |
| 모델 배포 자동화             | 수동 SCP → Temporal Workflow (HEF → RPi5 OTA) |
| Doltgres 1.0 출시 (2026 Q2 목표) | Beta 관찰 → 안정화 확인                     |

### 다음 행동 (Action Items)

**즉시 (Phase 1 시작)**:

-   [ ] wandb login 실행 (gpu-03)
-   [ ] test-qlora.py → train-intent.py 전환 (report_to="wandb")
-   [ ] Doltgres에 ml_datasets DB + intent_samples 테이블 생성 (meta JSONB 포함)
-   [ ] 샘플 데이터 10개를 Doltgres에 INSERT

**다음 단계 (Temporal Worker)**:

-   [ ] temporalio Python 패키지를 tuning.nix에 추가
-   [ ] 노트북에서 Local Mode로 Worker 개발/테스트 (CPU, 소규모 데이터)
-   [ ] gpu-03에 Temporal Python Worker 배포 (6 Activity)
-   [ ] 파이프라인 1회 실행 → Temporal UI + wandb 동시 확인

**안전장치**:

-   [ ] Doltgres → JSONL 백업 Activity 구현 (NFS에 저장)
-   [ ] 백업 Cron 또는 파이프라인 마지막 단계에 통합

**검증**:

-   [ ] 학습 완료 후 Doltgres에 평가 결과 기록
-   [ ] 데이터셋 v2 브랜치 → diff 확인 → 재학습
-   [ ] 전체 재현성 검증 (flake.lock + Doltgres commit + wandb run + git commit)
-   [ ] JSONL 백업에서 복원 테스트 (폴백 경로 검증)

### 참고 자료

#### 프로젝트 문서

-   hej-nixos-cluster/MODEL_TUNING.md — 전체 전략서
-   hej-nixos-cluster/docs/ml-파이프라인-도구세트-가이드 — 도구 비교 (초안)
-   hej-nixos-cluster/modules/gpu/tuning.nix — NixOS 환경 정의 (17패키지)
-   hej-nixos-cluster/scripts/test-qlora.py — QLoRA 검증 스크립트
-   hej-kip/temporal_bridge/ — Temporal + Doltgres Docker 구성

#### 조사 출처

Temporal:

-   [temporalio PyPI](https://pypi.org/project/temporalio/) — v1.22.0, Python SDK
-   [ML Workflows with Temporal](https://temporal.io/blog/ai-ml-and-data-engineering-workflows-with-temporal) — ML 파이프라인 패턴
-   [9 Ways to Use Temporal in AI Workflows](https://temporal.io/blog/nine-ways-to-use-temporal-in-your-ai-workflows)
-   [Temporal Python SDK: Failure Detection](https://docs.temporal.io/develop/python/failure-detection) — Heartbeat/Timeout 설정
-   [The Four Types of Activity Timeouts](https://temporal.io/blog/activity-timeouts)

Doltgres:

-   [DoltgreSQL GitHub](https://github.com/dolthub/doltgresql) — v0.54.10
-   [Doltgres Documentation](https://docs.doltgres.com)
-   [Why Doltgres over Dolt?](https://www.dolthub.com/blog/2025-04-17-doltgres-over-dolt/) — PostgreSQL 선택 근거
-   [State of Doltgres (2025-10)](https://www.dolthub.com/blog/2025-10-16-state-of-doltgres/) — 성숙도 현황
-   [SQLAlchemy + Doltgres Getting Started](https://www.dolthub.com/blog/2025-07-18-sql-alchemy-getting-started-doltgres/)
-   [Flock Safety: Dolt as ML Feature Store](https://www.dolthub.com/blog/2024-03-07-dolt-flock/) — 프로덕션 사례

비교:

-   [DVC vs Git-LFS vs Dolt vs lakeFS](https://lakefs.io/blog/dvc-vs-git-vs-dolt-vs-lakefs/) — 데이터 버전 관리 비교
-   [Data Version Control and Dolt Reproducibility](https://www.dolthub.com/blog/2021-04-16-dolt-dvc/)
-   [Temporal vs Airflow — ZenML](https://www.zenml.io/blog/temporal-vs-airflow)
-   [Dolt + Metaflow Integration](https://www.dolthub.com/blog/2021-04-12-metaflow-dolt-integration/) — ML 오케스트레이터 통합 사례
-   [Flyte + Dolt: Data Lineage](https://flyte.org/blog/upleveling-flyte-data-lineage-using-dolt)
