Agentic AI Design Patterns

CH11-스스로 채점하는 AI — 목표 설정과 모니터링(Goal Setting & Monitoring) 완벽 정리

빌드 피벗(Build Pivot) 2026. 6. 7. 18:29
반응형
AGENTIC AI DESIGN PATTERNS · 11
스스로 채점하는 AI — 목표 설정과 모니터링(Goal Setting & Monitoring) 완벽 정리
에이전트에 SMART 목표를 주고 스스로 평가·재시도하게 하기: 반복적 자기평가(Generate→Evaluate→Refine) 루프, LLM-as-Judge, Feedback Loop, 순수 Python + LangGraph 구현 2종, Multi-Agent 모니터링과 CRM·ERP·Groupware 적용까지
🟢 입문~중급 ⏱️ 약 17분 🔧 Python · LangGraph · Gemini 🏢 엔터프라이즈

TL;DR — 도구·메모리·MCP로 무엇이든 할 수 있게 된 에이전트. 그런데 "무엇을 향해, 어디까지 잘하고 있는가?"를 묻지 않으면 그저 그럴듯한 출력을 한 번 뱉고 끝입니다. Goal Setting & Monitoring은 에이전트에 SMART 목표를 주고, 스스로 평가하고, 미달성이면 구체적 피드백으로 다시 시도하게 만드는 패턴 — AI의 GPS 내비게이션입니다. 생성 → 평가 → (미달성)피드백 → 재생성 → 달성 핵심은 측정 가능한 목표반복, 그리고 멈출 줄 아는 한계(max_iterations)입니다.

1. 왜 목표 설정인가 — 연결되는 AI에서 스스로 점검하는 AI로

지난 편에서 에이전트는 MCP라는 USB-C 하나로 세상의 모든 시스템에 꽂힐 수 있게 됐습니다. 도구도, 메모리도, 학습도 갖췄죠. 그런데 도구가 많아질수록 새 질문이 생깁니다 — "무엇을 향해, 어디까지 잘하고 있는가?"

기존 LLM 사용 방식의 한계를 보죠. 사용자가 "Python으로 계산기 만들어줘"라고 하면 LLM은 코드를 한 번에 생성합니다. 버그가 있을 수도, 요구사항을 누락했을 수도 있지만 — 그 누구도 확인하지 않은 채 결과가 그대로 전달됩니다. 목표 설정과 모니터링(Goal Setting and Monitoring) 패턴은 여기에 "채점관"을 붙입니다. 명확한 목표를 정하고, 생성물이 그 목표를 달성했는지 스스로 평가하고, 미달성이면 구체적 피드백으로 다시 시도하게 만드는 것이죠.

🧠 일회성 생성 (One-shot)
한 번에 완벽 가정 — 첫 출력이 곧 최종
검증 없음 — 목표 달성 여부를 묻지 않음
누락·버그 그대로 전달
개선 메커니즘 부재 — 틀려도 못 고침
🎯 목표주도 생성 (Goal-Driven)
SMART 목표로 합격 기준을 명시
생성마다 자체 평가 (LLM-as-Judge)
미달성이면 피드백으로 원인 지목
목표 수렴까지 반복 (한계 내에서)
그림 1. 일회성 생성 vs 목표주도 생성 — 같은 작업, 결과 품질이 갈리는 지점

2025년 엔터프라이즈 AI가 이 패턴에 주목하는 이유는 분명합니다. 단순 생성이 아니라 검증된 결과물(신뢰성), 왜 이런 결과가 나왔는지 설명(추적성), 사람 개입을 줄이면서도 품질 보장(자율성), 그리고 무한 재시도가 아닌 목표 지향적 효율(비용)을 동시에 요구하기 때문이죠.

2. 개념과 오해 — 목표는 "프롬프트"가 아니다

📌 한 줄 정의 — AI 에이전트에게 명확한 목표를 부여하고, 목표 달성 여부를 지속적으로 모니터링하며, 미달성 시 스스로 수정하도록 하는 패턴.

주니어 개발자들이 이 패턴에서 가장 많이 빠지는 오해 세 가지를 먼저 짚고 갑니다.

