짧게 답하면 안 되지만, 길게 답하면 시간을 아낀다
완전한 파견 검사에는 진행자, 낭독자, 24명의 검토자, 그리고 작성자가 필요하다. 팀은 한 시간에 125줄의 속도로 대략 250줄의 코드를 2시간 동안 검토한다. 작은 변경에도 812인시가 드는 셈이다.
대형 언어 모델은 250줄을 1초도 채 걸리지 않아 읽을 수 있다. 체크리스트를 실행하고, 수상한 패턴을 지적하며, 사람이 파일을 열기 전에 구조화된 결함 기록을 생성할 수 있다.
그렇다고 팀을 대체할 수 있다는 뜻은 아니다. 팀은 대형 언어 모델이 숙제를 끝낼 때까지 회의를 시작하지 말아야 한다는 뜻이다.
대형 언어 모델이 파견 검사에서 실제로 할 수 있는 일
파견 검사에는 네 가지 명확한 역할이 있다. 각 역할은 대형 언어 모델이 할 수 있는 일과 할 수 없는 일에 대해 다르게 대응한다.
진행자는 검사를 계획하고, 참가 기준을 집행하며, 회의가 탈선하지 않도록 이끈다. 대형 언어 모델은 체크리스트를 만들고, 검사 전에 테스트가 통과하는지 확인하고, 줄 수를 기준으로 소요 시간을 추정할 수 있다. 하지만 엔지니어들이 설계 논쟁으로 빠져들고 있는지 알아차릴 수는 없다. 진행자의 역할은 사회적인 것이며, 대형 언어 모델은 사회적 존재가 아니다.
낭독자는 회의 중에 코드를 큰 소리로 다시 말해 그룹이 훑어보는 속도가 아니라 이해하는 속도로 논리를 처리하도록 강제한다. 대형 언어 모델은 코드를 요약할 수 있지만, 사람들이 속도를 늦추게 할 수는 없다. 낭독자의 진정한 가치는 사회적 강제력에 있다. 대형 언어 모델에는 그런 영향력이 없다.
검토자는 체크리스트와 도메인 지식을 바탕으로 코드를 검토하여 결함을 찾는다. 여기가 대형 언어 모델이 가장 유용한 곳이다. null 참조, 자원 누수, 처리되지 않은 오류 경로, 경계값 오류를 사람보다 빠르게 검사할 수 있다. 피로하지 않는다. 지루해 보이는 보조 함수가 안전해 보인다고 건너뛰지 않는다.
작성자는 질문에 답하고 결함을 수정한다. 대형 언어 모델은 작성자를 대체할 수 없다. 코드를 작성한 것도 아니고 의도를 확인할 수도 없기 때문이다.
따라서 현실적인 답은 ‘대체’가 아니라 ‘역할 이양’이다. 대형 언어 모델은 사람들이 방에 들어가기 전에 검토자 역할의 기계적인 부분을 끝내 버리는, 지치지 않는 사전 검토자로 기능할 수 있다.
대형 언어 모델이 진정으로 도움이 되는 곳: 준비 단계
파견 검사에서 가장 중요한 단계는 준비다. 모든 검토자는 회의 전에 혼자 자료를 검토한다. 연구에 따르면 준비에서 발견되는 결함은 전체 과정에서 발견되는 결함의 대략 절반을 차지한다. 대형 언어 모델이 이 단계를 강화할 수 있다면, 인간의 회의는 더 짧고 날카로워진다.
실용적인 접근법을 소개하겠다. 대형 언어 모델에 코드와 사용 언어에 맞춘 체크리스트, 그리고 구조화된 출력을 강제하는 프롬프트를 넘긴다. 대형 언어 모델의 출력은 인간 검토자의 출발점으로 사용하고, 대체재로 삼지 않는다.
프롬프트가 모델보다 중요하다. “이 코드를 검토해 줘” 같은 모호한 요청은 진부한 일반론만 돌려준다. 체크리스트와 출력 형식을 갖춘 구조화된 프롬프트라면 실행 가능한 결함을 얻을 수 있다.
아래는 OpenAI 호환 API를 사용하여 대형 언어 모델 기반 사전 검사를 수행하는 파이썬 스크립트다. 소스 파일을 읽고, 파견 검사 스타일의 체크리스트를 적용하며, 구조화된 결함 기록을 출력한다.
#!/usr/bin/env python3
"""
LLM pre-inspection for Fagan-style review.
Produces structured defect log from a checklist.
"""
import argparse
import os
from pathlib import Path
def build_prompt(code: str, filepath: str, language: str) -> str:
checklist = {
"python": [
"Missing null/None checks before dereferencing",
"Unclosed file handles or missing context managers",
"Bare except clauses that swallow exceptions",
"Mutable default arguments in function signatures",
"Race conditions in shared mutable state",
"Missing input validation on public functions",
],
"typescript": [
"Non-null assertions (e.g., !) without justification",
"Missing await on async calls",
"Any types that should be narrowed",
"Unhandled promise rejections",
"Missing input validation on public functions",
],
"rust": [
"Unwrap or expect without comment explaining invariants",
"Missing error propagation where Result is returned",
"Unsafe blocks without safety comments",
"Clone on large data structures in hot paths",
"Missing input validation on public functions",
],
}
items = checklist.get(language, checklist["python"])
checklist_text = "\n".join(f" - {item}" for item in items)
return (
"You are a Fagan inspection assistant. Review the following code "
"against the checklist. For each defect found, output a JSON object "
"with keys: line, category, severity (minor/major/critical), description. "
"If no defect is found for a checklist item, omit it. "
"Be specific about line numbers and exact variable names. "
"Do not suggest fixes. Fagan inspections only log defects, they do not solve them.\n\n"
f"File: {filepath}\n"
f"Language: {language}\n\n"
"Checklist:\n"
f"{checklist_text}\n\n"
"Code:\n```\n"
f"{code}\n"
"```\n\n"
"Output strict JSON array of defects only. No markdown, no preamble."
)
def inspect_file(filepath: str, api_key: str, base_url: str) -> list:
"""Run LLM pre-inspection and return parsed defect list."""
from openai import OpenAI
path = Path(filepath)
code = path.read_text()
# Infer language from extension
ext_map = {
".py": "python",
".ts": "typescript",
".tsx": "typescript",
".rs": "rust",
}
language = ext_map.get(path.suffix, "python")
client = OpenAI(api_key=api_key, base_url=base_url)
response = client.chat.completions.create(
model=os.environ.get("INSPECTION_MODEL", "gpt-4.1-mini"),
messages=[
{"role": "system", "content": "You are a precise code inspection tool."},
{"role": "user", "content": build_prompt(code, filepath, language)},
],
temperature=0.2,
max_tokens=2048,
)
raw = response.choices[0].message.content.strip()
# Some models wrap JSON in markdown fences. Strip them.
if raw.startswith("```json"):
raw = raw[7:]
if raw.startswith("```"):
raw = raw[3:]
if raw.endswith("```"):
raw = raw[:-3]
raw = raw.strip()
import json
try:
defects = json.loads(raw)
if not isinstance(defects, list):
return []
return defects
except json.JSONDecodeError:
print("Warning: LLM returned non-JSON output:")
print(raw[:500])
return []
def main():
parser = argparse.ArgumentParser(description="LLM pre-inspection for Fagan review")
parser.add_argument("files", nargs="+", help="Source files to pre-inspect")
parser.add_argument("--api-key", default=os.environ.get("OPENAI_API_KEY"))
parser.add_argument(
"--base-url",
default=os.environ.get("OPENAI_BASE_URL", "https://api.openai.com/v1"),
)
args = parser.parse_args()
if not args.api_key:
raise SystemExit("Error: set OPENAI_API_KEY or pass --api-key")
all_defects = []
for f in args.files:
defects = inspect_file(f, args.api_key, args.base_url)
all_defects.extend({"file": f, **d} for d in defects)
if not all_defects:
print("No defects flagged by LLM pre-inspection.")
return
print(f"LLM pre-inspection found {len(all_defects)} defect(s):\n")
for d in all_defects:
print(
f"[{d['severity'].upper()}] {d['file']}:{d.get('line', '?')} "
f"({d['category']}) {d['description']}"
)
if __name__ == "__main__":
main()
OpenAI SDK를 pip install openai로 설치하고, API 키를 설정한 뒤 python inspect.py src/auth.py를 실행하면 된다. 이 스크립트는 인간 검토자가 출발점 체크리스트로 사용할 수 있는 구조화된 결함 기록을 출력한다.
이것은 검사 자체가 아니다. 준비 작업이다. 결함에는 여전히 인간의 판단이 필요하다.
대형 언어 모델이 놓치는 것: 진짜 돈을 잡아먹는 결함
가장 비싼 결함은 구문 오류가 아니다. 잘못된 가정이다.
대형 언어 모델은 null 검사 누락을 찾아낼 것이다. 하지만 상위 서비스가 해당 필드를 보장하므로 null 케이스는 발생할 수 없어야 하며, 진짜 버그는 3주 전 팀이 계약을 변경하고 하위 코드를 업데이트하는 것을 잊었다는 사실에는 눈치채지 못할 것이다.
대형 언어 모델은 처리되지 않은 예외를 지적할 것이다. 하지만 작성자가 데이터베이스 트랜잭션이 자동으로 롤백될 것이라고 가정해서 예외 처리기가 빠져 있고, 그 가정이 팀이 사용하는 특정 격리 수준에서는 틀리다는 사실에는 주목하지 못할 것이다.
이것들은 의도 수준의 결함이다. 도메인 지식, 역사적 맥락, 그리고 “작성자가 진실이 아니라고 여기는 것을 무엇이라고 가정했는가?”라고 묻는 능력을 필요로 한다. 대형 언어 모델은 팀의 문서화되지 않은 가정에 접근할 수 없다. 지난 분기의 아키텍처 결정에 대한 기억도 없다. 요구사항 문서를 보고 코드가 잘못된 요구사항을 구현하고 있다는 것을 알아차릴 수도 없다.
파견 검사는 바로 이러한 결함을 잡기 위해 설계되었다. 인간 검토자는 서로 다른 정신적 모델과 서로 다른 맥락을 가져온다. 그들이 코드가 무엇을 해야 하는지에 대해 의견이 갈릴 때, 그들의 가정 사이의 틈이 진짜 버그가 사는 곳이다.
대형 언어 모델은 하나의 정신적 모델만 가지고 있으며, 그것은 공개 코드로 훈련된 것이지 당신의 코드베이스가 아니다.
진짜 트레이드오프: 커버리지 대 이해
대형 언어 모델 사전 검토는 커버리지를 제공한다. 모든 줄을 읽고, 모든 함수를 검사하며, 슬랙 알림에 절대 주의를 흐트리지 않는다. 완벽한 좁은 검토자다.
인간 검토는 이해를 제공한다. 코드를 사양에, 사양을 데이터베이스 스키마에, 스키마를 지난 스프린트 계획 회의에서 변경된 비즈니스 규칙에 연결한다. 코드 밖에 존재하는 결함을 찾을 수 있는 유일한 방법이다.
트레이드오프는 인간 대 기계가 아니다. 깊이 대 폭이다.
검토 팀을 대형 언어 모델로 교체하면, 구문 수준의 결함은 더 많이 찾게 되고 의도 수준의 결함은 더 많이 놓치게 된다. 순 결과는 어떤 종류의 버그가 당신을 괴롭히는지에 달려 있다. 본장애 인시던트가 대부분 null 역참조와 자원 누수라면, 대형 언어 모델은 도움이 될 것이다. 잘못된 비즈니스 로직과 놓친 경계 케이스가 대부분이라면, 대형 언어 모델은 거짓된 자신감만 줄 것이다.
실무에서 하이브리드 검토를 운용하는 방법
다음은 대형 언어 모델이 잘하는 일에는 대형 언어 모델을 쓰고, 인간만이 할 수 있는 일에는 인간 팀을 보존하는 실용적인 워크플로우다.
회의 전에, 대형 언어 모델 사전 검토 스크립트를 코드에 대해 실행한다. 모든 인간 검토자에게 그 출력물과 원본 코드를 함께 준다. 개별 준비 시간에 대형 언어 모델의 각 지적을 검증하거나 기각하도록 의무화한다. 이렇게 하면 그들이 훑어보았을 행들을 검토하도록 강제할 수 있다.
회의 중에도 낭독자는 여전히 코드를 큰 소리로 다시 말한다. 검토자도 여전히 문제를 제기한다. 하지만 이제는 이미 분류된 기계적 결함의 정제된 목록에서 출발한다. 회의 시간은 2시간에서 90분으로 줄어들 수 있고, 같은 시간 안에 더 많은 코드를 검토할 수도 있다.
진행자에게는 새로운 책임이 하나 추가된다: 대형 언어 모델의 정확도를 추적하는 것이다. 대형 언어 모델이 지적한 결함 중 실제인 것은 몇 개였는지, 거짓 양성은 몇 개였는지, 대형 언어 모델이 놓친 인간 전용 결함은 몇 개였는지 기록하라. 3~4번의 검토를 거치면, 체크리스트 프롬프트에 미세 조정이 필요한지 알게 될 것이다.
이것은 1990년대에 NASA가 도구 지원 검토를 실험했을 때 사용한 것과 똑같은 프로세스다. 자동 검사기가 쉬운 결함을 찾고 어려운 것은 인간에게 남겨두었다. 인간들은 쉬운 결함을 찾아 정신적으로 고갈되지 않았기 때문에 더 나은 성과를 보였다.
결론
대형 언어 모델은 완전한 검토 팀을 대체할 수 없다. 왜냐하면 검토는 단순한 코드 읽기가 아니기 때문이다. 그것은 작성자가 가정한 것과 코드가 실제로 하는 것 사이의 간극을 드러내도록 설계된, 구조화된 사회적 과정이다.
대형 언어 모델이 할 수 있는 것은 기계적인 부담을 제거하여 인간 팀을 더 효과적으로 만드는 것이다. 다섯 번째 역할, 즉 인간이 도착하기 전에 전장을 준비하는 지치지 않는 사전 검토자로 기능할 수 있다.
검토가 너무 비싸서 건너뛰고 있다면, 대형 언어 모델은 검토를 무료로 만들지 않는다. 더 짧게 만든다. 그것만으로도 종종 충분하다.
자주 묻는 질문
파견 검사란 무엇인가?
1976년 IBM의 마이클 파견이 고안한 6단계 구조화된 검토 프로세스다. 진행자, 낭독자, 검토자, 작성자라는 정의된 역할과 의무적인 개별 준비, 시간 제한이 있는 회의를 사용하여 테스트 전에 결함을 찾는다. 일관되게 60~90퍼센트의 결함 제거율을 보고한다.
대형 언어 모델이 인간 코드 리뷰어를 대체할 수 있는가?
가장 중요한 결함에 대해서는 대체할 수 없다. 대형 언어 모델은 null 검사 누락이나 자원 누수 같은 기계적인 문제를 포착한다. 상위 계약에 대한 잘못된 가정, 누락된 비즈니스 로직, 코드와 요구사항의 불일치 같은 의도 수준의 결함은 놓친다.
파견 검사에 대형 언어 모델을 통합하려면?
준비 단계에서 대형 언어 모델을 사용한다. 체크리스트에 대해 실행하고, 그 출력을 회의 전에 인간 검토자에게 전달한 뒤, 각 지적을 검증하도록 의무화한다. 이렇게 하면 회의 시간이 단축되고 인간의 집중력이 향상되지만, 인간의 판단은 배제되지 않는다.
대형 언어 모델 체크리스트 프롬프트를 효과적으로 만드는 것은 무엇인가?
구체성이다. 일반적인 프롬프트는 일반적인 출력을 낳는다. 효과적인 프롬프트는 정확한 결함 범주를 명명하고, 구조화된 JSON 출력을 요구하며, 수정안 제안을 금지하고, 정확한 행 번호와 변수 이름을 요구한다. 체크리스트는 사용 언어와 팀이 가장 자주 놓치는 결함에 맞춰야 한다.
한 파일로 시험해 보기
지난달에 본장애 인시던트를 일으킨 파일 하나를 고르시오. 팀이 신경 쓰는 5가지 특정 결함 유형의 체크리스트를 작성하시오. 위 스크립트를 해당 체크리스트로 실행하시오. 출력 결과를 해당 파일을 작성하지 않은 두 명의 엔지니어에게 전달하시오.
대형 언어 모델의 발견과 인간의 발견을 비교하시오. 겹치는 부분을 세고, 각자가 놓친 것을 세시오. 그 간극이 당신의 답이다.