📚 시리즈 — Databricks LLMOps
- ① AI Gateway — LLM 폴백·게이트웨이 프록시
- ② Prompt Registry — 프롬프트 버전·alias 관리 — 현재 글
- ③ MLflow Tracing — LangGraph 관측·PII 마스킹
1. 개요
Managed MLflow Prompt Registry는 MLflow 3 기반에서 LLM 프롬프트를 Unity Catalog 에 등록·버전 관리하고, alias(예: dev)로 운영에 연결하는 기능입니다.
프롬프트를 애플리케이션 코드 안에 하드코딩하지 않고 중앙에서 관리하는 것이 핵심 가치입니다.
- 버전(version) 은 불변(immutable) 스냅샷으로 쌓이고, alias 는 특정 버전을 가리키는 가변(mutable) 포인터라서, 운영 중에도 재배포 없이 프롬프트를 교체할 수 있습니다(자세한 정의는 §2).
- UI 에서 프롬프트를 조회·수정할 수 있어 비개발자도 협업이 가능합니다.
- 평가(
mlflow.genai.evaluate)·lineage 와도 연결됩니다.
상태: 본 기능은 Beta 입니다. workspace admin 이 Previews 페이지에서 활성화해야 사용할 수 있습니다(§3.1).
2. 핵심 개념
| 개념 | 설명 |
|---|---|
| Prompt | Unity Catalog 안의 명명 엔티티(named entity). 이름은 catalog.schema.prompt_name 3단계 |
| Version | 등록할 때마다 자동 증가하는 불변(immutable) 버전 (1, 2, 3 …) |
| Alias | 특정 버전을 가리키는 가변(mutable) 별칭 (이름 자유, 예: dev). 운영은 alias 로만 로드 |
| Template variable | {{변수명}} 형태의 이중 중괄호(double-brace) 문법. 예: {{question}}. .format() 으로 주입 |
| Format | Text(완성형 단일 문자열) 또는 Chat(role 기반 메시지) 두 형식 저장 가능 |
- 프롬프트 URI 형식:
prompts:/{catalog}.{schema}.{prompt_name}@{alias}(alias) 또는prompts:/{...}/{version}(버전 고정). - 버전 vs alias 사용 기준: 운영 코드는 버전 번호를 직접 쓰지 말고 alias 를 쓰는 것이 권장됩니다. 그래야
devalias 만 새 버전으로 옮겨 무중단 교체가 됩니다. - Text vs Chat 형식 ≠ 스트리밍: 형식 축(Text/Chat)은 프롬프트 저장 형태이고, 에이전트의 스트리밍 여부와는 무관합니다. 본 가이드 예시는 Text 템플릿 + 스트리밍 에이전트 조합입니다.
Text vs Chat 형식 상세: 두 형식 모두 {{변수}} 자동 추출은 동일하지만(.format() 호출 방식 동일), 반환 타입이 다릅니다.
- Text — 하나의 완성된 문자열 템플릿입니다.
.format()은 문자열(str) 을 돌려줍니다. system 지시문이나 단일 프롬프트에 적합합니다.
python
register_prompt(name=P, template="당신은 화물 어시스턴트입니다. 질문: {{question}}")
loaded.format(question="운임이 왜 올랐나요?")
# -> "당신은 화물 어시스턴트입니다. 질문: 운임이 왜 올랐나요?" ← 반환 타입: 문자열 1개(str)
- Chat —
role/content메시지의 리스트를 템플릿으로 저장합니다..format()은 변수를 채운 메시지 리스트(list[dict]) 를 돌려주므로 LLM 의messages인자에 바로 넣습니다. 역할 분리(system+user)나 few-shot 예시까지 버전 관리하고 싶을 때 적합합니다.
python
register_prompt(name=P, template=[
{"role": "system", "content": "당신은 A항공 화물(Cargo) 어시스턴트입니다. 한국어로 답합니다."},
{"role": "user", "content": "{{question}}"},
])
loaded.format(question="운임이 왜 올랐나요?")
# -> [{"role": "system", "content": "당신은 A항공 화물(Cargo) 어시스턴트입니다. 한국어로 답합니다."},
# {"role": "user", "content": "운임이 왜 올랐나요?"}] ← 반환 타입: 메시지 리스트(list[dict])
운영 RAG 에이전트(§5)는 system 문자열만 떼어 직접
messages를 구성하므로 Text 를 쓰고, 메시지 구조 자체(역할·few-shot)를 버전 관리하려면 Chat 을 택합니다.
3. 전제 조건과 활성화
3.1 Preview 활성화 (Managed MLflow Prompt Registry)
기능이 꺼져 있으면 등록·로드 호출이 모두 FEATURE_DISABLED 오류로 실패하므로, 아래에서 먼저 활성화합니다.
활성화 (workspace admin):
- workspace 우상단 본인 이름 → Settings
- 좌측 Previews (= "Manage Databricks previews")
- 검색창에
prompt입력 → "Managed MLflow Prompt Registry" (Beta) 토글 → On - 반영까지 수 분 소요 ("Preview enablement changes take effect in a few minutes")
3.2 소프트웨어·실험·권한
| 항목 | 요건 |
|---|---|
| MLflow | pip install -U "mlflow[databricks]>=3.1.0" (검증 환경 3.14.0) |
| MLflow Experiment | 프롬프트가 연결될 experiment 1개 (mlflow.set_experiment(...)) |
| Unity Catalog 스키마 권한 | 프롬프트를 저장할 스키마에 CREATE FUNCTION·EXECUTE·MANAGE |
권한이 스키마 레벨인 이유: 프롬프트는 UC 안에서 function 류 엔티티로 저장되므로 접근 통제가 스키마 레벨에서 이뤄집니다. 로드의 최소 권한은 카탈로그
USE CATALOG+ 스키마USE SCHEMA·EXECUTE입니다.
4. 빠른 시작 — 등록·로드·변수 주입
4.1 UI 에서 조회·관리
메뉴 위치: workspace 좌측 Experiments → 해당 experiment(예 css_cmarket_rag_agent_exp) 진입 → 상단 "Prompts" 탭. (UC 엔티티이므로 Catalog Explorer 의 해당 스키마에서도 확인됩니다.)
UI 에서 가능한 작업:
| 작업 | 방법 |
|---|---|
| 생성 | Prompts 탭 → new prompt 버튼 → Choose 로 UC 스키마 선택 → 이름 입력 → 형식 Text/Chat 선택 → 내용 작성({{변수}} 사용) → commit message → Create |
| 새 버전 | 프롬프트 옆 new version 버튼 → 수정 → Save (편집 = 새 버전 생성, 기존 버전은 불변) |
| 버전 비교 | 프롬프트 이름 클릭 → 좌상단 Compare |
| alias 관리 | 프롬프트 상세에서 alias 지정/이동 |
아래 화면은 §4.2 에서 등록한 프롬프트
<catalog>.<schema>.cargo_market_assistant의 상세 뷰입니다. 좌측 버전 목록(Version 1), 우측 활성 버전(v1)의 alias(@dev)·commit message(cargo cmarket assistant - 초기 버전)·템플릿 본문이 한 화면에 보입니다. 우상단 Create prompt version(새 버전), Compare(버전 비교), alias 편집 진입점도 같은 화면에 있습니다. (Prompts 탭의 프롬프트 목록은 우상단 Select a schema 로 스키마를 골라야 표시됩니다.)

