Parte 2: Construyendo tu primer agente de IA: Guía práctica con LangChain

La mayoría de los tutoriales sobre agentes de IA se saltan la parte difícil. Te cuento cómo construí un agente funcional con LangChain, tRPC y PostgreSQL, incluidos los errores reales que cometí por el camino.

Parte 2: Construyendo tu primer agente de IA: Guía práctica con LangChain
Feng LiuFeng Liu
19 de diciembre de 2025

El hype de los agentes de IA es real. Todo el mundo habla de sistemas autónomos que pueden pensar, planificar y ejecutar tareas. Pero aquí está el detalle que nadie te cuenta: la mayoría de los tutoriales te muestran el "escenario ideal" (happy path) y se saltan las partes donde todo se rompe.

La semana pasada, pasé dos días construyendo un agente de IA desde cero. No un ejemplo de juguete, sino uno real que gestiona una plataforma de blog, crea usuarios, escribe posts y realmente funciona. Voy a mostrarte exactamente cómo lo hice, incluyendo las partes que no funcionaron a la primera.

Código completo: github.com/giftedunicorn/my-ai-agent

Lo Que Realmente Estamos Construyendo

Olvida los ejemplos abstractos. Estamos construyendo un agente que:

  • Crea y gestiona usuarios en una base de datos PostgreSQL
  • Genera posts de blog bajo demanda
  • Responde de manera conversacional mientras usa herramientas
  • Mantiene el historial de la conversación
  • Se despliega de verdad (no solo demos en localhost)

El stack: Next.js, tRPC, Drizzle ORM, LangChain y Google's Gemini. No porque esté de moda, sino porque tiene tipado seguro (type-safe), es rápido y realmente funciona en producción.

La Arquitectura (Más Simple de lo que Crees)

Esto es lo que me sorprendió: los agentes de IA no son tan complicados. En su núcleo, son simplemente:

  1. Un LLM que puede llamar funciones
  2. Un conjunto de herramientas que el LLM puede usar
  3. Un bucle que ejecuta esas herramientas
  4. Memoria para mantener el contexto

Eso es todo. La complejidad viene de hacer que estas piezas funcionen juntas de manera fiable.

El Esquema de la Base de Datos

Primero, los cimientos. Necesitamos tablas para usuarios, posts y mensajes:

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(),
}));

Nada sofisticado. Solo datos relacionales limpios con PostgreSQL. La tabla Message almacena el historial de conversación, crucial para mantener el contexto entre peticiones.

Construyendo las Herramientas (Donde Ocurre la Magia)

Aquí es donde la mayoría de los tutoriales se vuelven vagos. "Solo crea algunas herramientas", dicen. Déjame mostrarte cómo se ve eso realmente.

Las herramientas son funciones que tu IA puede llamar. Con DynamicStructuredTool de LangChain, defines:

  1. Qué hace la herramienta (descripción)
  2. Qué inputs necesita (esquema con Zod)
  3. Qué ejecuta realmente (función)

Aquí está la herramienta para crear usuarios:

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})`;
  },
});

La descripción importa más de lo que crees. El LLM la usa para decidir cuándo llamar a esta herramienta. Sé específico sobre cuándo usarla.

¿El valor de retorno? Eso es lo que ve el LLM. Yo devuelvo texto estructurado con todos los detalles relevantes: IDs, nombres, confirmación. Esto ayuda al LLM a dar mejores respuestas a los usuarios.

El Agente: Uniendo Todo

Aquí es donde se pone interesante. La nueva API de LangChain (v1.2+) simplificó todo:

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,
});

Eso es todo. Sin ChatPromptTemplate, sin AgentExecutor, sin cadenas complejas. Solo createAgent e invoke.

El System Prompt (La Personalidad de tu Agente)

Aquí es donde le enseñas a tu agente cómo comportarse:

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.`;

Aprendí esto a la mala: sé explícito. Dile al agente exactamente qué hacer, cómo responder y qué detalles incluir. Los prompts vagos llevan a comportamientos vagos.

Manejando el Historial de Conversación

La mayoría de los ejemplos se saltan esto, pero es crítico para una buena experiencia de usuario. Así es como lo manejo yo:

// Get last 10 messages from database
const history = await ctx.db
  .select()
  .from(Message)
  .orderBy(desc(Message.createdAt))
  .limit(10);

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

Simple, pero efectivo. El agente ahora recuerda los últimos 10 intercambios. Suficiente para el contexto, no tanto como para que se confunda o salga caro.

