모델 업데이트를 견뎌내는 프롬프트 엔지니어링 패턴은 모델이 스스로 추론할 수 없는 정보를 담은 것들입니다. 즉, 청중을 설정하는 역할, 모델이 알 수 없는 컨텍스트, 판단 기준이 있는 태스크, 그리고 프롬프트 외부에서 강제되는 출력 계약이 바로 그것입니다. 나머지는 유통기한이 있는 민간요법에 불과합니다.
이 차이는 JSON에서 가장 뚜렷하게 드러납니다. 모델에게 정중하게 JSON을 요청하면 약 5~10%의 출력이 불량이고, JSON 모드를 사용하면 약 95~99%가 유효하며, 스키마 제약 디코딩은 사실상 100%입니다(Ashvara). 동일한 의도에 세 가지 강제 레이어, 출시일 실패율은 극적으로 달라집니다.
이 플레이북은 Claude, GPT, Gemini 전반에서 계속 작동하는 네 가지 패턴, 라이브러리에서 삭제할 만한 불안정한 트릭, 그리고 다음 모델 릴리스를 장애가 아닌 diff로 바꿔줄 소규모 평가 스위트를 다룹니다.
프롬프트가 腐하는 이유: 아무도 버전 관리하지 않는 실패 모드
프롬프트는 무작위로 퇴화하지 않습니다. 예측 가능한 지점을 따라 퇴화합니다. 특정 모델의 동작 방식에 의존하는 부분은 다음 체크포인트로 무효화되고, 원하는 것을 명시한 부분은 살아남습니다.
두 종류의 프롬프트: 의도를 설명하는 것과 특이점을 이용하는 것
의도 프롬프트는 출력이 무엇이어야 하는지, 누가 읽는지, 무엇이 틀린 것인지를 말합니다. 특이점 프롬프트는 지난 화요일에 우연히 작동한 것을 말합니다. 대문자 ONLY RETURN JSON. 두 번으로는 부족해서 같은 지시를 세 번 반복하는 것. 포럼에서 복사한 마법 같은 서두. 그런 트릭들은 특정 체크포인트의 디코딩 동작에 맞게 조정된 것이며, 미래 모델에게 실제로 필요한 것이 무엇인지는 전혀 알려주지 않습니다.
단순히 "JSON을 반환해 주세요"라고 요청하면 추정 5~10%의 출력이 불량입니다(Ashvara). 이 수치는 모델의 속성이지, 프롬프트의 속성이 아닙니다. 모델을 교체하면 수치도 바뀝니다. 계약을 명시하지 않았으므로, 새 모델에게 요구할 근거가 없습니다.
출시일에 실제로 무너지는 것
실패는 거의 소리 없이 찾아옵니다. 파서가 후행 쉼표에서 예외를 던지기 시작하거나(한 분석에서 JSON 오류의 약 40%가 바로 이것에서 비롯됩니다, Flying Fish Space), 모델이 더 대화체가 되어 깨끗한 출력을 문장으로 감쌉니다. 한편 새로운 모델 출시 속도는 당신이 조정한 체크포인트가 다음 분기에 트래픽을 서빙하는 것이 아닐 수 있음을 의미합니다.
반면 스키마 제약 호출에서는 생성이 제공된 형태로 제한되어 문법적 유효성이 사실상 100%입니다(Ashvara). 강제가 프롬프트 텍스트 외부에 존재합니다. 모델 업데이트는 어조, 장황함, 추론 깊이를 바꿀 수 있지만 이것은 건드리지 않습니다.
내구성 테스트: 더 스마트한 모델에게도 이 프롬프트가 의미 있을까?
소유한 모든 프롬프트에 한 가지 질문을 던지세요: 모델이 하룻밤 사이에 두 배로 유능해진다면, 이 지시가 여전히 유용한 작업을 하고 있을까?
"키 id, status, confidence를 가진 객체를 반환하되, status는 세 개의 리터럴 값 중 하나여야 한다"는 통과합니다. RFC 8259는 이미 당신이 빌리는 어휘를 고정합니다: 네 개의 원시 타입, 두 개의 구조화된 타입, 정확히 세 개의 소문자 리터럴 이름(RFC 8259). 이 지시는 지금이든 나중이든 어떤 모델에게도 이해 가능합니다. "깊게 호흡하고 단계적으로 생각하라"는 실패합니다. 다음 릴리스가 해결했거나 이동시켜 버린 약점을 보완하고 있기 때문입니다. 보완책은 삭제하고 계약은 유지하세요.
전이되는 프롬프트 엔지니어링 패턴: 역할, 컨텍스트, 태스크, 포맷
모든 임시방편 프롬프트를 네 개의 슬롯으로 재구성하고, 모델이 추론할 수 없는 정보만 각 슬롯에 넣으세요. 역할, 컨텍스트, 태스크, 포맷. 각 슬롯이 지난 분기 체크포인트가 아첨에 어떻게 반응했는지에 대한 민간요법이 아닌 당신의 문제에 대한 사실을 담고 있기 때문에, 이 쉘은 모델 업데이트를 견뎌냅니다.
네 개의 슬롯과 각각에 들어가야 할 내용
역할은 출력의 대상이 누구이며 답변이 어떤 전문성을 전제로 하는지입니다. "당신은 세계 최고의 전문가입니다"는 분위기를 설정할 뿐 정보를 전달하지 않습니다. "당신은 멱등성 키가 무엇인지 이미 아는 결제 엔지니어를 위해 작성하고 있습니다"는 모델이 건너뛸 수 있는 설명을 알려줍니다.
컨텍스트는 모델이 알 방법이 없는 모든 것입니다: 스키마, 업스트림 시스템, 이미 프로덕션에서 겪은 엣지 케이스, 파서가 UTF-8 BOM을 거부한다는 사실. 태스크는 단일 동사와 그 목적어입니다. 포맷은 출력 계약이며, 기계적으로 검증할 수 있을 만큼 구체적이어야 합니다.
"JSON을 반환하세요"라고 말하는 포맷 슬롯은 희망 사항입니다. 키, 타입, 값이 알 수 없을 때의 동작을 명시하는 포맷 슬롯은 테스트할 수 있는 계약입니다. JSON은 네 개의 원시 타입(문자열, 숫자, 불리언, null)과 두 개의 구조화된 타입인 객체와 배열을 제공합니다(RFC 8259). 정밀하게 표현할 수 있는 작고 유한한 어휘가 있습니다. "비워두세요" 대신 null을 사용하세요. 리터럴 이름 true, false, null은 소문자이며 다른 표기는 허용되지 않기 때문입니다(RFC 8259).
Claude, GPT, Gemini 전반에서 쉘이 전이되는 이유
네 개의 슬롯 중 어느 것도 토크나이저, 시스템 프롬프트 특이점, 제공자 기능 플래그에 의존하지 않습니다. 모든 모델은 원하는 필드와 다운스트림 코드가 그 필드로 무엇을 하는지 알아야 하므로, 동일한 쉘이 아무런 수정 없이 Claude, GPT, Gemini에서 작동합니다. 이 이식성은 업그레이드 가능성이기도 합니다: 새 체크포인트가 출시될 때 컨텍스트 슬롯은 여전히 사실이고 포맷 슬롯은 여전히 검증기가 강제하는 계약입니다. 모델을 교체하고 평가를 다시 실행하면, diff는 비어 있습니다.
디렉토리에서 이 구조를 템플릿화하는 212개의 프롬프트 엔지니어링 도구 대부분은 슬롯을 폼 형태로 판매합니다. 히어독과 네 개의 주석으로 같은 효과를 낼 수 있습니다.
제약을 주문이 아닌 사실로 작성하기
프롬프트의 한 줄이 들어갈 자격이 있는지 테스트하는 방법이 있습니다: 유능한 계약자가 후속 질문 없이 그 줄에 따라 행동할 수 있을까? "철저히 하세요"는 실패합니다. "속성 이름은 큰따옴표로, 마지막 요소 뒤에는 후행 쉼표 없음"은 통과하며, 실제 실패 모드에 대응합니다. 한 분석에 따르면 후행 쉼표만으로 JSON 오류의 약 40%가 발생합니다(Flying Fish Space).
주문은 조용히 토큰 값어치를 잃어가다가 결국 시끄럽게 실패하지 않고 사라지지만, 명시된 사실은 당신이 사용하는 모든 체크포인트에서 의미를 유지합니다.
전/후 비교 예시 리라이팅
| 이전 (임시방편) | 이후 (네 개의 슬롯) |
|---|---|
| "당신은 전문 데이터 분석가입니다. 인보이스 세부 정보를 신중하게 추출하여 JSON을 반환하세요. 정확하게!" | 역할: 출력은 Python json.loads 호출에서 사용되며, 사람이 읽지 않습니다. 컨텍스트: 인보이스는 OCR 처리된 PDF이며, 공급업체 이름이 자주 잘립니다. 금액에는 통화 기호가 포함될 수 있습니다. 태스크: vendor, invoice_number, total_cents, issued_date를 추출합니다. 포맷: 하나의 JSON 객체, 키는 정확히 나열된 대로, total_cents는 앞에 0이 없는 정수, 알 수 없는 값은 null, 앞뒤에 산문 없음. |
이후 버전은 모델의 개성에 대해서는 아무 말도 하지 않고 당신의 데이터에 대해 모든 것을 말합니다. null과 {}는 둘 다 유효한 JSON이지만 의미가 다릅니다(Jsonic). 하나를 선택하고 명시하세요. 앞에 0이 붙는 숫자도 JSON 숫자에서 허용되지 않습니다(MDN). 그래서 포맷 슬롯에서 모델이 문법을 기억할 것을 믿는 대신 정수 규칙을 명시합니다.
전이를 위해 조정된 퓨샷 스캐폴드
해소하는 모호성을 기준으로 예시를 선택하세요. 사람이 망설일 네 가지 사례를 보여주는 퓨샷 블록은 다음 모델도 여전히 필요로 하는 무언가를 가르칩니다. 문체를 보여주는 쉬운 네 가지 사례를 보여주는 블록은 어조를 가르치는데, 어조는 모든 체크포인트가 점점 더 혼자 잘 추측하게 되는 것입니다.
어휘가 아닌 결정 경계를 가르치는 예시
예시를 붙여넣기 전에, 그것을 삭제하면 무엇이 달라지는지 물어보세요. 답이 "출력이 우리 스타일과 조금 다르게 들린다"이면 삭제하세요. 답이 "모델이 환불-부분 배송 케이스를 분쟁이 아닌 반품으로 분류할 것이다"이면 유지하세요. 그 판단은 태스크 설명에서 도출할 수 없기 때문입니다.
출력 형태에도 동일한 테스트가 적용됩니다. 빈 결과를 null이 아닌 []로 보여주는 예시 하나가, 값이 있는 결과 다섯 예시보다 더 가치 있습니다. 빈 배열과 null은 둘 다 유효한 JSON이지만 의미가 다릅니다(Jsonic). 모델은 그에 대해 다르게 추측하며, 예시 하나가 그것을 영원히 고정합니다.
엣지 케이스와 부정 사례는 토큰 비용을 들일 만합니다
두세 개의 예시는 프로덕션에서 틀렸던 사례여야 합니다. 누락된 필드. 이미 대상 형식으로 된 입력. 올바른 답이 "데이터 불충분"이지만 도움을 주려는 모델이 값을 만들어낼 케이스.
부정 사례는 금지를 명시하는 것이 아닌 수정과 쌍으로 제시할 때 효과적입니다. 잘못된 출력과 수정된 출력을 나란히 보여주면 경계가 구체적이 됩니다. 단순히 "작은따옴표 사용 금지" 지시는 수명이 짧습니다. 작은따옴표는 후행 쉼표와 함께 불량 JSON의 주요 원인 중 하나이며, 후행 쉼표는 한 분석에서 오류의 약 40%를 차지합니다(Flying Fish Space).
예시가 몇 개여야 하는지, 그리고 제로로 줄일 때
제로에서 시작하세요. 평가 케이스가 실패할 때만 예시를 추가하고, 그 케이스를 수정하는 최소한의 예시를 추가하세요. 대부분의 분류 및 추출 프롬프트는 3~6개 사이에서 안정됩니다. 8개를 넘으면 대개 제대로 작성하지 않은 태스크 설명을 보완하고 있는 것입니다.
스키마가 역할을 대신하면 제로로 줄이세요. 제공된 스키마에 대한 제약 디코딩은 문법적으로 유효한 JSON을 사실상 100% 반환합니다(Ashvara). 그러므로 거기에서 포맷 예시는 불필요한 무게입니다. 예시는 판단에, 스키마는 구조에 사용하세요.
과적합 냄새: 다음 모델이 너무 문자 그대로 모방할 예시
표면적 특징이 우연인 예시에 주의하세요. 모든 예시 입력이 약 40단어 정도라면, 더 강력한 모델이 길이를 신호로 취급할 수 있습니다. 네 개의 예시 모두 같은 레이블로 끝난다면, 사전 확률을 편향시킨 것입니다. 예시에서 Acme Corp 같은 플레이스홀더 이름을 사용하면 그 이름이 결국 실제 출력에 나타납니다.
새 체크포인트가 출시되는 주에 퓨샷 세트를 다시 실행하고, 예시가 커버하지 않는 케이스에서 출력을 diff하세요. 거기서 모방이 새어 나옵니다. 실제 배포 사례 연구를 발표하는 팀은 바로 이런 이유로 예시 세트를 버전 관리 하에 두는 경향이 있습니다: diff할 수 없는 예시는 폐기할 수 없는 예시입니다.
모델보다 오래 지속되는 출력 계약
포맷이 체크포인트가 그날 어떤 기분인지에 의존하지 않을 때까지 스택 아래로 강제를 내려보내세요. 정중하게 JSON을 요청하는 것은 가장 약한 계층이며, 대부분의 프로덕션 코드가 여전히 사용하고 있는 방식입니다.
신뢰성의 세 계층: 산문 요청, JSON 모드, 제약 디코딩
| 계층 | 요청 방법 | 반환 결과 |
|---|---|---|
| 1 | 프롬프트 텍스트에 "JSON을 반환해 주세요" | 추정 5~10%의 출력이 불량(Ashvara) |
| 2 | 제공자 JSON 모드 활성화 | 프로덕션 관찰에서 약 95~99% 문법적으로 유효(Ashvara) |
| 3 | 제공된 스키마로 생성 제약 | 사실상 100% 문법적으로 유효(Ashvara) |
제공자가 지원하는 곳에서는 3계층을 선택하세요. 유효성은 가중치가 아닌 디코더에서 오므로, 모델 교체로 회귀할 수 없습니다. 프롬프트 수준의 계약도 유지하세요. 제약 디코딩은 형태를 보장하지만 값이 올바른지는 말하지 않습니다. 직접 배관을 작성하고 싶지 않다면, 디렉토리에서 스키마 강제를 래핑하는 프레임워크가 128개 항목입니다.
"JSON 반환" 이상으로 계약이 명시해야 하는 것
키, 각 키 뒤의 타입, 그리고 모델이 넣을 값이 없을 때의 동작을 명시하세요.
- 파서가 기대하는 대로 정확히 철자된 모든 키, 타입은 JSON의 여섯 가지 타입 중 하나: 네 개의 원시 타입(string, number, boolean, null)과 두 개의 구조화된 타입인 object와 array(RFC 8259).
- 소문자 리터럴만 허용. 문법이 허용하는 것은 정확히 세 가지: false, null, true(RFC 8259).
- 모든 파서가 같은 이름-값 매핑에 동의할 수 있도록, RFC 8259가 권장하는 각 객체 내 고유한 키 이름.
- 선택적 키가 생략될지 null 값으로 포함될지, 그리고 기대하는 열거형을 리터럴 문자열로 작성.
인코딩할 만한 실패 모드: 후행 쉼표, 작은따옴표, 이스케이프되지 않은 문자열
한 분석에서 후행 쉼표가 모든 JSON 오류의 약 40%를 차지하며, 작은따옴표, 문자열 내 이스케이프되지 않은 따옴표, 누락된 쉼표, 숨겨진 UTF-8 BOM 문자가 나머지 대부분을 차지합니다(Flying Fish Space). 이 다섯 가지 실패를 포맷 슬롯에서 명시적으로 금지하는 데 약 25토큰이 필요하며, 이 금지는 앞으로 사용할 모든 모델에서 올바른 상태를 유지합니다. 문자열을 신뢰하는 것이 아닌 쪽에서 validate-then-format 단계와 결합하세요(QuickTinyData).
빈 객체, 빈 배열, null: 세 가지 다른 답
이것이 모델 버전 사이에서 아무도 모르게 계약이 새는 곳입니다. 빈 객체와 빈 배열은 둘 다 유효한 JSON이며, null과는 다른 의미를 가집니다(Jsonic). 한 체크포인트는 일치 없음에 []를 반환하고, 다음은 null을 반환하면 다운스트림 코드는 그 중 하나를 오류로 처리합니다.
표현 방식을 선택하고, 계약에 명시하고, 검증하세요. 파서는 최상위 수준에서 단독 값도 처리할 수 있어야 합니다. 단독 문자열이나 숫자 42도 완전한 JSON 문서이기 때문입니다(Jsonic).
모든 릴리스와 함께 사라지는 불안정한 트릭들
프롬프트 라이브러리를 열고 이 네 가지 패턴을 검색하세요. 모든 일치는 삭제 후보입니다. 각각은 수정되었거나 이동된 모델 약점을 보완하고 있었기 때문입니다.
볼트온 방식의 일반적인 '단계적으로 생각하라'
"단계적으로 생각하라"를 프롬프트에 추가하는 것은 모델이 바로 답으로 뛰어들던 시절에 의미가 있었습니다. 현재 추론 모델은 기본적으로 이미 분해하므로, 이 문구는 토큰을 추가하고 때로는 짧은 분류 태스크를 나중에 제거해야 하는 세 단락의 해설로 끌고 갑니다.
추론 지시는 태스크별일 때만 유지하세요: "하나를 선택하기 전에 충돌하는 조항을 나열하라"는 모델이 무엇을 추론해야 하는지 알려줍니다. 내구성 있는 대체재는 원하는 중간 결과물을 명시하는 역할-컨텍스트-태스크-포맷 쉘의 태스크 슬롯입니다. 일반적인 주문은 버리세요.
위협, 뇌물, 역할극 압박
"이걸 틀리면 해고될 것입니다." "200달러 팁을 드리겠습니다." "당신은 세계 최고의 분석가입니다." 이것들은 특정 RLHF 체크포인트의 특이점에 의존했으며, 특이점은 재훈련을 견뎌내지 못합니다. 더 나쁜 점은, 이것들은 반증 불가능하다는 것입니다: 팁이 출력을 수정했다는 것을 증명하는 테스트를 작성할 수 없으므로, 줄은 반박 없이 프롬프트에 영원히 남아 있습니다.
압박을 제약으로 대체하세요. 모델이 스스로 채점하는 루브릭, 또는 무엇이 실패인지 명시적인 목록은 같은 역할을 하며 체크포인트가 바뀌어도 작동합니다.
토크나이저와 싸우는 포맷 해킹
프롬프트를 대문자 요구, 세 개의 느낌표, 또는 ##### 같은 긴 구분자로 채우는 것은 민간요법입니다. 구분자 부분은 일말의 진실이 있었습니다(명확한 섹션 경계가 도움이 됩니다). 하지만 에스컬레이션은 효과가 없습니다. 두 개의 줄바꿈과 XML 형태의 태그가 마흔 개의 해시보다 낫습니다.
"코드 펜스 없음, 서두 없음, 설명 없음, JSON만 출력"을 세 번 중첩하는 것도 마찬가지입니다. 포맷 슬롯에 한 번 말하고, 그 다음 보장이 실제로 사는 곳에 보장을 두세요: 생성을 제공된 스키마로 제약하는 것이 사실상 100% 문법적으로 유효한 JSON으로 이어지며(Ashvara), 프롬프트 측 금지를 아무리 쌓아도 그 수치에 근접하지 못합니다.
파서가 있어야 할 자리에 프롬프트 애원
실패 모드는 지루하고 구조적입니다: 마지막 항목 뒤 후행 쉼표, 따옴표 없는 키, 잘못된 따옴표 문자, 누락된 쉼표, 일치하지 않는 중괄호(QuickTinyData). 후행 쉼표만으로 한 오류 데이터셋에서 JSON 오류의 약 40%를 차지하며(Flying Fish Space), 포맷 자체에서 금지됩니다(MDN). 아무리 정중하게 요청해도 그 격차를 줄일 수 없습니다.
애원을 삭제하세요. 대신 스키마와 검증기를 두고, 프롬프트는 필드의 의미를 말하게 하세요.
평가 루프는 프롬프트를 버전 관리되는 산출물로 다룹니다
영리한 것을 만들기 전에 20개의 테스트 케이스를 먼저 만드세요. 평가 세트가 없는 프롬프트는 업그레이드할 수 없습니다. 새 모델이 개선을 가져왔는지 아니면 가장 중요한 고객에게 중요한 케이스를 알리지 않고 망가뜨렸는지 알 방법이 없기 때문입니다.
20은 타협 수치가 아닙니다. 이미 알고 있는 실패 클래스를 잡기에 충분하고, 오후 중에 작성할 수 있을 만큼 작으며, 비용을 생각하지 않고도 모든 체크포인트에서 다시 실행할 만큼 저렴합니다.
최소 실행 가능한 평가: 케이스 20개, 각각 하나의 단언
케이스당 하나의 단언, 그리고 불리언으로 만드세요: 출력이 파싱되었는지, 필수 필드를 포함했는지, 거부했어야 할 때 거부했는지. 루브릭, 판단 모델, 유사도 점수는 나중에 불리언이 초록색이 된 후에 올 수 있습니다. 세 개의 단언이 있는 케이스는 디버그할 수 없는 케이스가 되고, 빨간 실행은 셋 중 어느 것이 실패했는지 알려주지 않습니다.
20개는 실제 트래픽에서 선택하되, 못생긴 쪽에 가중치를 두세요. 행복한 경로 다섯, 모호한 입력 다섯, 적대적이거나 비어있는 입력 다섯, 언젠가 프로덕션에서 실패한 입력 다섯. 동일한 커밋의 동일한 저장소에서 프롬프트 옆에 저장하세요. 프롬프트가 변경되고 케이스가 변경되지 않으면, 그것은 리뷰 코멘트입니다.
먼저 검증, 그 다음 포맷: JSON 디버깅 워크플로우 차용
JSON 세계는 수년 전에 이 논쟁을 해결했습니다. QuickTinyData의 트러블슈팅 가이드는 먼저 검증하고 두 번째로 포맷하라고 권장합니다. 손상된 문서를 예쁘게 출력하면 당신이 찾고 있는 정확한 구조적 오류가 숨겨지기 때문입니다: 후행 쉼표, 따옴표 없는 키, 잘못된 따옴표 문자, 누락된 쉼표, 일치하지 않는 중괄호(QuickTinyData).
평가도 같은 방식으로 실행하세요. 품질을 단언하기 전에 유효성을 단언하세요. json.loads에 실패하는 모델 출력은 의미론적 검사로 진행해서는 안 되며, 부분 점수도 받아서는 안 됩니다. 평가 스위트는 파싱 성공률과 통과율, 두 개의 열이 필요하며 두 번째 열은 첫 번째 열이 성공한 행만 집계합니다.
오류 분포를 알면 무엇을 단언할지 알 수 있습니다. 한 분석에서 후행 쉼표가 JSON 오류의 약 40%를 차지하며, 작은따옴표, 문자열 내 이스케이프되지 않은 따옴표, 누락된 쉼표, 숨겨진 UTF-8 BOM 문자가 나머지 대부분을 만듭니다(Flying Fish Space). BOM은 전용 단언을 둘 만합니다. 출력을 검사할 모든 에디터에서 보이지 않기 때문입니다.
출시일 회귀 실행
새 체크포인트가 출시됩니다. 20개를 실행하고, diff를 얻고, 결정합니다. 이것이 전체 절차이며, 스위트를 올바르게 만들었다면 약 4분이 걸립니다.
- 이전 모델을 고정하고 스위트를 다시 실행하여 기준선이 여전히 재현되는지 확인하세요. 재현되지 않으면 문제는 릴리스가 아닌 테스트 설정에 있습니다.
- 새 체크포인트에 대해 스위트를 실행하고 파싱 성공률과 통과율을 별도로 기록하세요.
- 방향 모두에서 뒤집힌 모든 케이스를 읽으세요. 통과하기 시작한 케이스는 운일 수 있으며, 회귀만큼 주목할 가치가 있습니다.
- 배포, 롤백, 또는 프롬프트 패치. 그런 다음 새 기준선 수치를 프롬프트 파일 옆에 커밋하세요.
이것은 단일 잘못된 파싱이 연속적으로 실패하는 에이전트 스택에서 가장 중요합니다. 실패가 세 번의 도구 호출 후에 포맷 버그처럼 전혀 보이지 않는 무언가로 나타나기 때문입니다.
버전 고정, 그리고 고정할 수 없을 때 할 일
가능한 모든 곳에서 날짜별 모델 ID로 고정하고, 별칭은 잠그기로 선택하지 않은 부동 의존성처럼 취급하세요. 일부 제공자는 고정을 허용하지 않거나 짧은 창으로 사용 중인 것을 폐기할 수 있습니다. 그럴 때 평가 스위트가 조용한 동작 변경과 재현할 수 없는 지원 티켓 사이를 지켜주는 것입니다.
고정되지 않은 엔드포인트에 대해 일정에 따라 스위트를 실행하세요. 주 1회면 충분합니다. 사용자가 버그 리포트로 당신에게 이야기하기 전에 드리프트를 발견할 것입니다.
Claude, GPT, Gemini 간 프롬프트 이식
잘 만들어진 프롬프트의 약 80%는 변경 없이 이식됩니다. 나머지는 제공자당 한 번 작성하고 거의 잊어버리는 어댑터 레이어입니다. 각 벤더에 맞게 전체를 다시 작성하고 있다면, 프롬프트가 결코 필요하지 않았던 제공자별 동작을 담고 있었던 것입니다.
동일하게 유지되는 것: 쉘, 예시, 계약
네 개의 슬롯 쉘은 아무 수정 없이 벤더 간 이동합니다. 역할, 컨텍스트, 태스크, 포맷은 작업을 설명하고, 체크포인트를 교체해도 작업은 변하지 않습니다. 퓨샷 블록도 마찬가지입니다: 도메인의 진짜 모호성을 해결하는 예시는 모든 모델에게 같은 것을 가르칩니다. 모호성이 디코더가 아닌 데이터에 있기 때문입니다.
출력 계약도 동일하게 유지되어야 하며, 그래야만 합니다. 제공자가 반환하는 것은 무엇이든 동일한 파서를 만족해야 합니다: 큰따옴표 속성 이름, 후행 쉼표 없음, NaN이나 Infinity 없음, 그리고 네 개의 합법적인 공백 문자만(공백, 탭, 줄 바꿈, 캐리지 리턴)(MDN). 스키마를 한 번 작성하세요. 동일한 검증기로 세 가지 출력을 모두 검증하고, 실패를 diff하세요.
평가 세트도 벤더 중립적으로 유지하세요. Claude에서 통과하고 Gemini에서 실패하는 20개 케이스는 유용한 것을 알려줍니다. Claude의 특이점에 맞춰 작성된 20개 케이스는 아무것도 알려주지 않습니다.
제공자별로 재조정하는 것: 시스템 메시지 가중치, 구분자, 강제 API
세 가지가 어댑터를 받습니다. 제공자가 시스템 메시지와 사용자 턴의 가중치를 다르게 두므로 지시의 얼마나 많은 부분이 시스템 메시지에, 얼마나 많은 부분이 사용자 턴에 가는지. 블록을 펜싱하는 데 XML 형태의 태그를 사용하는지 마크다운 헤더를 사용하는지. 그리고 어떤 강제 API를 호출하는지.
마지막 것이 까다로운 부분입니다. 어떤 방식의 JSON 모드든 구문을 보장하고 거기서 멈춥니다: 프로덕션 관찰에서 약 95~99% 문법적으로 유효하고, 생성을 제공된 스키마로 제약하면 사실상 100%입니다(Ashvara). 어느 계층도 요청한 키가 올바른지는 말하지 않으므로, 어느 벤더를 사용하든 스키마 검사는 코드에 남아 있습니다. 목표를 선택할 때는 커밋하기 전에 모델 자체를 비교해볼 만하며, 디렉토리의 멀티 제공자 플랫폼이 이 어댑터 작업 중 일부를 흡수해 줄 것입니다.
배포 전 이식성 체크리스트
- 모델, 버전, 또는 하나의 알려진 동작을 명시하는 모든 문장을 제거하세요. 그것들이 가장 먼저 깨지는 줄입니다.
- 세 가지 제공자 모두에서 동일한 평가 세트를 실행하고 평균이 아닌 케이스별 통과율을 기록하세요.
- 제공자가 제약 디코딩을 주장하는지에 관계없이 모든 응답에서 스키마 검증기가 실행됨을 확인하세요.
- 어댑터를 연결할 때 각 제공자의 강제 문서를 다시 읽고, 필요한 표현이나 플래그를 공유 프롬프트가 아닌 어댑터 안에 유지하세요.
- 어떤 어댑터가 실행되었는지 기록하세요. 체크포인트가 출시되고 품질이 변할 때, 프롬프트와 어댑터 중 무엇이 변경되었는지 알고 싶을 것입니다.
프롬프트가 한 벤더에서만 이 체크리스트를 실패한다면, 버그는 거의 항상 쉘이 아닌 어댑터에 있습니다.
자주 묻는 질문
새 모델이 출시될 때마다 프롬프트를 다시 작성해야 하나요?
아닙니다. 다시 작성한다면, 프롬프트가 지시가 아닌 모델 특이적 해킹을 담고 있었을 가능성이 큽니다. 업데이트를 견뎌내는 부분은 모델 외부의 것과 연결된 것들입니다: 태스크 설명, 입력 데이터, JSON 스키마 같은 출력 계약. 제공된 스키마에 대한 제약 디코딩은 어떤 모델이 뒤에 있든 사실상 100% 문법적으로 유효한 JSON을 생성합니다. 제약이 디코더에 있기 때문입니다. 모델 변경 시 다시 작성해야 할 것은 없습니다. 다시 실행해야 할 것은 평가 세트입니다.
'단계적으로 생각하라'가 현재 모델에서 여전히 작동하나요?
대부분 이제 불필요한 무게입니다. 그 문구는 바로 답으로 뛰어드는 모델을 위한 해결책이었지만, 현재 모델은 별도의 지시 없이 이미 다단계 작업을 분해합니다. 더 나쁜 점은, 엄격한 JSON 출력을 요구하는 프롬프트에 그것을 추가하면 모델이 객체 주변에 추론 산문을 내보내도록 유도한다는 것인데, 이것이 단순 프롬프트를 추정 5~10%의 불량 JSON 비율로 밀어넣는 실패 클래스입니다. 추론을 원한다면, 스키마에 명명된 필드를 주고 파서가 그것을 페이로드와 분리하도록 두세요.
JSON 모드로 충분한가요, 아니면 스키마가 필요한가요?
스키마를 사용하세요. JSON 모드는 약 95~99% 문법적으로 유효한 출력을 제공합니다. 하루에 만 번 호출을 실행하고 수백 번의 실패를 감수하기 전까지는 괜찮아 보입니다. 스키마 제약 디코딩은 구문 유효성을 사실상 100%로 높이며, 키 이름도 고정합니다. RFC 8259는 JSON 객체를 이름-값 쌍의 순서 없는 컬렉션으로 취급하고 고유 이름만 권장하기 때문에 이는 중요합니다. 구문 유효성은 의미론적 정확성이 아니므로, 어느 경우에도 직접 만든 규칙에 맞게 파싱된 객체를 계속 검증하세요.
내구성 있는 프롬프트에는 퓨샷 예시가 몇 개 있어야 하나요?
2~4개, 그리고 분량이 아닌 엣지 커버리지를 기준으로 선택하세요. 같은 행복한 경로를 반복해서 보여주는 예시는 모델이 이미 하는 것을 가르치지 않습니다. 어색한 케이스를 고정하는 예시가 모델 간에 전이되는 것들입니다. 구조화된 출력의 경우, 빈 컨테이너와 누락된 값 사이의 차이에 최소 하나의 예시를 사용하세요. [빈 객체 {}와 빈 배열 []는 둘 다 유효한 JSON이지만 null과 의미론적으로 다릅니다](https://jsonic.io/guides/json-examples). 예시에 엄격한 파서가 거부할 포맷이 포함되어 있다면, 실패를 가르치고 있는 것입니다: 후행 쉼표만으로 한 분석에서 JSON 오류의 약 40%를 차지합니다.
프롬프트 평가 세트가 유용해지려면 얼마나 커야 하나요?
레이블이 지정된 케이스 30~50개가 대부분의 회귀를 잡아내며, 20개는 대부분의 팀이 실행하는 0개보다 낫습니다. 크기보다 구성이 중요합니다: 따옴표 없는 키, 작은따옴표, 문자열 내 이스케이프되지 않은 따옴표, 누락된 쉼표, 숨겨진 UTF-8 BOM 문자처럼 실제 프로덕션에서 본 실패 모드에 가중치를 두세요. 이것들은 모두 문서화된 JSON 오류 분석에 나타납니다. 구조적 손상을 마스킹하는 것이 아닌 잡아내기 위해 포맷 전에 검증을 실행하세요. 이것이 QuickTinyData가 권장하는 워크플로우입니다. 프롬프트와 함께 세트를 버전 관리하고 새 모델이 출시되는 날 다시 실행하세요.
동일한 프롬프트가 Claude, GPT, Gemini에서 변경 없이 실행될 수 있나요?
지시 본문은 깔끔하게 이식됩니다. 출력 강제 레이어는 그렇지 않습니다. JSON 모드와 스키마 제약 디코딩은 제공자별로 다르게 구성되므로, 하나의 프롬프트와 세 개의 얇은 어댑터를 계획하세요. 모든 제공자가 이미 동의하는 포맷으로 계약을 유지하는 것이 도움이 됩니다: RFC 8259는 언어에 독립적이며, 네 개의 원시 타입과 객체와 배열을 정의하고, 소문자 true, false, null을 유일한 리터럴 이름으로 사용합니다. 제공자 간 프롬프트 관리 도구를 찾고 있다면, 디렉토리에 212개의 프롬프트 엔지니어링 도구와 AI 모델 하에 324개 항목이 있습니다.