OpenAI Realtime 프롬프트 토큰 사전 검증

마지막 업데이트 2026-09-12

문서 읽는 법 · 설명식

이 문서는 이렇게 읽으면 됩니다

OpenAI Realtime 프롬프트 토큰 사전 검증의 현재 구현을 먼저 확인한 뒤, 공통 변수 변경의 영향 범위와 권장 운영 구조를 따라갑니다. 실제 코드·테스트·로그로 확인한 사실과 아직 구현되지 않은 설계는 상태 배지로 구분했습니다.

핵심 흐름 펼쳐 보기
  1. 현재 수동 검증 경로와 그 한계를 확인합니다.
  2. DynamoDB 토큰 컬럼과 종속 활동 재검증의 역할을 구분합니다.
  3. 저장 시 검증, 해시 캐시, 세션 시작 안전망 순서로 권장 구조를 확인합니다.
  • 현재 구현된 수동 검증 흐름
  • DynamoDB 행 검토와 토큰 컬럼의 효용
  • 권장 운영 구조: 사전 검증 중심의 하이브리드

현재 구현, DynamoDB 검토, 공통 변수 영향도 재검증, 런타임 안전망을 한 문서로 정리한다.

작성 2026-09-03 이슈 ID 미지정 PPI develop 작업트리 코드 커밋·배포 전

결론

미채택 프롬프트 테스트 화면에서 편집 중인 지침을 전개한 뒤 OpenAI /v1/realtime/client_secrets로 왕복 검증하는 경로를 제안했으나, 이 방식은 커밋되지 않았다. 실제 구현은 아래 현행 반영 박스 참고 — 로컬 토크나이저 기반 prompt-token-guard.ts(PPI-1268).

부분 해결 이 기능은 선택한 사용자·아바타·활동 변수 조합 한 건을 검사한다. 활동 템플릿 저장 차단, 공통_룰 변경 시 모든 종속 활동 재검증, 세션 시작 전 캐시 확인은 아직 구현되지 않았다.

운영 설계 필요 권장 구조는 저장 시 영향도 기반 사전 검증 + 검증 결과 캐시 + 세션 시작 시 최종 해시 확인이다. 매 세션마다 임시 시크릿을 발급하는 방식은 비용·지연·OpenAI 가용성 의존을 늘리므로 캐시 미스 안전망으로만 사용한다.

⚠ 현행 반영 (2026-09-12 확인) — 아래 3·4절은 채택되지 않은 설계안입니다

이 문서가 “현재 구현”이라 적은 apps/web/lib/voice-agent/realtime-instruction-validation.tsapps/web/app/api/prompt-test/validate-instructions/route.tsgit 히스토리에 존재한 적이 없습니다. OpenAI에 임시 시크릿을 발급해 왕복 검증하는 이 방식은 채택되지 않았습니다.

실제로 착지한 것은 PPI-1268(f9e0a4ae, 2026-09-08)의 로컬 토크나이저 기반 사전 경고입니다 — 핵심 파일은 apps/web/lib/prompt-token-guard.ts 하나입니다.

항목이 문서의 설계안실제 구현 (PPI-1268)
판정 주체OpenAI client_secrets 왕복로컬 gpt-tokenizer o200k_base 인코딩
네트워크·비용검증마다 발생없음 — 입력 중 실시간 계산 가능
한도provider 응답 문구로 분류TOKEN_HARD_LIMIT 16,384 / 실제 차단은 TOKEN_WARN_THRESHOLD 15,500
프리셋 변수실제 사용자·아바타 선택 필요3글자 더미 "값값값"로 근사(오늘_날짜만 실값). 그 오차를 흡수하려고 884토큰 여유를 둔 것
적용 지점프롬프트 테스트 화면 1곳활동 템플릿·프롬프트 변수 저장 API + UI 카운터 다수(아래)

