문서가 노후화되지 않도록 유지하는 에이전트를 구축한 방법
요약
자율 코딩 에이전트 운영 시 발생하는 문서 노후화 문제를 해결하기 위해, 코드 변경 후 문서를 자동으로 동기화하는 전용 워크플로우 구축 방법을 소개합니다.
핵심 포인트
- 자율 에이전트는 코드 변경에 집중하므로 문서 업데이트가 누락되기 쉬움
- 단순 프롬프트 추가가 아닌 별도의 '문서 동기화 패스' 구축이 필요함
- 코드 변경 사항(diff)을 캡처하여 문서와 일치시키는 가드레일 설정이 핵심
요약 (TL;DR)
저는 모든 diff(차이점)를 일일이 지켜보지 않아도 프로젝트에 변경 사항을 반영하는 자율 코딩 에이전트 (autonomous coding agent)를 운영하고 있습니다. 몇 달 동안 문서는 조용히 부식되었습니다. 더 이상 존재하지 않는 플래그 (flags)를 설명하는 README, 세 번의 리팩토링 (refactor) 전에 이미 삭제한 설정 파일에 대한 설치 단계 등이 방치되었습니다. 저는 모든 변경 사항이 발생한 후에 에이전트에게 "문서가 여전히 현실과 일치하는가"를 확인하는 전용 단계를 부여함으로써 이 문제를 해결했습니다. 이때 모든 커밋을 문서 에세이로 만들지 않도록 자체적인 가드레일 (guardrails)을 설정했습니다. 어떻게 작동하는지, 그리고 그 과정에서 무엇이 망가졌는지 소개합니다.
문제점
문서는 부식됩니다. 모든 엔지니어는 이 사실을 알고 있습니다. 보통은 사람이 진행하는 속도에 맞춰 천천히 부식됩니다. 누군가 함수 시그니처 (function signature)를 변경하고 README를 업데이트하는 것을 잊어버리면, 6주 뒤에 팀원이 더 이상 존재하지 않는 코드 버전을 설명하는 지침을 따르느라 한 시간을 허비하게 됩니다.
이제 루프 (loop) 안에 자율 에이전트를 넣어보겠습니다. 사람이 각 diff를 검토하기 전에 하루에도 수십 개의 작은 변경 사항을 만들어내는 에이전트 말입니다. 부식은 더 이상 6주가 걸리지 않습니다. 6일 만에 일어납니다.
저는 이를 설치 가이드에서 처음 발견했습니다. 문서에는 "--mode 플래그와 함께 configure.py를 실행하세요"라고 적혀 있었습니다. 하지만 2주 전, 제 에이전트가 관련 없는 변경 사항의 일부로 해당 스크립트를 리팩토링 (refactor)했고 플래그 이름을 --profile로 변경해 놓은 상태였습니다. 이름 변경은 정확했습니다. 코드도 정확했습니다. 테스트도 통과했습니다. 하지만 아무도 문서를 업데이트하지 않았습니다. 문서를 업데이트하는 것이 누구의 업무도 아니었기 때문입니다. 에이전트는 주어진 작업에 집중하고 있었고, 저는 변경되어야 할 산문 (prose)이 변경되지 않은 것을 잡아낼 만큼 모든 diff를 면밀히 읽고 있지 않았습니다.
더 깊은 문제는 이것입니다: 자율 에이전트는 "내가 지시받은 작업"을 최적화하지, "저장소 전체의 상태"를 최적화하지 않습니다. 코드 변경은 주요 결과물 (artifact)입니다. 문서는 역사적으로 인간만이 유지 관리하는 것을 기억해 온 부수 효과 (side effect)입니다. 루프에서 인간을 제거하면 그 부수 효과는 그냥... 일어나지 않게 됩니다.
저에게는 세 가지 선택지가 있었습니다:
- 모든 diff(차이점)의 문서 영향도를 직접 검토한다 (자동화의 의미가 퇴색됨)
- 관리되지 않는 운영의 비용으로 문서 노후화(doc rot)를 수용한다 (특정 리포지토리(repo) 규모를 넘어서면 유지 불가능함)
- "문서 동기화 유지"를 에이전트 자체 워크플로우(workflow)의 일급 시민(first-class) 단계로 만든다
저는 3번 옵션을 선택했습니다.
해결 방법
1단계: 사후 고려 사항이 아닌, 전용 동기화 패스(sync pass) 구축
이 방식의 첫 번째 버전은 부끄러울 정도로 순진했습니다. 메인 프롬프트(prompt)에 "필요한 경우 문서도 업데이트하세요"라는 한 줄을 추가했을 뿐이었습니다. 결과는 거의 아무런 효과가 없었습니다. "필요한 경우"라는 표현은 바쁜 사람이 이를 그냥 건너뛰는 것과 마찬가지로, 모델이 주요 작업에 집중할 때 조용히 무시해 버릴 법한 모호한 지침입니다.
실제로 효과가 있었던 방법은 문서 동기화(doc sync)를 별도의 패스로 분리하여, 코드 변경이 완료되고 테스트가 통과된 후 별도의 단계로 실행하는 것이었습니다:
1. 에이전트가 코드 변경을 완료하고 테스트를 통과함
2. Diff(차이점)를 캡처함 (변경 된 파일, 추가/삭제/이름 변경된 함수, 수정된 설정 키 등)
3. 좁은 범위로 제한된 두 번째 에이전트 호출을 실행함:
...
마지막 포인트는 제가 예상했던 것보다 더 중요했습니다. 초기에는 5단계를 제대로 제어(gate)하지 못해서, 의미 있는 변화가 없을 때조차 문서 동기화 에이전트가 거의 매 실행마다 변경할 "무언가"를 찾아내곤 했습니다. 이에 대한 자세한 내용은 가드레일(guardrails) 섹션에서 다루겠습니다.
2단계: 전체 리포지토리를 읽지 않고 "어떤 문서가 관련 있는지" 범위 지정하기
매번 변경 사항이 생길 때마다 에이전트에게 전체 문서 폴더를 건네주며 "업데이트가 필요한 것이 있나요?"라고 물을 수는 없습니다. 이는 느리고 비용이 많이 들 뿐만 아니라, 더 나쁜 점은 모델이 이미 괜찮은 내용까지 친절하게 다시 써버리도록 유도한다는 것입니다.
대신, 저는 가벼운 역색인(reverse index)을 구축했습니다. 즉, 어떤 문서 파일이 어떤 소스 파일, 설정 키(config keys), 또는 CLI 플래그(flags)를 참조하는지를 정리한 것입니다. 대단한 기술은 아닙니다. 주로 문서 디렉터리 전체에서 파일 이름, 함수 이름, 플래그 문자열을 대상으로 grep을 수행하여 구축하며, 한 번 구축된 후에는 점진적으로 갱신됩니다. 만약 diff가 configure.py와 --mode 플래그를 건드린다면, 동기화 패스는 이미 configure.py나 --mode를 언급하고 있는 문서들만 살펴봅니다. 그 외의 모든 것은 구조적으로 범위(scope)에서 제외됩니다.
def find_affected_docs(changed_symbols, doc_index):
affected = set()
for symbol in changed_symbols:
...
이것은 두 가지 효과를 가져왔습니다. 동기화(sync) 과정이 병목 현상 없이 모든 변경 사항마다 실행될 수 있을 만큼 충분히 빨라졌고, 영향 범위(blast radius)를 작게 유지했습니다. 에이전트는 건드릴 이유가 없는 문서는 문자 그대로 다시 쓸 수 없습니다. 왜냐하면 해당 문서가 에이전트의 컨텍스트 윈도우(context window)에 들어오지 않기 때문입니다.
3단계: 드리프트 탐지(Drift detection)는 느낌(vibes)이 아니라 주장(claims)에 기반해야 합니다
동기화 에이전트에 사용한 첫 번째 프롬프트는 "문서의 정확성을 검토하라"는 것이었습니다. 이는 너무 모호합니다. 이로 인해 아무도 요청하지 않은 과도한 재작성(rewrites), 톤 변화, 그리고 서식 변경(reformatting)이 발생합니다.
효과가 있었던 방법은 작업을 주장 검증(claim verification)으로 재정의하는 것이었습니다. 문서에서 구체적이고 확인 가능한 주장(예: "이 스크립트는 --mode 플래그를 허용한다", "설정은 settings.yaml에 있다", "3단계는 선택 사항이다")을 추출한 뒤, 각 주장을 현재 코드와 대조하여 확인하는 방식입니다. 이제 거짓이 된 주장들만 수정됩니다. 스타일, 구조, 관련 없는 섹션 등 그 외의 모든 것은 명시적으로 금지됩니다.
영향을 받는 문서 섹션의 각 문장에 대해:
- 이것이 코드 동작, 파일 경로, 플래그 또는 설정 키(config key)에 대한 사실적 주장인가?
- 만약 그렇다면: 현재의 디프(diff)가 이 주장을 거짓으로 만드는가?
...
이 한 가지 변화만으로 동기화 에이전트의 "오탐(false positive)" 편집률이 극적으로 감소했습니다. 거의 매 실행마다 무언가를 건드리던 상태에서, 실제로 내용이 오래된(stale) 경우에만 문서를 건드리는 상태로 바뀌었습니다.
4단계: 가드레일(Guardrails), 에이전트는 과하게 설명하는 것을 좋아하기 때문입니다
문서 동기화 단계가 작동하자 새로운 문제가 발생했습니다. 에이전트가 문서를 쓰는 것을 좋아하게 된 것입니다. README를 건드릴 기회만 생기면 아무도 요청하지 않은 문맥을 한 단락 추가하거나, 목록을 표로 재구성하거나, 한 줄짜리 노트를 세 문장으로 확장해 버리곤 했습니다. 기술적으로 이 중 틀린 것은 없었습니다. 하지만 이 모든 것이 범위 이탈(scope creep)이었습니다.
저는 동기화 에이전트의 지침에 명시적인 제약 조건을 추가했습니다:
- 문서 파일당 최대 diff 크기 제한 (전체 재작성이 아닌 몇 줄 수준)
- 새로운 섹션 추가 금지, 구조 변경 금지, 톤 변경 금지
- 하나의 코드 diff로 인해 N개 이상의 문서 파일이 수정되어야 하는 경우, 모든 파일을 수정하는 대신 작업을 중단하고 나에게 알림 — 이는 보통 문서가 오래된 것이 아니라 코드 diff가 너무 광범위하다는 신호임
- 모든 문서 편집은 해당 편집이 무효화한 구체적인 주장(claim) 및 원인이 된 diff와 함께 로그에 기록되어, 사전에 검토하는 대신 사후에 감사(audit)할 수 있도록 함
마지막 포인트는 제가 이 에이전트 설계의 다른 모든 곳에서 사용하는 "조용히 실패하지 말고, 크게 실패하라 (fail loud, not silent)" 원칙과 동일합니다. 검토 불가능한 재작성이 제 리포지토리(repo)에 조용히 반영되는 것보다, 제가 무작위로 확인할 수 있는 로그 항목을 보는 편이 훨씬 낫습니다.
교훈 (Lessons Learned)
-
"필요하면 문서를 업데이트하세요"는 지침이 아니라 동전 던지기나 다름없습니다. 모호하고 조건적인 지침은 바쁜 사람이 놓치는 것과 마찬가지로, 작업 압박을 받는 에이전트들도 건너뛰어 버립니다. 문서 동기화는 메인 작업의 각주가 아니라, 자체적인 성공 기준을 가진 별도의 예정된 단계(scheduled pass)가 되어야 했습니다.
-
출력의 범위를 정하기 전에 입력의 범위를 정하세요. 가장 큰 성과는 역색인(reverse index)을 구축하여 동기화 에이전트가 실제 diff와 관련된 문서만 볼 수 있게 한 것이었습니다. 과도하게 의욕적인 재작성으로 인해 발생했던 모든 문제는 에이전트가 컨텍스트 내에서 다루는 문서의 표면적(surface area)이 넓어질수록 악화되었고, 범위를 좁힐수록 개선되었습니다.
-
"정확성을 검토하라"보다 "주장 검증(Claim verification)"이 효과적입니다. 작업을 개방형 정확성 검토 대신 "이 구체적이고 검증 가능한 주장들을 확인하라"로 전환한 것이 범위 이탈(scope-creep) 문제를 해결한 핵심이었습니다. 개방형 검토 프롬프트는 개방형 재작성을 유도합니다.
-
에이전트의 유능함은 제한(cap)이 없다면 오히려 부담이 됩니다. 문서 동기화 단계는 틀려서 실패한 것이 아니라, 너무 의욕적이었기 때문에 실패했습니다. diff 크기 제한과 너무 많은 파일이 연루되었을 때 작업을 강제로 중단하는 기능이 드리프트 탐지(drift-detection) 로직 자체보다 더 중요하다는 것이 밝혀졌습니다.
조용한 문서 수정은 수정이 없는 것보다 더 나쁩니다. 어떤 주장(claim)이 어떤 수정을 트리거했는지 정확히 기록(logging)해 두면, 모든 README를 처음부터 다시 읽는 대신 5분 만에 일주일 치의 문서 변경 사항을 감사(audit)할 수 있습니다. 사후에 감사할 수 없다면, 방치된 상태로 실행되게 두지 마세요.
다음 단계
현재 동기화 패스(sync pass)는 문서를 검증 가능한 주장이 포함된 산문(prose)으로만 이해합니다. 다이어그램(diagram)은 건드리지 않으며, 문서 파일 전체가 단순히 부정확해진 것이 아니라 완전히 쓸모없게 된 경우(obsolete)를 식별하지는 못합니다(이는 여전히 "알림 받기" 케이스에 해당합니다). 저는 영향을 받은 문서 인덱스(affected-docs index)를 확장하여, 단순히 문장 수준의 드리프트(drift)를 포착하는 것을 넘어 "이 가이드 전체가 더 이상 존재하지 않는 워크플로를 설명하고 있다"는 점을 잡아낼 수 있도록 작업 중입니다. 이는 플래그 및 경로 확인(flag-and-path checking)보다 더 모호한(fuzzy) 문제입니다.
마무리
실제 코드베이스를 대상으로 어떤 종류의 자율 에이전트(autonomous agent)를 실행하든, 사람이 모든 디프(diff)를 검토하는 것을 멈추는 순간 문서가 가장 먼저 조용히 부패(rot)하게 됩니다. 문서 동기화를 메인 프롬프트(main prompt)에 덧붙인 희망 사항으로 취급하지 말고, 자체적인 가드레일(guardrails)을 갖춘 별도의 단계로 취급하세요.
이 내용이 유용했다면, 자율 코딩 에이전트(autonomous coding agents) 실행에 관한 더 많은 빌드 인 퍼블릭(build-in-public) 포스트를 위해 저를 팔로우해 주세요. 아직 사용해 보지 않으셨다면 Claude Code를 시도해 보세요. 제가 이 모든 것을 구축해 온 기반입니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기