초안 에이전틱 디자인 패턴 - 목표 설정
복잡한 목표를 자율적으로 분해하고 진행 상황을 추적하며 전략을 적응시킬 수 있는 지능형 에이전트를 구축하세요 - 모두 Vercel의 서버리스 인프라에서 효율적으로 실행됩니다.
멘탈 모델: 프로젝트 매니저 에이전트
목표 설정 에이전트를 고수준 목표를 받아 실행 가능한 작업으로 분해하는 전문 프로젝트 매니저로 생각해보세요. PM이 "새 제품 출시"를 스프린트, 작업, 하위 작업으로 분해하면서 진행 상황을 모니터링하고 계획을 조정하는 것처럼, 우리 에이전트는 목표를 계층적 구조로 분해하고 실행 상태를 추적하며 진행 상황에 따라 전략을 적응시킬 것입니다 - 모두 TypeScript와 LangGraph의 그래프 기반 오케스트레이션을 통해 구현됩니다.
기본 예제: 간단한 목표 분해 에이전트
1. 목표 에이전트 상태 정의
// app/agents/goal/state.ts
import { Annotation } from "@langchain/langgraph";
import { BaseMessage } from "@langchain/core/messages";
export const GoalAgentState = Annotation.Root({
messages: Annotation<BaseMessage[]>({
reducer: (current, update) => current.concat(update),
default: () => []
}),
currentGoal: Annotation<string>({
reducer: (current, update) => update || current,
default: () => ""
}),
subGoals: Annotation<string[]>({
reducer: (current, update) => {
if (Array.isArray(update)) return update;
return current.concat(update);
},
default: () => []
}),
completedSubGoals: Annotation<string[]>({
reducer: (current, update) => current.concat(update),
default: () => []
}),
goalStatus: Annotation<"planning" | "executing" | "completed" | "failed">({
reducer: (current, update) => update || current,
default: () => "planning"
})
});
이 상태 스키마는 LangGraph의 타입 안전한 Annotation 시스템을 사용하여 목표 계층 구조와 실행 상태를 추적합니다.
2. 목표 분해 노드 생성
// app/agents/goal/nodes/decompose.ts
import { ChatGoogleGenerativeAI } from "@langchain/google-genai";
import { HumanMessage, AIMessage } from "@langchain/core/messages";
import { z } from "zod";
import { zodToJsonSchema } from "zod-to-json-schema";
import { map, chunk } from "es-toolkit";
const SubGoalsSchema = z.object({
subGoals: z.array(z.object({
task: z.string().describe("구체적이고 실행 가능한 작업"),
priority: z.number().min(1).max(5).describe("우선순위 1-5"),
dependencies: z.array(z.string()).describe("먼저 완료해야 하는 작업들")
}))
});
export async function decomposeGoal(state: typeof GoalAgentState.State) {
const model = new ChatGoogleGenerativeAI({
modelName: "gemini-pro",
temperature: 0.3
});
const prompt = `다음 목표를 구체적이고 실행 가능한 하위 작업들로 분해하세요:
목표: ${state.currentGoal}
작업 간의 의존성을 고려하고 우선순위를 배정하세요.`;
const response = await model.invoke([
new HumanMessage(prompt)
], {
functions: [{
name: "decompose_goal",
description: "목표를 하위 작업들로 분해",
parameters: zodToJsonSchema(SubGoalsSchema)
}],
function_call: { name: "decompose_goal" }
});
const functionCall = response.additional_kwargs.function_call;
const decomposition = JSON.parse(functionCall?.arguments || "{}");
// 우선순위와 의존성으로 정렬
const sortedGoals = decomposition.subGoals
.sort((a: any, b: any) => {
if (a.dependencies.length === 0 && b.dependencies.length > 0) return -1;
if (b.dependencies.length === 0 && a.dependencies.length > 0) return 1;
return b.priority - a.priority;
});
const subGoalTasks = map(sortedGoals, (goal: any) => goal.task);
return {
messages: [response],
subGoals: subGoalTasks,
goalStatus: "executing" as const
};
}
분해 노드는 구조화된 출력을 사용하여 목표를 우선순위가 지정되고 의존성을 인식하는 하위 작업으로 분해합니다.
3. 목표 에이전트 그래프 구축
// app/agents/goal/graph.ts
import { StateGraph, END } from "@langchain/langgraph";
import { GoalAgentState } from "./state";
import { decomposeGoal } from "./nodes/decompose";
import { executeSubGoal } from "./nodes/execute";
import { evaluateProgress } from "./nodes/evaluate";
export function createGoalAgent() {
const workflow = new StateGraph(GoalAgentState)
.addNode("decompose", decomposeGoal)
.addNode("execute", executeSubGoal)
.addNode("evaluate", evaluateProgress)
.addEdge("decompose", "execute")
.addEdge("execute", "evaluate")
.addConditionalEdges(
"evaluate",
async (state) => {
if (state.goalStatus === "completed") return "end";
if (state.subGoals.length > state.completedSubGoals.length) return "execute";
return "end";
},
{
execute: "execute",
end: END
}
);
return workflow.compile();
}
그래프는 완료될 때까지 목표 분해, 실행, 진행 상황 평가를 루프로 오케스트레이션합니다.
4. API 라우트 핸들러
// app/api/agent/goal/route.ts
import { NextRequest, NextResponse } from "next/server";
import { createGoalAgent } from "@/agents/goal/graph";
import { HumanMessage } from "@langchain/core/messages";
export async function POST(req: NextRequest) {
const { goal } = await req.json();
const agent = createGoalAgent();
const result = await agent.invoke({
messages: [new HumanMessage(`목표 달성: ${goal}`)],
currentGoal: goal
});
return NextResponse.json({
goal,
subGoals: result.subGoals,
completedSubGoals: result.completedSubGoals,
status: result.goalStatus
});
}
서버리스 환경에서 목표 처리를 트리거하는 간단한 API 엔드포인트입니다.
5. 프론트엔드 통합
// app/components/GoalTracker.tsx
"use client";
import { useMutation, useQuery } from "@tanstack/react-query";
import { useState } from "react";
import { groupBy } from "es-toolkit";
export function GoalTracker() {
const [goal, setGoal] = useState("");
const goalMutation = useMutation({
mutationFn: async (goal: string) => {
const res = await fetch("/api/agent/goal", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ goal })
});
return res.json();
}
});
return (
<div className="card bg-base-100 shadow-xl">
<div className="card-body">
<h2 className="card-title">목표 설정 에이전트</h2>
<input
type="text"
placeholder="목표를 입력하세요..."
className="input input-bordered w-full"
value={goal}
onChange={(e) => setGoal(e.target.value)}
/>
<button
className="btn btn-primary"
onClick={() => goalMutation.mutate(goal)}
disabled={goalMutation.isPending}
>
{goalMutation.isPending ? "처리중..." : "목표 설정"}
</button>
{goalMutation.data && (
<div className="mt-4">
<div className="badge badge-outline">
{goalMutation.data.status}
</div>
<div className="divider">하위 목표</div>
<ul className="space-y-2">
{goalMutation.data.subGoals.map((subGoal: string, idx: number) => (
<li key={idx} className="flex items-center gap-2">
<input
type="checkbox"
className="checkbox checkbox-sm"
checked={goalMutation.data.completedSubGoals.includes(subGoal)}
readOnly
/>
<span className="text-sm">{subGoal}</span>
</li>
))}
</ul>
</div>
)}
</div>
</div>
);
}
목표 제출 및 진행 상황 추적을 위한 TanStack Query가 있는 React 컴포넌트입니다.
고급 예제: 자율적 목표 모니터링 시스템
1. 모니터링 메트릭이 포함된 강화된 상태
// app/agents/advanced-goal/state.ts
import { Annotation } from "@langchain/langgraph";
import { BaseMessage } from "@langchain/core/messages";
interface GoalMetrics {
startTime: number;
estimatedCompletion: number;
actualProgress: number;
blockers: string[];
adjustments: number;
}
export const AdvancedGoalState = Annotation.Root({
messages: Annotation<BaseMessage[]>({
reducer: (current, update) => current.concat(update),
default: () => []
}),
currentGoal: Annotation<string>(),
subGoals: Annotation<Array<{
id: string;
task: string;
status: "pending" | "in_progress" | "completed" | "failed";
progress: number;
dependencies: string[];
estimatedHours: number;
actualHours: number;
}>>({
reducer: (current, update) => {
if (Array.isArray(update)) return update;
// 기존 하위 목표에 대한 업데이트 병합
return current.map(goal => {
const updateItem = update.find((u: any) => u.id === goal.id);
return updateItem ? { ...goal, ...updateItem } : goal;
});
},
default: () => []
}),
metrics: Annotation<GoalMetrics>({
reducer: (current, update) => ({ ...current, ...update }),
default: () => ({
startTime: Date.now(),
estimatedCompletion: 0,
actualProgress: 0,
blockers: [],
adjustments: 0
})
}),
strategy: Annotation<"waterfall" | "parallel" | "adaptive">({
default: () => "adaptive"
}),
humanApproval: Annotation<boolean>({
default: () => false
})
});
고급 상태에는 상세한 메트릭, 전략 선택, 인간 개입 플래그가 포함됩니다.
2. 의존성이 있는 지능형 목표 계획
// app/agents/advanced-goal/nodes/planner.ts
import { ChatGoogleGenerativeAI } from "@langchain/google-genai";
import { z } from "zod";
import { partition, sortBy, filter } from "es-toolkit";
import { v4 as uuidv4 } from "uuid";
const PlanSchema = z.object({
plan: z.object({
approach: z.string(),
reasoning: z.string(),
subGoals: z.array(z.object({
task: z.string(),
estimatedHours: z.number(),
dependencies: z.array(z.string()),
skills: z.array(z.string()),
priority: z.enum(["critical", "high", "medium", "low"])
})),
risks: z.array(z.string()),
successCriteria: z.array(z.string())
})
});
export async function createExecutionPlan(state: typeof AdvancedGoalState.State) {
const model = new ChatGoogleGenerativeAI({
modelName: "gemini-pro",
temperature: 0.2
});
const planningPrompt = `다음 목표에 대한 상세한 실행 계획을 수립하세요:
목표: ${state.currentGoal}
목표를 분석하고 다음을 제공하세요:
1. 전반적인 접근 방식과 논리
2. 시간 추정이 포함된 상세한 하위 작업
3. 작업 의존성 (다른 작업이 완료되어야 하는 작업들)
4. 각 작업에 필요한 기술/리소스
5. 잠재적 위험과 차단 요소
6. 명확한 성공 기준
병렬 실행 기회와 임계 경로 최적화를 고려하세요.`;
const response = await model.withStructuredOutput(PlanSchema).invoke([
{ role: "system", content: "당신은 목표 분해와 실행 전략을 전문으로 하는 전문 프로젝트 기획자입니다." },
{ role: "user", content: planningPrompt }
]);
// 계획을 실행 가능한 하위 목표로 변환
const subGoals = response.plan.subGoals.map((goal, idx) => ({
id: uuidv4(),
task: goal.task,
status: "pending" as const,
progress: 0,
dependencies: goal.dependencies,
estimatedHours: goal.estimatedHours,
actualHours: 0,
priority: goal.priority
}));
// 예상 완료 시간 계산
const criticalPath = calculateCriticalPath(subGoals);
const estimatedCompletion = Date.now() + (criticalPath * 60 * 60 * 1000);
// 최적 전략 결정
const [independent, dependent] = partition(
subGoals,
g => g.dependencies.length === 0
);
const strategy = independent.length > dependent.length ? "parallel" : "waterfall";
return {
subGoals,
metrics: {
estimatedCompletion,
actualProgress: 0,
blockers: response.plan.risks,
adjustments: 0
},
strategy,
messages: [{
role: "assistant",
content: `계획 생성됨: ${response.plan.approach}\n전략: ${strategy}`
}]
};
}
function calculateCriticalPath(goals: any[]): number {
// 간단한 임계 경로 계산
const goalMap = new Map(goals.map(g => [g.task, g]));
const calculatePath = (goalId: string, visited = new Set()): number => {
if (visited.has(goalId)) return 0;
visited.add(goalId);
const goal = goalMap.get(goalId);
if (!goal) return 0;
const depTimes = goal.dependencies.map((d: string) =>
calculatePath(d, visited)
);
return goal.estimatedHours + Math.max(0, ...depTimes);
};
return Math.max(...goals.map(g => calculatePath(g.task)));
}
고급 플래너는 의존성 분석과 임계 경로 최적화가 포함된 상세한 실행 계획을 수립합니다.
3. 모니터링이 포함된 병렬 실행
// app/agents/advanced-goal/nodes/executor.ts
import { Send } from "@langchain/langgraph";
import { filter, map, take } from "es-toolkit";
export async function parallelExecutor(state: typeof AdvancedGoalState.State) {
// 실행 가능한 하위 목표 찾기 (대기 중인 의존성이 없는 것)
const executableGoals = filter(state.subGoals, goal => {
if (goal.status !== "pending") return false;
const deps = goal.dependencies;
if (deps.length === 0) return true;
return deps.every(depTask => {
const depGoal = state.subGoals.find(g => g.task === depTask);
return depGoal?.status === "completed";
});
});
if (executableGoals.length === 0) {
return { goalStatus: "blocked" };
}
// 최대 3개의 목표를 병렬로 실행
const toExecute = take(executableGoals, 3);
// 병렬 실행을 위한 Send API 사용
return toExecute.map(goal =>
new Send("execute_single", {
goalId: goal.id,
task: goal.task,
parentGoal: state.currentGoal
})
);
}
export async function executeSingleGoal({ goalId, task, parentGoal }: any) {
// 진행 상황 업데이트와 함께 목표 실행 시뮬레이션
const steps = 5;
const updates = [];
for (let i = 1; i <= steps; i++) {
await new Promise(resolve => setTimeout(resolve, 100)); // 작업 시뮬레이션
updates.push({
id: goalId,
progress: (i / steps) * 100,
actualHours: (i / steps) * 2
});
}
return {
subGoals: [{
id: goalId,
status: "completed",
progress: 100
}],
messages: [{
role: "assistant",
content: `완료됨: ${task}`
}]
};
}
병렬 실행기는 독립적인 작업을 식별하고 LangGraph의 Send API를 사용하여 동시에 실행합니다.
4. 실시간 모니터링 및 적응
// app/agents/advanced-goal/nodes/monitor.ts
import { ChatGoogleGenerativeAI } from "@langchain/google-genai";
import { mean, sum, filter } from "es-toolkit";
export async function monitorAndAdapt(state: typeof AdvancedGoalState.State) {
const model = new ChatGoogleGenerativeAI({ modelName: "gemini-pro" });
// 진행 메트릭 계산
const completedCount = filter(state.subGoals, g => g.status === "completed").length;
const totalCount = state.subGoals.length;
const overallProgress = (completedCount / totalCount) * 100;
// 지연 확인
const actualHours = sum(state.subGoals.map(g => g.actualHours));
const estimatedHours = sum(state.subGoals.map(g => g.estimatedHours));
const scheduleVariance = ((actualHours - estimatedHours) / estimatedHours) * 100;
// 차단 요소 식별
const stuckGoals = filter(state.subGoals,
g => g.status === "in_progress" && g.progress < 30
);
// 적응형 전략 조정
if (scheduleVariance > 20 || stuckGoals.length > 0) {
const adaptationPrompt = `현재 목표 진행 상황:
- 전체: ${overallProgress.toFixed(1)}%
- 일정 편차: ${scheduleVariance.toFixed(1)}%
- 차단된 작업: ${stuckGoals.map(g => g.task).join(", ")}
궤도에 다시 오르기 위한 전략 조정을 제안하세요.`;
const response = await model.invoke([
{ role: "system", content: "당신은 프로젝트 복구 전문가입니다." },
{ role: "user", content: adaptationPrompt }
]);
// 필요시 재계획 트리거
if (scheduleVariance > 50) {
return {
strategy: "adaptive" as const,
metrics: {
adjustments: state.metrics.adjustments + 1,
actualProgress: overallProgress
},
messages: [response],
humanApproval: true // 주요 변경사항에 대한 인간 승인 요청
};
}
}
return {
metrics: {
actualProgress: overallProgress
},
goalStatus: overallProgress === 100 ? "completed" : "executing"
};
}
모니터는 지속적으로 진행 상황을 추적하고 병목 지점을 식별하며 필요할 때 적응형 재계획을 트리거합니다.
5. 장기 실행 목표를 위한 지속성 레이어
// app/agents/advanced-goal/persistence.ts
import { kv } from "@vercel/kv";
import { SqliteSaver } from "@langchain/langgraph-checkpoint-sqlite";
export class GoalPersistence {
private checkpointer: SqliteSaver;
constructor() {
this.checkpointer = new SqliteSaver("/tmp/goals.db");
}
async saveGoalState(goalId: string, state: any) {
// 빠른 액세스를 위해 Vercel KV에 저장
await kv.hset(`goal:${goalId}`, {
currentGoal: state.currentGoal,
status: state.goalStatus,
progress: state.metrics.actualProgress,
subGoals: JSON.stringify(state.subGoals),
lastUpdated: Date.now()
});
// 30일 만료 설정
await kv.expire(`goal:${goalId}`, 30 * 24 * 60 * 60);
}
async getGoalState(goalId: string) {
const state = await kv.hgetall(`goal:${goalId}`);
if (state && state.subGoals) {
state.subGoals = JSON.parse(state.subGoals as string);
}
return state;
}
async getActiveGoals(userId: string) {
const pattern = `goal:${userId}:*`;
const keys = await kv.keys(pattern);
const goals = await Promise.all(
keys.map(key => kv.hgetall(key))
);
return goals.filter(g => g && g.status !== "completed");
}
}
지속성 레이어는 Vercel KV를 사용하여 상태 저장을 하므로 서버리스 함수 호출 간에도 목표 추적이 가능합니다.
6. 인간 개입이 포함된 완전한 그래프
// app/agents/advanced-goal/graph.ts
import { StateGraph, END } from "@langchain/langgraph";
import { AdvancedGoalState } from "./state";
import { createExecutionPlan } from "./nodes/planner";
import { parallelExecutor, executeSingleGoal } from "./nodes/executor";
import { monitorAndAdapt } from "./nodes/monitor";
export function createAdvancedGoalAgent() {
const workflow = new StateGraph(AdvancedGoalState)
.addNode("plan", createExecutionPlan)
.addNode("parallel_execute", parallelExecutor)
.addNode("execute_single", executeSingleGoal)
.addNode("monitor", monitorAndAdapt)
.addNode("human_review", async (state) => {
// 인간 입력을 위한 인터럽트
return interrupt({
message: "계획 조정이 필요합니다",
currentPlan: state.subGoals,
suggestedChanges: state.messages[state.messages.length - 1]
});
});
// 엣지 정의
workflow
.addEdge("plan", "parallel_execute")
.addEdge("execute_single", "monitor")
.addEdge("parallel_execute", "monitor")
.addConditionalEdges(
"monitor",
async (state) => {
if (state.humanApproval) return "human_review";
if (state.goalStatus === "completed") return "end";
if (state.goalStatus === "blocked") return "plan";
return "parallel_execute";
},
{
human_review: "human_review",
plan: "plan",
parallel_execute: "parallel_execute",
end: END
}
)
.addEdge("human_review", "plan");
return workflow.compile({
checkpointer: new SqliteSaver("/tmp/advanced_goals.db")
});
}
완전한 그래프는 필요할 때 계획, 병렬 실행, 모니터링, 인간 개입을 오케스트레이션합니다.
7. 실시간 스트리밍 API
// app/api/agent/advanced-goal/stream/route.ts
import { NextRequest } from "next/server";
import { createAdvancedGoalAgent } from "@/agents/advanced-goal/graph";
import { GoalPersistence } from "@/agents/advanced-goal/persistence";
export async function POST(req: NextRequest) {
const { goal, userId } = await req.json();
const goalId = `${userId}:${Date.now()}`;
const persistence = new GoalPersistence();
const encoder = new TextEncoder();
const stream = new ReadableStream({
async start(controller) {
const agent = createAdvancedGoalAgent();
// 이벤트가 발생할 때마다 스트림
for await (const event of agent.stream({
currentGoal: goal,
messages: []
}, {
streamMode: "updates",
configurable: { thread_id: goalId }
})) {
// 진행 상황 업데이트 전송
const update = {
type: "progress",
goalId,
data: event
};
controller.enqueue(
encoder.encode(`data: ${JSON.stringify(update)}\n\n`)
);
// 주기적으로 상태 저장
if (event.monitor) {
await persistence.saveGoalState(goalId, event.monitor);
}
}
controller.close();
}
});
return new Response(stream, {
headers: {
"Content-Type": "text/event-stream",
"Cache-Control": "no-cache",
"Connection": "keep-alive",
},
});
}
스트리밍 API는 목표가 처리될 때 실시간 업데이트를 제공하므로 진행 상황 추적 UI에 완벽합니다.
8. 고급 프론트엔드 대시보드
// app/components/AdvancedGoalDashboard.tsx
"use client";
import { useState, useEffect } from "react";
import { useQuery, useMutation } from "@tanstack/react-query";
import { groupBy, sortBy, filter } from "es-toolkit";
interface Goal {
id: string;
task: string;
status: string;
progress: number;
dependencies: string[];
}
export function AdvancedGoalDashboard() {
const [goalInput, setGoalInput] = useState("");
const [streamData, setStreamData] = useState<any[]>([]);
const startGoal = useMutation({
mutationFn: async (goal: string) => {
const response = await fetch("/api/agent/advanced-goal/stream", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ goal, userId: "user123" })
});
if (!response.body) throw new Error("스트림 없음");
const reader = response.body.getReader();
const decoder = new TextDecoder();
while (true) {
const { done, value } = await reader.read();
if (done) break;
const chunk = decoder.decode(value);
const lines = chunk.split("\n");
for (const line of lines) {
if (line.startsWith("data: ")) {
const data = JSON.parse(line.slice(6));
setStreamData(prev => [...prev, data]);
}
}
}
}
});
// 상태별로 목표 그룹화
const latestUpdate = streamData[streamData.length - 1];
const subGoals = latestUpdate?.data?.monitor?.subGoals || [];
const goalsByStatus = groupBy(subGoals, (g: Goal) => g.status);
return (
<div className="container mx-auto p-4">
<div className="card bg-base-100 shadow-xl mb-6">
<div className="card-body">
<h2 className="card-title text-2xl">고급 목표 설정 및 모니터링</h2>
<div className="form-control">
<div className="input-group">
<input
type="text"
placeholder="목표를 입력하세요..."
className="input input-bordered flex-1"
value={goalInput}
onChange={(e) => setGoalInput(e.target.value)}
/>
<button
className="btn btn-primary"
onClick={() => startGoal.mutate(goalInput)}
disabled={startGoal.isPending}
>
{startGoal.isPending ? (
<span className="loading loading-spinner"></span>
) : (
"목표 시작"
)}
</button>
</div>
</div>
</div>
</div>
{subGoals.length > 0 && (
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
{/* 대기 중인 작업 */}
<div className="card bg-base-200">
<div className="card-body">
<h3 className="card-title text-lg">
대기중 ({goalsByStatus.pending?.length || 0})
</h3>
<div className="space-y-2">
{(goalsByStatus.pending || []).map((goal: Goal) => (
<div key={goal.id} className="bg-base-100 p-3 rounded">
<div className="text-sm font-medium">{goal.task}</div>
{goal.dependencies.length > 0 && (
<div className="text-xs text-base-content/60 mt-1">
다음을 기다리는 중: {goal.dependencies.join(", ")}
</div>
)}
</div>
))}
</div>
</div>
</div>
{/* 진행 중 */}
<div className="card bg-warning/20">
<div className="card-body">
<h3 className="card-title text-lg">
진행중 ({goalsByStatus.in_progress?.length || 0})
</h3>
<div className="space-y-2">
{(goalsByStatus.in_progress || []).map((goal: Goal) => (
<div key={goal.id} className="bg-base-100 p-3 rounded">
<div className="text-sm font-medium">{goal.task}</div>
<progress
className="progress progress-warning w-full mt-2"
value={goal.progress}
max="100"
/>
<div className="text-xs text-right mt-1">
{goal.progress}%
</div>
</div>
))}
</div>
</div>
</div>
{/* 완료됨 */}
<div className="card bg-success/20">
<div className="card-body">
<h3 className="card-title text-lg">
완료됨 ({goalsByStatus.completed?.length || 0})
</h3>
<div className="space-y-2">
{(goalsByStatus.completed || []).map((goal: Goal) => (
<div key={goal.id} className="bg-base-100 p-3 rounded">
<div className="text-sm font-medium line-through">
{goal.task}
</div>
<div className="badge badge-success badge-sm mt-1">
완료
</div>
</div>
))}
</div>
</div>
</div>
</div>
)}
{/* 실시간 업데이트 피드 */}
{streamData.length > 0 && (
<div className="card bg-base-100 shadow-xl mt-6">
<div className="card-body">
<h3 className="card-title">실시간 업데이트</h3>
<div className="h-48 overflow-y-auto space-y-1">
{streamData.slice(-10).reverse().map((update, idx) => (
<div key={idx} className="text-sm">
<span className="badge badge-ghost badge-sm mr-2">
{new Date().toLocaleTimeString()}
</span>
<span className="text-base-content/80">
{update.type}: {JSON.stringify(update.data).slice(0, 100)}...
</span>
</div>
))}
</div>
</div>
</div>
)}
</div>
);
}
실시간 스트리밍 업데이트, 칸반 스타일 작업 시각화, 진행 상황 추적이 포함된 모든 기능을 갖춘 대시보드입니다.
결론
에이전틱 디자인 패턴의 목표 설정은 정적인 목표를 동적이고 자체 관리하는 시스템으로 변환합니다. LangGraph의 그래프 기반 오케스트레이션, TypeScript의 타입 안전성, Vercel의 서버리스 인프라를 활용하여 목표를 자율적으로 분해하고 진행 상황을 추적하며 전략을 적응시키는 프로덕션 레디 에이전트를 구축할 수 있습니다. 이 패턴의 힘은 구조화된 계획과 적응형 실행을 결합하는 데 있습니다 - 최고의 프로젝트 매니저처럼 우리 에이전트는 철저히 계획하고 효율적으로 실행하며 필요할 때 전환할 수 있으며, 동시에 완전한 관찰 가능성과 인간 감독 기능을 유지합니다.