AI가 쓴 것을 어떻게 믿는가 — 가장 싼 검사 장치 네 개
AI에게 시켜서 뭔가를 만들 때, 어려운 부분은 만드는 것이 아니었습니다. 만든 것이 맞는지 아는 것이었습니다.
저는 이 질문에 오래 답을 못 했습니다. 눈으로 읽어보는 것 말고는 방법을 몰랐고, 눈으로 읽는 것은 내가 이미 아는 것만 잡아냅니다. 직접 짜본 적이 없으면 틀린 것을 봐도 틀린 줄 모릅니다.
그래서 방향을 바꿨습니다. 내가 판단할 수 있는 것만 검사하는 대신, 판단이 필요 없는 것을 기계가 검사하게 했습니다. 네 개를 쓰고 있고, 전부 짧습니다.
① 숫자가 어디서 왔는지 대조합니다
AI는 그럴듯한 숫자를 만들어냅니다. 위험한 이유는 틀린 숫자가 틀려 보이지 않기 때문입니다. 문장 속의 수치는 그 자체로 근거처럼 읽힙니다.
그래서 반대로 만들었습니다. 먼저 쓸 수 있는 숫자 목록을 만들고, 그 목록에 없는 숫자가 본문에 나오면 막습니다.
핵심은 그 목록이 어디서 오느냐입니다. 손으로 적는 값이 아닙니다. 수치마다 그 값을 다시 뽑아내는 명령을 함께 적어둡니다.
- id: guard_key_count
claim: "설정에 선언된 가드 규칙 키 수"
kind: grep_count
cwd: "config"
pattern: '^\s+guard_\w+:'
glob: "settings.yaml"
값이 없습니다. 세는 방법만 있습니다. 코드가 바뀌면 값도 따라 바뀝니다.
② 단정하는 표현을 막습니다
두 번째는 더 짧습니다. 낱말 목록 하나입니다. “검증됐다”, “증명된”, “보장합니다” 같은 것들.
왜 막느냐. 근거 없이 단정하는 순간 나머지 전부의 신뢰가 같이 무너지기 때문입니다. 읽는 쪽은 문장 하나가 과장인 것을 알아채면 앞뒤를 다 의심합니다. 저라도 그럽니다.
이 검사는 저를 여러 번 잡았습니다. 지금 쓰고 있는 전자책의 한 부 제목이 원래 *“토큰을 크게 줄이는 방법”*이었습니다. 저는 줄어드는 배수를 실제로 재본 적이 없습니다. 그래서 “크게"를 뺐습니다.
초기 진입자에게 이 검사가 특히 쓸모 있는 이유가 있습니다. AI에게 소개 문구를 써달라고 하면 거의 항상 단정하는 문장이 섞여 나옵니다. AI는 잘 팔리는 문장을 흉내 내는데, 그 문장들이 원래 그렇게 생겼기 때문입니다. 그대로 쓰면 그 주장의 책임은 쓴 사람이 집니다.
③ 키가 코드에 박혔는지 봅니다
AI가 만들어주는 코드에는 API 키가 코드 안에 그대로 박혀 있는 일이 흔합니다. 그게 가장 짧고, 물어본 사람이 바로 돌려볼 수 있는 형태니까요. AI 입장에서는 친절한 겁니다.
문제는 그다음입니다. 처음 하는 사람은 그게 문제인 줄 모르고 저장소에 그대로 올립니다. 공개된 저장소에 올라간 키는 사람이 찾는 게 아닙니다. 자동으로 훑는 프로그램들이 금방 찾아냅니다.
실천은 둘입니다. 값을 코드 밖(환경변수)에 두고, 올리기 직전에 키처럼 생긴 문자열을 찾는 검사를 걸어둡니다. 사람은 잊어버리니까요.
한 가지 덧붙입니다. 저는 이 검사를 처음에 너무 넓게 만들어서 검사 코드 자체의 문구까지 잡아냈습니다. 아무것도 잘못하지 않았는데 계속 막히니 검사를 끄고 싶어졌습니다. 그게 제일 나쁜 결과입니다. 꺼진 검사는 없는 검사보다 나쁩니다. 있다고 착각하니까요.
④ 검사 장치를 검사합니다
마지막이 제일 중요합니다.
검사를 만들어놓고 그게 진짜 막는지 확인하지 않으면, 그건 검사가 아니라 장식입니다. 저는 이 말을 오래 흘려들었습니다. 통과했다는 초록색 글씨를 보면 마음이 놓이니까요. 그런데 통과는 두 가지 뜻입니다. 지킬 것이 없어서 통과했을 수도 있습니다.
방법은 단순합니다. 검사를 일부러 하나 꺼봅니다. 그리고 그 검사에 대응하는 시험이 실제로 실패하는지 봅니다. 껐는데도 통과하면, 그 검사는 처음부터 아무것도 안 지키고 있었던 겁니다. 규칙 이름과 “이 규칙이 없으면 반드시 깨져야 하는 시험"을 짝지어 두고 하나씩 꺼가며 돌립니다. 저희는 12개 규칙을 이 방식으로 확인합니다.
이걸로 실제 결함을 잡았습니다.
설정 파일에 *“출처 없는 수치를 차단한다”*는 규칙이 켜져 있었습니다. 저는 그게 있는 줄 알았습니다. 선언돼 있었으니까요. 그런데 그 규칙이 대조할 허용 수치 목록을 만드는 코드가 없었습니다. 읽을 입력이 없는 선언이었습니다. 껐을 때 아무 시험도 실패하지 않아서 드러났습니다.
이게 무서운 종류의 결함인 이유는 잘 돌아가고 있는 것처럼 보이기 때문입니다. 설정에는 켜져 있고, 시험은 통과하고, 아무도 뭐라 하지 않습니다.
지금까지 이 검사 장치들이 잡아낸 저희 코드의 결함이 6개입니다. 전부 저희가 만든 것이고, 남이 알려준 것이 아닙니다.
오늘 무엇부터 하면 되나
넷을 다 만들 필요는 없습니다. 순서를 매기면 이렇습니다.
- 키 검사부터. 사고가 났을 때 되돌리기가 가장 어렵습니다
- 단정 표현 검사. 낱말 목록 하나면 되고, 만드는 데 몇 분 걸립니다
- 숫자 목록. 숫자를 다루는 글을 만든다면 필요합니다
- 검사를 검사하기. 검사가 두 개쯤 쌓인 다음에 하면 됩니다
하나만 기억하면 좋겠습니다. 검사를 만든 날과 그 검사가 진짜 막는지 확인한 날은 다른 날입니다. 저는 그 사이에 몇 주를 안심하고 지냈습니다.
확인되는 것과 안 되는 것
정직하게 구분해 두겠습니다.
확인되는 것: 위 검사들이 실제로 존재하고 돌아간다는 것, 그리고 결함을 잡았다는 것. 저희 저장소를 열면 코드가 있습니다.
확인 안 되는 것: 이 방식이 다른 방식보다 낫다는 주장입니다. 같은 작업을 검사 없이도 해보고 나란히 비교한 적이 없습니다. 저희 사례 하나이고 일반적인 주장이 아닙니다.
이 구분을 흐리지 않으려고 원고에 ②번 검사를 걸어뒀습니다. 이 글도 그 검사를 통과해야 올라갑니다.