0Pricing
AI Prompt Engineering · 강의

로깅 및 문서화 전략

재현 가능한 디버깅을 위해 프롬프트 버전, 입력, 출력을 기록합니다.

로깅 및 문서화 전략은(는) CoddyKit의 무료 AI Prompt Engineering 강의입니다. 이것은 4개 중 4번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 AI Prompt Engineering 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. AI Prompt Engineering 강의에는 총 4개의 강의가 포함되어 있습니다.

프롬프트 기록이 중요한 이유

기록이 없으면 사용자가 보고할 때까지 프롬프트 실패를 알 수 없습니다. 기록을 사용하면 다음을 수행할 수 있습니다:

  • 회귀가 발생하는 즉시 감지
  • 과거의 모든 실패를 발생 당시와 정확히 동일하게 재현
  • 프롬프트가 발전하면서 시간에 따른 개선 정도 측정
  • 규정 준수 또는 안전성을 위해 모델 동작 감사

운영 프롬프트 시스템에서 기록은 선택 사항이 아닙니다. 신뢰할 수 있는 LLM 애플리케이션의 기반입니다.

최소 필수 기록 항목

모든 프롬프트 상호작용은 최소한 다음 필드를 기록해야 합니다:

  • timestamp: ISO 8601 UTC
  • prompt_id: 사용된 프롬프트 템플릿
  • model: 정확한 모델 이름 및 버전
  • temperature: 샘플링 매개변수
  • input: 사용자 메시지(PII가 포함된 경우 해시)
  • output: 모델 응답
  • latency_ms: 응답 시간
  • tokens_used: 입력 + 출력 토큰
import time, json
from datetime import datetime, timezone

def logged_call(prompt_id, system_prompt, user_message, model='gpt-4o', temperature=0.7):
    start = time.time()
    resp = client.chat.completions.create(
        model=model,
        messages=[
            {'role': 'system', 'content': system_prompt},
            {'role': 'user', 'content': user_message}
        ],
        temperature=temperature
    )
    latency = int((time.time() - start) * 1000)
    output = resp.choices[0].message.content
    log_entry = {
        'timestamp': datetime.now(timezone.utc).isoformat(),
        'prompt_id': prompt_id,
        'model': model,
        'temperature': temperature,
        'input': user_message,
        'output': output,
        'latency_ms': latency,
        'input_tokens': resp.usage.prompt_tokens,
        'output_tokens': resp.usage.completion_tokens
    }
    append_log(log_entry)
    return output

구조화된 기록 형식

기록 파일에는 줄바꿈으로 구분된 JSON(JSONL)을 사용하십시오. 각 줄은 완전하고 유효한 JSON 객체입니다. 이 형식은 다음과 같은 장점이 있습니다:

  • 잠금 없이 쉽게 추가할 수 있음
  • jq, 판다스 및 모든 기록 집계 도구에서 읽을 수 있음
  • 실시간 처리에 적합함 — 각 줄을 도착하는 즉시 처리할 수 있음
import json

LOG_FILE = 'prompt_logs.jsonl'

def append_log(entry):
    with open(LOG_FILE, 'a') as f:
        f.write(json.dumps(entry) + '\n')

def read_logs():
    with open(LOG_FILE) as f:
        return [json.loads(line) for line in f if line.strip()]

# Query: all entries for prompt_id 'summarize_v3'
logs = read_logs()
summarize_logs = [e for e in logs if e['prompt_id'] == 'summarize_v3']
print(f'Total calls to summarize_v3: {len(summarize_logs)}')

프롬프트 버전 관리

프롬프트는 시간이 지나면서 변경됩니다. 버전 관리가 없으면 과거 동작을 재현하거나 프롬프트 버전 간 모델 출력을 비교할 수 없습니다. 모든 기록 항목에 버전 식별자를 사용하십시오.

간단한 버전 관리 방법은 의미론적 버전 문자열(예: v1.2.3) 또는 깃 커밋 해시를 사용하는 것입니다. 프롬프트 버전은 전용 파일에 저장하여 어떤 버전이든 재실행에 사용할 수 있도록 검색 가능하게 하십시오.

PROMPTS = {
    'summarize': {
        'v1': 'Summarize the following text.',
        'v2': 'Summarize the following text in 3 sentences.',
        'v3': 'Summarize the following text in exactly 3 sentences. '
              'Start each sentence on a new line. No bullet points.'
    }
}

CURRENT_VERSIONS = {'summarize': 'v3'}

