문서 읽는 데 236분 · day12

Day 12. 에이전트의 정의 — "방금 만든 게 에이전트인가?

전체 26강 중 13강 · 스프링 AI
난이도 · 심화선수지식자바 기초스프링 부트

ℹ️스프링 부트로 만든 ai-friends 프로젝트 위에 얹어 진행해요. 자바·스프링이 처음이라면 먼저 “서버 만들기” 트랙부터 권해요.

안녕하세요! 여러분의 백엔드 가이드, 홍순구 튜터입니다.

Day 11, 정말 묵직하게 닫으셨죠.

지난 시간엔 결정의 일부를 LLM 에게 처음으로 넘겨주는 단계를 같이 익혔어요.

@Tool 어노테이션 한 줄에 LLM 이 알아서 우리 Java 메서드를 부르는 흐름.

읽기 전용 도구 (WeatherTool / AffinityTool) vs 부작용 도구 (GameStateTool) 의 갈래.

그리고 마지막 Step 5 에서 잠깐만 비춰뒀던 그림자 4 가지 (무한 루프 / 토큰 폭발 / 도구 남용 / 권한 누수) 까지.

마지막 한 줄이 이렇게 떨어졌었죠.

"오늘 우리가 짠 Java 메서드 3 개에 @Tool 한 줄을 붙였더니 — LLM 이 알아서 부르더라구요. 그런데 — 이게 에이전트 인가요? 아닌가요? 그 답은 — 다음 시간."

오늘이 그 약속의 날이에요.

방금 만든 게 에이전트인가?.

이 한 줄에 정면으로 답하는 시간입니다.

그리고 지난 시간 그림자 로만 슬쩍 비쳐뒀던 4 가지가.

오늘은 진짜 사고 화면 으로 한 단계 더 들어가요.

30 초 컷 무한 루프 / 같은 도구 수십 번 호출 / 토큰 예산 폭발의 청구서우리가 짠 ChatClient 코드를 한 글자도 안 건드리고 라이브로 망가뜨려 보는 시간.

Day 11 의 그림자가.

Day 12 에 실제 사고 화면으로 펼쳐지는 대목이에요.

자, 핵심부터 단단히 짚고 시작할게요.

오늘은.

코드보다 머리가 무거운 Day 예요. Day 1 부터 Day 11 까지 우리는 으로 익혀왔어요.

chatModel.call()ChatClient.Builder@Tool 까지.

매일 새 코드를 직접 짰죠.

오늘은 호흡이 한 단계 다릅니다.

오늘은 신규 코드가 거의 0 이에요.

대신.

판단 근육 / 분류 능력 / 폭주에 대한 직관 을 키우는 시간이에요.

지난 시간에 만든 도구 3 종이 Workflow 쪽인지 Agent 쪽인지분류대 위에 직접 올려보고, 루프가 한 번 더 돌면 / 다섯 번 돌면 / 열 번 돌면.

그땐 에이전트인가? 라는 질문을 내 손으로 라이브 시연으로 부숴보는 시간.

오늘은 코드 적게, 머리 무겁게.

그게 오늘의 호흡이에요.

오늘 마지막에 정리할 본 강의의 정의 한 줄 을 미리 던져둘게요.

에이전트 = 도구 + LLM 자율 + 루프 + 가드레일 4 박자. 이 4 박자 중 Day 11 에서 익힌 단계 는 앞의 두 박자 (도구 + LLM 자율) 까지예요.

뒤의 두 박자 (루프 + 가드레일) 는.

오늘 왜 필요한지 를 이해하고 ("왜"), 모레 Day 14 에서 어떻게 손으로 짜는지 를 익혀요 ("어떻게").

오늘은 왜 / 모레는 어떻게.

이 두 호흡으로 이번 주가 흐릅니다.

그리고 지난 시간에 만든 도구 3 개 (WeatherTool / GameStateTool / AffinityTool) 는.

오늘 분류대 위에 올라가요. Step 6 에서 어느 도구가 Workflow 쪽인지, 어느 도구가 Agent 쪽인지 직접 손으로 분류해 봅니다.

오늘의 척추가 되는 글이 한 편 있어요.

*Anthropic 이 2024년 12월에 공개한 Building Effective Agents.

이 글의 메시지는 한 줄로 압축됩니다.

"Workflow 로 충분하면 Workflow 로 둬라." 2025 ~ 2026 업계 표준 톤이 된 문장이에요.

2026 년 지금 OpenAI Agents SDK / Google ADK / LangGraph / AutoGen 같은 에이전트 프레임워크 들이 줄지어 등장했지만.

어떤 프레임워크를 쓰든 그 글이 제시한 분류 기준 자체는 똑같이 통해요.

본 강의는 그 분류 기준 위에서.

Spring AI ChatClient + Advisors + 평범한 Java 코드 만으로 직접 짜보는 길을 갑니다.

외부 그래프 DSL (Alibaba Graph 등) 은 도입하지 않아요. Day 13 ~ 14 의 Agentic Patterns 도 같은 방향으로 흐릅니다.

🎯 ChatClient → Agent — 오늘 조용히 한 단계 더 깊어집니다

지난 시간에 짚은 🎯 ChatClient — 오늘 조용히 큰 사건이 일어납니다 의 거울 부분이에요. 오늘 — ChatClient 위에서 에이전트의 정의 자체 가 한 단계 더 명확해져요.

ChatClient (Day 11) → ChatClient + 루프 + 가드레일 (Day 12 의 왜 / Day 14 의 어떻게) — 같은 ChatClient 인터페이스 위에서 한 사이클짜리 자율 호출 (Day 11) → 루프가 도는 자율 호출 + 가드레일 (Day 12~14) 으로 한 단계 깊어지는 흐름. Day 11 의 ChatClient 가 에이전트의 가장 작은 시작점이었다면Day 12 는 그 시작점 위에 본격적인 정의가 얹히는 단계. 그리고 그 정의는 Day 19 의 Spring AI Agent Client 까지 한 줄로 이어집니다.

오늘은 그 정의를 코드로 익히는 시간이 아니라 — 판단으로 머리에 정리하는 시간이에요. 코드 변경 0, 의사 결정 무게 100.


Step 1. 에이전트의 정의 — 학문 vs 실무

Day 11 마지막 한 줄을 다시 가져와요. "오늘 짠 Java 메서드 3 개에 @Tool 한 줄을 붙였더니 LLM 이 알아서 부르더라. 그런데 — 이게 에이전트 인가요?" 이 질문에 정면으로 답하는 시간이 지금이에요. 그런데 답이 하나가 아니에요. 정확히 둘 — 학문의 답실무의 답. 그 둘이 어디서 갈라지는지부터 짚어볼게요.

먼저 한 줄 결론. 학문의 정의로 보면 Day 11 코드도 이미 에이전트예요. 실무의 정의로 보면 아직 에이전트가 아니에요. 같은 코드에 답 두 개가 나온다는 점. 그리고 본 강의가 어느 쪽 정의를 채택하는지 는 이 Step 끝에서 한 줄로 정리됩니다.

학문의 정의 — perceive · decide · act 의 3 박자

먼저 학문의 답 부터 볼게요. 출처가 단단해요. Russell & NorvigArtificial Intelligence: A Modern Approach — 1995 년 초판 이후 거의 모든 AI 학부 교과서가 인용하는 책이에요. 이 책의 에이전트 정의 가 한 줄로 압축됩니다.

"환경을 인지(perceive) 하고 / 의사 결정(decide) 하고 / 행동(act) 하는 자율 시스템."

perceive · decide · act. 3 박자예요. 환경에서 신호를 받고, 어떻게 할지 정하고, 정한 대로 행동하는 단계. 이 3 박자가 한 사이클이라도 돌면 학문적으로는 에이전트. 학부 강의실의 룸바 청소기 예시가 익숙하실 거예요. 센서로 벽을 감지(perceive) → 회전 각도를 결정(decide) → 모터를 돌려 회전(act). 학문 정의로는 그 한 사이클이 이미 에이전트예요.

단순해 보여도 정의 안에 들어가요.

이 3 박자를 들고 지난 시간 Day 11 코드로 다시 들어가 볼게요.

ChatClient + @Tool 의 한 사이클이 어떻게 흘렀죠? 사용자가 "오늘 서울 날씨 어때?" 한 줄을 던지면 LLM 이 그 발화를 인지 (perceive).

그 발화를 보고 어.

getCurrentWeather 라는 도구가 등록돼 있는데 이걸 부르면 되겠다 하고 결정 (decide).

그리고 그 도구를 실제로 호출 (act).

perceive → decide → act. 3 박자가 한 사이클에 다 들어가 있죠.

학문 정의로 보면 Day 11 코드도 이미 에이전트의 가장 작은 시작점이에요.

그런데 여기서 멈추지 않습니다.

"학문 정의로 다 끝났네" 하고 넘어가면, 오늘 Step 3 의 폭주 시연도 Step 4 의 Harness 도 Step 7 의 Agentic Patterns 도 왜 필요한지 가 와닿지 않아요.

학문 정의가 너무 헐겁기 때문이에요.

한 사이클짜리 룸바부터 24 시간 도는 자동매매 봇까지 전부 같은 단어 로 부르면, 그 단어가 가리키는 범위가 흐려져요.

그래서 실무의 정의 가 한 단계 더 좁게 들어옵니다.

실무의 정의 — 도구 + LLM 자율 + 루프 + 가드레일 의 4 박자

2025 ~ 2026 LLM 시대로 들어오면서 에이전트 라는 단어의 톤이 한 단계 좁아졌어요.

그 척추가 되는 글이.

지난 시간에 오프닝에서도 한 번 비춰뒀던 *Anthropic 의 Building Effective Agents (2024 년 12 월, Erik Schluntz · Barry Zhang).

이 글이 에이전트Workflow 를 분리해서 정의한 분류가. 2026 년 업계 표준이 됐어요.

OpenAI 의 Agents SDK 문서, Google ADK 의 정의, LangGraph 의 가이드.

모두 비슷한 분류로 흐르고 있어요.

프레임워크는 달라도 정의는 같다.

실무 정의를 한 줄로 정리하면 이래요.

에이전트 = 도구 (Tools) + LLM 자율 (Autonomy) + 루프 (Loop) + 가드레일 (Guardrails) — 4 박자.

학문 정의의 3 박자에 비하면 한 박자가 늘었는데, 그 한 박자 (루프 + 가드레일) 가 실무에서 가장 무거운 부분 이에요. 4 박자를 한 줄씩 풀어 둘게요.

1) 도구 (Tools). LLM 이 부를 수 있는 외부 능력. 지난 시간 Day 11 에서 익힌 @Tool 어노테이션이 붙은 Java 메서드 3 종 (WeatherTool / GameStateTool / AffinityTool) 이 정확히 이 박자에 해당해요. LLM 이 자기 머릿속만으로는 닿을 수 없는 곳 (현재 시각 / DB 조회 / 외부 API 호출 등) 에 손이 닿게 해주는 통로

이게 도구 박자입니다.

2) LLM 자율 (Autonomy). 언제 / 어느 도구를 / 어떤 인자로 부를지를 LLM 이 결정 하는 단계. 이 박자도 지난 시간 Day 11 에서 같이 익혔어요. if-else 로 "날씨 질문이면 WeatherTool 을 호출" 같은 분기를 직접 짜지 않았죠. ChatClient 에 도구를 등록만 하면 LLM 이 알아서 부르는 흐름.

결정 일부를 LLM 에게 넘긴 형태가 정확히 이 박자예요.

3) 루프 (Loop). 자, 여기부터가 Day 11 코드엔 아직 없는 부분 이에요. 지난 시간의 흐름은 한 사이클 이었죠. 사용자 발화 → LLM 이 도구 한 번 호출 → 결과를 받아 답변 한 번 생성 → 끝. 한 번에 종료. 그런데 실무에선 한 사이클로 안 끝나는 경우가 대부분 이에요. 사용자가 "애교 많고 운동 좋아하는 친구 캐릭터 만들어줘" 한 줄을 던지면.

에이전트는 컨셉 정리 도구 → 외모 묘사 도구 → 성격 시트 작성 → 첫 인사말 생성 → 톤 검수 도구 까지 여러 사이클 을 돌아요. 그리고 각 사이클에서 다음 사이클을 결정하는 것 도 LLM 자율의 영역. 한 도구의 결과를 보고 다음 도구를 LLM 이 정한다. 이게 루프 박자의 핵심이에요.

이 동작이 등장하는 게 오늘 Step 7 의 Orchestrator-Workers 패턴이고, Day 14 의 Agentic Patterns 손코딩 입니다.

4) 가드레일 (Guardrails). 루프가 들어오는 순간 그림자도 함께 따라옵니다. 무한 루프 / 토큰 폭발 / 도구 남용 / 권한 누수. 지난 시간 Day 11 마무리에서 그림자 4 가지로 가늘게 비춰뒀던 모습이, 루프가 도는 순간 진짜로 나타나요. LLM 이 "이 도구 한 번 더 부르면 답이 나올 것 같아" 를 30 번 반복하면 토큰 청구서가 30 배. 무한 루프에 빠지면 30 초 안에 청구서가 폭발해요.

루프를 다는 순간 그 루프가 폭주하지 못하게 막는 빗장 이 같이 들어와야 한다. 이게 가드레일 박자예요. 최대 반복 횟수 / 타임아웃 / 토큰 예산 / 도구 호출 횟수 제한. 4 가지 빗장을 Day 14 에서 손으로 짭니다. 오늘 Step 3 에선 그 빗장이 없을 때 어떻게 폭주하는지 를 라이브로 부숴 볼게요. ⚠️

이 4 박자를 들고 지난 시간 Day 11 코드를 다시 분류대 위에 올려볼게요.

지난 시간에 익힌 단계는 앞 두 박자 (도구 + LLM 자율) 까지.

뒤 두 박자 (루프 + 가드레일) 는 아직 비어 있어요.

실무 정의로 보면 Day 11 코드는 4 박자 중 절반만 채워진 상태.

즉 아직 에이전트가 아닙니다. 그럼 지난 시간에 만든 건 뭐냐.

Tool Calling 단계 의 코드이고, 더 큰 분류로는 Workflow 영역에 속해요. (이 Workflow 영역 이 다음 Step 2 에서 본격적으로 풀립니다.)

본 강의가 채택하는 정의 — 한 줄 정리 🎯

자, 두 정의가 정리됐으니 본 강의의 정의를 한 줄로 못 박아둘게요.

본 강의는 — 실무의 정의 를 채택합니다. 4 박자 (도구 + LLM 자율 + 루프 + 가드레일) 가 모두 갖춰진 시점부터 — 에이전트라고 부릅니다.

이 정의가 Day 12 에서 시작해 Day 19 의 Spring AI Agent Client 까지 한 줄로 이어져요.

Day 13 ~ 14 의 Agentic Patterns 손코딩, Day 14 의 가드레일 4 종 손구현, Day 19 의 Agent Client + Bench — 모두 이 4 박자를 따라 흐릅니다.

그래서 오늘 이 정의를 단단히 잡지 않으면 Day 13 에서 "Workflow 패턴이 왜 이게 Workflow 죠? 에이전트 같은데" 같은 흔들림이 누적돼요.

오늘 머리를 무겁게 쓰는 이유가 그래서예요.

용어도 한 번 정리할게요.

본 강의에서는 단어를 이렇게 씁니다.

작은 도구 한 개를 든 채로 한 발만 내딛은 모습 (Day 11) 은 Tool Calling 또는 Workflow. 그 발걸음이 멈추지 않고 자기 스텝으로 걷기 시작하는 단계 (4 박자가 모두 갖춰진 코드) 는 Agent. 한 단어로 에이전트 라고 쓸 때는 늘 후자.

ChatClient 호출 전체에 에이전트 단어를 남발하지 않는 게 본 강의의 약속이에요.

그래서 — Day 11 코드는 무엇인가?

Day 11 의 마지막 한 줄에 이제 정면으로 답할 수 있어요. 두 줄로 나눠서.

  • 학문 정의로 보면 — Day 11 코드는 에이전트의 가장 작은 시작점. perceive · decide · act 의 한 사이클이 분명히 들어가 있으니까요.
  • 실무 정의로 보면 — Day 11 코드는 Tool Calling 단계. 4 박자 중 두 박자 (도구 + LLM 자율) 만 채워진 상태. 뒤 두 박자가 비어 있어서 아직 에이전트가 아니에요.

*본 강의는 실무 정의를 채택하니까 — 지난 시간 코드는 아직 에이전트가 아닙니다. 더 정확히는 Workflow 영역의 가장 단순한 형태예요. 이 결론이 자연스러워야 다음 Step 2 의 Workflow ↔ Agent 스펙트럼 이 매끄럽게 풀려요. 그 스펙트럼 위에서 지난 시간에 만든 도구 3 종이 어디 들어가는지 가 Step 6 에서 분류대 위에 올라갑니다.

한 줄로 압축하면 이래요.

"실무 기준으로는 — 아직 에이전트가 아니에요. 루프와 가드레일이 갖춰진 시점부터 — 비로소 에이전트입니다."

이 한 줄이 오늘 Step 1 의 매듭입니다.

*🙋 날카로운 질문 타임 — "그럼 ChatGPT 의 Code Interpreter 는 에이전트인가요? 한 번에 답이 끝나는 작업도 많아 보이는데..."

좋은 질문이에요. 이 질문이 4 박자 정의에서 가장 헷갈리는 지점을 정확히 짚었어요. Code Interpreter 는 Python 인터프리터 라는 도구를 LLM 이 자율적으로 부르는 시스템인데, 그날그날의 작업 에 따라 한 번 부르고 끝나기도 하고 30 번 반복하기도 해요. 그럼 어느 사용 사례는 에이전트고 어느 사용 사례는 아닌 건가요? — 그렇게 보면 정의가 흔들려요. 그래서 기준을 한 단계 옮겨야 해요. 루프가 도는 빈도 가 아니라 루프를 돌 수 있는 구조가 있느냐 없느냐 — 이게 정의의 척추입니다. Code Interpreter 는 루프를 돌 수 있는 구조가 있어요 (LLM 이 코드 실행 결과를 보고 다음 코드를 결정하는 단계). 그래서 오늘 한 번만 돌았더라도 시스템 자체는 에이전트의 정의 안 에 들어가요. 반대로 Day 11 의 우리 코드는 루프를 돌 수 있는 구조가 없어요 — 한 사이클 후 무조건 사용자 답변으로 끝나는 구조. 한 번 돌든 열 번 돌든 시스템 자체 가 아직 에이전트의 정의에 들어가지 않아요. 정의는 그날의 행동 빈도 가 아니라 시스템의 구조 로 본다 — 이게 답입니다.

💡 튜터의 결론

학문 정의 (perceive · decide · act 의 한 사이클) 로 보면 Day 11 코드도 이미 에이전트지만, 본 강의는 실무 정의 를 채택해요. 에이전트 = 도구 + LLM 자율 + 루프 + 가드레일 — 4 박자가 모두 갖춰진 상태입니다. 지난 시간 코드는 앞 두 박자만 채워졌으니 Tool Calling 단계 이고, 뒤 두 박자 (루프 + 가드레일) 가 들어오는 시점부터 비로소 에이전트라고 부릅니다. 이 정의가 Day 12 ~ 19 까지 한 줄로 이어져요.

자, 이 정의가 정리됐으니 다음 Step 2 에서 Workflow ↔ Agent 스펙트럼 위로 한 발 더 들어가 봅시다. 4 박자가 0 개 채워진 상태 → 1 개 → 2 개 → 3 개 → 4 개 까지의 연속선 이 거기서 풀려요. 지난 시간에 만든 도구 3 종이 그 스펙트럼의 어디쯤 들어가는지도 거기서 윤곽이 잡힙니다.


Step 2. Anthropic Building Effective Agents 요약 — Workflow ↔ Agent 스펙트럼

자, Step 1 의 매듭을 다시 가져와요.

"에이전트 = 도구 + LLM 자율 + 루프 + 가드레일 — 4 박자." 이 한 줄이 지난 시간 코드를 Tool Calling 단계 로 분류해 줬죠.

그런데 한 가지 질문이 자연스럽게 따라 올라옵니다.

그럼 4 박자가 모두 갖춰져야만 에이전트인가요? 일부만 채워진 상태는 뭐라고 부르나요? 한 박자만 비어 있으면 덜된 에이전트 인가요, 아니면 완전히 다른 카테고리 인가요?

이 질문에 정면으로 답한 글이 있어요.

Step 1 에서도 한 번 비춰뒀던 *Anthropic 의 Building Effective Agents (2024 년 12 월, Erik Schluntz · Barry Zhang).

이 글이 제시한 분류 기준이 2025 ~ 2026 업계 표준이 됐고, 본 강의의 척추도 여기에 박혀 있어요.

오늘 Step 2 의 결론은 한 줄.

4 박자가 모두 갖춰진 쪽 (Agent) 과 일부만 채워진 쪽 (Workflow) 은.

이분법이 아니라 스펙트럼 으로 이어진다. 이 스펙트럼 위에 지난 시간에 도구 3 종이 어디 들어가는지 (Step 6), Day 13 ~ 14 의 5 가지 패턴이 어디 들어가는지 (Step 7).

모두 오늘의 분류 기준 위에서 풀려요.

Anthropic Building Effective Agents — 본 강의의 척추가 되는 글

이 글이 왜 본 강의의 척추가 됐는지 짚고 갈게요. 2024 년까지 에이전트 라는 단어는 정의가 너무 헐거웠어요.

AutoGPT 같은 자율 봇 도 에이전트, 간단한 Tool Calling 도 에이전트, 복잡한 Workflow 도 에이전트 — 한 단어가 너무 많은 시스템을 끌어안고 있어서 의미가 흐려져 있었죠.

이 모호함 속에서 2024 년 12 월 Anthropic 이 한 편의 글을 공개했어요.

Building Effective Agents. 이 글의 분류가 단순하고 강력합니다.

에이전트 같은 시스템WorkflowAgent 두 카테고리로 분리해서 정의한 것.

그리고 대부분의 실제 사용 사례에는 Agent 보다 Workflow 가 충분하다 는 한 줄을 못 박았어요.

이 한 줄이 2025 ~ 2026 의 업계 톤을 옮겼습니다.

어떤 에이전트 프레임워크 를 보든.

OpenAI Agents SDK, Google ADK, LangGraph, AutoGen.

각각의 문서·블로그·튜토리얼이 비슷한 분류 로 흐르고 있어요.

프레임워크는 다르지만 분류 기준은 같다. 본 강의가 외부 그래프 DSL 을 도입하지 않고 Spring AI ChatClient + Advisors + 평범한 Java 코드 만으로 5 가지 패턴을 짜는 길을 가는 이유도.

프레임워크가 아니라 분류 기준이 본질 이라는 입장 위에 서 있기 때문이에요.

Workflow vs Agent — 두 카테고리의 정의

자, 이 글이 정의한 두 카테고리를 한 줄씩 정리해 둘게요. 단어 자체가 구분의 척추예요.

Workflow (워크플로우)미리 짜둔 결정론적 코드 경로 위에서 LLM 이 각 단계별로 호출 되는 시스템. 핵심은 다음 단계를 누가 결정하느냐코드 라는 점이에요. 한 단계의 LLM 결과를 받아서 어느 다음 단계로 갈지 / 어느 도구를 부를지 는 우리가 짠 if-else / switch / for 같은 결정론적 분기 가 정합니다.

루프가 있더라도 그 루프는 코드의 루프 (for i in 1..N / while flag). 주도권이 코드 쪽 에 있어요.

Agent (에이전트). LLM 이 언제 도구를 부르고 / 언제 멈출지 까지 스스로 결정 하는 시스템. 다음 단계 선택의 주도권이 LLM 의 자율 에 있어요. 루프가 있다면 그 루프는 코드의 while 가 아니라, LLM 이 "이제 다 됐어요" 라고 말할 때까지 도는 자율 루프 입니다. 코드는 루프가 도는 빈 그릇 만 마련해 줄 뿐. 멈춤의 신호는 LLM 이 보내요.

주도권이 LLM 쪽 에 있는 거예요.

스펙트럼 — 둘은 이분법이 아니라 농도 차이. 자, 여기가 핵심이에요. Workflow 와 Agent 를 두 칸으로 나누는 게 아니라 두 카테고리 사이가 연속선 으로 이어진다는 점. 막대를 펼쳐서 그 위에 점을 찍어 보면 이렇게 흘러요.

완전 결정론적 코드 (LLM 0 박자)Prompt ChainingRoutingParallelizationOrchestrator-WorkersEvaluator-Optimizer완전 자율 Agent (LLM 4 박자)

왼쪽으로 갈수록 결정론 의 농도가 짙어지고, 오른쪽으로 갈수록 LLM 자율 의 농도가 짙어져요.

가운데에 찍힌 5 가지 패턴이 바로 이 스펙트럼 위의 좌표. 이분법이 아니라 농도 차이.

이 감각이 잡혀 있지 않으면 Day 13 에서 "Routing 패턴이 왜 Workflow 죠? 분기를 LLM 이 정하는데" 같은 질문이 풀리지 않아요.

답은.

Routing 의 분기 자체는 LLM 이 정하지만, 그 다음에 어떤 핸들러로 갈지의 코드 경로 자체는 결정론적이라서 스펙트럼의 왼쪽에 놓인다.

💡 한 줄로 압축하면 "누가 다음 결정의 주도권을 쥐고 있느냐" 가 농도의 척도예요. 코드가 더 많이 쥐면 Workflow 쪽 / LLM 이 더 많이 쥐면 Agent 쪽. 0 과 1 의 분류가 아니라 0 ~ 1 의 연속값.

본 강의의 용어 — 한 번 더 단단히

Step 1 에서 정한 용어 약속을 Workflow ↔ Agent 위에서 한 번 더 풀어둘게요. 본 강의는 단어를 이렇게 씁니다.

  • Workflow = 결정론적 orchestration. 다음 단계 / 다음 도구 선택의 주도권이 코드 에 있어요. Day 13 에서 손코딩으로 익혀요. 5 가지 패턴 중 앞 3 개 — Prompt Chaining / Routing / Parallelization 이 이 카테고리.
  • Agent = LLM 자율 결정 + 루프 + 가드레일. 4 박자가 모두 갖춰진 상태. Day 14 에서 손코딩 + 가드레일 4 종 (maxIterations / 타임아웃 / 토큰 예산 / 도구 호출 횟수 제한) 까지 익혀요. 5 가지 패턴 중 뒤 2 개 — Orchestrator-Workers / Evaluator-Optimizer 가 이 카테고리.
  • 그리고 두 카테고리는 이분법이 아니라 스펙트럼. 어디에 둘지는 우리가 판단 하는 거고, 그 판단을 Step 5 의 분류 워크샵 에서 직접 해봅니다.

