[REF:id] 태그로 남고, 모델이 원본이 필요하면 expand_context를 호출해 정확한 원문을 즉시 복구한다.
Paritok-official/paritok-4b-v1 · 베이스 Qwen3-4B-Instruct-2507 · 어댑터 LoRA r=32 · 미들웨어 Python 3.10+ · 라이선스 Apache 2.0 · 패키지 버전 1.2.7 · 학습 데이터 45K 궤적 · SWE-bench 품질 유지 86.5% · 압축률 25.7% · q4 모델 ~2.5GB · 24GB GPU 1장 자체호스팅 · 제작 2인 팀 · 최초 릴리스 2026-07-14)
Paritok은 "코딩 에이전트와 LLM 사이에 앉은 압축 통역사"다. 에이전트가 매 턴 LLM에 보내는 요청에는 방금 읽은 파일 전체, 방금 실행한 bash 출력, 지난 대화 수십 턴, 그리고 70개가 넘는 툴 정의(JSON 스키마)가 통째로 들어간다. 이 대부분은 실제 답을 내는 데 필요 없다. Paritok은 그 요청을 가로채 필요한 것만 남기고 나머지를 요약·생략한 뒤 올려보낸다. LLM은 훨씬 짧은 입력을 받고, 너는 짧아진 만큼 청구서를 덜 낸다.
변호사(LLM)는 시간당 요금을 받는다 — 읽는 페이지(입력 토큰)만큼 돈을 낸다. 3000쪽 원본을 그대로 넘기면 비싸다. 유능한 보조원(Paritok)은 사건 판단에 꼭 필요한 핵심 — 계약 조항, 날짜, 이름 — 은 한 글자도 빼지 않고, 반복되는 정형 문구·잉여 로그는 "여기 이런 내용 있음"으로 줄여 30쪽으로 만든다.
결정적으로, 요약본에는 각 항목마다 원본 쪽 번호([REF:id])가 붙어 있다. 변호사가 "이 조항 원문 전체를 봐야겠다" 싶으면 그 번호를 부르고, 보조원이 즉시 원본 그 페이지를 그대로 가져다준다. 그래서 줄였지만 잃지 않는다.
2025~2026년 코딩 에이전트가 폭발적으로 퍼지면서 새로운 고통이 생겼다 — 토큰 청구서. 에이전트는 한 작업을 끝내려고 수백 번 LLM을 호출하고, 매번 "지금까지의 모든 파일 + 모든 출력 + 모든 대화"를 다시 통째로 밀어넣는다. 긴 세션에서 한 턴 입력이 3만 토큰을 넘기는 일이 흔하다. Paritok의 README는 이걸 정면으로 조준한다 — 10인 팀 3개월 프로젝트에서 입력 비용 $13,500 → $3,468, 약 1만 달러 절감(전형 74% 절감 가정)이라고 예시를 든다.
Paritok이 급부상한 이유는 "압축"이라는 오래된 아이디어에 세 가지 신선한 각도를 붙였기 때문이다.
기존 프롬프트 압축기(LLMLingua-2 등)는 일반 텍스트로 학습됐다. Paritok은 실제 코딩 에이전트 궤적 45,000건으로 학습해서, import 문·함수명·파일 경로·에러 클래스는 "비싼 값"으로 지키고 디버그 라인은 과감히 버린다. 같은 작업에서 gpt-4.1-mini 프롬프팅보다 약 2배 더 세게 압축하면서 정답률은 동급이라고 주장한다.
압축의 공포는 "혹시 중요한 걸 버렸으면?"이다. Paritok은 압축된 조각마다 [REF:id] 태그를 달고, 원본은 로컬 섀도 스토리지에 보관한다. LLM이 원문이 필요하면 expand_context라는 가상 툴을 호출 → 미들웨어가 정확한 원문을 즉시 반환한다. 전송 구간에서만 손실이고, 필요할 때 완전 복구 가능이라는 설계다.
가중치는 Apache 2.0, 4B라서 24GB GPU 한 장 또는 Ollama로 CPU/맥에서도 돈다(q4 ~2.5GB). SaaS 종속도, 압축기에 붙는 토큰당 별도 요금도 없다. 데이터 파이프라인까지 공개해 재현 가능하다고 강조한다.
| 컨텍스트 소스 | 품질 유지율 ¹ | 압축률(낮을수록 셈) |
|---|---|---|
| 무압축 기준선 | 100.0% | 100.0% |
| gpt-4.1-mini (압축기) | 85.6% | 50.2% |
| gpt-5 (압축기) | 93.6% | 61.9% |
| Paritok-4B-v1 ⭐ | 86.5% | 25.7% |
¹ 품질 유지율 = 압축기 정답률 ÷ 무압축 기준선 정답률. 높을수록 좋다. 즉 Paritok은 토큰을 절반 이하로 쓰면서 gpt-4.1-mini와 같은 정답 유지율을 냈다는 주장이다.
86.5% / 25.7% 같은 수치는 2인 팀의 자체 평가다. README도 "per-issue 결과와 재현 방법은 v2 릴리스와 함께 공개"라고 적어, 현재는 제3자 검증 전이다. "95% 절감" 같은 상단값은 툴 출력이 극단적으로 반복되는 롱세션 가정치이니, 실제 절감은 워크로드에 따라 크게 달라진다. 학습으로 배운 요약이라 드물게 환각·오요약 가능성도 원리상 남는다(그래서 expand_context가 안전장치).
| 항목 | Paritok-4B-v1 | LLMLingua-2 | gpt-4.1-mini 프롬프트 |
|---|---|---|---|
| 코딩 궤적 학습 | ✅ | ❌ | ❌ |
| 함수명·경로 보존 | ✅ 설계상 | 부분적 | 부분적 |
| 압축률(낮을수록 셈) | 25.7% | ~40% | 50.2% |
| 자체호스팅 오픈 가중치 | Apache 2.0 | MIT | 비공개 API |
| 압축기 토큰당 요금 | 0 (자체호스팅) | 0 (오픈) | 토큰당 과금 |
Paritok은 한 저장소 안에 성격이 완전히 다른 두 세계가 같이 산다. (A) 사용자가 매일 돌리는 런타임(미들웨어+프록시)은 의존성이 극도로 가볍고, (B) 모델을 만드는 학습·데이터 파이프라인은 무거운 ML 스택이다. 이 분리를 이해하는 게 핵심이다.
pyproject.toml의 기본 의존성은 딱 넷뿐이다. 사용자가 pip install paritok 할 때 이것만 깔린다.
paritok up, paritok proxy, paritok init 같은 CLI 명령 뼈대.paritok.yaml 설정 파싱.[proxy])paritok/proxy/server.py(1,291줄)의 엔진.requirements.txt) — 무겁다모델을 직접 재현하려는 사람만 건드리는 영역. 전형적인 HuggingFace 미세조정 스택이다.
Paritok을 이해하는 가장 좋은 방법은 "에이전트가 요청 하나를 던진 순간부터, 압축된 요청이 Anthropic에 도착하기까지"를 따라가는 것이다. 전체 그림은 이렇다.
코딩 에이전트는 MCP 서버까지 붙으면 매 요청에 70개+ 툴 정의(JSON)를 통째로 싣는다. 대부분은 지금 작업과 무관하다. tool_discovery.py는 사용자 의도를 임베딩해 가장 관련 있는 top-K(기본 5, 최대 8)만 전체 스키마로 남기고 나머지는 최소 스텁으로 바꾼다.
영리한 포인트는 프롬프트 캐시 친화다. 툴 선택은 대화당 한 번 고정(freeze)돼서, 턴이 바뀌어도 tools[] 블록이 바이트 단위로 동일 → LLM의 KV 캐시를 무효화하지 않는다. 스텁된 툴이 나중에 필요하면 gateway_search_tools로 되찾는다.
compress.py의 파이프라인은 각 tool_result(파일 읽기 결과, bash 출력 등)를 이렇게 처리한다.
1. 이미 압축됨? ([REF:] 접두사면 건너뜀)
2. 토큰 게이팅 (min 512 미만이면 압축 안 함, max 50000 초과 청킹)
3. SHA256 캐시 (같은 내용 재등장 → 재압축 없이 기존 [REF] 재사용)
4. 4B 모델 호출 (Ollama에 "이 조각 압축해" 프롬프트)
5. 효과 검사 (refusal_threshold 0.05 미만이면 원본 유지)
6. 섀도 저장 (원본 보관 + [REF:id src=경로] 태그로 치환)
주목할 디테일: Claude Code의 Read 툴은 cat -n 스타일 줄번호( 1\t실제내용)를 붙인다. Paritok은 매칭 비교 때 이 줄번호 접두사를 정규화해 벗겨서, 같은 파일을 offset만 바꿔 다시 읽어도 동일 섀도로 인식(재압축 방지)한다.
HistoryConfig는 최근 4턴은 원본 그대로 두고, 전체 컨텍스트가 창의 80%를 넘으면 그 이전 턴들을 한 번 요약한다. 긴 세션에서 "95% 절감"이 나오는 지점이 바로 여기 — 파일·툴 출력이 반복 누적된 옛 히스토리가 통째로 접힌다.
미들웨어는 툴 목록에 실재하지 않는 두 개의 가상 툴을 몰래 끼워넣는다. LLM은 이걸 진짜 툴처럼 부르지만, 호출은 상위 API로 안 가고 프록시가 가로채 로컬에서 처리한다.
expand_context(shadow_id) — [REF:abc123]의 원문 전체를 섀도 스토리지에서 즉시·정확히·로컬로 반환. 다시 Read/Grep 하는 것보다 빠르고 재압축도 없다.gateway_search_tools(query) — 1단계에서 스텁된 툴 스키마를 되찾음.도서관 대출 시스템. 책 전체(원본)를 늘 들고 다니면 무겁다. Paritok은 각 책을 "제목+한 줄 초록+청구기호([REF:id])" 카드로 바꿔 준다. 대부분은 카드만 봐도 충분하다. 정말 본문이 필요하면 청구기호로 expand_context를 불러 그 책 원본을 그 자리에서 꺼내 온다 — 책은 버려진 게 아니라 서고(섀도 스토리지)에 그대로 있다.
모델 판단만 믿지 않는다. src/mustkeep.py는 하나의 거대 정규식으로 절대 버리면 안 되는 스팬을 스캔한다 — 파일 경로, 스택트레이스의 File "...", 줄번호, 커밋 해시, URL, XxxError/XxxException 같은 에러 클래스, snake_case·camelCase 식별자, 패키지명(numpy·torch…). 이 스팬들은 압축 대상에서 보호된다. "모델의 감각 + 규칙의 보증"을 겹쳐 함수명·경로 손실을 막는 이중 안전장치다.
구조가 던지는 메시지는 분명하다. 왼쪽 위(paritok/)만 알면 도구를 쓸 수 있고, data_pipeline/·training/은 "우리가 어떻게 이 모델을 만들었는지 다 공개한다"는 투명성의 증거물이다. 특히 data_pipeline/review_app/(사람이 압축 결과를 눈으로 검수하는 Electron 앱)의 존재는, 데이터 품질을 손으로 관리했다는 신호다.
이 프로젝트의 진짜 교재 가치는 "에이전트를 안 고치고 동작을 바꾸는 법"이다. ANTHROPIC_BASE_URL 하나만 바꿔 요청을 가로채고, 본문을 변형해 상위로 포워딩하고, 헤더(진짜 API 키)는 그대로 흘려보낸다. proxy/adapters/에서 Anthropic Messages·OpenAI Chat·OpenAI Responses 세 가지 와이어 프로토콜을 서로 변환하는 코드는, LLM 인프라를 짜는 사람에게 그대로 참고서가 된다.
"gpt-4.1-mini에게 정답을 만들게 하고 4B가 흉내 낸다"는 교사 증류 + LoRA 파이프라인 전체(data_pipeline/ → training/)가 공개돼 있다. 데이터 수집 → 세그먼트화 → 교사 라벨링 → 필터/리밸런스 → SFT → 체크포인트 선택의 6단계를 그대로 읽을 수 있는, 흔치 않은 오픈 교재다.
mustkeep.py는 "LLM은 감으로 압축하되, 규칙으로 핵심을 보증한다"는 방어적 설계의 좋은 예다. 순수 LLM도 순수 규칙도 아닌 겹layer 안전망 — 프로덕션 AI 시스템에서 자주 필요한 패턴이다.
bge-small로 툴을 top-K 선택하는 tool_discovery.py는 로컬 임베딩으로 무엇을 컨텍스트에 넣을지 고르는 미니 RAG다. 여기에 "선택을 대화당 고정해 프롬프트 캐시를 안 깬다"는 비용 인지까지 얹혀 있어, 실전 토큰 경제학을 배우기 좋다.
paritok up으로 프록시를 띄우고 Claude Code를 붙인 뒤, curl 127.0.0.1:8080/stats로 내 실제 세션의 압축률·절감 토큰을 관찰해 보라. 그다음 trace.enabled를 켜서 원본 vs 압축본을 tool_result 단위로 diff — "무엇이 버려지고 무엇이 지켜지는가"를 눈으로 확인하는 게 이 도구를 신뢰(또는 불신)하는 가장 빠른 길이다.
| 경로 | 필요 자원 | 비고 |
|---|---|---|
| Ollama 자체호스팅 (기본) | q4 모델 ~2.5GB 디스크, CPU/맥에서도 구동 | paritok up이 자동 pull. 가장 쉬운 길 |
| vLLM (LoRA 어댑터 직접) | 24GB GPU 1장, bf16 | Qwen3-4B + LoRA를 OpenAI 호환 서빙 |
| Paritok GPU 서버 | GPU 불필요, API 키만 | paritok.com 유료 호스팅(use_gpu_server: true) |
:latest는 q4_K_M(~2.5GB, 런타임 검증 대상).OPENAI_BASE_URL을 무시하고 ~/.codex/config.toml만 읽는다 → Paritok이 그 파일을 대신 써 준다(codex.enabled: true).컨텍스트가 이미 2,000토큰 미만이거나, 히스토리가 누적되지 않는 단발 질의응답이면 300ms 오버헤드만 얹힐 뿐 절감이 없다. "바이트 단위로 완전 동일한 컨텍스트, 요약 단계 자체를 용납 못 함"인 워크로드도 부적합(다만 이 경우 대부분 expand_context로 커버된다고 README는 반박한다). v1은 Python 편중 — TypeScript·Rust·Go 등 다국어 지원은 v2 로드맵이다.
pip install "paritok[proxy]" → paritok up → ANTHROPIC_BASE_URL 설정 후 Claude Code로 아무 프로젝트나 몇 턴 작업. /stats를 찍어 compression_ratio와 tokens_saved를 기록하라. 짧은 작업 vs 긴 롱세션에서 숫자가 어떻게 달라지는지 비교.
src/mustkeep.py의 COMBINED_PATTERN은 numpy·torch 등 정해진 패키지명만 보호한다. 여기에 네가 쓰는 스택(예: React 훅 useXxx, 환경변수 ENV_VAR, 도커 이미지 태그)을 보호 스팬으로 추가하고, 압축 trace에서 그것들이 실제로 지켜지는지 확인하라.
trace.enabled로 남는 JSONL(원본·압축본·토큰수)을 읽어, tool_result별로 "원본 ↔ 압축본 side-by-side diff + 절감 토큰"을 보여 주는 작은 HTML 대시보드를 짜라. 어떤 종류의 콘텐츠가 잘 압축되고(로그) 어떤 건 안 되는지(코드) 데이터로 답이 나온다.
proxy/adapters/를 참고해, Gemini 네이티브 API나 다른 공급자용 어댑터를 하나 추가하라. 요청 파싱 → ParitokEngine.process_request() 호출 → 압축 결과를 그 프로토콜로 재직렬화하는 흐름을 익히면, LLM 게이트웨이의 뼈대를 완전히 이해하게 된다.
data_pipeline/로 소규모 궤적 풀을 만들고, 더 작은 베이스(예: Qwen3-1.7B)에 LoRA SFT로 축소판 압축기를 학습해 보라. 교사 증류 → 필터 → SFT → 체크포인트 선택의 전 과정을 직접 밟으며, 압축률/품질 트레이드오프를 스스로 튜닝.
BASE_URL 리다이렉션으로 클라이언트 안 고치고 가로채기.| 용어 | 뜻 |
|---|---|
| 압축률(CR) | 압축 후/전 토큰 비율. 25.7% = 원본의 4분의 1로 줄임. 낮을수록 세게 압축. |
| 품질 유지율 | 압축기 정답률 ÷ 무압축 정답률. 86.5% = 무압축의 86.5%만큼 문제를 품. |
| [REF:id] | 압축된 조각 자리에 남는 참조 태그. src=경로 힌트 포함 가능. |
| 섀도 스토리지 | [REF:id]의 원본을 보관하는 로컬 저장소. expand_context가 여기서 원문을 꺼냄. |
| expand_context | LLM이 부르는 가상 툴. 압축된 원문을 즉시·정확히 복구. |
| gateway_search_tools | 툴 발견 단계에서 스텁된 툴 스키마를 되찾는 가상 툴. |
| 툴 발견 | 70개+ 툴 중 관련 top-K만 전체 스키마로 남기는 스키마 다이어트. |
| must-keep | 정규식으로 보호하는 절대-보존 스팬(경로·에러·식별자·해시…). |
| LoRA | 본체는 두고 얇은 보정 어댑터만 학습하는 미세조정 기법(r=32). |
| 교사 증류 | gpt-4.1-mini의 압축 정답을 4B가 흉내 내며 배우는 방식. |
| refusal_threshold | 압축 효과가 5% 미만이면 그냥 원본을 유지(무의미한 압축 방지). |
| use_gpu_server | 압축을 자체 하드웨어(false)/Paritok 호스팅(true) 어디서 돌릴지 스위치. |