def get_prompt(prompt_id):
    version = CURRENT_VERSIONS[prompt_id]
    return version, PROMPTS[prompt_id][version]

version, prompt = get_prompt('summarize')
log_entry['prompt_version'] = version

기록에서 PII 처리

사용자 입력에는 개인 식별 정보(PII)가 포함될 수 있습니다. 원시 입력을 기록하면 GDPR 또는 CCPA를 위반할 수 있습니다. 선택지는 다음과 같습니다:

  • 해시: 입력의 SHA-256을 저장합니다. 중복 제거에는 재현 가능하지만 재실행에는 사용할 수 없습니다
  • 가리기: 정규식 또는 NER 모델을 사용하여 기록하기 전에 PII를 대체합니다
  • 별도 저장: 접근 제어가 적용된 암호화 저장소에 PII를 기록하고, 주 기록에는 참조 ID만 기록합니다
import hashlib, re

def redact_pii(text):
    # Redact email addresses
    text = re.sub(r'[\w.-]+@[\w.-]+\.\w+', '[EMAIL]', text)
    # Redact phone numbers (US format)
    text = re.sub(r'\b\d{3}[-.]\d{3}[-.]\d{4}\b', '[PHONE]', text)
    return text

def hash_input(text):
    return hashlib.sha256(text.encode()).hexdigest()[:16]

log_entry['input'] = redact_pii(user_message)
log_entry['input_hash'] = hash_input(user_message)

지연 시간 및 비용 추적

기록을 통해 비용 및 지연 시간 현황판을 만들 수 있습니다. 프롬프트 변경 후 성능이나 비용의 회귀를 감지할 수 있도록 프롬프트 버전별 지표를 추적하십시오:

def compute_cost(entry, price_per_1m_input=5.0, price_per_1m_output=15.0):
    input_cost = entry['input_tokens'] / 1_000_000 * price_per_1m_input
    output_cost = entry['output_tokens'] / 1_000_000 * price_per_1m_output
    return input_cost + output_cost

def prompt_stats(prompt_id, version):
    logs = [e for e in read_logs()
            if e['prompt_id'] == prompt_id and e.get('prompt_version') == version]
    if not logs:
        return
    avg_latency = sum(e['latency_ms'] for e in logs) / len(logs)
    total_cost = sum(compute_cost(e) for e in logs)
    print(f'{prompt_id} {version}: {len(logs)} calls, avg {avg_latency:.0f}ms, total ${total_cost:.4f}')

출력 평가 기록

원시 기록을 넘어 각 기록 항목에 평가 점수도 함께 저장하십시오. 이를 통해 추세를 분석할 수 있습니다. 프롬프트 버전이 바뀌면서 출력 품질이 향상되고 있습니까?

def evaluated_call(prompt_id, system_prompt, user_message, evaluator_fn):
    output = logged_call(prompt_id, system_prompt, user_message)
    score = evaluator_fn(user_message, output)
    # Update the last log entry with the evaluation score
    logs = read_logs()
    last = logs[-1]
    last['eval_score'] = score
    last['eval_pass'] = score >= 0.8
    # Rewrite the last line
    with open(LOG_FILE, 'a') as f:
        # In practice, use a DB or separate eval log
        pass
    return output, score

프롬프트 문서화

각 프롬프트 템플릿에는 다음 내용을 다루는 문서 항목이 함께 있어야 합니다:

  • 목적: 이 프롬프트가 수행하는 작업
  • 변수: 어떤 자리표시자가 있으며 각 자리표시자에 어떤 값이 필요한지
  • 알려진 제한 사항: 실패하는 것으로 알려진 입력
  • 버전 기록: 각 버전에서 무엇이 변경되었으며 그 이유
  • 시험 사례: 이 프롬프트의 시험 모음 링크
PROMPT_DOCS = {
    'summarize': {
        'purpose': 'Summarize a single text passage into 3 sentences.',
        'variables': {'text': 'The passage to summarize (max 2000 tokens)'},
        'known_limitations': [
            'Fails to preserve numbers accurately for texts with many statistics',
            'May not summarize correctly for non-English text'
        ],
        'versions': {
            'v1': 'Initial version — vague length instruction',
            'v2': 'Added 3-sentence limit',
            'v3': 'Added line-break and no-bullet formatting fix'
        },
        'test_suite': 'tests/test_summarize.py'
    }
}

중앙 집중식 기록 서비스 사용

