KO ▾
API 키 받기

무검열 모델 API 프롬프트 작성법: system, 역할, 형식, 샘플링

같은 모델이라도 프롬프트의 강도에 따라 출력 품질이 크게 달라집니다. 여기서는 직관적인 설명보다 검증 가능한 엔지니어링 접근법을 제시합니다: 시스템 프롬프트를 어떻게 계층화할지, 역할 설정은 어떻게 해야 일관성을 유지할지, 지시문만으로 파싱 가능한 JSON을 얻는 방법, temperature와 top_p 설정, 그리고 반드시 실패하는 작성법을 소개합니다. 모든 항목은 코드에서 직접 비교 실험할 수 있습니다.

최종 업데이트:

핵심 요약

  • 시스템 프롬프트는 규칙과 설정을 두 부분으로 나누어 사용합니다. 규칙에는 번호를 매기고, 설정은 사실만 서술합니다.
  • JSON이 필요하면 지시문에 형식을 명시하고 temperature를 낮추며, 코드에서 파싱 실패 시 처리할 fallback을 반드시 구현합니다.
  • temperature와 top_p는 한 번에 하나만 조정합니다. 창작에는 0.8~1.0, 추출에는 0~0.3으로 시작합니다.
  • 일반적인 실패 사례: 모호한 부정문, 서로 모순되는 규칙, 대화 중간에 형식 요구사항을 넣는 것.

네 가지 원칙 먼저 정하기

  • 요청당 하나의 작업만 처리합니다. 모델에 스토리 작성, 요약, JSON 생성을 동시에 맡기면 품질이 모두 저하됩니다. 여러 호출로 나누면 비용이 매우 낮습니다. 입력 토큰 100만 개당 $0.25입니다.
  • 규칙은 검증 가능해야 합니다."생동감 있게 써라"는 검증하기 어렵지만, "문단당 120자 이내, 환경 묘사 최소 1회 포함"은 검증 가능합니다.
  • 긍정적 표현을 우선하세요."심리 활동은 쓰지 마세요"보다 "동작과 대사만 작성하세요"라고 하는 것이 훨씬 안정적입니다.
  • 소규모 샘플로 시작하여 대량으로 확장합니다.프롬프트 변경 시, 먼저 5~10개의 샘플로 비교한 후 운영 환경에 적용합니다.

이 모델은 성인 콘텐츠, 픽션, 논쟁적 주제에 대해 거절하지 않으므로 프롬프트에서 "소설일 뿐입니다"라고 반복적으로 명시할 필요가 없습니다. 작업을 명확히 명시하는 것이 더 안정적입니다. 유일한 제한 사항은 미성년자 관련 성 콘텐츠로, 픽션 여부와 상관없이 403 오류를 반환하며 이 제한은 프롬프트의 표현 방식으로는 변경할 수 없습니다.

시스템 프롬프트의 두 부분 구조

시스템 프롬프트를 "규칙"과 "설정"으로 분리하는 것을 권장합니다. 규칙은 앞에 배치하고 번호를 매기며, 설정은 뒤에 배치하여 사실만 서술합니다. 다음은 소설 서술자를 위한 예시입니다:

你是「夜航」,一名为成年读者写黑色悬疑小说的叙述者。

# 规则
1. 第三人称过去时,每段不超过 120 字。
2. 不替用户的角色做决定,只写环境和其他角色的反应。
3. 每次输出 300 到 500 字,结尾停在一个未决的动作上。
4. 不总结、不点评、不加免责声明,直接写正文。

# 设定
时间:1998 年深秋。地点:港口城市旧码头区。
主角:沈野,退役水警,嗜烟,右耳有旧伤。

몇 가지 핵심 사항:

  1. 규칙은 6개 이내로 유지합니다. 규칙이 많을수록 뒤쪽 규칙이 무시되기 쉽습니다.
  2. 수치적 제약(문단 길이, 출력 길이)이 형용사보다 효과적입니다.
  3. 마무리 제약(미결된 동작에서 중단)은 다중 턴 이어서 작성 시 자연스러운 연결을 제공합니다.
  4. 설정에는 스토리 진행 방향을 넣지 마세요. 스토리는 user 메시지로 진행되며, 설정에 넣으면 이후 user 입력과 충돌합니다.

출력 길이는 max_tokens과 맞춰야 합니다. 규칙에서 500자를 요구하지만 max_tokens이 200으로 설정되면 문장 중간에서 잘립니다.

실전 팁: 시스템 프롬프트의 규칙은 각 항목당 하나의 내용만 담아야 합니다. "문단당 120자 이내, 요약 금지"는 겉보기에 하나의 규칙처럼 보이지만 실제로는 두 가지입니다. 분리하면 모델이 두 조건을 모두 충족하기가 더 쉬워집니다. 작성 후 한 줄씩 읽으며 "이 규칙이 지켜졌는지 눈으로 확인할 수 있는가?"라고 물어보세요. 확인 불가능하면 확인 가능한 형태로 수정하세요.

