-
산문은 손실 압축, 코드는 무손실 — 무엇을 지킬 수 있는지는 '중요도'가 아니라 '식별 가능성'이 정한다IT 2026. 7. 31. 23:00
먼저 이 글이 무엇을 줄이는 이야기인지부터 못 박아 두자. 여기서 압축하는 것은 모델이 뱉는 출력이 아니라, 모델에게 매번 밀어 넣는 입력 컨텍스트다. 앞선 글에서 다룬 caveman의 본체 스킬은 "모델이 짧게 말하게" 만들어 출력 토큰을 줄였다. 오늘 볼 두 도구는 반대편을 친다 — 모델이 읽기도 전에, 컨텍스트에 실릴 텍스트 자체를 미리 깎아 둔다. 구체적으로 무엇을 깎느냐면 이 둘이다.
caveman-compress— 디스크에 놓인 에이전트 메모리 파일. `CLAUDE.md`, 할 일 목록, 선호 설정 같은 markdown 문서를 압축본으로 덮어쓴다.caveman-shrink— MCP 서버가 노출하는 도구 설명(description) 필드. 파일이 아니라 서버 응답을 오가는 문자열을 실시간으로 깎는다.
둘 다 모델의 대답에는 손대지 않는다. 대답이 나오기 전에 이미 컨텍스트에 눌러앉아 있는 텍스트를 줄이는 것이다.
왜 이게 남는 장사인가? AI 에이전트에게 매 세션 똑같은 메모리 파일을 물려줄 때마다 입력 토큰이 그대로 다시 나간다. MCP 도구 설명도 마찬가지로 요청마다 프롬프트에 실린다. 한 번 깎아 두면 이후 모든 세션·모든 요청에서 값이 빠진다. 그리고 이 문서들은 대개 산문이라 군더더기가 많다. "You should always make sure to run the test suite before pushing"은 "Run tests before push"로 줄여도 뜻이 하나도 안 상한다. 그래서 이 파일들을 자동으로 압축하자는 발상은 자연스럽다.
그런데 막상 압축기를 붙여 보면 멈칫이 온다. 압축기는 산문만 줄이는 게 아니라 코드 블록 안의 주석을 지우고, 명령어를 "더 간결하게" 바꾸고, URL의 쿼리 스트링을 정리해 버린다. 산문은 조금 뭉개져도 뜻만 통하면 그만이지만, `git commit --amend`에서 `--amend`가 사라지거나 `/src/config.yaml` 경로가 `config.yaml`로 줄면 그 파일은 망가진 것이다. 여기서 이 글의 첫 문장이 나온다 — 산문은 손실 압축이어도 되지만, 코드는 무손실이어야 한다.
`caveman`이라는 도구는 이 경계를 두 가지 전혀 다른 방법으로 긋는다. 하나는 LLM에게 압축을 맡기되 결과를 기계로 대조하는 사후 대조고, 다른 하나는 코드를 텍스트에서 아예 들어낸 뒤 압축하는 사전 봉인이다. 그리고 두 방법을 나란히 놓고 보면, 애초에 무엇을 무손실로 지킬 수 있는지가 그 조각의 중요도가 아니라 오탐 없이 식별할 수 있는가로 결정된다는 사실이 드러난다. 오늘 하고 싶은 이야기는 그것이다.
손실 압축과 무손실 압축은 원래 다른 물건이다
이미지로 비유하면 익숙하다. 사진은 JPEG로 저장한다 — 사람 눈이 못 알아챌 만큼만 정보를 버려서 용량을 확 줄이는 손실 압축(lossy compression)이다. 반면 프로그램 실행 파일은 절대 JPEG로 저장하지 않는다. 1비트만 틀어져도 실행이 안 되니 ZIP 같은 무손실 압축(lossless compression, 복원하면 원본과 byte 단위로 똑같은 방식)을 쓴다. 무엇을 압축하느냐에 따라 허용되는 손실의 양이 다르다.
메모리 파일 한 장 안에도 이 두 종류가 섞여 있다. 설명 문장은 사진에 가깝고, 코드·명령어·URL·경로는 실행 파일에 가깝다. 그러니 파일 전체에 같은 압축을 걸면 안 된다. 문제는 "같은 파일 안에서 어디까지가 사진이고 어디부터가 실행 파일인지"를 기계가 알아내야 한다는 것이다. 이 경계 긋기가 생각보다 어렵고, 이 글의 두 도구는 그 어려움에 정반대로 대응한다.
답 하나 — LLM에게 맡기고, 결과를 기계로 대조한다
먼저 `caveman-compress`. 압축 대상은 앞서 말한 에이전트 메모리 파일 — 세션마다 컨텍스트로 실리는 `CLAUDE.md` 같은 markdown 문서다. Python 스킬이고, 파일 본문을 통째로 LLM(`call_claude()`)에 보내 "코드·URL·경로는 건드리지 말고 산문만 줄여라"라고 시킨다. 프롬프트로 부탁하는 방식이다. 여기서 LLM은 압축을 수행하는 일꾼이지, 압축의 대상이 아니라는 점을 기억해 두자 — 이 일꾼이 뱉은 결과물이 곧 새 메모리 파일이 되어, 앞으로 모든 세션의 입력이 된다.
부탁의 문제는 명백하다. LLM은 비결정적(non-deterministic, 같은 입력에도 출력이 매번 달라질 수 있는 성질)이라, 열 번 중 아홉 번은 지시를 지켜도 열 번째에 조용히 명령어 플래그를 빠뜨린다. 그리고 이 압축의 목적이 "사람이 안 읽는 파일을 자동으로 줄이는 것"이라, 그 열 번째 실수를 눈으로 잡아 줄 사람이 없다. 그래서 `caveman-compress`는 압축 뒤에 결정론적 검증기(deterministic validator, 매번 똑같이 판정하는 규칙 기반 대조기)를 붙인다.
다이어그램 설명. 메모리 파일이 압축을 거쳐 통과하거나, 실패하면 원본으로 되돌아오는 전체 흐름이다. 눈여겨볼 순서가 셋 있다. 첫째, 백업이 압축보다 먼저다. 그것도 그냥 쓰고 마는 게 아니라 다시 읽어서 원본과 byte가 같은지 확인한 뒤에야 다음으로 간다 — 백업이 깨진 채로 원본을 덮어쓰면 되돌릴 곳이 없어지기 때문이다. 둘째, 검증은 덮어쓰기를 막는 관문이 아니라 덮어쓴 뒤에 되돌리는 롤백 장치다. 파일은 일단 압축본으로 바뀌고, 검증에 최종 실패하면 백업에서 원본을 복구한다. 셋째, 첫 검증 실패에서 곧장 재압축으로 돌아가지 않고 검증기가 지목한 부분만 집어 고치는 좁은 수정으로 간다. 이미 잘 압축된 부분까지 다시 건드려 새 오류를 만들지 않기 위해서다. 검증은 최대 두 번, 그 사이 수정은 한 번 — 그래도 못 넘기면 억지로 밀지 않고 원본을 지킨다. 망가진 압축본보다 안 줄인 원본이 낫다는 판단이 흐름에 박혀 있다.
검증기가 나누는 두 등급 — 여기가 이 글의 핵심이다
검증기(`validate.py`)는 백업(원본)과 압축본을 나란히 놓고 여러 불변식(invariant, 압축 전후로 반드시 같아야 하는 성질)을 기계로 비교한다. 중요한 건 어긋남을 두 등급으로 나눈다는 점이다 — 어떤 어긋남은 압축을 실패로 되돌리고(error), 어떤 어긋남은 기록만 남긴다(warning).
다이어그램 설명. 같은 검증기가 어긋남을 두 갈래로 가른다. 실패 처리 쪽에는 코드 블록·URL·인라인 코드·헤딩 개수가 묶인다 — 하나라도 어긋나면 압축을 통째로 되돌린다. 특히 코드 블록은 문장 단위가 아니라 byte 단위 완전 일치라, 주석 한 글자나 공백 하나만 달라도 실패다. 반대로 경고 쪽은 어긋나도 압축을 막지 않는다. 글머리표 개수는 산문을 합치다 보면 자연히 줄어드는 게 정상이고, 제목 문구를 짧게 다듬는 정도도 산문 압축의 정상 범위다.
그런데 여기서 한 항목이 눈에 걸린다. 경로 문자열 변화가 왜 경고인가? 이 글의 도입부에서 나는 `/src/config.yaml`이 `config.yaml`로 줄면 "그 파일은 망가진 것"이라고 썼다. 망가지는 게 맞다면 실패 처리여야 하지 않나. 코드는 이렇게 되어 있다.
def validate_urls(orig, comp, result): u1, u2 = extract_urls(orig), extract_urls(comp) if u1 != u2: result.add_error(f"URL mismatch: lost={u1 - u2}, added={u2 - u1}") # ← 압축 되돌림 def validate_paths(orig, comp, result): p1, p2 = extract_paths(orig), extract_paths(comp) if p1 != p2: result.add_warning(f"Path mismatch: lost={p1 - p2}, added={p2 - p1}") # ← 기록만코드 설명. 구조가 판박이인 두 함수인데 마지막 한 줄만 다르다. URL이 하나라도 달라지면 `add_error`로 압축을 되돌리고, 경로가 달라지면 `add_warning`으로 기록만 하고 넘어간다. 중요도로 보면 이상하다 — 링크 깨지는 것과 경로 깨지는 것 중 뭐가 더 치명적인지는 문서 나름이다. 답은 중요도에 있지 않고, 그 조각을 오탐 없이 찾아낼 수 있느냐에 있다.
경로를 찾아내는 정규식은 소스 주석부터 "crude but effective"(조잡하지만 쓸 만함)라고 자백한다.
# crude but effective path detection PATH_REGEX = re.compile( r"(?:\./|\.\./|/|[A-Za-z]:\\)[\w\-/\\\.]+" # ./ ../ / C:\ 로 시작하는 것 r"|[\w\-\.]+[/\\][\w\-/\\\.]+" # 또는 그냥 슬래시가 낀 단어쌍 )코드 설명. 문제는 두 번째 줄이다. "슬래시가 낀 단어쌍"이면 무엇이든 경로로 본다. 그러면 `and/or`, `input/output`, `TCP/IP`, `24/7` 같은 평범한 산문이 죄다 경로로 잡힌다. 파이썬 정규식의 `\w`는 유니코드까지 포함하니 `읽기/쓰기` 같은 한국어 표현도 마찬가지다. 이제 산문 압축이 "input/output 처리"를 "IO 처리"로 줄였다고 하자. 정당한 압축인데, 검증기 눈에는 "경로가 사라졌다"로 보인다. 이걸 실패 처리로 두면 멀쩡한 압축이 오탐 때문에 계속 되돌아간다. 그래서 경고로 내려놓은 것이다.
반대로 실패 처리에 올라간 항목들을 다시 보면 공통점이 하나 있다. 전부 명확한 구분자를 갖는다. 코드 블록은 백틱 세 개 펜스로 열고 닫히고, 인라인 코드는 백틱으로 감싸이고, URL은 `https://` 스킴으로 시작한다. 구분자가 있으면 "여기부터 여기까지가 코드"라고 오탐 없이 잘라낼 수 있고, 오탐이 없으니 어긋남을 곧장 실패로 처리해도 안전하다. 경로에는 그런 구분자가 없다. 슬래시는 코드에도 산문에도 똑같이 나온다.
그래서 이렇게 정리된다. 무손실을 강제할 수 있느냐를 결정하는 것은 그 조각이 얼마나 중요한가가 아니라, 그 조각을 산문과 오탐 없이 구별할 수 있는가다. 아무리 지키고 싶어도 식별이 안 되면 강제할 수 없다. 강제하려 들면 오탐이 정상 동작을 죽인다. 경로가 경고에 남아 있는 건 설계자가 경로를 가볍게 봐서가 아니라, 이 파이프라인에서는 경로를 지킬 방법이 없기 때문이다.
덧붙여, "결정론적 검증"이라는 말도 여기서 정확히 해 두는 게 좋겠다. 결정론적이라는 건 같은 입력에 언제나 같은 판정이 나온다는 뜻이지, 모든 위반을 차단한다는 뜻이 아니다. 경로 경고는 결정론적이면서 동시에 아무것도 막지 않는다. 둘은 모순이 아니다.
실패 처리 쪽이 얼마나 깐깐한지는 인라인 코드 검증을 보면 안다. 단순히 "있다/없다"가 아니라 같은 조각이 몇 번 나오는지 개수까지 센다.
# 인라인 코드가 개수까지 보존됐는지 대조 — 하나라도 사라지면 error def validate_inline_codes(orig, comp, result): c1 = Counter(extract_inline_codes(orig)) # '조각 → 등장 횟수'로 집계 c2 = Counter(extract_inline_codes(comp)) if c1 != c2: lost = set(c1.keys()) - set(c2.keys()) added = set(c2.keys()) - set(c1.keys()) # 완전히 사라진 조각뿐 아니라, 3번 나오던 게 1번으로 준 것도 손실로 잡는다 for code, count in c1.items(): if code in c2 and c2[code] < count: lost.add(f"{code} (lost {count - c2[code]} of {count} occurrences)") if lost: result.add_error(f"Inline code lost: {lost}") # 사라진 건 압축 되돌림 if added: result.add_warning(f"Inline code added: {added}") # 새로 생긴 건 기록만코드 설명. `Counter`(등장 횟수를 세는 파이썬 자료구조)로 원본과 압축본의 백틱 조각을 각각 집계해 비교한다. 두 대목이 눈에 띈다. 첫째, `git commit`이 세 번 나오던 문서에서 두 번으로 줄어도 잡는다 — 완전 소멸뿐 아니라 부분 유실까지 손실로 본다. 둘째, 없어진 조각과 새로 생긴 조각의 처리가 비대칭이다. 사라진 조각은 압축 자체를 되돌리지만, 새로 생긴 조각은 기록만 한다. 코드를 잃는 건 복구 불가능한 사고지만, 산문이 코드처럼 보이게 바뀌는 건 대개 무해하기 때문이다. 백틱이라는 구분자가 있어서 이렇게까지 깐깐하게 셀 수 있다는 점도 다시 확인된다 — 경로에는 셀 수 있는 경계 자체가 없다.
답 둘 — 압축기에게 코드를 아예 보여주지 않는다
검증은 사후 대응이다. "틀렸다"를 알려 줄 뿐, 애초에 안 틀리게 하지는 못한다. 같은 저장소의 다른 도구인 `caveman-shrink`는 정반대 길을 간다. 압축 대상이 디스크의 메모리 파일에서 MCP(Model Context Protocol) 도구 설명 필드로 바뀌지만, 그것도 여전히 모델의 입력이다 — 도구 정의는 요청마다 프롬프트에 통째로 실리기 때문이다. `caveman-shrink`는 MCP 서버 앞에 끼어 앉아 그 설명 필드를 지나가는 길에 실시간으로 줄여 주는 미들웨어인데, 응답마다 LLM을 부를 여유가 없다. 그래서 이 도구는 LLM을 아예 쓰지 않는다. 압축기 자체가 정규식 치환이다 — 관사(`a`, `an`, `the`), 군더더기(`just`, `really`, `basically`), 인사말(`please`, `thanks`), 얼버무림(`perhaps`, `maybe`, `I think`)을 규칙으로 걷어낸다.
그런데 LLM을 걷어내도 문제는 그대로 남는다. 정규식 압축기도 코드 안의 관사를 지우고 함수 이름의 공백을 뭉갤 수 있다. 압축기가 LLM이든 정규식이든, 산문과 코드가 한 문자열에 섞여 있는 한 사고는 난다. `caveman-shrink`의 답은 압축기를 고치는 게 아니라 입력을 고치는 것이다.
다이어그램 설명. 코드와 산문을 분리해 산문만 압축하고 다시 합치는 과정이다. 순서가 곧 안전장치다 — 보호 대상을 봉인표로 먼저 바꿔치기해 코드·URL·경로를 텍스트에서 통째로 들어내면, 그다음 산문 압축 단계는 코드를 볼 수조차 없다. 압축기가 실수로 코드를 건드릴 물리적 가능성 자체가 사라진다. 앞의 검증기가 "틀리면 되돌린다"였다면, 이쪽은 "틀릴 수가 없다"이다. 그리고 이 구조의 핵심은 압축기가 갈아 끼울 수 있는 부품이 된다는 것이다. 실제 코드에서 봉인 함수는 압축 함수를 인자로 받는다(
withProtectedSegments(text, transform)) — 오늘은 그 자리에 정규식 압축기가 들어가 있지만, LLM을 넣어도 코드는 여전히 안전하다.봉인 대상 목록은 이렇게 생겼다. 앞서 검증기가 실패 처리로 잡던 것들이 거의 그대로, 그리고 더 넉넉하게 들어 있다.
// 산문 속에 섞여 있어도 절대 건드리지 않을 조각들 (봉인 대상, 위에서부터 순차 적용) const PROTECTED_PATTERNS = [ /[\s\S]*?```/g, // 1. 펜스 코드 블록 /`[^`\n]+`/g, // 2. 인라인 코드 (백틱) /\bhttps?:\/\/\S+/gi, // 3. URL 전체 /\b[\w.-]*[\/\\][\w.\/\\\-]+/g, // 4. / 또는 \ 가 든 경로 /\b[A-Z][A-Za-z0-9]*(?:_[A-Z][A-Za-z0-9]*)+\b/g, // 5. CONST_CASE 식별자 /\b\w+\.\w+(?:\.\w+)*\(\)?/g, // 6. dotted.method 또는 pkg.fn() /[A-Za-z_][A-Za-z0-9_]*\s*\([^)]*\)/g, // 7. 함수 호출 /\b\d+\.\d+\.\d+\b/g, // 8. 버전 번호 (1.2.3) ];
<p><em>코드 설명.</em> 여기서 <strong>경로(4번)가 다시 등장한다는 점이 결정적이다.</strong> 앞의 검증기에서는 경로를 지킬 수 없어 경고로 내려놨는데, 봉인 파이프라인에서는 지킬 수 있다. 이유는 오탐의 대가가 정반대이기 때문이다. 검증기에서 `input/output`을 경로로 오탐하면 <strong>멀쩡한 압축이 실패</strong>한다. 반면 봉인에서 `input/output`을 경로로 오탐하면 그 표현이 압축 대상에서 빠질 뿐이다 — <strong>덜 줄어들 뿐, 망가지지는 않는다.</strong> 같은 조잡한 정규식이라도 봉인에 쓰면 오탐의 비용이 "압축률 약간 손해"로 끝나고, 검증에 쓰면 "압축 자체가 죽음"이 된다. 그래서 경로는 봉인할 수는 있어도 검증할 수는 없다. 어디에 규칙을 놓느냐가 같은 규칙의 운명을 가른다.</p> <h2>중첩 — 봉인표가 봉인표를 감싸는 순간</h2> <p>봉인의 함정은 보호 규칙이 <strong>위에서부터 순차 적용</strong>된다는 데서 나온다. 앞 규칙이 심어 놓은 봉인표가, 뒤 규칙이 잡으려는 패턴 안으로 빨려 들어갈 수 있다. 실제 사례를 하나 돌려 보자. 원문은 이렇다.</p>Use setPlan(STARTER/BUSINESS) to upgrade.
<p>봉인이 진행되는 과정을 한 줄씩 따라가면 이렇게 된다. (봉인표는 NUL 바이트로 감싼 번호이고, 눈에 보이게 <code>␀</code>로 표기했다.)</p>규칙4 (경로) STARTER/BUSINESS → segments[0] 남은 텍스트: Use setPlan(␀0␀) to upgrade. 규칙7 (함수 호출) setPlan(␀0␀) → segments[1] 남은 텍스트: Use ␀1␀ to upgrade. ⚠ segments[1] 안에 ␀0␀ 이 들어 있다 — 봉인표가 봉인표를 감쌌다 1회 복원 Use setPlan(␀0␀) to upgrade. ← 안쪽 봉인표가 그대로 노출 2회 복원 Use setPlan(STARTER/BUSINESS) to upgrade. ← 원문 복원 ```
코드 설명. 경로 규칙이 먼저 `STARTER/BUSINESS`를 삼켜 봉인표로 바꾼다. 그러자 남은 텍스트에
setPlan(␀0␀)라는 함수 호출 모양이 새로 생긴다. 뒤이어 도는 함수 호출 규칙이 이걸 통째로 삼키면서, 0번 봉인표를 품은 채 1번 봉인표로 저장된다. 이게 중첩이다. 이때 복원을 한 번만 돌리면 겉껍질만 벗겨져setPlan(␀0␀)이 그대로 출력에 남는다. 코드 안에 NUL 바이트와 숫자가 박힌 채로 파일이 저장되는 것이다 — 무손실을 지키려던 장치가 오히려 코드를 망가뜨린다. 그래서 복원은 남은 봉인표가 없을 때까지 반복한다.반복 횟수의 상한은 8번으로 박혀 있는데, 그 근거가 깔끔하다. 반복이 필요한 횟수는 중첩 깊이에만 비례하고 입력 크기와는 무관하다. 그리고 중첩 깊이는 아무리 깊어도 보호 규칙 개수(8개)를 넘을 수 없다 — 한 규칙은 한 번만 돌기 때문이다. 그러니 8번이면 어떤 현실 입력도 완전히 풀리고, 동시에 비정상 입력이 무한 루프로 끌고 가는 것도 막힌다. 상한이 넉넉해서 안전한 게 아니라, 구조적으로 8을 넘길 수 없어서 안전하다.
봉인표를 왜 하필 NUL 바이트로 감쌌는지도 여기서 이해된다. 만약 봉인표가 그냥 공백에 둘러싸인 숫자였다면, 산문에 원래 있던 평범한 숫자와 구별되지 않는다. "repeat 1 time for the retry" 같은 문장의 `1`이 복원 단계에서 1번 코드 조각으로 치환되는 사고가 난다. NUL 바이트는 정상적인 마크다운 문서에 절대 나타나지 않으므로 충돌이 원천 차단된다. 봉인표 자체도 산문과 오탐 없이 구별될 수 있어야 한다는 것 — 이 글의 주제가 여기서 한 번 더 반복된다.
정리 — 지킬 수 있는 것과 지킬 수 없는 것
같은 저장소의 두 도구가 같은 문제에 정반대로 답했다. 하나는 LLM에게 맡기고 결정론적 검증기로 되돌리고, 다른 하나는 코드를 텍스트에서 들어내 압축기가 볼 수 없게 만든다. 후자가 우월해 보이지만 공짜는 아니다 — 봉인은 정규식으로 "코드처럼 생긴 것"을 미리 다 찾아낼 수 있을 때만 성립하고, 그러지 못한 문서에서는 압축률을 잃는다. 전자는 LLM의 판단력을 빌려 더 과감하게 줄이는 대신, 그 대가로 검증기를 지고 간다.
그리고 두 도구를 나란히 놓아야만 보이는 사실이 있다. 경로는 봉인할 수는 있어도 검증할 수는 없다. 같은 조잡한 정규식인데, 사전 봉인에 쓰면 오탐의 대가가 "덜 줄어듦"이고 사후 검증에 쓰면 "정상 압축이 죽음"이기 때문이다. 무엇을 무손실로 지킬 수 있는지는 그 조각을 얼마나 지키고 싶은지가 아니라, 그 조각을 오탐 없이 식별할 수 있는지, 그리고 오탐했을 때 무엇을 잃는지가 정한다.
이건 압축만의 이야기가 아니다. LLM에게 무언가를 맡길 때 "제발 잘해 줘"라는 프롬프트 뒤에 기계가 판정하는 안전망을 한 겹 두는 것 — 그리고 그 안전망을 압축기의 앞에 놓을지 뒤에 놓을지(압축기에게 건네는 입력에서 코드를 미리 들어낼 것인가, 압축기가 내놓은 출력을 원본과 대조할 것인가)를 오탐의 비용으로 따져 정하는 것. 개인 작업에 AI를 깊게 들일수록, 나는 이 두 질문을 자꾸 다시 꺼내 쓰게 된다.
마지막으로 층위 하나만 다시 짚고 끝내자. 이 글에는 "입력"과 "출력"이 두 겹으로 나온다. 바깥 층에서는 에이전트가 읽는 입력(메모리 파일과 MCP 도구 설명)이 압축의 대상이고, 안쪽 층에서는 압축기 자신의 입력과 출력이 안전망을 놓을 두 후보 자리다. 봉인은 압축기의 입력을 손보고, 검증은 압축기의 출력을 대조한다. 그렇게 다듬어진 결과물이 다시 바깥 층으로 나가 에이전트의 입력이 된다. 헷갈리기 쉬운 자리라, 두 층을 분리해 읽으면 이 글의 구조가 한눈에 잡힌다.
참고한 공개 자료:
- Model Context Protocol 명세: https://modelcontextprotocol.io/
- Anthropic — Building effective agents: https://www.anthropic.com/research/building-effective-agents
- Lossless vs lossy compression 개요: https://en.wikipedia.org/wiki/Lossless_compression
- CommonMark 명세 (fenced code block 규칙): https://spec.commonmark.org/
이 글은 생성형 AI의 도움을 받아 작성되었습니다. 원본 자료를 기반으로 AI가 초안을 생성하고, 작성자가 검토·편집하였습니다.
'IT' 카테고리의 다른 글
에이전트 호출의 생명주기 — 왜 그냥 API 호출로는 안 되나 (0) 2026.08.02 에이전트는 서로를 어떻게 찾는가 — 발견, 그리고 에이전트의 '명함' (0) 2026.08.02 AI 에이전트의 두 개의 축 — 도구를 붙이는 일과 동료를 부르는 일은 다르다 (0) 2026.08.02 서브에이전트 출력 압축 — 토큰 절약의 잊힌 세 번째 축, 메인 컨텍스트 예산 (0) 2026.08.01 상주 컨텍스트를 한 번만 압축하면 — 매 세션 영구히 아끼는 입력 토큰 (0) 2026.08.01 축약어는 토큰을 아끼지 못한다 — caveman의 규칙 (0) 2026.07.31 AI 코딩 에이전트의 토큰 절약 — 뇌가 아니라 입을 줄인다 (0) 2026.07.31 자율 에이전트인가, 통제된 하네스인가 — LLM을 부리는 두 가지 모델 (0) 2026.07.30 AI 시스템 테스트, 무엇을 가짜로 두고 무엇을 진짜로 돌릴까 — mock 경계 원칙 (0) 2026.07.29 채점자도 AI라면 — LLM-as-judge로 답변 품질을 자동 평가할 때 빠지는 함정 (0) 2026.07.29