Bagian 2: Membangun AI Agent Pertama Anda: Panduan Praktis dengan LangChain

Kebanyakan tutorial agen AI melewatkan bagian-bagian yang rumit. Inilah cara saya membangun agen yang berfungsi menggunakan LangChain, tRPC, dan PostgreSQL — termasuk kesalahan-kesalahan yang saya buat selama prosesnya.

Bagian 2: Membangun AI Agent Pertama Anda: Panduan Praktis dengan LangChain
Feng LiuFeng Liu
19 Desember 2025

Hype seputar AI agent memang nyata. Semua orang membicarakan sistem otonom yang bisa berpikir, merencanakan, dan mengeksekusi tugas. Tapi ada satu hal yang tidak diceritakan orang kepada Anda: kebanyakan tutorial hanya menunjukkan "happy path" (skenario mulus) dan melewatkan bagian saat semuanya rusak.

Minggu lalu, saya menghabiskan dua hari membangun AI agent dari nol. Bukan contoh mainan—tapi agent sungguhan yang mengelola platform blog, membuat user, menulis postingan, dan benar-benar berfungsi. Saya akan menunjukkan kepada Anda bagaimana tepatnya saya melakukannya, termasuk bagian-bagian yang gagal pada percobaan pertama.

Kode lengkap: github.com/giftedunicorn/my-ai-agent

Apa yang Sebenarnya Kita Bangun

Lupakan contoh-contoh abstrak. Kita akan membangun agent yang:

  • Membuat dan mengelola user di database PostgreSQL
  • Menghasilkan postingan blog sesuai permintaan
  • Merespons secara percakapan sambil menggunakan tools
  • Menyimpan riwayat percakapan
  • Benar-benar di-deploy (bukan cuma demo localhost)

Tech stack-nya: Next.js, tRPC, Drizzle ORM, LangChain, dan Google Gemini. Bukan karena lagi tren—tapi karena type-safe, cepat, dan benar-benar berfungsi di production.

Arsitekturnya (Lebih Sederhana dari Dugaan Anda)

Inilah yang mengejutkan saya: AI agent tidak serumit itu. Pada intinya, mereka hanyalah:

  1. Sebuah LLM yang bisa memanggil fungsi
  2. Sekumpulan tools yang bisa digunakan LLM
  3. Sebuah loop (siklus) yang mengeksekusi tools tersebut
  4. Memori untuk menjaga konteks

Itu saja. Kompleksitasnya muncul dari cara membuat bagian-bagian ini bekerja sama secara andal.

Skema Database

Pertama, fondasinya. Kita butuh tabel untuk user, post, dan pesan:

export const User = pgTable("user", (t) => ({
  id: t.integer().primaryKey().generatedAlwaysAsIdentity(),
  name: t.varchar({ length: 255 }).notNull(),
  email: t.varchar({ length: 255 }).notNull().unique(),
  bio: t.text(),
  createdAt: t.timestamp().defaultNow().notNull(),
  updatedAt: t.timestamp().defaultNow().notNull(),
}));

export const Post = pgTable("post", (t) => ({
  id: t.integer().primaryKey().generatedAlwaysAsIdentity(),
  userId: t
    .integer()
    .notNull()
    .references(() => User.id, { onDelete: "cascade" }),
  title: t.varchar({ length: 500 }).notNull(),
  content: t.text().notNull(),
  published: t.boolean().default(false).notNull(),
  createdAt: t.timestamp().defaultNow().notNull(),
  updatedAt: t.timestamp().defaultNow().notNull(),
}));

Tidak ada yang aneh-aneh. Hanya data relasional yang bersih dengan PostgreSQL. Tabel Message menyimpan riwayat percakapan—krusial untuk menjaga konteks antar request.

Membangun Tools (Di Sini Keajaibannya Terjadi)

Di sinilah kebanyakan tutorial menjadi tidak jelas. "Buat saja beberapa tools," kata mereka. Izinkan saya tunjukkan seperti apa bentuk sebenarnya.