운영 시스템에서는 로컬 파일 대신 중앙 집중식 서비스에 기록을 작성하십시오:

  • LangSmith: LangChain의 기본 추적 및 평가 플랫폼
  • 웨이츠 앤 바이어스 프롬프트: 프롬프트 실험 추적
  • 데이터독 / 그라파나: 사용자 지정 지표를 지원하는 표준 운영 현황판
  • 수파베이스 / PostgreSQL: 에스큐엘로 기록을 조회하여 임시 분석 수행

구조는 동일하고 대상만 변경됩니다.

# Example: writing to Supabase
from supabase import create_client

supabase = create_client('https://xxx.supabase.co', 'your-anon-key')

def log_to_supabase(entry):
    supabase.table('prompt_logs').insert(entry).execute()

# Now query with SQL:
# SELECT prompt_id, prompt_version, AVG(latency_ms), COUNT(*)
# FROM prompt_logs
# WHERE timestamp > NOW() - INTERVAL '7 days'
# GROUP BY prompt_id, prompt_version
# ORDER BY COUNT(*) DESC;

실패 급증 알림

실패율이 임계값을 초과해 급증하면 알림을 설정하십시오. 예를 들어 5분 구간에서 프롬프트 호출의 10% 초과가 유효하지 않은 JSON을 반환하면 알림을 보내십시오.

from collections import deque
from datetime import datetime, timezone, timedelta

recent_results = deque(maxlen=100)  # sliding window

def track_and_alert(prompt_id, success, alert_fn, threshold=0.10):
    recent_results.append({'success': success, 'time': datetime.now(timezone.utc)})
    window = [
        r for r in recent_results
        if r['time'] > datetime.now(timezone.utc) - timedelta(minutes=5)
    ]
    if not window:
        return
    fail_rate = sum(1 for r in window if not r['success']) / len(window)
    if fail_rate > threshold:
        alert_fn(f'ALERT: {prompt_id} failure rate {fail_rate:.0%} in last 5 min')

보존 및 보관

로그 보존 정책을 정의하십시오:

  • 원시 호출 로그: 30일(순환 방식) — 양이 많고 최근 문제를 디버깅하는 데 필요합니다
  • 집계 지표: 1년 — 추세 분석과 비용 예측에 필요합니다
  • 실패 로그: 무기한 — 근본 원인 패턴을 파악하는 데 필요합니다

30일이 지난 원시 로그는 압축하여 보관하십시오. 실패 로그는 절대 삭제하지 마십시오. 실패 로그는 프롬프트 엔지니어링을 위한 조직의 축적된 기억입니다.

지식 확인

하나의 큰 JSON 배열과 비교할 때 프롬프트 로그에 줄바꿈으로 구분된 JSON(JSONL) 형식을 사용하는 주요 장점은 무엇입니까?

복습: 로그 기록과 문서화

프롬프트 로그 기록과 문서화를 위한 주요 관행:

  • 모든 호출 기록: 시간 기록, 프롬프트 ID, 버전, 모델, 온도, 입력, 출력, 지연 시간, 토큰 수
  • JSONL 형식 사용: 추가에 적합하며 표준 도구로 조회할 수 있음
  • 프롬프트 버전 관리: 모든 변경 사항에 새 버전을 부여하고 로그에서 해당 버전을 참조함
  • PII 처리: 기록하기 전에 민감한 입력을 마스킹하거나 해시 처리함
  • 비용과 지연 시간 추적: 프롬프트 업데이트 후 회귀를 감지함
  • 실패 급증 시 알림: 이동 구간별 실패율 모니터링

이것으로 프롬프트 실패 디버깅에 관한 17번 과정을 마칩니다. 다음: 프롬프트 주입과 방어.

자주 묻는 질문

“로깅 및 문서화 전략” 강의는 무료인가요?

네 — “로깅 및 문서화 전략” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 AI Prompt Engineering 강의 전체를 잠금 해제할 수 있습니다. AI Prompt Engineering 강의에는 총 4개의 강의가 포함되어 있습니다.

“로깅 및 문서화 전략”에서 뭘 배우나요?

재현 가능한 디버깅을 위해 프롬프트 버전, 입력, 출력을 기록합니다. 브라우저에서 직접 실행하는 실습 코드로 AI Prompt Engineering을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

AI Prompt Engineering을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 AI Prompt Engineering은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 4번째 강의입니다.

“로깅 및 문서화 전략” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 AI Prompt Engineering 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 AI Prompt Engineering 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. 예상치 못한 출력 진단
  2. 프롬프트의 근본 원인 분석
  3. 체계적인 디버깅 접근법
  4. 로깅 및 문서화 전략
← AI Prompt Engineering(으)로 돌아가기