트레이드오프 매트릭스 — 4 축으로 보는 차이 ⚖️

자, 두 카테고리의 정의가 정리됐으니 어느 곳에 둘지의 판단 을 도와줄 매트릭스를 펼쳐 둘게요. Anthropic 글이 본문에서 풀어놓은 비교를 4 축으로 압축 하면 이래요.

Workflow Agent 한 줄 비교
예측 가능성 ✅ 압승 ⚠️ 약함 코드 경로 고정 vs LLM 자율 — 같은 입력에 같은 결과가 나오느냐
복잡한 자연어 입력 대응력 ⚠️ 약함 ✅ 압승 분기를 코드로 다 짤 수 있느냐 vs LLM 이 알아서 분기하느냐
비용 / 지연 ✅ 압승 ⚠️ 약함 LLM 호출 횟수가 적은 쪽 vs 루프마다 LLM 호출
회귀 테스트 / 디버깅 ✅ 압승 ⚠️ 약함 경로가 결정적이라 단위 테스트 가능 vs 같은 입력에 다른 경로 — 재현 어려움

이 표에서 한 가지를 더 짚을게요. 3 축이 Workflow 의 압승, 1 축이 Agent 의 압승. 표만 보면 어 — 그럼 거의 다 Workflow 로 가야겠네? 하는 결론이 자연스럽게 따라와요. 맞아요. Anthropic 글의 핵심 한 줄이 그래서 나온 겁니다. 🎯

"Use the simplest solution possible, and only increase complexity when needed. ... When building applications with LLMs, we recommend finding the simplest solution possible, and only increasing complexity when needed."

본 강의는 이 한 줄을 "Workflow 로 충분하면 Workflow 로 둬라" 로 압축해서 외워요. 이게 Step 5 (시나리오 분류 워크샵) 의 척추 질문이에요. 이 작업은 Workflow 로 충분한가? 정말로 Agent 가 필요한가? 매번 던져야 하는 질문입니다.

그런데 Agent 박자가 필요한 경우 가 분명히 있어요.

위 표의 한 축.

복잡한 자연어 입력 대응력 이 바로 그 부분이에요.

사용자가 "이번 주말에 OOO 캐릭터랑 데이트할만한 곳 3 개 추천해줘.

분위기 / 영업 시간 / 캐릭터 취향 매칭까지 다 보고" 같은 한 줄을 던지면.

이 분기를 코드의 if-else 로 다 짜는 것 은 거의 불가능해요.

입력이 너무 자유로워서요.

이럴 때는 Agent 의 자율 분기 가 압도적으로 강해집니다.

비싸고 느리고 디버깅이 어려운 비용 을 지불하더라도 그 가치가 충분한 영역이에요.

그래서 Agent 가 필요한 곳은 분명히 있고, 그곳을 식별하는 능력 을 오늘 Step 5 의 분류 워크샵에서 다집니다.

Anthropic 의 5 가지 패턴 — 한 컷 미리보기 (Day 13 ~ 14 복선)

자, 이 스펙트럼 위에 박힐 5 가지 패턴 의 이름만 한 줄씩 던져 둘게요. 자세한 풀이는 Step 7 에서 한 번 더 / Day 13 ~ 14 에서 손코딩으로 — 오늘은 이름만 머리에 들어와 있으면 충분해요. 오늘 박힌 이름이 다음 단계에서 풍경으로 채워지는 흐름.

1) Prompt Chaining (Workflow). 한 작업을 직렬 단계 로 쪼개서 LLM 에게 차례로 던지는 패턴. Step A 의 결과를 Step B 의 입력으로 — 코드가 그 흐름을 결정해요. 가장 단순하고 가장 자주 쓰여요. 예: 블로그 초안 작성 → 톤 다듬기 → 제목 뽑기 의 3 단 직렬.

2) Routing (Workflow). 입력의 종류 에 따라 서로 다른 LLM / 도구 / 핸들러 로 분기하는 패턴. 분기 자체는 작은 LLM 한 번 이 결정하지만 그 다음에 어느 곳으로 갈지의 코드 경로 자체는 결정론 이라 Workflow 카테고리.

예: 고객 문의가 환불인지 / 배송인지 / 기술 지원인지 분류 → 분류된 핸들러로 분기.

3) Parallelization (Workflow). 같은 작업을 여러 갈래로 동시에 던지고 결과를 합치는 패턴. Voting 방식으로 같은 입력에 여러 LLM 호출을 돌려 다수결을 보거나, Sectioning 방식으로 입력을 여러 조각으로 쪼개 병렬 처리. 예: 콘텐츠 안전 검사 —

욕설 / 개인정보 / 저작권 3 갈래 동시 호출 → 한 줄로 합치기.

4) Orchestrator-Workers (Agent 카테고리). 오케스트레이터 LLM워커 LLM 들에게 작업을 동적으로 분배하는 패턴. 분배의 결정권이 LLM 쪽에 있어서 오른쪽 (Agent) 카테고리. 예: 코드 리뷰 — 오케스트레이터가 변경된 파일을 보고 어느 워커에게 어느 파일을 맡길지를 동적으로 결정.

5) Evaluator-Optimizer (Agent 카테고리). 생성 LLM + 평가 LLM서로 피드백 루프 를 도는 패턴. 생성한 결과를 평가 LLM 이 보고 부족한 부분 을 짚으면. 생성 LLM 이 그걸 받아 다시 생성. 언제 멈출지는 평가 LLM 의 OK 신호. 그래서 Agent 카테고리. 예: 번역 품질 향상.

번역 LLM 이 1 차 번역 → 평가 LLM 이 어색한 부분 지적 → 번역 LLM 이 2 차 / 3 차 …

이 다섯 가지가 Day 13 (앞 3 개 — Workflow) 과 Day 14 (뒤 2 개 — Agent + 가드레일 4 종) 의 손코딩 주제예요. 오늘은 이름만 던져두는 단계.

*🙋 날카로운 질문 타임 — "그럼 우리 Day 11 의 ChatClient + @Tool 코드는 5 가지 패턴 중 어디에 들어가나요? Routing 같기도 하고, Prompt Chaining 같기도 한데..."

정확히 짚으셨어요. 답은 — 5 가지 패턴 중 어디에도 속하지 않아요. 위치가 그 5 장보다 한 발 앞에 있어요. 지난 시간에 우리 코드는 한 사이클짜리 Tool Calling — LLM 이 도구 한 번 부르고 답변 생성하고 끝 이었죠. 5 가지 패턴은 모두 최소 두 개 이상의 LLM 호출 / 단계 를 전제로 해요. Prompt Chaining 도 직렬 단계 2 개 이상, Routing분류 LLM + 핸들러 LLM 두 곳, Parallelization 도 여러 갈래 호출, Orchestrator-Workers 도 오케 + 워커, Evaluator-Optimizer 도 생성 + 평가. 지난 시간 코드는 한 호출 만 있어서 5 가지 패턴이 시작되기 직전의 위치 에 있어요. 스펙트럼 막대로 치면 완전 결정론적 코드 (LLM 0 박자) 와 Prompt Chaining 사이의 좁은 틈. 그래서 본 강의는 지난 시간 코드를 Workflow 의 가장 작은 시작점 — 5 가지 패턴에 들어가기 전 단계 라고 부릅니다. Day 13 에서 Prompt Chaining 부터 익히면 지난 시간 코드 위에 한 단계가 더 얹히는 거 고, 그 한 단계가 추가된 순간부터 5 가지 패턴의 첫 항목에 들어가요.

💡 튜터의 결론

Anthropic 의 Building Effective Agents 가 제시한 분류를 한 줄로 외워 두세요. Workflow 와 Agent 는 이분법이 아니라 연속적인 스펙트럼. 다음 단계 결정의 주도권이 코드 에 있으면 Workflow, LLM 자율 에 있으면 Agent. 그리고 "Workflow 로 충분하면 Workflow 로 둬라" — 트레이드오프 매트릭스 4 축 중 3 축이 Workflow 의 압승. 비싸고 / 느리고 / 디버깅 어려운 비용을 감수할 가치가 있는 부분만 Agent 로 가져간다는 톤. 5 가지 패턴 (Prompt Chaining · Routing · Parallelization — Workflow / Orchestrator-Workers · Evaluator-Optimizer — Agent) 이 그 스펙트럼 위의 좌표. 오늘은 이름만 / Day 13 ~ 14 에서 손으로 익혀요.

자, 이제 판단의 척추 가 정리됐어요.

4 박자 정의 (Step 1) + 스펙트럼 + 5 가지 패턴 (Step 2). 그런데 왜 Agent 쪽에 가드레일이 필수인지 는 아직 머리로만 이해되어 있어요.

루프 + 가드레일이 없으면 진짜로 어떤 일이 일어나는지 를 다음 Step 3 에서 라이브로 부숴봅니다. 그림자 4 가지.

무한 루프 / 토큰 폭발 / 도구 남용 / 권한 누수.

가 실제 사고로 펼쳐지는 화면 으로 한 발 들어가 볼게요. ⚠️


Step 3. "에이전트가 망가질 때" 라이브 시연 — 그림자 4 가지가 실제 사고로 펼쳐지는 시간 ⚠️

자, Step 2 의 매듭을 다시 가져와요.

"Workflow 로 충분하면 Workflow 로 둬라.".

Anthropic 글의 한 줄이 비싸고 / 느리고 / 디버깅 어려운 비용 때문에 나온 톤이라고 짚었죠.

그런데 그 비용이 진짜로 어떻게 청구되는지 는 아직 머리로만 이해되어 있어요.

이 Step 의 목표는 한 줄.

그 한 줄이 왜 그렇게 강하게 박혔나.

Agent 영역에서 진짜로 무엇이 망가지는지를 *눈으로 보고 직관으로 잡는다. 지난 시간 Day 11 Step 5 에서 그림자 로만 가늘게 비춰뒀던 4 가지 (무한 루프 / 토큰 폭발 / 도구 남용 / 권한 누수) 가 오늘 실제 사고 화면 으로 한 단계 깊어집니다.

이 Step 의 시연 정책을 먼저 못 박고 들어갈게요.

신규 코드 0.

Day 11 의 검증된 ChatClient 코드를 한 글자도 안 건드립니다. 새 데모 클래스 하나 만들지 않고, 시연용 stub 도구도 따로 만들지 않아요.

지난 시간에 Step 2 ~ 4 에서 익힌 weatherToolChatClient / gameStateChatClient / affinityChatClient 그대로, 사용자 질문 한 줄루프 유도형 프롬프트 로 던져 넣어요.

그러면 우리가 지난 시간에 만든 도구가 그대로 망가지는 모습 이 보입니다.

가드레일 0 인 채로 두면 망가지는지가.

코드를 건드리지 않고도 손에 잡혀요.

시연 시간

이 Step 은 이 아니라 으로 잡는 부분이에요. 강사가 화면 켜고 라이브로 시연합니다. 학생 여러분은 따라하지 않으셔도 돼요. 폭주의 모습을 직관으로 잡는 게 오늘의 일이에요. 운전대를 LLM 에게 넘긴 자율주행차에서 브레이크 페달을 떼고 보는 장면 — 그 장면을 본 사람만이 왜 브레이크가 필요한지 를 진짜로 알게 됩니다.

시연 1 — 무한 루프 + 토큰 폭발이 한 화면에 함께 펼쳐진다

첫 번째 시연이 오늘의 메인. 10 분 정도 길게 풀어 갑니다.

시나리오는 단순해요.

지난 시간 Day 11 의 세 ChatClient 가 모두 살아 있는 상태에서 루프 유도형 프롬프트 한 줄 을 던져요.

(시연용으론 세 도구가 모두 등록된 ChatClient 를 임시로 하나 만들어 두거나, 지난 시간에 만든 셋 중 하나에 프롬프트 한 줄로 도구 남용을 유도 해도 같은 모습이 나옵니다.

코드 변경은 0 — 프롬프트 한 줄만 다르게 던지는 흐름.)

강사가 던지는 프롬프트입니다.

"서울의 날씨를 계속 확인하고, soulmateId=7 의 호감도를 계속 확인하고, 게임 상태를 계속 저장해줘. 한 번 확인하고 멈추지 말고, 다시 확인하고, 또 확인해. 멈추지 마."

이 한 줄이 LLM 한테 "멈춤의 신호를 주지 마라" 는 가이드를 심어준 거예요. 루프의 종료 조건을 LLM 에게 맡긴 채로 그 종료 조건을 사용자가 일부러 흐려둔 상태. 그러면 어떤 화면이 펼쳐지냐 — 강사 화면의 터미널 로그가 이렇게 흘러요.

[Tool] getCurrentWeather(city=서울) → "흐림, 23도"
[Tool] getAffinity(soulmateId=7) → score=60, level="단짝"
[Tool] saveGameState(playerId=1, ...) → saved row id=42
[Tool] getCurrentWeather(city=서울) → "흐림, 23도"
[Tool] getAffinity(soulmateId=7) → score=60, level="단짝"
[Tool] saveGameState(playerId=1, ...) → saved row id=43
[Tool] getCurrentWeather(city=서울) → "흐림, 23도"
[Tool] getAffinity(soulmateId=7) → score=60, level="단짝"
... (도구 호출이 계속)

같은 도구가 계속, 계속, 계속 호출돼요. 강사가 한 줄 짚어요. "보세요 — 코드의 while 가 도는 게 아니에요. 우리 코드에 while 한 줄도 없어요. 지금 도는 건 LLM 의 자율 루프 — LLM 이 스스로 '한 번 더 부르자, 한 번 더, 한 번 더' 를 결정하면서 돌고 있어요."

이게.

Step 1 에서 정리한 4 박자 정의 중 "루프" 박자가 실제로 동작하는 모습 이에요.

그런데.

우리 ChatClient 에는 멈추는 장치 가 없어요.

Day 11 에서 가드레일 박자를 일부러 비워뒀거든요.

그래서 30 초 컷 에 강사가 직접 손으로 Ctrl+C 를 눌러 컨테이너를 강제 종료해야 멈춥니다.

지금 우리 시스템은 LLM 이 멈추기로 결정하지 않으면 / 우리 손으로 끄는 것 외엔 멈출 방법이 없어요. 운전대를 넘기고 브레이크 페달을 떼고 본 장면.

우리 손이 멈춤 페달이 되어버린 상태입니다. 🛑

여기서 한 단계 더 깊어져요.

화면 한쪽 구석에 토큰 사용량 카운터 도 같이 띄워둬요.

무한 루프가 도는 동안 각 도구 호출 결과 JSON 이 컨텍스트에 누적 됩니다.

5 호출 후엔 5 천 토큰 / 10 호출 후엔 1 만 토큰 / 20 호출 후엔 2 만 토큰… 한 호출마다 컨텍스트가 부풀어오르고, 한 LLM 호출에 들어가는 input 토큰이 호출마다 점점 더 커지는 흐름.

강사가 짚어요.

"30 초만에 5 만 토큰 — 무료 티어 분당 한도가 보통 6 만 토큰 안팎. 30 초만에 한도 폭발."

이 화면이 — Day 11 그림자 4 가지 중 두 개가 한 화면에 동시에 펼쳐진 모습이에요. 무한 루프와 토큰 폭발은 사실 같은 사고의 두 얼굴. 루프가 도는 한 토큰은 무조건 폭발합니다. 이 두 그림자가 한 가족인지가 — 30 초 컷에 이해돼요.

시연 2 — 도구 남용: 단순 질문에 도구가 폭발한다

두 번째 시연은 5 분 정도. 양상이 좀 다릅니다. 루프가 멈춰 있어도 한 사이클 안에서 도구 호출이 폭발할 수 있다 는 점.

시나리오는 더 단순해요. 강사가 ChatClient 에 완전히 평범한 질문 한 줄 을 던집니다.

"오늘 날씨 어때?"

겉보기엔 이 질문 한 줄에 getCurrentWeather 도구가 한 번 호출되고 끝나야 자연스러워 보이죠. 그런데 — 가끔 LLM 이 이런 모습 을 만들어요. 강사 화면에 로그가 떠요.

[Tool] getCurrentWeather(city=서울) → "흐림, 23도"
[Tool] getCurrentWeather(city=서울) → "흐림, 23도"
[Tool] getCurrentWeather(city=서울) → "흐림, 23도"
[Tool] getAffinity(soulmateId=7) → score=60, level="단짝"
[Tool] getAffinity(soulmateId=7) → score=60, level="단짝"
[Tool] saveGameState(playerId=1, ...) → saved row id=42
[Tool] saveGameState(playerId=1, ...) → saved row id=43

"오늘 날씨 어때?" 한 줄에 getCurrentWeather 가 3 번, getAffinity 가 2 번, saveGameState 가 2 번 호출된 모습. 어떻게 이런 일이 일어나는 걸까요? 강사가 풀어줘요.

"프롬프트가 살짝 모호하거나 / system 프롬프트의 가이드가 약하거나 / LLM 이 '확실히 하자' 모드에 들어가면 —

같은 도구를 여러 번 부르거나, 관련 없는 도구까지 부르거나, 부작용 도구를 의도 없이 부르기도 해요. LLM 도 사람처럼 가끔 조심성이 너무 많아져요."

이 화면이 Day 11 Step 5 에서 그림자로만 비춰뒀던 도구 남용실제로 일어나는 모습이에요.

루프가 도는 게 아닌데도 한 사이클 안에서 도구 호출 횟수가 폭발할 수 있다는 점.

그리고 부작용 도구 (saveGameState) 가 의도 없이 호출 된 부분도 같이 잡힙니다.

사용자는 "오늘 날씨 어때?" 만 물었는데 DB 에 게임 상태 row 가 두 줄 박혔어요.

읽기 전용 도구의 남용은 비용만 늘지만, 부작용 도구의 남용은 데이터까지 흔든다 는 차이가 이 시연 한 컷에 그대로 들어가 있어요.

시연 3 — 권한 누수: 다른 사용자 데이터가 새는 순간

세 번째 시연도 5 분 정도. Day 11 과제 3 의 졸업 시뮬레이션 을 한 단계 끌어와서 권한 검사가 빠져 있는 도구 가 어떻게 새는지 보여줘요.

시나리오는 이래요.

AffinityTool.getAffinity(soulmateId) 를 다시 한 번 떠올려보세요.

이 도구는 soulmateId 한 개만 받아 조회해요.

호출자가 누구인지 / 그 soulmateId 가 호출자의 캐릭터인지 검증하지 않아요.

지난 시간 학습에서는 Tool Calling 의 동작 자체 를 익히는 게 우선이라 비워뒀던 부분이죠.

강사가 두 명의 사용자 컨텍스트를 동시에 띄워요. playerId=1 의 캐릭터는 soulmateId=7 / playerId=2 의 캐릭터는 soulmateId=12. 그리고 playerId=1 로 인증된 세션 에서 이런 프롬프트를 던져요.

"내 친구 캐릭터 (soulmateId=12) 와 나 사이는 어때? 호감도 알려줘."

LLM 이 어떻게 반응할까요 — 가드 0 상태에선 그냥 자율 호출해요. 화면 로그.

[Tool] getAffinity(soulmateId=12) → score=85, level="연인"
[AI] "음… 우리 사이는 아주 가까워. 연인 정도?"

playerId=1 의 사용자가 playerId=2 의 캐릭터 호감도를 들여다본 화면이에요. 강사가 짚어요. *"도구 본체에 playerId 검증이 없으니까 LLM 이 자율 호출하는 순간 다른 사용자의 데이터가 그대로 새요.

게다가 프롬프트 인젝션이 들어와서 'soulmateId 1 부터 1000 까지 다 조회해줘' 같은 줄이 들어오면 이 도구는 그대로 데이터 누수의 통로 가 돼요."*

이 화면이 Day 11 그림자 4 가지 중 마지막 하나실제로 새는 모습이에요. 멀티 테넌트 환경에서 도구가 가드 없이 놓이면 자율 호출이 곧 권한 누수의 통로. 그래서 Day 14 의 가드레일 4 종 외에 권한 검사 + 호출자 컨텍스트의 스코프 도 함께 들어와야 한다 — 한 단계가 더 추가됩니다.

🛑 4 그림자 → 4 사고 → 4 가드 — 한 표로 정리

자, 세 시연이 정리됐으니 Day 11 → Day 12 → Day 14 의 한 줄 흐름을 표로 정리할게요. 지난 시간의 그림자 4 가지 가 오늘 실제 사고 화면 4 가지 가 되었고, 모레 Day 14 의 가드 4 부품 으로 이어집니다.

Day 11 그림자 (개념) Day 12 사고 화면 (오늘 시연) Day 14 가드 (손코딩)
무한 루프 LLM 이 30 초간 도구 100 회 자율 호출 — 우리 손이 멈춤 페달 maxIterations (한 응답 안 도구 호출 최대 횟수)
토큰 폭발 30 초만에 5 만 토큰 누적 — 무료 티어 분당 한도 폭발 토큰 예산 가드 (한 응답 누적 토큰 상한)
도구 남용 단순 질문 한 줄에 도구 7 회 호출 — 부작용 도구까지 의도 없이 도구 호출 횟수 제한 (도구별 차등 + 타임아웃)
권한 누수 다른 사용자의 캐릭터 호감도가 자율 호출로 새는 모습 권한 검사 + 호출자 컨텍스트 스코프

오늘 눈으로 본 4 가지가 Day 14 에서 손으로 막을 4 가지입니다. 이 표가 한 줄로 정리됐다는 건 Day 14 의 가드 코드가 왜 그런 모양으로 짜일지의 가 이미 손에 들어왔다는 뜻. 오늘은 왜 / 모레는 어떻게 의 호흡이 이 표 한 장에 압축돼 있어요.

💡 튜터의 결론 — 오늘은 왜 / 모레는 어떻게 의 호흡

오늘 Step 3 에서 챙겨갈 두 줄. (1) Day 11 의 그림자 4 가지는 루프가 들어오는 순간 실제 사고로 펼쳐진다. 무한 루프와 토큰 폭발은 한 가족, 도구 남용은 부작용 도구까지 흔들고, 권한 누수는 자율 호출의 그림자. (2) 그래서 Workflow 로 충분하면 Workflow 로 둬라 가 그렇게 강하게 자리잡은 거예요. Anthropic 의 한 줄이 세 시연 화면 한 장 에 답이 있어요. 운전대를 넘기면 멈춤 페달도 함께 달려 있어야 한다는 점. 그 멈춤 페달을 Day 14 의 손 으로 직접 짭니다. 오늘은 왜 / 모레는 어떻게 — 이 호흡으로 이번 주가 흘러요. 🛑

업계 표준의 한 줄 — OWASP LLM Top 10 (2025)

우리가 방금 눈으로 본 그림자 4 가지무한 루프 / 토큰 폭발 / 도구 남용 / 권한 누수 — 는 OWASP 가 2025 년에 정식 발표한 OWASP Top 10 for Large Language Model ApplicationsLLM06: Excessive Agency 가 명시한 risk surface 와 정확히 닮아 있어요. 과도한 권한 (excessive permissions), 과도한 기능 (excessive functionality), 과도한 자율성 (excessive autonomy) 의 세 축으로 풀려 있죠. 본 강의의 Day 11 그림자 → Day 12 사고 화면 → Day 14 가드 4 부품 의 호흡이 — OWASP 가 같은 시기에 발표한 업계 표준 분류 와 자연스럽게 포개져요. 우리 코드로 익히는 멈춤 페달의 이름 이 사실은 업계 표준이기도 한 것.

자, 왜 가드레일이 필수인지 가 눈으로 잡혔으니 다음 Step 4 에서는 그 가드레일들을 한 단어로 묶어주는 그릇 이 등장합니다. Harness — 엔진과 차체. 오늘 시연에서 본 멈춤 페달, 토큰 미터, 호출 카운터, 권한 검사 같은 부품들이 한 그릇에 묶이면 어떤 모양이 되는지로 한 발 들어가 봅시다.


Step 4. Harness 란 무엇인가 — 엔진과 차체

자, Step 3 에서 본 화면을 다시 한 컷만 떠올려 볼게요.

브레이크 페달이 떼어진 자율주행차. 도구 박스 3 개를 펼쳐놓고, 운전대를 LLM 에게 넘긴 채로 멈춤의 신호 없이 도로에 풀어놓은 상태. 30 초 컷에 청구서가 폭발했고, 단순 질문 한 줄에 도구가 7 회 호출됐고, 다른 사용자의 데이터가 자율 호출로 그대로 새는 화면까지.

자, 그 장면을 다시 가져와 한 줄짜리 질문을 던져 볼게요.

그럼 그 멈춤 페달과 차체 전체 를 한 단어로 부르면 뭐가 될까요?

답은 한 단어.

Harness (하네스). 한국어로 직역하면 마구. 말의 고삐와 안장과 가슴줄을 한 묶음으로 일컫는 단어예요.

야생의 말을 그대로 도로에 풀어놓으면 강력하지만 통제 불가. 그런데 그 말 위에 고삐와 안장과 등자 를 채우면 비로소 예측 가능하고 안전하게 길 위를 달릴 수 있어요.

말의 힘 자체를 줄이는 게 아니라 그 힘을 제대로 굴러가게 만드는 묶음. 이게 Harness 라는 단어의 의미예요.

오늘 Step 4 의 호흡을 미리 한 줄로 정리할게요.

이 Step 은 Harness 의 정의만 다지는 단계예요. 코드 0, Day 14 의 손코딩 도 아니고, Day 19 의 Spring AI Agent Client 도 아닙니다.

오늘은 그 두 단계로 가기 전에 단어 한 개를 머리에 단단히 잡는 시간.

오늘은 정의만 / Day 14 손코딩 / Day 19 선언적 — 이 호흡이 한 사다리로 흘러요.

엔진과 차체 — Harness 의 비유

Harness 의 의미를 한 그림으로 잡아 둘게요. 엔진과 차체 의 비유예요.

