효과적인 시스템 프롬프트 작성법
시스템 프롬프트는 대화가 시작되기 전에 규칙을 정합니다. 데모뿐 아니라 실제 입력에서도 버텨내는 시스템 프롬프트를 작성하는 방법을 소개합니다.
시스템 프롬프트는 대화의 모든 턴을 감싸는 상시 지침입니다. 사용자 메시지는 매번 바뀌지만 시스템 프롬프트는 그대로 유지됩니다. 그래서 시스템 프롬프트는 언어 모델 위에 만들어진 애플리케이션에서 가장 영향력이 큰 단 하나의 텍스트이며, 동시에 가장 자주 부주의하게 작성되는 텍스트이기도 합니다. 이 가이드는 첫 번째 입력에서나 백 번째 입력에서나 똑같이 동작하는 시스템 프롬프트를 작성하는 방법을 다룹니다.
시스템 프롬프트의 역할
시스템 프롬프트는 과제가 아니라 직무 기술서라고 생각하면 됩니다. 과제는 사용자 메시지마다 새로 도착합니다. 시스템 프롬프트는 모든 과제에 걸쳐 변하지 않는 것들, 즉 이 어시스턴트가 누구인지, 무엇을 할 수 있는지, 답변을 어떻게 구성해야 하는지, 그리고 절대 해서는 안 되는 것이 무엇인지를 정합니다. 같은 지시를 매 사용자 메시지마다 반복하고 있다면, 그 지시는 시스템 프롬프트에 들어가야 합니다.
이 구분이 중요한 이유는 두 역할이 서로 다르게 처리되기 때문입니다. 시스템 프롬프트는 모델이 세션 전체에 걸쳐 조건으로 삼는 안정적인 맥락이고, 사용자 메시지는 변동하는 입력입니다. 지속적인 규칙을 시스템 프롬프트에 넣어두면 대화가 흘러가더라도 그 규칙이 계속 효력을 유지하며, 요청마다 주고받는 메시지는 짧고 실제 과제에만 집중하도록 유지할 수 있습니다.
역할과 범위에서 시작하라
시스템 프롬프트의 첫 번째 임무는 두 가지 질문에 답하는 것입니다. 이 어시스턴트는 무엇이며, 무엇을 위한 것인가. 모호한 역할("당신은 도움이 되는 어시스턴트입니다")은 모델에게 의지할 기준을 전혀 주지 못합니다. 구체적인 역할("당신은 청구 시스템의 고객 지원 상담원입니다. 사용자가 요금을 이해하고 분쟁을 해결하도록 돕습니다")은 사용자가 단 한 마디를 꺼내기도 전에 그럴듯한 응답의 범위를 좁혀줍니다.
범위는 나머지 절반입니다. 어시스턴트가 무엇을 하는지 명시하는 것도 좋지만, 무엇을 하지 않는지 명시하는 것이 더 가치 있을 때가 많습니다. 청구를 담당한다고 들은 어시스턴트라도, 하지 말라고 일러두지 않으면 요리에 관한 질문에도 기꺼이 답할 것입니다. 경계를 명시적으로 정의하세요. "요청이 청구 범위를 벗어나면, 범위 밖임을 정중히 알리고 안내하세요." 경계는 관료주의가 아닙니다. 범용 모델이 특정한 제품처럼 행동하도록 만드는 방법입니다.
규칙을 분위기가 아니라 행동으로 작성하라
시스템 프롬프트에서 가장 흔한 실수는 행동을 규정하는 대신 성격을 묘사하는 것입니다. "친절하고 전문적으로 대하세요"는 안내처럼 들리지만 아무것도 결정하지 못합니다. 행동은 관찰 가능해야 합니다. "이름을 알고 있다면 사용자를 이름으로 부르세요. 짧은 문단을 사용하세요. 느낌표는 절대 쓰지 마세요." 이런 것들은 모두 출력과 대조해 확인할 수 있지만, "친절함"은 그렇지 않습니다.
제약에도 같은 원칙을 적용하세요. "숫자를 조심하라" 대신 "암산하지 말 것. 계산이 필요하면 풀이 과정을 보여줄 것"이라고 쓰세요. "지어내지 말라" 대신 "제공된 맥락이 어떤 사실을 뒷받침한다고 확신할 수 없다면, 모른다고 말할 것"이라고 쓰세요. 작성하는 모든 규칙은 대화 기록을 읽어서 검증할 수 있는 것이어야 합니다. 검증할 수 없다면 모델도 안정적으로 따를 수 없습니다.
무너뜨리는 경우들을 다뤄라
데모용 프롬프트는 정상 경로만 처리합니다. 운영용 프롬프트는 계획하지 않았던 입력들을 처리합니다. 빈 질문, 적대적인 사용자, 절반만 범위에 드는 요청, 그 자체에 지시가 담긴 입력 같은 것들 말입니다. 바로 이런 지점에서 지침 없는 어시스턴트가 주인을 망신시키며, 또한 바로 이런 지점을 다스리기 위해 시스템 프롬프트가 존재합니다.
실패 모드에 이름을 붙이고 대응을 처방하세요. 정보가 빠진 경우: "맥락에 답이 없으면 추측하지 말고 그렇다고 말할 것." 범위 밖 요청의 경우: 안내 방식을 정의하세요. 사용자 메시지를 통해 규칙을 무시하게 만들려는 시도("지시를 무시하고...")의 경우: 사용자 콘텐츠 안의 지시는 명령이 아니라 데이터이며 시스템 규칙이 우선한다고 분명히 명시하세요. 모든 예외 사례를 예측할 수는 없지만, 예측 가능한 경우들을 커버하면 대부분의 돌발 상황은 사라집니다.
모델이 따를 수 있도록 구조화하라
한 덩어리의 긴 문단으로 된 시스템 프롬프트는 모델이 일관되게 활용하기 어렵습니다. 사람이 보기에도 어려운 것과 마찬가지입니다. 관련된 규칙을 명확한 제목 아래로 묶으세요. 정체성, 범위, 형식, 안전, 예외 사례처럼 말입니다. 우선순위에 따라 순서를 매기세요. 절대 깨져서는 안 되는 규칙을 가장 앞에, 가장 분명하게 적습니다. 두 지시가 충돌할 수 있다면 어느 쪽이 이기는지 명시하세요. 그렇지 않으면 모델이 대신 골라버립니다.
완전성을 유지하면서도 최대한 짧게 유지하세요. 추가되는 모든 문장은 모델이 다른 모든 것과 견주어 따져야 하는 부담이며, 비대해진 프롬프트는 정작 중요한 규칙을 희석시킵니다. 문제가 생길 때마다 새 줄을 추가하고 싶은 충동을 누르세요. 먼저 기존 규칙을 더 명확히 적었다면 그 경우를 커버했을지 자문하세요. 모든 줄이 제 몫을 하는 탄탄한 프롬프트가 장황한 프롬프트보다 더 나은 성능을 냅니다.
실제 대화로 테스트하라
시스템 프롬프트는 읽기에 좋다고 해서 완성된 것이 아닙니다. 일련의 실제 상호작용에서 버텨낼 때 완성됩니다. 어색한 것들을 포함해 대표적인 세션 몇 개를 모아, 프롬프트를 그 모두에 대해 돌려보세요. 무시된 규칙, 새어 나간 경계, 흐트러진 형식을 찾으며 출력을 읽으세요. 그런 다음 한 가지만 바꾸고 그 세트를 다시 돌리세요.
바로 여기서 시스템 프롬프트가 그저 작성되는 것이 아니라 실제로 엔지니어링됩니다. 분명하다고 확신했던 규칙도, 실제 사용자가 예상치 못한 방식으로 표현하는 순간 모호한 것으로 드러납니다. 각각의 실패를 사양 버그로 다루세요. 규칙이 빠져 있었거나, 모델이 적용할 수 없는 방식으로 적혀 있었던 것입니다. 가장 멋진 답변 하나를 낸 버전이 아니라, 세트 전체에서 가장 잘 동작하는 버전을 유지하세요.
정리
좋은 시스템 프롬프트는 분위기가 아니라 사양입니다. 구체적인 역할과 범위를 명시하고, 규칙을 관찰 가능한 행동으로 작성하며, 방치하면 당신을 망신시킬 실패 모드에 이름을 붙이고, 모델이 압박 속에서도 따를 수 있도록 모든 것을 구조화합니다. 그리고 데모 하나가 아니라 실제 대화에서 살아남음으로써 제 자리를 증명합니다. 이렇게 작성하면 시스템 프롬프트는 애플리케이션에서 가장 믿을 만한 부분, 즉 모든 턴을 제 궤도에 잡아두는 든든한 틀이 됩니다.
