[BETA] 제네릭 프롬프트 관리 API - PR 없이 통합하기
[BETA] 제네릭 프롬프트 관리 API - PR 없이 통합하기
문제
프롬프트 관리 프로바이더로서 LiteLLM에 통합하는 전통적인 방법은 다음을 요구했어요:
- LiteLLM 저장소에 PR 제출
- 리뷰와 병합 대기
- LiteLLM 코드베이스에서 프로바이더별 코드 유지
- API 변경에 맞춰 통합 업데이트
해결책
제네릭 프롬프트 관리 API(Generic Prompt Management API)를 사용하면 간단한 API 엔드포인트를 구현해 PR 없이 즉시 LiteLLM에 통합할 수 있어요.
주요 이점
- PR 불필요 - 즉시 배포하고 통합하세요
- 간단한 계약 - GET 엔드포인트 하나, 표준 JSON 응답
- 변수 치환 -
{variable}문법으로 프롬프트 변수 지원 - 커스텀 파라미터 - config를 통해 프로바이더별 query param 전달
- 완전한 제어 - 프롬프트 관리 API를 직접 소유하고 유지
- 모델·파라미터 오버라이드 - 프롬프트에서 모델과 파라미터 선택적 오버라이드
3단계로 시작하기
1단계: LiteLLM 설정
config.yaml 에 추가하세요:
prompts:
- prompt_id: "simple_prompt"
litellm_params:
prompt_integration: "generic_prompt_management"
api_base: http://localhost:8080
api_key: os.environ/YOUR_API_KEY
2단계: API 엔드포인트 구현
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
@app.get("/beta/litellm_prompt_management")
async def get_prompt(prompt_id: str):
return {
"prompt_id": prompt_id,
"prompt_template": [
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Help me with {task}"}
],
"prompt_template_model": "gpt-5.6-terra",
"prompt_template_optional_params": {"temperature": 0.7}
}
3단계: 앱에서 사용
from litellm import completion
response = completion(
model="gpt-5.6-terra",
prompt_id="simple_prompt",
prompt_variables={"task": "data analysis"},
messages=[{"role": "user", "content": "I have sales data"}]
)
이것으로 끝이에요! LiteLLM이 프롬프트를 가져오고, 변수를 적용하고, 요청을 만듭니다.
출처: 문서
본문
API 계약
엔드포인트
GET /beta/litellm_prompt_management 을 구현하세요.
요청 형식
엔드포인트는 query parameter가 있는 GET 요청을 받아요:
GET /beta/litellm_prompt_management?prompt_id={prompt_id}&{custom_params}
Query 파라미터:
prompt_id(필수): 가져올 프롬프트의 ID- 커스텀 파라미터:
provider_specific_query_params에서 설정한 추가 파라미터
예시:
GET /beta/litellm_prompt_management?prompt_id=hello-world-prompt-2bac&project_name=litellm&slug=hello-world-prompt-2bac
응답 형식
{
"prompt_id": "hello-world-prompt-2bac",
"prompt_template": [
{
"role": "system",
"content": "You are a helpful assistant specialized in {domain}."
},
{
"role": "user",
"content": "Help me with {task}"
}
],
"prompt_template_model": "gpt-5.6-terra",
"prompt_template_optional_params": {
"temperature": 0.7,
"max_tokens": 500,
"top_p": 0.9
}
}
응답 필드:
prompt_id(string, 필수): 프롬프트의 IDprompt_template(array, 필수): 선택적{variable}플레이스홀더가 있는 OpenAI 형식 메시지 배열prompt_template_model(string, 선택): 이 프롬프트에 사용할 모델 (ignore_prompt_manager_model: true가 아니면 클라이언트 모델을 오버라이드)prompt_template_optional_params(object, 선택): temperature, max_tokens 등 추가 파라미터 (ignore_prompt_manager_optional_params: true가 아니면 클라이언트 params와 병합)
LiteLLM 설정
config.yaml 에 추가하세요:
model_list:
- model_name: gpt-5.6-luna
litellm_params:
model: openai/gpt-5.6-luna
api_key: os.environ/OPENAI_API_KEY
prompts:
- prompt_id: "simple_prompt"
litellm_params:
prompt_integration: "generic_prompt_management"
provider_specific_query_params:
project_name: litellm
slug: hello-world-prompt-2bac
api_base: http://localhost:8080
api_key: os.environ/YOUR_PROMPT_API_KEY # optional
ignore_prompt_manager_model: true # optional, keep client's model
ignore_prompt_manager_optional_params: true # optional, don't merge prompt manager's params (e.g. temperature, max_tokens, etc.)
설정 파라미터
prompt_integration: 반드시"generic_prompt_management"여야 합니다provider_specific_query_params: API로 보내는 커스텀 query 파라미터 (선택)api_base: 프롬프트 관리 API의 기본 URLapi_key: 인증용 선택적 API 키 (Bearer 토큰으로 전송)ignore_prompt_manager_model:true이면 프롬프트의 모델 대신 클라이언트가 지정한 모델 사용 (기본false)ignore_prompt_manager_optional_params:true이면 프롬프트의 선택 파라미터를 클라이언트 params와 병합하지 않음 (기본false)
사용법
LiteLLM SDK로 사용
프롬프트 ID를 사용한 기본 사용법:
from litellm import completion
response = completion(
model="gpt-5.6-terra",
prompt_id="simple_prompt",
messages=[{"role": "user", "content": "Additional message"}]
)
프롬프트 변수 사용:
response = completion(
model="gpt-5.6-terra",
prompt_id="simple_prompt",
prompt_variables={
"domain": "data science",
"task": "analyzing customer churn"
},
messages=[{"role": "user", "content": "Please provide a detailed analysis"}]
)
프롬프트 템플릿에서 {domain}은 "data science"로, {task}는 "analyzing customer churn"으로 치환됩니다.
LiteLLM Proxy로 사용
- config로 프록시 시작:
litellm --config /path/to/config.yaml
- prompt_id로 요청:
curl http://0.0.0.0:4000/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ***" \
-d '{
"model": "gpt-5.6-terra",
"prompt_id": "simple_prompt",
"prompt_variables": {
"domain": "healthcare",
"task": "patient risk assessment"
},
"messages": [
{"role": "user", "content": "Analyze the following data..."}
]
}'
- OpenAI SDK로 사용:
from openai import OpenAI
client = OpenAI(
base_url="http://0.0.0.0:4000",
api_key="sk-<your-litellm-api-key>"
)
response = client.chat.completions.create(
model="gpt-5.6-terra",
messages=[
{"role": "user", "content": "Analyze the data"}
],
extra_body={
"prompt_id": "simple_prompt",
"prompt_variables": {
"domain": "finance",
"task": "fraud detection"
}
}
)
구현 예시
완전한 참조 구현(여러 예시 프롬프트, 인증, 편의 엔드포인트 포함)은 mock_prompt_management_server.py를 참고하세요.
최소 FastAPI 예시:
from fastapi import FastAPI, HTTPException, Header
from typing import Optional, Dict, Any, List
from pydantic import BaseModel
app = FastAPI()
# In-memory prompt storage (replace with your database)
PROMPTS = {
"hello-world-prompt": {
"prompt_id": "hello-world-prompt",
"prompt_template": [
{
"role": "system",
"content": "You are a helpful assistant specialized in {domain}."
},
{
"role": "user",
"content": "Help me with: {task}"
}
],
"prompt_template_model": "gpt-5.6-terra",
"prompt_template_optional_params": {
"temperature": 0.7,
"max_tokens": 500
}
},
"code-review-prompt": {
"prompt_id": "code-review-prompt",
"prompt_template": [
{
"role": "system",
"content": "You are an expert code reviewer. Review code for {language}."
},
{
"role": "user",
"content": "Review the following code:\n\n{code}"
}
],
"prompt_template_model": "gpt-5.6-terra",
"prompt_template_optional_params": {
"temperature": 0.3,
"max_tokens": 1000
}
}
}
class PromptResponse(BaseModel):
prompt_id: str
prompt_template: List[Dict[str, str]]
prompt_template_model: Optional[str] = None
prompt_template_optional_params: Optional[Dict[str, Any]] = None
@app.get("/beta/litellm_prompt_management", response_model=PromptResponse)
async def get_prompt(
prompt_id: str,
authorization: *** = Header(None),
project_name: Optional[str] = None,
slug: Optional[str] = None,
):
"""
Get a prompt by ID with optional filtering by project_name and slug.
Args:
prompt_id: The ID of the prompt to fetch
authorization: Optional *** token for authentication
project_name: Optional project name filter
slug: Optional slug filter
"""
# Optional: Validate authorization
if authorization:
token = authorization.replace("Bearer ", "")
# Validate your token here
if not is_valid_token(token):
raise HTTPException(status_code=401, detail="Invalid API key")
# Optional: Apply additional filtering based on custom params
if project_name or slug:
# You can use these parameters to filter or validate access
# For example, check if the user has access to this project
pass
# Fetch the prompt from your storage
if prompt_id not in PROMPTS:
raise HTTPException(
status_code=404,
detail=f"Prompt '{prompt_id}' not found"
)
prompt_data = PROMPTS[prompt_id]
return PromptResponse(**prompt_data)
def is_valid_token(token: str) -> bool:
"""Validate API token - implement your logic here"""
# Example: Check against your database or secret store
valid_tokens = ["your-secret-token", "another-valid-token"]
return token in valid_tokens
# Optional: Health check endpoint
@app.get("/health")
async def health_check():
return {"status": "healthy"}
# Optional: List all prompts endpoint
@app.get("/prompts")
async def list_prompts(authorization: *** = Header(None)):
"""List all available prompts"""
if authorization:
token = authorization.replace("Bearer ", "")
if not is_valid_token(token):
raise HTTPException(status_code=401, detail="Invalid API key")
return {
"prompts": [
{"prompt_id": pid, "model": p.get("prompt_template_model")}
for pid, p in PROMPTS.items()
]
}
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8080)
예시 서버 실행
- 의존성 설치:
uv add fastapi uvicorn
- 위 코드를
prompt_server.py로 저장 - 서버 실행:
python prompt_server.py
- 엔드포인트 테스트:
curl "http://localhost:8080/beta/litellm_prompt_management?prompt_id=hello-world-prompt&project_name=litellm&slug=hello-world-prompt-2bac"
기대 응답:
{
"prompt_id": "hello-world-prompt",
"prompt_template": [
{
"role": "system",
"content": "You are a helpful assistant specialized in {domain}."
},
{
"role": "user",
"content": "Help me with: {task}"
}
],
"prompt_template_model": "gpt-5.6-terra",
"prompt_template_optional_params": {
"temperature": 0.7,
"max_tokens": 500
}
}
고급 기능
변수 치환
LiteLLM은 {variable} 문법으로 프롬프트 템플릿의 변수를 자동 치환해요. {variable}과 {{variable}} 형식 모두 지원됩니다.
예시 프롬프트 템플릿:
{
"prompt_template": [
{
"role": "system",
"content": "You are an expert in {domain} with {years} years of experience."
}
]
}
클라이언트 요청:
completion(
model="gpt-5.6-terra",
prompt_id="expert_prompt",
prompt_variables={
"domain": "machine learning",
"years": "10"
}
)
결과:
"You are an expert in machine learning with 10 years of experience."
캐싱
LiteLLM은 가져온 프롬프트를 메모리에 자동 캐시해요. 캐시 키에는 다음이 포함됩니다:
prompt_idprompt_label(제공 시)prompt_version(제공 시)
즉, API 엔드포인트는 고유한 프롬프트 구성당 한 번만 호출됩니다.
모델 오버라이드 동작
기본 동작 (ignore_prompt_manager_model 없음):
prompts:
- prompt_id: "my_prompt"
litellm_params:
prompt_integration: "generic_prompt_management"
api_base: http://localhost:8080
API가 "prompt_template_model": "gpt-5.6-terra"를 반환하면, LiteLLM은 클라이언트가 무엇을 지정했든 gpt-5.6-terra를 사용합니다.
ignore_prompt_manager_model: true 설정 시:
prompts:
- prompt_id: "my_prompt"
litellm_params:
prompt_integration: "generic_prompt_management"
api_base: http://localhost:8080
ignore_prompt_manager_model: true
LiteLLM은 프롬프트의 모델을 무시하고 클라이언트가 지정한 모델을 사용해요.
파라미터 병합 동작
기본 동작 (ignore_prompt_manager_optional_params 없음):
클라이언트 params는 프롬프트 params와 병합되며, 프롬프트 params가 우선합니다:
# Prompt returns: {"temperature": 0.7, "max_tokens": 500}
# Client sends: {"temperature": 0.9, "top_p": 0.95}
# Final params: {"temperature": 0.7, "max_tokens": 500, "top_p": 0.95}
ignore_prompt_manager_optional_params: true 설정 시:
클라이언트 params만 사용됩니다:
# Prompt returns: {"temperature": 0.7, "max_tokens": 500}
# Client sends: {"temperature": 0.9, "top_p": 0.95}
# Final params: {"temperature": 0.9, "top_p": 0.95}
보안 고려 사항
- 인증:
api_key파라미터로 프롬프트 관리 API를 보호하세요 - 권한 부여: 커스텀 query 파라미터로 팀/사용자 기반 접근 제어 구현
- 속도 제한: API 남용을 막기 위한 rate limiting 추가
- 입력 검증: 처리 전 모든 query 파라미터 검증
- HTTPS: 프로덕션에서는 암호화 통신을 위해 항상 HTTPS 사용
- 시크릿: API 키는 config 파일이 아닌 환경 변수에 저장
사용 사례
✅ 제네릭 프롬프트 관리 API 사용:
- PR을 기다리지 않고 즉시 통합하고 싶을 때
- 프롬프트 관리 서비스를 직접 유지할 때
- 프롬프트 버전 관리와 업데이트를 완전히 제어해야 할 때
- 커스텀 프롬프트 관리 기능을 만들고 싶을 때
- 내부 시스템과 통합해야 할 때
✅ 일반적인 시나리오:
- 조직을 위한 내부 프롬프트 관리 시스템
- 팀 기반 접근 제어가 있는 멀티 테넌트 프롬프트 관리
- 서로 다른 프롬프트 버전의 A/B 테스트
- 프롬프트 실험과 분석
- 기존 프롬프트 엔지니어링 워크플로와 통합
언제 이것을 써야 하나
✅ 제네릭 프롬프트 관리 API 사용:
- PR을 기다리지 않고 즉시 통합하고 싶을 때
- 프롬프트 관리 서비스를 직접 유지할 때
- 업데이트와 기능을 완전히 제어해야 할 때
- 커스텀 프롬프트 저장 및 버전 관리 로직을 원할 때
❌ PR을 만들기:
- LiteLLM 내부와 더 깊이 통합하고 싶을 때
- 통합에 복잡한 LiteLLM 전용 로직이 필요할 때
- 빌트인 프로바이더로 소개되고 싶을 때
- 커뮤니티를 위한 재사용 가능한 통합을 만들 때
문제 해결
프롬프트를 찾지 못함
prompt_id가 정확히 일치하는지 확인 (대소문자 구분)- API 엔드포인트가 LiteLLM에서 접근 가능한지 확인
api_key를 사용한다면 인증 확인
변수가 치환되지 않음
- 변수가
{variable}또는{{variable}}문법을 사용하는지 확인 prompt_variables의 변수 이름이 템플릿과 정확히 일치하는지 확인- 변수는 대소문자를 구분해요
모델이 오버라이드되지 않음
- config에
ignore_prompt_manager_model: true가 있는지 확인 - API가 응답에서
prompt_template_model을 반환하는지 확인
파라미터가 적용되지 않음
ignore_prompt_manager_optional_params: true가 설정됐는지 확인- API가
prompt_template_optional_params를 반환하는지 확인 - 파라미터 이름이 OpenAI의 파라미터 이름과 일치하는지 확인
질문?
이것은 베타 API예요. 피드백에 따라 적극적으로 개선 중입니다. 추가 기능이 필요하면 이슈나 PR을 열어 주세요.