Skip to content

kimsh-1/gn-voice

Repository files navigation

gn-voice

gn-voice

AI가 쓴 한국어 초안을 한 사람의 실제 문체로 재작성하는 Claude Code 스킬입니다. 문체를 느낌이 아니라 측정값으로 다루죠


1. 상용 윤문 도구가 마음에 들지 않았습니다

이유는 단순합니다. 그 도구들이 내놓는 글이 제가 쓰는 방식이 아니었거든요.

문법도 맞고 흐름도 매끄러운데 읽으면 어딘가 불쾌하고, 몸에 안 맞는 옷 같았습니다. 사실 당연한 일이죠. 윤문 도구는 글을 좋은 글의 평균으로 끌고 가는데, 제 글은 원래 그 평균에 없거든요. 마침표를 안 찍고 끝내는 문장이 있고, 문장 중간에서 줄을 바꾸는 버릇이 있고, 진지한 존댓말로 가다가 갑자기 반말 한 줄을 툭 떨어뜨리죠. 도구가 다듬을수록 이런 게 지워지고, 지워질수록 제 글이 아니게 됩니다

필요한 건 교정이 아니라 복제였습니다. 그래서 직접 만들었죠

2. 내 글만 분석하면 되지 않을까

출발은 데이터였습니다. 그동안 블로그랑 스레드에 발행해 온 글을 전부 긁어모아서 986편짜리 코퍼스를 만들었죠

다만 글을 모아서 LLM한테 "이렇게 써줘"라고 통째로 던지는 방식은 안 통합니다. 그렇게 하면 모델은 인상비평 수준으로 흉내만 내는데, 소재나 말투 몇 개 집어 오다가 결국 자기 몸에 밴 매끈한 문장으로 돌아가죠. 흉내가 아니라 복제를 하려면 "이 사람의 글은 정확히 어떻게 생겼나"라는 정량 근거가 필요했고, 그래서 형태소 분석(kiwipiepy, 세종 품사 태그셋)을 썼습니다

걱정이 하나 있었습니다. 한국어 형태소 분석은 어렵다는 평이 지배적이거든요. 교착어라 어미 변형이 폭발적으로 많고, 구어·비문·신조어까지 들어가면 범용 분석기가 자주 틀립니다. 그런데 뒤집어 보면 저는 전 국민의 한국어를 다룰 필요가 없죠. 분석 대상을 한 사람으로 좁히면 다뤄야 할 분포가 확 줄어듭니다. 한 사람이 쓰는 어미 종류는 한정돼 있고, 문장을 흐트러뜨리는 방식도 일정하고, 버릇은 장르 안에서 반복됩니다. 그 좁은 분포 안에서라면 형태소 계측이 충분히 정확해지고, 뽑아낸 패턴을 따라 쓰게 만드는 것도 가능하지 않을까. 이 가설로 시작했습니다

실제로 재보니 패턴은 생각보다 완고했습니다.

  • "알아보겠습니다"라는 표현은 1,075편에서 한 번도 안 나왔습니다. 반면 AI 초안에는 흔하게 등장하는데, 이런 표현만 모아도 훌륭한 판별기가 됩니다(references/ai-tells.json)
  • 답글 612편에서 쉼표 사용의 중앙값은 0이었습니다. 저는 답글에 쉼표를 거의 안 찍거든요
  • 문장이 끝나기 전에 줄을 바꾸는 비율은 장르마다 다르지만, 같은 장르 안에서는 일정한 범위로 반복됩니다

이런 측정값을 장르×채널 23개 셀로 쪼개서 지문(fingerprint) 파일로 저장했습니다. 그리고 셀마다 "이 장르에서 이 사람은 어떤 어미로 끝내고, 어디서 줄을 바꾸고, 무엇을 절대 안 쓰는가"를 70줄 안쪽으로 증류한 장르 팩을 만들었죠. 본인 코퍼스에 근거한 개인 장르 팩 9종(답글·스레드 잡담·단문 팁·홍보·비즈 메모·강의·비즈 설명·에세이·칼럼)에, 특정인 문체가 아니라 장르 규범을 정리한 웰메이드 팩 6종(연설문·설명문·논설문·판매 카피·바이럴 포스트·명수필)을 더하면 총 15종입니다. 어느 팩을 적용할지는 화계 비율·자기지칭 밀도·글자수를 읽는 결정 트리(references/voice-core.md)가 정하고요

3. 코퍼스는 어떻게 쌓았나

글 986편을 모았다고 하면 뭔가 대단한 데이터베이스가 돌아갈 것 같죠. 근데 실제로는 정반대라, 저장 방식은 일부러 제일 단순한 걸 골랐거든요.

