클라우드 Mac에서 MLX 토크나이저와 채팅 템플릿 검증하기

클라우드 Mac에서 MLX 토크나이저와 채팅 템플릿 검증하기

클라우드 Mac에서 MLX 토크나이저와 채팅 템플릿 검증하기

동일한 대화를 클라우드 Mac으로 옮긴 뒤 MLX의 답변에 갑자기 역할 태그가 나타난다고 해서 반드시 가중치에 문제가 생긴 것은 아닙니다. 토크나이저 버전이나 채팅 템플릿, 중복으로 추가된 특수 토큰 때문에 실제 입력이 달라질 수 있습니다. 먼저 메시지를 토큰으로 변환하는 과정을 고정한 다음 생성 결과를 비교해야 입력 변화와 샘플링의 무작위성을 구분할 수 있습니다.

먼저 검증할 입력 계약 정의하기

이 실습에서는 추론 전처리만 검사합니다. 가중치를 로드하거나 tokens/s를 측정하지 않습니다. Python 가상 환경과 검증된 로컬 모델 디렉터리를 준비하세요. 해당 디렉터리에는 모델에 필요한 토크나이저 설정, 어휘 사전, 채팅 템플릿이 있어야 합니다. 규모가 같은 다른 모델에서 이 파일들을 복사해 오면 안 됩니다.

검증 기록에는 원본 메시지 배열, 템플릿으로 렌더링한 텍스트, 전체 토큰 ID 시퀀스의 세 가지를 남깁니다. 토큰 개수만 비교해서는 부족합니다. 길이가 같은 두 시퀀스도 서로 다른 내용을 표현할 수 있습니다. 일반 어휘가 같다고 해서 역할 경계와 종료 토큰까지 같다는 보장도 없습니다.

채팅 템플릿은 표시 형식이 아니라 모델의 입력 프로토콜입니다. 토큰화에 성공했다는 것은 변환이 끝났다는 뜻일 뿐, 모델에 올바른 역할 구조가 전달되었다는 뜻은 아닙니다.

다음 스크립트를 check_prompt.py로 저장하고, transformers와 해당 토크나이저에 필요한 의존성이 설치된 환경에서 실행하세요. 먼저 python -m pip freeze > requirements.lock.txt를 실행해 환경을 기록합니다. 이 목록은 버전 기록용이며, 플랫폼이 달라져도 설치 결과가 완전히 같다고 보장하지는 않습니다.

로컬 파일과 메시지 샘플 고정하기

스크립트는 네트워크 다운로드와 사용자 정의 원격 코드 실행을 명시적으로 비활성화합니다. 모델이 사용자 정의 구현에 의존한다면 먼저 구현을 검토하고 별도의 실행 방안을 마련하세요. 오류를 피하려고 임시로 실행 권한을 허용해서는 안 됩니다.

샘플에는 중국어, 줄바꿈, 꺾쇠괄호, 여러 턴의 대화가 포함되어 있으며, 생성 접두사를 추가하는 경우와 추가하지 않는 경우를 각각 검사합니다. 일반적인 user와 assistant의 교대 구조를 사용합니다. system 역할과 도구 호출은 모델이 명시적으로 지원하는지 확인한 뒤 별도 샘플로 추가해야 합니다.

import argparse
import json
from pathlib import Path
from transformers import AutoTokenizer

parser = argparse.ArgumentParser()
parser.add_argument("model_dir")
parser.add_argument("baseline")
parser.add_argument("--record", action="store_true")
args = parser.parse_args()

tokenizer = AutoTokenizer.from_pretrained(
    args.model_dir,
    local_files_only=True,
    trust_remote_code=False,
)
cases = [
    [{"role": "user", "content": "只回答数字:2+3\n<note>保留原文</note>"}],
    [
        {"role": "user", "content": "记住代号:实验甲"},
        {"role": "assistant", "content": "已记录。"},
        {"role": "user", "content": "代号是什么?"},
    ],
]
rows = []
for messages in cases:
    for generation in (False, True):
        rendered = tokenizer.apply_chat_template(
            messages,
            tokenize=False,
            add_generation_prompt=generation,
        )
        ids = tokenizer.apply_chat_template(
            messages,
            tokenize=True,
            add_generation_prompt=generation,
        )
        encoded = tokenizer.encode(
            rendered, add_special_tokens=False
        )
        if ids != encoded:
            raise SystemExit("Tokenization paths differ")
        rows.append({
            "messages": messages,
            "generation": generation,
            "rendered": rendered,
            "ids": ids,
        })

path = Path(args.baseline)
if args.record:
    with path.open("x", encoding="utf-8") as stream:
        json.dump(rows, stream, ensure_ascii=False, indent=2)
else:
    expected = json.loads(path.read_text(encoding="utf-8"))
    if rows != expected:
        raise SystemExit("Prompt contract changed")

기준 데이터는 만들되 자동으로 승인하지 않기

처음에는 python check_prompt.py ./model ./prompt-baseline.json --record를 실행합니다. 기록 시에는 배타적 생성 모드를 사용하므로 파일이 이미 있으면 오류가 발생합니다. 문제를 조사하는 과정에서 기존 증거를 덮어쓰지 않도록 하기 위한 장치입니다. 이후에는 --record를 빼고 실행하며, 아무 출력 없이 종료 코드가 0일 때만 검사를 통과한 것입니다.