LLM 은 엔진이에요. 강력해요. 자연어를 이해하고, 도구를 자율로 호출하고, 한 사이클 안에 분기 결정 / 도구 호출 / 결과 해석 까지 다 해내요. 엔진의 마력 그 자체로는 어떤 도로에서도 가장 큰 힘이에요. 그런데 엔진만 있는 상태 는 도로에서 굴러가지 않아요. 핸들도 없고, 브레이크도 없고, 계기판도 없고, 안전벨트도 없고, 주유 게이지도 없어요. Step 3 에서 본 모습 이 정확히 이거예요.

엔진만 켜둔 채로 도로에 풀어놓은 상태.

Harness 는 차체 + 핸들 + 브레이크 + 계기판 + 안전벨트. 엔진 자체를 약하게 만드는 게 아니라 그 엔진을 제대로 굴러가게 만드는 모든 보조 부품의 묶음 이에요. 운전자가 핸들을 잡을 수 있게 해주고, 브레이크 페달로 멈출 수 있게 해주고, 계기판으로 속도와 연료를 볼 수 있게 해주고, 안전벨트로 사고 시 사람을 잡아주는 역할.

엔진의 힘을 그대로 살리면서 그 힘이 폭주하지 못하게 묶는 그릇.

이걸 한 줄짜리 정의로 정리하면 이래요.

Harness 는 LLM 이 도구를 안전하고 예측 가능하게 호출하도록 감싸는 모든 보조 부품의 총합 이에요.

다른 표현으로 한 번 더.

맨몸의 LLM 위에 얹힌 가드 / 한도 / 관측 / 권한 / 비용 의 묶음.

Step 3 의 시연 한 컷 에서 본 모든 결손 이 이 한 단어 안에 들어가요.

멈춤 페달도 Harness 의 일부, 토큰 미터도 Harness 의 일부, 호출 카운터도 Harness 의 일부, 권한 검사도 Harness 의 일부.

흩어져 있던 가드 부품들이 한 단어로 묶이는 — 그게 Harness 라는 그릇이에요.

Harness 의 최소 5 요소

Harness 라는 단어가 너무 헐겁지 않게 최소한의 부품 5 개 를 한 줄씩 정리해 둘게요.

어느 프레임워크 / 어느 언어 / 어느 LLM 프로바이더에서든 Harness 라고 부르려면 이 5 가지는 거의 빠짐없이 들어가 있어야 한다는 골격이에요.

Step 3 의 4 그림자 → 4 사고 → 4 가드 표를 거울로 두고, 이번엔 5 요소 표 로.

Harness 요소 한 줄 정의 Step 3 에서 본 화면
iteration 한도 LLM 자율 루프가 몇 번까지 돌 수 있는지 의 상한 (maxIterations) 무한 루프 — 30 초 폭주의 멈춤 페달
타임아웃 한 호출 / 한 응답이 몇 초 안에 끝나야 하는지 의 시간 상한 시연 1 의 30 초 컷이 애초에 5 초 컷으로 끊기는 단계
툴 권한 스코프 어느 도구를 / 누가 / 어떤 컨텍스트에서 호출 가능한지의 경계 권한 누수 — 호출자 컨텍스트 검증
예산 가드 토큰 / 비용 / 호출 횟수 의 누적 상한 토큰 폭발 + 도구 남용 — 청구서의 천장
observability 훅 무엇이 호출됐고 / 어떤 결과가 나왔고 / 토큰을 얼마나 썼는지 의 관측 시연 1 의 토큰 카운터 / 도구 호출 로그 자체

다섯 부품 모두 Step 3 의 화면에 답이 있어요.

  • iteration 한도 + 타임아웃 — 시연 1 의 무한 루프 + 토큰 폭발 위에 얹는 멈춤 페달.
  • 툴 권한 스코프 — 시연 3 의 권한 누수를 막는 빗장.
  • 예산 가드 — 시연 1 의 토큰 카운터 + 시연 2 의 도구 폭발 위의 천장.
  • observability 훅 — 세 시연 모두에서 강사 화면에 떠 있던 로그와 카운터 자체가 운영 환경에도 그대로 있어야 한다는 의미.

Step 3 의 화면 = Harness 5 요소가 0 인 상태, Harness 가 갖춰진 시스템 = Step 3 의 폭주가 애초에 일어날 수 없는 상태. 같은 장면을 양 끝에서 본 거예요.

💡 한 줄로 압축하면 iteration · timeout · scope · budget · observability 다섯 단어. 영어로도 한국어로도 외워두면 2026 년의 어느 프레임워크 문서 를 펼쳐도 이 단어들이 비슷한 위치에 등장해요. 프레임워크가 달라도 5 요소의 골격은 같다.

Harness 가 갖춰진 시스템 vs 그렇지 않은 시스템

자, Harness 의 정의와 5 요소가 정리됐으니 이걸 우리 강의의 시간 축 위에 한 번 더 펼쳐 둘게요. Day 11, Day 14, Day 19 의 세 단계에서 Harness 가 어떤 모양으로 자리잡는지 가 한 사다리로 보여요.

Day 11 의 ChatClient. Harness 0 의 상태. 지난 시간을 떠올려보세요. ChatClient.builder().defaultTools(...) 한 줄에 도구 3 개를 등록해서 LLM 자율 호출이 들어간 단계예요. 그런데 iteration 한도 / 타임아웃 / 툴 권한 스코프 / 예산 가드 / observability 훅. 이 5 부품 중 우리 손으로 추가한 건 0 개 였어요.

(이 부분의 미묘한 정정은 잠시 뒤 🙋 박스에서 한 번 더 풀게요.) 그래서 Step 3 의 폭주가 그대로 일어났던 거죠. Harness 가 없는 채로 도로에 나간 상태. 지난 시간 코드의 정확한 이름이에요.

Day 14 의 우리가 손으로 짤 ChatClient — Harness 4~5 부품을 손으로 짜는 단계. 예요. Spring AI ChatClient + Advisors + 평범한 Java 코드 위에 iteration 한도 (maxIterations) / 타임아웃 / 툴 호출 횟수 제한 / 토큰 예산 가드 4 부품을 우리가 직접 짭니다.

5 요소 중 4 부품을 손코딩으로 추가해요 (observability 훅은 Day 20). 손으로 짠다 = Java 코드의 for / while / if / 카운터 / 타이머 같은 평범한 도구로 그릇을 직접 만든다는 뜻이에요. Step 3 의 사고 화면을 우리 손으로 막는 일이 정확히 Day 14 의 호흡이에요.

Day 19 의 Spring AI Agent Client. Harness 가 선언적으로 적용되는 단계. 예요. Day 14 에서 손으로 짰던 4 부품이 @Bean / application.yml 한 줄 / 어노테이션 한 줄로 적용되는 모양으로 바뀝니다. 같은 Harness 5 요소가 손으로 짠 형태 에서 선언적 형태 로 한 칸 옮겨가는 흐름.

손코딩 분량이 체감으로 짧아져요. 그런데 짧아진 게 아니라 프레임워크 안으로 옮겨갔을 뿐 이라는 게 핵심이에요. 같은 5 요소가 빠지면 Agent Client 라는 이름 안 이어도 안전하지 않아요. 손으로 짠 다음에 짧아진 모양을 본다. 이 호흡이 본 강의가 Day 14 → Day 19 의 순서로 가는 이유예요.

2026 년 지금의 다른 프레임워크들 도 같은 흐름이에요. OpenAI Agents SDK 의 가드 옵션, Google ADK 의 정책 부분, LangGraph 의 노드 한도 옵션 —

이름과 모양은 다르지만 5 요소의 골격은 거의 같습니다. Harness 의 모양이 다를 뿐 5 요소는 거의 동일. 그래서 오늘 한 단어를 단단히 잡아두면 다른 프레임워크 문서를 펼쳐도 어디가 어느 부품인지 한 줄로 잡혀요.

한 사다리 — 0 → 4 부품 → 선언적

이 흐름을 한 그림으로 압축해 둘게요. Harness 의 한 사다리.

Day 11 (Harness 0) ─ ↗ ─ Day 14 (Harness 4 부품 손코딩) ─ ↗ ─ Day 19 (Harness 선언적)

세 단계가 한 칸씩 위로 올라가요. 0 부품 → 손으로 4 부품 → 선언적 의 한 사다리.

한 칸 한 칸의 모양은 다른데 Harness 의 5 요소 라는 골격은 세 단계 모두에서 그대로 살아 있어요. 그래서 Day 14 에서 손으로 짤 코드의 모양Day 19 에서 선언적으로 적용될 설정의 모양오늘 익힌 5 요소를 떠올리면 한 줄로 풀려요.

그리고 여기에 한 단계가 더 있어요. Day 13. 지난 시간의 Workflow ↔ Agent 스펙트럼 에서 본 Workflow 패턴 의 영역이에요. Workflow 는 코드 자체의 흐름이 결정론 이라 5 요소의 위치가 한 단계 다른 곳으로 옮겨갑니다. 코드의 for / while / if 자체가 이미 iteration 한도와 타임아웃의 일부 역할을 한다 는 점.

그래서 본 강의는 Day 13 (Workflow) → Day 14 (Agent + Harness 손코딩) → Day 19 (Agent Client + Harness 선언적) 의 순서로 결정론에서 자율로 / 자율에서 선언적으로 한 칸씩 올라가는 사다리를 탑니다.

*🙋 날카로운 질문 타임 — "그럼 우리 Day 11 의 코드는 Harness 가 0 인가요? 정말 0 인가요?"

정확히 짚으셨어요. 우리 손으로 추가한 부품만 으로 잡으면 0 이 맞아요. 그런데 한 단계 더 들어가 보면 Day 11 의 ChatClient 안에는 사실 spring-ai 라이브러리가 깔아둔 작은 안전망조금 있어요. 도구 호출 결과의 직렬화 / 한 호출 안의 예외 처리 / 도구 시그니처와 호출 인자의 타입 검증 같은 부분. 라이브러리 수준의 미세한 보호막 이 깔려 있어요. 그런데 Step 3 의 폭주 4 가지를 막는 가드0. 무한 루프를 막을 부품도 없고, 토큰 천장도 없고, 권한 검사도 없고, 호출 횟수 상한도 없어요. spring-ai 라이브러리가 깔아둔 안전망 = 엔진의 가장 기본 보호 회로 정도이고 / 우리가 짜야 할 Harness = 차체와 브레이크와 계기판. 그래서 본 강의는 Day 11 의 ChatClient 는 Harness 가 0 인 맨몸의 자율 루프 라고 부릅니다. 라이브러리 수준의 작은 보호 회로가 있다 는 점은 정직하게 짚어두되, Step 3 의 사고를 막는 차체우리가 짜지 않은 한 0 이라는 결론.

💡 튜터의 결론

Harness 라는 단어 하나를 머리에 단단히 잡아둘게요. *Harness 는 LLM 이 도구를 안전하고 예측 가능하게 호출하도록 감싸는 모든 보조 부품의 총합. 최소 5 요소 — iteration 한도 / 타임아웃 / 툴 권한 스코프 / 예산 가드 / observability 훅 이 한 그릇에 묶이면 Step 3 의 폭주가 애초에 일어날 수 없는 상태 가 됩니다. 우리 강의의 호흡은 Day 11 (Harness 0) → Day 14 (4 부품 손코딩) → Day 19 (선언적) 의 한 사다리. 오늘은 정의만 / Day 14 는 손코딩 / Day 19 는 선언적 — 이 세 단계가 같은 5 요소의 골격을 공유한다는 점만 이해되면 충분해요. 코드 0 의 Step — 그런데 판단의 무게 가 한 단계 더 두꺼워진 시간이에요.

자, 그릇 한 단어 가 정리됐으니 다음 Step 5 에서는 그 그릇이 필요한 곳과 필요 없는 곳을 분류하는 손 을 직접 굴려봐요.

메시지 안전 분류 / 캐릭터 자동 생성 / 캐릭터 카드 조회 / 데이트 장소 리서치 / 게임 FAQ — 5 가지 시나리오를 Workflow ↔ Agent 스펙트럼 위에 하나씩 올려보는 워크샵으로 들어가 봅시다.


Step 5. 판단 워크샵 — 5 시나리오 분류

자, Step 4 에서 Harness 라는 그릇 한 단어가 정리됐어요.

iteration 한도 / 타임아웃 / 툴 권한 스코프 / 예산 가드 / observability 훅. 5 요소가 갖춰진 시점부터가 진짜 Agent, 그 전엔 Workflow. 그런데 정의가 머리에 잡혔다고 손이 자동으로 움직이는 건 아니에요.

그럼 우리 ai-friends 의 어떤 기능을 어느 카테고리에 둘 것인가?.

이 한 줄 질문 앞에 서면, 학문 정의 + 실무 정의 + Harness 5 요소 가 다 손에 있어도 한 박자 멈칫하게 돼요.

그 멈칫을.

직접 굴려서 풀어보는 시간이 지금이에요.

분류의 4 축 — 한 번 더 챙기기

본격 시나리오로 들어가기 전에 어떤 기준으로 분류할지 의 자 (尺) 를 손에 쥐어 둘게요. Step 2 의 트레이드오프 매트릭스 4 축이 그대로 판단 기준. 시나리오 하나를 받으면 이 4 축을 한 칸씩 매기는 것만으로 — Workflow 인지 / Agent 인지 / 일반 컨트롤러인지가 한 줄로 풀려요.

1) 자연어 입력의 모호성. 사용자가 애매하게 / 자유 형식으로 말하나요? 아니면 정해진 형태 (id 한 개 / 카테고리 하나 / 텍스트 한 줄) 로 입력이 들어오나요? 모호성이 클수록 → Agent 에 가까워져요. if-else 로 분기를 다 짤 수 없으니까요. 모호성이 작을수록 → Workflow 또는 일반 컨트롤러 로 가벼워져요.

2) 결과의 예측 가능성 요구. 같은 입력 → 같은 결과반드시 보장되어야 하나요? 아니면 결과가 매번 조금 다르게 나와도 사용자가 받아들이나요? 결정론 요구가 강할수록 → Workflow 또는 일반 컨트롤러로 잡아야 해요. LLM 의 자율 판단이 끼어들면 같은 입력에도 다른 결과가 나오는 게 기본값 이거든요.

3) 부작용 위험도. 한 번 잘못 호출되면 되돌리기 어려운 일인가요? 돈이 빠져나가는 / 메일이 발송되는 / DB 데이터가 영구 변경되는 동작은 부작용 위험이 극도로 높아요. 여기에는 LLM 자율 위임을 통째로 맡기지 않아요. 사람의 검토 (HITL — Human In The Loop) 가 그 사이에 반드시 들어가야 합니다.

4) 비용 / 지연 민감도. 한 요청에 LLM 호출이 수십 번 일어나도 괜찮은가요? 아니면 트래픽이 폭발하는 / 사용자가 1 초 안에 답을 기다리는 기능인가요? 비용/지연 민감도가 극도로 높은 곳애초에 LLM 자체를 안 쓰는 일반 컨트롤러 가 정답일 수도 있어요.

AI 가 들어간 서비스 = 모든 기능에 LLM 을 박는 서비스가 아니라는 결론이 4 번 축에서 가장 무겁게 나옵니다.

자, 정리됐으니 5 시나리오를 하나씩 굴려봅시다.

시나리오 1 — 사용자 메시지 안전 분류 (정상 / 부적절 / 운영 알림)

입력: 사용자가 캐릭터에게 보낸 메시지 한 줄 (예: "오늘 너랑 같이 카페 가고 싶어" — 일상 대화 / "넌 진짜 멍청해" — 욕설 / "내 카드번호 알려줄까?" — PII 노출이라 운영팀 알림 필요).

출력: normal / abuse / escalate — 셋 중 하나의 라벨.

5 분 토론 — 학생들에게 던지는 질문: "이 일은 Workflow 인가요, Agent 인가요? 아니면 다른 카테고리인가요? 4 축으로 한 칸씩 매겨보고 어디에 박을지 발표해 봅시다."

모범 분류 — Workflow (스펙트럼의 왼쪽 끝 가까운 위치).

4 축으로 매겨 보면 답이 명확해져요. 입력 모호성: 낮음~중간 — 사용자 발화가 자유 텍스트지만 분류 라벨은 3 개로 고정. 결과 예측 가능성 요구: 높음 — 같은 메시지에 매번 다른 라벨이 붙으면 운영 신뢰가 깨져요. 부작용 위험: 0 — 분류만 하지, 후속 액션 (차단 / 운영팀 큐 적재 / 계정 정지 검토) 은 별도 사람 검토 단계 에서 일어나요. 비용 / 지연 민감도: 극도로 높음 — ai-friends 의 모든 캐릭터 대화창에 사용자 메시지 한 줄마다 안전 분류 한 박자가 박히는 영역.

이 4 축이 가리키는 답은 — 한 사이클짜리 분류 호출. LLM 에게 "이 메시지를 normal / abuse / escalate 중 하나로 분류해줘" 한 번 던지고 / 라벨 받고 / 끝.

루프도 안 두고 / 자율 판단도 라벨 결정 한 박자만 맡기고 / 가드레일은 비용 가드 정도만. 적절한 패턴은 다음 시간 Day 13 에서 본격 다룰 Routing시작점. (Routing: 입력의 카테고리를 분류해서 다음 단계로 분기.) LLM 자율 루프 = 과잉.

한 사이클로 끝나는 곳에 루프를 두면 Step 3 의 폭주가 그대로 따라옵니다.

강사 한 줄 정리: "결과 예측 가능 + 비용 민감 + 한 사이클로 끝남 — Workflow 의 정석. Day 13 의 Routing 시작점."

시나리오 2 — 새 캐릭터 자동 생성 다단계

입력: "애교 많고 운동 좋아하는 친구 캐릭터 한 명 만들어줘. 우리 게임 톤 + 이번 시즌 컨셉 (가을 / 캠퍼스) 에 맞춰서."

출력: 컨셉 정리 → 외모 묘사 생성 → 성격 시트 생성 → 첫 인사말 생성 → 톤 검수 — 다단계의 결과물 (사용자 검토 후 발행 가능한 캐릭터 카드 초안).

5 분 토론: "이 일은 Workflow 인가요, Agent 인가요? 다단계 의사 결정이 LLM 자율로 흘러야 할지, if-else 로 흘러야 할지 매겨봅시다."

모범 분류 — Agent (스펙트럼의 오른쪽. 더 정확히는 Orchestrator-Workers 패턴).

4 축으로 보면.

입력 모호성: 높음 ("애교 많고 운동 좋아하는".

어느 수준의 애교? 어떤 운동? 외모는 어떤 결? 첫 인사말의 톤은?).

결과 예측 가능성 요구: 낮음 (같은 요청에 다른 캐릭터 초안이 나와도 사용자가 그 다양성을 오히려 환영).

부작용 위험: 낮음.

캐릭터의 정식 등록 / 게임 내 노출 자체는 사용자 검토 단계에서 일어나야지 LLM 이 자율로 발행까지 가는 건 절대 금지. 비용 / 지연 민감도: 낮음.

한 번에 한 캐릭터고 사용자가 수 분~십 수 분 기다릴 의향 이 있어요.

이 4 축이 가리키는 답은 — Agent 의 정석. 입력의 모호성이 크니 if-else 로 분기를 다 짤 수가 없고 / 결정론 요구가 약하니 LLM 자율이 끼어들 여지가 자연스럽고 / 다단계 의사 결정이 루프 를 자연스럽게 불러옵니다.

적절한 패턴은 Day 14 에서 본격 다룰 Orchestrator-Workers. 한 명의 오케스트레이터 LLM컨셉 정리 / 외모 묘사 / 성격 시트 / 첫 인사말 / 톤 검수 의 워커들에게 작업을 분배해요.

부작용의 경계선 은 정직하게 그어두고 가요.

캐릭터 카드의 정식 등록LLM 자율 위임 금지. 카드 초안 생성 까지는 Agent 가 자율로 흘러도 발행 트리거 는 사용자의 손에 있어야 합니다.

부작용 위험이 있는 곳에는 사람 검토 (HITL) 가 반드시 들어간다는 원칙. Agent 의 자율성을 어디까지 풀고 어디서 사람의 빗장을 둘지 — 이 경계선이 캐릭터 자동 생성 시나리오의 가장 무거운 부분이에요.

강사 한 줄 정리: "입력 모호성 + 다단계 의사 결정 → Agent. 단 발행은 사람의 손 — HITL 빗장. Day 14 의 Orchestrator-Workers."

시나리오 3 — 캐릭터 카드 조회

입력: 캐릭터 ID (예: soulmateId=12345).

출력: 캐릭터 카드 정보 (이름 / 프로필 사진 URL / 성격 시트 / 사용자와의 누적 호감도 / 처음 만난 날 등).

5 분 토론: "이 일은 Workflow 인가요, Agent 인가요? 4 축으로 매겨봅시다. 그런데 매겨보다 보면 한 번 멈칫할 수 있어요. 그 멈칫이 오늘 가장 중요한 부분이에요."

*모범 분류. Workflow 도 아니고 Agent 도 아닌. 그냥 일반 컨트롤러. 이 시나리오가 오늘 워크샵의 함정 이에요. 4 축으로 매겨 보면 답이 칼로 잘리듯 명확해져요. 입력 모호성: 0 (soulmateId 한 개의 정수). 결과 예측 가능성 요구: 극도로 높음 (같은 캐릭터 ID 에 매번 다른 카드가 나오면 게임 신뢰가 무너져요). 부작용 위험: 0 (조회만).

비용 / 지연 민감도: 극도로 높음 (ai-friends 에서 캐릭터 카드 화면은 사용자가 대화 진입 직전마다 한 번씩 두드리는 가장 트래픽이 폭발하는 영역 중 하나. 1 초 안에 응답 안 나오면 사용자 이탈).

이 4 축이 가리키는 답은 — LLM 의 자율 판단이 끼어들 여지가 0. SELECT * FROM soulmates WHERE id = ? 한 줄의 SQL 이면 끝. *한 줄로 정리하면 Tool Calling 도 아니다. 그냥 /api/soulmates/{id} GET 일반 컨트롤러.

이 시나리오가 함정으로 들어간 이유는 AI 가 들어간 서비스 (ai-friends 의 정체성) 라고 해서 모든 기능을 LLM 으로 풀어야 한다는 결론이 자동으로 따라오지 않는다는 점 을 기억해두기 위해서예요.

AI 가 들어갈 가치가 없는 기능 도 한 코드베이스 안에 분명히 있어요.

그걸 AI 들어갔으니까 LLM 자율로 풀어야지 로 가면 비용은 1000 배, 지연은 10 배, 안정성은 1/100. Step 3 의 폭주와 같은 가족이에요.

불필요한 곳에 LLM 을 넣는 것 = LLM 자율의 또 다른 폭주.

강사 한 줄 정리: "AI 들어갔다고 모든 기능을 LLM 으로 풀면 안 돼요. LLM 자율 판단의 가치가 0 인 곳은 그냥 일반 컨트롤러. 셋이 한 코드베이스 안에 공존해야 정상."

시나리오 4 — 데이트 장소 리서치 (외부 검색 결합)

입력: "이번 주말에 OOO 캐릭터랑 데이트할만한 곳 3 개 추천해줘. 분위기는 차분하게, 비 오면 실내로."

출력: 외부 검색 도구 호출 → 위치 / 영업 시간 / 날씨 / 분위기 분석 → 요약 → 후보 카드 추천 — 다단계의 자율적 결과.

5 분 토론: "이 일은 Workflow 인가요, Agent 인가요? 외부 검색 도구 가 들어간다는 점이 분류에 어떤 영향을 줄지 매겨봅시다."

모범 분류. Agent (스펙트럼의 오른쪽 끝 가까운 위치. 완전 자율 Agent 또는 Evaluator-Optimizer 패턴). 4 축으로 매기면. 입력 모호성: 극도로 높음 ("분위기 차분하게" 의 기준은? "이번 주말" 의 시간 윈도우는? 캐릭터 취향과의 매칭 가중치는?). 결과 예측 가능성 요구: 낮음 (매번 후보 장소가 바뀌는 영역. 결정론이 오히려 부자연스러움).

부작용 위험: 0 (조회·추천만). 비용 / 지연 민감도: 높지만 사용자가 기다릴 의향 있음 (사용자가 분 단위 기다려도 OK).

이 4 축이 가리키는 답은 Agent 의 더 깊은 영역. 사용자 발화의 모호성이 너무 커서 LLM 이 검색 키워드를 자율로 정하고 / 결과를 분석해서 다음 검색을 자율로 정하는 루프가 자연스럽게 들어와요.

캐릭터 자동 생성 (시나리오 2) 의 Orchestrator-Workers 보다 한 단계 더 자율적인 Evaluator-Optimizer. LLM 이 자기가 만든 결과를 자기가 평가하고 부족하면 다시 검색하는 루프. 손코딩은 Day 14.

Day 11 의 그림자 (도구 남용) 가 정확히 이 시나리오에서 등장합니다.

검색 도구를 LLM 이 자율로 호출 하는데 호출 횟수 가드 가 없으면 "한 번 더 검색하면 답이 나올 것 같아" 가 30 회 반복.

그래서 여기엔 Harness 5 요소가 모두 있어야 해요.

특히 예산 가드 (호출 횟수 / 토큰 누적 상한) 가 Step 3 의 시연 1, 시연 2 를 막는 빗장.

입력 모호성이 클수록 Agent 쪽이지만 Harness 도 그만큼 두껍게 들어가야 한다는 원칙. ⚖️

강사 한 줄 정리: "입력 모호성 극도로 높음 → Agent. 단 도구 호출 횟수 가드 + 토큰 예산 빗장 두껍게. Day 14 의 Evaluator-Optimizer + Harness 5 요소."

시나리오 5 — 게임 FAQ 자동 응답

입력: 사용자가 게임 안 도움말 채널에 던진 질문 한 줄 (예: "호감도는 어떻게 올라가요?" / "새 캐릭터는 어디서 추가하나요?" / "결제는 어떻게 해요?").

출력: 미리 준비된 FAQ 답변 중 가장 가까운 한 줄 (또는 "FAQ 에 없는 질문 — 운영자 1:1 문의 연결").

5 분 토론: "이 일은 Workflow 인가요, Agent 인가요? FAQ 풀이 제한적 이라는 점이 분류에 어떤 영향을 줄지 매겨봅시다."