Las Partes Complicadas (Lo Que Realmente Se Rompió)

Dependencias Circulares: Mi primer intento falló porque agent.ts importaba appRouter, el cual importaba agentRouter, creando una dependencia circular. ¿La solución? Crear un router temporal inline solo con los routers que necesitas para las herramientas.

Extracción de Respuesta de Herramientas: El formato de respuesta de LangChain cambió en la v1.2. El resultado ahora está en result.messages[result.messages.length - 1].content, no en result.output. Me tomó una hora descubrir esto.

Seguridad de Tipos (Type Safety): El parámetro func de la herramienta necesita tipado explícito. No puedes simplemente desestructurar; necesitas hacer un cast de input primero. TypeScript no te ayudará aquí automáticamente.

Configurando el Tuyo

Esto es lo que realmente necesitas:

  1. Instalar dependencias:
pnpm add @langchain/core @langchain/google-genai langchain drizzle-orm
  1. Variables de entorno:
POSTGRES_URL="your-database-url"  # Prueba Vercel Postgres, Supabase o PostgreSQL local
GOOGLE_GENERATIVE_AI_API_KEY="your-gemini-key"  # Obtenla en https://aistudio.google.com/app/apikey
  1. Configuración de base de datos:
pnpm db:push  # Crea las tablas desde el esquema
  1. Empieza a construir:
  • Define tu esquema de base de datos
  • Crea procedimientos tRPC para operaciones CRUD
  • Construye herramientas de LangChain que envuelvan esos procedimientos
  • Crea el agente con tus herramientas
  • Conéctalo a tu frontend

Qué Haría Diferente

Si empezara de nuevo mañana:

Empezar con menos herramientas. Construí 7 herramientas inicialmente. Quédate con 3-4 principales primero. Haz que funcionen perfectamente, luego expande.

Probar herramientas independientemente. No esperes a que el agente esté construido para probar tus herramientas. Llámalas directamente con datos de prueba primero.

Monitorear el uso de herramientas. Añadí logs para ver qué herramientas llama el agente y por qué. Esto reveló que las descripciones de mis herramientas necesitaban trabajo.

Usar streaming. Ahora mismo, los usuarios esperan la respuesta completa. El streaming haría que se sintiera más rápido, incluso si toma el mismo tiempo.

El Golpe de Realidad

Construir agentes de IA no es magia, pero tampoco es trivial. Pasarás más tiempo en:

  • Diseño de herramientas (¿qué debería hacer cada herramienta?)
  • Ingeniería de prompts (¿cómo hago que el agente se comporte correctamente?)
  • Manejo de errores (¿qué pasa si la base de datos cae? ¿qué pasa si el LLM alucina?)
  • Seguridad de tipos (hacer feliz a TypeScript con respuestas dinámicas del LLM)

Que en la parte de IA en sí.

Pruébalo Tú Mismo

El código de este tutorial es real; lo construí mientras escribía esto. Puedes:

  • Probarlo con: "create 3 mock users" (crea 3 usuarios de prueba)
  • Intentar: "create 2 blog posts for user 1" (crea 2 posts para el usuario 1)
  • Preguntar: "how many users do we have?" (¿cuántos usuarios tenemos?)

El agente maneja todo esto decidiendo qué herramientas llamar, ejecutándolas y respondiendo conversacionalmente.

Qué Sigue

Esto es solo la base. Desde aquí, podrías:

  • Añadir autenticación (¿quién puede crear qué?)
  • Implementar respuestas con streaming
  • Añadir herramientas más complejas (búsqueda, analíticas, integraciones)
  • Construir un bucle de retroalimentación (¿tuvo éxito la llamada a la herramienta?)
  • Añadir límites de velocidad (rate limiting) (no dejes que los usuarios creen 10,000 posts)

Pero empieza simple. Consigue que una herramienta funcione bien antes de añadir diez mediocres.

¿La mejor parte? Una vez que entiendes este patrón — herramientas + LLM + memoria — puedes construir agentes para cualquier cosa. Gestión de bases de datos, soporte al cliente, generación de contenido, lo que sea.

La parte difícil no es el código. Es diseñar herramientas que realmente resuelvan problemas reales.


Recursos:

Compartir esto

Feng Liu

Feng Liu

shenjian8628@gmail.com

Parte 2: Construyendo tu primer agente de IA: Guía práctica con LangChain | Feng Liu