Files
aio-01d4-stu/Lecture/72/00-DAY72-OVERVIEW.md
2026-10-25 22:57:12 +09:00

442 lines
15 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 72일차 개요 · Workflow 실행 흐름 최적화와 운영 관점 개선
> 노코드 멀티 에이전트 워크플로우 설계 및 운영 · 2026-10-26
> 30장 · 각 장은 가로줄(`---`)로 나뉩니다. 1교시에는 1~6장을 보고, 나머지 장은 각 단계 강의(1 · 3 · 5교시) 때 함께 띄웁니다.
> 숫자는 모두 강사 노트북 실측입니다 (65일차 n8n 2.42.6, OpenAI `gpt-4.1-mini`, 10/18 수업 준비 · 10/23~24 다시 잼).
| 장 | 범위 | 띄우는 때 |
| --- | --- | --- |
| 1~6 | 표지 · 목표 · 시간표 · 오늘 고칠 것 · 일하는 순서 · 실습 15개 | 1교시 시작 |
| 7~14 | 1단계 · 재기와 병목 | 1교시 강의 |
| 15~21 | 2단계 · 실행 흐름 최적화 | 3교시 강의 |
| 22~28 | 3단계 · 운영 관점의 안정성 | 5교시 강의 |
| 29~30 | 바이브 코딩 · 정리와 예고 (8교시 35분 정리는 [04-STAGE4-WRAPUP](04-STAGE4-WRAPUP.md)) | 7교시 · 8교시 |
---
## 1 / 30 · 표지
```mermaid
flowchart LR
M["재기"] --> F["병목"] --> C["한 가지 바꾸기"] --> R["다시 재기"]
R --> M
classDef d fill:#0F3D3E,stroke:#0F3D3E,color:#fff
classDef o fill:#F2A541,stroke:#F2A541,color:#fff
class M,R d
class F,C o
```
**72일차**
# Workflow 실행 흐름 최적화와 운영 관점 개선
빠르게, 그리고 멈춰도 답하게 · 재고 나서 고친다
<sub>노코드 멀티 에이전트 워크플로우 설계 및 운영 · 2026-10-26</sub>
---
## 2 / 30 · 오늘 할 수 있게 될 세 가지
| | 목표 | 내용 |
| :-: | --- | --- |
| **①** | **재서 병목을 찾는다** | p50 · p95 · 첫 호출 · `bench` · 단계별 `timings` · 종류별 재기 · 시간 예산 |
| **②** | **품질은 그대로 빠르게 만든다** | 규칙 먼저 · 캐시 · 적중률 · 캐시 키 설계 · 검토를 검사로 · 잃은 것 |
| **③** | **멈춰도 정해진 답을 한다** | timeout · 재시도 · 오류 출력 · LLM 없이 답 · 부분 고장 · 차단기 · 상태 점검 |
---
## 3 / 30 · 오늘의 시간표
| 교시 | 시간 | 무엇 |
| --- | --- | --- |
| 1 | 09:00~09:50 | 개요 · **1단계 강의** 재기와 병목 |
| 2 | 10:00~10:50 | **Lab 01** 실습 5개 |
| 3 | 11:00~11:50 | **2단계 강의** 실행 흐름 최적화 |
| 4 | 12:00~12:50 | **Lab 02** 실습 5개 |
| - | 13:00~14:00 | 점심 |
| 5 | 14:00~14:50 | **3단계 강의** 운영 관점의 안정성 |
| 6 | 15:00~15:50 | **Lab 03** 실습 5개 |
| 7 | 16:00~16:50 | 바이브 코딩 `tbench` (요청서 → TODO → SPEC → IMP-PLAN → 만들기 → 설치) |
| 8 | 17:00~17:50 | 발표 · **4단계 정리** (의미 · 효과 · 실전 응용) · 73일차 예고 |
> 강의 한 시간, 실습 한 시간. 실습은 Lab마다 **예제 3개 + 과제 2개**.
---
## 4 / 30 · 오늘 고칠 것: 느린 실습 워크플로우 (IT 헬프데스크)
```mermaid
flowchart LR
W(["질문"]) --> C{{"분류 LLM"}} --> D["FAQ · 접수"] --> A{{"답 LLM"}} --> R{{"검토 LLM"}} --> S(["답"])
```
| `base-helpdesk` (VPN 질문) | 10/18 | 10/24 |
| --- | --- | --- |
| LLM 호출 | 3번 | 3번 |
| push 직후 첫 호출 | 6.5초 | 4.4초 |
| 그 뒤 5번 | p50 2.61초 · p95 2.83초 | p50 2.69초 · p95 2.98초 |
| FAQ가 8초 느릴 때 | 9.0초 기다림 | 11.5초 |
| FAQ · LLM 오류 | HTTP 500 | HTTP 500 |
---
## 5 / 30 · 일하는 순서 (오늘은 고치기)
```mermaid
sequenceDiagram
participant 나
participant 에이전트 as ① CLI 에이전트
participant 도구 as ② flow.py
나->>도구: bench · call -v (재기)
나->>에이전트: 요청문 (바꿀 것 하나 · 그대로 둘 것 · 기대 결과)
에이전트-->>나: my-work/helpdesk.json · check ✔
나->>도구: push · test -v · bench (다시 재기 + 품질)
나->>도구: fault · llm down (고장 연습)
```
---
## 6 / 30 · 오늘의 실습 15개
| | 예제 1 | 예제 2 | 예제 3 | 과제 1 | 과제 2 |
| --- | --- | --- | --- | --- | --- |
| **Lab 01** 재기 | bench 기준 | 단계별 `timings` | 종류별 재기 · LLM 몫 | FAQ · 접수 나누기 · `slowest_step` | 시간 예산 `over_budget` |
| **Lab 02** 빠르게 | 규칙 먼저 | 질문 캐시 | 적중률 재기 | 검토 → 검사 (LLM 한 번) | FAQ 번호 캐시 `cache_by` |
| **Lab 03** 안정성 | timeout · 재시도 | LLM 없이 답 | 접수 API만 멈춤 | 상태 점검 `my-health` | 차단기 `breaker-faq` |
> 예제 3은 대부분 **재기만** 합니다 (Lab 03 예제 3은 만들기). 과제는 팀장의 말로 옵니다.
---
## 7 / 30 · 1단계 · 재기 전에 고치지 않기
| 짐작 | 실측 (10/24) |
| --- | --- |
| "데이터 API가 느릴 것" | FAQ · 접수 조회 합쳐 **18~43ms** |
| "IT 밖 질문은 금방 끝날 것" | 점심 메뉴도 **2.48초** (LLM 세 번) |
| "push 하면 바로 평소 속도" | 첫 호출 **4.4초** |
> 재기 → 병목 → **한 가지** 바꾸기 → 다시 재기 (품질도)
---
## 8 / 30 · 1단계 · p50 · p95 손으로
```text
1.1 1.2 1.2 1.3 1.3 1.4 1.4 1.5 1.6 9.8 (초, 예시)
```
| 평균 | p50 | p95 | max |
| --- | --- | --- | --- |
| 2.18초 | 1.3초 | 9.8초 | 9.8초 |
> 평균 2초는 **아무에게도 맞지 않는다.** 보통(p50)과 느린 쪽(p95)을 함께.
---
## 9 / 30 · 1단계 · 첫 호출과 같은 날 비교
| 날 | 첫 호출 | p50 | p95 |
| --- | --- | --- | --- |
| 10/18 | 6.5초 | 2.61초 | 2.83초 |
| 10/23 | 6.3초 | 3.14초 | 3.22초 |
| 10/24 | 4.4초 | 2.69초 | 2.98초 |
> 같은 워크플로우도 날마다 0.5초 다르다 → **바꾸기 전 · 후는 같은 날**. 첫 호출은 따로 (워밍업).
---
## 10 / 30 · 1단계 · 어디서 재나
| 어디서 | 보이는 것 | 한계 |
| --- | --- | --- |
| `flow.py bench` | 사용자가 기다린 시간, p50 · p95, 실패 | 안은 모름 |
| Executions | 노드마다 시간 | 한 번씩 눈으로 |
| 결과의 `timings` | 단계마다 ms (매번, 테스트로도) | 직접 만듦 (2교시 Lab 01 예제 2) |
---
## 11 / 30 · 1단계 · 단계별 시간 (Lab 01 예제 2)
```mermaid
flowchart LR
S["t0"] --> C{{"classify"}} --> T1["t1"] --> D["data"] --> T2["t2"] --> A{{"answer"}} --> T3["t3"] --> R{{"review"}} --> T4["t4"]
```
| classify | data | answer | review | total |
| --- | --- | --- | --- | --- |
| 616 ms | 18 ms | 1124 ms | 920 ms | 2698 ms |
> 10/24 VPN 한 번. `steps` · `llm_calls`도 **워크플로우가** 남긴다.
---
## 12 / 30 · 1단계 · 종류별로 재기 (Lab 01 예제 3)
| 질문 | p50 | total | LLM 몫 |
| --- | --- | --- | --- |
| FAQ (VPN) | 2.91초 | 2698 ms | 98.6% |
| 접수 (T-1002) | 2.99초 | 2647 ms | 97.8% |
| IT 밖 (점심) | 2.48초 | 2482 ms | 98.7% |
> 세 종류 모두 **LLM이 98%**. 병목은 HTTP가 아니라 LLM 호출 수.
---
## 13 / 30 · 1단계 · 어림 계산과 가장 느린 단계 (Lab 01 과제 1)
| 없애면 | 남는 시간 | 줄어듦 |
| --- | --- | --- |
| 데이터 조회 | 2.68초 | 0.7% |
| 분류 LLM | 2.08초 | 23% |
| 검토 LLM | 1.78초 | 34% |
| 분류 + 검토 | 1.16초 | 57% |
`slowest_step`: 10/24 네 번 중 answer 2 · review 1 · classify 1 (첫 호출) — 실행마다 바뀐다.
---
## 14 / 30 · 1단계 · 시간 예산 (Lab 01 과제 2)
| 예산 | `total_ms` | `llm_ms` | `over_budget` |
| --- | --- | --- | --- |
| 500 | 2609 | 2563 | true |
| 3000 (기본) | 3023 | 2973 | **true** |
| 3000 (접수) | 2904 | 2858 | false |
> 예산은 **사용자 쪽에서** 정한다. 넘어도 답은 보내고 **기록**한다 → 모으면 목표 수준(SLO).
---
## 15 / 30 · 2단계 · LLM 호출 줄이기
```mermaid
flowchart LR
Q(["질문"]) --> K{"캐시?"} -->|있음| Z(["0.05초"])
K -->|없음| D["데이터"] --> R{"규칙?"} -->|예| A{{"답 1번"}}
R -->|아니오| C{{"분류"}} --> A
A --> V["검사 (Code)"]
```
| LLM | 꼭 LLM이어야 하나 |
| --- | --- |
| 분류 | 번호 · FAQ 결과로 **규칙이 대부분** |
| 답 | 예 |
| 검토 | 말투는 지시문, 빈 답 · 길이 · 한국어는 **코드** |
---
## 16 / 30 · 2단계 · 규칙 먼저 (Lab 02 예제 1)
```mermaid
flowchart LR
D["FAQ · 접수 조회"] --> R{"규칙"}
R -->|"T-1234"| T["ticket"]
R -->|"FAQ 결과"| F["faq"]
R -->|"모름"| L{{"분류 LLM"}}
```
> 규칙을 쓰려면 **데이터 조회가 먼저** (20~40ms라 손해 없음). 규칙도 테스트한다.
---
## 17 / 30 · 2단계 · 캐시해도 되나 (Lab 02 예제 2)
| 답 | 캐시 | 까닭 |
| --- | --- | --- |
| VPN FAQ 답 | 예 | 같은 질문이면 같은 답 |
| "T-1002 상태" | **아니오** | 상태가 바뀜 |
| 본인 접수 건 | **아니오** | 남의 답이 나갈 수 있음 |
> 같은 질문 두 번째 **0.05초**, `llm_calls: 0` (10/24). 캐시는 **테스트도** 바꾼다 → `before`에 비우기, `no_cache`.
---
## 18 / 30 · 2단계 · 적중률 (Lab 02 예제 3)
| 적중률 | 평균 (어림, 0.05초 · 2.0초) |
| --- | --- |
| 0% | 2.00초 |
| 10% | 1.81초 |
| 30% | 1.42초 |
| 60% | 0.83초 |
> 캐시가 빨라도 **적중률이 낮으면 평균은 그대로**. 사람들은 같은 것을 다른 말로 묻는다.
---
## 19 / 30 · 2단계 · 캐시 키 설계 (Lab 02 과제 2)
| 키 | 적중 | 위험 |
| --- | --- | --- |
| 질문을 고친 글자 | 낮음 | 거의 없음 |
| **FAQ 번호** `faq-FAQ-003` | 높음 | 답이 질문에 맞춰지지 않음 |
| 뜻 (임베딩) | 높음 | 다른 질문에 같은 답 (오늘 안 함) |
| 10/24 | 결과 |
| --- | --- |
| "VPN 연결이 계속 끊어지는데요" (다른 말) | `cache_by: faq`, LLM 0번, **0.1초** (전에는 1.2초) |
---
## 20 / 30 · 2단계 · 검토를 검사로 (Lab 02 과제 1)
| 날 | LLM 2번 | LLM 1번 |
| --- | --- | --- |
| 10/18 | 2.01초 | **1.15초** |
| 10/23 | 2.39초 | **1.32초** |
| 10/24 | 2.22초 | **1.12초** |
(캐시 없이 VPN p50) · 검토 LLM은 10/24에 "처리 중"을 "승인 대기 중"으로 바꿔 써서 테스트를 깼다.
---
## 21 / 30 · 2단계 · 빨라진 만큼 잃은 것
| 바꾼 것 | 잃은 것 |
| --- | --- |
| 규칙 먼저 | 규칙이 틀리면 엉뚱한 분류 |
| 질문 캐시 | 오래된 답 · 남의 답 → **접수 현황은 캐시 안 함** |
| FAQ 번호 캐시 | 질문에 맞춘 답 |
| 검토 → 검사 | 뜻을 보는 검토 |
> 품질 테스트는 **답의 내용**을 본다. 구조(`llm_calls: 3`)를 고정한 테스트는 최적화를 막는다.
---
## 22 / 30 · 3단계 · 멈추는 방식
| 고장 | 고치기 전 |
| --- | --- |
| FAQ 느림 (8초) | 9.0 · 13.2 · 11.5초 기다림 |
| FAQ 오류 (500) | 0.1~0.2초 만에 HTTP 500 |
| LLM 키 틀림 | HTTP 500 |
| 접수 API만 오류 | FAQ 질문까지 담당자 연결 |
> 느림 → timeout · 오류 → 정해진 답 · 일부만 → 그 부분만 · 계속 → 차단기
---
## 23 / 30 · 3단계 · timeout · 재시도 · 오류 출력 (Lab 03 예제 1)
```mermaid
flowchart LR
H["HTTP<br/>timeout 2초"] -->|실패| R["0.5초 뒤<br/>한 번 더"] -->|실패| E["오류 출력 →<br/>담당자 연결"]
```
| 설정 | 최악 |
| --- | --- |
| 2초 × 2번 + 0.5초 | **4.5초** (실측 4.6~4.7초) |
| 2초 × 3번 + 0.5초 × 2 | 7.0초 |
> 재시도는 "잠깐 끊긴" 고장에. "계속 느린" 고장에는 차단기.
---
## 24 / 30 · 3단계 · 옵션은 재 보고 쓴다
| 설정 | 404 | 500 |
| --- | --- | --- |
| 없음 | 재시도 → 오류 출력 | 재시도 → 오류 출력 |
| `neverError` | 재시도 → **보통** | 재시도 → **오류** 출력 |
| + `fullResponse` | 바로 보통 (`statusCode`) | 바로 보통 (`statusCode: 500`) |
> 10/24 시험 워크플로우로 잼. 수업 준비 때 적은 "neverError는 500도 성공"은 **틀렸다.** 짐작하지 않고 잰다.
---
## 25 / 30 · 3단계 · LLM 없이 답하기 (Lab 03 예제 2)
| `llm down` | 고치기 전 | 고친 뒤 |
| --- | --- | --- |
| VPN | 500 | `간단 답변` FAQ 원문 |
| T-1002 | 500 | `간단 답변` 상태 그대로 |
| 점심 메뉴 | 500 | `담당자 연결` |
> 데이터로 답할 수 있는 것은 데이터로. 평소 답과 **같은 척하지 않는다.**
---
## 26 / 30 · 3단계 · 부분 고장 (Lab 03 예제 3)
| 접수 API 500일 때 | Lab 03 예제 2까지 | Lab 03 예제 3 정답 |
| --- | --- | --- |
| T-1002 | 담당자 (`data_api_down`) | 담당자 (`tickets_down`) |
| **VPN** | **담당자** | **자동 답변** |
| T-9999 (404) | 자동 답변 | 자동 답변 |
> 멈춘 **부분만** 줄이고 나머지는 평소대로 (우아한 저하). `fullResponse`로 상태 코드를 보고 나눈다.
> 덤: Lab 03 예제 1의 재시도가 404에도 걸려 평소 VPN `data_ms`가 605ms였다 → Lab 03 예제 3 뒤 38ms.
---
## 27 / 30 · 3단계 · 차단기 (Lab 03 과제 2)
```mermaid
stateDiagram-v2
[*] --> 닫힘
닫힘 --> 열림: FAQ 실패 → breaker-faq 저장 (30초)
열림 --> 닫힘: 30초 뒤 저절로
```
| FAQ 느림 | 결과 |
| --- | --- |
| 처음 질문 | 4.8초 뒤 담당자 (`data_api_down`) |
| 다음 질문 | **0.1초** 담당자 (`breaker_open`) — 차단기 없으면 4.6초 |
---
## 28 / 30 · 3단계 · 상태 점검 (Lab 03 과제 1)
```mermaid
flowchart LR
W(["my-health"]) --> A["/health"] --> F["FAQ 검색"] --> L{{"LLM 'OK'"}} --> S["ok · degraded · down"]
```
| 원칙 | 10/23 |
| --- | --- |
| 점검마다 짧은 timeout | FAQ 느림에도 3.1초 |
| 하나가 실패해도 끝까지 | FAQ 오류 → `degraded` |
| 상태는 코드가 | LLM 멈춤 → `degraded` |
---
## 29 / 30 · 7교시 · 바이브 코딩 `tbench`
```mermaid
flowchart LR
T["Doc/TODO.md"] --> S["Doc/SPEC.md"] --> P["Doc/IMP-PLAN.md<br/>엔진 → TUI"] --> I["단계별 구현"] --> C["확인"] --> U["uv tool install"] --> O["다른 폴더에서"]
```
| 요구 14개 | |
| --- | --- |
| 엔진 | R1 N번 · p50 · p95 · 실패 / R3 저장 · 비교 / R4 동시 / R6 첫 호출 · warmup / R7 실패 종류 / R8 키 가리기 / R9 `timings` 평균 / R10 기준 · 종료 코드 / R11 JSON Lines / R12 설정 / R13 기록 목록 |
| TUI | R2 오는 대로 표 · 스파크라인 / R5 요청 고르기 |
| 설치 | R14 `uv tool install` · 어느 폴더에서나 |
> 50분 안: 엔진 1단계 + TUI 1단계 + 설치. 큰 일은 **다단계로**, 단계마다 확인 · 체크 · commit.
--- | --- |
| R1 | N번 부르고 p50 · p95 · max · 실패 |
| R2 | TUI · 스파크라인 · 오는 대로 표 |
| R3 | 저장 · 바꾸기 전후 비교 (조건이 다르면 경고) |
| R4 | 동시에 k개 |
| R5 | turl 요청 다시 쓰기 |
`요청서 → SPEC 10분 → 1 글자로 → 2 TUI → 3 저장 · 비교 · 동시 → 4 정리` · 테스트는 가짜 서버로
---
## 30 / 30 · 오늘의 정리 · 73일차 예고
| 단계 | 한 줄 |
| --- | --- |
| 1단계 | 고치기 전에 잰다. p95 · 첫 호출 · 단계별 · 종류별 · 시간 예산 |
| 2단계 | 병목(LLM)을 규칙 · 캐시 · 검사로 줄이고, 키를 설계하고, 품질을 다시 확인 |
| 3단계 | timeout · 재시도 · 대체 답 · 부분 고장 · 차단기로 정해진 시간에 정해진 답, 상태 점검 |
| 바이브 코딩 | 재는 도구도 테스트한다 (가짜 서버) |
- 73일차: **입력·출력 검증과 응답 필터링, Workflow 보안** — 들어오는 질문과 나가는 답을 검사하고, 지시문 공격 · 개인정보를 막기
- 바이브 코딩: `tscan` · 폴더 · git에 올리기 전 파일에서 API 키 · 개인정보를 찾아 가려 보여 주기