---
id: ai-langgraph-agent-frameworks
title: Agent Frameworks — LangGraph / Mastra / CrewAI
category: Coding
status: draft
source_trust_level: B
verification_status: conceptual
created_at: 2026-05-09
updated_at: 2026-05-09
tags: [ai, agent, framework, vibe-coding]
tech_stack: { language: "TS / Python", applicable_to: ["Backend"] }
applied_in: []
aliases: [LangGraph, LangChain, Mastra, CrewAI, AutoGen, agent state, multi-agent]
---

# 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)
```ts
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)
```ts
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)
```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)
```ts
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)
```ts
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
```ts
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
```ts
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 (가벼운)
```ts
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
```ts
// 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
```ts
// 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 문서)
```ts
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 필수.

## 🔗 관련 문서
- [[AI_Agentic_Patterns]]
- [[AI_Function_Calling_Deep]]
- [[AI_LLM_Eval_Patterns]]
