블로그 / AI 트렌드
AI 트렌드

AI의 "다 했습니다"를 믿지 않는 법 — unlazy 스킬과 검사기 만들기

2026.08.23 · 자비스스튜디오

어제 하루 동안 저희 코드에서 문서에 적힌 규칙과 실제 코드가 어긋난 곳을 다섯 군데 찾았습니다. 전부 AI에게 맡겨서 작업한 부분이었고, 전부 "완료했습니다"라는 보고를 받은 뒤였습니다.

가장 뼈아팠던 건 이겁니다. 저희 문서 두 곳에 /me/threads 엔드포인트를 써야 한다고 분명히 적혀 있었는데, 정작 게시 엔진만 옛날 주소를 쓰고 있었습니다. 그래서 Threads 게시가 한 번도 성공한 적이 없었습니다. 아무도 몰랐고요.

그래서 이 주제를 정리하게 됐습니다. AI 에이전트의 완료 보고를 어떻게 검증할 것인가.

AI는 왜 안 하고 했다고 할까

마침 이 문제를 구조적으로 다루는 글이 있어서 잘 읽었습니다. Dr. Cha Tech Blog의 unlazy 스킬 가이드입니다. 원인을 두 가지로 짚습니다.

  • 주의력 분산 — 대화창이 채워질수록 모델이 초반 지시를 놓칩니다.
  • 비용을 아끼려는 성질 — 토큰과 계산량을 줄이려는 보상 구조가 내재돼 있습니다.

그 결과가 "모든 요청 작업을 마쳤습니다"라는 보고와, 실제로는 건너뛴 파일들입니다. 이걸 게으름(Laziness), 조기 종료(Premature Completion)라고 부릅니다.

여기서 중요한 건 프롬프트로는 안 고쳐진다는 점입니다. "빠짐없이 다 해줘"라고 아무리 강조해도, 그 문장 역시 길어진 대화 속 한 줄일 뿐입니다. 저희가 다섯 번 놓친 것도 전부 "문서에 적어둔" 규칙이었습니다.

이런 소식, 남들보다 먼저 받으실 분?
직접 돌려보고 되는 것만 골라 매주 보내드립니다. 광고성 하이프는 거릅니다.

📮 뉴스레터 신청

unlazy의 답 — 텍스트 말고 명령어로 확인한다

unlazy는 개발자 Leonxlnx가 공개한 오픈소스 스킬입니다. 접근이 명확합니다. 완료를 텍스트로 받지 않고, 실제 명령어를 돌려서 받습니다.

① Depth Tree — 작업을 잘게 찢는다

과제를 트리 구조로 분해하고, 각 조각마다 깨끗한 컨텍스트와 독립된 에이전트를 붙입니다. 대화가 길어져서 집중력이 떨어지는 문제 자체를 없애는 방식입니다.

② Gates — 게이트를 통과해야 다음으로

GATES.md라는 원장 파일에 목표·검증 명령어·예상 출력값·실제 증거를 적습니다. AI가 스스로 체크박스를 채워도 소용없습니다. 검증 스크립트가 명령어를 직접 실행해서 예상 출력이 나와야만 게이트가 열립니다.

표로 보면 차이가 분명합니다.

구분보통의 방식게이트 방식
완료 판정"완료했다"고 적으면 인정명령어 실행 결과로 판정
컨텍스트계속 누적 → 집중도 저하조각마다 독립
누락 대응어려운 과제는 스킵 가능미통과 시 다음 단계 진입 불가
설치
npx skills add Leonxlnx/unlazy

# 사용
/unlazy tree 2-3 [소규모 모듈 구현]
/unlazy tree 5   [대규모 리팩토링]

순차 실행은 대형 작업에서 3~4시간이 걸리는데, Claude Code의 서브 에이전트 병렬 처리를 붙이면 1시간 안쪽으로 줄어든다고 합니다. 자세한 설정은 원문 가이드를 보세요.

저희는 아직 unlazy를 실제 프로젝트에 붙여보지 않았습니다. 그래서 이 글에서는 써봤다고 말하지 않겠습니다. 대신 같은 문제를 저희가 어떻게 풀고 있는지를 적겠습니다 — 그건 매일 돌리고 있는 것이라 자신 있게 말할 수 있습니다.

