Paul Jialiang Wu agentic-portfolio English 中文 Español 日本語✉️ 무료 메일링 리스트
← 포트폴리오로 돌아가기

AI-native 시리즈 · 엔지니어링 관행

레포에 다음으로 들어올 개발자는 인간이 아니다. 준비를 위한 여섯 가지 관행.

1분 요약

적대적 AI가 내 레포를 처음부터 끝까지 읽고, 경로 순회(path traversal) 취약점을 포함해 내가 놓친 버그 21개를 찾아냈다. 이런 독자가 이제는 새로운 정상이다. 그래서 나는 코드베이스를 여섯 가지 관행 — OOP, AI-native, 컨텍스트 엔지니어링, 하니스 엔지니어링, 루프 엔지니어링, 그래프 엔지니어링 — 으로 리팩터링하고 모든 것을 측정했다: 코드 품질 56→95, AI 응답 130s→3s, 머지 전 버그 9개 수정. 각 관행이 무엇을 뜻하는지 설명하고 그 근거가 되는 영수증을 함께 보여준다.

아래 각 관행은 똑똑한 15살 아이에게 설명하듯 풀어 쓰고, 하나의 레포에서 일주일간 실제로 작업하며 얻은 숫자로 뒷받침한다. 약 8분 분량.

The next developer in your repo isn't human — six practices with receipts: 56→95 quality, 130s→3s latency, 21 bugs found and 9 fixed
먼저 스코어보드부터. 아래 관행들이 각 숫자가 어떻게 움직였는지 설명한다.

훑어보지 않는 독자

지난주, 브랜치를 머지하기 전에 나는 적대적 AI 리뷰어에게 내 레포를 넘기며 단 하나의 지시만 내렸다: find how this fails in production. No compliments. (번역: 이게 프로덕션에서 어떻게 실패하는지 찾아라. 칭찬은 필요 없다.) 그 결과 21건의 발견 사항이 돌아왔다. 그중 하나는 실제 경로 순회 취약점이었다 — 어휘적 검사만으로는 Recordings/../../.ssh/id_rsa 을 그냥 통과시켰을 것이다. 나는 그 파일을 직접 검토했었다. 그런데도 놓쳤다.

바로 그 순간 이 개념은 내게 더 이상 추상적이지 않았다: 이제 당신의 코드를 읽는 다음 개발자는 지친 채로 변경 내용을 대충 훑어보는 인간이 아니다. 1만 줄 전체를 읽고, 모든 분기를 따라가며, 레포의 구조를 문자 그대로 받아들이는 에이전트다. 코드베이스가 인간에게만 읽히는 구조라면, 최고의 독자이자 가장 가혹한 리뷰어를 그냥 무용지물로 만드는 셈이다.

그래서 질문 자체가 "이 코드는 깔끔한가?"에서 "에이전트가 여기서 작업할 수 있는가?"로 바뀌었다. 여섯 가지 실천법이 이 질문에 답한다. 어느 하나도 새로운 것은 없다. 새로운 것은 그것들이 지금 무엇을 위해 쓰이느냐다..

Six practice cards: OOP, AI-native, context engineering, harness engineering, loop engineering, graph engineering — each with its receipt
여섯 가지 실천법, 하나의 테스트. 모든 영수증은 같은 주에, 같은 레포에서 나왔다.

1 · OOP — 구조가 곧 에이전트 가독성이다

쉬운 말로: 객체지향 프로그래밍이란 코드를 작은 단위로 묶어 각자 하나의 역할만 맡기고 그 수행 방식은 숨기는 것이다. 그 단위는 "마크다운을 주면 청크를 준다"는 약속 하나만 지킨다 — 외부에서는 그 이상 알 필요가 없다.

OOP를 지지하는 고전적인 논거는 인간의 유지보수성이었다. 새로운 논거는 더 강력하다: 이음매(seam)야말로 에이전트가 안전하게 작업할 수 있는 지점이다. 내 수집(ingestion) 스크립트가 하나의 절차적 덩어리였을 때, 자동 리팩토링 루프는 56/100점을 매기고는 거의 개선하지 못했다(+2점 올리고 포기했다). 그것을 세 개의 이음매로 재구성하자 — 청크 분할 담당 클래스MarkdownChunker와 임베딩 생성 담당 클래스OpenAIEmbedder, a KnowledgeStore — 이 중 어느 하나든 다른 것들을 건드리지 않고 교체할 수 있게 되었다(다른 임베딩 제공자, 다른 데이터베이스). "로컬 임베더로 바꿔줘"라는 요청을 받은 에이전트는 이제 파일 전체가 아니라 클래스 하나만큼의 파급 범위를 갖는다.