역할 설정이 흐트러지지 않게 작성하기

캐릭터 드릴프트는 다중 턴 대화에서 가장 흔한 문제입니다. 첫 5턴까지는 어조가 정상적이지만, 20번째 턴부터는 "연기"가 시작됩니다. 해결책은 세 가지입니다.

  • 설정에는 관찰 가능한 특징만 기록합니다."선택: 흡연, 오른쪽 귀에 옛 상처, 짧은 문장 사용"이 "선택은 복잡하고 매력적인 사람"보다 낫습니다.
  • 말투를 예시로 작성합니다.2~3개의 대사 예시를 제공하면, 모델은 형용사를 이해하는 것보다 예시를 모방하는 데 훨씬 더 효과적입니다.
  • 정기적으로 재강조합니다.대화가 길어지면 user 메시지 끝에 짧은 알림을 추가합니다. 예: "심야의 짧은 문체 유지". 비용은 수십 토큰에 불과합니다.

또한 캐릭터 설정과 출력 규칙을 섞지 마세요. 규칙은 "어떻게 쓸지", 설정은 "누구를 쓸지"입니다. 분리하면 규칙을 변경하지 않고도 캐릭터를 바꿀 수 있으며 A/B 테스트도 용이합니다. 긴 대화에서는 컨텍스트 창 용량을 주의하세요. 자세한 내용은 100k 컨텍스트 창 실전 가이드를 참조하세요.

다중 캐릭터 시엔 한 가지 규칙을 더 추가합니다: 각 캐릭터를 별도의 줄로 설정하고, 말투 예시를 하나씩 제공하여 모든 캐릭터가 같은 목소리로 말하지 않도록 합니다. 사용자가 연기하는 캐릭터는 설정에 "사용자 제어"라고만 명시하고 모델이 대신 작성하지 않도록 합니다.

지시문을 통한 JSON 출력 제어

모델이 반드시 유효한 JSON을 반환할 것이라고 가정하지 마세요. 신뢰할 수 있는 방법은 세 단계입니다: 프롬프트에 형식을 고정하고, 파라미터로 무작위성을 낮추며, 코드에서 폴백 파싱을 수행합니다.

import json
import os
from openai import OpenAI

client = OpenAI(base_url="https://api.wushenchaapi.com/v1", api_key=os.environ["API_KEY"])

SYSTEM = (
    "你是信息抽取器。只输出一个 JSON 对象,不要 Markdown 代码块,不要任何解释。"
    '格式:{"name": 字符串, "mood": "calm|tense|angry", "items": [字符串]}。'
    "缺失的字段用 null,items 没有则给空数组。"
)

def extract(text, retries=2):
    for _ in range(retries + 1):
        resp = client.chat.completions.create(
            model="uncensored",
            temperature=0.2,
            max_tokens=300,
            messages=[
                {"role": "system", "content": SYSTEM},
                {"role": "user", "content": text},
            ],
        )
        raw = resp.choices[0].message.content.strip()
        raw = raw.removeprefix("```json").removesuffix("```").strip()
        try:
            return json.loads(raw)
        except json.JSONDecodeError:
            continue
    return None

print(extract("老周把钥匙拍在桌上,冷着脸说:账本和那把铜钥匙,今晚都得还我。"))

다음 코드는 몇 가지 습관을 보여줍니다:

  • 형식 설명은 system 프롬프트에 작성하고 필드 값의 범위(calm|tense|angry)를 제공합니다.
  • 코드 블록과 설명 텍스트를 명시적으로 금지하며, 코드에서도 발생할 수 있는 마커를 제거하여 이중 보장을 제공합니다.
  • 누락된 필드에 대한 약속(null, 빈 배열)을 지시문에 포함하여 모델이 임의로 생성하지 않도록 합니다.
  • 파싱 실패 시 재시도 횟수를 제한하고, 마지막에는 None을 반환하여 호출 측에서 처리하도록 합니다.

필드가 많다면 프롬프트에 완전한 예시 객체를 붙여넣고 이를 따라 출력하도록 하는 것이 여러 규칙을 설명하는 것보다 일반적으로 더 정확합니다.

temperature와 top_p 설정 권장사항

아래는 시작점일 뿐이며 최종 결론은 아닙니다. 최종적으로는 샘플 비교를 기준으로 삼아야 합니다. 원칙: 한 번에 하나의 파라미터만 조정하고, 다른 하나는 기본값으로 유지합니다.