오해 ① "목표 = 단순 프롬프트"라는 착각
"좋은 코드 작성"은 목표가 아니라 소망입니다. 목표는 측정 가능하고 검증 가능한 기준(SMART)이어야 LLM이 합격/불합격을 판정할 수 있습니다.
오해 ② "한 번 실행으로 끝"이라는 오해
핵심은 반복적 자기 평가(Iterative Self-Evaluation)입니다. Generate → Evaluate → Refine 사이클을 목표 달성까지 돌리는 게 본질이죠.
오해 ③ "LLM이 항상 옳다"는 믿음
판정자로 쓰는 LLM-as-Judge도 틀릴 수 있습니다. 중요한 작업은 다단계 검증(다중 LLM·실제 실행·인간 검토)이 필요합니다. (7장에서 자세히)

기억하기 쉬운 비유는 GPS 내비게이션입니다. 목적지 설정(Goal), 현재 위치 파악(Initial State), 경로 계획(Planning), 실시간 위치 추적(Monitoring), 경로 이탈 시 재계산(Feedback & Correction) — 에이전트도 똑같이 동작합니다.

3. SMART 목표 — 측정할 수 없으면 평가할 수 없다

AI 에이전트에게 주는 목표는 SMART 원칙을 따라야 합니다. 핵심은 마지막 두 글자입니다 — M(측정 가능)이 있어야 LLM이 채점할 수 있고, T(시간 제한, 즉 max_iterations)가 있어야 무한 루프를 막을 수 있습니다.

원칙 의미 나쁜 예 ❌ 좋은 예 ✅
Specific (구체적) 명확한 기준 "좋은 코드 작성" "함수당 20줄 이내"
Measurable (측정 가능) 수치화 가능 "빠르게 동작" "응답시간 100ms 이내"
Achievable (달성 가능) 현실적 목표 "버그 0개" "주요 기능 테스트 통과"
Relevant (관련성) 목적에 부합 "이쁜 UI" "사용자 입력 검증"
Time-bound (시간 제한) 제한 조건 "언젠가 완성" "5회 반복 내 완료"
그림 2. SMART 목표 5원칙 — 모호한 소망을 채점 가능한 기준으로

실제 코드에서는 이 목표가 단순한 문자열 리스트로 표현됩니다. 예컨대 계산기를 만든다면 ["4칙연산 지원", "0으로 나누기 예외처리", "모든 메서드에 docstring", "사용 예시 코드 포함"] 처럼요. 각 항목이 곧 합격 체크리스트가 됩니다.

4. 자기평가 루프 — Generate → Evaluate → Refine

패턴의 심장은 반복적 자기 평가 루프입니다. 생성(Generate)하고, 목표 대비 평가(Evaluate)하고, 달성됐으면 종료, 아니면 피드백을 받아 다시 생성합니다. 색으로 역할을 구분해 보면 흐름이 한눈에 들어옵니다 — 주황은 LLM의 일(생성·평가), 파랑은 런타임 분기, 초록은 최종 성공입니다.

1
생성
Generate
목표(+피드백) 기반 코드 생성
2
평가
Evaluate
목표 대비 합격/불합격 판정
3
목표 달성?
Goals Met?
조건부 분기
완료
Complete
Yes → 결과 반환
No + Feedback — ③에서 미달성이면 ②의 피드백을 들고 ①로 되돌아가 재생성 (단, iteration < max_iterations일 때만)
그림 3. 반복적 자기평가 사이클 — 목표 달성 또는 반복 한계까지

평가에 앞서 에이전트는 계획(Planning)을 세우기도 합니다. 목표 상태("사용자 인증 API 구현 완료")와 초기 상태("빈 프로젝트, FastAPI 설치됨")의 간극을 좁히기 위해, 사용 가능한 옵션(JWT/Session/OAuth)을 두고 단계별 실행 계획을 짜는 식이죠. 하지만 어떤 계획을 따르든 결국 매 단계가 위 루프로 검증된다는 점이 핵심입니다.

5. 구현 ① 순수 Python — 명시적 for 루프로 자기평가