공개 API: estimateInstructionTokens()(변수 전개 후 토큰 수) · estimateContentTokens()(#{} content 단독) · exceedsTokenLimit() · formatTokenLimitMessage(). 배선처는 app/api/activity-templates/{route,[id],bulk} · app/api/prompt-variables/{route,[id]} · components/ui/prompt-token-counter.tsx · prompt-variable-token-counter.tsx · hooks/use-token-count.ts입니다.

왜 content 단독 검사가 성립하나#{} content 자체가 이미 임계값을 넘으면 그걸 쓰는 어떤 템플릿이든 최종 지침도 반드시 넘습니다. 덕분에 사용처 전체를 스캔하지 않고도 변수 저장 시점에 가벼운 사전 경고를 낼 수 있습니다 — 아래 4절이 “미구현”이라 적은 영향도 문제의 실제 해법입니다.

토크나이저 주의 — 인코딩을 모델명이 아니라 o200k_base직접 고정했습니다. 새 realtime 모델이 추가되면 REALTIME_MODEL_MAP·REALTIME_MODEL과 함께 인코딩 계열이 그대로인지 먼저 확인해야 합니다.

1. 문제와 목표

활동 지침은 DynamoDB 원문 그대로 OpenAI에 전달되지 않는다. #{공통_룰} 같은 전역 프롬프트 변수, 사용자·아바타 프리셋, 활동별 변수까지 전개된 최종 지침이 Realtime 세션 입력이 된다. 따라서 개별 행의 원문 길이만 확인하면 실제 제한 초과를 놓칠 수 있다.

가장 큰 영향도 문제: 공통_룰의 content를 바꾸면 그 변수를 참조하는 모든 활동의 최종 지침이 동시에 달라진다. 이때는 변수 행 하나가 아니라 직접 참조하는 모든 활동 지침 전체를 다시 전개하고 검증해야 한다.

2. OpenAI 계약과 한도 해석

항목확인 내용PPI 설계 영향
세션 수명공식 Realtime conversation 문서는 최대 60분으로 안내한다.긴 세션에서는 대화 히스토리 truncation 정책도 별도 관리해야 하지만, 시작 지침 검증과는 다른 축이다.
gpt-realtime 모델 페이지2026-09-03 확인 시 context 32,000, max output 4,096으로 표시된다.내부 공유값 32,768/입력 28,672와 차이가 있으므로 파생 상수를 고정하지 않는다.
지침 거부 계약현재 테스트는 OpenAI 오류 예시 Instructions cannot be longer than 16384 tokensparam=instructionstoo_long으로 분류한다.로컬 tokenizer 추정치보다 provider가 같은 모델·엔드포인트에서 내린 판정을 최종 기준으로 사용한다.
지침 + tools공유된 GA 운영 조건은 instructions와 tools 합계 제한을 전제로 한다. 현재 PPI Agent 생성부에는 명시적 업무용 function tool이 없고, 검증 요청도 tools를 보내지 않는다.향후 tools를 추가하면 tool schema까지 동일 요청에 포함하고 toolSchemaHash를 검증 키에 넣어야 한다.

공식 참고: Realtime conversations, gpt-realtime model, Create Realtime client secret. 수치가 서로 다른 시점의 문서·서비스 계약 사이에서 바뀔 수 있으므로 검증 결과에는 model과 검증 시각을 함께 남겨야 한다.

3. 수동 검증 흐름 미채택 설계안

아래는 위 현행 반영 박스에서 설명한, 구현되지 않은 OpenAI 왕복 방식입니다. 설계 의도 기록으로만 남겨 둡니다.

편집 원문
instruction
variables
실제와 같은 전개
#{} + 프리셋 + 활동 변수
replaceAllVariables
OpenAI 판정
client_secrets
ok / too_long / rejected / unavailable
  1. apps/web/components/pages/prompt-test.tsx의 “검증” 버튼이 instruction, variables, userId, avatarId를 전송한다.
  2. apps/web/app/api/prompt-test/validate-instructions/route.ts가 인증, 필수 필드, 원문 1,000,000자 상한을 확인한다.
  3. 모든 전역 프롬프트 변수를 읽고, 선택 사용자·아바타의 프리셋과 활동 변수를 합쳐 실제 수업의 buildActivityInstruction과 같은 순서로 전개한다.
  4. apps/web/lib/voice-agent/realtime-instruction-validation.ts가 model gpt-realtime, 10초 TTL, 15초 요청 timeout으로 client secret 생성을 요청한다.
  5. 2xx는 통과, instruction 관련 400과 토큰 문구는 too_long, 그 외 400은 rejected, 비-400은 provider_unavailable로 분류한다.
  6. 응답의 임시 시크릿 값은 결과 객체에 넣지 않고 즉시 폐기한다. UI에는 변수 전개 후 문자 수와 provider 판정만 표시한다.

4. 빠진 게이트 2026-09-08 상당수 해소

검증 시점현재 상태의미
프롬프트 테스트 편집 중구현사용자가 버튼을 눌렀을 때 단일 최종 전개본을 검증한다. 저장은 하지 않는다.
활동 템플릿 지침 저장구현 (PPI-1268)activity-templates 저장·일괄 API가 estimateInstructionTokens()로 최종 전개본을 재고, 15,500 토큰 초과 시 저장을 차단한다.
프롬프트 변수 content 저장구현 (PPI-1268)prompt-variables 저장 API가 estimateContentTokens()로 content 단독 토큰을 재 차단한다. 이름 변경 시 옛 이름·새 이름 두 패턴을 모두 재계산해 선참조 템플릿 누락을 막는다.
세션 시작 직전미구현최종 지침 해시가 마지막 통과본과 같은지 확인하지 않는다. OpenAI 거부 시점까지 문제가 늦게 드러날 수 있다.
LLM 자동 축약미구현·비권장 기본값런타임에서 지침 의미를 바꾸므로 자동 복구 경로로 두지 않는다.

5. DynamoDB 행 검토와 토큰 컬럼의 효용

테이블현재 주요 필드현재 검증 메타데이터
ppi-activity2-template-{stage}id, title, type, steps, instructionEnabled, instruction, persona, theme, semanticVad, temperature, variables, subAvatars, createdAt, updatedAt 등없음
ppi-prompt-variable-{stage}id, name, content, tags, createdAt, updatedAt없음
미리 계산한 토큰 수 컬럼은 유용하다. 목록 정렬, 위험도 표시, 변경 전후 증감, 불필요한 provider 호출 회피에 효과가 있다. 하지만 단독 검증값으로는 부족하다. 활동 원문과 공통 변수의 토큰 수를 더해도 치환 후 tokenizer 경계가 달라질 수 있고, 프리셋·활동 변수·향후 tool schema·모델 버전이 최종 입력을 바꾼다.

권장하는 것은 단일 tokenCount가 아니라 검증 스냅샷이다.

validation: {
  status: "passed" | "too_long" | "rejected" | "stale",
  model: "gpt-realtime",
  providerLimitTokens: 16384,
  providerProvidedTokens: 12345,
  expandedChars: 21000,
  contentHash: "sha256(finalExpandedInstructions)",
  promptVariablesHash: "sha256(referencedVariableVersions)",
  toolSchemaHash: "sha256(effectiveTools)",
  validatedAt: 1788390000
}

프롬프트 변수 행의 contentTokenEstimate는 진단용으로 둘 수 있지만, 그 값이 통과했다고 해서 종속 활동이 통과한 것은 아니다. 신뢰 가능한 상태는 활동별 최종 전개본의 provider 판정과 해시다.

6. 변경 유형별 재검증 범위

변경반드시 재검증할 대상현재 코드에서 재사용 가능한 단서
활동 템플릿 instruction/variables 수정변경된 템플릿의 전체 최종 지침. 사용자·아바타 프리셋이 길이에 영향을 주므로 운영 대표 조합 또는 상한 조합을 사용한다.updateActivityTemplate 저장 경로, replaceAllVariables
공통_룰 content 수정#{공통_룰}을 직접 참조하는 모든 활동 템플릿의 전체 최종 지침/api/prompt-variables/[id]/usage가 모든 템플릿을 Scan하고 instruction.includes(pattern)로 직접 참조 목록을 만든다.
프롬프트 변수 이름 변경이름 전파 대상 전체현재 PUT 경로도 템플릿 전체를 Scan해 replaceAll로 이름을 전파하지만, 변경 후 토큰 검증은 하지 않는다.
프리셋 생성 규칙·tool schema·모델 변경기존 통과 결과 전체를 stale 처리하고 재검증검증 스냅샷의 model/hash 버전으로 무효화 가능
현재 프롬프트 변수는 서로 중첩하는 #{다른_변수} content가 저장 단계에서 금지된다. 따라서 현 구조의 영향도는 직접 참조 스캔으로 닫히지만, 향후 중첩을 허용하면 의존성 그래프와 순환 검출이 필요하다.

7. 권장 운영 구조: 사전 검증 중심의 하이브리드

  1. 편집 시 빠른 추정: 로컬 tokenizer/문자 수로 경고만 제공한다. 모델별 차이 때문에 저장 허용의 최종 근거로 사용하지 않는다.
  2. 저장 시 provider 검증: 활동 수정은 해당 활동, 공통 변수 수정은 모든 직접 종속 활동을 큐에 넣어 최종 전개본을 검증한다.
  3. 검증 결과 캐시: model + 최종 지침 hash + tool schema hash가 같으면 재호출하지 않는다. 결과가 모두 통과한 뒤 저장을 확정하거나, 대량 영향 변경은 draft→검증→publish 상태로 분리한다.
  4. 세션 시작 시 저비용 확인: 최종 전개본 hash와 통과 스냅샷만 비교한다. 일치하면 바로 시작하고, stale/cache miss일 때만 provider 검증을 호출한다.
  5. 장애 정책: 기존에 통과한 동일 hash가 있으면 OpenAI 검증 서비스 일시 장애에도 시작 가능하다. 새 hash가 미검증이면 fail closed 또는 관리자 override를 정책으로 명시한다.

효율 판단: 매 세션 provider 검증은 동일 지침에 대한 중복 네트워크 호출, 최대 15초 추가 대기 가능성, rate limit 및 provider 장애 결합을 만든다. 반면 저장 시 검증은 변경 횟수에 비례한다. 세션 횟수가 편집 횟수보다 훨씬 많으므로 사전 검증이 기본 경로로 더 효율적이다.

8. “거부되면 LLM으로 줄이고 시작” 방안 검토

세션 시작 critical path에서 자동 축약하는 방식은 권장하지 않는다. 길이는 줄어도 우선순위, 금지 규칙, 고정 멘트, STEP 조건이 사라질 수 있고, 매번 다른 결과가 나와 재현성과 감사 가능성이 떨어진다. 축약 LLM 자체의 지연·비용·실패도 세션 시작에 추가된다.

허용 가능한 형태는 관리자용 보조 흐름이다: 초과 지침 탐지 → 축약 초안 생성 → 원문 대비 의미 diff/필수 규칙 체크 → 회귀 대화 평가 → 사람이 승인 → 새 버전 저장 → 종속 활동 재검증. 운영 세션에서는 승인된 버전만 사용한다.

9. 검증 증거

자동 테스트 — 2026-09-03

운영 로그 확인 — provider 거부 건수

10. 남은 위험과 다음 단계

우선순위: ① 활동 저장 게이트 ② 공통 변수 영향도 재검증 큐 ③ DynamoDB 검증 스냅샷 ④ 세션 시작 hash 확인 ⑤ provider 거부 구조화 로그 ⑥ 관리자용 축약 제안 워크플로.

관련 문서