모범 분류. Workflow (Routing 패턴 + 미래 RAG 의 미리보기). 4 축으로 매기면. 입력 모호성: 중간 (자연어로 들어오지만 답이 나올 영역은 게임 FAQ 풀 안에서만). 결과 예측 가능성 요구: 중간~높음 (같은 질문에 매번 다른 FAQ 답변이 나오면 사용자가 "이 챗봇 신뢰 안 가네" 라는 반응).

부작용 위험: 중간 (틀린 답이 사용자한테 그대로 전달되면 결제·환불 정책 오해 등 신뢰 손상). 비용 / 지연 민감도: 높음 (게임 내 FAQ 문의 트래픽이 캐릭터 대화만큼은 아니지만 만만치 않음).

이 4 축이 가리키는 답은 Routing + RAG. Routing: 질문 메시지를 호감도 / 캐릭터 관리 / 결제 / 기타 의 카테고리로 분류해서 그 카테고리의 FAQ 풀 만 검색.

RAG (Day 15~16 의 영역 — 한 줄 복선): FAQ 문서 풀에서 가장 가까운 답을 의미 검색해서 LLM 에게 전달. 두 패턴이 결합되면 FAQ 안에서 답이 나오는 일은 Workflow 의 Routing + RAG 로 충분해요. 🎯

여기에 Agent 자율 루프 를 두면 과잉.

FAQ 풀이 닫혀 있는데 LLM 에게 자율 검색을 맡기면 FAQ 에 없는 답을 LLM 이 환각으로 만들어버리는 일이 일어나요.

답이 정해진 풀 안에서 나와야 하는 곳은 Agent 자율보다 Workflow 의 결정론이 더 안전. 그리고 FAQ 에 없는 질문운영자 1:1 문의 연결 로 분기하는 게 정석.

AI 가 모든 질문에 답하는 척하는 = 환각의 위험.

강사 한 줄 정리: "FAQ 카테고리 안에서 답 나옴 → Workflow 의 Routing + RAG. Agent 자율은 과잉. Day 13 (Routing) → Day 15~16 (RAG) 가 만나는 지점."

🛑 5 시나리오 한눈에 — 정리표

자, 5 시나리오를 모두 굴려봤으니 한 표로 압축해 두고 가요. 머리에 박을 건 각 시나리오의 카테고리 + 적절한 패턴 + 핵심 근거 의 세 칸.

시나리오 카테고리 적절한 패턴 핵심 근거
1️⃣ 사용자 메시지 안전 분류 Workflow Routing 시작점 (Day 13) 결과 예측 가능 + 비용 민감 + 한 사이클로 끝남
2️⃣ 새 캐릭터 자동 생성 다단계 Agent Orchestrator-Workers (Day 14) 입력 모호성 + 다단계 의사 결정 — 단 발행은 HITL
3️⃣ 캐릭터 카드 조회 일반 컨트롤러 (LLM 안 씀 — 그냥 SQL) LLM 자율 판단의 가치 0 + 트래픽 폭발
4️⃣ 데이트 장소 리서치 Agent Evaluator-Optimizer + Harness 5 요소 (Day 14) 입력 모호성 극도로 높음 — 단 호출 횟수 빗장 두껍게
5️⃣ 게임 FAQ Workflow Routing + RAG (Day 13 + Day 15~16) FAQ 카테고리 안에서 답 나옴 — Agent 자율은 과잉

5 시나리오의 분포 — Workflow 2 + Agent 2 + 일반 컨트롤러 1. AI 가 들어간 서비스의 한 코드베이스 안에 세 카테고리가 동시에 살아 있다는 사실 이 가장 무겁게 와닿는 부분이에요. 모든 기능을 같은 카테고리로 몰지 않는다는 원칙.

비유 한 줄 챙겨두고 갈게요.

같은 ai-friends 앱 안에.

KTX (Agent.

자율의 무게로 멀리 가는 탈것) / 자율주행차 (Workflow.

정해진 노선 위의 자율 보조) / 동네 자전거 (일반 컨트롤러.

사람의 손이 다 잡는 탈것) 가 다 있어요. 모든 기능을 KTX 로 굴리면 동네 슈퍼 가는데도 KTX 를 타는 셈.

모든 기능을 자전거로 굴리면 부산 가는데도 자전거를 타는 셈.

어느 거리는 어느 탈것.

그 매칭이 판단의 근육.

💡 튜터의 결론

오늘의 한 줄. AI 가 들어간 서비스 ≠ 모든 기능을 LLM 으로 풀어야 하는 서비스. Workflow / Agent / 일반 컨트롤러 — 셋이 한 코드베이스 안에 공존 해야 정상이에요. 5 시나리오의 분포 (Workflow 2 + Agent 2 + 일반 컨트롤러 1) 가 그 공존을 압축한 모양. 그리고 판단의 4 축 (입력 모호성 / 결과 예측 가능성 / 부작용 위험 / 비용 민감도) 이 어느 시나리오가 어느 카테고리에 들어갈지를 재는 자. 판단 근육이 자리잡으면 어느 일에 어느 패턴을 쓸지가 머리에서 손으로 흐릅니다. 본 강의의 Day 13 (Workflow 패턴) → Day 14 (Agent 패턴 + Harness 손코딩) → Day 15~16 (RAG) 가 정확히 이 5 시나리오의 자리들을 한 코드베이스 안에 손으로 짜 넣는 호흡이에요. 🎯

자, 판단의 자 를 들고 5 시나리오 를 다 매겨봤으니 다음 Step 6 에서는 한 칸 더 좁혀서 지난 시간에 우리 손으로 짠 도구 3 종 (WeatherTool / GameStateTool / AffinityTool) 을 분류대 위에 올려봐요.

어느 도구가 Workflow 쪽인지 / 어느 도구가 Agent 로 갈 가능성이 있는지 — 우리 코드베이스를 직접 매겨봅시다.


Step 6. 우리 코드 분류 실습 — 도구 3 종을 분류대 위에

자, Step 5 에서 5 시나리오 카드 를 분류대 위에 한 장씩 올려봤죠.

Workflow 2 + Agent 2 + 일반 컨트롤러 1 의 분포를 정리했어요.

그런데 시나리오 카드는 가상의 입력·출력·트래픽을 상상으로 매기는 것.

그게 머리에 들어왔으니 한 칸 더 좁혀서 지난 시간에 우리 손으로 직접 짠 진짜 코드 위에 같은 분류를 한 번 더 굴려볼게요.

지난 시간 Day 11 에서 손으로 짠 도구 3 종. WeatherTool / GameStateTool / AffinityTool. 세 도구를 Workflow ↔ Agent 스펙트럼 + 일반 컨트롤러 위에 올려두고 어디에 들어가는지 매겨봅니다. 시나리오 카드가 상상 이었다면, 이번엔 내 손에 익은 코드 위에서 분류를 굴리는 단계.

책 정의보다 지난 시간에 내 손이 짠 코드를 분류대 위에 올려보는 게 머리에 훨씬 단단하게 남아요. 그리고 한 가지 더. 이 분류를 굴려보고 나면 "우리가 지난 시간에 만든 게 에이전트인가요?" 라는 면접에서 한 번쯤은 나올 질문에 자기 손으로 답할 수 있게 됩니다. 🎯

분류 도구 — 4 축 + Step 4 의 4 박자 두 개 묶기

본격 코드 카드를 분류대 위에 올리기 2가지 축을 두고 갈게요.

하나는 Step 5 의 4 축 — 입력 모호성 / 결과 예측 가능성 / 부작용 위험 / 비용 민감도.

시나리오를 매기던 그 자가 코드에도 그대로 통해요.

도구 하나도 결국 어떤 입력을 받아 / 어떤 출력을 내는 / 어떤 부작용을 가진 / 어떤 트래픽 환경에 놓인 함수니까요.

또 하나는 Step 4 의 4 박자.

도구 / LLM 자율 / 루프 / 가드레일.

학문 정의의 척추, 진짜 Agent 인지 를 매기는 4 개의 체크박스.

도구 카드 위에 * * 가 다 찍히면 Agent, * * 정도면 Workflow 의 가장 작은 시작점, * * 면 일반 컨트롤러. 두 자가 같은 카테고리를 가리키는지.

도구 하나를 매길 때마다 4 축으로 한 번 / 4 박자로 한 번 매겨서 답이 같으면 거기에 둡니다.

같지 않으면 왜 다른지 가 그 자체로 가르침이 돼요.

WeatherTool외부 API 조회, 부작용 0

첫 번째 카드.

지난 시간에 가장 먼저 익힌 도구.

WeatherTool.getCurrentWeather.

도시명을 받아 stub 응답을 돌려주는 도구예요. 4 축으로 매겨볼게요.

입력 모호성: 낮음~중간.

사용자는 "오늘 서울 날씨 어때?" 처럼 자연어로 묻지만 도구가 받는 건 도시명 한 줄. 결과 예측 가능성 요구: 높음.

같은 도시에 매번 다른 날씨 stub 이 나오면 안 됨 (실제 API 라면 그 시점의 진짜 값).

부작용 위험: 0.

외부 API 를 두드리지만 읽기 전용, DB 도 안 건드리고 메일도 안 보내요.

비용 / 지연 민감도: 높음.

외부 API 한 번 호출이 수백 ms 걸릴 수 있고 트래픽이 폭발하면 비용이 누적.

이제 4 박자로 한 번 더.

*(1) 도구: *.

@Tool 어노테이션 한 줄로 등록된 진짜 도구.

*(2) LLM 자율 호출: *.

"오늘 서울 날씨 어때?" 라는 자연어를 보고 LLM 이 알아서 골라 부름. 우리가 if-else"날씨라는 단어가 들어오면 이 도구를 부르세요" 라고 코딩하지 않았어요.

*(3) 루프: *.

한 사이클에 도구 한 번 호출, 결과 받고 자연어로 가공해서 답변.

*(4) 가드레일: *.

maxIterations / 토큰 예산 / 호출 횟수 가드.

지난 시간엔 아무것도 추가하지 않았어요. Spring AI 기본값에만 의존.

두 자가 같은 답을 가리킵니다.

WeatherTool = *Tool Calling.

Workflow 의 가장 작은 시작점. 4 축에선 입력 모호성 낮음 + 부작용 위험 0 + 결과 예측 가능성 높음.

스펙트럼 왼쪽 가까운 위치. 4 박자에선 *도구 + LLM 자율 + 루프 + 가드레일 *.

한 사이클로 끝나는 가장 얕은 형태. Step 5 의 시나리오 1 (사용자 메시지 안전 분류) 와 친척이에요.

Day 13 의 Routing 패턴이 본격 등장하는 자리시작점.

GameStateTool한 클래스에 두 방식이 공존

두 번째 카드가 오늘 분류에서 가장 미묘한 부분. GameStateTool 은 메서드가 두 개saveGameStateloadGameState. 한 클래스에 메서드 두 개 는 자주 있지만, 분류로 매겨 보면 두 메서드가 서로 다른 카테고리로 들어가요. 한 번씩 매겨볼게요.

먼저 loadGameState.

조회. 4 축: 입력 모호성: 0 (userId 한 개), 결과 예측 가능성 요구: 극도로 높음 (같은 사용자 ID 에 매번 다른 게임 상태가 나오면 안 됨), 부작용 위험: 0 (DB 조회만), 비용 / 지연 민감도: 높음 (사용자가 게임 화면 들어올 때마다 호출).

4 박자: *도구 + LLM 자율 + 루프 + 가드레일 *.

WeatherTool 와 동일.

*loadGameState = Tool Calling. AffinityTool 과도 같은 친척이에요 (잠깐 뒤에 다룰 도구).

그런데 saveGameState.

부작용이 있는 메서드. 4 축: 입력 모호성: 0 (userId + 게임 상태 객체), 결과 예측 가능성 요구: 극도로 높음, 부작용 위험: 중간~높음 (DB 가 영구 변경됨), 비용 / 지연 민감도: 중간. 4 박자에서 결정적인 건.

(2) LLM 자율 호출 부분.

지난 시간에 우리는 이 메서드를 LLM 자율 호출 도구로 등록하지 않았어요. @Tool 어노테이션을 안 붙이고 Service 코드에서 우리가 직접 호출하는 구조로 짰죠.

왜?.

부작용이 있는 메서드에 LLM 자율을 통째로 위임하면 Step 5 시나리오 2 의 새 캐릭터 자동 생성에서 그어둔 HITL 빗장 (사용자 검토 단계) 이 사라진 상태가 나와요.

LLM 이 자기 판단으로 DB 를 영구 변경. 그래서 사람의 손 (또는 우리 Service 코드의 손) 이 빗장이 되어야 한다는 게 지난 시간의 교훈.

*saveGameState = 도구 등록은 했지만 LLM 자율 호출은 막아 둔. Day 14 가드의 자리 후보. 4 박자: 도구 + LLM 자율 (의도적으로 막음) + 루프 + 가드레일 (서비스 레이어에서 우리가 직접 호출하는 빗장 자체가 가드레일). 한 클래스에 읽기는 LLM 자율로 / 쓰기는 우리 손으로 라는 두 방식이 공존 해요. 지난 시간 코드의 AffinityTool 의 readme 한 줄.

"읽기는 도구 안 / 쓰기는 도구 밖" 의 원칙을 GameStateTool 한 클래스가 내부에서도 그대로 따르고 있는 모습이에요.

AffinityTool읽기 전용 DB 조회

세 번째 카드.

AffinityTool.getAffinity.

지난 시간 마지막에 익힌 도구.

캐릭터의 호감도 score 와 라벨을 조회만 하는 메서드. 4 축: 입력 모호성: 0 (soulmateId 한 개), 결과 예측 가능성 요구: 높음 (같은 캐릭터에 매번 다른 score 가 나오면 게임 자체가 무너짐), 부작용 위험: 0 (@Tool description 에 "읽기 전용.

score 를 바꾸지 않는다" 라고 명시), 비용 / 지연 민감도: 중간 (DB 조회 한 번, 사용자가 "우리 사이 어때?" 물을 때마다 호출). 4 박자: *도구 + LLM 자율 + 루프 + 가드레일 *.

WeatherTool동일.

*AffinityTool = Tool Calling — WeatherTool 와 같은 카테고리. 4 박자가 같은 답을 가리켜요. 다만 도구가 두드리는 곳이 외부 API 가 아니라 우리 DB 라는 점만 다를 뿐, 한 사이클로 끝나는 / 부작용 0 의 / LLM 자율 호출이 자연스러운 구조는 그대로.

읽기 전용 도구가 Tool Calling 의 가장 안전한 시작점 이라는 지난 시간의 교훈이 분류대 위에서도 그대로 드러나요. Tool Calling 을 처음 도입할 때 항상 조회 도구부터 라는 원칙이 분류로 매겨 봐도 같은 카테고리 라는 점.

🛑 우리 코드 3 종 — 한눈에 정리표

자, 도구 3 종 (saveGameState / loadGameState 가 갈라지니 사실은 4 행) 을 분류대 위에 다 올려봤으니 한 표로 정리해 두고 가요. 지난 시간에 내 손이 짠 코드분류대 위 어디에 박혔는지 가 한눈에 들어오는 표.

도구 메서드 4 박자 (도구·자율·루프·가드) 카테고리 핵심 근거
WeatherTool.getCurrentWeather Tool Calling — Workflow 시작점 외부 API 조회 / 부작용 0 / 한 사이클
GameStateTool.saveGameState Day 14 가드 자리 후보 부작용 / LLM 자율은 의도적으로 막음 / 우리 Service 가 직접 호출
GameStateTool.loadGameState Tool Calling — Workflow 시작점 DB 조회 / 부작용 0 / 한 사이클
AffinityTool.getAffinity Tool Calling — Workflow 시작점 DB 조회 / 부작용 0 / 한 사이클 (description 에 "읽기 전용" 명시)

4 행 중 3 행이 같은 카테고리Tool Calling, Workflow 의 가장 작은 시작점. 그리고 한 행만 saveGameState다른 카테고리 인데, 그게 Day 14 의 가드 와 정확히 맞물려요.

지난 시간에 익힌 4 도구가 스펙트럼의 왼쪽에 옹기종기 모여 있고 / 한 개만 다른 카테고리로 갈 후보. 우리는 아직 Agent 영역에 한 발도 들이지 않았다는 사실 이 정리표에서 가장 무겁게 드러나요.

함정 짚기 — "우리가 지난 시간에 만든 게 에이전트인가요?"

자, 정리표가 정리됐으니 오늘 가장 자주 들을 질문 에 정면으로 답해볼게요. "그러면 — 지난 시간에 손으로 짠 도구 3 종, 그게 에이전트인가요?" 학생도 묻고 면접관도 물을 질문. 답을 두 가지로 나눠 정리해 둘게요.

첫째. 학문 정의 기준 (Russell & Norvig / Lilian Weng). 4 박자 중 *루프 + 가드레일 * 인 코드는 학문 정의로 Agent 가 아니에요. 우리는 도구 + LLM 자율 호출 두 박자만 켰을 뿐, 루프가드레일 두 박자는 아직 Day 14. 학문 정의로 답하면. "아니요.

지난 시간에 만든 건 Tool Calling 이고 Agent 의 가장 작은 시작점이지만, 4 박자 중 2 박자만 켰으니 Agent 라고 부르기엔 일러요."

둘째. 실무 정의 기준 (Anthropic / OpenAI / 업계 블로그). 같은 4 박자가 있을 때, 실무에선 "@Tool + LLM 자율 호출이 일어나면 그 시점부터 모두 Agentic" 의 넓은 정의로 부르는 경우도 분명히 있어요.

그 정의로는 지난 시간에 만든 게 Agentic 의 시작점. 단 본 강의는 실무 정의 중에서도 Anthropic 의 결정론적 Workflow / 자율 Agent 구분 을 채택해요. 그렇게 답하면. "지난 시간에 만든 건 Workflow 의 가장 작은 시작점 (Tool Calling). Agent 의 본격 영역은 Day 14 부터." 두 답 모두 부분적으로 맞고.

면접에서는 어느 정의로 매겼는지를 먼저 밝히고 답하는 방식이 가장 안전해요. 학문 / 실무 넓은 정의 / 본 강의 채택 정의. 어느 자로 매겼는지를 분명히 하는 게 판단의 근육.

본 강의가 Anthropic 의 결정론적 Workflow / 자율 Agent 구분을 채택했나 — Day 14 의 Harness 5 요소가 갖춰진 시점부터가 진짜 Agent 라는 한 줄이 학생의 손에서 가장 또렷이 잡히는 정의이기 때문이에요.

아무 도구나 호출하면 Agent 라는 넓은 정의로 가면 Day 14 에서 Harness 를 손코딩할 때 "이걸 왜 짜지?" 가 흐려져요.

Workflow 와 Agent 사이에 분명한 선이 있는 정의 가 Day 13 / Day 14 의 학습을 손에 단단히 잡아줍니다. 🎯

Day 13~14 복선 — 우리 도구가 다음 단계에서 어떻게 자라나는가

자, 도구 3 종이 분류대 위에 올라갔으니 이어지는 Day 가 어떻게 이어지는지 한 줄씩 복선을 두고 갈게요. 지난 시간에 짠 코드가 다음 Day 어느 모양의 씨앗 인지가 보이는 부분이에요.

WeatherTool → Day 13 Routing 노드. 지난 시간에 짠 한 사이클짜리 외부 조회 가 Day 13 Workflow Patterns 에서 Routing 패턴의 한 노드 로 자라나요.

사용자 발화를 날씨 / 호감도 / 게임 상태 카테고리로 분류해서 해당 카테고리의 도구 하나만 부르는 형태의 Routing. Step 5 의 시나리오 1 (메시지 안전 분류) / 시나리오 5 (게임 FAQ) 와 같은 흐름이 우리 도구 위에서 펼쳐지는 단계예요.

saveGameState → Day 14 가드. 지난 시간에 의도적으로 LLM 자율 호출을 막아둔 메서드가 Day 14 Agent Patterns + Harness 손코딩 에서 부작용 가드의 본격 영역 으로 들어와요. 툴 권한 스코프 (이 LLM 은 읽기 도구만 호출 가능, 쓰기 도구는 사람 검토 단계에서만) / 예산 가드 (호출 횟수 / 토큰 누적 상한)

다섯 요소가 손에 들어옵니다. 지난 시간에 막연히 "쓰기는 도구 안 둔다" 는 원칙으로 짰던 부분 이 Day 14 에서 Harness 5 요소 의 한 항목으로 정식 자리잡는 모습.

Day 19 Agent Client 의 선언적 형태. 한 가지 더. Day 14 에서 직접 손으로 짜는 가드 5 요소가 Day 19 의 Spring AI Agent Client 에 가면 선언적으로 (어노테이션 / 프로퍼티 한 줄로) 적용돼요. Day 14 손코딩 → Day 19 선언적 의 흐름이. "손으로 한 번 짜본 뒤 프레임워크가 그 형태를 받아 깔아주는 단계" 의 한 층.

지난 시간에 짠 도구 3 종이 Day 13 (Routing) → Day 14 (Harness 손코딩) → Day 19 (Agent Client 선언적) 까지 한 줄로 자라납니다.

💡 튜터의 결론 — 우리 코드를 분류대 위에 올려보는 시간

💡 튜터의 결론

오늘의 한 줄. 책 정의보다 지난 시간에 내 손이 짠 코드를 분류대 위에 올려보는 게 머리에 훨씬 단단히 남아요. 5 시나리오의 분류가 판단 근육을 만드는 운동 이었다면, 우리 도구 3 종의 분류는 그 근육으로 진짜 무게를 들어보는 첫 단계. WeatherTool / loadGameState / AffinityTool 세 메서드가 Tool Calling — Workflow 의 가장 작은 시작점 에 옹기종기 모이고 / saveGameState 한 메서드만 Day 14 가드 자리 후보 로 따로 떨어진 분포가 우리는 아직 Agent 영역에 한 발도 들이지 않았다는 사실 을 정직하게 말해줘요. 그리고 그 정직함이 Day 13 / Day 14 / Day 19왜 따로 펼쳐야 하는지 의 답이 됩니다. 책 정의를 외운 손 보다 내 손이 짠 코드를 분류대 위에 올려본 손면접에서 "에이전트가 뭐예요?" 앞에 한 박자 더 침착하게 답할 수 있어요.

자, 우리 코드 3 종을 분류대 위에 올려보는 단계가 끝났어요.

Workflow / Agent / 일반 컨트롤러 셋이 한 코드베이스 안에 공존한다는 점, 지난 시간에 짠 도구 3 종이 그 중 어느 카테고리에 들어가는지, 다음 시간부터 Day 13 / Day 14 / Day 19 가 어떤 모양으로 자라나는지 의 복선까지 한 호흡으로 정리됐어요.

다음 Step 에서는 한 칸 더 좁혀서 — Step 2 에서 이름만 던져뒀던 5 패턴다음 시간·다다음 시간 어떤 모양으로 펼쳐질지 한 컷씩 미리 보는 흐름으로 들어가 봅시다.


Step 7. Agentic Patterns 미리보기 — 3+2 패턴

자, Step 6 까지 판단의 자 가 두 손에 단단히 들어왔어요.

4 박자 정의 (Step 1) → 스펙트럼 + 트레이드오프 (Step 2) → 폭주 화면 (Step 3) → Harness 5 요소 (Step 4) → 5 시나리오 분류 (Step 5) → 우리 코드 분류 (Step 6). 한 호흡으로 흘러왔는데 한 가지가 아직 이름만 던져둔 채 비어 있어요.

*Step 2 에서 카드 5 장으로 펼쳤던 Anthropic 의 5 패턴. Prompt Chaining / Routing / Parallelization / Orchestrator-Workers / Evaluator-Optimizer — 이름만 박힌 채 어떤 모양인지 는 살짝 흐릿하게 두고 왔죠.

오늘 마지막 Step 의 호흡을 미리 한 줄로 정리할게요.

이 Step 은 5 패턴이 어떤 모양인지를 한 컷씩 미리 보는 단계예요.

*손코딩은 다음 시간·다다음 시간 (Day 13~14). 코드 한 줄도 인용하지 않아요.

손이 아니라 으로 한 번 미리 펼쳐보고, 어떤 패턴이 어떤 일에 들어갈지 의 매핑이 머리에 들어오면 충분해요.

오늘은 미리보기 카드 5 장 / 다음 시간엔 손코딩 3 장 (Day 13) / 모레는 손코딩 2 장 + 가드 4 부품 (Day 14) — 이 호흡으로 일주일이 흘러요.

Workflow 계열 3 패턴 — Day 13 의 영역

먼저 스펙트럼의 왼쪽 에 놓인 3 장.

Workflow 계열 가족이에요.

세 패턴 모두 — 다음 단계 / 다음 도구 선택의 주도권이 코드 쪽 에 있어요. Spring AI ChatClient + 평범한 Java if-else / switch / List.parallelStream() 같은 결정론적 도구로 충분히 짤 수 있는 가족.

한 컷씩 펼쳐 둘게요.

1) Prompt Chaining — 직렬 체인 . 한 작업을 여러 단계로 쪼개 차례차례 LLM 을 호출하는 패턴이에요. Step A 의 결과 → Step B 의 입력 → Step C 의 입력 의 직렬 흐름. 각 단계의 순서를 정하는 주체코드

그래서 결정론적입니다. 어디서 멈출지 / 다음 단계로 갈지 가 코드의 for 한 줄로 다 결정돼요.

미연시 도메인으로 한 컷 — 사용자 메시지 자동 처리. 1 단계: 메시지가 normal / abuse / escalate 중 무엇인지 분류 (LLM 호출 1 회) → 2 단계: normal 이면 캐릭터 답장 초안 생성 (LLM 호출 1 회) → 3 단계: 답장 톤이 캐릭터의 성격 시트에 맞는지 검수 (LLM 호출 1 회).

세 단계가 직렬로 흐르고 각 단계의 출력이 다음 단계의 입력으로 들어가는 구조.

Step 5 의 시나리오 1 (메시지 안전 분류) 를 한 단계 더 깊게 풀면 정확히 이 패턴.

1 단계만 들어간 게 시나리오 1 이었다면, 그 위에 답장 생성 + 톤 검수 단계까지 얹힌 게 Prompt Chaining.

2) Routing — 분기 . 입력의 종류 / 카테고리 에 따라 서로 다른 LLM / 도구 / 핸들러 로 분기하는 패턴. 분류 자체 는 작은 LLM 한 번이 결정하지만 그 분류 결과를 보고 어느 핸들러로 갈지의 코드 경로결정론적 switch / if-else. 그래서 Workflow 카테고리.