프레임워크 없이 Gemini API만으로 패턴의 뼈대를 봅니다. 핵심은 생성기(Generator)와 평가기(Evaluator)의 책임 분리, 그리고 Pydantic으로 평가 결과를 구조화하는 것입니다. 먼저 목표·평가 결과를 데이터 모델로 못 박습니다.

PYTHON · Pydantic 데이터 모델
from pydantic import BaseModel, Field class GoalDefinition(BaseModel): # SMART 목표 정의 description: str = Field(description="목표 설명") criteria: list[str] = Field(description="구체적인 달성 기준 목록") max_iterations: int = Field(default=5, description="최대 반복 횟수") class EvaluationResult(BaseModel): is_satisfied: bool = Field(description="목표 달성 여부") # 루프 종료 신호 feedback: str = Field(description="개선을 위한 피드백") # 다음 시도 입력 satisfied_criteria: list[str] = Field(default=[]) unsatisfied_criteria: list[str] = Field(default=[])

평가는 LLM에게 구조화된 출력 형식을 강제해서 파싱을 쉽게 만듭니다. 자유 형식 답변("덧셈은 잘 됐는데 나눗셈이…")은 파싱이 어렵지만, 약속된 prefix를 쓰게 하면 한 줄씩 잘라 읽을 수 있죠.

PYTHON · 평가 결과 수동 파싱
# LLM에 요청한 출력 형식: # SATISFIED: 1, 2, 3 # UNSATISFIED: 4 # FEEDBACK: ZeroDivisionError 예외 처리 추가 필요 # ALL_GOALS_MET: False for line in response.split('\n'): line = line.strip() if line.startswith('FEEDBACK:'): feedback = line.replace('FEEDBACK:', '').strip() elif line.startswith('ALL_GOALS_MET:'): is_satisfied = line.replace('ALL_GOALS_MET:', '').strip().lower() == 'true'

마지막은 에이전트 본체입니다. range(1, max_iterations + 1) 루프 안에서 생성→평가→분기를 돌고, current_feedback을 다음 시도에 넘기는 것이 전부입니다.

PYTHON · GoalDrivenAgent.run() 핵심 루프
def run(self, task: str, goals: list[str]) -> dict: current_output, current_feedback = None, None for iteration in range(1, self.max_iterations + 1): # Step 1: 코드 생성 (이전 피드백 반영) prompt = create_generation_prompt(task, goals, current_output, current_feedback) generated = generate_content(prompt) # Step 2: 자체 평가 (LLM-as-Judge) evaluation = evaluate_content(generated, goals) # Step 3: 목표 달성 → 즉시 반환 if evaluation.is_satisfied: return {"success": True, "final_code": generated, "iterations": iteration} # Step 4: 피드백을 다음 반복으로 전달 current_output = generated current_feedback = evaluation.feedback # 최대 반복 초과 → 미달성으로 종료 (무한 루프 방지) return {"success": False, "final_code": current_output}

단순하지만 강력합니다. 단일 호출을 자기 개선 시스템으로 바꾸는 최소 단위가 바로 이 루프입니다. 다만 루프·분기·상태가 모두 지역 변수와 if문에 묻혀 있어, 흐름이 복잡해지면 추적이 어렵다는 한계가 있죠. 그래서 LangGraph가 등장합니다.

6. 구현 ② LangGraph — StateGraph로 선언적 루프

2025년 현재 LangChain 팀은 모든 새 에이전트에 LangGraph를 권장합니다. 상태는 StateGraph로 명시화하고, 분기는 if-else 대신 Conditional Edge로 선언하며, 파싱은 Structured Output이 자동으로 해줍니다. 먼저 평가 스키마와 상태를 정의합니다.

PYTHON · Structured Output 스키마 + State
from typing import TypedDict, Literal from langgraph.graph import StateGraph, START, END class Evaluation(BaseModel): grade: Literal["pass", "fail"] # 정확히 두 값만 허용 satisfied_goals: list[str] = [] unsatisfied_goals: list[str] = [] feedback: str confidence: float = 0.8 # 평가 신뢰도 0.0~1.0 evaluator_llm = llm.with_structured_output(Evaluation) # 자동 파싱! class AgentState(TypedDict): # 그래프 전역 상태 task: str; goals: list[str] generated_code: str; previous_code: str evaluation_grade: str; feedback: str iteration: int; max_iterations: int history: list[dict]