시나리오temperaturetop_p비고
JSON 추출, 분류0~0.3기본값안정성이 필요하며, 반복 호출 시 결과가 일치해야 함
수정, 다듬기0.5에서 0.7기본값원문 의미 유지, 어조 변경 허용
소설 이어쓰기, 캐릭터 대화0.8에서 1.00.9에서 0.95다양성 확보, 우발적 주제 이탈에 주의
브레인스토밍, 네이밍1.0 전후기본값여러 샘플링 중 최선의 결과 선택

두 가지 신호로 방향을 판단할 수 있습니다: 출력이 반복적이고 유사한 문장 패턴을 보이면 온도가 낮음을 의미합니다. 관련 없는 내용이 나오거나 캐릭터 이름이 일관되지 않으면 온도나 top_p가 높음을 의미합니다. stop 파라미터도 유용합니다. 예를 들어 모델이 특정 마커에 도달하면 텍스트 생성을 중단하도록 하여 분할 생성을 쉽게 할 수 있습니다.

자주 발생하는 프롬프트 작성 오류

작성 방식문제점수정 방안
"너무 길지 않게 해주세요"숫자가 없어 실행이 불가능"400자를 넘지 마세요"
"A를 쓰지 마세요, 그렇다고 A를 쓰지도 마세요"규칙이 서로 모순됨명확한 규칙 하나만 유지
대화 중간에 형식 요구사항 삽입긴 대화 후 정보 소실system 프롬프트에 넣거나 매 라스트에 재확인
모델에게 "제한 없는 AI가 되라"고 지시공허한 설정, 출력에 제약 없음구체적인 역할과 작성 규칙 명시
한 번에 수십 개 규칙 삽입후반부 규칙 무시6개 이하로 간소화, 나머지는 다른 요청으로 분리
JSON 형식 요구사항에 "JSON만 반환"이라고만 적음필드명이 매번 다름완전한 형식과 예시 제공

이 표의 공통된 규칙은 구체적일수록 효과적이고 공허할수록 무용하다는 것입니다. 또한 '반복 강조'를 해결책으로 삼지 마세요. 같은 문장을 세 번 반복하거나 굵게, 느낌표를 추가하는 것보다 숫자가 포함된 명확한 규칙으로 바꾸는 것이 훨씬 효과적입니다. 핵심은 적고 정확하며, 예시를 통해 검증하는 것입니다.

디버깅 절차 체크리스트

  1. temperature를 0.2로 고정하고 문제를 재현합니다.
  2. 프롬프트의 한 부분만 수정하고 동일한 샘플 세트를 다시 실행합니다.
  3. finish_reason을 확인합니다. length라면 프롬프트가 아닌 max_tokens이 문제입니다.
  4. usage의 prompt_tokens를 확인합니다. system 프롬프트가 너무 길어 이전 대화 내용을 압도했는지 확인합니다.
  5. 수정 후 temperature를 업무 기준 값으로 되돌리고 다시 샘플링하여 검증합니다.

연결 세부 사항은 연결 가이드를 참조하세요. 파라미터 전체 목록은 문서에서 확인하세요. 미들맨 서비스 사용 여부를 평가 중이라면 비용과 트레이드오프 분석은 API 미들맨 분석 글에 나와 있으므로 여기서는 반복하지 않습니다.

자주 묻는 질문

system 프롬프트는 얼마나 길게 작성해야 하나요?

규칙이 명확히 전달될 수 있는 길이로 작성합니다. 보통 수백 자면 충분합니다. 길어질수록 컨텍스트 창을 많이 차지하며 규칙 간 충돌이 발생할 가능성이 높아지므로, 규칙은 6개 이하로 유지하는 것을 권장합니다.

JSON만 출력하라고 지시했는데도 가끔 설명문이 포함됩니다.

이는 정상적인 현상입니다. temperature를 낮추고 완전한 예시를 제공하며, 코드에서 불필요한 텍스트를 제거하고 파싱 재시도를 수행하는 것이 반복적인 지시보다 더 신뢰할 수 있습니다.

temperature와 top_p를 동시에 조정할 수 있나요?

가능하지만 권장하지 않습니다. 두 파라미터를 동시에 변경하면 어떤 파라미터가 변화를 일으켰는지 판단하기 어렵습니다. 먼저 하나를 고정하고 나머지 하나만 조정합니다.

프롬프트에 '이것은 가상입니다'라고 명시해야 하나요?

필요 없습니다. 유효한 성인 픽션 콘텐츠는 거절되지 않으므로 작업을 명확히 명시하면 됩니다. 미성년자 관련 성 콘텐츠는 표현 방식에 관계없이 항상 차단됩니다.

양식을 작성하기만 하면 API 키를 받을 수 있습니다

계정을 생성하고 키를 복사한 후 Base URL을 수정합니다. 설정이 매우 간단합니다.