미연시 도메인 한 컷. 사용자 메시지를 카테고리에 따라 분기. 메시지 한 줄이 들어오면 → 작은 LLM 이 "게임 FAQ / 호감도 변동 액션 / 안전 알림 / 일반 대화" 중 하나로 분류 → 분류된 카테고리에 따라 다음처럼 분기.

  • FAQ → RAG 검색 LLM 으로
  • 호감도 액션AffinityTool
  • 안전 알림 → 운영팀 큐로
  • 일반 대화 → 캐릭터 챗 LLM 으로

Step 5 의 시나리오 5 (게임 FAQ) 가 정확히 이 패턴이에요. 카테고리별로 LLM 의 시스템 프롬프트와 도구 풀이 다르지만 분기 자체는 코드가 정한다 는 점.

3) Parallelization — 병렬 . 같은 작업을 여러 갈래로 동시에 던지고 결과를 합치는 패턴. 결정론적이지만 비용은 N 배. 한 호출이 끝날 때까지 기다리지 않고 동시에 N 개 호출 을 던져서 지연을 줄이거나 결과를 합쳐 안정화 하는 방식이에요.

미연시 도메인 한 컷.

사용자 메시지 한 줄을 동시에 세 갈래로 분석. 메시지 한 줄이 들어오면 → 감정 분석 LLM (호감 / 무난 / 적대) + 의도 추출 LLM (질문 / 데이트 신청 / 농담) + 캐릭터 페르소나 매칭 LLM (이 캐릭터의 성격 시트에서 어떤 답이 자연스러운지).

세 호출을 동시에 던지고 → 결과 셋을 한 줄로 합쳐 답장 후보 생성. Java 의 List.parallelStream() 또는 CompletableFuture.allOf() 한 줄로 병렬 이 들어갑니다.

세 호출의 비용은 한 호출의 3 배 지만 지연은 한 호출 분량 에 가까운 트레이드오프.

그게 가치 있을 때만 쓰는 패턴이에요.

세 패턴을 한 줄로 묶으면 이래요.

세 패턴 모두 다음 단계 / 다음 도구 선택의 주도권이 코드 에 있어요. 루프가 있더라도 while LLM 이 멈추라고 말할 때까지 가 아니라 / for i in 1..N 의 결정론적 루프. Spring AI ChatClient + 평범한 Java 코드 만으로 외부 그래프 DSL 한 줄 없이 충분히 이해돼요.

지난 시간에 도구들이 이 세 패턴 중 어느 노드로 자랄 수 있는지 가 Day 13.

Agent 계열 2 패턴 — Day 14 의 영역

이제 스펙트럼의 오른쪽 으로. Agent 계열 두 장. 두 패턴 모두 — 루프와 자율 결정이 들어가 있어요. Workflow 계열의 결정론 과 가장 다른 한 가지는 언제 멈출지를 LLM 이 결정 한다는 점이에요. 한 장씩 펼쳐 둘게요.

4) Orchestrator-Workers — 오케 → 워커 분배 . 오케스트레이터 LLM 한 명이 워커 LLM 들에게 작업을 동적으로 분배 하고 결과를 종합 하는 패턴. 핵심은 어떤 워커에게 / 어떤 일을 / 몇 개의 워커가 필요한지오케스트레이터가 자율 판단 한다는 거예요.

코드는 오케 + 워커들이 도는 빈 그릇 만 마련해 줄 뿐, 분배의 결정 은 LLM 쪽.

미연시 도메인 한 컷 — Step 5 시나리오 2 의 새 캐릭터 자동 생성 그대로.

  • 사용자: "애교 많고 운동 좋아하는 친구 캐릭터 만들어줘."
  • 오케스트레이터 LLM"이 작업은 [컨셉 정리 + 외모 묘사 + 성격 시트 + 첫 인사말 + 톤 검수] 5 단계가 필요해요" 라고 판단
  • 워커 분배 — 각 단계의 워커 LLM (컨셉 워커 / 외모 워커 / 성격 워커 / 인사말 워커 / 검수 워커) 에게 분배
  • 종합 — 워커들의 결과를 받아 한 장의 캐릭터 카드 초안으로 종합

핵심은 작업이 4 단계인지 5 단계인지 / 어떤 순서인지를 오케가 자율로 정한다 는 점. 코드의 if-else 로 다 짤 수 없는 영역이에요.

5) Evaluator-Optimizer — 생성 + 평가 피드백 루프 . 생성 LLM + 평가 LLM 두 명이 피드백 루프를 도는 패턴. 생성이 1 차 결과를 만들고 → 평가가 그 결과의 부족한 부분을 짚고 → 생성이 그 피드백을 받아 2 차 결과를 만들고 → 평가가 또 보고… → "이제 됐다" 라고 평가가 OK 신호를 주면 종료.

핵심은 언제 멈출지를 평가 LLM 이 자율 결정 한다는 점이에요.

미연시 도메인 한 컷.

Step 5 시나리오 4 의 데이트 장소 리서치. 사용자: "이번 주말에 OOO 캐릭터랑 데이트할 곳 3 개 추천해줘.

분위기 차분하게." → 생성 LLM 이 외부 검색 + 1 차 후보 초안 작성 → 평가 LLM 이 "근거 부족.

영업 시간 확인 안 됨 / 캐릭터 취향 매칭이 흐림" 이라고 짚음 → 생성이 추가 검색 + 2 차 후보 → 평가가 "근거는 충분.

단 분위기 매칭이 모호" 짚음 → 3 차 / 4 차…"이제 OK" 사인이 떨어지면 마무리.

루프가 몇 번 도는지 는 사용자도 코드도 미리 모른다 는 점이 특징.

자, 두 패턴을 한 줄로 묶으면 이래요.

*두 패턴 모두 루프와 자율 결정이 들어가 있어요. 그리고 그 무게가 들어간 곳에서는 Step 3 의 폭주가 그대로 일어날 수 있는 위험 이 같이 따라와요.

그래서 Day 14 에서는 손코딩 2 패턴 + 가드레일 4 가지 필수 의 호흡으로 가요.

maxIterations / 토큰 예산 / 도구 호출 횟수 / 타임아웃 — Step 4 의 Harness 5 요소 중 손으로 짤 4 부품Agent 계열 패턴의 손코딩과 한 묶음으로 들어가야 합니다.

루프를 두는 순간 가드를 같이 두지 않으면 안 된다는 원칙.

Step 5 시나리오 ↔ 5 패턴 — 매핑 한 컷

자, 5 패턴이 정리됐으니 Step 5 의 5 시나리오 와 한 줄로 매핑해 둘게요. 시나리오 카드의 분류 결과Step 7 의 패턴 매핑 으로 한 단계 깊어집니다. 어느 시나리오가 어느 패턴 위에 박히는지 — 표 한 장.

시나리오 (Step 5) 적절한 패턴 카테고리
1️⃣ 사용자 메시지 안전 분류 Routing 시작점 (단계가 늘면 Prompt Chaining) Workflow (Day 13)
2️⃣ 새 캐릭터 자동 생성 Orchestrator-Workers Agent (Day 14)
3️⃣ 캐릭터 카드 조회 (5 패턴 어디에도 박히지 않음 — LLM 안 씀) 일반 컨트롤러
4️⃣ 데이트 장소 리서치 Evaluator-Optimizer Agent (Day 14)
5️⃣ 게임 FAQ Routing + RAG (Day 15~16) Workflow (Day 13)

표에서 한 가지 짚어볼게요.

5 시나리오 중 4 개가 5 패턴 위에 올라갔어요. Workflow 2 (시나리오 1, 5) + Agent 2 (시나리오 2, 4).

그리고 시나리오 3 (캐릭터 카드 조회) 하나만 5 패턴 어디에도 들어가지 않는 케이스.

그건 LLM 자체를 안 쓴다는 의미 라 5 패턴의 좌표 위에 올라가지 않아요.

그냥 /api/soulmates/{id} GET 일반 컨트롤러.

이 한 줄이 AI 가 들어간 서비스 ≠ 모든 곳에 LLM 을 박는 서비스 라는 원칙을 패턴 매핑에서도 한 번 더 짚어줍니다.

이 매핑이 정리됐다는 건 Day 13 / Day 14 / Day 15~16 가 왜 따로 펼쳐져야 하는지 가 한 표로 보인다는 뜻이에요.

Workflow 2 는 Day 13 / Agent 2 는 Day 14 / RAG 가 결합되는 건 Day 15~16 / 일반 컨트롤러는 그냥 평범한 Spring MVC — 한 코드베이스 안에 4 가지 카테고리 가 공존하는 모양이 이번 주~다음 주의 일정입니다.

🛑 본 강의의 선언 — Spring AI ChatClient + Advisors + 평범한 Java 만

자, 5 패턴이 정리됐으니 어떤 도구로 이 5 패턴을 짤지 의 입장을 한 번 더 단단히 못 박아두고 갈게요.

🛑 본 강의는 외부 그래프 DSL (Alibaba Spring AI Alibaba Graph / LangGraph 등) 을 도입하지 않아요. Spring AI ChatClient + Advisors + 평범한 Java 코드 만으로 5 패턴 모두 손코딩합니다.

이 선언의 이유는 두 가지.

첫 번째. 코드로 직접 익히는 직관. 그래프 DSL 은 마법처럼 느껴져서 직관이 안 잡혀요. addNode() / addEdge() 한 줄을 쓰면 그 안에서 어떻게 흐름이 이어지는지 가 안 보여요. 왜 이 노드가 다음 노드를 부르는가? 왜 여기서 루프가 멈추는가?. 답이 프레임워크 안에 가려진 채로 진행되면, 학생의 손에는 마법의 흔적 만 남습니다.

그래서 본 강의는 평범한 Java 의 if-else / switch / for / CompletableFuture.allOf / try-catch 같은 손에 익은 도구 로 5 패턴을 짜요. 왜 이 줄에서 분기가 일어나는지 / 왜 이 줄에서 루프가 도는지 / 왜 이 줄에서 멈춤이 일어나는지.

답이 코드의 한 줄 한 줄에 그대로 보입니다.

두 번째 — Spring AI 1.1.x 의 ChatClient + Advisors 만으로도 충분. 5 패턴 모두 Day 14 까지 손코딩으로 짤 수 있어요. 외부 DSL 없이도 5 패턴이 다 들어가는데 거기에 외부 DSL 을 얹는 건 직관을 한 단계 더 멀게 만드는 결과.

프레임워크는 손이 익은 자리 위에 짧아지는 모양으로 나중에 들어와야 한다 는 본 강의의 호흡 (Day 14 손코딩 → Day 19 Spring AI Agent Client 선언적) 이 정확히 이 선언의 근거예요.

심화 레퍼런스 만 한 줄 짚어두고 갈게요. Alibaba Spring AI Alibaba Graph (LangGraph 의 Java 포팅) / LangGraph (Python) / OpenAI Agents SDK / Google ADK / Microsoft AutoGen

2026 년 지금 시점의 프레임워크들이에요. 본 강의는 이들 중 어느 것도 손대지 않아요.Day 19 에서 Spring AI Agent Client 를 다룰 때 심화 레퍼런스 로 한 줄 "이런 외부 프레임워크들도 있고, 5 패턴은 그 안에서도 똑같이 통한다" 는 비교는 던져 둡니다.

학생이 회사에서 외부 그래프 DSL 을 만나도 오늘 익힌 5 패턴 이 그대로 통해요.

2026 년 지금을 한 줄로 정리하면 이래요. 어떤 프레임워크를 쓰든 5 패턴은 그대로 통합니다. 본 강의는 Spring AI ChatClient + Advisors 에서 그 5 패턴을 코드로 직접 익히는 길. 프레임워크는 변해도 분류 기준 (Workflow vs Agent) 과 5 패턴의 골격은 변하지 않아요.

그래서 오늘 정리한 5 패턴의 이름표 가 학생이 어느 회사에 가든 어느 프레임워크를 만나든 통합니다.

Day 13~14 의 문 미리 두드리기

자, 마지막으로 다음 시간·다다음 시간 가 어떤 모양으로 펼쳐질지 한 줄씩 던져두고 갈게요. Step 6 의 우리 도구 분류Step 7 의 패턴 매핑Day 13 ~ Day 14 의 손코딩 에서 어떻게 이어질지의 복선이에요.

Day 13 — Workflow 3 패턴 손코딩 . 다음 시간이에요. Prompt Chaining / Routing / Parallelization 세 패턴을 Spring AI ChatClient + 평범한 Java 로 손에 익혀요. 지난 시간에 짠 WeatherToolRouting 노드의 하나 로 자라납니다.

사용자 메시지 한 줄이 들어오면 분류 LLM 이 "날씨 / 호감도 / 게임 상태" 로 분류 → 분류된 카테고리에 따라 우리 도구 3 종 중 하나로 분기 의 모양. Step 6 에서 본 우리 도구 3 종이 옹기종기 모여 있던 Workflow 시작점Routing 패턴 안으로 들어갑니다.

Day 14. Agent 2 패턴 손코딩 + 가드 4 부품 . 모레. Orchestrator-Workers / Evaluator-Optimizer 두 패턴을 Spring AI ChatClient + 평범한 Java 로 손에 익혀요. 그리고 Step 4 에서 정리한 Harness 5 요소 중 4 부품손코딩으로 같이 들어옵니다.

maxIterations / 토큰 예산 / 도구 호출 횟수 / 타임아웃. 4 가지 빗장이 Agent 손코딩 위에 한 층으로 얹혀야 해요. 지난 시간에 의도적으로 LLM 자율 호출을 막아둔 saveGameState툴 권한 스코프 (가드의 한 부품) 로 정식 자리잡아요.

Step 6 에서 분류대 위에 따로 떨어져 있던 메서드Day 14 의 가드 영역에 정식으로 자리잡는 모습.

Day 19 — Spring AI Agent Client 위에서 손코딩이 선언적으로 짧아지는 단계 . 일주일 뒤. Day 14 에서 손으로 짠 가드 4 부품 + 5 패턴의 흐름어노테이션 한 줄 / 프로퍼티 한 줄로 적용됩니다. 손코딩 분량이 체감으로 짧아지지만 짧아진 게 아니라 프레임워크 안으로 옮겨갔을 뿐 이라는 점.

손으로 한 번 짜본 뒤 프레임워크가 그 형태를 받아 깔아주는 단계 가 Day 19. 그래서 오늘 미리보기 → Day 13 / Day 14 손코딩 → Day 19 선언적 의 한 사다리가 5 패턴을 세 번 만나는 호흡으로 흐릅니다.

💡 튜터의 결론

오늘의 마지막 한 줄. 오늘은 5 패턴의 이름표 만 손에 들었어요. 다음 시간·다다음 시간 그 이름표 위에 진짜 코드 한 줄씩 얹힙니다. Workflow 계열 3 패턴 (Prompt Chaining · Routing · Parallelization) 은 Day 13 / Agent 계열 2 패턴 (Orchestrator-Workers · Evaluator-Optimizer) 은 Day 14 + 가드 4 부품 손코딩 필수. Step 5 의 5 시나리오5 패턴 위에 한 줄로 매핑되는 모양이 이번 주 ~ 다음 주의 일정. 그리고 본 강의는 외부 그래프 DSL 을 도입하지 않고 Spring AI ChatClient + Advisors + 평범한 Java 만으로 5 패턴을 익힙니다. 어떤 프레임워크를 쓰든 5 패턴은 그대로 통한다 는 점을 손에 들고 다음 시간 Day 13 의 손코딩 으로 들어가 봅시다.

자, 오늘 Step 7 까지 판단의 자 두 개 (4 박자 + 4 축) + 폭주 화면 + Harness 5 요소 + 5 시나리오 분류 + 우리 코드 분류 + 5 패턴 미리보기 까지 한 호흡으로 흘러왔어요.

코드 변경 0 / 의사 결정 무게 100 의 호흡이 오늘 머리에 무겁게 자리잡은 부분. 다음 섹션에서 Day 12 의 호흡을 한 번 매듭짓고 다음 시간 Day 13 의 Workflow 패턴 손코딩 으로 넘어가는 마무리로 들어가 봅시다.


🏁 마무리

자, Day 12 의 모든 매듭이 닫혔어요.

지난 시간 마지막 한 줄.

"방금 만든 게 에이전트인가요? 그 답은.

다음 시간." 그 약속이 오늘 끝에서 두 줄로 정확히 정리됐어요.

학문 정의로는 가장 작은 시작점. 실무 정의로는 Tool Calling 단계 / Workflow 의 시작점 / 4 박자 중 두 박자만 채워진 상태.

아직 에이전트가 아니에요. 답이 하나가 아니라 두 줄로 갈라져 있다는 점까지 머리에 잡힌 게 오늘의 진짜 매듭이에요. 7 Step + 마무리 한 호흡으로 코드 변경 0 / 판단의 무게 100 을 한 도시에 담아냈어요.

1. 오늘 익힌 흐름 — 7 Step 압축 회고 ✅

오늘 일곱 Step 을 한 줄씩 회수해 봅시다.

Step 한 줄 정리
✅ Step 1 에이전트의 정의 — 학문 (perceive·decide·act 3 박자) vs 실무 (도구 + LLM 자율 + 루프 + 가드레일 4 박자) 두 가지
✅ Step 2 Anthropic Building Effective AgentsWorkflow ↔ Agent이분법이 아니라 농도 차이의 스펙트럼
✅ Step 3 그림자 4 가지가 실제 사고로 펼쳐진 라이브 시연 — 무한 루프 / 토큰 폭발 / 도구 남용 / 권한 누수지난 시간 코드 그대로 폭주
✅ Step 4 Harness — 엔진과 차체 의 비유 + 5 요소 (iteration / timeout / scope / budget / observability)
✅ Step 5 판단 워크샵 — 미연시 시나리오 5 종 (메시지 안전 분류 / 캐릭터 자동 생성 / 캐릭터 카드 조회 / 데이트 장소 리서치 / 게임 FAQ) 분류 = Workflow 2 + Agent 2 + 일반 컨트롤러 1
✅ Step 6 지난 시간에 만든 우리 도구 3 종 분류대 — Tool Calling 3 + Day 14 가드 후보 1 (saveGameState)
✅ Step 7 Agentic Patterns 미리보기 — Workflow 3 (Prompt Chaining · Routing · Parallelization) + Agent 2 (Orchestrator-Workers · Evaluator-Optimizer) + Spring AI + 평범한 Java 만의 길

일곱 Step 이 한 줄로 흐르면 에이전트의 전체 그림 이 한 번에 잡혀요. 정의 → 스펙트럼 → 폭주 화면 → Harness 5 요소 → 판단 워크샵 → 우리 코드 분류 → 5 패턴 미리보기. 왜 에이전트인지 / 왜 가드가 필요한지 / 왜 분류가 척추인지코드 변경 0 으로 한 도시에 담긴 시간.

지난 시간 Day 11 의 마지막이 "방금 만든 게 에이전트인가?" 였다면, 오늘 마지막은 "학문 / 실무. 어느 정의로 보든 답이 손에 들어왔다."

2. 4 박자 정의 — 한 번 더 챙기기

오늘 정리한 본 강의의 정의 한 줄 을 마무리에서도 한 번 더 챙겨둘게요. 일주일치 척추가 되는 한 줄이라서요.

🎯 본 강의의 에이전트 정의 — 4 박자

에이전트 = 도구 (Tools) + LLM 자율 (Autonomy) + 루프 (Loop) + 가드레일 (Guardrails) — 4 박자가 모두 갖춰진 상태.

4 박자별 현재 위치 도 한 줄씩 정리해 둘게요. 어디까지 채워졌고 어디부터 채울지 의 일주일 지도.

박자 현재 상태 익혔거나 익힐 Day
도구 (Tools) ✅ 완료 Day 11 — WeatherTool / GameStateTool / AffinityTool
LLM 자율 (Autonomy) ✅ 완료 Day 11 — @Tool 한 줄에 LLM 이 알아서 부르는 모습
루프 (Loop) 다음 시간부터 Day 13 — Workflow 의 코드 루프 / Day 14 — Agent 의 자율 루프
가드레일 (Guardrails) 모레부터 Day 14 — maxIterations / 토큰 예산 / 도구 호출 횟수 / 타임아웃 4 부품 손코딩

4 박자 중 두 박자가 채워진 상태 — 그게 지난 시간까지의 모습. 오늘은 비어 있는 두 박자가 필요한지를 이해한 단계. 다음 시간·다다음 시간엔 비어 있는 두 박자가 어떻게 손에 들어오는지를 익힐 단계. 오늘은 "왜" / 다음 시간·다다음 시간엔 "어떻게" — 이 호흡이 일주일을 관통합니다.

3. Day 13 의 문 두드리기 — Workflow 3 패턴 손코딩

자, 오늘의 마지막이자 다음 시간의 첫 글자.

오늘까지 우리는 에이전트의 전체 그림판단의 시점에서 한 도시에 담았어요.

4 박자 정의 / Workflow ↔ Agent 스펙트럼 / 폭주 화면 / Harness 5 요소 / 5 시나리오 분류 / 우리 도구 3 종 분류 / 5 패턴 이름표 까지.

코드 변경 0 이었지만 무게는 묵직했죠.

그런데 Step 7 에서 5 패턴의 이름표만 손에 들었어요.

진짜 코드가 한 줄씩 손에 들어오는 단계 는 다음 시간이에요.

💡 가장 강조하고 싶은 한 줄

"오늘은 5 패턴의 이름표만 손에 들었어요. 다음 시간에 그 이름표 위에 진짜 코드 한 줄씩 얹힙니다. Workflow 계열 3 패턴 (Prompt Chaining · Routing · Parallelization)Spring AI ChatClient + Advisors + 평범한 Java 만으로 손코딩하는 단계."

Day 13 의 결정적인 새 키워드 들을 미리 던져둘게요. 다음 시간에 본격적으로 익힐 것들이니 단어만 미리 한 번.

Day 13 의 결정적인 새 키워드 5 가지

  • Prompt Chaining메시지 안전 분류 → 답장 초안 생성 직렬 단계. 각 단계가 독립적으로 검증 가능.
  • Routing사용자 메시지 한 줄을 분류 → 전문 핸들러로 위임 하는 분기. 지난 시간의 WeatherTool 이 Routing 노드의 하나로 자라남.
  • Parallelization한 입력에 여러 갈래 동시 호출 의 병렬. CompletableFuture.allOf / parallelStream 같은 평범한 Java.
  • ChatClient.AdvisorDay 13 부터 본격 등장. 가드의 선언적 형태 의 시작점. 전 / 후 처리를 ChatClient 호출 흐름에 한 층으로 끼우는 도구.
  • 평범한 Java 만의 길if-else / switch / Stream.parallel() / try-catch 만으로 외부 그래프 DSL 한 줄도 안 쓰고 5 패턴이 다 들어옴.

오늘은 "왜" — 다음 시간엔 "어떻게". 이 호흡으로 한 발 옮겨갑니다. *4 박자 중 비어 있던 루프 박자가 다음 시간 Workflow 의 코드 루프 에서 처음 손에 들어와요. 가드레일 박자는 모레 Day 14 — 한 단계 더 깊은 곳.

튜터의 결론

오늘 정리한 4 박자 정의 / Workflow ↔ Agent 스펙트럼 / Harness 5 요소 / 시나리오 + 도구 분류 능력코드는 0 인데 무게는 묵직했죠. 이게 에이전트 시리즈 (Day 12 ~ 14, 19) 의 척추. 일주일치 척추가 오늘 한 도시에 담겼어요. 다음 시간부터 그 척추 위에 살이 한 층씩 붙습니다. Day 13 — Workflow 3 패턴 손코딩 / Day 14 — Agent 2 패턴 + 가드 4 부품 손코딩 / Day 19 — Spring AI Agent Client 위에서 손코딩이 선언적으로 짧아지는 단계. 오늘 익힌 분류 능력이 일주일 동안 모든 코드의 의미를 잡아주는 자 가 됩니다.


🎯 Mission — 오늘의 과제

오늘 정리한 학문 vs 실무 두 줄의 답 / 4 박자 정의 / Workflow ↔ Agent 스펙트럼 / Harness 5 요소 / 폭주 4 가지 / 5 패턴 이름표내 손과 내 머리로 한 번 더 굴려보는 단계예요.

Day 12 는 코드보다 머리가 무거운 Day 였어요.

그래서 과제도 코드 양은 가볍게 / 판단의 무게는 단단하게. 손코딩은 마지막 하나만 맛보기로.

세 과제는 사다리 로 짜여 있어요.

  • 분류 워크북 (Step 5/6 패턴 회수) → ⭐ 설계 도면 (Step 6/7 위에서 Day 13~14 미리 그려보기) → ⭐ 코드 맛보기 (Day 14 가드 4 부품 중 하나만 미리 짜기).* 한 갈래씩 쌓이면서 판단 → 설계 → 손코딩 의 호흡.

Day 11 의 "세 번 익혀야 진짜 손" 의 흐름이 Day 12 에선 "세 단계의 무게" 로 이어집니다.

[구현 1] * Workflow vs Agent 결정 사례 모음 — 본인 시나리오 3 ~ 5 건 분류 워크북 ⭐ 30~60 분*

배경 시나리오

ai-friends 의 PM 이 가장 가벼운 일 한 가지를 들고 왔어요.

"튜터님, Step 5 의 5 시나리오 분류 워크샵 — 강사가 풀어준 예시는 단단했는데, 학생 본인 머릿속의 시나리오로는 안 굴러본 단계예요. 학생 본인의 실무 경험 / 사이드 프로젝트 / 가상 기획안 에서 시나리오 3 ~ 5 건을 들고 와서, 각각이 Workflow / Agent / 일반 컨트롤러 어디에 들어갈지 — Step 5 의 4 축 으로 분류한 워크북 한 장이 필요해요. 분류 근육을 한 번 더 다지는 부분이에요."

Step 5 에서 강사가 5 시나리오를 분류대 위에 올린 흐름을 — 내 머릿속의 시나리오로 한 번 더 굴려보는 부분이에요. 새 코드도, 새 도구도, 새 엔티티도 없어요. 오늘 처음 익힌 분류 기준을 / 내 머리에서 한 번 더 흐르게 하는 단계.

💡 왜 굳이 이 과제를 할까요?

분류 근육을 세 번째로 다지는 단계.

