틀린 건 판단이었고 고친 건 문구였다 — 내 파이프라인으로 내 파이프라인을 만든 기록

1편에서 오픈소스 워크플로 둘을 계승해 여섯 단계 파이프라인으로 다시 짠 이야기를 했다. 만든 다음이 이 글이다.

자기 자신을 재료로 삼았다

이 파이프라인의 개발은 이 파이프라인으로 했다. 도구가 자기 자신을 만드는 순환이다. 새 기능을 붙일 때 분석·아키텍처 단계를 직접 태우고, 거기서 나온 스펙으로 구현하고 테스트 단계로 검증했다.

여기엔 이상한 점이 있다. 도구가 미완성일수록 그 도구로 만드는 다음 판이 나빠지는데 그 나쁨이 곧 다음에 무엇을 고칠지 알려준다. 진행이 껄끄러운 지점이 그대로 결함 목록이 됐다.

이 구조의 값은 결함이 문서가 아니라 사용 중에 드러난다는 데 있다. 프롬프트 워크플로는 컴파일 에러가 없다. 문장이 어색해도 돌아가고, 지시가 모호해도 LLM이 그럴듯한 것을 만들어 낸다. 읽어서는 안 보이고 태워 봐야 걸린다.

변형 내역에 기록된 정정 중 스물여덟 건이 이렇게 나왔다. 갈래를 세면 셋이다.

잡히는 것 — 세 갈래

첫째, 내가 되물었다는 사실 자체가 신호였다. 단계를 하나씩 직접 호출해 돌렸더니 개발 단계가 격리 없이 그대로 실행됐다. 「왜 격리가 안 되지?」 하고 되물었고 답은 전체 흐름으로 시작해야 격리된다였다. 규칙은 있었고 진입부가 그걸 안 알려줬을 뿐이다. 내가 물었다는 건 도구가 안내를 빠뜨렸다는 뜻이다. 그래서 그 지점에 게이트를 넣었다. 이후로는 진행이 막힐 때마다 「내가 지금 뭘 묻고 있나」를 결함 목록에 먼저 적었다.

둘째, 단어가 자기 설명을 못 하면 매번 풀어 써야 했다. 모드 이름 하나를 수학 기호에서 따온 외래어로 지었는데 본문이 그 단어를 쓸 때마다 괄호로 뜻을 덧붙이고 있었다. 학술어로 지은 구조 용어들도 같았다. 정작 개발하면서는 그 말을 쓰지 않았다. 하루에만 여덟 번을 갈아치웠다. 풀어 쓰고 있다는 것 자체가 그 단어가 일을 안 한다는 신호다.

셋째, 한 문장이 서로 다른 두 경우를 뭉개고 있었다. 테스트 단계에 「실행 환경이 없으면 멈춘다」는 규칙이 있었는데 여기엔 테스트 러너 자체가 없는 경우와 러너는 있고 실제 DB만 없는 경우가 같이 들어 있었다. 후자는 멈출 이유가 없다. 그런데 한 문장으로 묶여 있어서 나는 테스트를 통째로 건너뛰었다. 둘을 분리하고 나서야 각각에 맞는 동작이 생겼다.

셋 다 문서를 다시 읽어서는 안 보였고 실제로 그 경우를 만나야 걸렸다.

가장 아팠던 것 — 실수의 소유권을 다시 정하기

한 번은 개발 단계에서 보조 에이전트를 붙여야 하는데 계속 안 붙이고 진행했다. 구현에 들어가기 전에 기존 코드와 설계 계약을 먼저 훑어 주는 역할이다. 원인을 짚어 보니 내가 명백히 잘못 판단했다. 앞 작업에서 「이건 가벼우니 생략」이라 정해 놓고 다음 작업에서 재평가 없이 그 결정을 관성으로 끌고 갔다.

여기서 끝낼 수 있었다. 사용자가 잘못 판단했으니 도구는 죄가 없다.

그런데 안내 문구를 다시 읽어 보니 그 오류를 자연스럽게 유도하고 있었다. 생략 기준이 적혀 있지 않았고, 작업마다 다시 판정하라는 요구도 없었고, 정보가 없을 때 어느 쪽이 안전한지도 비어 있었다. 나만 미끄러진 게 아니라 누구든 같은 자리에서 미끄러질 구조였다.

기본값부터 뒤집었다. 정보가 부족하면 생략이 아니라 켜는 쪽을 기본으로 두고 작업마다 다시 판정하게 했다. 앞 결정을 관성으로 끌고 가지 못하게 막았다. 검수 쪽에 이미 「의심되면 전체를 본다」는 규칙을 뒀는데 그 대칭을 여기에도 세운 셈이다. 어느 쪽으로 틀릴지 모를 때 어느 쪽으로 틀릴지를 미리 정해 두는 것이 기본값의 일이다.

그래서 이렇게 적고 고쳤다.

판단 오류는 사용자, 유도는 도구 — 후자가 고칠 지점이다.

같은 판단을 다른 자리에서 한 번 더 했다. 이번엔 틀린 쪽이 사람이 아니었다. 화면 설계 단계에서 진행 중이던 에이전트가 어떤 편집기 화면을 「가벼움」으로 오분류해 시각 검증을 건너뛰었다. 조작이 화면 자체를 좌우하는 화면이라 건너뛰면 안 됐다. 이것도 그 자리의 판단 문제지만 같은 오분류가 재발 가능했기에 가드를 넣었다. 조작이 화면을 좌우하는지 자가 점검하게 하고 해당되면 진행자 단독으로 생략하지 못하게 막았다.

두 사례는 틀린 주체가 달랐다. 한 번은 나였고 한 번은 에이전트였다. 그런데 고칠 자리는 같은 기준으로 정해졌다. 잘못한 주체가 누구냐가 아니라 그 잘못이 재발 가능한 구조에서 나왔느냐다. 재발 가능하면 사람을 탓해도 다음에 또 일어난다.

안 잡히는 것 — 도그푸딩도 자기 검토다

도그푸딩은 강력하지만 결정적인 구멍이 있다. 내가 만든 것을 내가 본다.

아키텍처 단계에 설계를 비판하는 절차를 넣어 뒀는데 실사용에서 맹점을 놓쳐 구현 중에 터진 적이 있다. 원인을 보니 그 비판이 작성 근거를 다 아는 자리에서 돌고 있었다. 왜 그렇게 설계했는지 아는 상태로는 그 설계가 틀렸을 가능성이 잘 보이지 않는데, 내가 도구를 보는 눈도 정확히 같은 상태다.

그래서 독립성을 조작 가능한 형태로 정의했다. 비판을 별도 컨텍스트의 독립 에이전트로 넘기되 결정만 전달하고 그 결정에 이른 맥락은 주지 않는다. 보안·확장·장애 전파·사전 부검처럼 서로 다른 각도를 병렬로 돌리고, 나온 지적을 합친다. 근거를 모르는 쪽이 보는 것이 근거를 아는 쪽에는 안 보인다.

이 조치가 도그푸딩의 한계를 없애 주지는 않는다. 다만 한계가 있다는 사실을 도구 구조에 반영했다. 내가 못 보는 자리를 내가 채우려 하지 않고 안 보는 눈을 하나 만들어 붙였다.

학습

← 전체 글 목록