⌚ 타임라인
00:00 - 인트로
02:18 - 5가지 패턴 소개
03:53- 초기셋팅
06:18 - 1 프롬프트 체이닝 (Prompt Chaining)
14:38 - 2. 라우팅 (Routing)
19:25 - 3. 병렬처리(Parallelization)
25:12 - 4. 오케스트레이터-워커(Orchestrator - Workers)
35:13 - 5 .평가-최적화(Evaluator-Optimizer)
1. 프롬프트 체이닝(Prompt Chaining)
- ex) 패턴과 대응하는 사례 : 여름 휴가 여행지를 정하기
2. 라우팅(Routing)
- ex) 질문에 따라 다른 AI 모델을 활용하기
3. 병렬처리(Parallelization)
- ex) 한번에 여러 AI모델의 응답 참고하기
4. 오케스트레이터-워커(Orchestrator - Workers)
- ex) 하위질문 생성해서 리서치하기
5. 평가-최적화(Evaluator-Optimizer)
- ex) AI 요약결과 피드백/개선 자동화
AI 에이전트가 되기 위해서는 어떤 점을 만족해야하는지 알아보다 보게 된 영상이다.
성희에게 공유해서 어떻게 생각하는지 물었을대 성희는 이건 AI 에이전트가 될수 없다고 말했다.
그냥 워크 플로우라고.
반면 나는 이런 기술을 통해 AI 에이전트라 불릴 수 잇는 서비스 구현이 가능하지 않나라고 생각했다.
그래서 영상 내용을 정리하고 그에 따른 것을 ai를 통해 다시 확인하였다.
다시 확인하니 짚고 넘어가야 하는 개념이 있다.
Workflow : 개발자가 미리 정해놓음
1단계 → 2단계 → 3단계 → 결과
이렇게 순서가 고정된다.
Agent
목표 → AI가 판단→어떤 도구를 쓸지 결정 → 필요하면 반복 → 필요하다면 다른 경로 선택 → 완료
경로가 고정되지 않음.
먼저 이쪽의 공통코드는 모든 예제가 사용해야 하는 부분으로 맨 처음에 두었다.
활용해서 각각의 다양한 패턴에서 응용을 하고 조검 더 고급스러운 자동화 워크플로우를 만들 수 있게 도와준다.
import re
from openai import AsyncOpenAI, OpenAI
OPENAI_API_KEY = ""
client = AsyncOpenAI(
api_key=OPENAI_API_KEY,
)
sync_client = OpenAI(
api_key=OPENAI_API_KEY,
)
def llm_call(prompt: str, model: str = "gpt-4o-mini") -> str:
messages = []
messages.append({"role": "user", "content": prompt})
chat_completion = sync_client.chat.completions.create(
model=model,
messages=messages,
)
return chat_completion.choices[0].message.content
async def llm_call_async(prompt: str, model: str = "gpt-4o-mini") -> str:
messages = []
messages.append({"role": "user", "content": prompt})
chat_completion = await client.chat.completions.create(
model=model,
messages=messages,
)
print(model,"완료")
return chat_completion.choices[0].message.content
if __name__ == "__main__":
test = llm_call("안녕")
print(test)
전체 함수들을 활용할때 사용되는 파일이 util.py가 있음.
두개의 함수가 존재
llm_call : 일반적으로 챗got 답변 자체를 텍승트로 출력
비동기, 병렬 다양한 함수 처리를 같이 할대로 3, 4번
1. 프롬프트 체이닝(Prompt Chaining)
우선 영상에서 말하는대로 첫번째로 프롬프트 체이닝을 보도록 하자.
우리가 LLM에 질문을 할 때 "여름 휴가로 어디가 좋을까?"라고 바로 질문을 하면 AI는 바로 답변을 준다.

이 방식이 챗GPT 같은 LLM과 대화를 할 때 활용하는 방식이다.
반면에 프롬프트 체이닝이라는 기법은 내가 질문을 하면
그 질문과 관련된 최종 답변을 도출하기 전에 여러 번 llm을 순차적으로 호출하는 기법이다.

