Agentic AI Design Patterns

CH01-프롬프트 체이닝 입문 | 단일 프롬프트의 한계부터 LangChain·LangGraph·Google ADK 구현까지

빌드 피벗(Build Pivot) 2026. 5. 31. 17:40
반응형
AGENTIC AI DESIGN PATTERNS · 01
복잡한 LLM 작업은 쪼개라
— 프롬프트 체이닝(Prompt Chaining) 완벽 정리
단일 프롬프트의 한계부터 4개 프레임워크 구현, 품질 게이트, CRM·ERP·Groupware 적용까지
🟢 입문~중급⏱️ 약 15분🧩 LangChain · LangGraph · ADK🏢 엔터프라이즈

TL;DR — 프롬프트 체이닝은 하나의 거대한 프롬프트를 검증 가능한 여러 단계로 분해하고, 각 단계의 출력을 다음 단계의 입력으로 연결하는 가장 기초적이고 중요한 에이전트 설계 패턴입니다. 단일 프롬프트 대비 정확도가 최대 15.6% 향상되고, 단계별 검증·재시도가 가능해집니다. 왜 → 언제 → 어떻게(4개 프레임워크) → 실전(품질 게이트·엔터프라이즈) 순서로 정리합니다.

1. 왜 쪼개는가 — 단일 프롬프트의 한계

“시장을 분석하고, 트렌드를 정리하고, 요약하고, 이메일 초안까지 한 번에 작성해줘.” 이렇게 여러 작업을 한 프롬프트에 욱여넣으면 LLM은 생각보다 자주 무너집니다. 반복적으로 관찰되는 단일 프롬프트의 5가지 한계가 있습니다.

  • 지시 무시(Instruction Neglect) — 지시 5개를 넘으면 누락. 실측 누락률 20~40%
  • 맥락 편류(Contextual Drift) — 생성 도중 처음 요구에서 점점 벗어남
  • 오류 전파(Error Propagation) — 앞 단계의 실수가 뒤로 그대로 번짐
  • 환각 증폭(Hallucination) — 검증 지점이 없어 잘못된 정보가 최종 결과로
  • 검증 불가 — 틀려도 “어느 단계에서” 틀렸는지 추적 불가

프롬프트 체이닝은 이 작업을 분석 → 정리 → 생성처럼 쪼갠 뒤 각 단계를 개별 검증합니다. 한 단계가 실패하면 그 단계만 다시 실행하면 됩니다.

❌ 거대한 단일 프롬프트
“시장 분석 + 트렌드 정리 + 요약 + 이메일 작성을 한 번에 해줘”
  • 지시 누락 20~40%
  • 어디서 틀렸는지 추적 불가
  • 재시도 = 전체 재실행
✅ 단계로 분해한 체인
1 분석2 정리3 생성
  • 단계별 검증 ✓
  • 실패 지점 즉시 격리
  • 실패한 단계만 재시도
그림 1. 모든 책임을 한 번에 떠넘기는 단일 프롬프트 vs. 단계별로 검증하는 체인

2. 프롬프트 체이닝이란

프롬프트 체이닝은 분할 정복(Divide & Conquer) 전략을 LLM에 적용한 것입니다. 복잡한 문제를 작은 단위로 나눠 순차 처리하고, 각 단계의 출력이 다음 단계의 입력이 되도록 연결합니다.

핵심 구성 요소 4가지

구성 요소 역할
Step (단계) 하나의 단계는 하나의 책임만 — 검증 가능·독립 재시도 가능한 최소 단위
State (공유 상태) 모든 단계가 함께 읽고 쓰는 저장소. 진행될수록 결과 누적
output_key 각 단계 결과를 어떤 이름으로 저장할지 지정 → 다음 단계가 {key}로 참조
Parser (구조화) 자연어를 JSON·객체로 변환 → 단계 간 데이터 전달 신뢰성 확보
입력
{topic}
Step 1
시장 분석가
Step 2
트렌드 분석가
Step 3
카피라이터
최종 결과
이메일 초안
공유 상태  state = { }
"analysis": …"trends": …"email": …
그림 2. 입력이 단계를 거치며 공유 상태(state)에 결과가 누적된다
역할 부여가 품질을 바꾼다. 각 단계에 "20년 경력의 시장 분석가" 같은 전문가 역할을 부여하면 같은 작업도 품질이 올라갑니다. 여기에 구조화 출력(JSON)을 더하면 단계 간 전달이 안정됩니다.