전부 그냥 텍스트 파일입니다 글 한 편이 파일 하나고 벡터 DB도 검색 엔진도 없다. 이 데이터를 읽는 게 사람이 아니라 AI라서, 파일을 바로 열어 읽는 쪽이 제일 빠르고 정확하거든요. 웹에서 긁어온 글에는 꾸미기 코드(HTML)가 잔뜩 붙어 오는데, 이건 저장하기 전에 전부 벗겨내고 글만 남긴다. 용량만 차지하지 문체 정보는 한 톨도 없으니까요.

그렇다고 아무 글이나 넣진 않습니다 모은 건 전부 1,193편인데 실제로 분석에 쓰는 건 986편이다. 넣기 전에 두 가지를 보는데, 이 글을 정말 처음부터 끝까지 내 손으로 썼는가, 그리고 내 문체가 제대로 드러나는가. 특히 AI 도움을 받아 쓴 글은 무조건 걸러내는데, AI가 섞인 글로 "AI 티를 지우는 기준"을 만들면 그 기준 자체가 오염되거든요. 이 판정은 모델 하나한테 안 맡기고, 여러 모델이 따로따로 매긴 다음 서로 어긋나면 다시 판정하죠. 어떤 글이 어떤 판정을 받았고 어디에 쓰이는지는 목록 파일(manifest) 한 곳에 전부 적힙니다.

일부는 시험용으로 아예 봉해 둡니다 문제집으로 공부하고 나서 똑같은 문제로 시험을 보면 이해한 건지 외운 건지 구분이 안 되죠. 그래서 편입한 글의 15%를 미리 떼어서 봉해 두고, 문체 규칙을 만들 때는 절대 안 봅니다. 이 글들은 오직 "새 글도 잘 복제하는가", 이거 하나 확인하는 시험에만 쓴다.

수치는 전부 자동으로 나옵니다 분석 스크립트가 코퍼스 전체를 훑어서 통계표(fingerprint)를 만들고, 실시간 검증에 필요한 부분만 뽑은 요약본을 따로 둡니다. 장르 팩에 적힌 수치요? 전부 이 통계표에서 나온 거고, 손으로 적어 넣은 숫자는 하나도 없다. 글이 추가되면 스크립트를 다시 돌리는 걸로 끝이다.

장부가 어긋나면 기계가 잡습니다 목록에는 있는데 파일이 없거나, 같은 글이 두 번 들어갔거나, 시험용 글이 학습에 새어 든 경우, 이런 걸 전수로 점검하는 테스트가 있거든요. 코퍼스가 아무리 커져도 이 검사 덕에 장부랑 실물이 어긋날 일은 없죠

4. 하나로 만들면 사고가 납니다, 그래서 셋으로 나눴습니다

처음엔 에이전트 하나가 다 하는 구조를 생각했습니다. 만들어 보니 성격이 다른 문제 세 개가 한 자리에서 충돌하더군요. 결국 역할을 셋으로 갈랐습니다

러너 · 재작성 담당. 첫 번째 문제는 규칙의 양입니다. 팩 15종에 전체 규칙을 전부 읽히면 토큰만 낭비되는 게 아니라 규칙끼리 서로를 희석하는데, 답글 하나 쓰는데 장문 강의 규칙이 어른거리는 식이죠. 그래서 러너는 먼저 입력 글의 장르를 판별하고 그 장르의 슬림 팩 하나만 읽어서 단일 호출로 재작성합니다. 명제 내용(사실·수치·고유명사·주장)은 한 글자도 못 바꾸게 체크리스트로 묶어 두고요

게이트 · 기계 검증 담당. 두 번째 문제는 채점의 순환입니다. LLM이 쓴 글을 LLM이 채점하면 서로 후한 점수를 주니까, 검증은 LLM이 아니라 파이썬 스크립트가 합니다. verify_style.py가 결과물의 어미 분포·구두점 밀도·개행 리듬을 실측 지문의 허용 밴드와 대조하고, 금칙어 사전(ai-tells.json)까지 검사합니다. 이 검사엔 하한선도 있어서 문장 길이가 실측보다 지나치게 고른, 그러니까 "너무 매끈한" 글은 통과를 못 합니다. gate_fidelity.py는 원문이랑 결과물의 수치·고유명사를 전수 대조해서 변조와 누락과 날조를 잡아내는데, 여기엔 주관이 없죠. 밴드를 벗어나면 어느 항목이 얼마나 벗어났는지 숫자로 돌려주고, 러너는 그 항목만 겨냥해 한 번 더 고칩니다