노드는 State를 입력받아 바꿀 필드만 dict로 반환하는 함수입니다. 평가 노드는 evaluator_llm.invoke() 한 줄로 파싱 없이 Evaluation 객체를 받습니다 — 5절의 수동 파싱이 통째로 사라지죠.

PYTHON · 평가 노드 + 조건부 분기 함수
def evaluator_node(state: AgentState) -> dict: # Structured Output → 수동 파싱 불필요 evaluation: Evaluation = evaluator_llm.invoke(eval_prompt) return { "evaluation_grade": evaluation.grade, "feedback": evaluation.feedback, "history": state.get("history", []) + [{...}], # 누적 } def should_continue(state) -> Literal["generator", "__end__"]: if state["evaluation_grade"] == "pass": # 달성 → 종료 return END if state["iteration"] >= state["max_iterations"]: # 한계 → 종료 return END return "generator" # 미달성 → 재시도

마지막으로 노드와 엣지를 엮어 그래프를 빌드합니다. add_conditional_edgesshould_continue의 반환값으로 다음 노드를 고르는 것이 핵심입니다.

PYTHON · 그래프 빌드 (START → generator → evaluator → 분기)
builder = StateGraph(AgentState) builder.add_node("generator", generator_node) builder.add_node("evaluator", evaluator_node) builder.add_edge(START, "generator") # 시작 → 생성 builder.add_edge("generator", "evaluator") # 생성 → 평가 builder.add_conditional_edges( # 평가 → 분기 "evaluator", should_continue, {"generator": "generator", END: END}, ) graph = builder.compile() # 실행 가능한 그래프로 final_state = graph.invoke(initial_state) # 암묵적 루프 실행

5절의 for 루프가 그래프의 엣지로, if문이 조건부 엣지로, 지역 변수가 State로 바뀐 것뿐입니다. 그런데 이 "선언적 전환" 덕에 상태 추적·시각화·체크포인트 재시작이 전부 따라옵니다.

7. LLM-as-Judge — 판정자도 틀린다

이 패턴의 평가 단계는 결국 LLM이 LLM의 결과물을 채점하는 구조입니다(LLM-as-Judge). 편리하지만, 채점관 자신이 틀릴 수 있다는 점을 잊으면 위험합니다. 그럴듯하지만 틀린 평가가 통과되면, 잘못된 결과물이 "목표 달성" 도장을 받고 나가버리니까요.

⚠️ 순진한 LLM-as-Judge
단일 LLM이 단독 판정 → 편향 그대로
코드를 읽기만 하고 실행 안 함
"True"라고 하면 그대로 신뢰
🛡️ 다단계 검증
다중 LLM 교차 검증 — 서로 다른 판정 비교
실제 실행 테스트 — 린터·테스트로 객관 검증
Human-in-the-Loop — 고위험 결정은 사람이
그림 4. LLM-as-Judge의 함정과 다단계 검증

LangGraph 구현에서 Evaluation.confidence(0.0~1.0)를 둔 이유가 여기 있습니다. 평가의 신뢰도가 낮으면 자동 통과시키지 말고 사람에게 에스컬레이션하라는 신호로 쓸 수 있죠. "LLM이 항상 옳다"는 가정 대신, 판정에도 안전장치를 둔다는 것이 성숙한 설계입니다.

8. 두 구현 비교 — 같은 목표, 다른 추상화

순수 Python과 LangGraph는 같은 자기평가 루프를 구현하지만, 추상화 수준이 다릅니다. 간단한 작업이면 Python이 빠르고, 노드가 늘거나 재시작·시각화가 필요하면 LangGraph가 유리합니다.

