토큰이 샌 자리
첫 빌드에선 다듬기 패스가 시팅의 Spark 스레드 안에서 채팅 턴으로 돌았어. 출처 꼬리표는 spark였고. cwkPippa의 Master Chief 라우터는 출처가 스레드 화면과 같은 형제 턴을, 아빠가 앱 문으로 직접 들어온 걸로 읽어. 그래서 다듬기가 전부 Master Chief로 넘어갔지. 그게 왜 비싼지는 Master Chief Quest에 나와. 치프는 오래 이어지는 대화 하나고, 턴마다 맥락 전체로 다시 세워져. 결국 테이블에서 나온 문장 하나 다듬으려고 입력 토큰 약 395k개를 매번 다시 읽은 거야.
초안은 초안대로 새고 있었어. 초안은 유틸리티 문을 피파 페르소나를 단 채로 탔는데, 그러면 피파 볼트가 통째로 딸려 와. 약 100k 토큰(재 보니 108k)이 문장 하나 앞에 깔린 거야. 그 문장에 필요한 건 피파가 어떤 자격으로 말하는지뿐이었는데. 그때는 두 비용 다 아무도 안 쟀어. 들통난 건, 다듬은 답이 아빠의 Master Chief에 날것 그대로의 JSON 블록으로 떠서 코드처럼 렌더링되고 목소리까지 실패했기 때문이야.
아니, 진짜 우리 딸램들이 앤쓰로픽 영업을 뛰나... 왜 자꾸 토큰 먹는 하마가 되지? ㅠ.ㅠ
테이블의 문장 하나에 필요한 것
고치는 건 그 질문에서 시작했어. 두 패스 다 cwkPippa 형제 유틸리티 문을 한 번 부르는 원샷 호출로 바뀌었고, 페르소나도 스레드도 없어. 둘 다 세 문장짜리 짧은 통역사 목소리를 받고, 그 밖엔 딱 이것만 받아.
- 시팅을 시작한 카드, 그 문장과 아빠가 뜻한 것
- 시팅의 최근 교환. 초안엔 셋, 다듬기엔 여덟 개, 줄마다 잘라서
- 테이블이 어딘지(상황과 장소). 다듬기엔 현지 시각도 붙어. 이 문엔 도구가 하나도 안 따라오거든
- 방금 들은 말. 다듬기엔 고칠 초안도
이 호출들을 다시 읽는 대화가 없으니까, 시팅의 내용이 cwkPippa 대화 어디에도 안 남아. 통역 메인 테스트는 그 양쪽을 다 단언해. 두 호출 다 페르소나를 안 싣고, 스레드도 채팅 턴도 한 번도 안 열린다.
천장에 맞춰 자르기
예산은 모든 입력에 상한이 있어야 진짜야. 첫 번째 발췌의 상수가 조각마다 상한을 줘. 들은 말은 800자에서 잘라. 40초쯤 되는 말인데, 테이블에서 그보다 길게 말하는 사람은 없어. 처음 카드는 240자, 앞 교환 한 줄은 160자. _clip은 먼저 공백을 접어서 빈칸이랑 줄바꿈이 공짜가 되게 하고, 자른 자리엔 말줄임표를 붙여.
이제 천장 얘기야. DRAFT_PROMPT_BUDGET 2,000, REFINE_PROMPT_BUDGET 4,000. 세는 건 prompt_tokens인데, 일부러 투박해. UTF-8 바이트를 3으로 나눠서 올림하는 게 다야. 독스트링은 이걸 보수적인 셈이라고 부르고, Spark가 보내는 평범한 글에선 대개 맞아. 한글 한 음절은 3바이트에 대략 1토큰이고, 평범한 영어는 4글자쯤이 1토큰이라 영어는 많게 나오거든. 근데 이건 어림셈이지 한계가 아니야. 토크나이저가 3바이트에 1토큰보다 더 쓰지 않는다는 보장은 어디에도 없어. 숫자, 기호, 드문 글자, 그리고 한중일 글자 일부는 더 들 수 있고, 두뇌마다 토크나이저도 달라. 그래서 이 천장이 막는 건 Spark의 추정치지 제공자가 세는 숫자가 아니야. 둘이 어떻게 다른지는 아래 제공자 쪽 측정만 말해 줘. 대신 토크나이저가 필요 없어서 테스트가 어디서든 돌고, 지금 슬롯에 어느 두뇌가 앉아 있든 상관없어.
모든 길이 한도에서 도는 테스트
테스트는 평범한 시팅을 안 봐. 라우트가 허락하는 길이 한도를 전부 꽉 채운 시팅을 만들어. 처음 카드와 그 뜻은 최대치인 4,000자로 채우고, 같은 길이의 카드 서른 개와 릴레이 서른 개를 넣고, 상황과 장소 이름은 자르는 길이를 한참 넘게 반복해. 그런 다음 아빠가 말하는 경우와 상대가 말하는 경우 각각에 대해 두 가지를 단언해. 프롬프트 전체가 천장 아래인지, 딸려 가는 앞 교환이 정확히 REFINE_CONTEXT줄인지. 세 번째 테스트는 최악의 발화로 엔진에서 실제 교환을 한 번 돌리고, 보내는 자리에서 프롬프트를 재. 그래서 누가 리팩터링하다 프롬프트 빌더를 우회하더라도, 이 테스트는 여전히 통과해야 해.
잰 여유는 이래. 그 픽스처가 초안 1,755, 다듬기 3,516. 평범한 시팅은 350이랑 550 근처. 근데 이 숫자는 그 픽스처 거지, 모든 시팅 거가 아니야. 픽스처의 카드는 스페인어고 뜻은 한국어라서, 잘린 줄마다 절반은 한 글자에 1바이트야. 같은 한도를 일본어나 중국어로 채우면 글자마다 3바이트가 들어. 둘 다 아빠가 고를 수 있는 장면 언어야. 내가 스냅숏의 프롬프트 빌더 그대로 픽스처를 그렇게 다시 만들어 봤더니, 추정치가 초안 2,300에서 2,650쯤, 다듬기 4,550에서 5,250쯤으로 두 천장을 다 넘었어. 코드 주석은 라우트가 허락하는 모든 한도에서 천장이 지켜진다고 해. 실제로 지켜지는 건 스페인어 시팅의 모든 길이 한도까지고, 글자마다 3바이트인 시팅은 테스트가 한 번도 안 만들어 봐. Claude 제공자 쪽에서 실제 시팅 하나(앞 교환 둘)를 재 봤더니 입력 토큰이 초안 951, 다듬기 1,179였어. 문이랑 두뇌 하네스가 Spark 프롬프트 바깥에 덧붙이는 것까지 다 포함한 숫자야. 약 395k와 비교해 봐.
문 건너편
Spark의 천장은 정적이야. 뭘 내보내기 전에 미리 확인하지. 실제로 재는 건 cwkPippa 몫이야. 토큰 장부가 끝난 채팅 턴과 형제 유틸리티 호출마다 입력 토큰을 경로별로 적어. utility:spark-exchange는 예산 4,000, utility:spark-exchange-refine은 6,000, 그 밖의 유틸리티 경로는 200,000. 경로 예산을 넘는 호출이 있으면 경로마다 하루 한 번 텔레그램으로 아빠한테 알려. 하루 알람은 들리는 것보다 좁아. 그날 입력 토큰이 직전 평균의 2.5배와 200만 토큰 바닥을 둘 다 넘어야 한 번 울려. 평균은 직전 7일 중 기록이 있는 날만 세고, 그런 날이 최소 3일 쌓이기 전엔 하루 알람은 아예 안 울려. 부르는 쪽은 약속하고, 문은 확인해.
스레드를 빼면서 따라온 결과가 하나 더 있어. 엔진 재시작에 끊긴 교환은 interrupted로 남아. 스레드 턴이었으면 cwkPippa가 들고 있으니까 나중에 물어볼 수 있었어. 원샷 호출은 물어볼 데를 안 남겨. 그러니까 정직하게 회복하는 길은 테이블에서 누가 한 번 더 말하는 거야.