Tools adalah fungsi yang bisa dipanggil oleh AI Anda. Dengan DynamicStructuredTool dari LangChain, Anda mendefinisikan:

  1. Apa yang dilakukan tool tersebut (deskripsi)
  2. Input apa yang dibutuhkannya (skema dengan Zod)
  3. Apa yang sebenarnya dieksekusi (fungsi)

Ini adalah tool untuk membuat user:

const createUserTool = new DynamicStructuredTool({
  name: "create_user",
  description:
    "Create a new user in the database. Use this when asked to add, create, or register a user.",
  schema: z.object({
    name: z.string().describe("The user's full name"),
    email: z.string().email().describe("The user's email address"),
    bio: z.string().optional().describe("Optional biography"),
  }),
  func: async (input) => {
    const { name, email, bio } = input as {
      name: string;
      email: string;
      bio?: string;
    };
    const user = await caller.user.create({ name, email, bio });
    return `Successfully created user: ${user.name} (ID: ${user.id}, Email: ${user.email})`;
  },
});

Deskripsi itu jauh lebih penting daripada yang Anda kira. LLM menggunakannya untuk memutuskan kapan harus memanggil tool ini. Harus spesifik tentang kapan menggunakannya.

Nilai kembaliannya (return value)? Itulah yang dilihat oleh LLM. Saya mengembalikan teks terstruktur dengan semua detail relevan—ID, nama, konfirmasi. Ini membantu LLM memberikan respons yang lebih baik kepada user.

The Agent: Menyatukan Semuanya

Di sini mulai menarik. API LangChain baru (v1.2+) menyederhanakan segalanya:

const agent = createAgent({
  model: new ChatGoogleGenerativeAI({
    apiKey: process.env.GOOGLE_GENERATIVE_AI_API_KEY,
    model: "gemini-2.0-flash-exp",
    temperature: 0.7,
  }),
  tools: [...createUserTools(caller), ...createPostTools(caller)],
  systemPrompt: AGENT_SYSTEM_PROMPT,
});

const result = await agent.invoke({
  messages: conversationMessages,
});

Itu saja. Tidak ada ChatPromptTemplate, tidak ada AgentExecutor, tidak ada chain yang rumit. Cukup createAgent dan invoke.

System Prompt (Kepribadian Agent Anda)

Di sinilah Anda mengajarkan agent Anda bagaimana harus bersikap:

const AGENT_SYSTEM_PROMPT = `You are an AI assistant that helps manage a blog platform.

You have access to tools for:
- User management (create, read, list, count)
- Post management (create, list)

When users ask you to perform actions:
1. Use the appropriate tools to complete the task
2. Be conversational and friendly
3. Provide clear confirmation with specific details
4. When creating mock data, use realistic names and content

Always confirm successful operations with relevant details.`;

Saya belajar ini dari pengalaman pahit: harus eksplisit. Beri tahu agent apa yang harus dilakukan, bagaimana merespons, dan detail apa yang harus disertakan. Prompt yang samar akan menghasilkan perilaku yang samar.

Menangani Riwayat Percakapan

Kebanyakan contoh melewatkan bagian ini, padahal ini kritis untuk pengalaman pengguna yang baik. Begini cara saya menanganinya:

// Ambil 10 pesan terakhir dari database
const history = await ctx.db
  .select()
  .from(Message)
  .orderBy(desc(Message.createdAt))
  .limit(10);

// Konversi ke format LangChain
const conversationMessages = [
  ...history.reverse().map((msg) => ({
    role: msg.role === "user" ? "user" : "assistant",
    content: msg.content,
  })),
  { role: "user", content: input.message },
];

Sederhana, tapi efektif. Agent sekarang mengingat 10 pertukaran pesan terakhir. Cukup untuk konteks, tapi tidak terlalu banyak sampai membuatnya bingung atau mahal.

Bagian yang Berantakan (Apa yang Sebenarnya Rusak)

Dependensi Sirkular: Percobaan pertama saya gagal karena agent.ts mengimpor appRouter, yang mengimpor agentRouter, menciptakan dependensi sirkular. Solusinya? Buat router sementara secara inline hanya dengan router yang Anda butuhkan untuk tools.

Ekstraksi Respons Tool: Format respons LangChain berubah di v1.2. Hasilnya sekarang ada di result.messages[result.messages.length - 1].content, bukan result.output. Butuh satu jam buat saya memecahkan ini.

