프롬프트 관리 툴 (사내 LLMOps)
git 의 형상관리 개념을 프롬프트에 그대로 옮긴 사내 도구. DB화 · 렌더 API · MCP 서버 · diff/merge/cherry-picking 까지.
사용 기술
FastAPIPostgreSQLSQLAlchemyAlembicMCPHandlebars/Jinja2React(Vite + TypeScript)
문제#
프롬프트가 서비스 품질을 결정하는데, 정작 그 프롬프트를 관리하는 방식이 시트였다. 문제는 "정리가 안 돼 있다"가 아니라 개선 루프 자체가 끊겨 있다는 것이었다.
- 프롬프트 버전 관리가 지나치게 복잡해, 지금 쓰이는 버전이 어떤 히스토리를 거쳐 배포됐는지 · 어떤 테스트를 통과했는지 를 아무도 파악할 수 없음
- 프롬프트 수정에는 LLM 툴을 많이 쓰는데, 시트에서 복사해 지시하고 결과를 다시 붙여넣어 테스트하는 왕복 작업을 매번 반복해야 함
- 그렇게 붙여넣은 LLM 은 변경 히스토리도 테스트 이력도 모르는 상태라 컨텍스트 없이 답할 수밖에 없어 개선 결과의 품질 자체가 떨어짐
세 번째가 핵심이다. 앞의 둘은 불편이지만, 세 번째는 도구의 한계가 결과물의 품질을 깎는 문제다.
해결 순서#
네 단계를 이 순서로 밟았다. 각 단계가 다음 단계의 전제가 된다.
① DB화 시트 → PostgreSQL
버전 · 배포 상태 · 변경 이력을 한곳에서
│
▼
② 외부 연동 API 변수(context)만 받아 렌더링 결과만 반환
LLM 호출 · 과금 · DB 기록 없는 드라이런
│
▼
③ 편집용 MCP 서버 Claude Code 에서 직접 조회 · 수정 · 테스트
복붙 왕복 제거 + LLM 이 히스토리를 컨텍스트로 확보
│
▼
④ git 형상관리 적용 배포 버전 지정 · 섹션 단위 diff · merge
cherry-picking · branch tree 히스토리 시각화기술 의사결정#
DB화 — 단일 소스 확보가 먼저#
시트에 흩어져 있던 프롬프트를 SQLAlchemy ORM + Alembic + PostgreSQL 저장소로 이관했다. 버전·배포 상태·변경 이력이 한곳에 모여야 그다음의 diff 도 MCP 도 의미가 생긴다.