심사관 · 품질 판정 담당. 세 번째 문제는 통계의 사각지대입니다. 모든 밴드를 통과했는데 읽어 보면 어색한 글이 있거든요. 통계는 분포를 보지 문장 하나의 어색함은 못 보죠, 그래서 마지막에 심사 에이전트가 결과물을 팩 기준과 대조해 A~D 등급을 매깁니다. 위반이 있으면 결과물에서 그 구절을 실제로 인용해 어떤 규칙에 걸렸는지 짚고, C 등급이면 러너한테 그대로 넘길 수 있는 문장 단위 재작업 지시문을 냅니다

세 역할을 모두 지나온 글만 최종본이 됩니다. 자체 평가에서는 서로 다른 장르 실주행 10회가 전부 수동 수정 없이 A 아니면 B 등급을 받았습니다.

5. 한계도 있습니다

숨길 이유가 없으니 그대로 적습니다.

AI 감별 모델은 여전히 안 속습니다. 개선을 3사이클 돌린 뒤에도 감별 LLM은 약 90%를 잡아냈거든요. 이 스킬의 목표는 기계 감별 회피가 아니라 사람 독자가 읽었을 때 원저자의 글로 느껴지는 거고, 이 구분은 중요해서 문서로 따로 남겨 뒀습니다

표본이 적은 장르는 정밀도가 떨어집니다. 홍보문처럼 원본이 13편뿐인 셀은 수치를 강제 기준이 아니라 방향 지표로만 쓰고, 팩에도 그렇게 적어 뒀습니다

마지막 판단은 사람 몫입니다. 게이트와 심사를 통과한 글도 올리기 전엔 글 주인이 한 번 읽는다는 걸 전제로 설계했습니다

6. 여러분의 글로도 됩니다

이 저장소는 특정인 문체의 사본이 아니라 글이 쌓여 있는 사람이라면 누구의 문체든 복제할 수 있는 파이프라인입니다. corpus/를 여러분의 글로 갈아 끼우면 같은 구조가 새 문체로 재구축되죠

# 1) corpus/ 를 본인의 글로 교체 (1편 = 1개 마크다운)
python scripts/fingerprint.py --corpus gn   # 2) 지문 재계산
python scripts/make_slim.py                 # 3) 런타임 검증 밴드 재생성
# 4) references/packs/ 의 팩을 템플릿 삼아 새 실측값으로 재증류
#    (LLM에게 "fingerprint 실측값으로 팩을 다시 써라"라고 맡겨도 됩니다)

한 가지만 지켜 주십시오. 코퍼스에는 반드시 본인 저작물만 넣으셔야 합니다. 남의 책·기사·게시물을 넣어서 그 문체를 복제하는 건 저작권 침해라 금합니다.

설치와 사용

git clone https://github.com/kimsh-1/gn-voice.git
cd gn-voice && bash install.sh   # 스킬·에이전트를 ~/.claude 아래에 연결

사용은 Claude Code 대화에서 자연어로 합니다. 글을 붙여 넣고 문체 변환을 요청하면 rewrite 모드(내용 보존, 문체만 교체)가 돌고, 아이디어를 주고 집필을 요청하면 compose 모드(아이디어를 재료로 집필)가 돕니다. 장르는 --style, 문체 주입 강도는 --wash(L0 최소 ~ L3 최대), 표현 장치 수위는 --clean으로 조절하고요

저장소 지도

SKILL.md                  스킬 본체 (파이프라인 정의)
agents/                   러너 · 작가 · 심사관 에이전트 3종
references/voice-core.md  장르 판별 트리 + 공통 문체 DNA
references/packs/         장르 팩 15종 (개인 9 + 웰메이드 6)
references/ai-tells.json  AI 상투구 금칙어 사전 (실측 기반)
corpus/                   원저자 공개 저작물 코퍼스
analysis/quant/           지문 계산 결과 (23셀 fingerprint)
style-profile/            3축 분류 기준 문서
scripts/                  fingerprint.py · make_slim.py 등 재현 도구
examples/                 AI 초안 → 최종본 완성 예시 + 검증 보고서

출처와 저작권

corpus/와 개인 장르 팩에 인용된 글은 모두 원저자 본인의 공개 저작물입니다. 외부 저작물 원문은 하나도 안 들어 있고, 공개판 빌드 때 지문 프로브 검사로 이걸 기계 검증하죠. 명수필 팩(wm-prose)의 인용문은 이효석, 이상, 김유정 등 1926~1943년 사이에 작고한 저자들의 글이라, 저작권 보호 기간이 만료된 퍼블릭 도메인 저작물입니다.

About

AI 한국어 초안을 개인 문체로 재작성하는 Claude Code 스킬 — 3축 분류·코퍼스 실측 접지·결정론 검증 게이트

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors