24장. 서비스 통합과 실행
돌아보기 — 아키텍처의 네 칸은 어디서 채워졌나
한 줄 요약
1장에서 코드 한 줄 없이 그렸던 아키텍처 그림에는 도구 · 지식 · 기억 · 오케스트레이션 네 칸이 있었습니다. 스물네 장을 지나며 그 칸이 전부 실제 파일로 채워졌습니다. 마지막으로 그림으로 돌아가 어느 칸이 어느 장에서, 어느 파일로 채워졌는지 짚어 봅니다.
1. 1장의 그림

1장에서 이 그림을 두고 이렇게 말했습니다. "이후의 모든 장은 이 그림의 빈칸 하나씩을 실제 코드로 채우는 일입니다." 이제 빈칸이 없습니다.
2. 네 칸과 채운 장
| 구성요소 | 1장에서 한 말 | 채운 장 | 남은 파일 |
|---|---|---|---|
| 도구 | 확인하고 처리하는 손 | 5~8장, 21장 | 조회 도구 haru_tools.py, 처리 도구 haru_actions.py |
| 지식 | 답의 근거가 되는 문서 | 12~15장 | chroma_db/, 정책안내 에이전트의 search_policy |
| 기억 | 대화를 이어 가는 힘 | 16~17장 | run_supervisor의 이력, 서버의 histories |
| 오케스트레이션 | 지휘 체계 | 18~23장 | haru_agents.py(전문 에이전트 셋), haru_supervisor.py, lesson23_hitl.py(사람의 승인) |
그리고 네 칸을 고객과 상담원이 쓸 수 있게 한 서버로 묶은 것이 이번 장의 app/main.py입니다. 그림 맨 아래의 "서빙" 칸입니다.
도구 — 5~8장, 21장
| 장 | 채운 것 |
|---|---|
| 5장 | 모델이 함수를 고르고 코드가 실행한다는 왕복의 원리 |
| 6장 | 실제 주문 데이터를 조회하는 도구 |
| 7장 | 도구가 여러 개일 때 설명글로 고르게 하기 |
| 8장 | 본인 확인, 개인정보 마스킹, 읽기와 쓰기의 구분 → haru_tools.py |
| 21장 | 처리 도구 — 배송지 변경, 교환 접수, 환불·취소 승인 요청. 되는지 안 되는지는 코드가 판정한다 → haru_actions.py |
도구는 두 묶음입니다. 그림의 "조회 도구"가 haru_tools.py, "처리 도구"가 haru_actions.py입니다.
| 조회 도구 | 처리 도구 | |
|---|---|---|
| 하는 일 | 읽는다 | 쓴다 (처리 기록을 남긴다) |
| 쥐고 있는 에이전트 | 주문조회 | 요청처리 하나뿐 |
| 검수에서 본 결과 | 주문번호와 재고 숫자가 데이터와 맞았다 | A00001 교환접수, A00002 배송지변경이 그 자리에서 처리됐다 |
Q8에서 기간이 지난 반품을 접수하지 않은 것, 티켓의 고객 이름이 "김*윤"으로 저장된 것도 이 칸의 결과입니다.
지식 — 12~15장
| 장 | 채운 것 |
|---|---|
| 12장 | 정책 PDF를 읽어 잘게 나누기 |
| 13장 | 의미로 검색할 수 있게 저장하기 → chroma_db/ |
| 14장 | 찾은 조항을 근거로 답하고, (근거: …) 를 붙이기 |
| 15장 | 검색 품질 높이기 |
Q3과 Q4의 답 끝에 붙은 "(근거: … 제N조)"가 이 칸의 결과입니다. Q5에서 VIP 등급의 반품 배송비 면제를 멤버십 정책 제2조에서 찾아 답한 것, Q7에서 환불 기간을 정책 제5조를 근거로 답한 것도 같은 칸이 한 일입니다.
기억 — 16~17장
| 장 | 채운 것 |
|---|---|
| 16장 | 대화 이력을 보관해 "그거"를 이해하게 하기 |
| 17장 | 긴 대화를 요약하고, 다음 방문까지 남는 고객 정보 |
"그중 이어폰은 언제 발송된 거예요?"가 주문번호로 풀려 넘어간 것이 이 칸의 결과입니다. 서버의 histories 딕셔너리는 16장의 이력을 session_id별로 늘어놓은 것입니다.
서버에 붙일 수 있는 부품도 하나 남아 있습니다. 17장에서 만든 요약과 장기 기억은 아직 app/main.py에 연결하지 않았습니다. 지금 서버는 16장의 이력만 씁니다. 부품은 만들어 두었으니, 긴 대화와 재방문 고객을 다루게 될 때 붙이면 됩니다.
오케스트레이션 — 18~23장
| 장 | 채운 것 |
|---|---|
| 18장 | 처리 흐름을 그래프(상태, 노드, 엣지)로 그리기 |
| 19장 | 문의마다 갈 길을 가르는 조건 분기 |
| 20장 | 복합 문의를 쪼개 처리하기 |
| 21장 | 전문 에이전트 셋(주문조회, 정책안내, 요청처리) → haru_agents.py |
| 22장 | 이들을 지휘하는 Supervisor → haru_supervisor.py |
| 23장 | 사람의 승인 — 되돌릴 수 없는 일 앞의 승인 게이트 |
Q6에서 주문조회, 정책안내, 요청처리가 차례로 불리고 세 보고가 답 하나로 묶인 것, Q9에서 주문조회 뒤에 요청처리가 이어져 배송지가 바뀐 것이 이 칸의 결과입니다.
사람도 이 지휘 체계 안에 있습니다. 그림의 처리 도구 칸에 적힌 "환불·취소 승인 요청 → 사람의 승인"이 그 자리입니다.
| 일의 성격 | 누가 끝내나 | 검수에서 |
|---|---|---|
| 되돌릴 수 있는 처리 | 요청처리 에이전트가 직접 | Q6 교환 접수, Q9 배송지 변경 |
| 되돌릴 수 없는 처리 (돈이 나간다) | 에이전트는 승인 요청까지, 사람이 승인 | Q10 주문 취소 |
| 에이전트가 처리할 수 없는 일 | 티켓으로 사람에게 넘긴다 | Q8-② 상담원 연결 |
23장에서 interrupt로 만든 승인 게이트와 이번 장의 상담원 화면은 같은 설계의 두 모습입니다. 요청을 승인대기로 등록하는 request_refund, 사람의 결정을 기록하는 decide가 양쪽에서 똑같이 쓰입니다. 23장은 그 사이의 기다림을 그래프의 멈춤으로, 이번 장은 상담원 화면의 승인 대기 목록으로 보여 주었습니다.
3. 문의 하나가 지나간 길
Q6 "지난주에 산 운동화가 불량이에요. 검정 270으로 교환 접수해 주세요."가 지나간 길을 따라가며 네 칸을 한 번에 봅니다.
| 순서 | 일어난 일 | 구성요소 | 만든 장 |
|---|---|---|---|
| 1 | 화면이 session_id와 함께 문의를 보낸다 |
(서버) | 24장 |
| 2 | 서버가 이 대화의 이력을 꺼내 문의를 붙인다 | 기억 | 16장 |
| 3 | Supervisor가 주문조회 에이전트에게 위임한다 | 오케스트레이션 | 22장 |
| 4 | 주문조회 에이전트가 주문 목록에서 운동화 주문을 찾고 등급을 조회한다 | 도구 (조회) | 6~8장 |
| 5 | Supervisor가 정책안내 에이전트에게 위임한다 | 오케스트레이션 | 22장 |
| 6 | 정책안내 에이전트가 불량 교환 조항을 검색한다 | 지식 | 13~14장 |
| 7 | Supervisor가 주문번호와 바꿀 옵션을 적어 요청처리 에이전트에게 위임한다 | 오케스트레이션 | 22장 |
| 8 | 요청처리 에이전트가 request_exchange를 부르고, 코드가 기간과 재고를 판정해 교환을 접수한다 |
도구 (처리) | 21장 |
| 9 | Supervisor의 코드가 기록 파일을 확인해 처리번호 A00001을 보고에 붙인다 |
오케스트레이션 | 22장 |
| 10 | Supervisor가 세 보고를 한 답으로 묶는다 | 오케스트레이션 | 22장 |
| 11 | 서버가 이벤트로 흘려보내고 이력을 갱신한다 | (서버) + 기억 | 24장 |
같은 시각 상담원 화면의 처리 내역에는 A00001 교환접수 · 완료가 올라옵니다. 이 요청이 교환이 아니라 환불이었다면 8번에서 승인대기로 등록되고, 그 뒤에 사람의 승인이라는 한 단계가 더 있었을 것입니다.
10초 남짓한 시간 동안 스물네 장의 거의 모든 부품이 한 번씩 일했습니다.
4. 과정 내내 반복된 것
네 칸을 채우는 동안 같은 판단이 여러 번 되풀이되었습니다. 기술 이름보다 이 판단이 남아야 합니다.
| 되풀이된 판단 | 나온 곳 |
|---|---|
| 고르는 것은 모델, 실행하는 것은 코드 | 5장 도구 호출, 22장 위임 |
| 틀리면 안 되는 값과 판정은 코드가 만든다 | 3장 환불액, 8장 티켓번호, 21장 기간·출고·재고 판정, 22장 [시스템 확인] |
| 하면 안 되는 일은 할 수 없게 만든다 | 8장 환불 실행 도구 없음, 22장 별 모양 구조, 23장 사람을 지나야만 닿는 decide |
| 되돌릴 수 없는 결정은 사람이 내린다 | 1장 방침, 21장 승인 요청까지만, 23장 승인 게이트, 24장 상담원 화면 |
| 규정은 짐작이 아니라 문서에서 | 12~15장, 21장 정책안내 에이전트 |
| 모르면 모른다고 하게 한다 | 3장 프롬프트, 14장 근거 없는 답 거절 |
| 바꿀 때마다 같은 질문으로 다시 확인한다 | 1장 질문 12개, 24장 최종 검수 |
모델은 바뀝니다. 프레임워크도 바뀝니다. 위의 일곱 줄은 모델이나 프레임워크가 바뀌어도 그대로 쓸 수 있습니다.
5. 범위를 넓히려면 어느 칸에 무엇을 더하나
1장에서 이 시스템의 범위를 고객지원으로 정했습니다. 범위를 넓히는 일도 같은 네 칸으로 적을 수 있습니다.
| 넓히려는 일 | 더할 것 | 구성요소 |
|---|---|---|
| 조건으로 상품을 찾아 추천하기 | 가격·평점으로 거르는 검색 도구, 리뷰 데이터와 그 검색 저장소, 추천을 맡는 네 번째 전문 에이전트 | 도구 · 지식 · 오케스트레이션 |
| 승인된 환불을 실제로 내보내기 | decide가 승인완료로 기록한 직후 결제 대행사의 환불 API를 호출 |
도구 |
| 상담원이 다음 날 승인해도 이어지는 긴 처리 | 23장의 그래프를 서버에 연결하고 체크포인터를 데이터베이스 기반으로 교체 | 오케스트레이션 |
| 여러 고객이 로그인해 쓰기 | 로그인한 고객마다 CustomerSession을 만들기 |
(서버) · 도구 |
| 서버를 다시 켜도 남는 대화 | 이력을 바깥 저장소에, 17장의 요약·장기 기억을 연결 | 기억 |
네 번째 에이전트를 붙이는 방법은 이미 압니다. 21장처럼 도구와 프롬프트를 묶어 에이전트를 만들고, 22장처럼 함수로 감싸 Supervisor의 도구 목록에 넣고, 운영 원칙에 한 줄을 더한 뒤, 표준 질문 열두 개에 새 질문을 더해 다시 돌립니다. 새 기능을 "어느 칸에 무엇을 더하는 일"로 말할 수 있다는 것이 이 과정을 마치고 남는 것입니다.
핵심 정리
- 네 칸은 도구(5~8장, 21장) · 지식(12~15장) · 기억(16~17장) · 오케스트레이션(18~23장) 에서 채워졌고, 24장이 이를 한 서버로 묶었습니다.
- 도구는 조회 도구(
haru_tools.py)와 처리 도구(haru_actions.py) 두 묶음이고, 오케스트레이션에는 요청처리 에이전트와 사람의 승인이 들어 있습니다. - 남은 파일은
haru_tools.py,haru_actions.py,chroma_db/,haru_agents.py,haru_supervisor.py,app/main.py입니다. - 문의 하나가 처리되는 동안 네 구성요소가 모두 한 번씩 일합니다.
- 17장의 요약·장기 기억은 만들어 둔 부품이고, 서버에 붙이는 일이 다음 확장입니다.
- 남는 것은 기술 이름이 아니라 되풀이된 판단입니다. 고르는 것은 모델, 실행과 보증은 코드, 바꿀 때마다 같은 질문으로 다시 확인.
- 범위를 넓히는 일을 어느 칸에 무엇을 더하는지로 말할 수 있습니다.