3줄 요약
- AI가 지어낸 통계는 값이 틀린 수치가 아니라 원문 대조가 불가능한 수치다. 2026-08-16 ai-edu 12편 감사에서 잡힌 형태는 두 가지였다. 같은 숫자가 서로 다른 주장 세 곳에 쓰였고, 같은 출처가 편마다 다른 값으로 인용됐다.
- 한 편만 읽어서는 안 보인다. 결함이 문장 안이 아니라 문장들 사이에 있어서, 발행본 전체를 모아 출처 문자열로 그룹핑해야 드러난다.
- 잡힌 문장은 값을 고치는 것이 아니라 지운다. 세 값 중 어느 것이 맞는지 확인할 방법이 없기 때문이다.
| 질문 | 답 |
|---|---|
| AI가 지어낸 통계는 어떤 형태로 남는가 | 같은 숫자가 다른 주장 여러 곳에 재사용되거나, 같은 출처가 편마다 다른 값으로 인용된다 |
| 한 편만 읽어서 찾을 수 있는가 | 찾기 어렵다. 편들 사이의 불일치라 전체를 모아 그룹핑해야 보인다 |
| 무엇으로 탐지하는가 | 발행본 내려받기(scripts/publish/aiedu_export.py) + 수치·출처 정규식 그룹핑 + 품질 게이트(scripts/publish/cc_quality_gate.py) |
| 의심과 확정을 가르는 기준은 | 한 출처에 값이 2개 이상이면 대조 대상, 한 값이 서로 다른 주장 2곳 이상에 붙어 있으면 재활용 의심 |
| 잡힌 문장은 어떻게 고치는가 | 치환 목록으로 삭제한다. new를 빈 문자열로 두면 삭제다 |
이 글대로 하면 무엇이 달라지는가 — AI가 써 준 글에 남아 있는 무출처 수치를 사람 눈이 아니라 명령 두 줄로 모아 볼 수 있고, 지워야 할 문장이 목록으로 나온다.
AI가 지어낸 통계는 어떤 형태로 남는가?
지어낸 통계란 값이 틀린 수치가 아니라 원문 대조가 불가능한 수치다. 그래서 값 자체를 노려보는 방식으로는 잡히지 않는다. 실제로 잡히는 지점은 재사용이다.
2026-08-16, 발행된 ai-edu 12편을 신선 컨텍스트 서브에이전트 2기에게 교차 감사시킨 결과에서 두 가지 형태가 나왔다. 첫째는 한 값이 여러 주장에 붙는 형태다. 한 해외 설문 지수의 "62%"라는 숫자가 응답 품질, 글쓰기 AI 사용률, 문서작업 방해라는 서로 다른 세 개의 주장에 같은 값으로 쓰여 있었다. 둘째는 한 출처가 여러 값을 갖는 형태다. "McKinsey 2023"이라는 같은 출처 표기가 세 편에서 각각 40%, 40~50%, 30~45%로 서로 다르게 인용됐다.
두 형태 모두 공통점이 하나 있다. 원문을 확인한 적이 없다는 것이다. 확인하지 않은 출처를 문장에 붙이면 생성 과정에서 출처는 장식이 되고, 장식은 재사용된다. 이 감사의 전체 결과와 채점 방식은 AI 2기에게 내 블로그 12편을 감사시킨 기록에 정리했다.
왜 한 편만 읽어서는 찾지 못하는가?
결함이 문장 안이 아니라 문장들 사이에 있기 때문이다. "한 조사에서 62%가 그렇다고 답했다"는 문장은 그 글 안에서 완결돼 보인다. 문법도 맞고 맥락도 맞다. 같은 62%가 옆 글에서 다른 주장에 붙어 있다는 사실은 그 글을 열어야 보인다.
사람이 이것을 발견하려면 12편을 동시에 기억해야 한다. 대신 기계가 하면 두 가지만 하면 된다. 문장에서 수치와 출처 표기를 함께 뽑고, 출처 문자열로 묶는 것이다. 묶고 나면 값이 갈리는 그룹과 주장이 갈리는 그룹이 그대로 보인다.
지어낸 통계를 어떤 절차로 탐지하는가?
4단계다. 3단계까지는 스크립트가 하고, 마지막 원문 대조만 사람이 한다.
- 발행본을 파일로 내려받는다. 데이터베이스에서 발행 상태의 글만 뽑아 글마다 한 파일로 쓰고, 목록을
index.json에 남긴다. 검사 도구가 데이터베이스를 직접 읽지 않게 하는 편이 토큰과 권한 양쪽에서 안전하다.
python -X utf8 scripts/publish/aiedu_export.py
실행하면 _poc/aiedu_fix/<id>-<slug>.html 파일들과 index.json이 생기고, 편마다 글자수와 슬러그가 한 줄로 찍힌다. 내려받은 결과가 0편이면 조회 조건(블로그 식별자, 발행 상태)부터 확인한다.
- 문장 단위로 수치와 출처를 함께 뽑는다. 아래 두 정규식은
scripts/publish/cc_quality_gate.py에서 그대로 가져온 것이다.NUM은 단위가 붙은 수치를,EVIDENCE는 그 수치에 근거 표지가 붙었는지를 본다.
NUM = re.compile(r"\d[\d,.]*\s*(%|퍼센트|배|건|편|개|초|분|시간|원|달러|토큰|자)")
EVIDENCE = re.compile(r"실측|측정|기준|20\d\d[-.]\d|n\s*=|전수|관측|scripts/|docs/|\.py|\.md|"
r"우리 환경|이 프로젝트")
- 출처 문자열로 그룹핑한다. 아래는 위 정규식과
scripts/publish/aiedu_apply_patch.py의 기관명 정규식을 묶어 돌리는 스크립트다. 출처별로 몇 개의 서로 다른 값이 붙어 있는지를 센다.
import collections, glob, re
ORG = re.compile(r"맥킨지|McKinsey|가트너|Gartner|하버드|Harvard|MIT|스탠퍼드|Stanford|"
r"딜로이트|Deloitte|포브스|Forbes|IDC|PwC|액센츄어|Accenture|"
r"Work Trend Index|AI Index")
NUM = re.compile(r"\d[\d,.]*\s*(%|퍼센트|배|건|편|개|초|분|시간|원|달러|토큰|자)")
groups = collections.defaultdict(list)
for path in glob.glob("_poc/aiedu_fix/*.html"):
text = open(path, encoding="utf-8").read()
for s in re.split(r"(?<=[.。!?])\s+|\n", text):
org, num = ORG.search(s), NUM.search(s)
if org and num:
groups[org.group(0)].append((path, num.group(0), s.strip()[:60]))
for src, hits in sorted(groups.items()):
values = sorted({v for _, v, _ in hits})
flag = "대조필요" if len(values) > 1 else "단일값"
print(f"{flag} {src:<20} 문장 {len(hits)} 값 {values}")
- 원문을 대조한다. 여기부터는 자동화되지 않는다. 그룹에 값이 두 개 이상이면 해당 보고서 원문을 찾아 어느 값이 맞는지 확인하고, 확인할 수 없으면 그 문장을 지운다.
의심과 확정은 무엇으로 가르는가?
세 개의 조건으로 가른다. 조건마다 다음 행동이 다르기 때문에 분리해 둘 값어치가 있다.
| 관측 | 판정 | 다음 행동 |
|---|---|---|
| 한 출처 그룹에 서로 다른 값이 2개 이상 | 대조 대상 | 원문 확인. 못 하면 문장 삭제 |
| 한 값이 서로 다른 주장 2곳 이상에 붙음 | 재활용 의심 | 값이 아니라 주장 쪽을 확인. 주장이 서로 무관하면 삭제 |
| 수치가 있는데 근거 표지가 없는 문장이 임계 초과 | 경고 | 사람이 읽고 판단. 발행은 막지 않는다 |
세 번째 임계는 고정값이 아니라 분량에 비례시킨다. scripts/publish/cc_quality_gate.py의 계산은 다음 한 줄이다.
limit = max(6, len(t) // 650)
임계를 고정하지 않는 이유는 이 검사가 문장 단위이기 때문이다. 근거 표지가 옆 문장에 있으면 그 문장은 무근거로 잡히고, 글이 길어질수록 그런 문장이 자연히 늘어난다. 고정 임계로 두면 깊이 쓴 글이 전부 경고를 달게 되어 경고 자체가 무의미해진다.
검사를 발행 전으로 옮기려면 무엇을 봐야 하는가?
발행 전 검사는 출처 그룹핑이 아니라 표현 검출로 바뀐다. 발행 전에는 대조할 다른 편이 아직 없기 때문에, "이 글이 남의 통계를 쓰고 있는가"만 본다. scripts/publish/cc_quality_gate.py는 이것을 오류로 처리해 발행을 막는다.
python -X utf8 scripts/publish/cc_quality_gate.py Blogs/claude-code/my-post.md
여기에 함정이 하나 있다. 지어낸 통계를 다루는 글은 그 통계 표현을 인용할 수밖에 없다는 것이다. 검사기가 인용부호 안과 밖을 구분하지 않으면, 정직한 글일수록 더 자주 걸리는 역설이 생긴다. 대응은 검사 대상 텍스트를 바꾸는 것이다. 금지 표현을 세기 전에 코드펜스, 인라인 백틱, 따옴표 안을 같은 길이의 공백으로 치환한 사본을 만들고 그 사본에서만 센다. 길이를 유지하는 이유는 뒤에 오는 위치 계산이 어긋나지 않게 하기 위해서다. 이 글에 기관명이 몇 개 들어 있으면서도 검사를 통과하는 이유가 그것이다.
손으로 점검할 때 쓰는 체크리스트로 옮기면 다음과 같다.
[ ] 본문의 수치마다 측정일·측정 방법·파일 경로 중 하나가 붙어 있는가
[ ] 확인하지 않은 외부 기관명이 인용부호 밖에 있는가
[ ] 같은 숫자가 이 글의 서로 다른 주장 두 곳에 쓰이지 않았는가
[ ] 기존 발행글과 같은 대상의 수치가 서로 다르지 않은가
[ ] 값을 확인할 수 없는 문장을 남겨 두지 않았는가
잡힌 문장은 어떻게 고치는가?
값을 고치지 않고 지운다. 여기서 오진이 한 번 났다. 처음 진단은 "인용된 값이 틀렸으니 맞는 값으로 바꾸면 된다"였다. 이 진단이 틀린 이유는 같은 출처가 세 편에서 40%, 40~50%, 30~45%로 갈렸다는 사실 자체에 있었다. 어느 값이 맞는지 판정하려면 원문이 필요한데, 원문을 확인한 적이 없어서 판정 기준이 없었다. 진짜 원인은 값의 오류가 아니라 출처의 부재였고, 부재에 대한 올바른 대응은 교정이 아니라 삭제였다.
수정은 글 전체를 다시 쓰지 않고 치환 목록으로만 한다. 목록 형식은 scripts/publish/aiedu_apply_patch.py가 받는 형태 그대로다.
{"id": 126, "slug": "example-slug",
"patches": [
{"old": "한 컨설팅 보고서에 따르면 40%가 개선됐다", "new": "", "why": "무출처 기관 통계"},
{"old": "설문 지수 62%가 이를 뒷받침한다", "new": "", "why": "같은 값이 다른 주장에 재사용됨"}
]}
적용 규칙은 두 줄이다. old는 원본에 정확히 1회 나타나야 하고, 0회이거나 2회 이상이면 그 항목만 실패로 기록하고 넘어간다. new가 빈 문자열이면 삭제다. "정확히 1회" 조건이 안전장치다. 여러 곳에 걸리는 문자열은 의도하지 않은 자리까지 바꾸므로 아예 적용하지 않는다.
적용 결과는 고쳤다는 보고가 아니라 숫자로 확인한다. 이 스크립트는 적용 전후로 기관 통계와 체험담 문형의 검출 수를 세어 같은 줄에 찍는다.
def scan(html):
return {"기관통계": len(ORG.findall(html)), "체험담": len(ANECDOTE.findall(html))}
먼저 반영 없이 결과만 본 다음 적용한다.
python -X utf8 scripts/publish/aiedu_apply_patch.py --dry
python -X utf8 scripts/publish/aiedu_apply_patch.py
여기서 한 번 걸린 함정은 줄바꿈이었다. 일부 글의 원본은 줄바꿈이 \r\r\n이었고, 파이썬이 파일을 텍스트 모드로 읽으면서 이를 \n\n으로 바꿔 놓았다. 그러면 원본을 보고 만든 old 문자열이 파일 안에서 0회로 잡혀 전부 실패한다. 대응은 패치 쪽 줄바꿈도 같은 규칙으로 정규화하는 것이다. 치환이 안 잡힌다는 실패가 나오면 문자열 내용보다 줄바꿈 표현을 먼저 의심하는 편이 빠르다.
이 탐지가 통하지 않는 경우는 언제인가?
정규식은 우리가 목록에 적어 둔 형태만 잡는다. 여기에 세 가지 한계가 있다.
첫째, 출처 표기가 없는 지어낸 통계는 그룹핑에 걸리지 않는다. "한 조사에 따르면 62%"처럼 기관명 없이 쓰면 ORG가 비어 그룹이 만들어지지 않는다. 이 빈틈은 근거 표지 검사가 2차 그물로 메우지만, 그쪽은 오류가 아니라 경고라서 발행을 막지 못한다.
둘째, 수치가 표 안에 있으면 문장 검사에서 빠진다. 근거 표지 검사는 |로 시작하는 줄을 제외하는데, 표의 셀을 문장으로 세면 거의 전부가 무근거로 잡히기 때문이다. 표에 든 수치는 사람이 본다.
셋째, 원문 대조 자체는 자동화되지 않는다. 4단계 중 3단계까지가 기계의 몫이고, 값이 갈린 그룹을 앞에 두고 무엇이 맞는지 정하는 일은 남는다. 그래서 이 절차의 산출물은 "이 글은 정확하다"가 아니라 "확인이 필요한 문장은 이것들이다"이다. 검사가 통과했다는 말은 결함이 없다는 뜻이 아니라 우리가 아는 형태의 결함이 없다는 뜻이다.
같은 이유로 검사기 쪽 결함도 남는다. 조판 규칙을 기계로 검사할 때 생기는 오탐과 그 대응은 스타일 블록 하나가 페이지 문서 전체를 오염시킨 이유에, 검사를 사람이 아니라 별도 세션의 에이전트에게 맡길 때의 설계는 교차 감사 하네스에 정리했다.
자주 묻는 질문
Q. AI가 지어낸 통계는 어떤 형태로 드러나는가?
A. 같은 숫자가 서로 다른 주장 여러 곳에 재사용되거나, 같은 출처 표기가 편마다 다른 값으로 인용되는 형태다. 2026-08-16 ai-edu 12편 감사에서 두 형태가 모두 나왔다.
Q. 글 한 편만 읽어서 지어낸 통계를 찾을 수 있는가?
A. 찾기 어렵다. 결함이 문장 안이 아니라 문장들 사이에 있어서, 발행본 전체를 내려받아 출처 문자열로 묶은 뒤에야 값이 갈리는 그룹이 보인다.
Q. 잡힌 수치는 맞는 값으로 고치면 되지 않는가?
A. 원문을 확인한 적이 없으면 어느 값이 맞는지 판정할 기준이 없다. 같은 출처가 세 편에서 40%, 40~50%, 30~45%로 갈렸던 사례가 그 예이고, 이때 올바른 대응은 교정이 아니라 문장 삭제다.
Q. 근거 표지 없는 수치 문장의 임계를 왜 고정하지 않는가?
A. 이 검사는 문장 단위라서 근거 표지가 옆 문장에 있으면 그 문장이 무근거로 잡힌다. 글이 길어질수록 그런 문장이 늘기 때문에 max(6, len(t) // 650)처럼 분량에 비례시킨다.
Q. 지어낸 통계를 다루는 글이 검사기에 걸리지 않게 하려면 어떻게 하는가?
A. 검사기가 코드펜스, 인라인 백틱, 따옴표 안을 같은 길이의 공백으로 치환한 사본에서만 금지 표현을 세도록 만든다. 결함을 설명하는 글은 그 표현을 인용할 수밖에 없기 때문이다.
Comments
Comments (0)
Leave a Comment