영수증: 레포의 Python 영역 품질 점수가 56 → 95/100로 상승했다 — 타이핑 100%, 독스트링 100%, 중첩 100% — 그러면서도 레포 자체의 테스트 게이트는 그 과정 내내 그린 상태를 유지했다.

2 · AI-native — 에이전트를 일급 사용자로 대우하기

쉬운 말로: AI-native 레포는 에이전트를 침입자가 아니라 사용자로 대한다. 에이전트가 감독 없이 작업하는 데 필요한 것들을 제공한다: 아키텍처를 설명하는 가이드, 그리고 — 가장 중요하게는 — 기계가 스스로 찾아낼 수 있는 결승선.

내 레포에는 아키텍처 가이드 문서가 있어서CLAUDE.md 코드가 무엇을 하는지뿐 아니라 함정까지 문서화해 둔다. 예를 들면 이런 식이다: "서명된 번들에 바이너리를 핫스왑하지 말 것 — macOS가 실행 시점에 즉시 죽인다." 그리고 루트에는 make 파일이 하나 있고 타깃은 하나뿐이다: Makefile checkmake check. 그 타깃이 바로 이 레포가 정의하는 '완료'다. 성과는 곧바로 나타났는데, 이 레포를 겨냥해 실행한 오케스트레이션 도구가 make check을 스스로 찾아내 make check make check를 스스로 찾아내 실행하고, 정직한 통과 결과를 보고했다. 별도 설정은 없었다. 레포가 에이전트에게 스스로를 검증하는 법을 알려준 셈이다.

영수증: anyagent goal --drivemake check를 발견해Makefile:check 실행했고, 종료 코드 0을 받았다. 이제 같은 게이트가 푸시할 때마다 CI에서 돌아간다.

3 · 컨텍스트 엔지니어링 — 컨텍스트는 배낭이 아니라 예산이다

쉽게 풀면: AI 프롬프트에 채워 넣는 모든 것은 시간과 주의력이라는 비용을 치른다. 컨텍스트 엔지니어링이란 무엇이 그 자리를 차지할 자격이 있는지 정하고, 이를 짊어져야 할 모델에 맞게 크기를 조절하는 일이다.

내 AI 어시스턴트의 시스템 프롬프트는 어느새 축적된 지식 팩으로 87KB까지 불어나 있었다. 프롬프트 캐싱을 지원하는 클라우드 모델에서는 그래도 거의 공짜나 다름없다. 하지만 API 장애 중에 전환했던 로컬 7B 모델에서는 재앙이었다 — 게다가 그 재앙은 눈에 보이지 않게 벌어졌다. 모델은 프롬프트 대부분을 읽지도 않은 채 잘라냈고, 응답마다 2분이 넘게 걸렸다. 직접 측정해보니, 시스템 프롬프트가 없을 때는 0.3초였지만 전체 팩을 넣었을 때는 129.7초가 걸렸다. 5KB로 줄이고 팩들을 필요할 때만 불러오는 파일로 옮긴 뒤에는: 3.0초. 같은 모델, 같은 하드웨어인데 43배 빨라졌다 — 모델이 애초에 보지도 못했던 단어들을 지워냈을 뿐인데 말이다.

영수증: 응답당 130초 → 3초, 전후로 시간을 재서 측정했다. 지식 팩들을 삭제한 게 아니라, 작업에 필요할 때만 불러오는 파일로 옮긴 것뿐이다.

4 · 하네스 엔지니어링 — 진실을 값싸게 만들기

쉽게 풀면: 하네스란 코드 주변을 둘러싼 장치로, 검증은 값싸게, 거짓말은 비싸게 만든다: 프로브, 게이트, 자체 테스트가 그것이다. 원칙은 사용자의 눈높이에서 검증하는 것 — 함수가 무엇을 반환하는지가 아니라 사용자가 무엇을 경험하는지를 테스트하는 것이다.

이번 주를 구한 건 바로 이 하네스였다. 내 앱의 전사(transcription) 기능이 아무 말 없이 아무것도 만들어내지 않았다. 단위 테스트는 통과했다 — 문제는 실제 앱 번들에서만 드러나는 macOS 권한 체계 속에 숨어 있었다. 이를 찾아낸 하네스는 다음과 같다: OS의 강제 종료 신호를 재현하는 프로브 앱, 어느 프로세스의 권한이 문제였는지 밝혀낸 크래시 리포트 포렌식, 그리고 마지막으로 합성 음성을 실제 마이크 파이프라인에 흘려보내는 스피커-투-마이크 자체 테스트 — 이것이 사람 개입 없이 수정 사항을 처음부터 끝까지 증명해냈다. 내 사용자가 "나는 테스트 기계가 아니다"라고 말했을 때, 그의 말이 맞았다. 그걸 증명하는 게 바로 하네스의 일이다.

