80개 이상의 마이크로서비스를 위한 AI 시스템 구축기: 6개월 후 팀 전체가 사용하게 되다
요약
AI 시스템을 여러 마이크로서비스에 걸쳐 구축하는 과정에서 발생한 문제점과 교훈을 다룹니다. 특히, 규칙(rule)이나 제약 조건을 프롬프트 파일에 반복적으로 복사/붙여넣기 하는 방식의 위험성을 지적하며, 단일 진실 공급원(Single Source of Truth)의 중요성을 강조합니다.
핵심 포인트
- 규칙은 여러 곳에 분산시키지 말고 중앙에서 관리해야 합니다. (SSOT)
- 반복적인 규칙 명시는 모델에게 혼란과 비용을 초래할 수 있습니다.
- AI 시스템 구축 시, 일관성과 중복 제거가 핵심 과제입니다.
지난 4월, 저는 Claude Code를 사용하여 80개 이상의 마이크로서비스에 걸쳐 에픽(epic)을 PR 준비가 완료된 코드까지 가져가는 시스템에 대해 글을 썼습니다. 만약 그 게시글을 읽으셨다면, 제가 이미 무언가를 완성한 사람처럼 들렸을 겁니다.
하지만 그렇지 않았습니다. 이 글은 제가 계획하지 않았던 후속 내용입니다. 여기에는 무엇이 잘못되었는지, 제가 무엇을 잘못했는지, 그리고 저를 위해 만든 도구가 어떻게 기술 팀 전체, 모든 신규 입사자, 심지어 코드를 작성하지 않는 사람들에게까지 사용되게 되었는지를 다룹니다.
한 파일에 '절대 하지 마라(DO NOT)'를 여덟 번 적다
몇 달이 지나면서 저는 제 자신의 규칙들을 믿기 시작했습니다. 가장 아팠던 것은 커밋(commits) 관련 부분이었습니다. 제 프롬프트에는 시스템이 절대 git commit을 실행해서는 안 된다고 대문자로 명시되어 있었습니다. 이것은 제가 가장 신경 쓰는 규칙입니다. 왜냐하면 역사가 되기 전에 모든 diff를 읽어보고 싶기 때문입니다. 어느 날, 저는 이 규칙이 불안하게 느껴지는 이유를 찾아보았고, 두 가지 것을 발견했습니다. 제 자체 설정 파일이 git 명령을 명시적으로 허용하고 있었던 것입니다. 그리고 저의 참고 문서 중 하나에는 준비된 git add && git commit 코드 조각이 포함되어 있었습니다. 저는 모델에게 18군데에서 절대 안 된다고 말하면서, 다른 두 군데에서는 권한과 예시를 제공하고 있었던 겁니다.
그전까지 제가 잘못된 것에 대한 해결책은 항상 같았습니다. 프롬프트 파일을 열고 대문자로 한 줄을 추가하는 것이었습니다. 필수(MANDATORY). 절대 안 됨(NEVER). 만약을 대비해 경고 이모지까지 붙였습니다.
그래서 어느 주말에 저는 제가 구축한 모든 것을 감사했습니다. 동일한 일련의 규칙들(커밋 금지, 린트(lint) 금지, 단계 건너뛰기 금지)이 18개의 다른 파일에 복사되어 붙여넣어져 있었습니다. 그중 하나의 파일에는
저는 조금 바보 같다는 느낌이 들었습니다. 이것은 제가 다른 사람의 풀 리퀘스트(pull requests)에서 지적하는 것과 정확히 같습니다: 중복된 로직과 단일 진실 공급원(single source of truth)의 부재입니다. 저는 절대 그것을 승인하지 않았을 겁니다. 그리고 이 코드는 저 자신이 좌절감에 차서 한 줄씩 작성한 것이었습니다.
문제는 복사-붙여넣기 규칙이 적용된 어떤 코드베이스에서 예측할 수 있는 피해였습니다:
- 드리프트(Drift). 제가 한 파일의 규칙을 변경했는데, 다른 17개 파일은 조용히 그와 다르게 작동했습니다. 모델은 어느 복사본이 진짜인지 추측해야 했습니다.
- 희석(Dilution). 모든 것이 필수적(MANDATORY)일 때, 아무것도 필수적이지 않게 됩니다. 모델은 대출 계산을 보호하는 규칙과 중괄호 위치에 대한 규칙을 구분할 수 없었습니다.
- 비용(Cost). 매번의 턴마다 코드를 읽어야 할 때도 똑같은 금지 사항들을 다시 읽어야 했습니다.
요청하는 것과 방지하는 것은 다르다
이 문제를 해결하기 위해 두 가지 부분이 필요했습니다.
첫 번째는 지루한 작업이었습니다: 하나의 규칙집을 만드는 것이었습니다. 모든 규칙에 GIT-1(
완벽한 방어막은 아닙니다. 다른 명령어 안에 감싸진 명령어가 여전히 매처(matcher)를 통과할 수 있기 때문에, 저는 작성된 규칙도 유지하고 주기적으로 권한 파일을 확인합니다. 하지만 일상적인 동작의 차이는 즉각적이었습니다.
스스로 디버깅하는 법을 배우다 (It learned to debug, which I never planned)
4월 버전은 한 가지 기능만 했습니다: 에픽(epic)을 코드로 변환하는 것이었습니다.
하지만 새로운 기능을 개발하는 것이 제 주간 업무의 대부분은 아닙니다. 상당 부분은 지원(support)입니다. 프로덕션 환경에서 무언가 실패하거나, 숫자가 잘못되었거나, 누군가가 그 이유를 당일 내로 알아야 합니다.
그래서 저는 시스템에 읽기 전용 에이전트(read-only agents)를 부여했습니다. 하나는 로그(logs)를 검색하고, 하나는 MongoDB를 쿼리하며, 하나는 SQL을 실행하고, 하나는 메트릭(metrics)을 읽습니다. 이들 중 어느 것도 무언가를 쓸 수는 없습니다.
로그 에이전트의 첫 번째 버전은 저에게 무언가를 가르쳐주었습니다. 저는 문제점을 설명했고, 그것은 자신이 상상하는 로그 메시지 형태를 검색했습니다. 아무것도 찾지 못하자, 완전한 확신을 가지고 '없다'고 보고했습니다.
해결책은 놀라울 정도로 간단합니다: 로그를 검색하기 전에, 코드에서 실제 로그 문자열을 먼저 검색해야 합니다. 이것이 제가 디버깅할 때 직접 하는 일입니다. 다만 저는 그것을 글로 적어본 적이 없었을 뿐, 그 과정 자체가 하나의 단계라는 것을 깨닫지 못했습니다.
우리가 해결하는 모든 사고(incident)는 이제 런북(runbook)이 됩니다. 현재 29개가 있습니다. 다음에 같은 문제가 발생하면, 시스템은 제로(zero)부터 시작하는 대신 런북에서 시작하며, 그 주에 지원 업무를 맡은 사람도 마찬가지입니다.
팀원이 풀 리퀘스트(pull request)를 열었던 날
5월에 동료가 해당 프레임워크에 대한 풀 리퀘스트를 열었습니다. 이 기능은 서비스의 로컬 클러스터를 띄워 디버깅할 수 있는 기술이었습니다. 제가 요청한 것은 아니었습니다.
몇 주 후 다른 사람이 제가 방금 설명했던 데이터베이스와 로그 에이전트를 추가했습니다. 지금까지 세 명의 팀원이 기여했습니다.
이는 어떤 토큰 개수보다 저에게 더 중요했습니다. 지난 4월에 저는 이것이 '그냥 팀이 필요로 하는 것'이라고 썼습니다. 솔직히 말하자면, 그때는 제가 필요한 것이었고, 팀원들도 그렇게 해주기를 바라고 있었습니다. 다른 사람의 풀 리퀘스트가 첫 번째 실질적인 증거였습니다.
저는 그 diff를 두 번 읽었던 기억이 납니다. 복잡하지 않았습니다. 제가 그것을 두 번 읽은 이유는 누군가가 제 프롬프트 파일들을 충분히 깊이 살펴보고 확장할 가치가 있다고 판단했기 때문입니다. 그때까지 저는 무언가가 어디에 있는지 아는 유일한 사람이었습니다.
제가 만들지 않은 사람들에게 사용되기 시작하다
오늘날 기술팀 전체가 이 리포지토리에서 작업합니다. 제가 이를 발표하거나 추진하지 않았습니다. 이는 한 명씩 퍼져나갔는데, 보통 누군가가 동료에게 오후를 걸릴 만한 답변을 2분 만에 얻는 것을 목격한 후에였습니다.
이제 신규 입사자들이 여기서 시작합니다. 80개 이상의 서비스를 가진 회사에 새로 온 사람이라면 첫 달을 경험적으로 알고 있습니다. 어떤 서비스가 무엇을 소유하고 있는지 모르고, 질문할 때마다 선임 엔지니어를 방해하는 것 같은 기분이 들죠. 이제 신규 입사자는 먼저 시스템에게 질문합니다. 시스템은 서비스 맵과 코드 자체로부터 답변하며, 절대 한숨 쉬지 않습니다.
새로 합류하는 사람들에게 던지는 첫 질문은 예전에는
가장 놀라웠던 부분은 제품 팀이었습니다. 그들은 코드를 작성하지 않는데도 이 저장소(repo)를 열어보는 것을 본 적이 없었기 때문입니다. 하지만 그들은 우리가 어떤 외부 공급업체(third-party vendors)에 의존하는지, 그리고 각 흐름(flow)이 어느 것 뒤에 위치하는지에 대한 단순한 질문을 던지는 데 사용합니다. 이전에는 엔지니어에게 메시지를 보내고 시간이 되는 사람을 기다려야 했습니다. 이제는 직접 질문하고 실제 코드에 근거한 답변을 얻습니다.
저는 코드를 전달하기 위한 파이프라인을 구축했습니다. 사람들이 가장 많이 찾는 것은 더 간단합니다. 시스템이 어떻게 작동하는지 물어보고 바로 답을 얻는 방법입니다.
쌓여간 작은 변화들
리뷰어(Reviewers). 이제는 제가 보기 전에 계획이나 diff를 읽는 리뷰 에이전트가 있습니다. 여기에는 특히 핀테크 리스크를 확인하고 작업을 차단할 수 있는 에이전트도 포함됩니다. 이전에는 이러한 차단이 프롬프트의 문장 하나로 이루어졌습니다. 하지만 지금은 워크플로우가 확인하는 상태(state) 조각이기 때문에 우회할 수 없습니다. 제가 정한 규칙 중 하나는 리뷰어가 저자만큼 능력이 뛰어난 모델이어야 한다는 것입니다.
작업에 적합한 모델. 로그를 가져오는 작업에는 가장 비싼 모델이 필요하지 않습니다. 깊은 코드 분석(Deep code analysis)과 테스트 주도 구현(test-driven implementation)에서는 그렇습니다. 이제 각 에이전트는 자신의 작업에 맞는 모델로 실행됩니다.
두 번째 코드베이스. 시스템은 이전에는 하나의 저장소만 알았지만, 이제는 두 개의 분리된 세트의 저장소 전반에서 작동합니다.
4월의 나에게 해주고 싶은 말
- 만약 세 번째로 같은 규칙을 작성하고 있다면, 구조적인 문제가 있는 것입니다. 문제는 모델이 아닙니다.
- 어떤 규칙들이 불변(invariant)인지 결정하고, 그 규칙들은 프롬프트 외부에서 강제하세요.
- 실제로 하는 작업에 맞춰 구축하세요. 저에게는 코드 생성 기능이 더 나은 데모를 만들지만, 실제로는 디버깅을 위해 사용했습니다.
- 준비되었다고 느껴지기 전에 공유하세요. 이 시스템의 가장 좋은 부분들은 제가 작성한 것이 아닙니다.
- 누가 실제로 사용하는지 지켜보세요. 저는 에픽(epic)을 배포하는 엔지니어를 위해 이것을 만들었습니다. 신규 입사자들과 제품팀도 여기서 많은 것을 얻고, 그들은 제가 부가 기능으로 취급했던 것으로 사용합니다.
수치로 보는 성과
저는 깔끔한 전후 비교 벤치마크를 가지고 있지 않으며, 스스로 만들어내고 싶지도 않습니다. 대신 셀 수 있는 것들을 알려드리겠습니다:
- 92개의 서비스가 오늘날 매핑되었는데, 이는 지난 4월에 언급했던 80개 이상의 서비스에서 증가한 수치입니다.
- **31개의 기능(feature)**이 프레임워크 내에 자체 작업 공간을 갖게 되었습니다.
- 실제 운영 중 발생한 사고(production incidents)를 통해 **29개의 실행 매뉴얼(runbooks)**이 만들어졌습니다.
- 3명의 팀원이 여기에 코드를 기여했으며, 전체 기술팀에서 사용하고 있습니다.
- 첫 번째 게시물에서 언급했던 토큰 수치는 여전히 유효합니다. 무거운 읽기 작업이 별도의 에이전트(agent)에서 이루어지기 때문에, 에픽당 약 75,000개에서 15,000개로 줄었습니다.
모든 것이 어떻게 연결되는가
위의 내용을 건너뛰었다면, 이것이 전체 시스템을 한 장의 그림으로 보여줍니다. 세 가지 종류의 요청(질문, 에픽, 또는 사고)이 들어옵니다. 이들은 모두 동일한 공유 지식으로부터 읽어오고 동일한 가드레일(guardrails) 내에서 실행되며, 각 요청이 생성하는 결과물은 다음 사람을 위해 다시 입력됩니다.
몇 가지는 변하지 않았습니다. 저는 여전히 모든 단계에 승인합니다. 모든 디프(diff)를 읽고, 모든 풀 리퀘스트(pull request)를 제가 직접 올립니다. 그리고 이것이 바뀌지 않을 것이라고 기대하며, 바뀌기를 원하지도 않습니다.
흥미로운 부분은 엔지니어를 루프에서 제거하는 것이 아니었습니다. 그것은 엔지니어가 머릿속에 담아둘 컨텍스트의 양을 줄이는 것이었습니다.
만약 여러분이 비슷한 것을 구축하고 있다면, 한 가지 알고 싶습니다. 여러분의 규칙 중 어떤 것이 벽(walls)이었고, 어떤 것이 단지 요청(requests)에 불과했는지요?
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기