드라이런 렌더 엔드포인트#
변수(context)만 받아 LLM 호출 · 과금 · DB 기록 없이 렌더링 결과만 돌려주는 엔드포인트를 뒀다. 덕분에 어떤 프로그램에서든 같은 프롬프트를 가져다 쓸 수 있고, 렌더 결과 확인에 토큰이 들지 않는다.
편집용 MCP 서버 — 복붙 왕복을 없앤 지점#
Claude Code 에서 프롬프트를 직접 조회·수정·테스트하도록 MCP 서버를 붙였다. 복붙 왕복이 사라진 것보다 중요한 건, LLM 이 변경 히스토리와 테스트 이력을 컨텍스트로 갖고 작업하게 됐다는 점이다. 문제 정의의 세 번째 항목이 여기서 풀린다.
터미널에서 자연어로 지시하면 수정 결과가 draft 로 저장되고 관리 페이지 버전 목록에 바로 뜬다. "조금 더 눅여줘" 처럼 이어서 지시하면 새 버전을 쌓지 않고 같은 draft 를 갱신하므로, 대화를 주고받는 동안 버전 목록이 지저분해지지 않는다.
개발자 노트북 Claude Code
└ MCP 서버 — 프로세스는 각자 로컬에서 뜬다
│
│ HTTP (프롬프트 API 호출만 나간다)
▼
공유 서버 프롬프트 API ──▶ PostgreSQL
draft 로 저장 · 서빙에는 영향 없음
│
▼
사람 관리 페이지에서 배포(publish)MCP 서버에 로직을 두지 않았다#
서버는 프롬프트 API 를 HTTP 로 호출하기만 하는 얇은 번역기로 뒀다. 검증·버전 부여·렌더는 전부 기존 API 에 남겨 뒀다. MCP 쪽에 로직을 복제하면 웹 UI 로 고칠 때와 Claude Code 로 고칠 때의 동작이 갈라지고, 그 순간 "프롬프트의 진실은 DB" 라는 전제가 깨진다.
프로세스는 각자 노트북에서 띄운다#
MCP 서버는 공유 서버가 아니라 각 개발자의 Claude Code 가 띄우고, 공유 서버로 나가는 것은 HTTP 호출뿐이다. 공유 서버에 설치·배포할 것이 없어 도입 비용이 환경변수 하나와 의존성 설치로 끝난다.
LLM 이 프로덕션을 직접 바꾸지 못하게 했다#
MCP 경로로 만들어지는 것은 draft 뿐이라 서빙에는 영향이 없고, 배포는 사람이 관리 페이지에서 한다. 편집자 식별도 웹과 다르게 뒀다 — 웹 로그인은 처음 보는 ID 를 자동 가입시키지만, MCP 경로는 계정 존재 여부만 확인하고 없으면 거절해서 신원 없는 편집이 들어오지 않는다.
다만 여기까지가 한계다. draft 에 편집자 ID 가 남지만 권한 구분은 없어서 로그인한 사람은 누구나 편집·배포할 수 있다. 이 ID 는 접근 제어가 아니라 이력 추적용이고, 사내 도구라는 전제에서 멈춘 선택이다.
git 형상관리 개념을 프롬프트에 적용#
- 배포 버전 지정 — 어느 버전이 지금 프로덕션에 나가 있는지 명시적으로 관리
- 섹션 단위 diff — 외부 의존성 없이 LCS 를 직접 구현해 프롬프트를 섹션 단위로 비교
- merge — 서로 다른 버전의 변경을 합침
- cherry-picking — 특정 버전의 개별 섹션만 골라 가져옴
- branch tree 히스토리 시각화 — 버전 계보를 git branch tree 형태로 표시


Handlebars 전환과 골든 스냅샷 검증#
프롬프트 저장 표기를 프로덕션과 동일한 Handlebars 로 전환하면서 전처리기를 직접 구현했다. 표기 방식을 바꾸는 작업은 출력이 미묘하게 달라져도 알아채기 어렵다는 게 위험 요소다. 골든 스냅샷 75건을 바이트 단위로 동일 검증해 표기 변경이 출력에 영향을 주지 않음을 입증한 뒤 적용했다.
모델 관리 통합 중 발견한 폴백 위험#
모델 관리도 같은 툴에 통합하면서 vLLM 프로바이더 라우팅을 추가했다. 이 과정에서 미등록 모델 키가 OpenRouter 로 조용히 폴백돼 엉뚱한 엔드포인트로 요청이 나가는 위험을 발견해 라우팅까지 함께 구현했다. per-model 엔드포인트와 API key 는 write-only 로 저장하고, 카나리 시크릿 전수 검증으로 값이 노출되지 않음을 확인했다.
결과#
- 팀 전체가 신뢰할 수 있는 단일 프롬프트 소스 확보 — 어떤 버전이 어떤 이력을 거쳐 배포됐는지 추적 가능
- 프롬프트 개선을 MCP 로 복붙 없이 즉시 수정·테스트할 수 있게 됐고, LLM 이 히스토리를 컨텍스트로 갖게 되면서 제안 품질도 함께 상승
- 테스트 과정에서 시도한 아이디어까지 버전으로 남아, 당장 채택하지 않은 시도도 나중에 cherry-picking 으로 손쉽게 되살릴 수 있게 됨
- AI팀 4인이 상시 사용하며 모델 10종 · 프롬프트 30개 버전을 관리. 프롬프트 수정·테스트에 걸리던 시간이 1시간 → 30분으로 단축되어 테스트를 더 자주 돌릴 수 있게 됨