4.2 코드로 등록·로드
먼저 대상 스키마에 권한을 부여합니다. 등록·alias 지정은 쓰기 작업이라 CREATE FUNCTION·EXECUTE·MANAGE 가 필요합니다(§3.2). main.default 처럼 권한 없는 스키마면 등록이 실패합니다.
GRANT USE CATALOG ON CATALOG <catalog> TO `<principal>`;
GRANT USE SCHEMA, CREATE FUNCTION, EXECUTE, MANAGE ON SCHEMA <catalog>.<schema> TO `<principal>`;
-- <principal> = 사용자 이메일 또는 Service Principal application-id
이어서 등록·로드:
import mlflow
mlflow.set_tracking_uri("databricks") # 고정값 — Databricks 호스팅 MLflow tracking 서버 사용
mlflow.set_registry_uri("databricks-uc") # 고정값 — databricks-uc 로 설정해야 UC 에 등록됩니다
PROMPT = "<catalog>.<schema>.cargo_market_assistant" # catalog.schema.name
# 1) 등록 — 화물 시장운임(cmarket) 어시스턴트 템플릿 + {{question}} 변수 (이중 중괄호)
p = mlflow.genai.register_prompt(
name=PROMPT,
template=(
"당신은 A항공 화물(Cargo) 시장운임(cmarket) 분석을 돕는 AI 어시스턴트입니다. "
"제공된 컨텍스트에 근거해 한국어로 답변하고, 근거가 없으면 추측하지 마세요.\n"
"질문: {{question}}"
),
commit_message="cargo cmarket assistant - 초기 버전",
)
# p.version -> 1, p.variables -> ['question'] (변수 자동 추출)
# 2) 운영 alias 지정
mlflow.genai.set_prompt_alias(PROMPT, alias="dev", version=p.version)
# 3) alias 기준 로드
loaded = mlflow.genai.load_prompt(f"prompts:/{PROMPT}@dev")
# 4) 변수 주입 후 사용
text = loaded.format(question="이번 분기 항공 화물 운임이 오른 이유가 뭔가요?")
# -> "당신은 A항공 화물(Cargo) ... 질문: 이번 분기 항공 화물 운임이 오른 이유가 뭔가요?"
실행 결과 (apne2, dev 환경): 위 코드를 그대로 실행한 결과입니다.
| 호출 | 결과 |
|---|---|
register_prompt(... "...{{question}}") |
version=1, variables={'question'} (변수 자동 추출) |
set_prompt_alias(..., "dev", version=1) |
dev → v1 |
load_prompt("prompts:/...@dev") |
version=1 로 로드 |
loaded.format(question="이번 분기 항공 화물 운임이 오른 이유가 뭔가요?") |
"당신은 A항공 화물(Cargo) ... 질문: 이번 분기 ..." |
변수가 없는 순수 시스템 지시문(역할·규칙)으로 등록하면
variables=[]이며, 에이전트는 이를 system 메시지 로 주입합니다.{{question}}같은 변수가 있는 완성형 템플릿은.format()으로 채워 단일 user 메시지 로 보냅니다. 운영 RAG 에이전트(멀티턴)는 전자(시스템 프롬프트) 패턴을 씁니다 — §5 참조.
5. Model Serving 통합 (운영 패턴)
5.1 에이전트 로드 패턴 (alias + TTL 캐시 + fallback)
import os, time, mlflow
mlflow.set_tracking_uri("databricks") # 고정값 — Databricks 호스팅 MLflow tracking 서버
mlflow.set_registry_uri("databricks-uc") # 고정값 — UC 등록·로드 (서빙에서도 두 URI 필수)
PROMPT_NAME = "<catalog>.<schema>.css_cmarket_system_prompt" # 로드할 프롬프트 (dev 카탈로그)
PROMPT_ALIAS = os.getenv("PROMPT_ALIAS", "dev") # 환경별 config 로 주입
PROMPT_TTL = float(os.getenv("PROMPT_TTL_SECONDS", "300")) # 캐시 TTL(초)
# 로드 실패 시 쓸 내장 기본값 (예시 — 운영 코드의 SYSTEM_PROMPT 역할)
FALLBACK_SYSTEM = "당신은 A항공 화물(Cargo) 어시스턴트입니다. 한국어로 답변합니다."
_cache, _cache_t, _ver = None, 0.0, None # 캐시된 템플릿 / 마지막 로드 시각 / 활성 버전
def system_prompt():
"""캐시된 system 프롬프트 반환 (TTL 경과 시 registry 에서 최신 재로드)."""
global _cache, _cache_t, _ver
now = time.monotonic()
if _cache is None or (now - _cache_t) >= PROMPT_TTL: # TTL 경과 → 최신 재로드
try:
p = mlflow.genai.load_prompt(f"prompts:/{PROMPT_NAME}@{PROMPT_ALIAS}")
_cache, _ver, _cache_t = p.template, p.version, now # 성공: 템플릿·버전·시각 갱신
except Exception:
# 첫 로드 실패 → 내장 기본값으로 대체
if _cache is None:
_cache, _cache_t = FALLBACK_SYSTEM, now
return _cache
5.2 로깅·배포 (권한 부여·env override)
from mlflow.models.resources import DatabricksServingEndpoint
# resources 에는 LLM 엔드포인트만 넣습니다. 프롬프트 접근 권한은 아래 env override 로 해결합니다.
logged = mlflow.pyfunc.log_model(
name="agent", python_model="agent.py",
pip_requirements=["mlflow[databricks]>=3.1.0", "databricks-sdk", "openai"],
resources=[DatabricksServingEndpoint(endpoint_name="databricks-gemini-3-flash")])
서빙 런타임에서 프롬프트를 로드하려면, 권한을 가진 Service Principal(SP) 자격증명을 env override 로 주입합니다. 아래 ①②③ 을 적용합니다.
① 스키마 권한 — 서빙 SP 에 §4.2 등록과 동일한 스키마 권한을 부여합니다. load_prompt 도 레지스트리 갱신을 동반하므로 USE SCHEMA·CREATE FUNCTION·EXECUTE·MANAGE 가 모두 필요합니다.
GRANT USE CATALOG ON CATALOG <catalog> TO `<sp-application-id>`;
GRANT USE SCHEMA, CREATE FUNCTION, EXECUTE, MANAGE ON SCHEMA <catalog>.<schema> TO `<sp-application-id>`;
② LLM 엔드포인트 호출 권한 — LLM 이 커스텀 서빙 엔드포인트일 때만 그 SP 에 CAN_QUERY 를 부여합니다. Foundation Model API 엔드포인트(databricks-*, 예 databricks-gemini-3-flash)는 별도 부여 없이 SP 가 호출할 수 있어 이 단계가 필요 없습니다. 커스텀 엔드포인트는 UI, 또는 CLI(엔드포인트 ID 를 받음 — 이름 아님)로 부여합니다:
EP_ID=$(databricks serving-endpoints get <custom-endpoint-name> | jq -r .id)
databricks serving-endpoints update-permissions "$EP_ID" \
--json '{"access_control_list":[{"service_principal_name":"<sp-application-id>","permission_level":"CAN_QUERY"}]}'
③ 배포 시 그 SP 자격증명을 env override 로 주입 — 자동 인증 토큰은 로깅 시 선언한 resources(LLM 엔드포인트)로만 제한되므로, 프롬프트 접근 권한을 가진 SP 자격증명을 환경변수로 직접 넣습니다:
from databricks import agents
agents.deploy(MODEL, version, endpoint_name="<agent-endpoint>", scale_to_zero=True,
environment_vars={
"MLFLOW_EXPERIMENT_ID": "<exp-id>",
"DATABRICKS_HOST": "https://<workspace-host>",
"DATABRICKS_CLIENT_ID": "<sp-application-id>", # ①(+커스텀 LLM이면 ②)를 grant 한 SP
"DATABRICKS_CLIENT_SECRET": "{{secrets/<scope>/<key>}}",
})
env override 를 쓰면, 자동 토큰이 대신 처리하던 LLM 엔드포인트 자동 권한(passthrough)이 꺼집니다. 따라서 주입하는 SP 가 ①프롬프트 스키마 권한을 가져야 하며, LLM 이 커스텀 엔드포인트면 ②
CAN_QUERY도 함께 필요합니다(FMAPI 면 불요).
6. 평가 기반 승격 흐름
Databricks 권장 운영 흐름은 여러 버전 생성 → 평가 → best 선택 → alias 승격 입니다.
- a. 후보 프롬프트 여러 버전 등록 (v1, v2, …)
- b. 동일 evaluation dataset 으로 비교 —
mlflow.genai.evaluate(data=..., predict_fn=..., scorers=[...]) - c. 점수가 좋은 버전 선택
- d.
set_prompt_alias(PROMPT, alias="dev", version=<best>)로 승격
import mlflow
from mlflow.genai.scorers import Correctness, RelevanceToQuery # 내장 scorer 예시
# eval_dataset (직접 구성): [{"inputs": {"question": "..."},
# "expectations": {"expected_response": "..."}}, ...]
# call_llm(prompt_text) -> str : LLM 호출 래퍼 (직접 구현)
METRIC = "correctness/mean" # 실제 키는 사용한 scorer 에 따라 다름 — res.metrics 로 확인
results = {}
for v in [1, 2, 3]:
pr = mlflow.genai.load_prompt(f"prompts:/{PROMPT}/{v}")
res = mlflow.genai.evaluate(
data=eval_dataset,
predict_fn=lambda q, _p=pr: call_llm(_p.format(question=q)),
scorers=[Correctness(), RelevanceToQuery()],
)
results[v] = res.metrics
best = max(results, key=lambda v: results[v][METRIC])
mlflow.genai.set_prompt_alias(PROMPT, alias="dev", version=best)
eval_dataset 구성: 각 row 는
inputs(프롬프트 변수)와expectations(정답·기대 응답) 컬럼을 가집니다. 점수 metric 키 이름(correctness/mean등)은 사용한 scorer 에 따라 달라지므로, 선택 기준으로 쓰기 전에res.metrics를 한 번 출력해 실제 키를 확인하세요. 승격은 alias 재지정 한 번이며, 운영 에이전트는 TTL 주기 내 자동으로 새 버전을 사용합니다.
7. 참고 자료
- Prompt Registry (MLflow 3, Databricks)
- Create and edit prompts
- Use prompts in deployed applications
- Prompt Registry examples
📚 시리즈 — Databricks LLMOps
- ① AI Gateway — LLM 폴백·게이트웨이 프록시
- ② Prompt Registry — 프롬프트 버전·alias 관리 — 현재 글
- ③ MLflow Tracing — LangGraph 관측·PII 마스킹
'Databricks > MLflow' 카테고리의 다른 글
| Databricks LLMOps ③ MLflow Tracing — LangGraph 관측·한국어 PII 마스킹 (0) | 2026.07.06 |
|---|
댓글