AI를 자동완성이 아니라 파이프라인으로 쓰는 법
코드를 대신 짜주는 도구로 쓰면 생산성은 20% 오르고 끝납니다. 단계를 나누고 각 단계의 출력을 검증 가능하게 만들면 그때부터 배가 됩니다.
LLM을 도입했는데 기대만큼 빨라지지 않았다는 이야기를 자주 듣습니다. 대부분 같은 지점에서 막힙니다. AI를 "코드를 대신 써주는 사람"으로 쓰고 있기 때문입니다.
이렇게 쓰면 얻는 건 타이핑 속도입니다. 그런데 개발에서 타이핑은 원래 병목이 아니었습니다.
병목은 타이핑이 아니다
기능 하나를 만들 때 실제로 시간이 어디에 들어가는지 적어보면 대략 이렇습니다.
| 단계 | 비중 | AI 적용 난이도 |
|---|---|---|
| 요구사항 파악·정리 | 25% | 낮음 |
| 설계·대안 검토 | 20% | 낮음 |
| 코드 작성 | 15% | 매우 낮음 |
| 테스트 작성 | 15% | 낮음 |
| 디버깅·수정 | 20% | 높음 |
| 문서화 | 5% | 매우 낮음 |
코드 작성은 15%입니다. 여기만 두 배 빨라져봐야 전체는 7% 빨라집니다. 반면 앞단(요구사항·설계)과 뒷단(테스트·문서)은 합쳐서 65%인데, 적용 난이도는 오히려 낮습니다.
단계를 쪼개고 출력을 고정한다
핵심은 하나의 큰 프롬프트로 끝내지 않는 것입니다. 단계를 나누고, 각 단계의 출력을 다음 단계가 기계적으로 소비할 수 있는 형태로 고정합니다.
// 나쁜 예 — 한 번에 다 시킨다. 실패하면 어디가 틀렸는지 알 수 없다.
const result = await llm("이 요구사항으로 API를 만들어줘: " + requirements);
// 좋은 예 — 단계를 나누고 각 출력을 스키마로 검증한다.
const spec = SpecSchema.parse(await llm.json(specPrompt(requirements)));
const design = DesignSchema.parse(await llm.json(designPrompt(spec)));
const code = await llm(implementPrompt(design));스키마 검증이 들어가는 순간 두 가지가 생깁니다.
- 실패가 조용히 지나가지 않습니다. 잘못된 출력은 다음 단계로 넘어가기 전에 걸립니다.
- 어느 단계가 문제였는지 특정됩니다. 결과가 이상할 때 프롬프트 전체를 의심하지 않아도 됩니다.
평가셋 없이는 개선도 없다
프롬프트를 고쳤을 때 좋아졌는지 나빠졌는지 감으로 판단하고 있다면, 그건 개선이 아니라 도박입니다.
제가 쓰는 최소 구성은 이렇습니다.
- 실제 사례 30~50건을 정답과 함께 고정
- 프롬프트 변경 시 전체를 다시 돌려 정확도 비교
- CI에서 임계값 미만이면 머지 차단
npm run eval -- --suite classification --threshold 0.9430건이면 충분하냐고 묻는 분들이 계신데, 0건보다 30건이 압도적으로 낫습니다. 완벽한 평가셋을 만들려다 아무것도 안 만드는 경우를 너무 많이 봤습니다.
사람이 남아야 하는 자리
전부 자동화하면 되지 않느냐는 질문에는 분명히 답합니다. 두 자리는 사람이 지켜야 합니다.
- 설계 결정 — 무엇을 만들지, 무엇을 안 만들지. AI는 주어진 방향으로 잘 가지만 방향 자체를 정하지는 못합니다.
- 경계 검증 — 이 코드가 프로덕션에 나가도 되는가. 책임지는 주체가 필요합니다.
나머지는 넘겨도 됩니다. 그리고 그 "나머지"가 생각보다 많습니다.
정리
- 코드 생성만 시키면 전체의 15%만 건드리는 셈입니다
- 단계를 쪼개고 출력을 스키마로 고정하면 실패 지점이 격리됩니다
- 평가셋 30건이라도 있으면 프롬프트 변경이 도박에서 개선으로 바뀝니다
- 설계 결정과 최종 검증은 사람이 남습니다
다음 글에서는 이 파이프라인을 CI에 붙여 회귀를 자동으로 잡는 구성을 다루겠습니다.
댓글 & 토론
Powered by GitHub DiscussionsGitHub Discussions 댓글 시스템 준비 중
GitHub 저장소에서 Discussions 기능을 활성화하고 Giscus를 연동하면 방문자가 GitHub 계정으로 댓글을 남길 수 있습니다.