3. 언제 쪼개야 하나 — 분해 의사결정

분해는 정확도를 올리지만 호출 횟수(비용·지연)도 늘립니다. 교재는 복잡도 점수로 정량화합니다.

복잡도 점수 권장 전략
5~7점 단일 프롬프트로 충분
8~11점 프롬프트 체이닝 권장
12점 이상 체이닝 + 품질 게이트 필수

점수는 지시 개수, 출력 형식 복잡성, 검증 필요성, 오류 파급 영향, 컨텍스트 길이를 합산합니다. 한 단계를 더 쪼갤지는 ① 중간 검증 ② 부분 재시도 ③ 재사용 ④ 다른 사고 유형 ⑤ 스키마 차이 ⑥ 다른 모델·도구 중 2개 이상 해당하면 분해합니다.

🧠
“하나의 Step = 하나의 사고 유형”. 분류와 생성을 한 단계에 섞지 마세요. 인지적 단일성을 지켜야 검증 가능하고 실패가 그 단계에 격리됩니다. 현업 업무는 IPODC(Input·Process·Output·Decision·Condition)로 인터뷰해 단계를 도출합니다.

4. 구현 ① 순수 Python — 원리를 손으로

프레임워크의 마법을 걷어내면 본질은 단순합니다. state 딕셔너리 하나를 두고, 각 단계가 거기서 읽어 프롬프트를 만들고 결과를 다시 저장하는 것뿐입니다.

PYTHON
class PromptChain: def __init__(self, name="PromptChain"): self.steps = [] self.state = {} # 모든 단계가 공유하는 저장소 (핵심!) def add_step(self, name, role, prompt_template, output_key, parser=None): self.steps.append({"name": name, "role": role, "prompt_template": prompt_template, "output_key": output_key, "parser": parser}) return self # 메서드 체이닝: .add_step().add_step() def execute(self, initial_input): self.state["input"] = initial_input for step in self.steps: prompt = self._format_prompt(step["prompt_template"], step["role"]) output = self._call_llm(prompt) if step["parser"]: output = step["parser"](output) self.state[step["output_key"]] = output # 결과 누적 → 다음 단계가 참조 return self.state

장점은 완전한 제어와 0개의 의존성, 데이터 흐름이 코드에 그대로 드러난다는 점입니다. 학습·내재화에 가장 좋습니다. 단점은 보일러플레이트가 많다는 것 — 그래서 프레임워크가 등장합니다.

5. 구현 ② LangChain LCEL — 파이프로 선언

LCEL은 Unix 셸의 파이프처럼 prompt | llm | parser로 컴포넌트를 연결합니다. 모든 컴포넌트가 동일한 Runnable 인터페이스라 자유롭게 조합됩니다.

PYTHON
# 기본: prompt | llm | parser — 한 줄로 한 단계 extraction_chain = prompt_extract | llm | StrOutputParser() # 다단계: 이전 체인의 출력을 다음 프롬프트 변수로 매핑 transform_chain = ( {"specifications": extraction_chain} | prompt_transform | llm | StrOutputParser() ) full_chain = ( {"json_specs": transform_chain} | prompt_analyze | llm | StrOutputParser() ) result = full_chain.invoke({"text": input_text}) # 한 번의 호출로 전체 실행

RunnableParallel로 독립 분석을 동시에 돌리고, RunnableLambda로 전처리·검증 함수를 체인 중간에 끼워 넣을 수 있습니다. 빠른 프로토타이핑에 최적입니다.

