9.1 AI 결과의 출처와 버전 관리 - 같은 입력, 다른 결과
모델 이름과 digest, 프롬프트 해시, 입력 해시를 결과와 함께 저장하는 SQLite 스키마와 코드, 프롬프트만 바꾼 두 번의 실행 결과를 SQL로 비교한 실험, 재처리와 사람 수정 보존 정책을 설명합니다.
#왜 출처를 저장해야 하나
AI 분석은 같은 영상을 다시 돌리면 결과가 달라질 수 있습니다. 모델이 바뀌거나, 프롬프트를 고치거나, 후처리 규칙이 바뀌면 그렇습니다. 결과만 저장해 두면 몇 달 뒤 "예전엔 이 장면이 검색됐는데 지금은 안 된다"는 문의를 받았을 때 무엇이 달라졌는지 설명할 수 없습니다. 또 사람이 고친 값을 재처리가 덮어써 버리는 사고도 흔합니다.
그래서 AI 결과에는 항상 다음을 함께 저장합니다.
| 저장할 것 | 이유 |
|---|---|
| 모델 이름과 digest(내용 해시) | 이름이 같아도 내용이 바뀔 수 있음. 어떤 모델이었는지 특정 |
| 실행 파라미터(온도, seed 등), 출력 스키마·후처리 코드의 버전 | 재현 조건. 이것이 빠지면 같은 모델·프롬프트로도 다른 결과가 나온 이유를 설명할 수 없음 |
| 프롬프트 해시 | 프롬프트가 바뀌었는지 비교 |
| 입력 해시 | 같은 입력이었는지 확인 |
| 실행 시각, 상태 | 이력, 실패 추적 |
| 사람의 검수 상태와 수정자 | 사람이 확정한 값 보호 |
#스키마
8장 1편의 ai_segment를 실행 단위(run) 와 결과 항목(item) 으로 나눈 구조입니다.
CREATE TABLE ai_run (
run_id TEXT PRIMARY KEY, asset_id TEXT NOT NULL, task TEXT NOT NULL,
model TEXT NOT NULL, model_digest TEXT, params_json TEXT,
prompt_sha256 TEXT NOT NULL, input_sha256 TEXT NOT NULL,
started_at TEXT, finished_at TEXT, status TEXT NOT NULL DEFAULT 'running');
CREATE TABLE ai_item (
id INTEGER PRIMARY KEY, run_id TEXT NOT NULL REFERENCES ai_run(run_id),
kind TEXT NOT NULL, start_ms INTEGER, end_ms INTEGER, payload_json TEXT NOT NULL,
confidence REAL, review_state TEXT NOT NULL DEFAULT 'pending',
reviewed_by TEXT, reviewed_at TEXT);
CREATE INDEX ix_ai_item_run ON ai_item(run_id);
CREATE INDEX ix_ai_run_asset ON ai_run(asset_id, task);
- 외래키(
REFERENCES)는 연결마다PRAGMA foreign_keys = ON을 실행해야 동작합니다(5장 4편). - 항목의 본문은
payload_json에 넣습니다. 작업마다 필드가 다르기 때문입니다. 검색이 필요한 필드(kind, 시간)만 컬럼으로 두었습니다.
import datetime
import hashlib
import json
import uuid
sha = lambda s: hashlib.sha256(s.encode("utf8")).hexdigest()
now = lambda: datetime.datetime.now().isoformat(timespec="seconds")
def start_run(con, asset_id, task, model, digest, params, prompt, input_text):
rid = str(uuid.uuid4())
con.execute("INSERT INTO ai_run(run_id,asset_id,task,model,model_digest,params_json,prompt_sha256,input_sha256,started_at) VALUES (?,?,?,?,?,?,?,?,?)",
(rid, asset_id, task, model, digest, json.dumps(params, sort_keys=True), sha(prompt), sha(input_text), now()))
return rid
def finish_run(con, rid, items, status="done"):
con.executemany("INSERT INTO ai_item(run_id,kind,start_ms,end_ms,payload_json,confidence) VALUES (?,?,?,?,?,?)",
[(rid, k, s, e, json.dumps(p, ensure_ascii=False), c) for k, s, e, p, c in items])
con.execute("UPDATE ai_run SET status=?, finished_at=? WHERE run_id=?", (status, now(), rid))
모델 digest는 Ollama의 /api/tags 응답에 있는 값(이 실험에서는 aaee06c39dcf...)을 앞 12자리만 저장했습니다. 클라우드 서비스를 쓸 때는 모델 버전 이름(날짜가 붙은 이름)을 저장합니다. 이름만 있고 버전이 없는 별칭은 시간이 지나면 다른 모델을 가리킬 수 있습니다.
#실험: 프롬프트만 바꿨더니
8장 5편의 같은 대본에 대해 프롬프트만 다르게 두 번 실행했습니다. v2는 시스템 지시에 "키워드는 3~5개로 제한하세요"를 덧붙였습니다. 두 실행을 저장하고 SQL로 비교했습니다.
SELECT task, model, model_digest, substr(prompt_sha256,1,12), status FROM ai_run
→ ('metadata', 'qwen3.8:27b', 'aaee06c39dcf', 'f09a9da8eeef', 'done') ← v1 (30.1초, 키워드 6개)
→ ('metadata', 'qwen3.8:27b', 'aaee06c39dcf', 'e70096e6f599', 'done') ← v2 (19.6초, 키워드 5개)
입력 해시는 같음: True / 프롬프트 해시는 다름: True
-- 한 실행의 키워드 집합 (JSON 함수 사용)
SELECT json_extract(payload_json,'$.text') FROM ai_item WHERE run_id = ? AND kind = 'keyword';
두 실행의 키워드 집합을 비교한 결과입니다.
v1에만 있음: 광화문광장, 세종대로 통제, 시민 인터뷰
v2에만 있음: 광화문, 교통 통제
공통: 3개
프롬프트 한 줄을 덧붙였을 뿐인데 키워드가 개수뿐 아니라 내용도 달라졌습니다(광화문광장 → 광화문, 세종대로 통제 → 교통 통제). 입력 해시와 모델 digest는 같고 프롬프트 해시만 달랐다는 사실이 DB에 남아 있으므로, 이 차이의 원인 후보를 프롬프트 변경으로 좁힐 수 있습니다(실행 파라미터도 같았는지 함께 확인합니다). 이 기록이 없다면 모델 업데이트인지 프롬프트 수정인지 추측해야 합니다.
#운영 정책
| 상황 | 정책 |
|---|---|
| 모델·프롬프트 변경 | 기존 결과는 삭제하지 않고 새 run을 추가. 검색 색인에는 "현재 채택된 run"만 반영 |
| 재처리 | 같은 (asset, task, 입력 해시, 모델 digest, 프롬프트 해시, 정규화한 실행 파라미터, 출력 스키마·후처리 버전)가 이미 done이면 건너뜀(멱등). 이 중 하나라도 달라졌으면 새 run |
| 사람이 수정한 항목 | review_state = 'edited'이면 재처리가 덮어쓰지 않음. 새 결과와 충돌하면 검수 큐로 |
| 실패 | status = 'failed'와 오류 내용을 남기고 재시도 횟수 제한 |
| 삭제 | 삭제 의무가 확정된 경우 해당 영상의 ai_item, 대본, 임베딩, 썸네일 등 파생 데이터를 함께 처리하고, 법정 보존이나 예외가 있는지 검토(9장 3편) |
| 비교 | 새 모델 도입 전, 같은 정답 세트(8장 6편)로 이전 run과 지표 비교 |
#정리
- AI 결과는 모델 digest, 프롬프트 해시, 입력 해시와 함께 저장해야 달라진 원인을 설명할 수 있습니다.
- 결과를
run단위로 쌓고 지우지 않으며, 현재 채택된run만 검색에 반영합니다. - 사람이 고친 값은 재처리로부터 보호하고, AI 원본 결과와 구분해 둡니다.
#참고 자료
링크는 2026-10-28에 열람이 되는 것을 확인했습니다. 규격과 도구 문서는 개정될 수 있으므로 적용하기 전에 최신 판을 확인하세요.