
AI에게 기사를 쓰게 했더니, 품질 체크 측이 단조로운 문장을 권장하고 있었다
요약
AI 생성 콘텐츠의 품질을 검증하기 위해 문장 린트(Lint) 규칙을 설계할 때 발생하는 오류를 다룹니다. 가독성과 같은 주관적 품질을 단락 길이와 같은 수치로 대체할 때 발생하는 왜곡과, 이를 방지하기 위해 실제 사례로부터 기준을 역산해야 함을 강조합니다.
핵심 포인트
- 주관적 품질(가독성)을 수치로 대체할 때 발생하는 데이터 왜곡 주의
- 검사 메커니즘은 좋은 예와 나쁜 예 모두로 테스트되어야 함
- 임계값 설정 시 감각이 아닌 실제 양질의 사례로부터 역산 필요
기술 기사를 지속적으로 내고 싶지만, 한 편을 쓰는 데 몇 시간이 걸립니다. 그래서 초안은 AI에게 맡기기로 했습니다.
하지만 AI가 쓴 문장은 그대로 내보낼 수 없습니다. 매번 문체가 바뀌기도 하고, 그대로 두면 어디선가 읽은 듯한 무난한 원고가 됩니다. 그렇다고 매번 제가 전부 읽고 수정한다면, AI에게 쓰게 만든 의미가 절반으로 줄어듭니다.
그래서 자신이 과거에 써서 반응이 좋았던 기사에서 문체 규칙을 추출하고, 그중 기계로 판정할 수 있는 것들만 스크립트로 만들었습니다. 1인칭은 무엇을 사용할지, 독자에게 말을 걸지 말 것, 1단락은 몇 문장까지인지, AI가 자주 사용하는 마무리 관용구를 넣지 말 것, 필요한 헤드라인(見出し)이 갖춰져 있는지, 분량이 범위 안에 들어오는지. 원고가 돌아오면 우선 이것을 통과시킨 후 읽는 방식입니다.
어느 날, 돌아온 원고가 **경고 제로(警告ゼロ)**로 통과했습니다. 내용을 읽어봐도 사실관계에 이상한 점은 없습니다.
그럼에도 불구하고, 그 원고는 반려되었습니다. 이유는 단 한 마디였습니다.
문면이 단조롭다. 불렛 포인트(箇条書き)처럼 되어 있다.
「전부 초록색인데, 왜 읽을 수 없는 걸까」
다시 살펴보니 거의 모든 단락이 1문장뿐이었고, 짧은 문장이 같은 어조로 위에서 아래까지 이어지고 있었습니다. 품질을 지키기 위해 준비했던 검사는 이 부자연스러움을 단 한 번도 경고하지 않았습니다.
원인을 추적해 보니, 검사하는 측이 망가져 있었다는 것을 알게 되었습니다. 게다가 고치려고 시도하면서, 이번에는 '좋은 기사'를 탈락시키는 기준을 추가할 뻔했습니다.
이 기사에서 말하고 싶은 것은, 그 끝에서 도달한 한 가지 점입니다. 가독성(読みやすさ)처럼 사람이 감각으로 판단하는 품질을 기계에게 측정하게 하려면, 임계값(閾値)을 즉흥적으로 결정해서는 안 됩니다. 좋다고 여겨지는 실물을 측정하여, 거기서부터 역산해야 합니다. 그렇게 하지 않으면, 검사는 바람직한 글쓰기 방식을 위반으로 간주하여 걸러내기 시작합니다.
이 기사에서 알 수 있는 것
- 주관적인 품질 기준을 감각이 아닌 수중에 있는 실례로부터 결정하는 절차를 알 수 있습니다.
- 일본어 글자 수를 바이트(Byte) 수로 측정하면 문장의 품질 기준이 어떻게 망가지는지 재현할 수 있습니다.
- 생성물을 검사하는 메커니즘 자체를 좋은 예와 나쁜 예 모두로 테스트해야 하는 이유를 알 수 있습니다.
이 검사에서 무엇을 측정하고 있었는가
조금 더 구체적으로 쓰겠습니다. 규칙 중에는 기계로 측정할 수 있는 것과 측정할 수 없는 것이 있었습니다.
측정할 수 있는 것은 쉽습니다. 관용구가 포함되어 있는지는 문자열을 찾으면 되고, 헤드라인의 유무나 분량도 셀 수 있습니다. 문제는 「가독성」입니다. 이것은 사람이 읽고 판단하던 부분이라 그대로는 조건이 되지 않습니다. 그래서 가독성 대신이 될 만한 숫자로 단락의 길이를 선택했습니다. 너무 긴 단락은 너무 많은 내용을 담고 있어 읽기 어렵다는 경험칙입니다.
오해하지 않으셨으면 하는 점은, AI에게 세세한 규칙을 전달하는 방법 자체가 나빴다고는 생각하지 않는다는 것입니다. 신경 쓰였던 점은, 측정할 수 없는 것을 다른 숫자로 대용했을 때, 그 숫자가 정말로 원래의 품질을 나타내고 있는가 하는 점이었습니다. 이번에는 그 지점에서 발목을 잡혔습니다.
이 기사에서 다루지 않는 범위
여기서는 모델 자체의 성능 비교나 프롬프트(Prompt) 작성법 전반에 대해서는 다루지 않습니다. 대상은 문장 lint 설계와 그 기준을 실제 문장으로부터 어떻게 결정하는지에 집중합니다.
경고 제로인데, 거의 전부가 1문장 단락이었다
돌아온 원고는 준비해 두었던 검사를 경고 제로로 통과했습니다. 내용에도 사실상의 오류는 없었으며, 표면상으로는 꽤 깔끔한 합격 결과로 보였습니다.
그런데 실제로 읽어보니, 짧게 끊긴 단락이 위에서 아래까지 거의 같은 어조로 나열되어 있습니다. 하나하나의 문장은 이상하지 않은데, 기사 전체로는 불렛 포인트를 세로로 늘려놓은 듯한 느낌이 남았습니다.
AI는 이 지시를 무시했던 걸까요? 처음에는 그렇게 생각했지만, 여기에는 조금 복잡한 사정이 있었습니다.
우리가 전달한 문장 규칙에는 「1단락은 2~4문장」과 「짧은 단락을 의도적으로 섞을 것」이 모두 적혀 있었습니다. AI는 후자를 무시한 것이 아니라, 거의 모든 단락에 적용한다는 묘한 방식으로 지켰던 것입니다.
——규칙을 따르지 않은 것이 아니라, 따르는 방식이 망가져 있었던 것입니다.
모델을 바꿔도 36%에서 42%로 악화되었다
그래서 처음에 의심한 것은 문장을 쓰게 하는 모델과의 상성이었습니다. 코딩 특화 모델을 범용 모델로 바꾸고, 완전히 동일한 소재로 다시 한번 원고를 쓰게 했습니다.
그런데 1문장으로 끝나는 단락의 비율은 36%에서 42%로 늘어났습니다. 읽는 맛을 고치기 위해 모델을 바꿨는데, 숫자만 보면 오히려 악화되었습니다.
여기서 비로소 쓰는 쪽이 아니라 「합격을 내보내고 있는 쪽」을 의심하게 되었습니다.
「160자」를 의도했지만, 160바이트를 측정하고 있었다
검사 스크립트(Inspection script)에서는 단락이 너무 길어지지 않았는지도 확인하고 있었습니다. 평균 길이가 160을 초과하면 "글자 수가 너무 많다"라는 취지의 경고를 내보내는 구조였습니다.
문제는 그 160이 정말로 "160자"인가 하는 점이었습니다. 확인해 보니, 사용 중이던 awk의 length()가 세고 있었던 것은 이 환경에서 글자 수가 아니라 바이트(Byte) 수였습니다.
이 차이는 일본어를 딱 5글자만 입력해 보면 바로 재현할 수 있습니다. 실제로 무엇을 측정하고 있는지 확인하기 위해, あいうえお의 길이를 그대로 표시해 보겠습니다.
printf 'あいうえお\n' | awk '{print length($0)}'
15
겉보기에는 5글자인데, 결과는 15가 되었습니다. UTF-8 방식의 일본어는 1글자가 3바이트이므로, 5글자라면 15바이트로 계산됩니다.
즉, 경고문에서는 "160자"라고 부르던 임계값(Threshold)이 실제로는 160바이트가 되어 있었습니다. 일본어라면 대략 53글자를 넘어서는 시점부터 너무 긴 단락으로 취급되어 버립니다. 여기서 곤란한 점은 직접 작성한 문장 규칙과의 관계입니다. 그 규칙에서는 60~120자 정도의 단락을 권장하고 있는데, 그 길이에 맞춰 글을 쓰는 순간 lint 측에서는 경고 대상이 되고 있었습니다.
문장 규칙과, 문장을 지키기 위한 검사가 서로 반대되는 것을 요구하고 있었습니다.
글자 수로 다시 측정하기
이번 용도에서는 UTF-8의 연속 바이트(Continuation byte)인 0x80 ~ 0xBF를 제거한 뒤 길이를 측정했습니다. 선두 바이트만 남기면 이번에 다루는 문자열에서는 글자 수로 계산할 수 있기 때문입니다. 아까와 같은 あいうえお를 사용하여, 이번에는 연속 바이트를 제거한 뒤 length()를 호출합니다. 동일한 입력으로 결과를 비교한 것은 수정 전후의 차이를 그 자리에서 확인하고 싶었기 때문입니다.
printf 'あいうえお\n' | awk '{s=$0; gsub(/[\200-\277]/ stuck,"",s); print length(s)}'
5
이번에는 기대했던 5가 반환되었습니다. 적어도 이번 검사에서는 "160자"라고 쓰면서 160바이트를 측정하던 불일치를 여기서 해소할 수 있습니다.
단락 단위로 집계하고 싶다면, awk의 레코드 구분자(Record separator)에 RS=""를 지정하는 방법도 사용할 수 있습니다. 빈 줄로 구분된 덩어리를 하나의 레코드로 취급할 수 있어 단락의 길이를 측정하기 쉬워집니다.
lint는 긴 문장만을 꾸짖고 있었다
바이트와 글자를 혼동했다는 점뿐이라면 임계값을 수정하면 끝날 문제처럼 보입니다. 그런데 검사 조건을 다시 읽어보니, 문장을 단조롭게 만드는 방향으로 작동하는 메커니즘이 하나 더 있었습니다.
당시의 lint는 "단락이 너무 긴" 경우에만 경고를 보냈고, 너무 짧은 쪽에는 아무런 조건이 없었습니다. 모든 단락을 한 문장씩 잘게 나누면 길이 경고는 쉽게 피할 수 있습니다. AI 입장에서 보면, 길게 쓰면 경고를 받고 짧게 끊어 쓰면 아무 말도 듣지 않는 구조입니다. ——검사 그 자체가 짧은 단락을 대량으로 만드는 방향으로 생성물을 밀어붙이고 있었던 셈입니다.
여기서 단순히 "한 문장 단락을 줄이면 된다"라고 생각했습니다. 한 문장뿐인 단락이 4할을 넘으면 경고하는 조건이라면, 이번의 단조로움을 기계로도 잡아낼 수 있을 것처럼 보였습니다.
다만, 이번에는 규칙을 추가하기 전에 과거의 기사들을 실제로 측정해 보기로 했습니다.
좋은 기사를 측정했더니 예상과 반대였다
본보기로 삼았던 기사 A~D와 이번에 반려된 원고를 동일한 방법으로 계측했습니다. 나아가 이전부터 "AI가 쓴 것처럼 보인다"라고 지적받던 오래된 기사도 비교 대상으로 추가했습니다.
결과는 처음에 생각했던 "한 문장 단락이 많을수록 단조롭다"라는 가설을 상당히 깔끔하게 무너뜨렸습니다. 감각으로 임계값을 정하기 전에 측정해 본 덕분에, 하마터면 추가할 뻔했던 또 다른 오판을 알아챌 수 있었습니다.
| 기사 | 단락 평균 글자 수 | 표준 편차 | 120자 이상 단락 | 한 문장 단락 |
|---|---|---|---|---|
| 본보기 기사 A | 60.5 | 32.8 | 7% | 51% |
| ... |
의외였던 점은 본보기 기사 A에서는 한 문장 단락이 51%, 기사 C에서는 56%나 되었다는 것입니다. "4할을 넘으면 경고"라는 규칙을 그대로 적용했다면, 좋다고 판단했던 기사까지 탈락시켰을 것입니다.
그렇다면 사람이 "단조롭다"라고 느낀 원고와 본보기 기사를 구분 짓던 숫자는 무엇이었을까요?
차이는 짧은 단락이 아니라, 장단(長短)의 낙차에 있었다
표를 살펴보니 눈에 띄었던 것은 '120자 이상의 단락'의 비율이었습니다. 모범 사례 4개에서는 약 7~25% 정도가 혼재된 반면, 반려된 원고는 1%에 불과했고, 오래된 기사는 0%였습니다. 모범 기사에도 한 문장으로 끝나는 짧은 단락이 상당히 많습니다. 하지만 그 사이에 설명을 충분히 담은 긴 단락이 들어가 있어, 짧은 부분과의 낙차가 생겨나 있었습니다.
짧은 단락 자체가 나쁜 것이 아니라, 짧은 단락만 존재하는 것이 문제였다고 생각합니다.
이는 글을 읽었을 때의 감각과도 일치했습니다. 짧은 한 문장을 배치할 곳이 있기 때문에, 그 전후에 있는 긴 설명과의 차이가 생겨나며 글의 리듬으로 느껴집니다.
반대로 모든 것을 같은 길이로 맞추면, 단락 하나하나에는 읽기 쉽지만 전체적으로는 평평해집니다. 품질을 수치화할 때 평균값만으로는 이 '변동성(揺れ)'을 포착하기 어렵다는 것도 알게 되었습니다.
기준을 바꾸자 사람의 평가와 기계 판정이 일치했다
그래서, 한 문장 단락의 비율만을 문제 삼는 안은 접었습니다. 대신, 120자 이상의 단락이 적절하게 혼재되어 있는지라는 방향에서 글의 장단(長短)을 보게 되었습니다.
지표를 바꿔서 같은 기사군을 다시 측정해 보니, 모범 사례였던 A~D는 경고가 뜨지 않았습니다. 반면, 반려된 AI 원고와 이전부터 부자연스럽다고 여겨졌던 오래된 기사만이 빨간색으로 표시되었습니다.
드디어 사람이 읽고 느끼던 이질감과 기계가 내리는 판정이 같은 방향을 가리키게 되었습니다.
여기서 중요했던 것은, 새로운 기준(閾値)을 생각해 낸 것보다, 좋다고 알고 있는 글로 검증했다는 점이었습니다. lint 규칙에도 정상 케이스와 비정상 케이스를 모두 준비할 필요성을 느꼈습니다.
대체하는 숫자는 실례로부터 역산하여 결정한다
돌아보면, 막혔던 부분 두 곳 모두 같은 성질을 가지고 있었습니다. 측정할 수 없는 것을 다른 숫자로 대신했을 때, 그 숫자를 임의로 정하고 있었다는 것입니다.
가독성 대신 단락의 길이를 선택한 것은 타당했다고 생각합니다. 문제가 된 것은 그 다음 단계인 '그럼 몇 글자까지를 좋다고 할 것인가'였습니다. 160이라는 숫자를 설정했을 때, 저는 손에 있는 기사를 한 개도 측정하지 않았습니다. 다음에 '한 문장 단락은 4할 이하'를 생각해 냈을 때도 마찬가지로, 측정한 것은 구현 이후였습니다.
—결국, 실례를 측정하기 전까지는 자신의 기준이 맞는지 알 수 없었던 것입니다.
순서를 역전시키자, 둘 다 구현 전에 잡을 수 있었습니다. 먼저 좋다고 생각하는 기사 몇 개를 측정하고, 숫자의 분포를 본 후에, 그 범위를 벗어나는 것만 걸러내는 방식입니다. 이번에 그렇게 하니, 첫 번째 안은 모범 사례의 기사를 떨어뜨린다는 것을 알게 되었고, 대신 사용해야 할 숫자가 표에서 떠올랐습니다.
또 하나, 검사 자체에도 좋은 예와 나쁜 예 둘 다를 적용할 필요가 있습니다. 이번 lint는 나쁜 원고를 빨간색으로 표시하는 것은 확실했지만, 좋은 원고를 초록색으로 표시할 수 있는지는 한 번도 확인하지 못했습니다. 한쪽만 보는 검사는 한쪽에만 효과가 있습니다.
마지막에 남은 생각
사람이 감각적으로 판단하는 품질을 기계로 측정하게 하려면, 기준치는 임의가 아니라 좋다고 여겨지는 실물을 측정하여 역산해야 한다는 결론에 이르렀습니다.
소개
저는 집 안에 물리 서버를 두고 인프라를 배울 수 있는 장소를 만들고 있습니다.
교재는 등록 없이 무료로 읽을 수 있습니다. 실제 서버에 접속하는 연습은 구축 중이며, 아직 모든 장에 대응하고 있지는 않습니다.
전체 챕터 인덱스: infra-study.org/curriculum
감상 폼: 감상 폼(Tally)
X(@taro3_01)에서 업데이트를 공지합니다. 팔로우하면 다음 알림을 받을 수 있습니다.
Discussion

AI 자동 생성 콘텐츠
본 콘텐츠는 Zenn AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기