영수증: 세 가지 근본 원인(권한 강제 종료, 프롬프트 귀속 오류, 런루프 고갈)을 각각 목적에 맞게 만든 프로브로 격리했고, 최종 셀프 테스트는 사람 개입 없이 ~1.2초 간격으로 실시간 트랜스크립트 청크 51개를 만들어냈다.

5 · 루프 엔지니어링 — 닫힌 피드백, 정직한 채점

쉬운 말로: 루프란 실행 → 측정 → 조정으로 이어지는 모든 순환을 뜻한다. 루프 엔지니어링이란 이 순환을 닫혀 있게 (측정치가 실제로 피드백되도록) 만들고, 정직하게 (정체는 정체라고만 보고하고, 가짜 성공은 절대 꾸며내지 않게) 만드는 일이다.

이 레포에는 온갖 규모의 루프가 돌아가고 있다: 1차 제공자가 호출 도중 죽으면 다음 단계가 응답을 이어받는 서킷 브레이커 방식의 LLM 페일오버 체인, 클라우드가 실패하면 로컬이 해당 청크를 넘겨받아 아무것도 누락되지 않게 하는 트랜스크립션(transcription)의 청크 단위 폴백, 그리고 앞서 언급한 리팩터링 루프까지. 이 리팩터링 루프에서 가장 가치 있었던 행동은 바로 멈추는 것이었다 — 56→58로 보고한 뒤 "제안할 변경 사항 없음"이라 말하고 스스로 그만두었다. 자기 점수를 부풀리는 엔진은 차라리 없는 게 낫다. 정체를 정체라고 정직하게 알린 이 신호 덕분에, 기계의 노력이 어디서 끝나고 사람의 판단이 어디서부터 넘겨받아야 하는지 정확히 알 수 있었다.

영수증: 리팩터링 루프는 승리를 자칭하는 대신 58/100에서 스스로 정체 상태임을 보고했다. 이후 사람이 직접 개입한 단계에서 동일한 게이트를 통과하며 95점까지 끌어올렸다. 모든 단계는 테스트 게이트를 거쳤고, 회귀가 발생하면 롤백되었다.

6 · 그래프 엔지니어링 — 기억은 엔터티와 관계의 합이다

쉬운 말로: 파일과 폴더는 사물 간의 관계를 기억하지 못한다. 그래프 — 서로 연결된 사물들 — 는 작업이 어떻게 누적되는지를 보여주는 방식이다: 이 회의는 저 프로젝트에 속하고, 이 트랜스크립트는 저 지식 베이스에 공급된다.

이 레포의 메모리 레이어는 처음부터 끝까지 그래프 형태다. 트랜스크립트는 지식 저장소 안에 임베딩으로 저장되어 파일명이 아니라 의미로 검색되고, 회의는 누가 무엇에 대해 뭐라고 말했는지를 매핑하는 지식 그래프 엔진으로 내보내진다. 그리고 가장 최근에 추가된 엣지인 "Projectize"는 회의 노트를 작업이 계속 이어지는 프로젝트 폴더 안에 가져다 놓으며, 다음 단계까지 이미 라우팅해 둔다. 예전에는 녹음 파일이 막다른 길이었다면, 이제는 엣지를 가진 하나의 노드가 되었다.

영수증: 회의를 한 번 클릭하면, 프로젝트 레포 안에 날짜가 찍힌 노트 문서가 생기고 자동 라우팅된 다음 단계까지 그 안에 함께 담긴다 — 회의가 지식 저장소에서 썩는 대신 프로젝트의 그래프에 합류한 셈이다.

그 과정에서 깨진 것들 (일부러 남겨둔다)

한 문장 요약

코드는 이음매(seam) 단위로 구조화하고(OOP), 에이전트에게 정문과 결승선을 내주고(AI-native), 컨텍스트는 돈처럼 아껴 쓰고(컨텍스트 엔지니어링), 진실을 확인하는 비용을 낮추고(하네스), 모든 피드백 주기를 정직하게 닫고(루프), 기억은 사물과 관계로 저장한다(그래프). 그런 다음 가장 냉혹하고 결코 대충 훑어보는 법이 없는 리뷰어를 찾아 레포를 맡기면, 그 손을 빌려 스스로 더 나아진다.

관련 글

Paul Jialiang Wu · AI-Native Series · 모든 수치는 일주일간 하나의 레포에서 측정한 것이며, 방법론은 레포의 changelog에 있다.