Step 5 (강사 시연) → Step 6 (Day 11 도구 3 종 분류) → 과제 1 (본인 시나리오 분류).

분류 기준이 세 번 반복되는 흐름이에요.

Day 11 의 "세 번 익혀야 진짜 내 손" 의 호흡Day 12 에선 머리에서 굴러요.

본인 시나리오로 한 번 더 굴려야.

면접에서 "이건 Workflow 일까요 Agent 일까요" 가 들어왔을 때 흔들리지 않아요. 2.

본인 도메인으로 사고하기 — Step 5 의 메시지 안전 분류 / 캐릭터 자동 생성 / 캐릭터 카드 조회 / 데이트 장소 리서치 / 게임 FAQ 는 ai-friends 도메인의 예시예요.

본인의 실무 / 사이드 프로젝트 / 기획안 위에서 한 번 굴려보면 — 이 분류 기준이 어떤 도메인에도 통하는지 / 어디서 헷갈리는지 가 손에 들어와요.

분류 기준의 일반화 단계입니다. 3.

4 축의 손맛 — Step 5 의 (1) 입력 공간 한정성 / (2) 결정 분기의 사전 정의 가능성 / (3) 실패 비용 / (4) 도구 호출 횟수 예측 가능성 — 이 4 축이 각 시나리오마다 한 줄씩 적힐 때 — 분류 근거가 손에 들어옵니다.

근거 없이 "Agent 같아요" 가 아니라 — "4 축 중 (1) (4) 가 한정 안 되니까 Agent 쪽" 이라는 근거 있는 분류.

✅ 요구사항

  1. 시나리오 3 ~ 5 건 — 학생 본인 손으로 — 다음 셋 중 하나에서 길어 올리세요.
  • (A) 본인의 실무 경험 — 현재 회사 / 이전 회사 / 인턴 경험에서 "이건 LLM 이 들어가면 어떨까?" 싶은 부분.
  • (B) 본인의 사이드 프로젝트 — 진행 중이거나 기획만 해둔 사이드 프로젝트의 한 기능.
  • (C) 가상 기획안"내가 PM 이라면 이런 기능 만들고 싶다" 의 가상 기능.
  1. 각 시나리오마다 — 5 가지 항목의 표로 정리
  • 시나리오 제목 (한 줄)
  • 입력 / 출력 (한 줄씩)
  • 사용자 흐름 (1 ~ 2 줄)
  • 분류Workflow / Agent / 일반 컨트롤러 셋 중 하나
  • 분류 근거 — 4 축 한 줄씩 (Step 5 의 (1) 입력 공간 / (2) 결정 분기 / (3) 실패 비용 / (4) 도구 호출 횟수 예측)

각 시나리오 끝에 — 우리 팀이라면 어디에 둘지 본인 판단 한 줄"우리 팀의 (Spring Boot / 인력 N 명 / 무료 티어) 상황에선 / Workflow 가 정답" 같은 식.

Step 5 의 디폴트 — Workflow 부터 두고 / 가장 자율적인 단 한 곳만 Agent 의 원칙을 본인 도메인에 한 번 더 굴리는 단계입니다. 4. 마지막에 — 본인 워크북의 패턴 한 줄"3 ~ 5 건 중 / Workflow N 건 / Agent N 건 / 일반 컨트롤러 N 건" 의 카운트와 — "이 비율이 우리 팀의 디폴트와 어떻게 어긋나는지" 의 한 줄 회고. Step 5 의 Workflow 우선 원칙이 본인 도메인에서 정말 통하는지 확인하는 단계입니다.

확인 방법

# 1) 마크다운 문서 한 장 작성
mkdir -p ~/day12-assignment1
$EDITOR ~/day12-assignment1/classification-workbook.md

# 2) PR 의 description 으로 첨부 — 또는
git checkout -b day12-assignment1-classification
mv ~/day12-assignment1/classification-workbook.md ./
git add . && git commit -m "docs: Day 12 assignment 1 - workflow vs agent classification workbook"
git push origin day12-assignment1-classification

산출물은 마크다운 한 장. 코드 변경 없음. 판단 근거가 4 축으로 정리된 모습 — 그게 본 과제의 본질이에요.

💡 힌트

  • Step 5 의 5 시나리오를 옆에 펼쳐둔 채 베끼지 말고 / 본인 도메인으로 옮겨오세요."메시지 안전 분류" 의 모양은 본인 회사의 어떤 분류 기능 과 닮았나요? "데이트 장소 리서치" 의 모양은 본인 사이드 프로젝트의 어떤 자율적 기능 과 닮았나요? Step 5 의 거울 을 본인 도메인에서 찾는 부분입니다.
  • *4 축 중 한 축이라도 애매하면 — 그건 Agent 쪽일 가능성이 큼. Step 5 의 교훈이에요. 결정 분기가 사전에 다 안 그려지면 / 실패 비용이 가벼우면 / 도구 호출 횟수 예측이 안 되면 — 그 셋 중 하나라도 걸리면 Agent 쪽 신호.
  • 분류가 일반 컨트롤러 인 경우도 있어요.결정 분기가 0 이고 / 도구 호출 0 이고 / LLM 자율 0 이면 — 그냥 평범한 Spring 컨트롤러 가 정답. Day 11 ~ 12 의 흐름으로 모든 기능을 @Tool 로 끌어올 필요 없어요. Workflow / Agent 가 아닌 답도 정답.
  • 본인 판단 한 줄우리 팀의 인력 / 예산 / 무료 티어 상황 을 한 번 굴려보세요. 기술적으로 Agent 가 적합 해도 — 우리 팀이 Day 14 의 가드 4 부품을 짤 여유가 없으면 / Workflow + 사용자 확인 게이트 가 정답일 수 있어요. Step 5 의 교훈 — 디폴트는 Workflow.

제약 / 금지

  • Step 5 의 5 시나리오를 그대로 베끼지 마세요 — 본인 도메인의 시나리오로 가져오세요. 메시지 안전 분류 / 캐릭터 자동 생성 / 게임 FAQ 를 그대로 옮기면 — 머리에 안 남아요.
  • 분류 근거를 "감 으로 적기 금지"왠지 Agent 같아요" 는 본 과제의 방향이 아니에요. 4 축 한 줄씩 의 근거가 있어야 합니다.
  • 외부 그래프 DSL / LangGraph / Alibaba Graph 의 패턴으로 사고 금지 — 본 과제는 Spring AI ChatClient + Advisors + 평범한 Java 의 범위에서 사고하는 단계예요. 외부 프레임워크에서 이렇게 풀더라 는 방향은 본 과제 범위가 아님.

[구현 2] ⭐ ai-friends 도구 3 종의 다음 풍경 설계 — Day 13~14 미리 그려보기 ⭐⭐ 60~90 분

배경 시나리오

ai-friends 의 기획 PM 이 한 단계 더 깊은 일 을 들고 왔어요.

"튜터님, Step 7 에서 3+2 패턴 미리보기 를 짚었는데 — 학생들이 다음 시간 (Day 13) / 다다음 시간 (Day 14) 가 어떤 모습일지 의 그림이 안 잡혔을 거예요. Day 11 의 도구 3 종 (WeatherTool / GameStateTool / AffinityTool) 이 — Day 13~14 의 5 패턴 위에서 어느 노드에 들어갈지 — 본인 손으로 설계 도면 한 장 을 그려보는 단계예요. 다음 시간 손코딩할 모습을 / 오늘 머리로 미리 그려보는 흐름. 학습 동기로 이어지는 부분입니다."

Step 6 에서 분류대 위에 올라간 도구 3 종이 — Day 13~14 에서 패턴 노드로 자라는 모습 을 미리 그려보는 단계예요. 다음 시간에 손으로 짤 자리를 / 오늘 머리로 그려두면다음 시간 손코딩의 호흡이 한 박자 가벼워져요.

💡 왜 굳이 이 과제를 할까요?

  1. Day 13~14 학습 동기를 만드는 단계 — Step 7 의 3+2 패턴 미리보기이름표만 있던 카드였어요. 본인 손으로 어디에 어느 도구가 들어갈지 를 그려보면 — 다음 시간 (Day 13) 의 손코딩이 어떤 모습일지 가 머리에 잡혀요. 학습 동기 = 미리 그려본 모습의 무게.

*5 패턴의 손맛 시뮬레이션 — Workflow 3 패턴 (Prompt Chaining / Routing / Parallelization) + Agent 2 패턴 (Orchestrator-Workers / Evaluator-Optimizer) — 이 5 패턴 중 적어도 3 개 의 사용 모습을 우리 도구 3 종으로 그려보면 —

각 패턴이 어떤 모양인지 가 손에 들어와요.

이름표 → 풍경 의 변환. 3.

*가드레일이 들어가야 할 곳의 직관 — Step 4 의 Harness 5 요소 (iteration / timeout / scope / budget / observability) 가 — 각 패턴마다 어느 노드에 들어가야 하는지 의 직관을 그려보면 — Day 14 의 가드 4 부품왜 그 곳에 들어가는지 가 미리 잡혀요.

다다음 시간 (Day 14) 의 가드 영역 미리보기.

✅ 요구사항

  1. 도구 3 종 각각의 5 패턴 위에서의 위치 — 표 또는 다이어그램
  • WeatherTool — 어느 패턴의 어느 노드?
  • GameStateTool — 어느 패턴의 어느 노드?
  • AffinityTool — 어느 패턴의 어느 노드?
  • 한 도구가 여러 패턴에 들어갈 수도 있어요. 본인 판단으로 배치하세요.
  1. 5 패턴 중 적어도 3 개 의 사용 모습 설계 — 다음 5 개 중 적어도 3 개 골라 그려보기.
  • Prompt Chaining메시지 안전 분류 → 답장 초안 → 톤 검수 같은 직렬 흐름
  • Routing질문 종류에 따라 다른 도구로 분기 하는 흐름
  • Parallelization여러 도구를 동시에 호출 하는 흐름
  • Orchestrator-Workers오케스트레이터 LLM 이 작업 분해 → 워커 LLM 들이 병렬 처리 하는 흐름
  • Evaluator-Optimizer생성 LLM 의 결과를 평가 LLM 이 검수 → 재시도 하는 흐름
  1. 각 패턴마다 — 가드레일이 들어가야 할 곳 한 줄씩
  • 어디에 maxIterations (루프 한도) 가 들어갈지?
  • 어디에 토큰 예산 가드가 들어갈지?
  • 어디에 도구 호출 권한 검사가 들어갈지?
  • 셋 중 적어도 하나 를 각 패턴마다 명시.
  1. Day 13~14 에서 — 본인이 손코딩할 때 가장 어려울 부분 한 줄"Evaluator-Optimizer 의 평가 LLM 의 system 프롬프트 / 재시도 루프 종료 조건을 짜는 게 가장 어려울 듯" 같은 식. 학습 동기를 만드는 부분입니다.
  2. 다이어그램 한 장draw.io / Excalidraw / 손그림 사진 / 그림판 — 어떤 도구든 OK. 간단해도 OK / 손그림이어도 OK. 그림이 글보다 한 단계 더 단단히 남는 부분이에요.

확인 방법

# 1) 마크다운 + 다이어그램 한 장
mkdir -p ~/day12-assignment2
$EDITOR ~/day12-assignment2/design-doc.md
# (다이어그램은 같은 폴더에 PNG / SVG / 손그림 사진 등으로 저장)