JSON을 항목별로 검토하세요. 사용자 내용이 온전히 남아 있는지, 역할 구분이 모델 설명에 맞는지, assistant의 이전 답변 뒤에 적절한 경계가 있는지, 생성 모드에서 다음 답변을 시작할 위치가 준비되어 있는지 확인합니다. 일부 템플릿은 생성 접두사 설정을 무시하므로 두 결과가 반드시 달라야 한다고 요구해서는 안 됩니다.

기준 데이터, 스크립트, 의존성 목록, 사용한 토크나이저 파일의 체크섬을 함께 버전 관리에 포함하세요. 샘플에는 합성 데이터만 사용해야 합니다. 실제 대화, 액세스 토큰, 내부 문서를 저장소에 커밋할 기준 데이터에 넣지 마세요.

실제 MLX 호출 경로에서 입력 변화 추적하기

스크립트를 통과한 뒤에도 애플리케이션 진입점에서 같은 템플릿과 매개변수를 사용하는지 확인해야 합니다. 어떤 호출 계층은 메시지 배열을 받고, 어떤 계층은 이미 렌더링된 문자열을 받습니다. 렌더링된 문자열을 채팅 래퍼에 다시 넘기면 템플릿이 두 번 적용될 수 있습니다. 생성 함수에 진입하기 직전에 합성 샘플의 최종 토큰 ID를 캡처해 기준 데이터와 항목별로 비교하세요.

특수 토큰을 중복 추가하지 않기

템플릿에는 시작 토큰이나 종료 토큰이 이미 들어 있는 경우가 많습니다. 그래서 스크립트는 렌더링된 텍스트를 인코딩할 때 add_special_tokens=False를 사용합니다. BOS를 별도로 직접 덧붙이지 마세요. 디코딩한 결과가 “정상으로 보인다”는 이유만으로 통과시켜서도 안 됩니다. 특수 토큰을 숨기는 디코딩 옵션 때문에 중복 입력이 드러나지 않을 수 있습니다.

차이가 발견되면 먼저 rendered를 비교한 다음 ids를 비교합니다. 텍스트가 다르면 템플릿과 메시지 전처리부터 살펴보세요. 텍스트는 같은데 ID가 다르면 어휘 사전, 추가 토큰, 토크나이저 구현을 확인합니다. 실제 입력이 같다는 사실을 확인한 뒤에야 샘플링 매개변수와 가중치 버전을 점검해야 합니다.

실패를 재검토 가능한 점검 항목으로 만들기

빈 내용, 후행 공백, 이모지, 긴 중국어 샘플을 추가할 때는 각 항목이 무엇을 검증하는지 명시하세요. 무작위 문자열만 쌓아 두어서는 안 됩니다. 긴 입력은 애플리케이션 계층에서 컨텍스트 예산도 확인해야 합니다. 이 스크립트는 생성 작업에 필요한 출력 공간을 확보해 주지 않으며, 잘림 처리 정책도 검증하지 않습니다.

인계 전에 네 가지를 확인하세요. 오프라인 실행 중 파일을 다운로드하지 않는지, 일반 검사에서 기준 데이터를 덮어쓰지 않는지, 템플릿과 토큰 어느 쪽에서 차이가 나더라도 작업이 중단되는지, 의존성 업그레이드에 사람의 검토가 필수인지 점검합니다. 기준 데이터를 갱신할 때는 후보 파일을 따로 저장하고 변경 내역을 제출하세요. 검사 실패 분기에서 자동으로 다시 기록해서는 안 됩니다.

임대 기간에 보존해야 할 것은 특정 답변의 스크린샷이 아니라 다시 실행해 검증할 수 있는 입력 증거입니다. 그래야 다른 클라우드 Mac으로 옮겼을 때 모델이 받은 내용이 바뀌지 않았음을 먼저 입증한 뒤, 답변이 달라진 이유를 논의할 수 있습니다.

자주 묻는 질문

검사할 때 모델 가중치를 로드해야 하나요?

아니요. 템플릿 렌더링과 토큰화에는 로컬 토크나이저 파일만 필요합니다. 생성 품질을 평가하는 검사는 아닙니다.

업데이트 후 토큰 ID가 달라지면 기준을 덮어써도 되나요?

먼저 토크나이저 파일, 템플릿, 의존성 버전의 차이를 확인하세요. 의도한 변경인지 검토한 뒤 새 기준을 승인해야 합니다.

실험 기간에 맞춰 Mac 대여하기

Mac mini M4를 단독으로 이용하세요. 통합 메모리 16GB / SSD 256GB를 제공합니다. 일·주·월·분기 단위로 선결제하며, 기간이 끝나면 자동 갱신 없이 기기가 중지됩니다. 모델과 실행 환경은 직접 준비해야 하며, 실제 이용 가능 여부는 콘솔에 표시되는 최신 상태를 기준으로 합니다.

일 단위로 Mac 대여하기

구성을 확인한 뒤 실험을 시작하세요

모델 가중치, 최대 사용량, 대여 기간을 확인한 다음 이용 기간을 선택하세요. 연결 방법이 궁금하다면 도움말 센터를 먼저 살펴보세요.