Objetivos de aprendizaje
Después de leer este artículo podrás:
- Entender la arquitectura de un chatbot con IA (front-end, API y modelo)
- Escribir una API en FastAPI que responde en streaming
- Poner el chatbot en línea protegiendo la clave y el gasto
En esta página
- ¿Cómo es la arquitectura de un chatbot con IA?
- ¿Qué necesitas antes de empezar?
- ¿Cómo escribir la API con streaming?
- ¿Cómo lee el front-end la respuesta en streaming?
- ¿Cómo proteger la clave y el gasto?
- ¿Qué necesita el servidor para alojar esto?
- ¿Qué errores son comunes?
- Cómo hacerlo en Square Cloud
- Preguntas frecuentes
Alojar un chatbot con IA parece un tema nuevo, pero la parte que alojas es una vieja conocida: una API HTTP. El "cerebro" está en el proveedor del modelo (Anthropic, OpenAI, Google). Tu servidor recibe el mensaje, llama al proveedor y reenvía la respuesta.
Eso cambia lo que importa. No necesitas GPU ni mucha memoria. Necesitas un proceso siempre encendido, una clave de API bien guardada y protección contra el abuso, porque cada mensaje cuesta dinero.
¿Cómo es la arquitectura de un chatbot con IA?#
Son tres piezas:
- Front-end: la pantalla de chat (un sitio, un widget, una app). Guarda la conversación y muestra el texto a medida que llega.
- Backend (lo que tú alojas): una API con un endpoint como
POST /chat. Valida la entrada, añade el prompt de sistema, llama al modelo y devuelve la respuesta. - Proveedor del modelo: la API del LLM. Para entender lo que hace por debajo, mira qué es un LLM.
El backend existe por un motivo central: la clave de API nunca puede llegar al navegador. Cualquiera que abra las DevTools puede copiarla. Mira también qué hacer si se filtra la clave.
¿Qué necesitas antes de empezar?#
- Una versión de Python que todavía tenga soporte. La versión mínima que exigen el SDK de Anthropic, FastAPI y Uvicorn está en la documentación de cada uno.
- Una clave de API del proveedor. Aquí usamos la de Anthropic, pero la estructura es la misma para cualquier otro.
- Nociones básicas de variables de entorno.
Crea la carpeta del proyecto con un requirements.txt:
fastapi
uvicorn
anthropic¿Cómo escribir la API con streaming?#
Sin streaming, el usuario mira una pantalla vacía hasta que el modelo termina la respuesta entera. Con streaming, el texto aparece a medida que se genera. El SDK de Anthropic lo expone con client.messages.stream y text_stream, y FastAPI lo reenvía con StreamingResponse.
import os
from typing import Literal
from anthropic import AsyncAnthropic
from fastapi import FastAPI
from fastapi.responses import StreamingResponse
from pydantic import BaseModel, Field
client = AsyncAnthropic() # lee ANTHROPIC_API_KEY del entorno
MODEL = os.environ["ANTHROPIC_MODEL"] # sin ella, la app falla al iniciar con KeyError
SYSTEM = "Eres el asistente de la tienda Ejemplo. Responde en español, de forma breve."
app = FastAPI()
class Msg(BaseModel):
role: Literal["user", "assistant"]
content: str = Field(max_length=4000)
class ChatIn(BaseModel):
messages: list[Msg] = Field(min_length=1, max_length=20)
@app.post("/chat")
async def chat(body: ChatIn):
async def stream_text():
async with client.messages.stream(
model=MODEL,
max_tokens=1024,
system=SYSTEM,
messages=[m.model_dump() for m in body.messages],
) as stream:
async for text in stream.text_stream:
yield text
return StreamingResponse(stream_text(), media_type="text/plain; charset=utf-8")
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=int(os.environ.get("PORT", "8000")))Guarda el código como main.py. Lo que vale la pena notar:
- La API no guarda estado. El front-end envía la conversación entera en cada petición, y el modelo no "recuerda" nada entre llamadas. Los límites de 20 mensajes y 4.000 caracteres contienen el costo y el tamaño del contexto.
- El modelo es configuración, no código. Anthropic retira modelos con el tiempo, así que el ID queda en la variable
ANTHROPIC_MODEL, sin valor por defecto: si falta, la app se detiene al iniciar, en lugar de fallar con el primer mensaje. Copia el ID de la lista de modelos de Anthropic. Para tareas de alto volumen y baja latencia, lo habitual es un modelo pequeño, rápido y barato, como los de la línea Haiku. max_tokenses obligatorio en la API y funciona como techo de costo por respuesta.- El bloque final permite iniciar con
python main.py, escuchando en0.0.0.0en el puerto de la variablePORT(8000 si no existe).
Prueba local:
pip install -r requirements.txt
export ANTHROPIC_API_KEY="pega-tu-clave-aqui"
export ANTHROPIC_MODEL="id-de-un-modelo-pequeno"
uvicorn main:app --port 8000
curl -N -X POST localhost:8000/chat \
-H "Content-Type: application/json" \
-d '{"messages":[{"role":"user","content":"Hola, ¿qué tal?"}]}'El -N desactiva el búfer de curl, así que ves el texto llegar poco a poco.
¿Cómo lee el front-end la respuesta en streaming?#
En el navegador, fetch ya expone el cuerpo como un stream:
async function ask(messages, onText) {
const res = await fetch("/chat", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ messages }),
});
if (!res.ok || !res.body) throw new Error(`Error ${res.status}`);
const reader = res.body.pipeThrough(new TextDecoderStream()).getReader();
for (;;) {
const { value, done } = await reader.read();
if (done) break;
onText(value);
}
}Llama a ask con el historial y añade cada fragmento (onText) a la burbuja de la respuesta. Si el front-end está en otro dominio, configura CORS en FastAPI para aceptar solo el origen de tu sitio.
¿Cómo proteger la clave y el gasto?#
Un endpoint de chat público es una invitación al abuso. Antes de compartir el enlace:
- La clave solo en una variable de entorno, nunca en el código ni en el repositorio.
- Límite de peticiones por IP o por usuario, aplicado en el borde o con una librería en FastAPI.
- Tope de gasto en el panel del proveedor. Es la red de seguridad si falla el límite de tu código.
- Exige autenticación si el bot es de uso interno o para clientes.
- Trata el texto del usuario como no confiable. Alguien puede intentar que el modelo ignore el prompt de sistema. Lee qué es el prompt injection antes de darle herramientas o datos sensibles al modelo.
Para estimar la factura, mira cuánto cuesta una API de LLM.
¿Qué necesita el servidor para alojar esto?#
- Un proceso siempre encendido. Las plataformas que suspenden la app por inactividad provocan una primera respuesta lenta. Para un chat, prefiere un contenedor que no hiberne.
- HTTPS. El navegador bloquea llamadas inseguras desde páginas HTTPS.
- Soporte para respuestas en streaming. Los proxies que guardan la respuesta en búfer rompen el efecto. Prueba con
curl -Nya en el entorno final. - Poca RAM. El servidor solo reenvía texto, así que el consumo es bajo. Mide con carga real y mira cómo dimensionar RAM y CPU.
- Logs. Los vas a necesitar para descubrir por qué el proveedor devolvió un error 429 o 5xx. Para el framework en sí, mira alojar FastAPI, Flask y Django.
¿Qué errores son comunes?#
- El streaming llega todo de golpe: hay un proxy o una compresión guardando en búfer entre la app y el navegador. Prueba directamente en la app con
curl -N. - Error 401 del proveedor: la variable
ANTHROPIC_API_KEYno está definida en el entorno de producción. - Error 404 o "model not found": el ID de
ANTHROPIC_MODELestá mal o el modelo fue retirado. Elige otro de la lista oficial y reinicia la app, sin tocar el código. - Error 422 de FastAPI: el cuerpo no coincide con el modelo de Pydantic (por ejemplo,
roledistinto deuser/assistant, o una conversación vacía). - Factura alta a fin de mes: falta un límite por usuario o el
max_tokenses demasiado alto. Mira la sección de protección.
Cómo hacerlo en Square Cloud#
La sección sobre el servidor pedía un proceso siempre encendido, HTTPS, streaming sin búfer y logs. En Square Cloud, la API corre en un contenedor aislado y siempre encendido, sin cold start ni modo de suspensión, y toda aplicación web recibe un subdominio *.squareweb.app con HTTPS. El proxy delante de la aplicación no corta conexiones largas y deja pasar SSE y WebSocket sin búfer; aun así, repite la prueba con curl -N en el subdominio.
- Sube
main.pyyrequirements.txtcomo ZIP en el panel, o usa la CLI, GitHub o la extensión de VS Code. Al iniciar, la plataforma instala elrequirements.txt. El archivosquarecloud.appes opcional: el panel lo genera en el deploy, o lo escribes en la raíz del proyecto. - Elige
main.pycomo archivo principal. El bloque final del código ya escucha en0.0.0.0, en el puerto de la variablePORT, que define la plataforma. Una aplicación web usa al menos 512 MB del pool de RAM del plan. - Registra
ANTHROPIC_API_KEYyANTHROPIC_MODELen las variables de entorno de la aplicación. El cambio se aplica en el siguiente reinicio, sin rebuild. - Sigue los logs en tiempo real para ver los errores 429 o 5xx del proveedor.
Si prefieres no mantener una cuenta en un proveedor de modelos, el AI Gateway, disponible desde el plan Standard (R$44,99 al mes), es una API compatible con la de OpenAI para el modelo cubic, en beta con acceso anticipado sin costo extra. Con el SDK openai usas la base URL https://api.squarecloud.app/v2/ai, una clave de la cuenta con el scope ai:chat y model="cubic"; el modelo también puede llamar a tus funciones (hasta 32 tools) y buscar en la web por su cuenta. Para este chatbot hay dos salvedades: el gateway todavía no hace streaming, así que la respuesta llega entera al final; y el Standard atiende una solicitud a la vez, hasta 1000 por día. Un chat público con muchos visitantes simultáneos sigue mejor servido por un proveedor con streaming. Los límites y los planes pueden cambiar cuando termine la beta.
El Hobby, desde R$12,49 al mes, aloja la API, pero no incluye el gateway. Mira los planes en hosting de APIs.
IA
Aloja apps con IA en contenedores siempre encendidos
Preguntas frecuentes
¿Necesito GPU para alojar un chatbot con IA?
No, si usas un modelo por API (Claude, GPT, Gemini). Quien ejecuta la inferencia es el proveedor, y tu servidor solo reenvía texto. La GPU solo entra si alojas tú mismo un modelo abierto.
¿Puedo llamar a la API del modelo directamente desde el navegador?
No. La clave quedaría visible para cualquier visitante y otra persona podría gastar tu crédito. La llamada tiene que salir de un backend tuyo.
¿Cuánta memoria usa un chatbot así?
Poca, porque solo reenvía texto. Mide con carga real antes de dimensionar.
¿Cómo evito que alguien gaste mi crédito de IA?
Limita las peticiones por IP o por usuario, limita el tamaño de la conversación y el max_tokens, y configura un tope de gasto en el panel del proveedor.
Más en IA
Ver los 13 artículos- ¿Cuánto cuesta crear y mantener un chatbot con IA?Mantener un chatbot con IA cuesta tokens del modelo, hosting, base de datos y, con RAG, contexto extra. Mira cómo hacer la cuenta por conversación.
- ¿Cuánto cuesta un sistema RAG? Embeddings, base de datos y LLMUn RAG tiene tres costos: embeddings, base de datos vectorial y LLM. Mira la cuenta para mil preguntas al día, con precios hipotéticos, y dónde crece la factura.
- Cómo crear un bot de Discord con IACrea un bot de Discord con IA en discord.js: comando /ask, clave de API en variable de entorno, memoria por canal, límites de Discord y cómo ponerlo en línea.
- Cómo hospedar n8nHospedar n8n es ejecutar su servidor en un proceso siempre encendido, con URL pública HTTPS, base de datos y clave de cifrado fija. Paso a paso.