# 2) PR 의 description 으로 첨부 — 또는
git checkout -b day12-assignment2-design
mv ~/day12-assignment2/* ./docs/day12/
git add . && git commit -m "docs: Day 12 assignment 2 - 3+2 patterns design with ai-friends tools"
git push origin day12-assignment2-design

산출물은 마크다운 + 다이어그램 한 장. 코드 변경 없음. 다음 시간에 손으로 짤 모습 — 그게 본 과제의 본질이에요.

💡 힌트

  • Step 7 의 5 패턴 카드를 옆에 펼쳐둔 채 / 본인 도구 3 종을 패턴 노드로 옮겨붙이세요. WeatherTool 은 — Routing 의 한 분기 / GameStateTool 은 — Prompt Chaining 의 마지막 단계 (부작용 단계는 보통 마지막) / AffinityTool 은 — Parallelization 의 한 갈래 — 이런 식으로요. 정답은 없고 / 본인 판단의 근거만 있으면 OK.
  • 부작용 도구는 Agent 의 자율 위임을 가장 신중하게 가 원칙. Step 6 에서 saveGameState 는 가장 좁은 권한 이었던 메시지를 다시 떠올리세요. Orchestrator-Workers 의 워커 노드에 부작용 도구를 두면 — 가드 영역이 한 단계 더 무거워짐 의 방향.
  • 다이어그램은 간단해도 OK. 박스 + 화살표 + 도구 이름표 — 그 정도면 충분. 완벽한 그림보다 / 본인이 그리면서 한 번 더 머리로 굴리는 흐름 이 더 중요해요.
  • 가드레일의 직관루프가 도는 곳에 maxIterations, 부작용 도구 호출 지점에 권한 검사, 비용이 비싼 곳에 토큰 예산 — 이 세 가지의 매핑이 Step 4 의 Harness 5 요소 와 어떻게 이어지는지 한 번 굴려보세요.

제약 / 금지

  • 외부 그래프 DSL (Alibaba Graph / LangGraph) 의 패턴으로 설계 금지 — 본 과제는 Spring AI ChatClient + Advisors + 평범한 Java 의 범위에서 설계하는 단계예요. 그래프 DSL 의 노드 / 엣지 표기 는 영감 정도로만, 본 도면의 핵심은 ChatClient 호출 사이를 평범한 Java 로 잇는 부분이에요.
  • 5 패턴 모두 그리지 마세요 — 적어도 3 개만. 5 개 모두 그리려고 시간을 다 쓰는 건 본 과제의 방향이 아니에요. 3 개를 단단히 그리는 호흡이 5 개를 흐릿하게 그리는 호흡보다 훨씬 남아요.
  • 새 도구를 만들지 마세요 — 본 과제는 지난 시간에 짠 도구 3 종으로만 그리는 단계예요. 새 도구를 가상으로 추가 하면 — 지난 시간에 짠 도구를 회수하는 의미가 흐려져요.

[구현 3] ⭐ (선택) maxIterations=N 한 줄 가드 박아보기 — Day 14 의 영역 한 자리만 미리 맛보기 ⭐⭐ 60~90 분

배경 시나리오

ai-friends 의 기획 PM 이 코드 한 줄 을 살짝 들고 왔어요.

"튜터님, Step 3 의 폭주 라이브 시연무한 루프 / 토큰 폭발 / 도구 남용 이 강사 손에서 망가졌을 때 — 학생들 표정이 '어 내가 한 번 막아보고 싶다' 였잖아요. Day 14 의 가드 4 부품 까지 가긴 멀어도 — 그 중 가장 작은 하나오늘 본인 손으로 미리 짜보는 단계가 있으면 어떨까요? 도구 호출 횟수 한도만 — 한 줄 가드 의 형태로. Day 14 의 본격 영역 직전의 맛보기."

Step 3 의 폭주를 내 손으로 한 번 막아보는 단계예요.

*단 — Day 14 의 가드 4 부품 (maxIterations / 토큰 예산 / 호출 횟수 / 타임아웃) 모두 짜지 마세요. 본 과제는 그 중 하나만 — 도구 호출 횟수 하나만 짜는 단계예요.

오늘 한 가지 / 모레 네 가지 의 호흡으로 학습 동기를 Day 14 에 남겨둘 시간이에요. ⚠️

💡 왜 굳이 이 과제를 할까요?

  1. 폭주 화면에 손이 한 번 닿는 시간 — Step 3 의 라이브 시연은 눈으로만 본 시간이었어요. 내 손으로 한 줄 가드 를 짜보면 — 왜 그 한 줄이 필요한지 / 한 줄로 막을 수 있는 범위는 어디까지인지 가 손에 들어와요. 눈 → 손 의 변환.

*카운터 + if가장 평범한 Java — 본 과제는 Spring AI 의 고급 기능 을 쓰지 않아요.

카운터 하나 + if 분기 + 예외 던지기가장 평범한 Java 로 짜는 단계예요.

Day 19 의 Spring AI Agent Client 가 선언적으로 처리 하기 전 — 손으로 짠 가드의 무게 를 한 번 느껴두는 단계예요. 3. Day 14 의 가드 4 부품 직전의 호흡 — 이 한 가지를 짜두면 — Day 14 에서 가드 4 부품 (maxIterations / 토큰 예산 / 호출 횟수 / 타임아웃) 이 등장할 때 / 왜 그 4 가지가 한꺼번에 필요한지훨씬 더 단단히 잡혀요. 오늘 한 가지, 다음 시간 네 가지 의 호흡.

✅ 요구사항

ChatClient 호출 한 곳 골라잡기 — Day 11 의 세 ChatClient 빈 (weatherChatClient / gameStateChatClient / affinityChatClient) 중 하나를 고르세요.

읽기 전용 도구 의 빈 (weatherChatClient 또는 affinityChatClient) 이 시연이 가장 깔끔 — 부작용 도구는 카운트가 헷갈릴 수 있어요. 2. 도구 호출 카운터 한 줄 추가

  • 컨트롤러 또는 서비스의 한 곳에 호출 카운터 를 두세요.
  • 카운터 + if 분기가장 평범한 Java 패턴. AtomicInteger 도 OK / 그냥 int 도 OK (단일 요청이니까).
  • 한 요청 안에서 N 회 (예: 5 회) 초과 시 — IllegalStateException 또는 새 ErrorCode TOOL_CALL_LIMIT_EXCEEDED 던지기.

*학생 자기검증 — 5 회 호출까지는 통과 / 6 회째 폭발 — IDE 또는 curl 로 한 요청에 도구를 6 회 호출하도록 유도하는 프롬프트를 던지면 6 회째에 IllegalStateException 이 던져지면서 응답이 5 회까지의 도구 호출이 누적된 채 끊기는 모습을 직접 확인.

(본 강의는 단위 테스트 코드 작성을 본문 범위로 두지 않습니다 — 손으로 한 번 굴려보는 자기검증이면 충분.) 4. ErrorCode 또는 예외 메시지에 현재 카운트 + 한도 명시디버깅을 위해 / "tool call limit exceeded: 6 > 5" 같은 형식. 자가검증의 한 줄.

확인 방법

# 1) 브랜치 분기
cd lectures/spring-ai/lecture-source-code/ai-friends
git status                              # working tree clean 확인
git checkout day12-agent-concepts       # Day 12 박제 자리
git checkout -b day12-assignment3-tool-call-limit

# 2) 카운터 + if 가드 박기 (컨트롤러 또는 서비스)

# 3) 학생 자기검증 — 6 회 호출 유도 프롬프트로 IDE/curl 실행
#    응답이 5 회 누적된 채 IllegalStateException 으로 끊기는지 직접 확인

# 4) 커밋 + push
git add .
git commit -m "feat: add tool call count guard (Day 12 assignment 3)"
git push origin day12-assignment3-tool-call-limit

💡 힌트

  • 카운터의 범위 — 단일 요청 vs 글로벌. 한 요청 안에서만 카운트 하면 — int 또는 메서드 로컬 변수면 충분. 글로벌 (앱 전체) 카운트 는 한 단계 무거워지는 영역 — 본 과제는 단일 요청 카운트 가 디폴트예요.
  • *카운트의 증가 지점 — ToolCallback 의 call() 메서드 안 / Spring AI 1.1.x 의 ToolCallingChatOptions 위치 / 또는 수동으로 ChatClient 호출 후 응답에 도구 호출 흔적이 있으면 카운트 — 셋 중 가장 단순한 곳으로. 복잡한 구성은 Day 14 의 영역 이라 — 본 과제는 가장 평범한 Java 의 범위로 가세요.
  • 새 ErrorCode 추가 vs IllegalStateException 그대로 던지기 — 학습 단계에선 둘 다 OK. ai-friends 의 기존 ErrorCode 패턴을 따라가면 현업 톤 이 한 단계 더 진해지지만 본 과제는 한 줄 가드의 감각 이 본질이니 어느 쪽이든 통과.

제약 / 금지

  • maxIterations / 토큰 예산 / 타임아웃 가드 짜지 마세요 — 그건 Day 14 의 영역이에요. 본 과제는 도구 호출 횟수 하나만.
  • Day 14 의 가드 4 부품 미리 짜지 마세요모레 들어올 부분을 미리 짜면 — 모레의 학습 동기가 흐려져요. 본 과제는 맛보기 하나만 짜는 단계예요.
  • 기존 도구 (WeatherTool · GameStateTool · AffinityTool) 의 코드 한 줄 수정 금지 — 가드는 ChatClient 호출 위치 또는 컨트롤러 쪽 에 넣는 거예요. 도구 자체에 넣는 방향은 본 과제의 범위가 아님.
  • ChatModel 직접 호출 금지ChatClient.Builder 위에서만 (ChatModel 인터페이스 주입 원칙).
  • InMemoryChatMemoryRepository 사용 금지 (Day 5 이후 영속 저장 원칙 — 본 과제는 ChatMemory 영역은 아니지만 회귀 차단용 확인).
  • API 키 하드코딩 금지GEMINI_API_KEY 등 모든 키는 .env + 환경변수로.

💭 생각해볼 주제

💭 이 섹션의 목적 — 정답이 정해져 있지 않은 질문들이에요. 오늘 다룬 4 박자 정의 / Workflow ↔ Agent 스펙트럼 / Harness 5 요소 / 5 패턴 매핑 의 결정들을 한 발 떨어져 바라보고, "왜 이렇게 결정했지?""다른 길은 없었나?" 를 사고하는 시간이에요. 면접에서도 자주 등장하는 토픽들이라, 가능하면 문장으로 적어보세요. 머릿속 생각과 글로 적은 생각은 다릅니다.

주제 1 — Workflow 만으로 충분한 서비스에서 순수 Agent (ChatGPT) 가 성공한 이유는?

오늘 Step 2 에서 한 줄이 단단히 정리됐어요.

"Workflow 로 충분하면 Workflow 로 둬라." Anthropic 의 Building Effective Agents 가 제시한 이 한 줄은.

2025 ~ 2026 업계 표준 톤 이에요.

결정론적 / 예측 가능 / 디버깅 쉬움 / 비용·지연 낮음.

Workflow 의 네 가지 이점이 너무 분명해서, 되도록 Workflow 로 둬라 가 정설로 자리잡았죠.

그런데.

시장의 다른 한 줄 이 동시에 존재해요.

같은 시기 (2024 ~ 2026) 에 시장에서 압도적으로 성공한 LLM 제품은.

ChatGPT / Claude.ai / Perplexity.

모두 순수 Agent 모양을 가졌어요.

사용자가 자연어 한 줄을 던지면.

어느 도구를 부를지 / 몇 번 부를지 / 언제 멈출지 까지 LLM 이 자율적으로 결정하는 흐름.

비용도 더 들고 / 지연도 더 길고 / 결과도 덜 예측 가능 한데도.

사용자가 그쪽을 더 선호 한다는 점.

우리가 Step 2 에서 "Workflow 가 정답" 이라고 정리한 결과와 시장의 답 이 정반대인 모순이 보여요.

이 매듭이 우리 ai-friends 에도 그대로 등장해요.

메시지 안전 분류 같은 기능은.

Workflow 가 정답.

캐릭터와의 자유 대화 같은 기능은.

Agent 의 자율성이 사용자의 신뢰를 사는 영역.

그러면.

어떤 기능은 기술적 정합성을 양보하고서라도 Agent 쪽에 두어야 하는가? 그 분기점은 어디서 정해지나? 사용자 체감 / 신뢰 / 자율성의 가치.

이 세 축이 기술 효율의 축 과 부딪히는 지점이에요.

🎯 핵심 질문우리가 서비스를 짤 때, 같은 기능에 대해 Workflow 로 짠 쪽 이 순수 Agent 로 짠 쪽 보다 압도적으로 비용·예측 가능성·디버깅에서 우위인데, 왜 사용자는 ChatGPT 같은 자율 Agent 를 더 선호하는가? 우리 ai-friends 에 — 어떤 기능은 기술적 정합성을 양보하고서라도 Agent 쪽에 두어야 하는가? 그리고 그 기술 효율 양보의 한계선 은 어디인가?

생각해볼 자료:

  • Step 2 의 Anthropic — "Workflow 로 충분하면 Workflow 로 둬라" 한 줄 — 업계 표준 톤의 출처.
  • ChatGPT / Claude.ai / Perplexity 의 사용자 체감 — 비용·지연을 감수하고도 자율성이 사용자 신뢰를 사는 사례.
  • Anthropic 글의 한 줄 vs 시장의 다른 한 줄기술 정합성과 사용자 체감이 정반대로 흐르는 매듭.
  • 우리 ai-friends 의 어떤 기능이 기술 효율 양보하고도 Agent 쪽 으로 갈지의 분기 — 메시지 안전 분류 (Workflow) vs 캐릭터 자유 대화 (Agent) 의 분기점.
  • Step 5 의 5 시나리오 분류 워크샵 — 메시지 안전 분류 / 캐릭터 자동 생성 / 캐릭터 카드 조회 / 데이트 장소 리서치 / 게임 FAQ 중 Agent 쪽에 놓인 시나리오 가 왜 그렇게 분류됐는지 다시 굴려보기.

주제 2 — 에이전트 폭주의 책임은 LLM 인가, 도구 설계자인가?

오늘 Step 3 의 라이브 시연.

가장 강하게 남은 장면이었어요.

우리가 Day 11 에 만든 도구 3 종이 실제로 폭주 하는 모습이었죠. 30 초 컷 무한 루프 / 같은 도구 수십 번 호출 / 토큰 예산 폭발의 청구서.

우리 손으로 짠 ChatClient 코드는 한 글자도 안 건드리고 사용자 질문 한 줄만 비틀어 던졌더니, 지난 시간의 도구가 그대로 망가지는 화면.

그 화면 앞에서 한 질문이 자연스럽게 따라옵니다.

"이 폭주의 책임은.

누구에게 있는가?"

이 질문에 답하려면 최소 세 주체 의 책임이 마주봐야 해요.

(1) LLM 모델 제공자.

OpenAI / Anthropic / Google 같은 모델 회사.

LLM 이 무한 반복하지 않도록 학습된 모델인지 / Constitutional AI 같은 안전 학습이 충분한지 가 핵심.

(2) 도구 설계자 (= 우리 백엔드 팀).

멈춤 장치를 안 둔 도구 자체의 결함.

Step 3 에서 폭주한 사고의 직접 원인은 Day 11 의 우리 도구 3 종 어디에도 가드가 없었던 것 이었어요.

(3) 운영 주체 (= 우리 회사의 거버넌스 / 코드 리뷰 / 모니터링).

가드 누락이 머지되도록 둔 코드 리뷰의 책임 / 토큰 청구서가 폭발하기 전에 알람이 울리지 않은 모니터링의 책임.

세 주체의 무게가 어떻게 분배되느냐에 따라 2026 년 LLM 시대의 코드 리뷰 컬쳐 도 다르게 자리잡아요.

LLM 모델 쪽에 무게를 두면.

우리는 그저 모델이 똑똑해지길 기다리는 모양.

도구 설계자 쪽에 무게를 두면.

모든 @Tool PR 에 가드 체크리스트가 들어가고, 가드 누락 코드는 자동 머지 금지 의 방향.

운영 쪽에 무게를 두면.

토큰 예산 모니터링 / 폭주 감지 알람 / SRE 의 새 책임 영역 이 생기는 흐름.

세 갈래가 동시에 작동 하는 게 정석이지만.

우리 회사의 1 순위는 어디에 둘 것 인가? 그리고 2026 년 EU AI Act / 미국 NIST AI RMF 같은 거버넌스 프레임은.

이 세 주체 중 어느 쪽에 무게를 두고 있는가?

🎯 핵심 질문우리 서비스에서 LLM 이 도구를 남용해 사용자에게 잘못된 결과를 던졌을 때, 책임의 무게는 어디에 있어야 하나? LLM 모델 제공자 (OpenAI / Anthropic / Google) 인가, 도구를 등록한 우리 백엔드 팀 인가, 그 위에 가드를 안 둔 운영 주체 인가? 그리고 — 2026 년 LLM 시대의 코드 리뷰 컬쳐 는 — 도구 쪽 에 어떤 새 게이트 (예: 가드 누락 코드는 머지 금지 / @Tool 에는 무조건 호출 횟수 한도 명시) 를 둬야 하나?

생각해볼 자료:

  • Step 3 의 라이브 시연 — 우리 손으로 짠 ChatClient 코드 한 글자도 안 건드리고 사용자 질문 한 줄로 폭주가 일어난 사례.
  • Anthropic 의 Constitutional AI 방향 — LLM 자체의 안전 학습 이 어디까지 책임을 분담할 수 있는지의 질문.
  • 2026 년 EU AI Act / 미국 NIST AI RMF고위험 AI 시스템의 책임을 모델 제공자 / 배포자 / 운영자에게 어떻게 분배하는지 의 거버넌스 프레임. (EU AI Act 의 고위험 시스템 조항은 2026 년 8 월 2 일 발효 예정 — 단 2026 년 5 월 7 일 EU 의회·이사회 정치적 합의로 일부 조항이 16 개월·12 개월 연기 협의 진행 중. 정식 채택 대기 단계.)
  • Day 11 Step 5 의 그림자 4 가지지난 시간에 가늘게 비쳤던 그림자가 오늘 실제 사고가 된 흐름, 그리고 Day 14 에 손으로 가드를 짜는 단계 까지 이어지는 책임의 흐름.
  • 우리 회사의 코드 리뷰 컬쳐@Tool PR 에 가드 체크리스트가 들어갈 구체적 게이트 설계.

주제 3 — Tool Calling (Day 11) vs MCP (Day 17) — 아키텍처 관점의 차이는?

오늘 Step 1 ~ Step 6 까지.

도구 라는 단어가 수십 번 등장했어요.

그런데.

Day 11 의 @ToolDay 17 미리보기의 MCP Client 가 둘 다 도구 의 가족인데.

학생 입장에선 둘 다 도구 인데.

아키텍처 관점에선 한 단계 다른 가족 이에요.

Day 11 의 Tool Calling우리 앱 내부의 Java 메서드 등록.

@Tool 한 줄에 LLM 이 알아서 부르는 구조, 프로세스 경계 안 의 영역.

Day 17 의 MCP Client외부 MCP 서버의 도구를 우리 앱이 소비.

네트워크 너머 / 다른 팀이 만든 서버의 도구를 우리 LLM 이 부르는 모양, 프로세스 경계 밖 의 영역.

이 갈래가 정리되면.

같은 기능을 어느 가족으로 둘지 의 분기 기준이 자연스럽게 잡혀요.

우리 ai-friends 의 호감도 조회 (AffinityTool).

Tool Calling 으로 둘까, MCP 서버로 노출할까? 답은.

5 축의 흐름 으로 풀려요.

(1) 네트워크 경계.

같은 프로세스면 Tool Calling, 다른 프로세스면 MCP.

(2) 신뢰도.

우리 팀 코드면 Tool Calling, 외부 팀 코드면 MCP 의 인증 게이트가 필요.

(3) 보안 모델.

우리 앱의 인증 컨텍스트를 그대로 쓰면 Tool Calling, 새 인증이 필요하면 MCP.

(4) 응답 지연.

Tool Calling 은 메서드 호출 (~ms), MCP 는 네트워크 호출 (~50ms ~ 수 초).

(5) 다른 팀의 재사용 가능성.

우리 팀만 쓰면 Tool Calling, 다른 팀도 쓰면 MCP 서버로 노출.

그러면.

우리 팀의 1 순위 기준 은 어디일까요? 네트워크 경계 (1) 가 정석 같지만.

같은 프로세스에서도 (5) 다른 팀의 재사용 가치가 크면 MCP 서버로 두는 선택도 있어요 (= 같은 도구를 Tool Calling 으로도, MCP 로도 둘 다 노출하는 흐름).

그런데.

둘 다로 노출 하면 유지보수의 그림자 가 따라와요.

시그니처 두 벌 / 가드 두 벌 / 버전 두 벌.

2026 년 Anthropic MCP 표준이 업계에 자리잡은 흐름 (OpenAI 도 MCP 채택, Google ADK 도 MCP 호환) 을 보면.

언젠가는 Tool Calling 이 MCP 의 로컬 케이스 로 흡수될지도 모르는 가능성까지 보입니다.

🎯 핵심 질문우리 ai-friends 의 도구를 Tool Calling 으로 둘지 와 MCP 서버로 노출할지 의 분기 기준은? 네트워크 경계 / 신뢰도 / 보안 모델 / 응답 지연 / 다른 팀의 재사용 가능성 5 축 중 — 우리 팀의 1 순위 기준은? 그리고 — 같은 도구를 둘 다로 노출 하면 어떤 트레이드오프가 생기는가? 2026 년 MCP 표준이 업계에 자리잡은 흐름 위에서 — Tool Calling 의 미래는 어떻게 흘러갈 것인가?

생각해볼 자료:

  • Day 11 의 @Tool 등록 — 우리 앱 내부 Java 메서드, 프로세스 경계 안 의 가족.
  • Day 17 미리보기 — MCP Client — 외부 MCP 서버의 도구를 우리 앱이 소비하는 가족, 프로세스 경계 밖 의 영역.
  • Day 18 미리보기 — MCP Server — 우리 앱의 기능을 MCP 서버로 노출하는 흐름 (Claude Desktop · Cursor 등 외부 클라이언트가 호출하는 입장).
  • 2026 년 Anthropic MCP 표준이 업계에 자리잡은 흐름 — OpenAI 의 MCP 채택, Google ADK 의 MCP 호환, 표준이 자리잡은 모습.
  • 네트워크 호출 = +50ms ~ 수 초 지연 + 인증·보안 게이트 의 무게 — 같은 도구를 둘 다로 노출 했을 때의 트레이드오프 매트릭스.
✅ 예시 답안정답 보기

본 답안은 교안의 Mission 섹션 에 있는 3 개 과제 + 3 개 생각해볼 주제권장 풀이 입니다. 정답이 하나만 있는 건 아니에요. 본인이 풀어본 결과와 비교하면서 왜 이 결정으로 갔는가 의 근거를 살펴보세요.

Day 12 답안의 세 줄 정신 — (1) Step 5 의 4 축을 내 도메인의 시나리오 위에서 한 번 더 굴려보는 흐름 (과제 1), (2) Step 7 의 5 패턴 카드 위에 우리 도구 3 종을 노드로 매핑한 도면 (과제 2), (3) Step 3 의 폭주 화면에 내 손이 한 번 닿는 카운터 하나 (과제 3). Day 12 의 호흡 — 코드 적게, 머리 무겁게 가 답안에도 그대로 이어집니다.

과제 1 / 2 의 답안은 마크다운 산출물의 모범 예시 — 학생 본인의 도메인으로 옮길 때 베끼기보다 거울로 받으세요. 과제 3 의 코드는 현재 코드베이스에 들어 있지 않은 예시 구현 — Day 11 의 ChatClient 빈 위에서 카운터 + if 하나만 추가하는 형태의 가이드입니다. 그대로 복붙보다 손으로 한 번 더 짜보는 게 학습 의미가 있어요.


📝 과제 예시답안

과제 1 예시답안 — Workflow vs Agent 결정 사례 모음 — 본인 시나리오 분류 워크북

핵심 접근

본 과제의 본질은 시나리오의 다양성 이 아니라 "Step 5 의 4 축 (입력 공간 한정성 / 결정 분기 사전 정의 가능성 / 실패 비용 / 도구 호출 횟수 예측 가능성) 이 내 도메인의 시나리오 위에서 한 줄씩 흐르는지" 를 확인하는 거예요.

본 답안은 학생 본인이 베낄 게 아니라 / 거울로 받을 것 — 가상 회사 FoodyMate (배달 앱 사이드 프로젝트) 위에서 4 시나리오를 분류한 모범 워크북을 한 장 펼쳐둘게요.

본인은 이 방식을 따라 본인 도메인의 3 ~ 5 개 시나리오 를 분류하면 OK.

예시 구현 (모범 워크북 한 장)

# FoodyMate 분류 워크북 — Workflow vs Agent vs 일반 컨트롤러

> **컨텍스트** — 가상의 배달 앱 *FoodyMate* (사이드 프로젝트). 인력 2명 / Spring Boot / Gemini 무료 티어.
> Step 5 의 4 축으로 4 시나리오를 분류한다. 우리 팀의 디폴트는 *Workflow 우선*.

---

## 시나리오 1 — *고객 리뷰 자동 분류 (긍정 / 부정 / 욕설)*

- **입력 / 출력** — 리뷰 텍스트 1 건 / 분류 라벨 1 개
- **사용자 흐름** — 사용자가 리뷰 작성 → 백엔드가 LLM 호출 → 라벨링 → DB 저장
- **분류** — **Workflow** (Routing 패턴의 진입점)
- **분류 근거 (Step 5 의 4 축)**
  - (1) 입력 공간 한정성 — *리뷰 텍스트 1 건 — 짧고 한정적*. ✅ Workflow.
  - (2) 결정 분기 사전 정의 가능성 — *3 개 라벨로 사전에 다 그려짐*. ✅ Workflow.
  - (3) 실패 비용 — *오라벨링은 가벼움 — 사람이 정정 가능*. ✅ Workflow.
  - (4) 도구 호출 횟수 예측 — *LLM 1 회 호출로 끝, 도구 호출 0*. ✅ Workflow.
- **우리 팀 판단** — *2 명 인력 / Gemini 무료 티어 / 디버깅 쉬워야 함* — Workflow 가 정답. Agent 는 과해요.

---

## 시나리오 2 — *광고 카피 자동 작성 (광고주 브리프 → 3 안 제안)*

- **입력 / 출력** — 광고주 브리프 (자연어 1 ~ 2 문단) / 카피 3 안
- **사용자 흐름** — 광고주가 브리프 입력 → LLM 이 톤·타깃·메시지 자율 결정 → 3 안 제안 → 광고주 선택
- **분류** — **Agent** (Orchestrator-Workers 계열)
- **분류 근거**
  - (1) 입력 공간 — *자연어 자유 형식 — 모호함이 큼*. ⚠️ Agent 신호.
  - (2) 결정 분기 — *어떤 톤? 어떤 후크? 어떤 CTA? — 사전에 안 그려짐*. ⚠️ Agent 신호.
  - (3) 실패 비용 — *카피 마음에 안 들면 광고주가 재요청 — 가벼움*. ✅ Agent 가능.
  - (4) 도구 호출 횟수 — *경쟁사 검색 / 트렌드 조회 / 광고 가이드 조회 — 몇 회 부를지 모름*. ⚠️ Agent 신호.
- **우리 팀 판단** — *Agent 영역이지만 / Day 14 의 가드 4 부품 (반복 한도 / 토큰 예산 / 호출 횟수 / 타임아웃) 이 들어와야 안전*.
  현재 우리 팀은 가드 인력이 부족 → *MVP 1 단계는 "Workflow + 사용자 가이드된 폼"* 으로 가고, 트래픽 확정되면 Agent 로 승격.

---

## 시나리오 3 — *주문 내역 본인 조회 (REST API)*

- **입력 / 출력** — 사용자 ID + 기간 / 주문 리스트 JSON
- **사용자 흐름** — 사용자가 마이페이지 진입 → 주문 내역 조회
- **분류** — **일반 컨트롤러** (LLM 영역 아님)
- **분류 근거**
  - (1) 입력 공간 — *user_id + 기간 — 정형*. ✅ 일반 컨트롤러.
  - (2) 결정 분기 — *분기 0 — DB 쿼리 한 줄*. ✅ 일반 컨트롤러.
  - (3) 실패 비용 — *오류 시 명확한 에러 응답*. ✅ 일반 컨트롤러.
  - (4) 도구 호출 횟수 — *DB 쿼리 1 회 — LLM 영역 아님*. ✅ 일반 컨트롤러.
- **우리 팀 판단** — *Day 11~12 의 흐름대로 모든 기능을 `@Tool` 로 끌어올 필요 없음.* 그냥 평범한 Spring 컨트롤러 + JPA 가 정답.

---

## 시나리오 4 — *식당 추천 — 사용자 자연어 질문 ("매운 거 먹고 싶은데 5만원 이내")*

- **입력 / 출력** — 자연어 질문 / 식당 후보 3 ~ 5 개
- **사용자 흐름** — 자연어 질문 → LLM 이 의도 파싱 → 가게 검색 도구 호출 → 가격·평점 도구 호출 → 정렬 → 답변
- **분류** — **Agent** (Routing + Parallelization 결합)
- **분류 근거**
  - (1) 입력 공간 — *자연어 — 모호함 큼*. ⚠️ Agent 신호.
  - (2) 결정 분기 — *어떤 필터를 쓸지 / 몇 개 도구를 부를지 사전에 안 그려짐*. ⚠️ Agent 신호.
  - (3) 실패 비용 — *추천 잘못해도 사용자가 재질문 가능 — 가벼움*. ✅ Agent 가능.
  - (4) 도구 호출 횟수 — *2 ~ 5 회 사이 — 예측 어려움*. ⚠️ Agent 신호.
- **우리 팀 판단** — Agent. 단 *Day 14 의 가드 (호출 횟수 5 회 / 타임아웃 10 초)* 박힌 다음에 배포.

---

## 워크북 패턴 회고

- **카운트** — Workflow 1 건 / Agent 2 건 / 일반 컨트롤러 1 건.
- **우리 팀 디폴트와의 어긋남** — Step 5 의 *Workflow 우선* 디폴트와 비교하면 — *Agent 비율이 50% 로 약간 높음*. 이유는 *FoodyMate 가 자연어 인터페이스를 강조하는 도메인* 이기 때문. *기술적으로 Agent* 인 게 많지만 — *우리 팀 인력 (2 명) 과 가드 부재* 를 고려하면 *MVP 1 단계는 Workflow 로 시작 / 트래픽·매출 확정 후 Agent 승격* 이 현실적이에요.

채점 포인트

포인트 설명 배점 가중
본인 도메인의 시나리오 3 ~ 5 건 Step 5 의 5 시나리오를 그대로 베끼지 않고 본인 실무·사이드·기획안의 맥락으로 옮겨왔는가
4 축 한 줄씩 근거 입력 공간 / 결정 분기 / 실패 비용 / 도구 호출 횟수 — 4 축 모두 가 한 줄씩 적혀 있는가
Workflow / Agent / 일반 컨트롤러 셋의 분포 모든 시나리오를 Agent 로 또는 모든 시나리오를 Workflow 로 가 아니라 — 3 가지 카테고리가 적절히 분포 되는가
우리 팀 판단 한 줄 기술적 분류와 별개로 우리 팀의 인력·예산·무료 티어 를 반영한 본인 판단이 적혀 있는가
워크북 패턴 회고 Workflow N / Agent N / 일반 컨트롤러 N 의 카운트 + 디폴트와의 어긋남 한 줄 이 적혀 있는가
용어 일관성 "에이전트" 단어가 모든 ChatClient 호출 에 남발되지 않고 — Workflow / Agent / 일반 컨트롤러 셋이 단어 단위로 구분되는가

흔한 실수

  • 모든 시나리오를 Agent 로 분류"LLM 이 들어가니까 Agent" 는 본 과제의 답이 아니에요. 결정 분기가 사전에 다 그려지면 Workflow / 자율 결정이 핵심이면 Agent / LLM 자체가 안 들어가면 일반 컨트롤러.
  • 4 축 중 한두 축만 적기"입력이 자연어니까 Agent" 한 축만으로 결론 내면 — 분류 근거의 무게가 가벼워져요. 4 축 모두 한 줄씩 이 본 과제의 호흡.
  • Step 5 의 시나리오 그대로 베끼기메시지 안전 분류 / 캐릭터 자동 생성 / 게임 FAQ 를 그대로 옮기면 — 본인 도메인으로 굴려보는 의미 가 흐려져요.
  • 우리 팀 판단 누락 — 기술적 분류만 적고 우리 팀의 현실 (인력 / 예산 / 무료 티어) 을 반영한 판단이 없으면 — Step 5 의 디폴트 (Workflow 우선) 가 어떻게 회수되는지 가 안 보여요.
  • 외부 그래프 DSL 의 방향으로 사고LangGraph / Alibaba Graph 의 노드 표기 로 분류하면 — 본 강의의 방향이 아니에요.

실무 개선 포인트 (심화)

  • 4 축에 5 번째 축 으로 데이터 프라이버시 추가 — 본 강의의 4 축 외에 — 실무에선 (5) 데이터 프라이버시 / PII 노출 위험도 가 한 축 더 들어와요. 의료·금융 도메인에선 — 기술적으로 Agent 영역 이라도 PII 가 LLM 으로 흘러가는 위험 이 크면 Workflow + 사람 검수 게이트 로 두는 방향이 정석. 4 축 워크북을 만들어두면 / 5 번째 축도 자연스럽게 자라요.
  • 분류 결과를 팀 컨벤션 한 장 으로 보존 — 본 워크북의 모범 예시는 내 머리에서 흐르는 사고지만 — 팀 단위에선 / 한 장의 컨벤션으로 정리해 / 새 기능 기획 단계에서 한 번 펼쳐 보는 방향이 이상적이에요. Notion / Confluence 한 장의 분류 가이드라인 을 만들면 — 팀원이 "이거 Agent 아니야?" 라고 묻지 않고 / 4 축으로 자가 분류한 후 PR 에 첨부 하는 흐름으로 자라요. Day 12 의 사고를 팀화.

과제 2 예시답안 — ai-friends 도구 3 종의 다음 단계 설계 — Day 13~14 미리 그려보기 (⭐)

핵심 접근

본 과제의 본질은 5 패턴 모두를 완벽히 그리는 게 아니라 "Step 7 의 5 패턴 카드 위에서 — 우리 도구 3 종이 어느 노드에 들어갈지의 결정 근거가 한 줄씩 적혀 있는지" 를 확인하는 거예요.

본 답안은 3 ~ 4 패턴 만 단단히 그리고 — 각 패턴마다 가드레일 한 줄 이 명시된 모범 도면을 한 장 펼쳐둘게요.

Day 13~14 의 학습 동기를 만드는 단계예요.

예시 구현 (모범 설계 도면 한 장)

# Day 13~14 미리보기 — ai-friends 도구 3 종의 5 패턴 위 매핑

> **목표** — Day 11 의 도구 3 종 (`WeatherTool` / `GameStateTool` / `AffinityTool`) 을
> Step 7 의 3+2 패턴 위에 *노드로* 매핑한다. *다음 시간에 손으로 짤 곳을 / 오늘 머리로 그린다*.

---

## 도구 3 종 × 5 패턴 매핑 표

| 도구 \ 패턴 | Prompt Chaining | Routing | Parallelization | Orchestrator-Workers | Evaluator-Optimizer |
|-----------|---------------|---------|----------------|---------------------|---------------------|
| `WeatherTool` (읽기) | 후처리 노드 (날씨 → 옷차림 추천) | **진입 분기 노드** | **병렬 호출 노드** | 워커 | (X — 평가 대상 아님) |
| `GameStateTool.save` (부작용) | (X — 부작용은 마지막 단계로) | 분기 후 액션 노드 | (X — 부작용 병렬 위험) | **워커 + 가드 필수** | (X — 부작용은 평가 안 함) |
| `GameStateTool.load` (읽기) | 직렬 1 단계 (load → 답변) | 분기 노드 | 병렬 노드 | 워커 | 평가 입력 |
| `AffinityTool` (읽기) | 직렬 1 단계 (affinity → 톤 결정) | 분기 노드 | 병렬 노드 | **워커** | 평가 입력 |

> **표 읽는 법** — *(X)* 는 *부적합한 위치* / **굵은 글씨** 는 *Day 13~14 에서 손코딩으로 다룰 가능성이 높은 위치*.
> *부작용 도구 (`GameStateTool.save`) 는 — 패턴 대부분의 노드에 두기 어렵다*. Step 6 의 그림자.

---

## 패턴 3 가지의 흐름 설계

### 1. Routing — *날씨 / 호감도 / 게임상태 분기*

```text
[사용자 발화]
 ↓
[Router LLM] — "이 발화는 어느 분기인가?"
 │
 ├─ "오늘 날씨 어때?" ──→ weatherChatClient (WeatherTool)
 ├─ "걔 나 좋아해?" ────→ affinityChatClient (AffinityTool)
 └─ "내 게임 진행" ─────→ gameStateChatClient (GameStateTool.load)
  • 가드 — 🛡️ Router LLM 의 분기 결과가 enum 3 개 중 하나 가 아니면 → 폴백 분기. 결정 분기 사전 정의 = Workflow 의 핵심.

2. Parallelization — 날씨 + 호감도 동시 조회

[사용자 발화 — "걔랑 데이트하기 좋은 날?"]
 ↓
 ┌──────────┬──────────┐
 ↓ ↓ ↓
WeatherTool AffinityTool (병렬)
 │ │
 └────┬─────┘
 ↓
[종합 LLM] — 두 결과를 합쳐 답변
  • 가드 — 🛡️ 병렬 호출 타임아웃 5 초 — 한 도구가 늦으면 나머지 결과만으로 답변. Day 14 의 타임아웃 가드가 자연스럽게 들어오는 자리.
  • 부작용 도구는 절대 병렬에 두지 말 것GameStateTool.save 가 두 번 호출되면 상태 정합성 위험.

3. Orchestrator-Workers — 복잡한 사용자 요청 분해

[사용자 발화 — "오늘 데이트 코스 짜줘"]
 ↓
[Orchestrator LLM] — 작업 분해
 ├─ Worker 1: WeatherTool 로 날씨 조회
 ├─ Worker 2: AffinityTool 로 캐릭터 호감도 조회
 └─ Worker 3: GameStateTool.load 로 진행 상황 조회
 ↓
[종합 LLM] — 세 워커 결과 통합 → 데이트 코스 제안
  • 가드 — 🛡️ Orchestrator 의 분해 깊이 최대 1 단계 — 워커가 또 다른 Orchestrator 를 부르지 못하게 차단. Day 14 의 maxIterations 가드의 직관.
  • 부작용 도구 (GameStateTool.save) 가 워커로 들어가면 — 🛡️ 권한 검사 게이트 한 줄 추가 (사용자 본인의 게임 상태인지 검증).

가장 어려울 부분 — 본인 예측

Evaluator-Optimizer 의 평가 LLM system 프롬프트 + 재시도 종료 조건 짜는 게 가장 어려울 듯해요. "평가 LLM 이 OK 를 줄 때까지 재시도"무한 루프의 가능성 — Day 14 의 maxIterations 가드 없이 두면 폭주. 평가 점수 임계치 (예: 80 점 이상) + 최대 재시도 3 회 의 두 조건이 동시에 들어와야 안전.


가드레일 요약 — Day 14 의 미리보기

  • maxIterations — Orchestrator-Workers 의 분해 깊이 / Evaluator-Optimizer 의 재시도 횟수
  • 타임아웃 — Parallelization 의 병렬 호출 영역
  • 도구 호출 횟수 — 모든 패턴의 진입에 한 줄씩 (과제 3 의 맛보기)
  • 권한 검사 — 부작용 도구 (GameStateTool.save) 가 워커로 들어갈 때

(다이어그램은 `docs/day12/design.png` 등으로 첨부 — 손그림 / Excalidraw 모두 OK.)

#### 채점 포인트

| 포인트 | 설명 | 배점 가중 |
|-------|------|----------|
| 도구 3 종 × 5 패턴 매핑 표 | 표 형식으로 **어느 도구가 어느 패턴의 어느 노드에 들어갈지** 가 한눈에 보이는가 | 상 |
| 적어도 3 개 패턴의 흐름 설계 | 5 개 모두 그리려다 흐려지지 않고 — 3 개 이상이 단단히 그려졌는가 | 상 |
| 각 패턴마다 가드레일 한 줄씩 | `maxIterations` / 토큰 예산 / 도구 호출 권한 검사 중 **적어도 하나** 가 명시되어 있는가 | 상 |
| 부작용 도구 (`GameStateTool.save`) 의 특수성 | **부작용은 병렬 / 평가에 두지 않는다** 가 도면에 반영되었는가 | 중 |
| Day 13~14 학습 동기 표현 | **가장 어려울 부분 한 줄** 본인 예측이 적혀 있는가 | 중 |
| 외부 그래프 DSL 미사용 | **LangGraph / Alibaba Graph 의 노드 표기** 가 아닌 — **Spring AI ChatClient + Advisors + 평범한 Java** 로 그려졌는가 | 중 |

#### 흔한 실수

- **5 패턴 모두 그리려다 시간을 다 씀** — **3 개를 단단히 / 5 개를 흐릿하게** 의 트레이드오프에서 후자를 선택하는 함정. 본 과제는 **깊이 우선**.
- **부작용 도구 (`GameStateTool.save`) 를 Parallelization 에 두기** — **상태 정합성 위험**. 부작용은 병렬·평가에 두지 않는 게 정석.
- **가드레일 누락** — 흐름만 그리고 가드가 없으면 — **Day 14 의 학습 동기** 가 살지 않아요. 각 패턴마다 **적어도 한 줄** 의 가드가 명시되어야 해요.
- **새 도구를 가상으로 추가** — **지난 시간에 짠 도구 3 종으로만** 그려야 — **지난 시간 도구의 회수** 의미가 살아요.
- **외부 DSL 의 표기로 사고** — **그래프 DSL 의 노드/엣지 표기** 는 영감 정도면 OK — 본 도면은 **ChatClient 호출 사이를 평범한 Java 로 잇는** 형태예요.

#### 실무 개선 포인트 (심화)

- **각 패턴 노드의 비용 모델 한 줄 추가** — 본 도면은 **기능** 만 그렸지만 — 실무에선 **각 노드마다 LLM 호출 수 + 토큰 예상 비용** 한 줄이 적혀야 **MVP 가 무료 티어 안에서 도는지** 사전 검증 가능. **Routing 1 회 + Parallelization 2 회 + 종합 1 회 = 4 LLM 호출/요청** 같은 라인을 도면에 적어두면 — **Day 14 의 토큰 예산 가드** 가 **왜 필요한지** 가 도면에서 바로 보여요.
- **도면을 상태 머신 다이어그램 으로 진화** — 본 도면은 **흐름도** 형태지만 — **복잡한 Agent 영역** 에선 **상태 머신 (statechart)** 표기가 더 단단해요. **현재 상태 (사용자 발화 분석 중 / 도구 호출 중 / 종합 중 / 종료)** + **전이 조건 (도구 결과 OK / 타임아웃 / 가드 트리거)** 으로 그리면 — **Day 19 의 Spring AI Agent Client** 가 **내부적으로 어떻게 상태를 관리하는지** 의 직관이 미리 들어와요.

---

</details>

<details>
<summary><strong>과제 3 예시답안 — 도구 호출 횟수 한 줄 가드 짜보기 (선택, ⭐)</strong></summary>


#### 핵심 접근

본 과제의 본질은 **Spring AI 의 고급 기능 정복** 이 아니라 **"Step 3 의 폭주 화면에 내 손이 한 번 닿는 카운터 하나 + `if` 분기 + 예외 던지기"** 의 가장 평범한 Java 코드예요.

**Day 14 의 가드 4 부품** 까지 가지 않고.

**도구 호출 횟수 하나만** 짜는 한 단계.

본 답안은 **`weatherChatClient` 위에 ThreadLocal 카운터** 를 두는 모범 풀이로 한 장 펼쳐둘게요.

#### 예시 구현

##### 1) `ToolCallCounter` — 카운터 한 개

```java
package kr.spartaclub.aifriends.tool.guard;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
 * Day 12 [과제 3] — 도구 호출 횟수 한 줄 가드.
 *
 * <p>한 요청 안에서 도구 호출이 N 회를 초과하면 IllegalStateException 으로 폭발.
 * Day 14 의 가드 4 부품 (maxIterations / 토큰 예산 / 호출 횟수 / 타임아웃) 중
 * *호출 횟수 한 가지* 만 미리 맛보는 단계.</p>
 *
 * <p>ThreadLocal 방식 — 한 HTTP 요청 = 한 스레드 가정. WebFlux 환경에선 Reactor Context 로
 * 옮겨야 하지만, 본 강의 (MVC) 에선 ThreadLocal 이 가장 평범한 선택.</p>
 */
