karawaci.kode

2026-06-13 · 7 min

LangChain vs Claude SDK Direct: 6 Bulan Build Agent

Enam bulan lalu saya start build customer service agent untuk klien e-commerce mid-size Jakarta (~14k order/bulan). Versi 1 saya pakai LangChain karena banyak tutorial. Tiga bulan kemudian saya rewrite full pakai Claude SDK direct. Comparison real berdasarkan kerja produktif.

Setup

Use case: agent untuk customer support yang handle order status, return, tukar produk, escalate kompleks ke human. Tools yang agent butuh akses:

  • Query order status (Postgres)
  • Update return status (Postgres + audit log)
  • Send WhatsApp notification (WA Business API)
  • Lookup product catalog (Postgres)
  • Escalate ke human (Telegram bot ke tim CS)

Volume: ~800 conversation/hari, average 6 turn per conversation.

Versi 1: LangChain

Stack: LangChain.js 0.3, ChatAnthropic provider, agent + tools pattern.

const llm = new ChatAnthropic({ model: 'claude-sonnet-4.7' });
const tools = [orderStatusTool, returnTool, ...];
const agent = createReactAgent({ llm, tools, checkpointer });

LOC code agent: ~1,800 LOC (termasuk tool wrapper, prompt template, state management).

Time-to-MVP: 6 hari.

Yang LangChain kasih:

  • Pre-built agent loop (ReAct pattern)
  • Memory abstraction (conversation state)
  • Tool call retry / error handling baked-in
  • Streaming dengan callback chain

Yang LangChain bikin pusing:

  • Abstraction berlapis: error stack trace 15 frame dalam. Susah debug.
  • Breaking change frequent: dalam 6 bulan saya migrate 3x karena API minor version bump.
  • Output format kadang inconsistent: tool call sometimes wrap dalam __arg, sometimes flat. Saya tambah defensive parsing.
  • Token usage tidak transparent: saya susah audit cost per conversation.

Latency v1 (LangChain)

Conversation turn (user message → agent response):

  • P50: 3,4 detik
  • P95: 7,8 detik
  • P99: 18 detik (with retry on tool fail)

Component breakdown:

  • LangChain orchestration overhead: ~280ms per turn
  • Claude API call: 2,8-6 detik
  • Tool execution: 100-500ms

LangChain overhead 280ms per turn × 6 turn/conv = 1,7 detik per conversation. Real.

Versi 2: Claude SDK direct

Tiga bulan kemudian saya rewrite. Stack: @anthropic-ai/sdk langsung, tool_use API native, state di Postgres.

async function runAgent(messages: Message[], userId: string) {
  while (true) {
    const response = await anthropic.messages.create({
      model: 'claude-sonnet-4.7',
      max_tokens: 4096,
      tools: TOOL_DEFINITIONS,
      messages,
    });
    
    if (response.stop_reason === 'end_turn') {
      return response.content;
    }
    
    if (response.stop_reason === 'tool_use') {
      const toolUse = response.content.find(c => c.type === 'tool_use');
      const result = await executeTool(toolUse, userId);
      messages.push({ role: 'assistant', content: response.content });
      messages.push({ role: 'user', content: [{ 
        type: 'tool_result', 
        tool_use_id: toolUse.id, 
        content: JSON.stringify(result) 
      }]});
    }
  }
}

LOC: ~520 LOC. Reduction 71%.

Time-to-rewrite: 4 hari.

Latency v2 (Claude SDK direct)

Conversation turn:

  • P50: 2,2 detik
  • P95: 4,8 detik
  • P99: 9 detik

P50 turun 38%, P95 turun 38%. Source: no LangChain orchestration overhead.

Cost

Token usage per conversation rata-rata:

  • LangChain v1: 8,400 token input + 1,200 token output (prompt template heavy)
  • SDK direct v2: 4,200 token input + 1,150 token output (lean prompt)

Cost per conversation (Claude Sonnet 4.7 pricing):

  • v1: 8,400 × $3/M + 1,200 × $15/M = $0,043
  • v2: 4,200 × $3/M + 1,150 × $15/M = $0,030

Saving per conv: $0,013. Volume 800 conv/hari × 30 = 24,000 conv/bulan.

Monthly saving: $0,013 × 24,000 = $312/mo (~Rp 5jt/mo).

Plus prompt caching (Claude SDK direct support out-of-box, LangChain v1 saya pakai tidak): cache hit rate 68% di sistem prompt, additional saving ~$140/mo.

Total saving cost: ~$450/mo dari rewrite.

Yang break

  1. State persistence: LangChain ada built-in checkpointer (Postgres adapter). Untuk SDK direct, saya tulis sendiri: serialize messages JSON ke conversation_state table. Effort 4 jam, jadi pattern reusable.

  2. Tool retry logic: LangChain ada retry default. Untuk SDK direct, saya tulis manual:

async function executeTool(toolUse, userId, attempt = 1) {
  try {
    return await tools[toolUse.name](toolUse.input, userId);
  } catch (e) {
    if (attempt < 3 && isRetriable(e)) {
      await sleep(500 * attempt);
      return executeTool(toolUse, userId, attempt + 1);
    }
    return { error: e.message };
  }
}
  1. Streaming UX: LangChain support streaming via callback. SDK direct saya pakai anthropic.messages.stream(). Different API tapi works. Saya tulis adapter ke Next.js Server-Sent Events response.

  2. Observability: di LangChain saya pakai LangSmith ($39/mo). Di SDK direct saya log manual ke OpenObserve (self-hosted di Hetzner). Saving $39/mo + lebih privacy-friendly.

Yang LangChain tetap menang

  • Multi-provider switching: ganti dari Claude ke OpenAI ke Gemini di config. SDK direct saya butuh adapter pattern manual.
  • Pre-built integrations: ada wrapper untuk Pinecone, Qdrant, Confluence, dll. SDK direct saya implement sendiri.
  • Community knowledge: lots of tutorial. SDK direct lebih sedikit example untuk pattern non-trivial.

Kalau project Anda multi-provider atau early prototyping: LangChain valid pilihan. Untuk production single-provider: SDK direct menang.

Debugging experience

Real story: di v1, agent kadang stuck di tool calling loop (infinite retry). Stack trace 15 frame dalam LangChain internal. Saya butuh 4 jam debug satu issue.

Di v2, agent loop saya tulis sendiri, ~50 LOC. Bug semacam itu kebetulan ada juga (off-by-one di max iteration counter), tapi debug ~20 menit karena code transparent.

Konsisten dengan pengalaman saya di pattern simpler debugging vs LangChain: less abstraction, more control.

Memory

LangChain v1 RSS process Bun: ~340MB stable. SDK direct v2 RSS process Bun: ~180MB stable.

LangChain dependency footprint besar (~85MB node_modules), SDK direct minimal (~12MB).

Verdict

Untuk production agent dengan Claude single-provider: SDK direct clear winner. Less LOC, faster, cheaper, more debuggable.

LangChain valid untuk: multi-provider orchestration, prototype eksploratoris, atau team yang butuh ekosistem integration luas tanpa effort wrapper.

Bukan magic — rewrite ke SDK direct butuh re-implement state management + retry + observability yang LangChain provide. Effort 4 hari, payback dalam 2 minggu dari saving cost + faster latency.

Pattern saya sekarang: prototype dengan LangChain (cepat eksplorasi), production rewrite ke SDK direct (kontrol + cost). Dua tools, satu workflow.

Ditulis oleh Reza Pradipta