8.4 KiB
8.4 KiB
id, title, category, status, source_trust_level, verification_status, created_at, updated_at, tags, tech_stack, applied_in, aliases
| id | title | category | status | source_trust_level | verification_status | created_at | updated_at | tags | tech_stack | applied_in | aliases | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| ai-langgraph-agent-frameworks | Agent Frameworks — LangGraph / Mastra / CrewAI | Coding | draft | B | conceptual | 2026-05-09 | 2026-05-09 |
|
|
|
Agent Frameworks
Agent 구현 framework. LangGraph (state machine), Mastra (TS modern), CrewAI (multi-agent), AutoGen (Microsoft). 자체 implementation 도 좋음 — overkill 주의.
📖 핵심 개념
- State graph: node + edge.
- State persistence: checkpoint.
- Streaming: 매 step 응답.
- Human-in-the-loop: 중간 confirm.
💻 코드 패턴
LangGraph (Python / JS)
import { StateGraph, END, MemorySaver } from '@langchain/langgraph';
import { ChatAnthropic } from '@langchain/anthropic';
import { z } from 'zod';
const State = z.object({
messages: z.array(z.any()),
toolResults: z.record(z.string()).optional(),
});
const llm = new ChatAnthropic({ model: 'claude-opus-4-7' });
const graph = new StateGraph(State)
.addNode('agent', async (state) => {
const response = await llm.invoke(state.messages);
return { messages: [...state.messages, response] };
})
.addNode('tools', async (state) => {
const last = state.messages.at(-1);
const results: Record<string, string> = {};
for (const call of last.tool_calls ?? []) {
results[call.id] = await executeTool(call.name, call.args);
}
return {
messages: [...state.messages, ...Object.entries(results).map(([id, content]) => ({ role: 'tool', tool_call_id: id, content }))],
toolResults: results,
};
})
.addEdge('__start__', 'agent')
.addConditionalEdges('agent', (state) => {
const last = state.messages.at(-1);
return last.tool_calls?.length > 0 ? 'tools' : END;
})
.addEdge('tools', 'agent')
.compile({ checkpointer: new MemorySaver() });
// 실행 (streaming)
const stream = await graph.stream(
{ messages: [{ role: 'user', content: '...' }] },
{ configurable: { thread_id: 'session-1' } }
);
for await (const chunk of stream) {
console.log(chunk);
}
Mastra (TS modern)
import { Mastra } from '@mastra/core';
const mastra = new Mastra({
agents: {
weatherAgent: new Agent({
name: 'Weather',
instructions: 'Help users with weather questions.',
model: openai('gpt-4o'),
tools: { getWeather: weatherTool },
}),
},
workflows: {
customerSupport: workflow,
},
});
const result = await mastra.agents.weatherAgent.generate('Tokyo weather?');
→ TS-first, modern, evals + observability built-in.
CrewAI (multi-agent, Python)
from crewai import Agent, Task, Crew
researcher = Agent(
role='Senior Researcher',
goal='Discover latest AI trends',
backstory='You are an expert AI researcher...',
tools=[search_tool],
)
writer = Agent(
role='Tech Writer',
goal='Write engaging articles',
)
task1 = Task(description='Research 2026 AI trends', agent=researcher)
task2 = Task(description='Write article based on research', agent=writer)
crew = Crew(agents=[researcher, writer], tasks=[task1, task2])
result = crew.kickoff()
→ Role-based multi-agent. 빠른 시작 but 정밀 제어 어려움.
Vercel AI SDK (modern, simple)
import { generateText, tool } from 'ai';
import { openai } from '@ai-sdk/openai';
import { z } from 'zod';
const result = await generateText({
model: openai('gpt-4o'),
tools: {
getWeather: tool({
description: 'Get weather',
parameters: z.object({ city: z.string() }),
execute: async ({ city }) => fetchWeather(city),
}),
},
maxSteps: 5, // tool loop
prompt: 'Tokyo weather?',
});
console.log(result.text, result.toolCalls);
→ 단순 use case 강력.
State 영속 (LangGraph)
import { PostgresSaver } from '@langchain/langgraph-checkpoint-postgres';
const checkpointer = PostgresSaver.fromConnString('postgresql://...');
const graph = ...compile({ checkpointer });
// 같은 thread_id = 이어서
await graph.invoke(input, { configurable: { thread_id: userId } });
Human-in-the-loop
const graph = new StateGraph(State)
.addNode('plan', planNode)
.addNode('confirm', confirmNode) // 사용자 승인 대기
.addNode('execute', executeNode)
.addEdge('plan', 'confirm')
.addConditionalEdges('confirm', (state) =>
state.approved ? 'execute' : END
)
.compile({
interrupt_before: ['execute'], // 항상 멈춤
});
// 1. Plan 까지 실행
const state = await graph.invoke(input, config);
// 2. UI 가 사용자 confirm
if (await askUser(state.plan)) {
// 3. 이어서 실행
await graph.invoke(null, { ...config, recursionLimit: 10 });
}
Streaming + tools
const stream = await graph.streamEvents(input, {
...config,
version: 'v2',
});
for await (const event of stream) {
if (event.event === 'on_chat_model_stream') {
process.stdout.write(event.data.chunk.content);
}
if (event.event === 'on_tool_start') {
console.log('\nTool:', event.name);
}
}
자체 implementation (가벼운)
class Agent {
private messages: Message[] = [];
private maxIters = 10;
constructor(
private llm: LLM,
private tools: Tool[],
private systemPrompt: string,
) {}
async run(userMsg: string): Promise<string> {
this.messages.push({ role: 'user', content: userMsg });
for (let i = 0; i < this.maxIters; i++) {
const r = await this.llm.chat({
system: this.systemPrompt,
messages: this.messages,
tools: this.tools,
});
this.messages.push({ role: 'assistant', content: r.content });
if (r.stopReason === 'end_turn') return r.text;
if (r.toolCalls) {
const results = await Promise.all(
r.toolCalls.map(call => this.executeTool(call))
);
this.messages.push(...results.map(toToolResult));
}
}
throw new Error('max iters');
}
}
→ 위 AI_Function_Calling_Deep 가 baseline.
Observability
// LangSmith / Langfuse / Helicone
import { LangSmithTracer } from 'langsmith';
const tracer = new LangSmithTracer({
projectName: 'my-agent',
});
await graph.invoke(input, {
callbacks: [tracer],
});
→ 매 LLM call + tool call 추적.
Memory systems
// Short-term: conversation messages
// Long-term: vector DB
import { MemoryClient } from '@mem0/sdk';
const memory = new MemoryClient();
// Save
await memory.add(userId, 'User prefers dark mode and minimal UI');
// Retrieve relevant
const memories = await memory.search(userId, currentQuery);
// Inject to system prompt
const system = `${baseSystem}\n\nRelevant context:\n${memories.join('\n')}`;
Eval (위 LLM Eval 문서)
import { evalDataset, exactMatch, llmJudge } from 'mastra/evals';
await evalDataset({
agent: weatherAgent,
cases: [
{ input: 'Tokyo weather?', expected: { contains: 'Tokyo' } },
],
metrics: [exactMatch, llmJudge('helpful')],
});
비교
LangGraph:
+ 가장 강력 / production-ready
+ State machine 명시
- Python 우월 (TS 제한)
Mastra:
+ Modern TS-first
+ Eval / observability built-in
- 새로움 (검증 적음)
CrewAI:
+ Multi-agent simple
- 정밀 제어 어려움
Vercel AI SDK:
+ 단순 / TS 친화
- Multi-step 제한적
자체:
+ 정확 제어
- 모든 거 직접
🤔 의사결정 기준
| 상황 | 추천 |
|---|---|
| 단순 1-2 step | Vercel AI SDK |
| Multi-step / state | LangGraph (Python) / Mastra (TS) |
| Multi-agent | CrewAI / AutoGen |
| Production / 큰 규모 | LangGraph + LangSmith |
| Quick prototype | Vercel AI SDK |
| 완전 제어 | 자체 |
❌ 안티패턴
- Framework 선택 전 use case 명시 X: overkill / 부족.
- State persistence 없음 + long task: crash 시 잃음.
- Max iter 없음: 무한 / 비용 폭발.
- HITL 없음 + dangerous tool: 실수 책임.
- Multi-agent 가 single agent 대체: 단일 가 충분 자주.
- Memory 모든 거 inject: context 폭발. retrieval.
- Eval 없음: 향상 측정 X.
🤖 LLM 활용 힌트
- 단순 = Vercel AI SDK.
- Production state = LangGraph / Mastra.
- Multi-agent overkill 자주.
- HITL + state persistence 필수.