측면 ① 순수 Python ② LangGraph
루프 명시적 for 그래프 엣지(암묵적)
분기 if-else Conditional Edge
상태 지역 변수 StateGraph (TypedDict)
파싱 수동(문자열 prefix) Structured Output(자동)
시각화 불가 Mermaid 지원
확장성 제한적 높음(노드 추가 용이)
학습 곡선 낮음 중간
그림 5. 순수 Python vs LangGraph — 같은 루프, 다른 추상화 수준

LangGraph가 주는 네 가지 추가 능력 — 명시적 상태 관리, 조건부 분기, Human-in-the-Loop 삽입, 체크포인트 영속성(장시간 작업 중단 후 실패 지점부터 재개) — 은 엔터프라이즈로 갈수록 가치가 커집니다.

9. Multi-Agent Goal Monitoring — 전문가들의 합격선

복잡한 작업에서는 단일 에이전트 대신 여러 전문가 에이전트가 협력합니다(7장 멀티 에이전트와 연결). 각자 다른 목표를 갖고, 그 위에서 Goal Monitor가 "모든 에이전트의 결과물이 목표에 부합하는가?"를 검증하며 미달성 시 해당 에이전트에게 재작업을 요청합니다.

👨‍💻 Peer Programmer
기능 요구사항 100% 구현
🔎 Code Reviewer
코드 품질 점수 80점 이상
🧪 Test Writer
테스트 커버리지 70% 이상
📄 Documenter
모든 public 함수 docstring
↓ 결과물 검증 ↓
🎯 Goal Monitor (목표 모니터)
각 에이전트 결과물이 목표에 부합하는지 검증 → 미달성 시 해당 에이전트에게 재작업 요청
그림 6. Multi-Agent 목표 모니터링 — 전문가별 목표 + 통합 감시자

여기에 Prompt Refiner(명확성 점수 90점 이상)까지 더하면, 프롬프트 자체를 개선하는 메타 에이전트도 같은 목표-모니터링 틀 안에서 동작합니다. 핵심은 모두가 측정 가능한 목표를 갖고, 한 명의 모니터가 합격선을 지킨다는 점입니다.

10. 엔터프라이즈 — CRM·ERP·Groupware의 Goal-Driven ROI

레거시 시스템의 고통점은 공통적으로 "사후에야 안다"입니다. CRM은 응대 품질을 표본 10%만 사후 검토하고, ERP는 재고가 부족해진 뒤에야 발주하며, Groupware는 프로젝트 지연을 주간 보고에서야 발견하죠. Goal-Driven Agent는 이를 실시간 목표 모니터링으로 바꿉니다.

영역 Goal-Driven 적용 개선 지표 연간 효과
CRM 응대 품질 자동 검증·재생성 응대 시간 40%↓ $120,000
CRM 일관된 품질로 만족도↑ 고객 만족도 15%↑ $80,000
ERP 적정 재고 목표 실시간 추적 재고 비용 30%↓ $150,000
ERP 발주 제안·자동 승인 발주 프로세스 50%↓ $40,000
Groupware 마일스톤 일일 모니터링 프로젝트 지연 20%↓ $60,000
Groupware 회의 Action Item 추적 회의 효율 30%↑ $30,000
합계 연간 총 비용 $315,000 ROI 52.4% $480,000
그림 7. Goal-Driven Agent의 엔터프라이즈 ROI (12개월 기준)

총 효과 $480,000 대비 연간 총 비용 $315,000(초기 $240,000 + 운영 $75,000) — ROI 52.4%, 투자 회수 기간 7.9개월입니다. 도입은 3단계로 권장됩니다: Phase 1 PoC(1~3개월·CRM 1팀·$50K·품질 10%↑) → Phase 2 파일럿(4~6개월·CRM+ERP·$100K·ROI 20%+) → Phase 3 전사(7~12개월·전체·$165K·ROI 50%+). 기술 스택은 LangGraph + Gemini 2.0 + LangSmith(관찰)를 권장합니다.

11. 케이스 스터디 — CRM 고객 응대 품질 자동 관리

지금까지의 조각을 하나로 꿰어 봅니다. 목표는 SMART로 정의됩니다 — S: 5가지 품질 기준 충족 / M: 품질 점수 85점 이상 / A: AI가 자체 평가 가능 / R: 고객 만족도와 직접 연관 / T: 응답 생성 후 3초 이내 평가. 고객 문의가 들어오면 다음 5단계가 돕니다.