6. 구현 ③ LangGraph — 상태 그래프로 제어

분기·반복·재시도가 필요한 복잡한 워크플로우라면 LangGraph입니다. TypedDict로 상태를 명시적으로 선언하고, 노드와 엣지로 흐름을 그립니다.

PYTHON
class ChainState(TypedDict): # 상태를 명시적으로 정의 → 타입 안정성 input_text: str specifications: str json_specs: str analysis: str graph = StateGraph(ChainState) graph.add_node("extract_specs", extract_specifications) graph.add_node("transform_json", transform_to_json) graph.add_node("analyze_product", analyze_product) graph.add_edge(START, "extract_specs") graph.add_edge("extract_specs", "transform_json") graph.add_edge("transform_json", "analyze_product") graph.add_edge("analyze_product", END) chain = graph.compile() # 실행 가능한 그래프로 컴파일

각 노드는 업데이트할 필드만 dict로 반환하면 됩니다. stream()으로 단계별 상태 변화를 실시간 추적할 수 있어 중간 결과 디버깅이 쉽고, add_conditional_edges()로 조건 분기·루프도 자연스럽게 구현됩니다.

7. 구현 ④ Google ADK — output_key로 자동 전달

Google ADK의 SequentialAgent는 가장 선언적입니다. 각 LlmAgentoutput_key만 지정하면 결과가 자동으로 세션 상태에 저장되고, 다음 에이전트는 {key}로 그 값을 참조합니다.