- 개념: 하나의 거대한 프롬프트로 한 번에 결과를 도출하는 것이 아니라, 여러 번 LLM 호출을 순차적(Sequential)으로 연결하여 단계별로 결과물을 고도화하는 패턴입니다. [06:37]
- 영상 내 구현 예시 (여름 휴가 계획 짜기):
💡 개발자 Tip (문맥 유지): 체인이 깊어질 때 직전 단계의 응답뿐만 아니라 최초의 사용자 입력값(Initial Input)을 계속 문맥(Context)으로 함께 넘겨주어야 초기 의도가 왜곡되지 않고 완결성 높은 답변이 나옵니다. [13:01]
이건 메모리와 관련된 내용인것 같다.
1.1. 1_prompt_chaining.py
프롬프트를 통해 단계별로 응답을 좁혀주는게 아닌가라는 생각을 했다
from typing import List
from utils import llm_call
def prompt_chain_workflow(initial_input: str, prompt_chain: List[str]) -> List[str]:
response_chain = []
response = initial_input
for i, prompt in enumerate(prompt_chain, 1):
print(f"\n==== 단계 {i} ====\n")
final_prompt = f"{prompt}\n사용자 입력:\n{response}"
print(f"🔹 프롬프트:\n{final_prompt}\n")
response = llm_call(final_prompt)
response_chain.append(response)
print(f"✅ 응답:\n{response}\n")
return response_chain
## 처음 입력값을 계속 유지해야 하는 경우!
def prompt_chain_workflow_2(initial_input: str, prompt_chain: List[str]) -> List[str]:
response_chain = []
response = initial_input
for i, prompt in enumerate(prompt_chain, 1):
print(f"\n==== 단계 {i} ====\n")
final_prompt = f"{prompt}\n\n🔹 문맥(Context):\n{response}\n🔹 사용자 입력: {initial_input}"
print(f"🔹 프롬프트:\n{final_prompt}\n")
response = llm_call(final_prompt)
response_chain.append(response)
print(f"✅ 응답:\n{response}\n")
return response_chain
# 처음 사용자가 질문을 함.
initial_input ="""
나는 여름 휴가를 계획 중이야. 따뜻한 날씨를 좋아하고, 자연 경관과 역사적인 장소를 둘러보는 걸 좋아해.
어떤 여행지가 나에게 적합할까?
"""
# 프롬프트 체인: LLM이 단계적으로 여행을 계획하도록 유도
prompt_chain = [
## 여행 후보지 3곳을 추천하고 그 이유를 설명
"""사용자의 여행 취향을 바탕으로 적합한 여행지 3곳을 추천하세요.
- 먼저 사용자가 입력한 희망사항을 요약해줘
- 사용자가 입력한 희망사항을 반영해서 왜 적합한 여행지인지 설명해주세요
- 각 여행지의 기후, 주요 관광지, 활동 등을 설명하세요.
""",
## 여행지 1곳을 선택하고 활동 5가지 나열
"""다음 여행지 3곳 중 하나를 선택하세요. 선택한 여행지 알려주세요. 그리고 선택한 이유를 설명해주세요.
- 해당 여행지에서 즐길 수 있는 주요 활동 5가지를 나열하세요.
- 활동은 자연 탐방, 역사 탐방, 음식 체험 등 다양한 범주에서 포함되도록 하세요.
""",
## 선택한 여행지에서 하루 일정 계획
"""사용자가 하루 동안 이 여행지에서 시간을 보낼 계획입니다.
- 오전, 오후, 저녁으로 나누어 일정을 짜고, 각 시간대에 어떤 활동을 하면 좋을지 설명하세요.
""",
]
responses = prompt_chain_workflow_2(initial_input,prompt_chain)
final_answer = responses[-1]
print(final_answer)
■ initial_input : 최초 프롬프
■ prompt_chain :
■ prompt_chain_workflow_2 :
처음 입력값을 계속 유지해야하는 경우 prompt_chain_workflow_2를 사용한다.
prompt_chain_workflow와의 차이는
똑같이
파이널 맨처음에 사용자가 한 질문에 대해 그에 맞는 맥락에 맞게 다시 수정한다.
for i, prompt in enumerate(prompt_chain, 1):
print(f"\n==== 단계 {i} ====\n")
final_prompt = f"{prompt}\n사용자 입력:\n{response}"
반복문을 돌면서 사용자의 프롬프트와 반응을 실시간을 공개한다.
다시 예제를 보자
여행지 추천 → 한 곳 선택 → 일정 생성
코드에 이미 단계가 박혀 있다.
AI가 "아 나는 4단계로 해야겠다"를 결정하지 않는다. 개발자가 결정했다. 그리서 이건 100% Workflow다.
만약
사용자 : 2박 3일 강릉 여행 추천해줘
AI : 이 경우는 축제가 중요하네
→ 축제 검색
AI : 비 오네
→ 맛집 검색
이렇게 AI가 다음 행동을 스스로 결정하면 Agent에 훨씬 가깝다.
Agent 코드가 되는 방향으로 바꿔보자면
def travel_agent(user_input: str):
context = user_input
while True:
# LLM이 다음 행동을 스스로 결정
decision = llm_call(f"""
사용자 목표: {user_input}
지금까지 진행 상황: {context}
목표가 달성됐으면 DONE을 출력하고,
아직이면 다음에 해야 할 작업 하나를 출력해.
""")
if "DONE" in decision:
break
# 결정된 작업 실행
result = llm_call(f"{decision}\n\n현재 상황: {context}")
context += f"\n{result}"
2. 라우팅(Routing)
질문을 하면 바로 답하는게 아니라
고민을 하고 고민한 상황을 가지고 답변을 해준다.