저희가 쓰는 방법 — 규칙을 문서가 아니라 코드에 둔다

저희가 얻은 결론은 한 줄입니다.

문서에만 적힌 규칙은 지켜지지 않습니다. 기계가 검사해야 합니다.

같은 얘기를 반대로 하면, 규칙을 지키게 하고 싶으면 그 규칙을 어겼을 때 빨간불이 켜지는 스크립트를 만들어야 한다는 뜻입니다. 게이트와 같은 발상이고, 훨씬 소박한 형태로 만들 수 있습니다.

예시 — 광고 고지 검사기

저희는 제휴 링크가 들어간 글에 공정위 고지를 넣어야 합니다. 문서에 규칙을 적어뒀는데, 어느 날 확인해보니 양쪽으로 다 어긋나 있었습니다. 제휴 링크가 하나도 없는 글 두 편에 고지가 붙어 있었고(허위표시도 위반입니다), 반대 경우도 있었습니다.

그래서 60줄짜리 스크립트를 만들었습니다. 핵심은 이 부분입니다.

check-ad-disclosure.mjs — 양방향 대조
// 대가를 받는 링크의 표시. 새 제휴처가 생기면 여기 추가한다.
const AFFILIATE = /3ha\.in|coupa\.ng|\/invitation\/|[?&]ref=|referral/i;

// 화면에 실제로 보이는 고지만 센다. CSS 규칙만 남아 있는 건
// 아무것도 표시하지 않으므로 위반이 아니다 — 이걸 세면 오탐이 4건 난다.
const SHOWN = /<p class="ad-disclosure"/;

function checkBlog(slug) {
  const html = fs.readFileSync(path.join(BLOG, slug, "index.html"), "utf8");
  const shown = SHOWN.test(html);
  const aff = AFFILIATE.test(html);

  if (shown && !aff) problems.push({ slug, why: "고지가 있는데 제휴 링크가 없다 (허위표시)" });
  if (aff && !shown) problems.push({ slug, why: "제휴 링크가 있는데 고지가 없다" });
}

// 불일치가 있으면 종료코드 1 — CI·훅에 걸기 좋게
process.exit(problems.length ? 1 : 0);

보시면 알겠지만 특별할 게 없습니다. 정규식 두 개와 if 두 줄입니다. 중요한 건 이게 사람의 기억이 아니라 종료코드로 판정된다는 점입니다. 게시 전에 한 번 돌리면 끝입니다.

검사기를 만들 때 배운 것

위 코드의 주석 한 줄을 눈여겨봐 주세요. "이걸 세면 오탐이 4건 난다". 처음 만들었을 때 CSS 규칙만 남아 있는 파일까지 위반으로 잡았습니다. 검사기가 틀리면 사람이 검사기를 무시하기 시작합니다. 그러면 없느니만 못합니다.

그래서 새 검사기를 만들면 반드시 이 순서로 확인합니다.

  1. 지금 통과해야 하는 것들에 돌려서 0건이 나오는지 (오탐 확인)
  2. 일부러 어긴 것을 만들어서 잡히는지 (미탐 확인)
  3. 메시지에 어디가 왜 틀렸는지가 적히는지

3번이 특히 중요합니다. "검사 실패"만 뜨는 검사기는 결국 안 쓰게 됩니다.

이 글을 쓰다가 바로 겪었습니다. 위 코드를 본문에 붙이고 검사기를 돌렸더니 이 글이 위반으로 잡혔습니다. 코드 안에 적힌 리퍼럴 패턴 문자열을 검사기가 진짜 제휴 링크로 읽은 겁니다. 처음엔 코드 블록만 검사에서 뺐는데 그것도 부족했습니다 — 본문에서 그 단어를 한 번 더 언급하니 또 걸리더군요. 결국 HTML 전체가 아니라 href 값만 보도록 바꿨습니다. 글자로 적는 건 링크가 아니니까요. 그리고 위의 세 단계를 다시 돌렸습니다 — 65개 글에서 오탐 0건, 일부러 어긴 파일은 양방향 다 잡힙니다.

어제 이 방식으로 잡힌 것들

1. Threads 게시가 한 번도 성공한 적 없음

