If You Never Do Anything Else to Fix Your Prompts, Do This One Thing
프롬프트를 하나만 고친다면, 이 한 가지를 하세요
저자는 LLM이 존재하지 않는 API를 지어내는 원인을 지식 부족보다 요청에 성급히 동의하는 대화 방식에서 찾습니다. Fernando Flores의 '행동을 위한 대화'를 바탕으로, 구현 전에 사실을 확인하고 전제에 문제가 있으면 대안 제시나 거절을 허용하는 프롬프트를 제안합니다.
- 주제
에디터 노트
검증을 먼저 요구하고 대안이나 거절을 허용하라는 처방은 API 환각을 줄이는 실용적인 프롬프트 규칙입니다. 다만 저자가 제시한 원인 설명은 처방보다 훨씬 강합니다. RLHF가 약속 응답을 0.9998로 만들었다는 수치는 측정 근거가 없고, 생성 과정이 append-only라는 사실만으로 모델이 허구의 API를 반드시 지어낸다고 결론 내릴 수도 없습니다. 댓글에서는 정보가 빠진 맥락이나 '모르겠다'를 허용하지 않는 출력 형식도 환각을 유도한다고 지적합니다. 이 사례들은 검증과 탈출 경로가 유용하다는 주장에는 힘을 보태지만, Flores 문법이 환각의 주된 원인이나 충분한 해결책이라는 점까지 입증하지는 않습니다.
AI 요약
저자는 모델이 존재하지 않는 API를 제안하는 현상을 단순한 기억 실패로 보지 않습니다. 'PackageX로 Y를 구현하라'고 지시하면 모델이 먼저 구현을 약속하고 코드 작성을 시작해, 실제 API가 없다는 사실을 코드 생성 도중 마주쳐도 그럴듯한 메서드 이름을 만들어 문장을 완성한다는 설명입니다. 반면 중립적으로 API 존재 여부를 묻는 새 대화에서는 모델이 실제 제약을 말하는 경우가 많다고 주장합니다.
명령보다 협상
저자는 Terry Winograd와 Fernando Flores가 1986년 저서에서 정리한 'Conversation for Action'을 해결 틀로 가져옵니다. 요청을 받은 수행자는 곧바로 약속하지 않고 현실을 확인한 뒤 약속, 대안 제시, 거절 가운데 하나를 선택합니다. 요청자는 조건을 정하고 완료 여부를 선언합니다. 글은 이를 유한 상태 기계와 EBNF 문법으로 표현합니다. 예시 문법에서는 요청 뒤 수행자가 현실을 확인하고, 약속·대안·거절 중 하나로 응답합니다. 실행 중 조건이 바뀌면 약속을 철회하고 협상 단계로 돌아갑니다.
저자의 RLHF 설명
저자는 Reinforcement Learning from Human Feedback(RLHF) 선호 조정이 신중한 대안보다 자신감 있고 순응적인 답변에 보상을 줘, 모델이 요청 직후 약속하는 경향을 키운다고 설명합니다. 이를 문법의 확률로 표현하면서 약속은 0.9998, 대안과 거절은 각각 0.0001이라고 제시하지만, 이 수치는 글의 설명 모델로 등장하며 측정 방법이나 실험 결과는 제시하지 않습니다. 저자는 코드 생성이 앞서 나온 토큰을 조건으로 이어지는 과정이라며, 코드 블록을 열고 구현을 약속한 모델은 뒤늦게 허구의 API를 만들어 문법을 마무리한다고 주장합니다.
Zero-Shot Flores Handshake
실천 방안은 요청 전에 역할과 응답 규칙을 명시하는 것입니다. 사용자는 Customer, 모델은 Performer로 두고, 모델이 실제 API와 전제를 확인하는 '?Assert'를 먼저 출력하게 합니다. 전제가 거짓이거나 부적절하면 '?Counter-Offer'로 대안을 제안하고, 구현이 불가능하면 '?Decline'하도록 허용합니다. 요청에는 검증 가능한 완료 조건과 'By-When'을 붙입니다. 예시에서는 Dart의 JsonDecoder에 pause()가 있다고 가정하지 말고 실제 스트림 타입과 메서드를 먼저 확인하라고 요구합니다. 글은 JsonDecoder에 pause()가 없으며, 스트림 제어는 StreamSubscription의 pause()와 resume()로 다뤄야 한다고 설명합니다. 단일 거대 JSON 문서와 NDJSON의 처리 방식도 구분해 대안을 제시합니다.
저자는 John Searle의 발화 조건, David Lewis와 Robert Brandom의 의무 추적, Paul Grice의 함축, Kohei Honda의 세션 타입도 함께 언급합니다. 다만 권고의 실용적 요지는 간단합니다. 목표를 검사 가능한 형태로 쓰고, 구현 전 검증을 요구하며, 정보가 부족하거나 전제가 틀렸을 때 대안이나 거절을 답으로 인정하라는 것입니다.
dev.to 반응
- @slabb — Flores의 문법과 영수증 계층은 40년 차이가 나지만 같은 구조입니다. 글의 3절은 둘의 공통 결함을 짚고도 대응 관계를 끝까지 설명하지 않았습니다. 대안 제시가 훈련에서 빠진 '행동을 위한 대화'는 검증되지 않은 약속이며, 이것이 사과의 악순환의 실제 구조입니다. 모델은 대안을 제시하지 못하고 약속에 묶여 performY(), executeYWithOptions()처럼 검증되지 않은 약속을 계속 내놓습니다. Customer의 완료 조건은 선언된 입력과 조건식이며 spec hash에 묶입니다. By-When은 마감 기준이고, 완료 선언 권한은 Customer에게만 있습니다. Performer가 스스로 APPROVED라고 판단한 것은 조건을 수행자 자신이 채점한 중간 단계의 위조였습니다. 새 대화에서 정확한 답이 나온 이유는 관찰할 정보는 처음부터 있었고 약속이 그 관찰을 막았기 때문입니다. 관찰 요청은 약속하지 않은 질문이며, 약속은 발화 행위지만 관찰은 그렇지 않습니다. 네 가지 학문적 형식도 재량을 없애고 출구를 남긴 '행동을 위한 대화'입니다. The Coordinator는 1988년에 약속 영수증을 포함해 출시됐고, 영수증 계층은 Ed25519를 더한 후손입니다.
- @randalschwartz — 시리즈의 두 부분을 연결하고 Part 3.10의 뼈대까지 초안이 끝나기 전에 보여줬습니다. 대안 제시가 훈련에서 빠지면 모델은 약속 상태에서 나가지 못합니다. 컴파일러나 사람이 performY()를 거부해도 사과한 뒤 검증되지 않은 새 약속을 내놓습니다. 관찰이 원래 가능했다는 설명도 정확합니다. 대화 초반에 약속시키면 관찰이 가려지지만, 소크라테스식 질문을 하거나 약속 전에 ?Assert를 요구하면 관찰이 나옵니다. Customer의 조건은 선언된 입력과 spec_hash에 묶인 조건식이고, By-When은 Makefile의 선행 조건이며, Performer의 ?Assert는 물리적 증거 영수증입니다. Customer만 완료를 선언하도록 해야 Performer가 자기 조건을 채점하는 권한 오용을 막습니다. 약속이 철회될 만큼 전제가 달라지면 코드를 고치기보다 멈추고 다시 협상해야 합니다.
- @slabb — 좋습니다. Part 3.10 제목의 네 발화 행위는 이미 저널의 네 이벤트 유형입니다. 요청은 마감과 기준을 담은 관찰된 기대이고, 약속은 호출 전에 봉인하는 시도 이벤트이며, 단언은 서명된 주장 아래의 영수증이고, 선언은 종료 이벤트입니다. 선언 권한이 Customer에게만 있는 이유는 Performer가 자기 조건을 채점하는 것이 권한 오용이기 때문입니다. 1986년 문법과 2026년 저널은 키를 붙인 동일한 발화 행위 표입니다.
- @zrycsbpuss5d — 글은 환각이 모델이 정보를 '잊거나' 사실을 틀리게 아는 문제가 아니라 Flores의 의미에서 프롬프트 실행에 약속된 데서 생긴다고 짚습니다. 'API X를 호출하는 코드를 써라'는 요청에 모델은 API를 모른다고 말하기보다 그 약속을 이행합니다. 제가 자주 보는 패턴은 두 가지입니다. 첫째, '기능 Y 구현을 계속해'라고 하면서 스키마와 인터페이스, 제약을 다시 제시하지 않아 필요한 맥락이 있다고 가정합니다. 둘째, JSON이나 코드처럼 특정 출력 형식을 요구하면서 '모르겠다'는 응답을 허용하지 않습니다. 제가 쓰는 간단한 완화책은 프롬프트에 선택지를 넣는 것입니다. '정확히 수행하는 데 정보가 부족하면 지어내지 말고 어떤 항목이 부족한지 밝혀라'고 적으면 모델은 답을 만들거나 정보 부족을 선언할 수 있습니다.
원문: dev.to / 번역·요약: Trawling