| 테스트 `cases/lab02.json` | — | 7/9 (예제 2에서 만들 캐시 케이스가 아직 실패, 접수 답에서 검토 LLM이 "처리 중"을 바꿔 씀) |
- 수업 준비 때(10/18): 접수 질문 2.4~2.8초 → 1.9~2.3초 (LLM 3번 → 2번).
- **규칙이 틀리면?** 예를 들어 "프린터 설치 담당자가 누구예요?"처럼 FAQ 낱말(`프린터` · `설치`)이 들어 있지만 FAQ가 답이 아닌 질문은 규칙으로 `faq`가 됩니다. 반대로 FAQ 낱말이 없는 질문("회의실 화면 공유가 안 돼요")은 LLM이 분류해야 합니다. `cases/lab02.json`에 "규칙으로 모르면 LLM이 분류" 케이스가 있는 까닭입니다. 규칙도 테스트합니다.
## 3. 캐시 (4교시 Lab 02 예제 2)
### 일반 설명
**캐시**는 한 번 만든 결과를 가까운 곳에 저장해 두고, 같은 요청이 오면 다시 만들지 않고 돌려주는 것입니다. 브라우저, CDN, 데이터베이스 앞의 Redis, LLM 응답 저장이 모두 캐시입니다.
| 방식 | 하는 일 | 오늘 |
| --- | --- | --- |
| **캐시 어사이드** (cache-aside) | 일하기 전에 캐시를 보고, 없으면 일한 뒤 저장 | ✔ (워크플로우가 직접) |
| 읽기 대행 (read-through) | 캐시가 알아서 원본을 읽어 옴 | |
| 쓰기 동시 (write-through) | 원본을 바꿀 때 캐시도 함께 | |
- **수명(TTL)**: 저장한 값이 저절로 사라지는 시간. 짧으면 적중이 줄고, 길면 오래된 답이 나갑니다.
- **무효화(invalidation)**: 원본이 바뀌었을 때 캐시를 지우는 일. "컴퓨터 과학에서 어려운 것은 캐시 무효화와 이름 짓기 두 가지"라는 농담이 있을 만큼 어렵습니다.
- **키**: 답을 바꾸는 것은 **모두** 키에 들어가야 합니다 (질문, 사람마다 다르면 사람, 자료가 바뀌면 자료 판번호). 하나라도 빠지면 다른 사람 · 다른 상황의 답이 나갑니다.
- 캐시해도 되는 것: **같은 키면 언제 · 누구에게나 같은 답**. 개인 정보가 든 답, 시시각각 바뀌는 상태는 캐시하지 않습니다.
| 첫 질문을 띄어쓰기만 바꿔 | `cached: true`, `cache_by: "question"` | 0.0초 |
| 다른 말 + `no_cache` | `cached: false` | 1.2초 |
- Lab 02 과제 2를 하기 전 워크플로우(과제 1 정답)로는 "다른 말"이 `cached: false`, LLM 1번, 1.2초였습니다 (10/24, 4/6).
- 데이터 조회는 하고 LLM만 건너뜁니다. 그래서 질문 캐시(0.1초 이하)보다는 조금 느리지만 LLM보다는 훨씬 빠릅니다.
- **잃는 것**: FAQ 번호 캐시의 답은 **처음 물은 사람의 질문**에 맞춰 쓴 답입니다. "VPN이 끊겨요"에 맞춘 답이 "VPN 설치는 어떻게 해요?"에도 나갈 수 있습니다 (둘 다 FAQ-003). 답이 FAQ 원문 요약이면 괜찮고, 질문마다 달라야 하면 이 캐시는 맞지 않습니다.
- 접수 현황은 여기서도 캐시하지 않습니다. 사람마다 · 시간마다 다르니까요.
## 6. 검토 LLM을 검사 코드로 (4교시 Lab 02 과제 1)
### 일반 설명
LLM의 답을 검사하는 방법은 둘입니다.
| 방법 | 잘하는 것 | 약한 것 |
| --- | --- | --- |
| **코드 검사** (가드레일 · 검증기) | 빠름, 늘 같음, 설명 가능: 빈 답, 길이, 형식(JSON 모양), 금지어, 언어 | 뜻은 모름 |
| **LLM 검토** (LLM-as-judge) | 뜻을 봄: 사실과 맞나, 말투, 없는 약속 | 느리고 비쌈, 흔들림, 검토가 오히려 사실을 바꿔 쓸 수 있음 |
- 업계에서는 **코드 검사를 먼저** 두고, 뜻을 꼭 봐야 하는 업무에만 LLM 검토를 남기는 경우가 많습니다.
- 말투 같은 것은 검토로 고치기보다 처음 답을 쓰는 지시문으로 정하는 것이 싸고 빠릅니다.
### 오늘 실습에서
검토 LLM이 한 일을 Executions에서 비교하면 대부분 **말투만** 바꿨습니다. 그런데 10/24에는 접수 상태 "처리 중"을 "승인 대기 중"으로 바꿔 써서 Lab 01 예제 2의 테스트 `cases/lab01.json`이 한 번 실패했습니다. 말투는 답 LLM의 지시문("합니다체, 3문장 이내")으로 정하고, 셀 수 있는 것은 코드가 봅니다.
- 날마다 숫자는 다르지만 **LLM 하나를 빼면 약 1초 줄어든다**는 것은 같습니다 (1단계 7절 어림과 맞음).
- Lab 02 과제 1 테스트 `cases/lab02-challenge.json`은 2.5초 안을 기대합니다. 10/24 15번 모두 통과했습니다 (`--repeat 3`, 0.9~1.6초).
## 7. 잃은 것도 적는다
### 일반 설명
성능을 위한 변경은 거의 늘 무언가와 맞바꿉니다 (속도 ↔ 정확도, 속도 ↔ 최신성, 속도 ↔ 단순함). 개발 팀은 이것을 **설계 결정 기록(ADR, Architecture Decision Record)** 으로 남깁니다: 무엇을 정했나, 왜, 다른 선택지는, 무엇을 잃었나.
- 몇 달 뒤 누군가 "왜 검토가 없지?"라고 물을 때, 기록이 없으면 같은 논의를 처음부터 다시 합니다.
- 잃은 것을 적어 두면 상황이 바뀌었을 때(예: 규제 업무가 추가됨) 무엇을 되돌려야 할지 바로 압니다.
### 오늘 실습에서
| 바꾼 것 | 얻은 것 | 잃은 것 |
| --- | --- | --- |
| 규칙 먼저 | LLM 1번 줄임 | 규칙이 틀리면 엉뚱한 분류 (규칙을 테스트로) |
| 질문 캐시 | 같은 질문 0.1초 | 오래된 답 · 남의 답 위험, 테스트가 복잡해짐 |
| FAQ 번호 캐시 | 다른 말로 물어도 LLM 0번 | 답이 질문에 맞춰지지 않음 |
| 검토 → 검사 | LLM 1번 줄임 | 뜻을 보는 검토는 사라짐 (69일차의 "사실에 없는 약속" 검사) |
Lab 02 과제 1 · 과제 2를 마칠 때 `my-work/PERF.md` 3절에 바꾼 것마다 한 줄씩, **잃은 것까지** 적습니다. 운영에서 "왜 이렇게 했지?"라고 물을 때 답이 됩니다.
## 8. 캐시는 테스트도 바꾼다
### 일반 설명
테스트끼리 **상태를 나눠 쓰면** 순서에 따라 결과가 바뀝니다 (앞 테스트가 남긴 캐시 · 데이터). 이렇게 "가끔 실패하는" 테스트를 플래키(flaky) 테스트라고 하고, 쌓이면 아무도 테스트를 믿지 않게 됩니다.
- **격리**: 테스트 앞에서 상태를 비우거나(초기화), 테스트마다 다른 키를 씁니다.
- **겉으로 드러난 결과를 본다**: "LLM을 3번 불렀나" 같은 내부 구조를 기대하면, 정당하게 고친 코드도 실패합니다. 품질 테스트는 답의 내용을, 구조는 그 구조를 만든 단계의 테스트에서만 봅니다.
- LLM 문장은 여러 표현을 허용하는 기대로 씁니다 (여러 낱말 중 하나, 숫자 · 고유명사처럼 바뀌면 안 되는 것만 정확히).
### 오늘 실습에서
> 수업 준비 때 "규칙으로 모르는 질문"이 캐시에 들어가 다음 테스트에서 0.1초로 나왔습니다. 그래서 테스트에 `no_cache: true`, 테스트 전에 캐시 비우기(`before`)를 둡니다.
| 테스트를 흔드는 것 | 오늘 한 일 |
| --- | --- |
| 앞 테스트가 남긴 캐시 | `cases/lab02*.json` 맨 위 `before`에 `/cache-clear` |
| 재는 요청이 캐시에 맞음 | `no_cache: true` (Lab 02 예제 3 · 과제 1의 `bench`가 쓰는 `requests/faq-vpn-nocache.json`) |
| 구조를 보는 기대 (`llm_calls: 3`, `steps`에 `review`) | 품질 테스트는 **답의 내용**만, 구조는 그 단계 테스트에서만 |
| LLM 문장 | 여러 표현 중 하나 (`찾지 못` · `확인되지` · `없습니다` · `존재하지`) |
> 수업 준비 때 처음 쓴 품질 테스트에 `llm_calls: 3`, `steps`에 `review` 같은 **구조**가 들어 있어 정당하게 빨라진 워크플로우가 실패했습니다.
**요청문(프롬프트)이란.** 실습에서 CLI 코딩 에이전트(codex · claude · agy)에게 보내는 글입니다. 에이전트는 이 글만 보고 n8n 워크플로우 JSON을 만들거나 고칩니다. 이 절은 이 단계에서 배운 것을 **요청문(프롬프트)에 어떤 칸으로 적을지** 실습 전에 정리하는 자리입니다. 실습 문서의 `▶ 빈칸 채우기 · 요청문(프롬프트) 뼈대`가 이 칸을 실제 문장으로 만든 것이고, 빈칸 ①~④는 그 문장 속 정확한 값입니다.
| 칸 | 에이전트에게 알려 주는 것 | 빠지면 생기는 일 |
| --- | --- | --- |
| 무엇을 | 만들거나 바꿀 기능 | 에이전트가 짐작해서 다른 것을 만듦 |
| 어디에 | 고칠 파일 · 노드 · 자리 | 엉뚱한 노드를 고치거나 새 파일을 만듦 |
| 어떤 모양으로 | 결과 JSON의 칸 이름 · 값 · 응답 코드 | 테스트가 보는 칸 이름과 달라 실패 |
| 그대로 · 하지 말 것 | 건드리면 안 되는 것 | 다른 곳까지 바뀌어 무엇 때문인지 모르게 됨 |
| 확인 | 통과해야 할 테스트 파일 | "다 됐다"를 판단할 기준이 없음 |
67~71일차의 다섯 가지(① 파일 ② 입력 ③ 처리 ④ 결과 모양 ⑤ 기대 결과)와 같은 뜻입니다. 파일 · 입력이 "어디에", 처리가 "무엇을", 결과 모양이 "어떤 모양으로", 기대 결과가 "확인"입니다. 72일차부터는 **이미 있는 워크플로우를 고치는** 요청이 많아 "그대로"가 따로 한 칸이 됐습니다.