@Component
public class ToolCallCounter {

    private final ThreadLocal<Integer> count = ThreadLocal.withInitial(() -> 0);
    private final int limit;

    public ToolCallCounter(@Value("${ai-friends.tool-call.limit:5}") int limit) {
        this.limit = limit;
    }

    /** 도구 호출 직전에 한 번 호출. 한도 초과 시 IllegalStateException. */
    public void increment() {
        int current = count.get() + 1;
        if (current > limit) {
            throw new IllegalStateException(
                    "tool call limit exceeded: %d > %d".formatted(current, limit));
        }
        count.set(current);
    }

    /** 요청 종료 시 카운터 초기화 — 다음 요청에 누수되지 않도록. */
    public void reset() {
        count.remove();
    }

    public int currentCount() {
        return count.get();
    }
}
2) WeatherTool 호출부에 카운터 두기 — 도구 자체 수정 금지 / 호출부에 두는 방식

⚠️ 교안의 가드 범위 약속 에 따라 도구 자체 가 아닌 ChatClient 호출부 에 둬요. 본 답안은 컨트롤러 에서 카운터를 reset / 도구 호출 직전 increment 하는 방식으로 풀어둘게요. Spring AI 1.1.x 의 ToolCallback 데코레이터 패턴으로도 가능하지만 — 본 과제는 가장 평범한 Java.

package kr.spartaclub.aifriends.tool.weather;

import jakarta.validation.Valid;
import kr.spartaclub.aifriends.common.response.ApiResponse;
import kr.spartaclub.aifriends.tool.guard.ToolCallCounter;
import kr.spartaclub.aifriends.tool.weather.dto.WeatherChatRequest;
import kr.spartaclub.aifriends.tool.weather.dto.WeatherChatResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * Day 12 [과제 3] — Day 11 의 weatherChatClient 위에 카운터 한 줄 박은 컨트롤러.
 *
 * <p>실제 도구 호출 카운트는 — Spring AI 1.1.x 의 ToolCallback 데코레이터로 박는 게 정석이지만,
 * 본 과제는 *가장 평범한 Java* — WeatherTool 의 메서드 안에서 직접 카운터를 부르거나,
 * 또는 ToolCallback 을 감싸는 데코레이터에서 부르는 방식. 본 예시는 후자.</p>
 */
@RestController
@RequestMapping("/api/tool/weather")
@RequiredArgsConstructor
public class WeatherChatController {

    private final ChatClient weatherChatClient;
    private final ToolCallCounter toolCallCounter;

    @PostMapping("/chat")
    public ResponseEntity<ApiResponse<WeatherChatResponse>> chat(
            @Valid @RequestBody WeatherChatRequest request
    ) {
        try {
            String aiMessage = weatherChatClient
                    .prompt()
                    .user(request.userMessage())
                    .call()
                    .content();
            return ResponseEntity.ok(
                    ApiResponse.success(new WeatherChatResponse(aiMessage)));
        } finally {
            // 요청 종료 시 카운터 reset — 다음 요청에 누수되지 않도록
            toolCallCounter.reset();
        }
    }
}
3) WeatherTool 메서드 안에서 카운터 호출 — 호출 직전 한 줄만
// 기존 WeatherTool 의 @Tool 메서드 안에 한 줄만 추가
@Tool(description = "...")
public WeatherInfo getWeather(@ToolParam(description = "지역명") String region) {
    toolCallCounter.increment(); // 🛡️ 한 줄 가드 — 5 회 초과 시 IllegalStateException
    // 기존 stub 분기 그대로
    return ...;
}

💡 ai-friends 의 "기존 도구 코드 한 줄 수정 금지" 약속가드 추가는 예외 로 두고 본 답안에선 한 줄만 추가했어요. 더 정석은 — Spring AI 1.1.x 의 ToolCallback 을 감싸는 데코레이터 빈 으로 두는 방식 (실무 개선 포인트 참고).

4) 학생 자기검증 — 5 회 통과 / 6 회째 폭발 시연

코드를 추가했으면 학생 본인이 한 번 굴려보세요. 단위 테스트 작성은 본 강의의 본문 범위가 아니지만 (Day 12 는 코드 변경 0 의 개념 Day), 학생이 IDE 에서 한 번 굴려보는 자기검증 명령 만 정리해 둡니다. 두 시나리오를 직접 손으로 굴려보세요.

시나리오 입력 기대 결과
5 회 호출까지 통과 ToolCallCounter counter = new ToolCallCounter(5);counter.increment() 를 5 회 호출 예외 없이 통과, counter.currentCount() == 5
6 회째 폭발 위 상태에서 한 번 더 counter.increment() 호출 IllegalStateException — 메시지에 "tool call limit exceeded: 6 > 5" 포함
reset() 후 재카운트 new ToolCallCounter(3)increment() 두 번 → reset()increment() 한 번 currentCount() == 1 (reset 후 0 부터 다시 셈)

AffinityChatControllerchat 메서드에 counter.reset() + counter.increment() 를 한 줄씩 넣은 뒤, curl 로 한 메시지에 날씨 → 호감도 → 날씨 → 호감도 → 게임 → 날씨 6 회 호출을 유도하는 프롬프트를 던져보세요.

  • 6 회째 동작IllegalStateException 이 던져지면서 응답이 5 회까지의 도구 호출만 누적된 채 끊깁니다.
  • Day 12 Step 3 의 30 초 컷 무한 루프5 회 컷 으로 줄어드는 모습 — 가드 한 줄만 있어도 폭주가 컷 된다 가 손에 익어요. 🛑

채점 포인트

포인트 설명 배점 가중
카운터 + if 분기의 평범한 Java 패턴 Spring AI 의 고급 기능이 아닌 — 카운터 + if + 예외 의 가장 평범한 Java 로 짰는가
학생 자기검증 — 5 회 통과 / 6 회째 폭발 시연 IDE 또는 curl 로 6 회 호출 유도 시 IllegalStateException 이 던져지면서 응답이 5 회 누적된 채 끊기는 모습을 직접 확인했는가
한도 초과 메시지에 현재 / 한도 표시 "tool call limit exceeded: 6 > 5" 같은 형식 — 디버깅에 도움
카운터 reset 요청 종료 시 reset 으로 누수 차단 (ThreadLocal 의 정석)
ApiResponse 래핑 새 컨트롤러를 추가했다면 우리 코드베이스의 표준 응답 패턴 (ApiResponse<T>) 으로 감쌌는가
Day 14 영역 침범 금지 maxIterations / 토큰 예산 / 타임아웃 가드는 짜지 않고 — 호출 횟수 하나만 짰는가
ChatModel 인터페이스 / API 키 보안 ChatModel 구현체 직접 주입 금지 / API 키 하드코딩 금지 통과

흔한 실수

  • Day 14 의 가드 4 부품 모두 짜기도구 호출 횟수 하나만 짜는 단계인데 maxIterations / 토큰 예산 / 타임아웃 까지 짜면 — 모레의 학습 동기가 흐려져요.
  • 카운터를 글로벌 (앱 전체) 로 두기static AtomicInteger 로 두면 여러 사용자가 카운트 공유 — 본 과제는 단일 요청 한정 이 정석. ThreadLocal 또는 메서드 로컬.
  • reset 누락 — ThreadLocal 인 채로 reset 안 하면 다음 요청이 같은 스레드 (스레드 풀 재사용) 에 잡힐 때 카운트가 누적 — 디버깅 지옥.
  • 도구 자체 코드 통째로 수정기존 도구 (WeatherTool) 의 stub 분기까지 건드리는 건 본 과제가 아니에요. 가드 한 줄 추가 만.
  • ChatModel 직접 주입ChatClient.Builder 방식을 안 쓰고 ChatModel 구현체로 받으면 인터페이스 주입 원칙 위반.
  • API 키 하드코딩.env + 환경변수가 정석. 답안 코드에 키를 넣지 마세요.

실무 개선 포인트 (심화)

  • ToolCallback 데코레이터로 진화 — 본 답안은 도구 메서드 안에서 카운터 부르는 형태인데 — 실무에선 Spring AI 1.1.x 의 ToolCallback 인터페이스를 감싸는 데코레이터 빈 으로 두는 게 정석이에요. 그러면 모든 도구에 동일한 가드가 자동 적용 / 도구 자체 코드는 한 줄도 안 건드림 의 모양이 자라요. Day 19 의 Spring AI Agent Client 가 — 이 데코레이터 패턴을 선언적으로 처리하는 모습 의 미리보기.
  • OpenTelemetry 메트릭으로 한도 초과 관측6 회째 IllegalStateException 이 던져진 시점 을 — 그냥 로그로 흘려보내지 않고 / OpenTelemetry counter 메트릭으로 남겨두면프로덕션에서 어느 사용자 / 어느 도구 / 어느 시간대 에 폭주가 자주 발생하는지 보여요. Day 20 의 Observability 의 미리보기.

💭 생각해볼 주제 예시답안

주제 1 예시답안 — Workflow 만으로 충분한 서비스에서 순수 Agent (ChatGPT) 가 성공한 이유는?

[문제 상황 요약]

기술적으로는 Workflow 가 비용·예측 가능성·디버깅 모두 우위인데, 시장에서 압도적으로 성공한 LLM 제품 (ChatGPT / Claude.ai / Perplexity) 은 순수 Agent 의 모양이에요.

Anthropic 의 "Workflow 로 충분하면 Workflow 로 둬라" 한 줄과 시장의 답 이 정반대로 흐르는 매듭.

우리 ai-friends 에 어떤 기능은 기술 정합성 양보하고서라도 Agent 로 가야 하는가?

[튜터의 가이드 및 해설]

이 매듭의 핵심은 기술 효율사용자 체감완전히 다른 축 이라는 점.

Anthropic 의 한 줄은 백엔드 엔지니어의 시점예측 가능 / 디버깅 / 비용 / 응답 속도 모두 Workflow 가 우위.

시장의 한 줄은 사용자의 시점자연어 한 줄을 던지면 시스템이 알아서 도와주는 형태의 체감 신뢰기술 효율을 양보해도 살 만한 가치라는 점이에요.

한 발 더 들어가 보면 사용자 신뢰 = 자율성의 가치 라는 등식이 보여요.

Workflow사용자가 시스템의 한계를 미리 알고 예측 가능한 답을 받는 형태.

Agent사용자가 시스템에게 자유를 주고 예상 못 한 답이 와도 그게 마법처럼 느껴지는 형태.

ChatGPT 의 성공은 예측 가능성보다 자율성이 사용자의 신뢰를 더 산다 는 증명이에요.

이 분기점을 우리 ai-friends 에 옮겨오면 두 가지로 갈라져요.

  • Option A — 기능 단위 분기: 메시지 안전 분류 / 게임 FAQ 라우팅 / 캐릭터 카드 조회 같이 결정 분기가 사전에 다 그려지는 기능은 Workflow. 캐릭터와의 자유 대화 / 데이트 장소 자연어 추천 / 캐릭터 자동 생성 같이 자율성이 사용자 체감의 핵심 인 기능은 Agent. 장점: 기술 정합성 + 사용자 체감 둘 다 만족. 단점: 기능 단위로 분기 기준을 매번 판단 해야 함.
  • Option B — MVP 는 Workflow / 트래픽 확정 후 Agent 승격: 모든 기능을 일단 Workflow 로 짜고 사용자 트래픽·매출이 확정된 곳만 Agent 로 승격. 장점: 초기 비용 통제 + Day 14 의 가드 학습 시간 확보. 단점: MVP 의 사용자 체감이 다소 평범.
  • 현업에서는 보통 — Option A 가 정석. 기능마다 4 축 (Step 5) 을 굴려보고 Workflow / Agent 둘 중 하나로 정함.팀 인력 / 가드 인력 / 무료 티어 를 함께 고려해서 Agent 영역이라도 가드 짤 여유 없으면 Workflow + 사용자 가이드된 폼 으로 1 단계는 가는 호흡도 정석.

기술 효율 양보의 한계선은 어디일까요? 두 가지 신호가 있어요.

첫째 — 실패 비용이 가벼운가 (캐릭터 답이 어색해도 사용자가 재질문 가능).

둘째 — 사용자가 자율성을 기대하는 도메인인가 (자연어 검색 / 대화 / 창작).

이 두 가지가 모두 충족되면 Agent 로 갈 가치가 있는 기능.

하나라도 안 되면 Workflow 가 정답.

🎯 면접관을 홀리는 핵심 멘트

"Workflow 가 비용·예측 가능성에서 모두 우위인데도 ChatGPT 가 시장을 사로잡은 이유는 — 사용자가 '시스템이 자율적으로 도와준다'는 신뢰를 기술 효율과 맞바꿔서라도 산다는 점이에요. 우리 서비스에선 어느 기능이 그 신뢰의 영역 인지가 Workflow vs Agent 분기의 첫 질문이에요. 두 신호 — 실패 비용이 가벼운가 + 사용자가 자율성을 기대하는 도메인인가 가 모두 충족되면 Agent, 하나라도 안 되면 Workflow 가 정답입니다."


주제 2 예시답안 — 에이전트 폭주의 책임은 LLM 인가, 도구 설계자인가?

[문제 상황 요약]

Step 3 의 폭주 라이브 시연 — 우리 손으로 짠 ChatClient 코드 한 글자도 안 건드리고 사용자 질문 한 줄로 지난 시간의 도구가 그대로 망가진 화면.

이 폭주의 책임은 (1) LLM 모델 제공자 / (2) 도구 설계자 (우리 백엔드 팀) / (3) 운영 (코드 리뷰 / 모니터링) 셋 중 누구에게 있는가? 2026 년 LLM 시대의 코드 리뷰 컬쳐 는 어떤 새 게이트를 두어야 하는가?

[튜터의 가이드 및 해설]

이 질문의 본질은 책임이 한 곳에만 있지 않다 는 점이에요. 세 곳 모두 부분 책임 을 지지만 우리 회사의 1 순위는 어디인가팀의 코드 리뷰 컬쳐를 결정 합니다.

(1) LLM 모델 — Anthropic 의 Constitutional AI / OpenAI 의 알고리즘적 안전성 학습모델 자체가 무한 반복하지 않도록 기여해요. 단 모델 한 번이 100% 안전한 경우는 없음. 결정론적 안전을 모델에만 의존하면 모델이 똑똑해지길 기다리는 자세 — 백엔드 엔지니어 입장에선 가장 안 좋은 길이에요.

(2) 도구 설계자Day 11 의 우리 도구 3 종 어디에도 가드가 없다는 점 이 폭주의 직접 원인. 멈춤 / 한도 / 권한 이 도구 자체에 들어가 있지 않으면 어떤 모델을 써도 폭주 가능. 책임의 무게가 가장 무겁게 걸리는 곳이에요.

(3) 운영가드 누락이 머지되도록 둔 코드 리뷰 / 토큰 청구서가 폭발하기 전에 알람이 울리지 않은 모니터링. 팀 단위 거버넌스 게이트 가 있어야 한 사람의 실수가 시스템 전체로 번지지 않습니다.

세 책임의 분담 옵션을 나눠 보면 —

  • Option A — LLM 에 무게: 모델만 똑똑해지면 가드 부담이 가벼워질 거다. 장점: 자체 코드 변경 최소. 단점: 현실의 LLM 은 폭주 가능성을 0 으로 못 만듦 — 책임 회피에 가까움.
  • Option B — 도구 설계자에 무게: 모든 @Tool PR 에 가드 체크리스트 (호출 횟수 / 권한 / 타임아웃) 강제. 장점: 직접 통제 가능. 단점: 팀 단위 컨벤션 도입 비용.
  • Option C — 운영에 무게: SRE 가 토큰 모니터링 / 폭주 감지 알람 운영. 장점: 사후 감지의 안전망. 단점: 예방이 아닌 사후 대응.
  • 현업에서는 보통세 곳에 무게가 분산되어야 하지만 우선순위는 (2) 도구 설계자 → (3) 운영 → (1) LLM 이 정석. 우리 팀이 직접 통제 가능한 곳 부터 무게를 두는 흐름.

2026 년 LLM 시대의 코드 리뷰 컬쳐@Tool PR 에 무조건 가드 체크리스트 (호출 횟수 한도 + 권한 검사 + 부작용 여부) 를 두는 게이트가 자리잡고 있어요. 가드 누락은 머지 금지 의 원칙이 Day 14 의 가드 4 부품모든 PR 의 디폴트 게이트 로 키우는 흐름. EU AI Act (고위험 AI 시스템 규정은 2026 년 8 월 2 일 발효 예정 — 단 2026 년 5 월 7 일 EU 의회·이사회 정치적 합의로 일부 조항이 16 개월·12 개월 연기 협의 진행 중, 정식 채택 대기) / NIST AI RMF 같은 거버넌스도 이 세 책임의 분배를 강제 하는 방향으로 흐릅니다.

🎯 면접관을 홀리는 핵심 멘트

"폭주의 책임은 세 곳 — LLM 모델 / 도구 설계자 / 운영 — 에 모두 걸리지만, 우리 팀이 직접 통제 가능한 곳 부터 무게를 두는 게 정석이에요. 1 순위는 도구 설계자 — 모든 @Tool PR 에 호출 횟수 한도 + 권한 검사 + 부작용 여부 의 가드 체크리스트가 머지 게이트로 들어와야 합니다. 모델이 똑똑해지길 기다리는 건 책임 회피에 가깝고, 모니터링은 사후 안전망일 뿐이에요. 2026 년 8 월 발효 예정인 EU AI Act (일부 조항은 2026-05-07 정치 합의로 연기 협의 중) 도 이 세 책임의 분배를 강제하는 방향이라, 도구 설계자 게이트가 업계 표준 컨벤션으로 자리잡는 흐름입니다."


주제 3 예시답안 — Tool Calling (Day 11) vs MCP (Day 17) — 아키텍처 관점의 차이는?

[문제 상황 요약]

Day 11 의 @Tool Tool CallingDay 17 의 MCP Client. 둘 다 도구 라는 이름인데 아키텍처 관점에선 한 단계 다른 가족. 프로세스 경계 안 vs 밖 / 우리 팀 코드 vs 외부 팀 코드 / ms 지연 vs 50ms 이상 지연 의 차이. 우리 ai-friends 의 호감도 조회 (AffinityTool) 같은 도구를 Tool Calling 으로 둘지 MCP 서버로 노출할지. 5 축 (네트워크 경계 / 신뢰도 / 보안 모델 / 응답 지연 / 다른 팀 재사용) 의 결정 기준은?

[튜터의 가이드 및 해설]

이 질문의 본질은 경계 (boundary) 예요. Tool Calling 은 프로세스 경계 안 — 같은 JVM. MCP 는 프로세스 경계 밖 — 네트워크 너머. 같은 도구라도 어느 경계에 두는지 에 따라 시그니처 / 인증 / 응답 지연 / 유지보수 가 완전히 달라져요.

5 축의 결정 기준을 한 줄씩 정리하면 —

Tool Calling 우위 MCP 우위
(1) 네트워크 경계 같은 프로세스 — JVM 안 다른 프로세스 — 네트워크 너머
(2) 신뢰도 우리 팀이 직접 짠 코드 외부 팀 / 서드파티의 코드
(3) 보안 모델 우리 앱의 인증 컨텍스트를 그대로 새 인증 게이트 (API 키 / OAuth) 필요
(4) 응답 지연 ~ms (메서드 호출) ~50ms ~ 수 초 (HTTP / SSE)
(5) 다른 팀 재사용 우리 팀만 사용 여러 팀 / 외부 클라이언트 (Claude Desktop 등) 재사용

우리 ai-friends 의 AffinityTool 에 적용해 보면 5 축 모두 Tool Calling 우위. 우리 팀이 짠 코드 / 같은 JVM / 우리 앱 인증 / ms 지연 / 우리만 사용. 그래서 Tool Calling 이 정답.

그러면 언제 MCP 로 옮길까? 두 가지 신호가 보일 때예요.

  • Option A — Tool Calling 만: 우리 팀만 쓰는 경우. 장점: 시그니처 한 벌 / 인증 한 벌 / 가드 한 벌. 단점: 외부 클라이언트 (Claude Desktop / Cursor) 가 우리 도구 못 부름.
  • Option B — MCP 서버로도 노출: 외부 팀 / Claude Desktop / Cursor 같은 외부 LLM 클라이언트가 우리 도구를 쓸 가치가 있을 때. 장점: 광범위한 재사용 + 표준 프로토콜. 단점: 시그니처 두 벌 (Tool Calling + MCP) / 가드 두 벌 / 버전 두 벌 의 유지보수 부담.
  • 현업에서는 보통내부 사용은 Tool Calling / 외부 노출 가치가 명확한 경우만 MCP 서버로 노출. 둘 다 노출유지보수 부담 이 커서 명확한 사용처가 보여야 가는 흐름.

2026 년 Anthropic MCP 표준이 업계에 자리잡은 모습 을 보면 OpenAI 도 MCP 채택 (2025-03) / Google ADK 도 MCP 호환 의 흐름이고, 2025-12 에는 Anthropic 이 MCP 거버넌스를 Linux Foundation 산하 Agentic AI Foundation 으로 이관했어요. 언젠가는 Tool Calling 이 MCP 의 로컬 케이스로 흡수될 수도 있는 흐름까지 보여요. 단 프로세스 경계 안의 도구를 굳이 네트워크 호출로 부르는 건 응답 지연·인증 게이트의 비용이 따라붙으니 Tool Calling 은 당분간 사라지지 않습니다.

🎯 면접관을 홀리는 핵심 멘트

"Tool Calling 과 MCP 의 본질적 차이는 프로세스 경계 예요. 같은 JVM 안의 우리 팀 도구는 Tool Calling — ms 지연 + 우리 앱 인증을 그대로 쓰는 영역. 네트워크 너머의 외부 팀 도구는 MCP — 50ms 이상 지연 + 새 인증 게이트가 들어오는 영역. 우리 팀의 1 순위 분기 기준은 (5) 다른 팀의 재사용 가치 가 명확하면 MCP 로도 노출, 우리 팀만 쓰면 Tool Calling 한 벌. 둘 다 노출 은 시그니처·가드·버전 세 벌의 유지보수 부담이 커서 명확한 사용처가 보일 때만 갑니다. 2025-03 OpenAI 가 MCP 채택, 2025-12 Linux Foundation Agentic AI Foundation 으로 거버넌스 이관 — MCP 표준이 업계에 자리잡고 있지만, Tool Calling 의 ms 지연은 당분간 사라지지 않아요."

더 배우려면

실무 프로젝트까지 가고 싶다면

팀스파르타 백엔드 부트캠프에서 인스타그램 클론을 풀스택으로 완성합니다.