PYTHON
extractor = LlmAgent( name="FeedbackExtractor", model=MODEL_ID, instruction="고객 피드백에서 감정·제품·이슈·기대사항을 추출하라", output_key="extracted_info", # → session.state["extracted_info"] ) analyzer = LlmAgent( name="SentimentAnalyzer", model=MODEL_ID, instruction="{extracted_info}를 분석해 감성 점수와 우선순위를 매겨라", # {key} 참조 output_key="analysis_result", ) pipeline = SequentialAgent( name="CustomerFeedbackPipeline", sub_agents=[extractor, analyzer], # 선언 순서대로 자동 순차 실행 )

네 가지 방식 한눈에 비교

순수 Python
state = {}
의존성 0 · 학습용
LangChain LCEL
prompt | llm | parser
프로토타이핑
LangGraph
StateGraph(...)
분기 · 반복
Google ADK
SequentialAgent(...)
멀티 에이전트
그림 3. 같은 패턴, 네 가지 구현 방식 — 상태 관리 철학이 다르다
방식 연결 상태 관리 적합한 상황
순수 Python 직접 루프 dict 수동 학습·원리 이해
LangChain LCEL 파이프 | 자동 매핑 선형 순차·프로토타이핑
LangGraph 노드·엣지 TypedDict 명시 복잡한 워크플로우
Google ADK sub_agents output_key 자동 멀티 에이전트

8. 실전 패턴 ① 품질 게이트(Quality Gate)

체인이 길어질수록 한 단계의 결함이 뒤로 번지는 오류 전파가 치명적입니다. 해결책은 각 단계 뒤에 검증 체크포인트(Gate)를 두는 것 — 소프트웨어 품질 게이트 개념을 LLM 파이프라인에 적용합니다.

Producer
초안 생성
Critic
품질 검증·채점
기준 통과?
Pass ✓
승인
다음 단계
↩ Fail ✗ — 피드백과 함께 Producer로 재시도 (max_retries)
그림 4. 생산자(Producer)–검증자(Critic) 루프. 실패하면 피드백과 함께 재시도

핵심은 검증 실패 시 “구체적 피드백”을 다음 시도의 프롬프트에 주입하는 자기 수정 루프입니다. 무한 루프를 막기 위해 max_retries로 상한을 둡니다.

PYTHON
def _execute_step_with_retry(self, step): feedback = "" for attempt in range(1, self.max_retries + 1): prompt = self._format_prompt(step["prompt_template"], feedback) output = self._call_llm(prompt) validation = step["validator"](output, self.state) if validation.status == ValidationStatus.PASS: return True, output # 통과 → 다음 단계로 feedback = validation.feedback # 실패 → 피드백을 다음 시도에 주입 return False, output # max_retries 초과 → 에스컬레이션
⚠️
피드백은 “행동 가능한” 지침이어야 합니다.  ❌ “형식이 잘못됨” → ✅ “마크다운 코드블록을 제거하고 순수 JSON만 출력하세요”. 검증 함수는 ① 명확한 기준 ② 구체적 피드백 ③ 빠른 실행 ④ 재현 가능을 만족해야 합니다.

9. 실전 패턴 ② 구조화 출력(Structured Output)

단계 간 데이터를 자연어로 주고받으면 파싱이 깨지기 쉽습니다. Pydantic 스키마로 출력의 타입·범위·허용값(Enum)을 강제하면 LLM 출력을 타입 안전한 객체로 받고, 위반 시 ValidationError가 떠서 재시도와 연결됩니다.

PYTHON
class ExtractedFeedback(BaseModel): sentiment: SentimentType # Enum: 허용값만 (POSITIVE/NEGATIVE/…) key_points: List[KeyPoint] # 중첩 모델로 배열 구조까지 검증 mentioned_products: List[str] @field_validator("key_points") @classmethod def at_least_one(cls, v): if len(v) < 1: raise ValueError("최소 1개 필요") return v # LLM이 뱉은 JSON을 스키마로 검증 — 실패 시 ValidationError validated = ExtractedFeedback.model_validate(data) state["extracted"] = validated # 타입 보장된 객체를 다음 단계로

model_json_schema()로 스키마를 프롬프트에 넣어 LLM이 정확한 구조를 생성하게 하고, model_dump_json()으로 직렬화해 다음 단계에 자동 삽입하면 수동 파싱이 사라집니다.

10. 엔터프라이즈 적용 맵 — 어디에, 무엇을

프롬프트 체이닝은 학습용 예제에 그치지 않습니다. CRM·ERP·Groupware 전반에서 “여러 단계 + 중간 검증”이 필요한 업무라면 거의 그대로 적용됩니다.

CRM고객 관계 관리
영업리드 스코어링 · 견적 생성
★★★★★
서비스티켓 분류 · 자동 응답
★★★★★
분석이탈 예측 · CLV
★★★★☆
ERP전사 자원 관리
재무송장 처리 · 비용 분류
★★★★★
구매발주 · 공급업체 평가
★★★★★
재고수요 예측 · 최적화
★★★★☆
Groupware협업 시스템
결재결재선 추천 · 요약
★★★★★
메일분류 · 자동 응답
★★★★★
회의회의록 · 액션아이템
★★★★★
도입 효과 — 레거시 수작업 대비
−83%
데이터 입력 시간
2시간→20분/일
+567%
문서 처리량
30건→200건/일
−94%
고객 응답 시간
4시간→15분
−90%
데이터 오류율
5%→0.5%
그림 5. 시스템별 고적합 프로세스와 레거시 대비 도입 효과(ROI)

11. 케이스 스터디

① ERP 송장 처리 — 6단계 체인

비정형 송장(PDF·이미지)을 받아 회계 전표와 승인 라우팅까지 자동화합니다. 각 단계 뒤 품질 게이트가 결함의 전파를 막습니다.

1 데이터 추출
InvoiceData
2 검증·정규화
ValidatedInvoice
3 PO 매칭
MatchingResult
4 리스크 평가
RiskAssessment
5 회계 분개
AccountingEntry
6 승인 라우팅
ApprovalRouting
🛡 Gate 1~4  필수필드 · 수학검증 · 매칭신뢰도 95% · 리스크레벨 — 실패 시 피드백과 함께 재시도(결함 전파 차단)
< 30초처리/건
> 85%자동화율
> 95%추출 정확도
< 2%에러율
그림 6. ERP 송장 처리 6단계 체인 — 단계마다 품질 게이트

특히 Step 3 PO 매칭은 3-way 매칭 허용오차(수량 ±5%, 단가 ±3%, 총액 ±1%)와 매칭 신뢰도 95% 임계값으로 검증합니다.

② B2B 조달 — 4체인 + 금액별 승인

구매요청 한 줄이 발주서까지 이어지는 4단계 체인입니다. 각 단계의 출력 DTO가 다음 단계의 입력이 되어 컨텍스트가 보존됩니다.

단계 산출(DTO) 핵심 로직
1. 구매요청 분석 PurchaseRequestDTO 품목·금액·긴급도 추출
2. 공급업체 선정 SupplierRecommendationDTO 가격30%+납기25%+품질25%+실적20% → 상위 3개
3. 승인 라우팅 ApprovalRouteDTO 금액별 결재선·품목별 합의부서 자동 구성
4. 발주서 생성 PurchaseOrderDTO PO-2024-01-0001 형식 번호·표준 약관

금액 기준으로 승인 레벨이 자동 결정됩니다 — ~100만원: 팀장 / ~500만원: 부서장 / ~1,000만원: 본부장 / 1,000만원~: 임원.

PYTHON
# 4단계 조달 체인 (LCEL) — DTO가 단계 사이를 흐른다 full_chain = ( {"purchase_request_text": RunnablePassthrough()} | chain1 # 구매요청 분석 → PurchaseRequestDTO | (lambda dto: {"purchase_request_dto": dto, **load_suppliers(dto)}) | chain2 # 공급업체 선정 → SupplierRecommendationDTO | chain3 # 승인 라우팅 → ApprovalRouteDTO | chain4 # 발주서 생성 → PurchaseOrderDTO ) # 금액별 승인 레벨 자동 결정 if total < 1_000_000: level, approver = 1, "팀장" elif total < 5_000_000: level, approver = 2, "부서장" elif total < 10_000_000: level, approver = 3, "본부장" else: level, approver = 4, "임원"

12. 트레이드오프 & 베스트 프랙티스

체이닝은 공짜가 아닙니다. 호출이 늘면 비용과 지연도 늘죠. 하지만 실무에서는 그 이상을 돌려줍니다.

관점 단일 프롬프트 3단계 체이닝
호출 비용 $0.01 $0.03
실패율 20% 5%
재시도 포함 실제 비용 $0.012/건 $0.0315/건
지연 시간 ~2초 ~6초
품질 70% 95%

약간의 비용·지연을 더 내고 재작업 80% 감소, 품질 70%→95%를 얻습니다. 지연은 진행 표시·비동기로, 비용은 모델 계층화(단순 단계는 저렴한 모델)로 완화합니다.

체크리스트

  • ✅ 한 단계 = 한 책임(한 사고 유형). 분류와 생성을 섞지 않는다
  • ✅ 단계 간 데이터는 구조화 출력(Pydantic/JSON)으로 주고받는다
  • ✅ 중요한 단계 뒤에는 품질 게이트 + 자기 수정 루프를 둔다
  • ✅ 각 단계에 전문가 역할(role)을 부여한다
  • ✅ Happy Path 80% + Edge Case 20%를 분리하고, 예외는 명시적으로 에스컬레이션
  • ✅ 프로토타입은 LCEL → 안정화는 Pydantic·게이트 → 프로덕션은 LangGraph
★ 마치며

프롬프트 체이닝은 21개 에이전트 디자인 패턴의 가장 기초이자, 라우팅·병렬화·반성·계획 같은 상위 패턴이 모두 그 위에 세워지는 토대입니다. 출발점은 단순합니다 — “한 번에 시키지 말고, 검증 가능한 단계로 쪼갠다.” 그 한 문장이 정확도·신뢰성·디버깅 가능성을 통째로 바꿉니다.

#PromptChaining#LangChain#LangGraph#GoogleADK#LLM#AgenticAI#Pydantic#엔터프라이즈AI
반응형