Type Safety: Parameter func pada tool butuh pengetikan eksplisit. Anda tidak bisa langsung melakukan destructuring—Anda perlu melakukan casting input terlebih dahulu. TypeScript tidak akan membantu Anda di sini.

Mengatur Milik Anda Sendiri

Inilah yang sebenarnya Anda butuhkan:

  1. Install dependencies:
pnpm add @langchain/core @langchain/google-genai langchain drizzle-orm
  1. Environment variables:
POSTGRES_URL="your-database-url"  # Coba Vercel Postgres, Supabase, atau local PostgreSQL
GOOGLE_GENERATIVE_AI_API_KEY="your-gemini-key"  # Dapatkan dari https://aistudio.google.com/app/apikey
  1. Setup Database:
pnpm db:push  # Membuat tabel dari skema
  1. Mulai membangun:
  • Definisikan skema database Anda
  • Buat prosedur tRPC untuk operasi CRUD
  • Bangun tools LangChain yang membungkus prosedur tersebut
  • Buat agent dengan tools Anda
  • Sambungkan ke frontend Anda

Apa yang Akan Saya Lakukan Secara Berbeda

Kalau saya mulai lagi dari awal besok:

Mulai dengan lebih sedikit tools. Awalnya saya membangun 7 tools. Tetaplah dengan 3-4 tools inti dulu. Buat mereka bekerja dengan sempurna, baru ekspansi.

Tes tools secara independen. Jangan menunggu sampai agent selesai dibangun untuk mengetes tools Anda. Panggil mereka secara langsung dengan data tes terlebih dahulu.

Pantau penggunaan tool. Saya menambahkan logging untuk melihat tools mana yang dipanggil agent dan kenapa. Ini mengungkapkan bahwa deskripsi tool saya perlu diperbaiki.

Gunakan streaming. Saat ini, user menunggu respons lengkap. Streaming akan membuatnya terasa lebih cepat, meskipun memakan waktu yang sama.

Cek Realitas

Membangun AI agent itu bukan sihir, tapi juga bukan hal sepele. Anda akan menghabiskan lebih banyak waktu untuk:

  • Desain tool (apa yang harus dilakukan setiap tool?)
  • Prompt engineering (bagaimana membuat agent berperilaku benar?)
  • Error handling (bagaimana jika database down? bagaimana jika LLM berhalusinasi?)
  • Type safety (membuat TypeScript senang dengan respons LLM yang dinamis)

Daripada mengerjakan bagian AI-nya itu sendiri.

Coba Sendiri

Kode untuk tutorial ini nyata—saya membangunnya sambil menulis ini. Anda bisa:

  • Tes dengan: "create 3 mock users"
  • Coba: "create 2 blog posts for user 1"
  • Tanya: "how many users do we have?"

Agent menangani semua ini dengan memutuskan tools mana yang harus dipanggil, mengeksekusinya, dan merespons secara percakapan.

Apa Selanjutnya

Ini baru fondasinya. Dari sini, Anda bisa:

  • Menambahkan autentikasi (siapa yang bisa membuat apa?)
  • Mengimplementasikan respons streaming
  • Menambahkan tools yang lebih kompleks (pencarian, analitik, integrasi)
  • Membangun feedback loop (apakah panggilan tool berhasil?)
  • Menambahkan rate limiting (jangan biarkan user membuat 10.000 postingan)

Tapi mulailah dengan sederhana. Buat satu tool bekerja dengan baik sebelum menambahkan sepuluh yang biasa-biasa saja.

Bagian terbaiknya? Begitu Anda memahami pola ini—tools + LLM + memori—Anda bisa membangun agent untuk apa saja. Manajemen database, customer support, pembuatan konten, apa pun itu.

Bagian sulitnya bukan kodenya. Tapi merancang tools yang benar-benar memecahkan masalah nyata.


Sumber Daya:

Bagikan ini

Feng Liu

Feng Liu

shenjian8628@gmail.com

Bagian 2: Membangun AI Agent Pertama Anda: Panduan Praktis dengan LangChain | Feng Liu