- 개념: 사용자의 입력(질문)을 먼저 분석한 뒤, 그 질문의 특성, 난이도, 비용에 따라 가장 적합한 하위 모듈이나 LLM 모델로 동적으로 경로를 분기해주는 패턴입니다. [14:44]
- 영상 내 구현 예시 (동적 모델 스위칭):
- 구현 매커니즘: '라우터 LLM'에게 질문을 먼저 던져 단답형으로 사용할 모델명(또는 툴 이름)만 출력하게 유도한 뒤, 파이썬 조건문이나 파라미터 바인딩을 통해 해당 모델로 본 질문을 다시 던집니다. [18:32]
원본 예제 코드
from utils import llm_call
def run_router_workflow(user_prompt : str):
router_prompt = f"""
사용자의 프롬프트/질문: {user_prompt}
각 모델은 서로 다른 기능을 가지고 있습니다. 사용자의 질문에 가장 적합한 모델을 선택하세요:
- gpt-4o: 일반적인 작업에 가장 적합한 모델 (기본값)
- o1-mini: 코딩 및 복잡한 문제 해결에 적합한 모델
- gpt-4o-mini: 간단한 사칙연산 등의 작업에 적합한 모델
모델명만 단답형으로 응답하세요
"""
print(router_prompt)
selected_model = llm_call(router_prompt)
print("선택한 모델", selected_model)
response = llm_call(user_prompt, model = selected_model)
print(response)
return response
query1 = "1더하기 2는 뭐지?"
print(query1)
response = run_router_workflow(query1)
query2 = "리스본 여행일정을 짜줘"
print(query2)
response = run_router_workflow(query2)
query3 = "파이썬으로 API 웹서버를 만들어줘"
print(query3)
response = run_router_workflow(query3)
실행했으나 오류 발생으로

from openai import OpenAI
client = OpenAI()
models = client.models.list()
for m in models.data:
print(m.id)
3. 병렬처리(Parallelization)

- 개념: 하나의 요청이나 지문에 대해 여러 LLM 모델이나 프롬프트에 동시다발적으로 요청을 보내고(비동기 처리), 얻어진 독립적인 응답들을 하나로 취합(Aggregation)하여 최종 답변을 생성하는 패턴입니다. [19:32]
- 영상 내 구현 예시 (다중 교차 번역 검증):
- 💡 개발자 Tip (비동기 제어): 파이썬의 asyncio.as_completed 또는 asyncio.gather를 활용해 API 응답이 먼저 오는 것부터 순차적으로 처리함으로써 전체 워크플로우 속도를 획기적으로 단축할 수 있습니다. [23:51]

4. 오케스트레이터-워커(Orchestrator-Workers)

- 개념: 병렬 처리와 유사해 보이지만, "하위 작업의 개수와 종류를 런타임에 동적으로 결정한다"는 점에서 더 고도화된 패턴입니다. 중앙의 오케스트레이터 LLM이 문제를 분석해 하위 태스크(서브 질문)들로 쪼개고, 이를 각각의 워커(Worker)에게 배정하여 수행한 뒤 취합합니다. [25:16]
- 영상 내 구현 예시 (Deep Research 시스템 구현):
- 질문: AI가 미래 노동 시장에 미칠 영향을 분석해줘 [25:46]
- 오케스트레이터: 질문을 분석하여 1. 대체될 직업군, 2. 새로 생겨날 직업군, 3. 요구되는 기술의 변화라는 3개의 구조화된 제이슨(JSON) 형태의 하위 과업을 동적으로 생성합니다. [27:51]
- 워커: 분할된 서브 질문들을 비동기로 각각 수행하여 디테일한 정보를 수집합니다. [29:11]
- 취합(Aggregation): 최종적으로 모든 워커의 결과물을 모아 서식화된 대형 리서치 보고서(마크다운 형태)를 도출합니다. 단일 프롬프트로 물어봤을 때보다 훨씬 풍부하고 체계적인 인사이트가 확보됩니다. [30:24]
5. 평가-최적화(Evaluator-Optimizer)