1
응대 생성
고객 문의에 AI 답변 작성
2
목표 검증
5개 체크리스트 채점
3
미달 감지
"후속 안내 누락" 발견
4
재생성
피드백 반영해 보완
전송
모든 목표 달성 → 발송
체크리스트: ☑ 고객 이름 호칭 · ☑ 문의 내용 이해 · ☑ 해결책 제시 · ☐ 후속 안내(미달) · ☑ 친절한 어조 → 4번에서 보완
그림 8. CRM 응대 품질 자동 관리 — 사람이 보내기 전에 AI가 합격선을 지킨다

기존엔 표본 10%만 사후 검토하고 피드백이 2~3일 뒤에 왔지만, 이제는 모든 응대가 전송 전에 100% 검증됩니다. 같은 틀을 ERP 발주(적정 재고 목표)·Groupware 프로젝트(마일스톤 목표)에 그대로 복제할 수 있습니다.

12. 베스트 프랙티스 — 쓸 자리와 피할 자리

✅ 쓸 자리
합격 기준이 명확한 작업(코드·문서·응대 품질)
한 번에 못 맞히는 복잡한 생성물
품질 일관성이 비용보다 중요할 때
⛔ 피할 자리
목표를 수치화 불가(주관적 "느낌")한 작업
한 번 호출로 충분한 단순 작업(오버헤드만 증가)
저지연 필수인데 반복 비용을 못 감당할 때
📋 도입 체크리스트
☐ 목표를 SMART로 정의했는가 (특히 M·T)
max_iterations로 무한 루프를 막았는가
☐ 피드백이 구체적·행동 가능한가 ("좋지 않음" ✗ → "ZeroDivisionError 처리 추가" ✓)
☐ LLM-as-Judge에 다단계 검증·HITL을 두었는가
☐ 모든 반복을 로깅해 추적성을 확보했는가 (LangSmith)
☐ PoC → 파일럿 → 전사로 점진 확대하는가
★ 마치며

"순서대로 쪼개라"가 체이닝, "입력에 따라 길을 나눠라"가 라우팅, "독립 작업은 동시에"가 병렬화, "쓴 다음 읽고 고쳐라"가 리플렉션, "모르면 도구를 써라"가 도구 사용, "언제 어떤 순서로 쓸지 계획하라"가 플래닝, "전문가가 협력하라"가 멀티 에이전트, "겪은 것을 기억하라"가 메모리, "겪은 것에서 배워라"가 학습, "하나의 표준으로 외부와 연결하라"가 MCP였다면 — 목표 설정과 모니터링은 "무엇을 향해, 어디까지 왔는지 스스로 점검하라"입니다. 이제 에이전트는 자기 출력을 채점하고 합격선까지 고쳐 씁니다. 그런데 채점하고 고치는 과정에서도 일은 언제든 실패합니다 — API 타임아웃, 도구 오류, 예측 못 한 입력. 다음 편 예외 처리와 복구(Exception Handling & Recovery)에서는 에이전트가 넘어져도 다시 일어서는 법 — 재시도·백오프·서킷 브레이커·폴백 — 을 다룹니다.

시리즈: 01 Prompt Chaining → 02 Routing → 03 Parallelization → 04 Reflection → 05 Tool Use → 06 Planning → 07 Multi-Agent → 08 Memory → 09 Learning & Adaptation → 10 Model Context Protocol → 11 Goal Setting & Monitoring → (다음) 12 Exception Handling

#GoalSetting #목표설정 #SMART목표 #LLMasJudge #LangGraph #AI에이전트 #FeedbackLoop #생성형AI

안내: 본 글은 Agentic AI Design Patterns 학습 자료(교재·패턴정의·엔터프라이즈 적용전략·구현 2종)를 재구성한 교육용 콘텐츠입니다. 코드는 개념 설명용 예시이며, 프레임워크 API는 버전에 따라 달라질 수 있습니다.

반응형