Como desarrollar un chatbot con Claude Code
Aprende a desarrollar un chatbot usando Claude Code. Incluye ejemplos de codigo practicos y guia paso a paso.
Desarrollando un chatbot con Claude Code
El desarrollo de un chatbot de IA involucra muchos elementos como la implementacion de UI, integracion con API, gestion de conversaciones y procesamiento de streaming. Con Claude Code, puedes construir un chatbot que integre todos estos componentes en poco tiempo.
Implementacion basica de la UI de chat
> Crea un componente de chatbot en React.
> Con soporte para respuestas en streaming, visualizacion del historial de conversacion y formulario de entrada.
import { useState, useRef, useEffect } from "react";
interface Message {
id: string;
role: "user" | "assistant";
content: string;
}
export function ChatBot() {
const [messages, setMessages] = useState<Message[]>([]);
const [input, setInput] = useState("");
const [isLoading, setIsLoading] = useState(false);
const messagesEndRef = useRef<HTMLDivElement>(null);
useEffect(() => {
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
}, [messages]);
const sendMessage = async () => {
if (!input.trim() || isLoading) return;
const userMessage: Message = {
id: crypto.randomUUID(),
role: "user",
content: input,
};
setMessages((prev) => [...prev, userMessage]);
setInput("");
setIsLoading(true);
const assistantId = crypto.randomUUID();
setMessages((prev) => [
...prev,
{ id: assistantId, role: "assistant", content: "" },
]);
try {
const response = await fetch("/api/chat", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
messages: [...messages, userMessage].map(({ role, content }) => ({
role,
content,
})),
}),
});
const reader = response.body!.getReader();
const decoder = new TextDecoder();
while (true) {
const { done, value } = await reader.read();
if (done) break;
const chunk = decoder.decode(value);
setMessages((prev) =>
prev.map((m) =>
m.id === assistantId
? { ...m, content: m.content + chunk }
: m
)
);
}
} catch (error) {
setMessages((prev) =>
prev.map((m) =>
m.id === assistantId
? { ...m, content: "Ocurrio un error. Por favor, intentalo de nuevo." }
: m
)
);
}
setIsLoading(false);
};
return (
<div className="flex flex-col h-[600px] border rounded-lg">
<div className="flex-1 overflow-y-auto p-4 space-y-4">
{messages.map((msg) => (
<div
key={msg.id}
className={`flex ${msg.role === "user" ? "justify-end" : "justify-start"}`}
>
<div
className={`max-w-[70%] p-3 rounded-lg ${
msg.role === "user"
? "bg-blue-600 text-white"
: "bg-gray-100 text-gray-900"
}`}
>
{msg.content}
</div>
</div>
))}
<div ref={messagesEndRef} />
</div>
<div className="border-t p-4 flex gap-2">
<input
value={input}
onChange={(e) => setInput(e.target.value)}
onKeyDown={(e) => e.key === "Enter" && !e.shiftKey && sendMessage()}
placeholder="Escribe un mensaje..."
className="flex-1 p-2 border rounded-lg"
disabled={isLoading}
/>
<button
onClick={sendMessage}
disabled={isLoading}
className="px-4 py-2 bg-blue-600 text-white rounded-lg disabled:opacity-50"
>
Enviar
</button>
</div>
</div>
);
}
Ruta de API con soporte de streaming
Una ruta de API que llama a la API de Anthropic en el backend y devuelve la respuesta en streaming.
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic();
export async function POST(request: Request) {
const { messages } = await request.json();
const stream = await client.messages.stream({
model: "claude-sonnet-4-20250514",
max_tokens: 1024,
system: "Eres un asistente amable y educado. Responde en espanol.",
messages,
});
const encoder = new TextEncoder();
const readable = new ReadableStream({
async start(controller) {
for await (const event of stream) {
if (
event.type === "content_block_delta" &&
event.delta.type === "text_delta"
) {
controller.enqueue(encoder.encode(event.delta.text));
}
}
controller.close();
},
});
return new Response(readable, {
headers: { "Content-Type": "text/plain; charset=utf-8" },
});
}
Persistencia del historial de conversacion
Guarda las conversaciones en la base de datos para poder reanudarlas posteriormente.
import { db } from "@/lib/database";
export async function saveConversation(
userId: string,
messages: Message[]
) {
return db.conversation.upsert({
where: { id: `${userId}-current` },
update: {
messages: JSON.stringify(messages),
updatedAt: new Date(),
},
create: {
id: `${userId}-current`,
userId,
messages: JSON.stringify(messages),
},
});
}
export async function loadConversation(userId: string): Promise<Message[]> {
const conv = await db.conversation.findUnique({
where: { id: `${userId}-current` },
});
return conv ? JSON.parse(conv.messages as string) : [];
}
Integracion de RAG (Generacion Aumentada por Recuperacion)
Cuando se quiere crear un chatbot que responda basandose en documentos internos, la arquitectura RAG es efectiva.
import { searchDocuments } from "@/lib/vector-search";
async function generateRAGResponse(query: string, conversationHistory: Message[]) {
// Buscar documentos relacionados
const relevantDocs = await searchDocuments(query, { limit: 5 });
const context = relevantDocs
.map((doc) => `---\n${doc.title}\n${doc.content}\n---`)
.join("\n");
const systemPrompt = `Responde a las preguntas basandote en los siguientes documentos.
Si la informacion no se encuentra en los documentos, responde "No se encontro esa informacion".
${context}`;
return client.messages.stream({
model: "claude-sonnet-4-20250514",
max_tokens: 1024,
system: systemPrompt,
messages: conversationHistory,
});
}
Para ampliar la funcionalidad con la integracion de servidores MCP, consulta la guia de servidores MCP, y para el diseno efectivo de prompts, consulta los 5 tips para mejorar tus prompts.
Resumen
Con Claude Code, puedes desarrollar eficientemente un chatbot que incluye UI de chat, API de streaming, gestion de conversaciones y arquitectura RAG. Un enfoque de agregar funcionalidades de forma gradual es lo mas efectivo.
Para mas informacion, consulta la documentacion oficial de Claude Code y la referencia de la API de Anthropic.
Actualización 2026 para producción
Un chatbot es una aplicación que recibe un mensaje, conserva el contexto necesario y responde como si fuera una conversación. En términos sencillos, es una puerta de entrada para soporte, ventas, búsqueda interna o formación. El valor no está solo en mostrar una burbuja de chat, sino en reducir una tarea concreta: responder preguntas repetidas, clasificar contactos, buscar documentación o reunir datos antes de abrir un ticket.
Con Claude Code conviene empezar con un alcance pequeño. Un bot que responde diez preguntas frecuentes puede revisarse, medirse y mejorar en una semana. Un asistente que promete resolverlo todo suele fallar por coste, permisos, datos sensibles y respuestas difíciles de verificar. Antes de escribir más prompts, define qué puede contestar, cuándo debe decir “no lo sé” y a qué flujo humano debe enviar al usuario.
Tabla de arquitectura
| Capa | Responsabilidad | Nota de producción |
|---|---|---|
| UI en React | Entrada, historial, estado de carga y reintento | Revisa el patrón de estado en la documentación de React useState |
| Ruta API | Oculta claves y normaliza la petición al backend | Añade límites de tamaño, autenticación y timeout |
| Streaming | Envía texto parcial mientras se genera la respuesta | Usa Web Streams con cuidado; consulta MDN Streams API |
| Persistencia | Guarda conversaciones para reanudar y auditar | Minimiza datos personales y define borrado |
| RAG | Busca en documentos, políticas o páginas de producto | Si no hay evidencia, el bot no debe inventar |
| Webhooks | Envía eventos a CRM, tickets o Slack | Conecta con Claude Code Webhook Implementation |
| Analítica | Mide éxito, escalado, abandono y CTA | Complementa con Claude Code Analytics Implementation |
Para la forma de la petición, usa una estructura estable como la de Claude Code API Development: lista de mensajes con rol y contenido, instrucción del sistema en el servidor y una respuesta en streaming. Así puedes cambiar la interfaz o añadir canales sin rehacer todo.
Demo ejecutable de streaming
Guarda este archivo como chatbot-stream-demo.mjs y ejecútalo con node chatbot-stream-demo.mjs. No llama a Claude; sirve para verificar historial y streaming antes de conectar la ruta real.
const encoder = new TextEncoder();
const decoder = new TextDecoder();
const faq = new Map([
["password", "Open the account page, choose Reset password, and follow the email link."],
["pricing", "The pricing page explains plans. For a custom quote, collect team size and required features."],
["refund", "Refund requests should be routed to support with the order id and purchase email."],
]);
const history = [];
function chooseAnswer(question) {
const normalized = question.toLowerCase();
for (const [keyword, answer] of faq) {
if (normalized.includes(keyword)) return answer;
}
return "I could not find a safe answer in the FAQ. I will hand this to a human operator.";
}
async function* streamText(text) {
for (const token of text.split(/(\s+)/)) {
await new Promise((resolve) => setTimeout(resolve, 15));
yield encoder.encode(token);
}
}
async function ask(question) {
history.push({ role: "user", content: question });
const answer = chooseAnswer(question);
process.stdout.write(`\nUser: ${question}\nAssistant: `);
let fullAnswer = "";
for await (const chunk of streamText(answer)) {
const token = decoder.decode(chunk);
fullAnswer += token;
process.stdout.write(token);
}
history.push({ role: "assistant", content: fullAnswer });
}
await ask("How do I reset my password?");
await ask("Can I see pricing before talking to sales?");
console.log(`\n\nSaved ${history.length} messages.`);
Cuando lo lleves a producción, sustituye chooseAnswer por la llamada a Claude y conserva la secuencia: guardar mensaje del usuario, emitir respuesta parcial, guardar respuesta final. Evita así un fallo común donde la UI muestra texto, pero la base de datos queda vacía.
Casos de uso reales
Primer use case: cualificación comercial para SaaS. El bot responde sobre precios, seguridad, integraciones y requisitos, y solo envía a una consulta cuando detecta intención real. Esto mejora la monetización porque el equipo humano recibe conversaciones más preparadas.
Segundo caso: mesa de ayuda interna. Preguntas sobre vacaciones, gastos, VPN o alta de equipos suelen repetirse. Con RAG, el bot cita la política correcta y, si hace falta aprobación, abre un ticket por webhook.
Tercer caso: sitio educativo o de contenidos. El lector pregunta qué aprender después y el bot recomienda API, webhooks o analítica, enlazando a training cuando necesita acompañamiento. Es un workflow más natural que mostrar un banner genérico.
Cuarto caso: intake de incidentes. El bot recopila error, hora, navegador, cuenta y pasos de reproducción antes de crear el ticket. La meta no es resolverlo todo, sino entregar un informe completo.
Errores y riesgos concretos
No envíes historial ilimitado al modelo. Sube el coste, ralentiza la respuesta y puede mezclar instrucciones antiguas con la pregunta actual. Resume conversaciones largas y guarda solo lo necesario.
No conviertas una búsqueda débil en una respuesta segura. Si RAG no encuentra evidencia, el bot debe decirlo y ofrecer una ruta humana. Esta regla reduce muchos problemas de soporte.
No ignores el failure mode del streaming. Puede haber doble envío, conexión cortada, burbujas vacías o estado de carga infinito. Usa botón deshabilitado, cancelación, timeout y mensaje de reintento.
No publiques sin medición. Mide preguntas sin resolver, clics en CTA, escalados y conversaciones que terminan en compra o consulta. Los mensajes totales no bastan para saber si el bot genera negocio.
CTA de monetización
Si quieres convertir este chatbot en un activo comercial, conecta el final de la conversación con una oferta clara: diagnóstico, revisión de implementación, curso o plantilla. En ClaudeCodeLab, la ruta recomendada es training, porque permite pasar de leer el artículo a revisar una implementación real.
La secuencia útil para el lector es: entender el concepto aquí, profundizar en Claude Code API Development, automatizar eventos con webhooks y medir conversión con analytics.
PDF gratis: cheatsheet de Claude Code
Introduce tu email y descarga una hoja con comandos, hábitos de revisión y flujos seguros.
Cuidamos tus datos y no enviamos spam.
Sobre el autor
Masa
Ingeniero enfocado en workflows prácticos con Claude Code.
Artículos relacionados
Workflow de Obsidian a CLAUDE.md con Claude Code
Convierte notas de trabajo de Obsidian en notas operativas de CLAUDE.md para no repetir contexto.
Claude Code Revenue CTA Routing: de artículos a PDF, Gumroad y consulta
Un flujo con Claude Code para dirigir lectores a PDF gratis, Gumroad o consulta según intención.
Reglas de handoff para equipos con Claude Code: evidencia, permisos, rollback e ingresos
Formato práctico para entregar trabajo de Claude Code con pruebas, permisos, rollback, PDF gratis, Gumroad y consulta.