반복적으로 시행착오를 겪는
from utils import llm_call
def loop_workflow(user_query, evaluator_prompt, max_retries=5) -> str:
"""평가자가 생성된 요약을 통과할 때까지 최대 max_retries번 반복."""
retries = 0
while retries < max_retries:
print(f"\n========== 📝 요약 프롬프트 (시도 {retries + 1}/{max_retries}) ==========\n")
print(user_query)
summary = llm_call(user_query, model="gpt-4o-mini")
print(f"\n========== 📝 요약 결과 (시도 {retries + 1}/{max_retries}) ==========\n")
print(summary)
final_evaluator_prompt = evaluator_prompt + summary
evaluation_result = llm_call(final_evaluator_prompt, model="gpt-4o").strip()
print(f"\n========== 🔍 평가 프롬프트 (시도 {retries + 1}/{max_retries}) ==========\n")
print(final_evaluator_prompt)
print(f"\n========== 🔍 평가 결과 (시도 {retries + 1}/{max_retries}) ==========\n")
print(evaluation_result)
if "평가결과 = PASS" in evaluation_result:
print("\n✅ 통과! 최종 요약이 승인되었습니다.\n")
return summary
retries += 1
print(f"\n🔄 재시도 필요... ({retries}/{max_retries})\n")
# If max retries reached, return last attempt
if retries >= max_retries:
print("❌ 최대 재시도 횟수 도달. 마지막 요약을 반환합니다.")
return summary # Returning the last attempted summary, even if it's not perfect.
# Updating the user_query for the next attempt with full history
user_query += f"{retries}차 요약 결과:\n\n{summary}\n"
user_query += f"{retries}차 요약 피드백:\n\n{evaluation_result}\n\n"
def main():
## 기사 링크 : https://zdnet.co.kr/view/?no=20250213091248
input_article = """
오픈AI가 몇 주 안에 새로운 모델인 'GPT-4.5'를 출시하며 분산돼 있던 생성형 인공지능(AI) 모델을 통합키로 했다. 추론용 모델인 'o' 시리즈를 정리하고 비(非)추론 모델인 'GPT' 시리즈로 합칠 예정이다.
13일 업계에 따르면 샘 알트먼 오픈AI 최고경영자(CEO)는 지난 12일 자신의 X(옛 트위터)에 'GPT-4.5'를 조만간 출시할 것이라고 밝혔다. 현 세대인 'GPT-4o'의 뒤를 잇는 마지막 '비추론 AI'로, 내부적으로는 '오라이언(Orion)'이라고 불렸다.
현재 챗GPT 이용자를 비롯한 오픈AI의 고객들은 'GPT-4o', 'o1', 'o3-미니', 'GPT-4' 등 모델들을 각자 선택해 활용하고 있다. 최신 모델은 'GPT-4'를 개선한 'GPT-4o'로, 'GPT-4'는 2023년 하반기, 'GPT-4o'는 2024년 상반기 출시됐다.
오픈AI는 'GPT-5'도 지난해 공개하려고 했으나, 예상보다 저조한 성과를 거둬 출시가 연기된 상태다. 이에 그간 연산 시간을 늘려 성능을 높인 'o'시리즈 추론 모델을 새롭게 내세웠다.
샘 알트먼 CEO는 "이후 공개될 'GPT-5'부터는 추론 모델인 'o'시리즈와 'GPT'를 통합하겠다"며 "모델과 제품라인이 복잡해졌음을 잘 알고 있고, 앞으로는 각 모델을 선택해 사용하기보다 그저 잘 작동하길 원한다"고 말했다.
"""
user_query = f"""
당신의 목표는 주어진 기사를 요약하는 것입니다.
아래 주어진 기사 내용을 요약해주세요.
이전 시도의 요약과 피드백이 있다면, 이를 반영하여 개선된 요약을 작성하세요.
기사 내용:
{input_article}
"""
evaluator_prompt = """
다음 요약을 평가하십시오:
## 평가기준
1. 핵심 내용 포함 여부
- 원문의 핵심 개념과 논리적 흐름이 유지되어야 합니다.
- 불필요한 세부 사항은 줄이되, 핵심 정보가 누락되면 감점 요인입니다.
- 단어 선택이 다소 달라도, 주요 개념과 의미가 유지되면 PASS 가능합니다.
- 원문의 중요 개념 15% 이상이 빠졌다면 FAIL입니다.
2. 정확성 & 의미 전달
- 요약이 원문의 의미를 왜곡하지 않고 정확하게 전달해야 합니다.
- 숫자, 인명, 날짜 등 객관적 정보가 틀리면 FAIL입니다.
- 문장이 다르게 표현되었더라도 원문의 의미를 유지하면 PASS 가능합니다.
- 논리적 비약이 크거나 잘못된 해석이 포함되면 FAIL입니다.
3. 간결성 및 가독성
- 문장이 과하게 길거나 반복적이면 감점 요인입니다.
- 직역체 표현은 가독성을 해치지 않으면 허용 가능하지만, 지나치면 FAIL입니다.
- 일부 단어의 표현 방식이 달라도 자연스럽다면 PASS 가능합니다.
- 문장이 지나치게 어색해서 독해가 어렵다면 FAIL입니다.
4. 문법 및 표현
- 맞춤법, 띄어쓰기 오류가 5개 이상이면 FAIL입니다.
- 사소한 문법 실수는 감점 요인이나, 의미 전달에 영향을 주면 FAIL입니다.
- 문장이 비문이거나 문맥상 어색한 표현이 많으면 FAIL입니다.
## 평가결과 응답예시
- 모든 기준이 충족되었으면 "평가결과 = PASS"를 출력하세요.
- 수정이 필요한 경우, 구체적인 문제점을 지적하고 반드시 개선 방향을 제시하세요.
- 중대한 오류가 있다면 "평가결과 = FAIL"을 출력하고, 반드시 주요 문제점을 설명하세요.
요약 결과 :
"""
final_summary = loop_workflow(user_query, evaluator_prompt, max_retries=5)
print("\n✅ 최종 요약:\n", final_summary)
if __name__ == "__main__":
main()
- 개념: 생성(Generator/Optimizer)과 평가(Evaluator) 역할을 분리하여, LLM이 낸 결과물이 사전에 정의한 엄격한 기준(Criteria)을 통과할 때까지 반복적으로 피드백을 주고받으며 품질을 개선하는 루프 패턴입니다. [35:16]
- 영상 내 구현 예시 (뉴스 기사 완성도 높은 요약본 만들기):
- 생성기: 뉴스 기사를 초안 형태로 요약합니다. [37:33]
- 평가기: 사전에 정의된 기준(핵심 내용 포함 여부, 정확성, 간결성, 가독성 등)에 맞추어 초안을 평가합니다. 기준 미달 시 피드백 코멘트와 함께 FAIL을 반환하고, 만족 시 PASS를 반환합니다. [37:58]
- 루프 제어: FAIL인 경우, 파이썬의 while 루프 내에서 [이전 요약본 + 평가기 피드백 + 원본 기사]를 다시 생성기에 입력하여 수정본을 생성하게 합니다. 이 과정을 PASS가 뜨거나 최대 재시도 횟수(예: 5회)에 도달할 때까지 반복합니다. [38:52]
마무리
"블랙박스처럼 내부를 알 수 없는 대형 프레임워크에 의존하기보다, 이처럼 파이썬의 기본 제어문(for, while), 비동기 루틴(asyncio), 그리고 정형화된 데이터 구조(JSON 패싱)를 직접 다루는 것이 에이전트의 구동 원리를 근본적으로 이해하고 제어하는 데 훨씬 유리합니다. 복잡한 에이전트 시스템도 결국 이 5가지 기초 패턴들의 조합과 응용으로 귀결된다."
기타
https://www.anthropic.com/engineering/building-effective-agents
'스터디 > AI-Agent' 카테고리의 다른 글
| [작성중/AI-Agent] Claude.md 분석 (0) | 2026.06.15 |
|---|---|
| [작성중/AI-Agent] 끔직한 결말, 그리고 방향성을 잡기위한 재설계의 필요성 (0) | 2026.06.14 |
| [작성중/AI-Agent] Claude가 작성한 프로젝트, 어떤 순서로 만들어졌을까? (0) | 2026.06.14 |
| [AI-Agent] 이게 없으면 AI Agent가 아니다(정의부터 구현 기준까지) (0) | 2026.05.30 |
| [작성중]AI 기술의 발달 과정과 n8n (0) | 2026.05.15 |