KOEN
AI로 일하는 방식 · 실전 기록

AI를 믿을 수 있게 쓰는 법

산출물을 반증 가능하게 만들고, 담당자가 바뀌어도 굴러가게 넘기기
이기찬 · AI Product Engineer bit-habit.com 실제 프로젝트 사례 · 2026
이 글이 답하는 세 질문

AI를 쓴다는 건 결국 세 가지를 증명하는 일입니다 — 결과를 믿고 실무에 넣을 수 있는가, 성과가 조직에 남아 계속 굴러가는가, 도구를 비판적으로 골라 쓰는가. 각 주제가 무엇을 왜 묻는지는 해당 절 첫머리에서 다시 짚습니다.

flowchart TB
  R(["🧭 AI를 어떻게 쓰는가 — 세 가지를 증명하는 일"]):::root
  R --> H1
  R --> H2
  R --> H3
  H1["① 문제 해결 · 아키텍처  (§1)
결과를 믿고 실무에 넣을 수 있는가
신뢰성 = 리스크 관리"]:::h1 H2["② 업무 생산성  (§2)
성과가 조직에 남아 계속 굴러가는가
개인기 → 조직 역량"]:::h2 H3["③ 도구 · 모델  (§3)
한계를 알고 골라 쓰는가
기술 의사결정"]:::h3 classDef root fill:#EFEBFE,stroke:#5B3FD9,color:#3B2A82,stroke-width:2.4px; classDef h1 fill:#EFEBFE,stroke:#5B3FD9,color:#3B2A82,stroke-width:1.5px; classDef h2 fill:#fdf4e8,stroke:#a8560a,color:#7a3d06,stroke-width:1.5px; classDef h3 fill:#eef3f6,stroke:#33505f,color:#333C52,stroke-width:1.5px;

0.요약

AI를 더 빨리 쓰는 게 아니라, 결과를 믿을 수 있게 만드는 일을 합니다.
모델은 자신 있게 틀립니다. 그래서 확신도는 신호로 쓸 수 없습니다.
남는 방법은 하나 — 산출물을 반증 가능하게 만들고, 남이 이어받게 넘기는 것.
주제 (과제 지문)한 줄사례 · 근거
1.
문제 해결이나
아키텍처 개선 사례
정답을 채점할 수 없는 문제에서, AI가 낸 값을 되짚을 수 있게 만들었다.
정확도 → 추적 가능성으로 대체
💧 사례 1 · 수문조사 원가 검증 — 한국경영분석연구원, 정부 예산 검증 · 저장소 비공개
검증 네 겹 — 원본 대조 · 채널 검증(PDF는 뽑지 않고 이미지로) · 교차 파일 불변식 · 독립 2차 추정
불변식 42건 중 38건 오차 0(나머지 ±1.7%) · 서로 다른 두 파일이 말한 지점 수 355로 일치 · 독립 경로와 약 40% 격차는 맞추지 않고 조절 변수로 귀속
산정 10시간 → 1분. 목표는 속도가 아니라 수문조사를 모르는 사람도 1시간이면 검증할 수 있게

✈️ 사례 2 · 항공법 RAG — 같은 문제, 조건이 다를 때 · 데이터·코드·점수 전부 공개
정답셋을 만들 수 있으니 45개 설정 자동 채점. 검색 축은 API 0회로 무료화
동점이면 싼 쪽 — 토큰 38% 절감안 채택(정답 순위는 오히려 위) · 에이전틱은 27배라 기각 · 최대 변수는 청킹(커버리지 0.136 → 0.864)
[외부 채점] 강사 평가에서 완성도 9/10 · 수강생 중 1등
2.
AI를 활용한
업무 생산성 향상 사례
성과가 나 없이도 재현되도록 장치를 남겼고, 지금 그 장치가 시험받고 있다.
지표 = 단축된 시간이 아니라 담당자가 바뀌어도 재현되는 범위
같은 조직의 일하는 방식 자체 — 회의록 → AI 제안 → 사람 항목별 승인 → Board
장치 다섯 — 역할 분담(추출은 AI · Requirement Engineering은 사람) · 승인 게이트 · 작업 모델 · 유출 게이트 2단 · 판단을 ADR로
게이트가 실제로 잡은 것 셋 — 배정을 뒤집음(도메인) · 사내 용어를 걸러냄(보안) · "끝났다"를 두 번 되돌림(완료 판정)
[진술] 지침서 검토 10h → 2h
[로그] ADR 3건 · 학습 레슨 6개 · 조직 저장소 3개를 한 Board로
그리고 그 지표는 지금 테스트 중 — 6월 중순부터 제 가용 시간이 하루 2시간으로 줄고 팀원 둘이 합류했습니다. 결과는 아직 지켜보고 있습니다.
3.
도구 및 모델 분석
한계를 모델마다 다른 자리에서 직접 관찰해 기록하고, 알고 골라 썼다. 주력 Claude Codelearning 모드와 정액제가 이유. 취향이 아니라 도구를 하나씩 재보고 온 결과
한계 여섯을 모델별로 — Solar 모르는 것도 안다고 함 · 확신도 ≠ 정확도 · agentic에서 토큰이 비선형으로 · Gemini 긴 입력에서 숫자·관계 유실 · GPT·Gemini 논리적 전개는 못 그림 · 로컬(8B·16B) 좁은 도메인에 약함
공통 결론 — 사실은 도구·원문에서 가져오고, 모델에는 판단과 조립만
데이터를 밖으로 못 내는 환경에서 온프레미스가 왜 별도 엔지니어링인지
부록 A.
과제 지문 밖
운영 중인 인프라
같은 원리를 혼자 운영하는 시스템에 적용했다.
조직 사례가 아니라 본문에서 내렸지만, 주제는 같은 줄
단일 노드 k3s — *.bit-habit.com 아래 서비스 약 20개 · ARM 4코어 · 월 $0
AI에게 시킨 것은 인프라를 만드는 쪽이 아니라 이미 도는 인프라를 제3자가 반증할 수 있게 서술하는
반증 가능한 문서의 세 표식 — 스코어카드에 ❌를 남김 · 고치지 않기로 한 것에 이름을 붙임 · 순서를 결정으로 못 박음
장애 postmortem — 200 OK103일간 엉뚱한 사이트를 서빙. "응답했나"만 묻는 점검에는 안 보였습니다 → 상태 코드가 아니라 본문 내용을 단언하게 고침
세 주제의 연결 §3이 문제를 제기하고(모델은 자신 있게 틀린다), §1이 장치를 만들며(반증 가능하게), §2가 그것을 조직에 남깁니다(개인기 → 조직 역량).
그래서 세 절에서 같은 동작이 반복됩니다 — 결과만 남기지 않고, 결과가 나온 경로를 남기는 것. §1은 숫자마다 원본을, §2는 결정마다 근거를, 부록 A는 못 한 칸에 ❌를 붙였습니다. 잘한 것만 적힌 문서는 대조할 수 없으니까요.
근거의 등급 본문에 [로그](저장소·세션 기록으로 확인)와 [진술](사내 자료라 공개 불가, 진술로만)을 구분해 붙였습니다. §1의 원가 검증 앱은 저장소가 비공개이고 금액도 가렸지만 검증 설계는 전부 공개합니다. 사례 2·§2·부록 A는 저장소와 라이브가 열려 있습니다 (→ 부록 C).

1.문제 해결이나 아키텍처 개선 사례

이 주제가 던지는 세 질문 — 결과를 믿고 실무에 넣을 수 있는가.

프로젝트 둘을 같은 순서로 놓습니다 — 배경 → 핵심 프롬프트 → 검증. 하나를 읽으면 나머지는 같은 자리에서 같은 것을 찾을 수 있습니다.

둘을 고른 이유는 정답셋의 유무가 검증 설계를 통째로 가르기 때문입니다. 도메인(하천 예산 / 항공법)은 서로 아무 관계가 없고, 그래야 설계 덕분인지 도메인 덕분인지가 구분됩니다.

flowchart TB
  subgraph GA["💧 사례 1 · 수문조사 · 정답셋 없음"]
    direction LR
    A1["1-1 배경"]:::s1 --> A2["1-2 핵심 프롬프트"]:::s1 --> A3["1-3 검증
원본까지 되짚게 만든다"]:::s1 end subgraph GB["✈️ 사례 2 · 항공법 RAG · 정답셋 있음"] direction LR B1["1-4 배경"]:::s1 --> B2["1-5 핵심 프롬프트"]:::s1 --> B3["1-6 검증
수백 번 자동으로 채점한다"]:::s1 end GA --> GB classDef s1 fill:#EFEBFE,stroke:#5B3FD9,color:#3B2A82,stroke-width:1.3px;

💧 1-1. 사례 1 배경 — 무슨 일이었고, 왜 검증이 어려웠나

과제 질문 어떤 문제였으며, 당시의 기술적 제약 사항은 무엇이었습니까? 정부 수문조사 예산이 표준품셈 기준에 맞는지 검증하는 일입니다. 기존에는 엑셀 수작업으로 한 건에 10시간 이상이 들었고, 산정과 검산이 같은 손·같은 시트에서 일어나 오류가 드러날 자리가 없었습니다. 저장소비공개 (클라이언트 데이터, 1-1~1-3 공통). 대신 프롬프트 원문·검증 코드·화면을 이 문서에 싣습니다 → 부록 B 마스킹 정책

1-1-1 · 수문조사란

먼저 한 글자 수문(水文)은 댐의 물문(水門)이 아닙니다. "물의 기록", 영어로 hydrology입니다.

1-1-2 · 원가 검증이란

핵심은 감이나 관행이 아니라 국가가 정해 둔 기준서로 되짚는 데 있습니다.

표준품셈 — 그 기준서
flowchart LR
  A["편성 예산
지점·년 단가
실제로 잡힌 돈"]:::a B["표준품셈 역산
실비정액가산방식
기준대로면 나올 돈"]:::b A --- Q{{"둘이 다르다
어느 가정에서 벌어지나?"}}:::q --- B Q --> T["가정을 하나씩 원본까지 되짚는다
측정 횟수 · 투입 인원 · 보정계수 …"]:::t classDef a fill:#fdf4e8,stroke:#a8560a,color:#7a3d06,stroke-width:1.3px; classDef b fill:#EFEBFE,stroke:#5B3FD9,color:#3B2A82,stroke-width:1.3px; classDef q fill:#EFEBFE,color:#3B2A82,stroke:#5B3FD9,stroke-width:2.4px; classDef t fill:#eef3f6,stroke:#33505f,color:#333C52,stroke-width:1.3px;

1-1-3 · 앱이 한 일 · 안 한 일

하지 않은 것한 것
어느 쪽이 옳다고 판정하기 두 값을 나란히 놓고 차이의 출처를 추적하게 하기
"AI가 계산했습니다"로 근거 대신하기 가정마다 원본 문서·셀까지 붙이기

추적 대상은 셋입니다 — 측정 횟수를 몇 회로 봤는가, 1회당 몇 명·몇 시간인가, 어떤 보정계수를 적용했는가. 가정을 바꾸면 숫자가 어떻게 움직이는지 화면에서 보입니다.

걸려 있던 것

1-1-4 · 기존 방식 (10시간 → 1분)

노린 것 — 산정과 검증 분리 계산을 빠르게 만드는 게 목적이 아닙니다. 계산에 쓰던 시간을 검증으로 옮기는 것이 목적입니다.
로직을 한 번 세워 두면 산정은 1분이고, 남는 시간은 전부 "이 숫자가 어디서 왔나"를 보는 데 씁니다.
기존 (엑셀 수작업)
산정10시간 이상1분
검증 — 수문조사 숙련자산정과 분리되지 않음약 10분
검증 — 도메인 비숙련자사실상 불가약 1시간 ← 이게 진짜 목표

마지막 줄이 이 프로젝트의 실제 목표입니다. 수문조사를 모르는 사람도, 앱이 제시하는 근거만 따라가면 한 시간 안에 검증할 수 있게 만드는 것. 검증할 수 있는 사람의 수를 늘리는 일입니다.

1-1-5 · 정답셋이 없다

그래서 정확도를 추적 가능성으로 대체했습니다. 맞았는지 채점하는 대신 모든 숫자가 원본까지 되짚어지는지를 기준으로 삼았습니다 — 눈으로 대조할 수 있으면, 정답을 몰라도 틀렸을 때 틀렸다고 말할 수 있으니까요.

끝나지 않는 작업 실무자의 노하우를 계속 듣고 반영합니다. 어떤 가정을 왜 그렇게 잡는지는 기준서에 다 적혀 있지 않고, 현장에서 축적된 판단으로 채워집니다. 그 판단을 하나씩 앱의 근거로 옮기는 일이 계속됩니다 (→ §1-3의 의사결정자 피드백).

💧 1-2. 사례 1 핵심 프롬프트 — 코드보다 검증을 먼저 요구

과제 질문 AI에게 던진 핵심 프롬프트(질문)와 그에 대한 AI의 답변은 어땠는지? 이후 어떤 방식으로 대화가 진행되었는지 기술해 주세요. 첫 프롬프트에서 코드를 요구하지 않았습니다. 대신 "validation이 가장 중요하니 각 문장의 근거를 매번 citation해줘"를 요구했습니다.

1-2-1 · 첫 프롬프트 원문

다듬은 요약 대신 첫 프롬프트를 날것 그대로 남깁니다. 오디오 받아쓰기라 문장이 거칠고 오타도 있지만("파악을 할 수 있느", "validtion"), 그래서 결론이 아니라 사고의 흐름이 보입니다. 핵심만 하이라이트했습니다. (내부 데이터 폴더명 한 곳만 마스킹.)

강 별로 수문조사들을 한 것들이 다 저장되어 있는 데 너무 내용이 많고 그 예산이라고 할만한 부분도 카테고리가 너무 많다. 그래서 이 전체적으로 파악이 안되는데. 파악을 할 수 있느. 어떻게 보면 1분만에 이해할 수 있는 적절한 spread sheet와 인사이트를 보여주는 html을 만들어주고, 그 후 10분 정도 시간 들여서 이해할 수 있는 html도 만들어주고. 그 다음에 결국에는 궁극적으로 내가 원하는것은 1개 강의 수문을 조사시 몇명이 몇시간 얼마의 비용이 들어가는지 분석하는 것이다. 하지만 이게 바로 하게 되면 환각이 일어날수도있고, 이게 나름의 방정식일텐데 이해하기가 어려울 수도 있다. 마치 선형회귀로 서울 아파트 가격을 예측할때 다양한 feature들을 고려해서 더 정확하게 예측할 수 있겠다만, 그러면 이해가 안되니 heuristic하게 일단 size만 가지고 예측하는 것처럼. 처음에는 아주 간단한 마치 하나의 feature 고려하는 것처럼 정확도는 떨어지더라도 validtion이 될 수 있는 방향으로 해야겟다. html을 만들때 아무래도 streamlit으로 해야될 거 같으니. 아까 말한것과 다르게 html이 아니라 streamlit으로 만들어줘. 다시한번 말하는데 validation이 가장 중요하니, 가 문장의 근거는 실제 [내부 데이터]를 한번 가공해서 그 데이터를 매번 citation해줘.

이 한 문단이 담은 사고 흐름

  1. 데이터가 너무 많아 전체가 안 잡힌다 파일도 여러 개고, 예산 항목 분류도 지나치게 잘게 쪼개져 있다.
  2. 그래서 숲과 나무를 한 번에 요청했다 어차피 오래 걸리니 한 번의 대기로 둘 다 받는다. 전체 구조는 AI가 잘하고, 세부는 내가 조정한다.
  3. 세부만 곧장 요청하면 안 되나? 좁고 깊은 결과일수록 내가 원한 것과 어긋나기 쉽다. 게다가 AI가 그럴듯한 숫자를 지어내도 알아챌 수가 없다.
  4. 그래서 확인할 수 있는 형태부터 요청했다 정확도가 조금 떨어져도 값이 어디서 왔는지 따라갈 수 있어야 한다. 실패해도 전체 맥락은 남아 다음 대화의 자료가 된다.
  5. 결국 가장 중요한 것은 검증이다 빨리 만드는 것보다, 나온 결과를 믿을 수 있느냐가 먼저.
  6. 그래서 모든 숫자에 원본 출처를 붙이게 했다 어느 파일 어느 셀에서 온 값인지 화면에 같이 표시한다.
  7. 도구도 도중에 바꿨다 정적 HTML → Streamlit. 값을 바꿔 가며 확인할 수 있어야 해서.

코드 얘기는 한 줄도 없습니다. 전부 "무엇을 만드나"가 아니라 "어떻게 믿을 것인가"에 대한 요구입니다.

1-2-2 · 왜 숲과 나무를 한 번에 요청했나

가장 오해받는 대목입니다. 화면을 세 개 만들어 달라는 말도, 세 결과를 서로 대조하겠다는 말도 아닙니다.

1분판 — 전체 규모
만드는 것
강·연도별 총량과 단가를 한 화면에 요약
보는 사람
의사결정자. 설명 없이 1분 안에 본다
왜 맡기나
흩어진 자료에서 전체 구조를 뽑는 일은 AI가 잘한다
사이
10분판 — 분해
만드는 것
그 총량이 어떤 항목의 합인지 분해, 각 값에 원본 인용
보는 사람
실무자. 숫자를 따라 원본까지 내려간다
역할
숲에서 나무로 내려가는 계단. 어느 항목을 파고들지 여기서 정한다
나무
최종 — 수문 1건 원가
만드는 것
몇 명 · 몇 시간 · 얼마 — 법령 품셈에서 쌓아 올린 단가
보는 사람
발주처와의 원가 협의 자리
역할
협의에서 쓸 판정 근거 — "법령대로면 얼마"를 산식과 함께 제시

1-2-3 · 세 화면이 실제로 만들어진 모습

숲 화면 — 번호 붙은 인사이트 네 개와 각각의 원본 근거 인용 footer
숲 · 전체 규모. 결론 네 줄과 그 아래 근거 줄이 한 화면에 같이 있습니다 — 어느 파일 어느 시트 어느 셀에서 나온 값인지(D24×E24=F24)까지. 여기서는 수치를 전부 가렸습니다. 남은 문장만 읽어도 이 화면이 무엇을 하는지는 보입니다 — 결론마다 그 결론이 어디서 나왔는지가 붙어 있다는 것. 그리고 이 화면은 구경거리로 끝나지 않았습니다 — 네 번째 항목이 "표준품셈에 1회당 인·일이 이미 규정돼 있다"를 찾아냈고, 끝에 → 비용모델 v0 페이지에서 사용이라고 적혀 있습니다. 최종 계산의 열쇠를 숲에서 주웠습니다.
중간 화면 — 시도별 조사지점 수 막대그래프와 거점별 교통비 분포, 두 파일의 지점 수가 일치한다는 확인 문구
사이 · 분해. 총량을 시도별·거점별로 쪼개 봅니다. 오른쪽 아래 한 줄이 이 화면의 핵심입니다 — "교통비 파일의 연번 범위 합 = 355지점, 조사지점 파일과 정확히 일치". 서로 다른 두 파일이 같은 수를 말하는지 확인한 것으로, §1-3 장치 3(교차 파일 불변식)이 여기서 처음 등장합니다. 교통비 금액과 내부 파일명은 가렸고, 이 대조의 근거인 지점 수는 남겼습니다.
나무 화면 — 비용모델 v2 상단. 질문, 법정 산식, 근거 발췌 접이식, 관측소 선택
나무 · 최종. 질문을 화면 맨 위에 그대로 적어 둡니다 — "1회 하면 법령상 몇 명이·몇 시간·얼마가 나와야 하는가". 바로 아래가 그 답의 근거인 법정 산식이고, 접이식으로 표준품셈 원문 p.1이 붙어 있습니다. 값이 아니라 값이 나온 법적 경로를 먼저 보여주는 순서입니다.

이어진 대화는 아래 1-2-4~1-2-8에 원문(마스킹)으로 싣고, 그 결과는 1-3에 정리했습니다 — 목적을 헷갈린 AI를 되돌리고, 좌표 인용을 거부하고, 추출 채널 자체를 불신한 과정입니다.

이후 대화의 전개 — 다섯 번의 수정

모두 AI가 먼저 틀렸고, 발견해 방향을 바꾼 사건입니다.

앱 사이드바 — 10분 심화, 비용모델 v0/v1/v2, 원본 엑셀 뷰어, 질문 히스토리 페이지 목록
한 번에 만들지 않고 v0 → v1 → v2로 점점 지엽적인 모델을 쌓았습니다. 원본 뷰어·질문 히스토리까지 페이지로 남겼습니다.

1-2-4 · 목적 자체의 오해

아이고 니가 목적을 완전히 헷갈렸는데 … 우리가 원가 검증을 하는 프로젝트를 하고 있거든. 이 예산이 실제 그 법령하고 맞는지를 항상 보는 …
의도
결과

1-2-5 · 범위를 원자 단위로 좁힘

누가 그냥 todo를 해줘. 비용모델은 1개 강의 수문 조사시 몇명이 몇시간 얼마의 비용인지 부터 아는거로 하자.

새로운 비용모델을 만들자. 즉 매우 지엽적인 수문 1개 조사시에 몇명이 몇시간 얼마의 비용이 들어가는 지. 즉 특정 수문을 현재 조건을 보고 법령에 맞게 실제로 나오는지. 다른 예산은 일단 필요없다.
의도
결과

1-2-6 · 반증할 수 없는 근거

그 근거라는 부분을 spreadsheet의 일부를 복사붙여넣기 해서 누구나 spreadsheet에서 온 것처럼 해줘. … 새로운 수식이 나오면 그걸 근거를 보여줘
의도
결과
근거 발췌를 엑셀 뷰어 형태로 표시한 화면 — 행 번호와 열 문자를 유지하고 인용 행을 노랑으로 강조
값마다 근거 발췌가 접혀 있습니다. 열면 원본 시트 좌표(B101:D103)와 함께 인용 행의 앞뒤 행까지 나옵니다 — 앞뒤가 있어야 값이 잘린 것인지 원래 그런 것인지 판단됩니다. 금액·주소·내부 파일명은 마스킹했고, 격자 구조는 원본 그대로입니다.

1-2-7 · 텍스트 추출은 믿지 않는다 — 원본을 그대로 보여준다

pdf는 확실히 표로 되어 있으니 읽기가 어렵네. pdf는 스크린샷도 그냥 찍어서 근거로 보여주라
의도
결과

실제로 인력 투입 표를 텍스트로 뽑으면 이렇게 나옵니다.

(1) 평ㆍ저수 유량측정회0.050.650.850.90②●
표준품셈 투입인원수 산정기준 표를 이미지로 렌더한 근거 — 정부 공개문서
PDF 근거는 이렇게 붙습니다 — 페이지를 이미지로 렌더해 표를 표인 채로 보여주고, 인용한 부분만 형광펜으로 표시합니다. 추출기를 거치지 않으므로 무엇이 흘렀는지 의심할 일이 없고, 사람은 색칠된 곳만 보면 됩니다. (표준품셈 — 정부 공개문서)
지금 쓰는 방법과 그 한계

1-2-8 · 결과 말고 수식을 요구 — 결과가 아니라 근거를 대조할 수 있게

현장 출동인원이 몇명이 필요한지는 원래 알 수 없나? … 적용보정계수 같이 수식으로 계산한것들은 그 수식까지 표현해야지. 모든 수식은 다 표현해줘.
의도
결과
  1. 발견 — "현장 출동 인원"이 기본값 3으로 고정. 수식 자리에 적을 근거가 없음.
  2. 확인 — 표준품셈은 연인원(인·일)만 규정, 동시 투입 인원은 정하지 않음.
  3. 유도 — 데이터에서 범위를. 1일 내 완료 가정 + 사람은 쪼갤 수 없으므로 ⌈2.45⌉ = 3명, 등급 구성상 상한 4명.

상수를 유도로 바꾼 셈입니다. 수식을 요구하지 않았으면 보이지 않았을 자리였습니다.

수면폭 보정계수 유도 — 표준품셈 p.7을 이미지로 렌더
보정계수가 그 예입니다. 1.0이라고만 적으면 왜 1.0인지 확인할 수 없지만, 판정 규칙을 함께 펼치면 100 ≤ B=150 < 200 → 계수 1.0이라는 근거가 그 자리에서 대조됩니다. 규칙의 출처인 공개 품셈 p.7은 원본 이미지로 함께 붙였습니다.

💧 1-3. 사례 1 검증 및 적용 — 실무에 넣기 전, 네 겹으로 확인

과제 질문 AI가 작성한 코드나 가이드를 실제 환경에 적용하기 전, 어떤 검증(Test/Review) 과정을 거쳤습니까? 정답셋이 없으므로 정확도를 "추적 가능성"으로 대체했습니다. 맞았는지 채점하는 대신, 모든 숫자가 원본까지 되짚어지는지를 기준으로 삼았습니다.

1-3-1 · 이 절을 읽는 법

여기서부터가 이 일의 핵심입니다 — AI가 낸 것을 실무에 넣기 전에 거치는 유효성 검증(validation). 데이터를 밖으로 낼 수 없고 틀린 값이 곧 법적·금전적 리스크인 환경에서, reliability는 기능이 아니라 요건이었습니다.

개별 프롬프트 없음1-2와 달리 이 검증 장치들엔 개별 지시가 없습니다. P1에서 세운 "검증이 최우선"이라는 원칙 아래 AI가 스스로 만들었고, 검토해 채택했습니다. 무엇을 검증할지 정하는 건 사람, 실행은 AI — 판단을 쓰는 자리가 여기입니다.

맞는 답이 하나로 정해져 있지 않으니 점수를 매길 수 없습니다. 대신 모든 값이 원본으로 되짚어지게 만들어, 틀렸다면 어디서 틀렸는지 사람이 찾을 수 있게 했습니다.

flowchart TB
  A["AI가 낸 산출물"]:::src
  A --> B["원본 대조
행·열 좌표를 보존한 발췌"]:::dev A --> C["채널 검증
PDF는 이미지로 표 원형 확인"]:::dev A --> D["교차 파일 불변식
다른 파일이 같은 값을 말하나"]:::dev A --> E["독립 2차 추정
예산을 안 보는 두 번째 경로"]:::dev B --> F["실무 적용"]:::ok C --> F D --> F E --> F D -.->|"불일치는 숨기지 않고"| G["알려진 데이터 이슈로 공개"]:::warn classDef src fill:#eef3f6,stroke:#33505f,color:#333C52,stroke-width:1.3px; classDef dev fill:#EFEBFE,stroke:#5B3FD9,color:#3B2A82,stroke-width:1.3px; classDef ok fill:#5B3FD9,stroke:#3A2A7A,color:#ffffff,stroke-width:1.4px; classDef warn fill:#fdf4e8,stroke:#a8560a,color:#7a3d06,stroke-width:1.3px;

아래는 실제 코드입니다 — 말이 아니라 이렇게 돌아갑니다. (파일명·금액은 파라미터라 노출 없음, 로직은 원본)

1-3-2 · 원본 대조 — 인용한 셀을 원본 격자 그대로 보여준다

flowchart LR
  Q["인용할 셀 좌표
예: E9"]:::inp --> R["raw_slice
엑셀 행번호·열문자를 그대로 보존"]:::act R --> S["_row_style
표의 행마다 호출"]:::act S --> T{"이 셀이
인용 목록에 있나"}:::dec T -->|"셀까지 일치"| U["진노랑 + 굵게"]:::ok T -->|"행만 인용"| V["연노랑"]:::ok T -->|"아니다"| W["색 없음"]:::inp classDef inp fill:#eef3f6,stroke:#33505f,color:#333C52,stroke-width:1.2px; classDef act fill:#EFEBFE,stroke:#5B3FD9,color:#3B2A82,stroke-width:1.2px; classDef dec fill:#fdf4e8,stroke:#a8560a,color:#7a3d06,stroke-width:1.3px; classDef ok fill:#eaf6f0,stroke:#0a7048,color:#08512f,stroke-width:1.2px; classDef bad fill:#fdeeec,stroke:#a3241d,color:#7a1a15,stroke-width:1.2px;
인용 행·셀 하이라이트 applib.py
def evidence(rel_file, sheet_name, row_from, row_to, col_from="A", col_to=None,
             note="", expanded=False, hl_rows=None, hl_cells=None):
    """근거를 '원본 스프레드시트 발췌'로 붙이고, 인용된 행(연노랑)·셀(진노랑)을 하이라이트."""
    if hl_rows is None:
        hl_rows = []
    if hl_cells is None:
        hl_cells = []
    rows = set(hl_rows)    # 하이라이트할 엑셀 행 번호 목록
    cells = set(hl_cells)  # 하이라이트할 셀 좌표 목록 (예: "E9")
    df = raw_slice(rel_file, sheet_name, row_from, row_to, col_from, col_to)

    # pandas Styler가 행마다 호출하는 콜백 (C의 함수 포인터 인자와 같은 역할)
    def _row_style(row):
        out = []
        for col in df.columns:
            cell_name = col + str(row.name)  # 열 문자 + 행 번호 = 셀 좌표 (예: "E9")
            if cell_name in cells:
                out.append("background-color:#ffd54a; font-weight:600")  # 인용 셀
            elif row.name in rows:
                out.append("background-color:#fff3c4")                   # 인용 행
            else:
                out.append("")
        return out
# → '지어낸 좌표'와 '진짜 좌표'가 화면에서 색으로 갈린다.
근거 발췌 화면 — 엑셀 행 번호 50·51·52와 열 문자 A~E를 그대로 두고, 인용 행은 연노랑, 인용 셀은 진노랑으로 강조
위 코드가 만들어내는 화면입니다. 행 번호 50·51·52와 열 문자 A~E가 원본 엑셀 좌표 그대로라, 담당자가 원본 파일을 열어 같은 자리를 확인할 수 있습니다. 연노랑은 인용한 행, 진노랑은 실제로 값을 가져온 셀 — _row_style의 두 분기가 그대로 색으로 나타납니다. 앞뒤 행(50·52)을 함께 남긴 것도 의도입니다. 내부 파일명은 마스킹했습니다.

1-3-3 · 채널 검증 — 추출 경로 자체를 믿지 않는다

flowchart LR
  A["PDF 근거 요청"]:::inp --> B{"그 페이지의
렌더 이미지가 있나"}:::dec B -->|"있다"| C["이미지 그대로 표시
표 레이아웃이 살아 있다"]:::ok B -->|"없다"| D["기계 추출 텍스트로 폴백
표가 깨질 수 있음을 감수"]:::bad classDef inp fill:#eef3f6,stroke:#33505f,color:#333C52,stroke-width:1.2px; classDef act fill:#EFEBFE,stroke:#5B3FD9,color:#3B2A82,stroke-width:1.2px; classDef dec fill:#fdf4e8,stroke:#a8560a,color:#7a3d06,stroke-width:1.3px; classDef ok fill:#eaf6f0,stroke:#0a7048,color:#08512f,stroke-width:1.2px; classDef bad fill:#fdeeec,stroke:#a3241d,color:#7a1a15,stroke-width:1.2px;
PDF는 이미지로, 없으면 텍스트 폴백 applib.py
def evidence_pdf(label, txt_name, note="", expanded=False, hl=None):
    """PDF 근거: 페이지 스크린샷(인용 부분 형광펜)을 보여준다. 없으면 텍스트로 폴백."""
    title = "📎 근거 발췌 — `표준품셈(2023).pdf` " + label
    with st.expander(title, expanded=expanded):
        png = DATA / (txt_name + ".png")
        if png.exists():
            st.image(str(png), width='stretch')      # 표를 깨뜨리지 않는 이미지 그대로
            st.caption("↑ PDF 페이지 스크린샷 (etl.py가 렌더링, 🟡 = 인용 문구). " + note)
        else:
            st.code(_read_txt(txt_name), language=None)  # 폴백: 기계 추출 원문
            st.caption("↑ PDF에서 기계 추출한 원문. " + note)

# raw_slice — 엑셀 좌표(행 번호·열 문자)를 그대로 살려 2차원 배열로 잘라온다
data = []           # data[행][열]
row_names = []      # 엑셀 행 번호를 인덱스로
for r in range(row_from, row_to + 1):
    line = []
    for c in range(c0, c1 + 1):
        line.append(ws.cell(r, c).value)
    data.append(line)
    row_names.append(r)

1-3-4 · 교차 파일 불변식 — 서로 다른 파일이 같은 사실을 말하는가

마지막 장치가 쓸 기준선이 멀쩡한지를 먼저 검사합니다. 예산표의 지점당 단가는 적혀 있으니 맞다고 넘어갈 값이 아니고, 기준선이 틀려 있으면 격차(%)를 아무리 정밀하게 계산해도 의미가 없습니다.

앞의 세 장치가 사람이 확인할 수 있게 만드는 쪽이라면, 이 검사는 사람이 보지 않아도 걸립니다. 자기일관적인 환각으로는 통과할 수 없습니다.

검사한 불변식어떻게결과
수량 × 단가 = 총계총계 셀을 보지 않고 다시 곱해 대조42건 중 38건 정확 일치 · 4건 오차 ±1.7% 이내
조사지점 수지점 현황 파일과 별도의 교통비 파일에서 각각 집계양쪽 355로 일치
변경 전 / 후행 단위 대조7개 행 불일치를 행별로 출력
결측주소에 광역시도가 있는지 확인1건 발견
flowchart TB
  A["행 목록 records"]:::inp --> B{"수량·단가·총계 중
빈 칸이 있나"}:::dec B -->|"있다"| S["검사 대상 아님 — 건너뜀"]:::inp B -->|"없다"| C["model = 수량 × 단가
총계 셀은 보지 않는다"]:::act C --> D["err = 총계 − model"]:::act D --> E{"오차가 0.5 미만인가"}:::dec E -->|"예"| F["정확 일치 건수 +1"]:::ok E -->|"아니오"| G["최대 오차율 갱신 후 공개"]:::bad classDef inp fill:#eef3f6,stroke:#33505f,color:#333C52,stroke-width:1.2px; classDef act fill:#EFEBFE,stroke:#5B3FD9,color:#3B2A82,stroke-width:1.2px; classDef dec fill:#fdf4e8,stroke:#a8560a,color:#7a3d06,stroke-width:1.3px; classDef ok fill:#eaf6f0,stroke:#0a7048,color:#08512f,stroke-width:1.2px; classDef bad fill:#fdeeec,stroke:#a3241d,color:#7a1a15,stroke-width:1.2px;
불변식 검사 루프 app.py
# 교차 파일 불변식 검사: 수량 × 단가 = 총계. 총계 셀을 안 보고 다시 곱해서 대조한다.
records = items.to_dict("records")  # DataFrame → dict 배열 (C의 struct 배열처럼 순회)
n_exact = 0         # 오차 0으로 정확히 일치한 건수
max_err_pct = 0.0   # 최대 오차율(%)
for i in range(len(records)):
    row = records[i]
    qty, price, total_val = row["수량"], row["단가_백만원"], row["총계_백만원"]
    if pd.isna(qty) or pd.isna(price) or pd.isna(total_val):
        continue  # 셋 중 하나라도 빈 칸이면 검사 대상이 아니다
    model = qty * price          # 서로 다른 셀이 말하는 사실이라
    err = total_val - model      # 자기일관적 환각으로는 이 등식을 통과할 수 없다
    if abs(err) < 0.5:
        n_exact = n_exact + 1
    if total_val != 0:  # 총계 0인 행은 오차율 계산에서 제외
        err_pct = abs(err) / total_val * 100.0
        if err_pct > max_err_pct:
            max_err_pct = err_pct
불변식 검사 화면 — 항목·연도·수량과 오차_백만원 열이 보이고, 모든 행의 오차가 0
실제 화면입니다. 마지막 열 오차_백만원이 전부 0 — 총계 셀을 보지 않고 수량 × 단가로 다시 곱한 값이 원본 총계와 일치한다는 뜻입니다. 위 문장이 그 요약이고요(42건 중 38건 오차 0, 나머지 4건도 ±1.7% 이내). 단가·총계·모델값 열은 내부 예산 금액이라 가렸는데, 이 장치가 증명하는 것은 그 값들이 아니라 셋 사이의 등식이라 가려도 논지는 그대로 남습니다.

불일치 4건을 어떻게 다뤘나

어디에무작위가 아니라 한 항목군에 몰려 있었습니다 — 자동화 계측으로 전환 중인 신규 사업 계열.
총계가 엑셀 수식이 아니라 별도 산출값이고 단가는 그것을 정수로 반올림한 표기값이라, 총계를 수량으로 나누면 소수점 아래에서 어긋납니다.
성과눈으로는 못 찾을 0.13%짜리 차이를 등식 하나가 잡아냈습니다. 그것도 어느 항목군인지까지 좁혀서.
그래서기준선으로 쓸 항목은 전 연도 오차 0으로 성립했습니다. 어긋난 곳은 기준선이 아니었고, 마지막 대조를 그대로 진행할 수 있었습니다. 이 검사가 없었다면 "기준선이 멀쩡한지"를 물어볼 수조차 없었습니다.
발견된 이상치 — 감추지 않고 공개 4건·7건·1건 모두 앱과 저장소 문서의 "검증 상태"에 알려진 원본 데이터 문제로 공개했습니다. 원본의 문제를 조용히 보정하면 검증 도구 자체가 신뢰를 잃기 때문입니다.

[데이터] / [가정] 라벨 규약이 이때 정착했습니다

무엇을출처가 확인된 값과 채워 넣은 가정을 화면에서 구분합니다.
검증이 실패했을 때 "데이터가 틀렸는지, 가정이 틀렸는지"를 즉시 갈라야 합니다. 섞어 두면 불가능합니다.
실제로AI가 특정 단가를 출처 없이 그럴듯하게 채웠을 때, 그 값은 [가정]으로 표시되고 사용자가 수정 가능하게 남았습니다.

1-3-5 · 독립 2차 추정 — 두 경로로 같은 답을 구한다

같은 원가를 서로 모르는 두 경로로 계산합니다. 복식부기의 차변=대변, 또는 독립된 두 목격자처럼요.

경로 A · 예산에서
편성된 예산 → 지점당 단가
top-down · 발주 자료 기반
≠ ?
경로 B · 법령에서
표준품셈 × 노임단가 → 원가
bottom-up · 예산은 안 봄
경로 A · 예산에서경로 B · 법령에서
방향top-down — 편성 예산 → 지점당 단가bottom-up — 표준품셈 × 노임단가 → 원가
입력발주 자료공개 법령·공표 단가 — 예산을 한 번도 안 봄
전제 조건A의 단가는 1-3-4가 검사한 뒤에야 기준선으로 씁니다. 기준선이 틀리면 격차가 무의미하니까요.
두 값이 같으면서로를 검증한 것입니다.
다르면어디가 틀렸는지 신호입니다. 실제로 약 40% 차이가 났고, 모델을 억지로 맞추지 않고 격차의 원인(노임단가·측정 횟수·수면폭)을 조절 변수로 노출해 귀속했습니다.
예산과 견주는 이유 산출물이 숫자가 아니라 판정이라서입니다. 필요한 문장은 "±20% 이내이므로 정합적이다" 또는 "벗어나므로 근거가 필요하다"인데, 비교 대상이 없으면 검증이 아니라 계산입니다. 그래서 독립 경로의 가치는 어긋날 때 나옵니다.
flowchart TB
  L["표준품셈 인·일
등급별"]:::inp --> M["× 보정계수
수면폭 구간에서 유도"]:::act M --> N["× 공표 노임단가
등급별로 누적 = 직접인건비"]:::act N --> O["× 간접비·이윤 + 여비"]:::act O --> P["연 원가 annual
여기까지 예산을 한 번도 안 봄"]:::ok P --> R{"gap = annual 대 UNIT
얼마나 벌어졌나"}:::dec U["편성 예산 단가 UNIT
완전히 다른 출처"]:::inp -.-> R R --> Z["차이의 원인을 조절 변수로 노출"]:::act classDef inp fill:#eef3f6,stroke:#33505f,color:#333C52,stroke-width:1.2px; classDef act fill:#EFEBFE,stroke:#5B3FD9,color:#3B2A82,stroke-width:1.2px; classDef dec fill:#fdf4e8,stroke:#a8560a,color:#7a3d06,stroke-width:1.3px; classDef ok fill:#eaf6f0,stroke:#0a7048,color:#08512f,stroke-width:1.2px; classDef bad fill:#fdeeec,stroke:#a3241d,color:#7a1a15,stroke-width:1.2px;
법령만으로 원가를 쌓는 경로 비용모델 v2
def once_cost(task_name, fct):
    """측정 1회 대가(여비 포함, 부가세 제외) — 예산은 안 본다."""
    r = labor[labor["업무"] == task_name].iloc[0]  # 품셈에서 해당 업무 행 1개
    dl = 0.0                                       # 직접인건비 누적합
    for g in GRADES:
        man_days = float(r[g]) * fct               # 등급별 인·일 × 보정계수
        dl = dl + man_days * wages[g]              # × 공표 노임단가 → 누적
    cost = dl * (1 + ovh_rate) * (1 + fee_rate) + team * fare * 2
    return cost

# 지점당 고정 업무의 직접인건비: 업무 행 × 등급 이중 루프
fixed_records = fixed_tasks.to_dict("records")
fixed_dl = 0.0
for i in range(len(fixed_records)):
    r = fixed_records[i]
    for g in GRADES:
        fixed_dl = fixed_dl + float(r[g]) * wages[g]

annual = (n_py*cost_py + n_hs*cost_hs + fixed_cost) * vat_mult  # 법령만으로 나온 연 원가
gap = (annual - UNIT) / UNIT * 100      # UNIT = 편성 예산 단가(값은 다른 곳). 두 경로의 차이(%)
# → annual은 예산을 한 번도 안 봤다. 그래서 gap이 '진짜 신호'다.
독립 2차 추정 검증 화면 — 연간 원가를 수식·숫자 대입·결과 3열로 전개하고, 법령 기반 원가와 예산 단가를 나란히 대조
경로 B가 실제로 도는 화면입니다. 왼쪽 값은 표준품셈 인·일과 공표 노임단가만으로 쌓아 올린 것 — 예산 파일을 한 번도 읽지 않습니다. 금액은 전부 가렸습니다. 하나만 가리면 나머지로 복원되기 때문입니다 — 합계를 지워도 항목을 더하면 되고, 원가를 남기면 원가 ÷ (1+차이)로 예산이 나옵니다. 그래서 절대금액·비율·구성 항목을 함께 가려야 합니다. 대신 항목과 수식 열은 남겼습니다. 이 절의 주장은 값이 아니라 구조에 관한 것이라서입니다 — 연간 원가가 어떤 항의 합이고 각 항이 어떤 식에서 나오는지가 보이면, 값 없이도 이 화면이 무엇을 하는지 확인됩니다.

1-3-6 · 네 겹을 통과한 화면

원가 계산을 수식 → 숫자 대입 → 결과 3열로 전개한 화면 — 공개 노임단가 기반
최종 산출물에는 결과 숫자만 남지 않습니다. 수식 → 숫자 대입 → 결과 3열이 나란히 놓여, 값이 이상하면 어느 항에서 어긋났는지 그 자리에서 좁혀집니다. 앞의 네 단계가 노린 상태가 결국 이 화면입니다 — 믿어달라고 하지 않고, 직접 확인하게 하는 것.

1-3-7 · 적용 이후 — 의사결정자 피드백

앞의 넷은 내보내기 전의 검증이고, 이건 내보낸 뒤입니다. 여기서 나온 말이 다음 사이클의 입력이 됩니다.

이 분석은 의사결정자에게 성과 보고를 하며 마무리됐습니다. 비개발자입니다. 요지는 셋이었습니다. (실명·금액은 마스킹, 축어가 아닌 요약)

✅ 잘한 점"방향이 맞다"를 반복해 확인했습니다. 특히 입력하면 결과가 나오는 구조가 원하던 것이라고 했습니다.
⚠ 개선점세부 항목·인건비는 현업이 직접 조절할 수 있어야 하고, 장비 항목이 빠졌으며, 원가 쪽은 더 완성된 실제 산출물을 원했습니다.
→ 앞으로결론은 하나였습니다 — "옆에서 계속 소통하며 결과를 내놓을 사람이 상시로 필요하다." 이 말이 그 조직에서 AI 협업 시스템을 지속 운영하는 역할의 출발점이 됐습니다. 단발 산출물이 아니라 계속 굴러가는 관계로.

✈️ 1-4. 사례 2 배경 — 1,297쪽 법령에서 맞는 조항 찾기

과제 질문 어떤 문제였으며, 당시의 기술적 제약 사항은 무엇이었습니까? 1,297쪽 미국 연방항공규정(14 CFR)에서 근거 조항을 찾는 RAG입니다. 공개 저장소로 만든 학습 프로젝트라 데이터·코드·점수가 전부 공개돼 재현됩니다. 저장소github.com/bookseal/llm-app-lab · 라이브 llm-app-lab.bit-habit.com
정답셋 · 채점 코드 · 45개 설정 결과가 전부 공개돼 있어 1-5·1-6의 서술을 그대로 재현할 수 있습니다.
먼저 — RAG가 뭔가 오픈북 시험이라고 보면 됩니다. 1,297쪽 법전을 통째로 외우게(=모델에 전부 넣기) 하는 대신, 질문이 오면 관련 조항만 펼쳐 읽고 그걸 근거로 답하게 합니다. 외운 걸 말하면 지어낼 수 있지만, 펼쳐 읽고 답하면 어느 조항을 봤는지가 남습니다 — 이 문서 전체의 전제(믿으려면 근거가 남아야 한다)가 여기 그대로 옵니다.
통째로 안 넣는 이유는 둘 — 긴 입력은 모델이 다 읽지 않고(§3-3 한계 ④), 매번 넣으면 비쌉니다. 그래서 "다 넣기"가 아니라 "찾아 넣기"입니다.

찾아 넣으려면 법전을 미리 손봐 둬야 합니다. 뒤(1-5·1-6)에 계속 나오는 용어가 곧 그 조립 부품입니다.

부품무엇을 하나 (비유)고르는 지점
① 자르기
청킹
1,297쪽을 검색되는 조각으로 나눔 — 책을 포스트잇 단위로 쪼개기§ 조항 경계로 자를까, 글자 수로 자를까. 여기서 성능이 갈립니다.
② 색인
임베딩
각 조각을 의미 좌표로 바꿔 둠 — 뜻이 비슷한 문장을 가까운 자리에 꽂는 지도어느 임베딩 모델. 단어가 안 겹쳐도 뜻이 비슷하면 찾힙니다.
③ 찾기
검색방식
질문에 맞는 조각을 꺼냄뜻으로(벡터) · 단어로(키워드) · 섞기(하이브리드)
④ 몇 개
top-K
상위 몇 조각을 근거로 줄지적으면 근거가 빠지고, 많으면 잡음이 섞입니다.
⑤ 채점
LLM 심판
나온 답이 좋은지 다른 모델이 매김 — 사람 대신 채점관정확하지만 부를 때마다 돈이 듭니다.
그래서 이게 설계 문제인 이유①×②×③×④를 곱하면 조합이 수십 가지입니다. 어느 조합이 맞는지는 눈으로 못 고릅니다. 정답셋을 만들어 밤새 자동 채점으로 좁힌 게 1-5·1-6이고요 — RAG가 아니어도 통하는 접근입니다: 선택지가 너무 많고 정답을 적어 둘 수 있으면, 판단을 실험으로 바꾼다.

1-4-1 · 이 프로젝트가 무엇인가

1-4-2 · 무엇이 걸려 있었나

1-4-3 · 정답셋을 만들 수 있다

✈️ 1-5. 사례 2 핵심 프롬프트 — AI가 낸 답이 아니라, 그 답의 출처를 묻는다

과제 질문 AI에게 던진 핵심 프롬프트(질문)와 그에 대한 AI의 답변은 어땠는지? 이후 어떤 방식으로 대화가 진행되었는지 기술해 주세요. AI가 낸 답을 반박하지 않고, 그 답의 출처를 물었습니다. 세 번 모두 AI가 매끄럽게 답을 낸 뒤였습니다.

1-2에서 세운 원칙이 도메인이 바뀌어도 같은 자리에서 작동하는지 보이는 절입니다. 여기서도 프롬프트는 날것 그대로 남깁니다. 오타와 음성 받아쓰기 흔적을 그대로 뒀습니다.

1-2와 다른 점 1-2는 일이 시작될 때의 프롬프트였습니다. 여기 셋은 전부 AI가 이미 결과를 낸 뒤의 프롬프트입니다 — 캐묻고, 기각하고, 규칙으로 굳히는 자리입니다.

1-5-1 · 설명이 코드와 다른 것을 잡다

상황 — 하이브리드 검색을 AI가 RRF(순위 융합)라고 설명했고, 그 설명이 그대로 공개 문서 다섯 군데에 실렸습니다. 다이어그램·용어사전·본문까지 전부. 그런데 읽어도 계속 감이 안 잡혔습니다.

아니, 내가 궁금한건 앙상블을 어떻게 한지 아직 이해안돼. 어느 비율로 어떤 것을 쓰고, 언제 어떤 임베딩을 썼나?
의도
결과
정정 이력 보존

1-5-2 · AI가 미룬 판단을 되가져오다 — 에이전틱 기각

상황 — AI가 에이전틱 RAG를 직접 구현해 품질 우위를 보인 뒤, 어느 쪽으로 확정할지는 정해 주세요.라며 판단을 사용자에게 넘겼습니다.

지금 에이전틱으로 하면 그래도 10배 정도의 토큰 소모가 있는거 아니가? 우리는 단일 래그로 했을 때 복잡한 문제도 이미 잘 풀었다는것을 확인했어. 이정도 데이터에서는 에이전틱 루프 보다는 단일 래그도 잘 된다면 굳이 토큰 많이 써가면서 에이전트를 붙일 필요성ㅇ ㅣ있을까?
의도
결과
사람이 한 일 AI는 "품질이 좋다"까지 정확히 보여줬습니다. 하지만 품질과 비용을 같은 저울에 올리는 일은 넘겨줬습니다. 에이전트를 붙이면 무조건 낫다고 넘겨짚기 쉽지만, 토큰을 재 보니 이 데이터 규모에선 단발이 더 맞았습니다 — "언제 에이전트를 쓸지"는 코퍼스 크기와 비용을 아는 사람이 정할 문제였습니다.

1-5-3 · 규칙을 대화가 아니라 설정에 박다

상황 — 세션 두 개를 동시에 돌렸습니다. 한쪽이 실험 코드를, 한쪽이 문서를 맡았고 같은 저장소를 씁니다. 그러면 한쪽이 다른 쪽의 미완성 작업을 같이 커밋해 버리는 사고가 납니다.

그리고 너가 커밋할때는 너가 작업한것만 올려줘. 너가 작업하지 않은건 그대로 둬

claude-memory-backup 에서 커밋 관련된 모든 엠디 파일에 '한 세션에서는 그 세션이 작업한 것만 커밋한다'는 것을 추가해줘.
의도
결과
§2와 이어지는 지점 "담당자가 바뀌어도 재현되는가"가 §2의 기준인데, 그 기준이 여기서 이미 한 번 나옵니다. 세션이 바뀌어도 규칙이 남는가 — 규모만 다르고 같은 질문입니다.
이 절의 공통점 셋 다 AI가 매끄럽게 답을 낸 뒤의 일입니다 — 틀렸다기보다, 미처 짚지 않은 자리가 있었습니다. 겉으로는 어느 것도 이상해 보이지 않았습니다. 그래서 쓴 건 더 나은 직관이 아니라 같은 질문 하나 — "이 부분, 근거가 어디 있고 고려는 했나."

✈️ 1-6. 사례 2 검증 및 적용 — 정답셋이 있으니, 수백 번 자동으로 채점한다

과제 질문 AI가 작성한 코드나 가이드를 실제 환경에 적용하기 전, 어떤 검증(Test/Review) 과정을 거쳤습니까? 정답셋이 있으므로 검증을 사람이 보는 일에서 기계가 채점하는 실험으로 올렸습니다. 45개 설정을 밤새 돌렸습니다.

사례 1의 검증이 사람이 되짚을 수 있게 만드는 일이었다면, 여기서는 기계가 채점하게 만드는 일입니다. 장치 둘을 세우고, 그 위에서 45개 설정을 돌렸습니다.

1-6-1 · 비밀 시험지 — 튜닝에 안 쓰는 문제를 떼어 둔다

홀드아웃(holdout) — 튜닝에 쓴 문제로 시험을 보면 점수가 부풀려집니다. 그래서 몇 문항을 처음부터 떼어 채점에만 쓰고 튜닝에는 절대 안 쓰는 "비밀 시험지"로 남겨 둡니다. 14문항을 사람이 직접 만들고, 용도를 셋으로 갈랐습니다.

문항용도왜 갈랐나
4문항최종 시험지 — 튜닝에 한 번도 쓰지 않음 (split:"final")남은 문항에 설정을 맞추다 보면 그 문항에만 강해집니다. 시험지를 보고 공부하면 점수는 오르지만 실력은 안 오릅니다.
3문항거부가 정답 — 범위 밖 질문답을 잘하는지만 재면 모르는 걸 아는 척하는 모델이 1등을 합니다.
7문항튜닝용설정을 맞추는 데 쓰는 문항입니다.

거부 문항은 처음엔 없었습니다 — 범위 안 질문만 만들다가, "범위 밖 질문에 답을 지어내지 않는가"도 시험해야 한다는 걸 뒤늦게 깨닫고 추가했습니다.

1-6-2 · 싼 채점/비싼 채점 분리

검색 채점 retrieval생성 채점 generation
무엇을 재나정답 §조항이 검색 결과 안에 들어왔는가실제로 내놓은 답변의 품질
채점 방법코드로 대조 — 로컬 임베딩LLM 심판(judge)
비용API 호출 0회 · $0호출마다 과금
실행45개 설정을 밤새 전부검색이 확정된 뒤 소수에만

검색 채점을 코드로 돌린 덕에 45개 설정 전부를 $0로 훑고, 돈이 드는 생성 채점은 살아남은 소수에만 썼습니다 — 같은 실험량을 비용의 약 1/10로. 단, 생성 채점도 그 채점이 맞는지 확인하는 일도 공짜가 아니라, "완전 무료"가 아니라 비싼 채점을 최소한으로 부른 것에 가깝습니다.

1-6-3 · 결과 — 동점이면 싼 쪽

커버리지 = 정답 조항 중 검색이 실제로 찾아온 비율(찾은 정답 ÷ 전체 정답). MRR = 정답이 검색 결과에서 몇 번째로 나왔는지(앞 순위일수록 1에 가까움). 둘 다 검색 채점이라 코드로 매깁니다 — 그래서 45개 설정 전부에 매길 수 있었습니다.

설정커버리지MRR토큰
§경계 · bge · 하이브리드 · K80.8640.63617,284
§경계 · bge · 벡터 · K5 — 채택0.8180.71810,802
문자수 · minilm · 하이브리드 · K3 (최하위)0.1360.1822,939
판단근거
차이가 미세하다1위(K8)와의 커버리지 차이 0.046 — 11문항에서 사실상 한 문항 차이입니다. 판단이 갈릴 만한 격차가 아닙니다.
채택안이 더 낫다1위는 근거를 8조각씩(K8) 넣어 응답이 느립니다. 채택한 K5는 토큰 38% 적고 답도 빠른데, 정답을 더 앞 순위에 올립니다(MRR 0.718 vs 0.636). 커버리지만 0.046 손해 — 사용성까지 저울에 올리면 K5가 낫습니다.
동점이면 싼 쪽온프레미스 배포에서는 추론 비용도 응답 지연도 곧 제품 제약입니다.
같은 이유로 기각agentic 검색 루프는 토큰이 ~제곱으로 늘어(약 81k · 단발 대비 27배) 이득 대비 비쌌습니다. 배포는 single-shot, 루프는 문서화된 실험으로 남겼습니다.
가장 큰 변수청킹입니다. 문자 수 → §조항 경계로 바꾸자 커버리지가 0.136 → 0.864. 법령은 조항이 의미 단위인데 1,000자로 자르면 그 단위를 가로지릅니다.

1-6-4 · 적용 이후 — 강사 채점

여기서도 마찬가지입니다. 자동 채점이 끝난 뒤, 사람이 무엇을 지적했는지가 다음 개선의 출발점이 됩니다.

강사 채점 — 수강생 중 1등, 완성도 9/10 채점자는 Larry Arnstein — Impinj를 IPO로, Xnor.ai를 Apple 인수로 이끈 뒤 지금은 생성형 AI 스타트업(Simply Augmented) CTO입니다. 속도·완성도 등 여러 지표 중 완성도를 특히 높게 봤고 — 고민의 깊이를 평가하는 자리에서 수강생 중 1등이었습니다. 지적은 하나였습니다 — "UI를 더 다듬어라." 검색된 청크·토큰 수·점수를 화면에 그대로 노출해 뒀기 때문입니다. 검증을 위한 의도적 노출이었지만 완성도를 보는 자리에서는 틀린 기본값이었습니다. 다음엔 토글로 둡니다 — 만드는 사람과 쓰는 사람에게 필요한 정보는 다릅니다.
이 검증의 한계와 다음 수 채점 기준(정답셋)을 직접 만들었으니 자기 편향이 남습니다 — 다만 완성도는 강사 채점으로도 1등이라 그게 결정적 결함은 아니었습니다. 더 크게 남는 건 회고 쪽입니다:

1-7. 두 사례가 남긴 것

조건이 다르면 검증 방식도 갈립니다. 갈라지는 지점을 한 장으로 놓습니다.

사례 1 · 💧 수문 원가 검증사례 2 · ✈️ llm-app-lab RAG
도메인하천 예산 · 정부 기준서항공법 (14 CFR)
정답셋없음만들 수 있음 (holdout)
검증 방식사람이 원본까지 되짚기코드가 자동 채점
병목믿을 수 있는가설정이 너무 많다 · 채점이 돈이다
같은 것AI 산출물을 그대로 믿지 않고 반증 가능하게 만든다
두 검증을 나란히수문(단발 실무 · 추적성)과 llm-app-lab(정답셋 · 자동 벤치마킹)은 reliability의 두 얼굴입니다 — 정답이 없으면 모든 값을 원본까지 되짚게 만들고, 정답이 있으면 수백 번 자동으로 채점합니다. 공통점은 하나: "믿어달라" 대신 "직접 확인하라".

2.AI를 활용한 업무 생산성 향상 사례

이 절의 주제 — 위임의 경계 회의록을 주면 Board는 채워집니다. 문제는 그 다음입니다. 셋 다 이 절에서 실제로 일어났습니다. 그래서 다루는 것은 파이프라인이 아니라 무엇을 맡기고, 맡긴 것을 어떻게 되돌렸는가입니다.

이 주제가 던지는 세 질문 — 성과가 개인기가 아니라 조직 역량으로 남는가. 그리고 그러려면 AI에게 어디까지 맡길 수 있는가.

flowchart LR
  M{{"생산성 = 담당자가 바뀌어도
재현되는 범위"}}:::root M --> P["회의록
결정이 나오는 곳"]:::s2 P --> A["AI — 읽고 제안
근거 문장을 함께 인용"]:::s2 A --> V["사람 — 판단
항목별 승인 · 되묻기 · 반려"]:::gate V -->|"승인된 것만"| B["GitHub Projects 보드
기록이 남는 곳"]:::s2 V -.->|"모호하면 되묻기"| P classDef root fill:#EFEBFE,color:#3B2A82,stroke:#5B3FD9,stroke-width:2.4px; classDef s2 fill:#fdf4e8,stroke:#a8560a,color:#7a3d06,stroke-width:1.3px; classDef gate fill:#EFEBFE,stroke:#5B3FD9,color:#3B2A82,stroke-width:1.8px;

2-1. 배경 — 조직이 겪던 문제

과제 질문 조직이 어떤 문제를 겪고 있었습니까? 병목은 개발 속도가 아니라 의도의 전달이었습니다. 의사결정권자가 원하는 것이 팀장에게만 도달하고, 거기서 멈췄습니다. 저장소 — KIBA-Automation/project_management_with_ai_agent · 회의록 원문은 비공개

2-1-1 · 의도가 한 사람에서 멈춘다

[진술] 직원 약 40명, 개발자는 3명입니다 — 팀장(저)과 팀원 둘.

누가무엇을 아는가그래서
의사결정권자무엇을 원하는지. 다만 AI 자체엔 관심이 없음 — "자동화가 되는가"만 봅니다.기술 판단을 위임하고 결과만 봅니다.
팀장회의에 직접 들어가 의도와 뉘앙스까지.여기까지는 전달됩니다.
팀원회의 결과는 알지만 무엇을 만들어야 하는지는 모름.여기서 끊깁니다.
그래서 팀장이 병목이자 게이트

2-1-2 · 회의록을 그대로 쓸 수 없는 이유

회의는 화상으로, 생각나는 대로 흐릅니다. 그 기록에는 두 가지가 동시에 들어 있습니다.

전사에 남는 것전사에 안 남는 것그래서
결정된 사실 · 언급된 항목긴급도 · 중요도 — 비언어적 표현과 말투의 뉘앙스로 전달됩니다.우선순위는 회의에 직접 있던 사람만 매길 수 있고, 의사결정권자와 다시 조율해야 합니다.
요약을 맡기면 사라진다
문제를 한 줄로 의도는 팀장에서 멈추고, 그것을 팀원이 실행할 수 있는 형태로 바꾸는 일은 전부 사람 손에 있었습니다. 그 일을 어디까지 AI에 넘길 수 있는가 — 이 절은 그 경계를 찾은 기록입니다.

2-2. 접근과 구현

과제 질문 어떤 방식으로 문제를 해결하였습니까? 의도를 실행 가능한 형태로 바꾸는 일을 단계로 쪼개고, 각 단계를 AI와 사람에게 나눴습니다.

2-2-1 · 추출은 AI, Requirement Engineering은 사람

단계누가무엇을
추출AI전사를 청크로 나눠 한 줄씩 읽고 Issue를 뽑습니다. 통째로 요약하지 않으니 컨텍스트 손실이 없고, 실제로 거의 다 잡아냅니다.
Requirement Engineering사람뽑힌 Issue를 쪼개고 · 본문과 체크리스트를 쓰고 · 긴급도와 중요도를 매깁니다.
실행팀원 + AI 에이전트정리된 Issue를 받아 AI 에이전트로 작업합니다.
왜 우선순위는 넘길 수 없나
그 수고를 줄이는 방향 Requirement Engineering은 사람이 계속 해야 하는 일이지만, 드는 시간은 줄일 수 있습니다. AI에 도메인 맥락과 이전 판단을 계속 주입해, 초안이 손댈 곳이 적은 상태로 나오게 만드는 중입니다 — 게이트를 없애는 게 아니라 게이트 통과 비용을 낮추는 쪽입니다.

2-2-2 · 승인 게이트 — 어디까지 맡기고 어디서 끊는가

AI가 틀릴 수 있다는 전제에서 시작합니다. 그래서 "잘 시키는 법"이 아니라 "틀렸을 때 사람에게 오게 하는 법"을 설계했습니다.

권한무엇
묻지 않고 함Board 관찰 · 중복 항목 검색 · 변경안 작성까지
건별 승인 필요모든 쓰기. 기본값이 항목별이고, 전체 승인은 사람이 목록을 다 본 뒤 명시적으로 말할 때만
승인해도 금지삭제 · 권한·공개범위 변경 · 지정된 Board 밖 쓰기 · Board 아래의 코드·Issue · 회의록 내용을 GitHub에 노출
항상 지킬 것제안마다 근거가 된 회의록 문장을 그대로 인용 · 모호하면 짐작하지 말고 드러내서 되묻기
규칙을 가른 기준

2-2-3 · 작업 모델 — 제목이 아니라 구조에 정보를 넣는다

회의의 말을 Board 항목으로 옮길 때 어느 고도로 적을지가 계속 흔들렸습니다. 궁극 목표를 적을 수도, 체크리스트 한 줄을 적을 수도 있으니까요.

판별법 하나로 고정했습니다 — "이거 done이야, 아니야?"에 명확히 답할 수 있으면 작업 고도입니다.

고도판별어디로
너무 높음끝이 없어 done 판정 불가인력 추천 시스템 만들기Milestone
작업 (표준)done 여부에 답할 수 있음특정 화면에 필터 추가Issue
너무 낮음체크박스 한 줄함수에 파라미터 추가task list
한 줄로 남은 원칙제목에 정보를 넣을수록 손해, 구조에 넣을수록 이득. 상위 항목에 하위 항목을 묶어 두면 진척도가 자동으로 계산되지만, 같은 정보를 제목에 적어 두면 손으로 갱신해야 합니다.

2-2-4 · 유출 게이트 — 회의록이 기계 밖으로 나가지 않게

무엇
1단 · 사람 검토회의록은 먼저 git 추적에서 제외된 폴더로. 검토를 통과한 것만 저장소로 올라갑니다.한 번 push되면 나중에 파일을 지워도 이력에는 남습니다. 게이트는 push 이전에 있어야 합니다.
2단 · 기계 패턴승격 스크립트가 주민번호·전화번호·카드번호·계좌·이메일 5종을 차단사람 검토가 놓친 것을 잡는 마지막 그물입니다.
안 한 것브랜치로 분리하기스테이징 브랜치도 push되면 원격에 올라갑니다. 분리가 아니라 추적 제외여야 합니다.
이 게이트의 한계

2-2-5 · 판단을 기록으로

남긴 것내용
ADR 3건도구를 옮긴 이유 · 작업 모델 · 안전 계약. 왜 그렇게 정했는지를 각각 기록했습니다.
기각한 대안기록마다 함께 적었습니다. 예 — "먼저 쓰고 나중에 감사"는 되돌릴 수 없는 동작은 사후에 못 되돌린다는 이유로 기각.
미결 사항미결이라고 박아 뒀습니다 — "이것들은 정말로 안 정해진 것이다. 정해진 척하지 않도록 적어 둔다."
버린 경로탐색하다 접은 도구도 지우지 않고 읽기 전용으로 보존. 삭제가 아니라 경로의 기록으로.
여기가 §1과 이어지는 지점 코드에는 시스템이 무엇을 하는지가, ADR에는 왜 그렇게 되어 있는지가 담깁니다. §1에서 숫자마다 원본을 붙인 것과 같은 동작입니다 — 결과만 남기지 않고 결과가 나온 경로를 남기는 것.

2-3. 효과

과제 질문 생산성에 어떤 변화가 일어났습니까? [진술] 지침서 분석이 10시간 → 2시간. 그리고 팀장 한 사람이 쳐내던 일을 팀이 나눠 갖기 시작했습니다 — 다만 아직 고르게 돌아가지는 않습니다.
[로그] ADR 3건, 학습 레슨 6개, 조직 저장소 3개를 한 Board로.
생산성을 무엇으로 재는가 단축된 시간이 아니라 "담당자가 바뀌어도 재현되는 범위"로 잽니다 — 특정 개인에게만 의존하는 도구는 자산이 아니라 리스크니까요.
대상은 §1에서 수문조사 원가 검증을 한 바로 그 조직이고, 이번엔 일하는 방식 자체입니다.

2-3-1 · 조직에서 체감한 변화

[진술] 조직에서 직접 체감한 변화입니다.

무엇이어떻게 바뀌었나
장문 문서 검토지침서 한 건 10시간 → 2시간 (약 80% 단축)
회의 → Issue전에는 회의록이 사실상 버려졌습니다. 지금은 전사에서 Issue가 빠짐없이 뽑혀 Board로 갑니다.
Requirement Engineering여전히 사람 몫이지만, 맥락을 주입할수록 손댈 곳이 줄어듭니다.
실행팀장 혼자 쳐내던 일을 팀이 나눠 갖기 시작했습니다 — 아직 고르지는 않습니다(→ 2-3-5).

2-3-2 · 기록으로 확인되는 것

[로그] 저장소와 세션 기록으로 확인됩니다.

항목
한 Board로 모은 조직 저장소3개
Board로 이관된 작업 항목8개 (전량)
ADR3건
도구 사용 학습 과정6개 레슨 (레슨당 5~15분)

2-3-3 · 게이트가 실제로 잡은 것

사람이 실제로 막은 것 셋 · AI가 항목 배정을 "거의 확실"하다고 1순위로 제안 → 제가 다른 항목이 맞다고 뒤집음. 도메인 판단은 위임 불가.
· AI가 쓴 문서에 사내 도메인을 식별시키는 용어가 남음 → 제가 잡아내 일반화. 보안 판단도 위임 불가.
· AI가 "끝났다"고 선언 → 제가 두 번 되돌림. 완료 판정도 위임 불가.
2-2의 장치들은 이 셋이 매번 사람에게 오도록 만든 것입니다.

앞의 장치들이 장식이 아니었다는 증거입니다. 이 절 첫머리에 적은 셋이 실제로 걸린 기록 — 시스템이 작동한다는 증거는 속도가 아니라 사람이 무엇을 막았는가니까요.

AI가 한 것사람이 한 것그래서
Board 항목과 저장소를 짝지으며 특정 항목을 "거의 확실"하다고 1순위로 제안다른 항목이 맞다고 뒤집음도메인 판단은 넘길 수 없습니다.
저장소 소개 문서를 작성 — 사내 도메인을 식별시키는 용어가 남음그것을 잡아냄 — "좀 더 general해야 회사정보를 유출하지 않으면서…"§1의 보안 기준을 제 산출물에 스스로 적용한 셈입니다.
"끝났다"고 선언두 번 되돌림소개가 옛 도구 기준으로 남아 있었고, 예시가 사내 업무 그대로였습니다.

2-3-4 · 지표가 시험받는 중

이 절 첫머리에 "담당자가 바뀌어도 재현되는 범위"를 지표로 내걸었습니다. 그 지표가 지금 설계하지 않은 방식으로 시험받고 있습니다.

시점상태
2026년 5월이 시스템 착수 · 전담.
6월 중순팀원 2명 합류. 같은 시기에 제 가용 시간이 하루 2시간으로 축소.
현재실무는 팀원이 주로 진행 · 남은 역할은 조율과 검토.
왜 하루 2시간인가 6/22~8/14, 8주간 미국 시애틀 — 과기정통부 지원 AI·SW 인재 양성 사업의 글로벌 교육 프로그램, 30명 선발 (전자신문 · 경북일보). 체류지는 University of Washington입니다.
손을 뗀 게 아니라 하루 2시간으로 조율하고 나머지를 팀원이 이어받는 구조로 바꿨습니다. 8월 14일 종료 후엔 제약 없음.
뜻밖의 검증대 만든 사람의 가용 시간이 1/4로 줄고 새 사람 둘이 들어왔습니다. 이럴 때 필요한 게 정확히 ADR · 운영 매뉴얼 · 학습 과정인데, 만든 지 한 달 만에 실제 조건이 왔습니다.

2-3-5 · 한계와 다음 단계

한 번에 넘기는 인계가 아니라 계속 도는 루프입니다. 비즈니스 언어를 개발 언어로 바꾸는 자리에 사람이 서 있고, 그 자리를 매주 지납니다. 올리려는 것은 둘 — 검증 속도와 정확도. 하나만 올리면 의미가 없습니다.

막혀 있는 곳지금 하는 대응남은 일
Issue의 디테일이 부족
정리해 넘겨도 무엇부터 손댈지가 안 잡힘
AI에 맥락을 계속 주입해 초안의 손댈 곳을 줄임 승인 지점을 둘로 — ① 착수해도 되는 요구인가 ② 구현이 그 요구에 맞는가. ①의 체크리스트가 ②의 합격 기준이 됩니다.
Claude Code를 시작하지 못함
도구를 쥐여 줘도 첫 삽에서 막힘
옆에서 그대로 시연 — 설명이 아니라 따라 할 수 있는 장면으로 시연을 자산으로. 지금 보여주는 것을 남길 형태를 아직 못 정했습니다 — 학습 레슨이 그 시작입니다.
의도를 못 맞춤
Issue에 적힌 것은 하지만 그 너머는 팀장을 거쳐야 함
우선순위 판정을 사람이 계속 — 뉘앙스는 전사에 안 남으므로 자동 검증이 없습니다. §1의 검증 설계(불변식 · 인용 정합성)를 사람 승인 앞단에 붙여, 승인을 판단이 아니라 대조로.
아직 말할 수 없는 것

3.도구 및 모델 분석

이 주제가 던지는 세 질문 — 도구의 한계를 알고 골라 쓰는가.

flowchart TB
  C1["사용 도구 · 모델
무엇을 썼나"]:::s3 --> C2["선정 이유
왜 이 도구인가 — 전략적 선택"]:::s3 --> C3["장점 · 한계
어디까지 믿고 어디서 의심하나"]:::s3 classDef s3 fill:#eef3f6,stroke:#33505f,color:#333C52,stroke-width:1.3px;

3-1. 사용 도구 및 모델

과제 질문 (예: Cursor, Claude Code, ChatGPT, Gemini, Perplexity 등) 지금 쓰는 조합 — 작업은 Claude Code(정액 구독, learning 모드), 최신 탐색은 Perplexity(Comet 브라우저), 긴 영상·문서 흡수는 Gemini. 온프레미스 감각은 Ollama(로컬)와 Upstage Solar로 확인했습니다.

3-1-1 · 어떻게 여기까지 왔나

  1. 묻고 배우기 — ChatGPT 등장기 École 42 재학 중에 ChatGPT가 나왔습니다. 개념을 하나씩 물어보며 익히고, 코드는 복사·붙여넣기로 시작했습니다. 이후 검색 기능이 붙으면서 최신 정보는 검색을 먼저 시켰습니다.
  2. 많이 넣으면 다 읽을까? — Gemini 컨텍스트 실험 입력이 크다는 점을 이용해 회의 전사본을 1시간 · 2시간 · 10시간짜리로 넣어봤습니다. 1시간까지는 버티는데 2~3시간부터 내용이 날아갔고, 특히 숫자와 관계가 틀렸습니다. 컨텍스트 100만이라는 숫자가 곧 정확도는 아니었습니다.
  3. 그래서 RAG로 — 그리고 NotebookLM의 반대편 한계 많이 넣는 대신 필요한 것만 찾아 넣는 쪽이 맞다는 결론. NotebookLM은 출처에 충실했지만 복잡한 맥락을 엮는 데는 약했습니다. 정확한 인용과 넓은 이해가 서로 당기는 관계라는 걸 여기서 봤습니다.
  4. 만들어주는 건 어디까지? — 이미지·영상 학습 자료를 만들며 한계를 쟀습니다. 인포그래픽의 한글은 거의 안 되고(GPT ✗ · Gemini ○), 행렬이나 네트워크 흐름 같은 논리적 전개는 그럴싸하기만 할 뿐 틀렸습니다. 그래서 그 부분은 Manim(3Blue1Brown의 시각화 라이브러리)으로 직접 그립니다.
  5. 에이전트로 — Antigravity → Cursor Antigravity로 에이전트 IDE가 어떻게 굴러가는지를 처음 감 잡았고, Cursor에서 알았습니다 — 중요한 건 모델 성능만이 아니라 작업 흐름을 먼저 되묻는 설계라는 것. 브라우저를 붙여 스크린샷으로 스스로 확인까지 하더군요. 다만 API 과금이 비쌌습니다.
  6. Claude Code로 수렴 — 그리고 learning 모드 정액제로 같은 일을 감당할 수 있었고, 무엇보다 출력 스타일을 learning으로 바꿀 수 있었습니다. 이게 결정적이었습니다.
  7. 지금 — 역할을 나눠 쓴다 작업은 Claude Code, 최신 소식은 Perplexity, 긴 영상·문서는 Gemini. 그리고 온프레미스가 실제로 어떤 제약인지를 로컬 모델로 확인하는 중입니다.

3-1-2 · 도구별 역할

도구쓰는 자리왜 그 자리인가
Claude Code코드 · 검증 · 문서learning 모드 · Plan · 세션 · worktree · 대화 export. 정액제라 반복 실험의 비용 걱정이 없습니다.
Perplexity
(Comet 브라우저)
최신 소식 · 가벼운 브라우저 작업검색보다 빠르고, browser use로 클라우드 콘솔의 간단한 설정 변경까지 시킵니다. ChatGPT Atlas도 같은 기능이 있지만 한도가 금방 찹니다.
Gemini긴 영상 · 대량 문서YouTube 링크를 넣어 1~2시간짜리를 읽는 속도로 흡수합니다. 단, 커스텀 인스트럭션이 없으면 일반 요약은 쓸모가 없습니다.
Ollama (로컬)온프레미스 감각노트북에서 직접 돌려 하드웨어·메모리·로딩이 곧 제품 제약임을 체감했습니다.
Grok대화로만 써 봄제약이 적고 자유로운 편입니다. 어디에 쓸지는 아직 못 정했습니다 — 차량(Tesla)에 붙는다고 해서 기다리는 중입니다.
GitHub Copilot해커톤에서 잠깐Microsoft 주최 해커톤에서 써 봤습니다. 평범했습니다. 값이 훨씬 싸면 몰라도, Claude Code가 특별히 비싸지 않아 돌아갈 이유가 없었습니다.
Upstage Solar서비스 구현 (Booktoss)도구를 호출하는 에이전트로는 잘 돌았습니다. 한계는 3-3-2 ①에.

3-2. 선정 이유

과제 질문 수많은 AI 모델 중 왜 해당 모델(또는 도구)을 선택하셨습니까? 주력 도구로 Claude Code를 선택했습니다. 대신 짜주는 도구가 아니라 시니어이자 교사로 쓸 수 있어야 했기 때문입니다 — 이해 없이 만든 코드는 책임질 수 없으니까요.

3-2-1 · learning 모드가 결정적이었다

/configOutput style에서 learning으로 바꾸면, 답을 주기 전에 왜 그렇게 했는지 · 무엇을 배워야 하는지를 함께 설명합니다. (예전 명령은 /output-style이었고 v2.1.73에서 폐기 · v2.1.91에서 제거됐습니다.)

Claude Code 공식 문서의 Output styles 페이지 — Default 외 내장 스타일 셋(Proactive · Explanatory · Learning)과 Learning의 TODO(human) 설명, 그리고 /config로 바꾸라는 안내
제 주장이 아니라 Anthropic 공식 문서입니다 — code.claude.com/docs/en/output-styles (2026-07 확인). 내장 스타일은 Default 외 셋이고, 그중 Learning"collaborative, learn-by-doing mode where Claude will not only share 'Insights' while coding, but also ask you to contribute small, strategic pieces of code yourself"로 정의돼 있습니다. 코드에 TODO(human) 표시를 남겨 사람이 직접 채우게 한다는 것까지 문서에 적혀 있습니다 — 위에서 "대신 짜주는 도구가 아니라 시니어이자 교사로 쓴다"고 한 것이 제 사용법이 아니라 그 스타일의 정의 자체라는 뜻입니다.
무엇이 다른가그래서
터미널 명령을 직접 치게 한다손이 기억합니다. 대신 쳐주면 다음에도 못 칩니다.
맥락과 의도를 함께 준다"이렇게 했다"가 아니라 "이래서 이렇게 했다"가 남습니다.
중간에 인사이트를 끼워 넣는다작업이 끝나도 배운 게 남습니다.
왜 프롬프트로 대신할 수 없나

3-2-2 · 비용도 선택의 일부

도구과금결과
CursorAPI 종량설계는 좋았지만 쓸수록 비쌌습니다. 실험을 망설이게 됩니다.
Claude Code정액 · 월 100달러대같은 일을 비용 계산 없이 반복할 수 있습니다 — §1의 45개 설정 실험이 가능했던 이유이기도 합니다.
Gemini가족 요금제Google이 가족 단위로 싸게 내놓아 그때부터 본격적으로 썼습니다. 어떤 도구를 언제 쓰는지는 요금제가 정하기도 합니다.
GitHub Copilot값이 훨씬 싸면 몰라도, Claude Code가 특별히 비싸지 않아 옮길 이유가 없었습니다.
더 싼 쪽으로 갈 수 있었나 Antigravity나 Codex로도 될지 따져봤습니다. 결론은 learning 모드 하나가 남아서 못 갑니다 — 비용만 보면 다른 선택이 있지만, 이해가 함께 남는지가 제 기준이라서요.

3-3. 모델에 대한 평가 — 장점과 한계

과제 질문 해당 작업 수행 시 느꼈던 모델의 장점과 한계점은 무엇이었습니까? 장점 (Claude) — 원칙을 한 번 세우면 개별 지시 없이 따랐고, 자기 계획을 비판하게 시키면 유효한 반박을 냈습니다.
한계는 모델마다 다른 자리에서 나왔습니다.
모델쓴 자리거기서 본 한계
Claude작업 전반확신 있게 틀림(②) · agentic 루프에서 토큰이 제곱에 가깝게 증가(③)
Upstage Solar서비스 구현도구를 부르는 에이전트로는 잘 돌지만, 모르는 것도 안다고 답함(①)
Gemini대량 입력긴 전사본에서 2~3시간분부터 숫자·관계가 틀림(④)
GPT · Gemini이미지·영상논리적 전개를 못 그림 — 그럴싸하지만 틀림(⑤)
로컬 (8B·16B)온프레미스 실험덜 알려진 지역·좁은 도메인에 약함(⑥)
공통 결론은 하나 — 사실은 도구·원문에서 가져오고 모델에는 판단과 조립만 맡깁니다. 번호별 근거는 3-3-2에. 근거 저장소bookseal/Booktoss (①) · llm-app-lab (②③)

3-3-1 · 장점 — 모델이 값을 한 자리

장점관찰한 모델근거
① 원칙을 세우면 지시 없이도 따른다Claude§1-2에서 "validation이 가장 중요"를 한 번 못 박은 뒤, §1-3의 검증 장치 네 개는 개별 지시 없이 나왔습니다. 매번 무엇을 검증하라 시키지 않아도 후속 작업이 그 기준을 유지했습니다. → 사람이 정할 것은 원칙이고, 그 원칙의 반복 적용은 위임할 수 있습니다.
② 자기 계획을 비판하게 시키면 실제로 문다ClaudeRAG 실험 계획을 스스로 반박하게 하자 여섯 건의 유효한 반박이 나왔습니다 — "무료 축까지 순차 탐색할 이유가 없다", "이진 Recall은 다중정답 질문에서 거짓 신호다", "라벨 검증 전엔 점수를 믿지 마라". 전부 제 원안의 결함이었고 실험 설계에 반영했습니다.
③ 큰 저장소에서 맥락이 끊기지 않는다Claude파일 탐색 → 수정 → 실행을 이어가는 동안 앞의 결정을 유지했습니다. 여러 파일에 걸친 불변식 검사처럼 한 파일만 봐서는 못 만드는 코드가 여기서 나옵니다.
④ 판단 근거를 글로 남긴다Claude산문 품질이 좋아 코드와 함께 왜 그렇게 했는지가 문서로 남습니다. 담당자가 바뀌어도 이어받을 수 있느냐(§2)를 생산성 지표로 보는 저에겐 부수 효과가 아니라 본론이었습니다.

3-3-2 · 한계 — 모델별로 직접 관찰한 것

한계관찰한 모델근거와 결론
① 모르는 것도 안다고 말한다Solar도서관 통합검색 에이전트를 Upstage Solar API로 만들어 정상 동작했습니다. 그런데 그 서비스 이름을 대고 "이게 뭐냐"고 묻자 모르면서 아는 척 답했습니다. → 도구를 호출하는 에이전트로는 믿을 만해도, 모델이 사실을 안다고 가정하면 안 됩니다. 사실은 도구·원문에서 가져오고 모델엔 판단·조립만 맡깁니다.
② 확신의 강도 ≠ 정확도Claude · Solar①도, 아래 ③도 모델이 자신 있게 틀린 경우입니다. 확신도를 신호로 쓸 수 없다면, 구조로 반증 가능하게 만드는 수밖에 없습니다. §1의 장치들이 선택이 아니라 필수였던 이유입니다.
③ 비용의 비선형 증가Claude검색 품질을 높이려 반복 호출하는 agentic 루프에서 토큰이 제곱에 가깝게 증가했습니다(약 81k · 단발 대비 27배 — §1-5-2 실측). 품질 이득은 그만큼 크지 않았습니다. → 품질이 동률이면 저렴한 쪽을 택하고, 루프는 문서화된 실험으로 남겼습니다.
④ 긴 입력을 다 읽지는 않는다Gemini회의 전사본을 1·2·10시간짜리로 넣어보니 1시간까지는 버티고 2~3시간부터 내용이 날아갔습니다. 특히 숫자와 관계가 틀렸습니다. → 컨텍스트 크기는 정확도의 상한이지 보장이 아닙니다. 많이 넣는 대신 필요한 것만 찾아 넣는 쪽(RAG)으로 갔습니다.
⑤ 논리적 전개는 못 그린다GPT · Gemini행렬 연산이나 네트워크 흐름을 이미지·영상으로 만들게 하면 그럴싸하지만 틀립니다. 한글 인포그래픽도 거의 안 됩니다(GPT ✗ · Gemini ○). → 이 부분은 Manim으로 직접 그립니다. 표현은 맡겨도 논리는 못 맡깁니다.
⑥ 작은 지역·좁은 도메인에 약하다로컬 (Ollama)제 나름의 벤치마크가 하나 있습니다 — "감만동이 어디냐". 부산의 덜 알려진 동네라, 이런 곳까지 학습돼 있는지가 그 모델이 어디까지 아는지를 재는 자가 됩니다. 로컬 모델(8B·16B급)은 여기서 틀린 말을 많이 했습니다.
→ 그래도 쓸 자리는 있습니다. "좋아요 · 계속 하세요" 같은 짧은 반응이라면 충분하고 비용도 감당됩니다. 다만 판단이 필요한 자리에는 못 씁니다.
한계 다음이 한계들은 지적으로 끝내지 않습니다. 예컨대 Solar가 확신도를 표현하지 못하는 문제는 별도 검증 신호(Groundedness Check 등)를 붙여 점수로 되돌릴 수 있습니다 — 도구의 한계를 짚고 그걸 개선하는 쪽을 만드는 것 — 그게 하고 싶은 일입니다.

3-3-3 · 언제 무엇을 쓰는가

상황선택이유
탐색 · 학습 · 문서 작성Claude Code (learning 모드)결과와 이해가 함께 남음
사실 조회모델에 묻지 않고 도구·원문으로한계 ①
대량 반복 처리단발 호출 우선, 루프는 측정 후에만한계 ③
민감 데이터로컬 실행 또는 온프레미스데이터를 외부로 낼 수 없는 환경이 실재함
규칙을 정한 실제 대화 AI가 모듈을 통째로 구현하려 하자 이렇게 끊었습니다. (llm-app-lab · 원문)
"워워.. 니가 다 짜면 안 된다. 우리는 공부중이고. 다시 전으로 돌아가서 개념노트를 보고 뭘할지 같이 고민하자. 내가 코딩을 하면서 공부할거고 … 너가 시니어라 생각하고 나를 가르쳐주면서 같이 파일을 만들고 하면서 공부해야지."
마지막 항목 — 온프레미스 노트북에서 로컬 모델을 돌려보며 체감했습니다. 데이터를 밖으로 못 내는 환경에선 모델을 데이터 옆으로 가져가야 하고, 그때 하드웨어·메모리·로딩이 곧 제품의 제약이 됩니다. 온프레미스가 왜 별도 엔지니어링을 요구하는지 그 지점에서 이해했습니다.

3-3-4 · 그래서 관심 있는 방향

§1의 원가 검증은 클라이언트 데이터를 외부로 낼 수 없었고, §2의 회의록도 "회사 자료를 외부에 맡기면 안 된다"는 기준에 걸렸습니다. 제가 다뤄 온 일이 대체로 그런 자리였습니다.

선택지따져본 것
로컬 모델돌려는 봤지만 좁은 도메인에서 수준이 떨어져 그대로는 못 씁니다. 감각을 얻는 용도.
오픈웨이트 모델최근 공개된 것들을 토이 프로젝트에 붙여볼 생각입니다. 다만 학습 과정과 정렬 방식을 확인할 수 없는 모델은, 판단이 곧 근거가 되는 자리에 넣기 어렵습니다.
국내 온프레미스데이터를 못 내는 환경에서 실제로 남는 선택지입니다. 이 문서의 두 사례가 전부 거기 해당합니다.
덧 — 국산 AI를 두고 말이 많은 것에 대해
그래서 이 자리에 관심이 있습니다 §1이 다룬 것은 "AI가 낸 값을 어떻게 반증 가능하게 만드는가"이고, §2는 "그 방법을 조직에 어떻게 남기는가"였습니다. 데이터를 밖으로 못 내는 환경에서 그 둘을 동시에 해야 하는 자리라면 — 지금까지 해 온 일이 그대로 이어집니다.

A.부록 — 운영 중인 인프라를 남이 검증할 수 있게

§2의 주장은 조직에 관한 것이고, 이 부록은 같은 원리를 혼자 운영하는 시스템에 적용한 기록입니다. 조직 사례가 아니므로 본문에서 내렸지만, "AI가 쓴 것을 제3자가 반증할 수 있게 만든다"는 이 문서의 주제와는 같은 줄에 있습니다.

대상은 2025년부터 혼자 운영해 온 단일 노드 k3s 클러스터 — *.bit-habit.com 아래 약 20개 서비스가 여기서 돕니다.

A-1 · 왜 여기까지 왔나

중학교 1학년 때 리눅스 자격증을 땄습니다. 암기로 땄고, 이해한 게 아니라는 걸 그때 알았습니다. 지금 서른여덟이니 그 뒤로 25년, 계속 그걸 뒤집는 방식을 찾아왔습니다.

지금 이 클러스터는 그 연장선이고, 제약을 스스로 걸었습니다 — 1인이 무료 한 대로 어디까지 갈 수 있나. ARM 4코어에 서비스 20개, 월 $0입니다.

제약이 강제한 문서화 여유가 없으니 무엇이 왜 그렇게 돼 있는지 적지 않으면 먼저 잊습니다. 그래서 AI에게 시킨 일은 인프라를 만드는 쪽이 아니라, 이미 돌고 있는 인프라를 제3자가 반증할 수 있게 서술하는 쪽이었습니다.

A-2 · AI에게 시킨 것 · 안 시킨 것

누가
클러스터 실제 상태 수집 (kubectl 실측)AI — 문서의 주장과 대조할 원본
5단계 학습 구조 · 체크포인트 · 용어집 작성AI — 비계(scaffolding)
무엇을 공개하고 무엇을 한계로 적을지사람 — 판단
프로덕션 클러스터에 손대는 일사람 — AI에게 실행권을 주지 않음

결과물은 infra.bit-habit.com입니다. 소스는 공개 저장소 bookseal/bit-habit-infra에 있고, 라이브 상태는 status.bit-habit.com에서 60초마다 외부에서 확인됩니다.

A-3 · 반증 가능한 문서의 세 표식

"문서를 잘 썼다"는 검증 불가능한 주장입니다. 대신 제3자가 대조할 수 있는 형태인지를 봅니다. 세 가지를 넣었습니다.

① 스코어카드의 ❌ 잘한 것만 적힌 문서는 대조할 수 없습니다. 그래서 GitOps 기준 대비 현재 위치를 표로 놓고 못 한 칸을 그대로 뒀습니다 — Secrets ❌ gitignored, 손으로 적용 · Namespaces ⚠️ 대부분 default 하나. 그리고 결론을 한 줄로 적었습니다: "업계 표준과의 격차는 도구도 서비스도 아니고 비밀값 하나다."
② 고치지 않기로 한 것의 이름 장애 postmortem 끝에 같은 변경에서 일부러 고치지 않은 것을 따로 적었습니다 — 다른 저장소에 남은 낡은 라우팅 표 사본, 커밋 해시를 알 수 없는 이미지 마운트 방식. 이유는 문서에 그대로 있습니다:
"고치지 않기로 한 것을 적는 것도 회고의 일부다. 적히지 않은 기지(旣知) 이슈는 미지(未知) 이슈와 구별되지 않는다."
③ 순서를 결정으로 적는다

A-4 · 장애 postmortem — 200 OK

habit.bit-habit.com이 몇 달간 다른 사이트를 서빙했습니다. 에러 페이지가 아니라 정상 인증서와 200 OK로, 완벽하게 잘못된 사이트를 내보냈습니다. 업타임 모니터도, 제 상태 페이지도 "200이 왔나?"만 물었기 때문에 모든 자동 점검에 이 장애는 보이지 않았습니다.

진단은 층별 이분법으로 했습니다 — 매 단계마다 "문제가 이 층 위인가 아래인가"를 묻고 한쪽을 잘라냅니다. 결정타는 클러스터 내부에서 앱의 Service를 직접 호출해 본 것이었습니다. 앱은 멀쩡했고, 따라서 결함은 그 앞단에 있었습니다. 실제 원인은 독립된 두 실패가 겹친 데 있었습니다.

flowchart TB
  B["브라우저가
habit.bit-habit.com 요청"]:::s2b --> T["Traefik이 라우팅 표를 읽음"]:::s2b T --> F1["실패 ①
규칙이 엉뚱한 Service를 가리킴
포트폴리오 ← 앱이 아님"]:::bad F1 --> N["포트폴리오 Pod의 nginx가
요청을 받음"]:::s2b N --> F2["실패 ②
이 호스트와 맞는 server_name이 없어
기본 블록으로 폴백"]:::bad F2 --> R["200 OK + 잘못된 사이트
어디에도 에러가 없음"]:::bad APP["Flutter 앱
정상 · 건강 · 도달 불가
103일간 트래픽 0"]:::ghost classDef s2b fill:#EFEBFE,stroke:#5B3FD9,color:#3B2A82,stroke-width:1.3px; classDef bad fill:#fdeeec,stroke:#a3241d,color:#7a1a15,stroke-width:1.6px; classDef ghost fill:#f2f2f4,stroke:#8a8a95,color:#55555f,stroke-dasharray:4 3;

근본 원인은 라우팅 버그가 아니었습니다. 단일 진실 공급원(single source of truth) 버그였습니다. 그 앱은 클러스터에만 있고 어느 저장소에도 없었습니다. 그래서 그 앱을 가리키는 한 줄이, 정작 그 앱의 존재를 모르는 파일에 들어 있었습니다. 주인 없는 규칙은 표류하고, 아무도 눈치채지 못합니다.

여기서 나온 것 — 검증 체계 자체의 결함

A-5 · 왜 만들었나, 그리고 AI를 어떻게 썼나

무엇을 얻었나
공부가 목적남의 과제를 평가하며 k3s를 봤지만, 직접 세워 보지 않으면 아는 게 아니었습니다. 중학생 때 암기로 자격증을 딴 뒤로 25년째 지켜 온 기준입니다 — 산출물이 아니라 이해가 남아야 한다.
내 서버를 갖고 싶었다무료 한 대로 어디까지 가는지 보고 싶었습니다. 인증서·라우팅·배포·장애까지 전부 내 손을 거치면 감이 잡힙니다.
AI를 쓴 방식 — 비계는 AI가, 실행은 내가
현재 배포 구조

B.부록 — 마스킹 정책

공개 전 다음 기준으로 전수 치환 후 재검색으로 재확인했습니다.

대상처리
발주처·기관·고객사 명칭[발주처] 등으로 치환
내부 조직·팀 명칭삭제
시설·지점 주소삭제(건수만 유지). 국가 관측망처럼 정부가 공표하는 지점 명칭은 화면 판독을 위해 유지
내부 예산 절대금액전부 제거, 비율만 사용(±1.7%, 약 40%)
내부 파일명일반 명칭으로 대체
로컬 경로 · 계정삭제 또는 일반화
IP · API 키 · 토큰 · 패스워드본문·로그 전수 검색 후 제거
개인정보(성명·연락처 등)전수 검색 결과 해당 없음
표준품셈 등 공개 문서정부 공표 자료이므로 그대로 인용
참고 — 평소에도 같은 기준 관련 프로젝트를 공개 저장소로 옮길 때 "법령·품셈 PDF는 공개 문서이므로 포함, 내부 예산 엑셀은 제외"라는 기준으로 .gitignore를 구성했습니다. 또한 AI 세션 로그는 학습 자산이지만 그대로 공개하지 않습니다 — 터미널 출력이 절대경로·환경값·자격증명을 함께 끌고 오기 때문에, 익스포터 스크립트는 추적하고 산출물은 제외하도록 분리했습니다.

C.부록 — 공개 자료

본문의 각 주장을 뒷받침하는 공개 저장소와 라이브 사이트입니다. 직접 열어 확인하실 수 있습니다.

뒷받침하는 곳저장소 · 라이브
§1-4 ~ §1-6 사례 2 — 정답셋 · 45개 설정 벤치마킹 · 채점 코드 github.com/bookseal/llm-app-lab
llm-app-lab.bit-habit.com (라이브)
§2 전체 — 에이전트 운영 규칙(CLAUDE.md) · ADR · Board 스크립트 KIBA-Automation/project_management_with_ai_agent
회의록 원문은 비공개 — meetings/는 git 추적 제외
§3 한계① 도서관 통합검색 에이전트
(Solar API로 만들어 동작하나, 자기 이름은 모름)
github.com/bookseal/Booktoss
booktoss.bit-habit.com (라이브)
운영·관측 인프라의 한계를 문제로 공개 github.com/bookseal/bit-habit-infra
status.bit-habit.com (라이브 상태)

공개하지 않는 것이 문서의 중심 사례인 §1 원가 검증 앱의 저장소는 클라이언트 데이터를 다루므로 비공개입니다. 위 §1 화면들은 내부 예산 수치·조사지점 주소·내부 파일명을 마스킹하고 공개 표준품셈만 남긴 것입니다(부록 B). 가장 강한 증거를 그대로는 보일 수 없다는 것이 이 종류의 일에서 감수하는 대가입니다.