문서 두 곳에 올바른 엔드포인트가 적혀 있었지만 엔진만 안 고쳐져 있었습니다. 문서-코드 대조를 스크립트로 돌리면서 발견했습니다.

2. 캡션을 저장할 때마다 일부가 사라짐

파서가 같은 이름의 구역을 두 번 읽어서, 나중 것이 앞의 것을 덮어쓰고 있었습니다. 왕복 테스트(저장 → 다시 읽기 → 비교)를 붙이니 바로 나왔습니다.

3. 카드 템플릿 5종이 표지 서식을 한 번도 안 씀

카드마다 유형(표지·본문·마무리)을 붙이는 코드가 어디에도 없어서, 여섯 장이 전부 본문으로 그려지고 있었습니다. 배지와 강조 문구가 통째로 빠진 채로요.

세 개 다 "완료했습니다"를 받은 작업이었습니다. 그리고 세 개 다 사람이 눈으로 봐서는 못 찾았을 것들입니다. 결과물이 그럴듯하게 나왔으니까요.

정리 — 오늘 바로 할 수 있는 것

unlazy처럼 잘 만들어진 프레임워크를 붙이는 것도 좋은 선택입니다. 다만 그 전에, 규모에 상관없이 지금 당장 할 수 있는 게 있습니다.

  • AI에게 작업을 시킬 때 검증 명령어를 같이 정하세요. "다 하면 npm test를 돌려서 출력을 붙여줘"가 "빠짐없이 해줘"보다 백 배 낫습니다.
  • 지키고 싶은 규칙이 있으면 검사 스크립트로 만드세요. 30줄이면 충분합니다. 문서에 적는 건 그다음입니다.
  • 대화가 길어지면 새로 시작하세요. 컨텍스트가 쌓일수록 초반 지시가 흐려지는 건 구조적인 문제라, 참고 계속하는 게 답이 아닙니다.

결국 개발자의 일이 코드를 타이핑하는 것에서 AI가 내놓은 결과를 어떻게 검증할 것인가로 옮겨가고 있다는 이야기입니다. 저희도 그렇게 바뀌고 있고요.

그대로 가져가세요

위에서 쓴 검사기 뼈대입니다. 프로젝트에 맞게 정규식만 바꾸면 바로 돌아갑니다.

check-rule.mjs
import fs from "node:fs";
import path from "node:path";

const TARGET_DIR = "./content";        // 검사할 폴더
const MUST_HAVE = /지켜야 할 패턴/;      // 있어야 하는 것
const TRIGGER   = /이 조건일 때만/;       // 위 규칙이 필요해지는 조건

const problems = [];

for (const name of fs.readdirSync(TARGET_DIR)) {
  const file = path.join(TARGET_DIR, name);
  if (!fs.statSync(file).isFile()) continue;
  const text = fs.readFileSync(file, "utf8");

  const need = TRIGGER.test(text);
  const has  = MUST_HAVE.test(text);

  // 양방향으로 본다 — 빠뜨린 것도, 필요 없는데 붙인 것도 둘 다 문제다
  if (need && !has) problems.push(`${name}: 조건에 맞는데 규칙이 빠졌습니다`);
  if (!need && has) problems.push(`${name}: 조건이 아닌데 규칙이 붙어 있습니다`);
}

if (problems.length) {
  console.log(`불일치 ${problems.length}건`);
  for (const p of problems) console.log("  " + p);
  process.exit(1);                     // 종료코드로 말한다
}
console.log("불일치 없음 ✓");

쓰는 법: node check-rule.mjs — 게시나 배포 전에 한 번 돌립니다. 종료코드가 1이라 package.jsonprepublish나 git 훅에 그대로 걸 수 있습니다.

실측 위주 AI 뉴스레터 — 직접 돌려보고 되는 것만 골라 매주 보내드립니다.

unlazy Claude Code AI 에이전트 AI 게으름 개발 자동화 코드 검증

출처 · unlazy 스킬 소개와 설치·설정은 Dr. Cha Tech Blog의 "AI의 환각과 게으름을 원천 차단하는 unlazy 스킬 완벽 가이드"를 참고했습니다. 스킬 원본은 github.com/Leonxlnx/unlazy입니다.