IA aplicada, con límites y revisión
Integro modelos, agentes y servidores MCP en sistemas que ya están en producción. Cada integración tiene un límite escrito y cada línea generada pasa por revisión antes del deploy.
Cuándo uso un modelo
Uso un modelo cuando la tarea se repite, tiene una entrada clara y alguien puede revisar la salida. Clasificar texto libre, extraer datos de documentos o preparar un primer borrador son buenos candidatos.
Si la tarea pasa una vez al mes, un script o una persona la resuelve mejor y más barato.
Cuándo no
- Una consulta lenta por un índice faltante. Eso se mide y se arregla en la base de datos.
- Un modelo de datos mal pensado. La IA hereda el desorden y lo repite más rápido.
- Un proceso que nadie definió. Automatizarlo solo produce confusión con mejor tiempo de respuesta.
Cuando la respuesta es código y no IA, lo digo. Lo desarrollo en cuándo no usar IA.
Agentes con permisos acotados
Un agente recibe las herramientas que la tarea necesita y ninguna más. Cada herramienta tiene un alcance definido: qué puede leer, qué puede escribir y qué queda registrado.
Las acciones que cambian datos o salen del sistema piden confirmación de una persona. Un agente sin límites es un incidente esperando su turno.
Servidores MCP
MCP (Model Context Protocol) es un protocolo abierto para conectar un modelo con herramientas y datos propios. Lo uso para exponer solo lo que la tarea necesita. Cada servidor tiene credenciales propias y no escribe cuando la tarea es de lectura.
Lo que el agente no puede leer, no puede filtrar.
Qué datos no salen del entorno
- Credenciales, claves y secretos de cualquier tipo.
- Datos personales de clientes, salvo acuerdo explícito.
- Código o datos que el contrato marca como confidenciales.
Antes de conectar el modelo de un proveedor externo reviso qué se envía, qué conserva el proveedor y por cuánto tiempo.
Cómo audito el código generado
Leo lo que el modelo escribe antes de que llegue a producción. Rápido no es lo mismo que correcto.
- Validación de entrada. Qué pasa con un valor vacío, enorme o malicioso.
- Contratos. Si la función devuelve lo que el resto del sistema espera.
- Manejo de errores. Si el error se registra, se propaga o se traga.
- Dependencias. Si apareció una librería nueva y quién la mantiene.
- Secretos. Si quedó una clave, un token o una URL interna en el código.
- Pruebas. Si hay una prueba que falle cuando el cambio está mal.
La lista completa, con ejemplos, está en cómo audito el código que escribe un modelo.
Un ejemplo de revisión
Ejemplo ilustrativo, escrito para esta página. No viene de un cliente.
# Lo que propuso el modelo
def buscar_ventas(request):
cliente = request.args["cliente"]
sql = f"SELECT * FROM ventas WHERE cliente = '{cliente}'"
filas = db.execute(sql).fetchall()
return {"filas": filas}
Compila y devuelve datos. En la revisión aparecen cinco problemas:
- Arma el SQL con el valor que manda el usuario. Eso es inyección SQL.
- Si falta el parámetro, la excepción llega cruda al usuario.
SELECT *devuelve columnas que la pantalla no usa y que quizá no debería ver.- No hay límite de filas. Un cliente con años de histórico trae la tabla entera.
- Ninguna prueba cubre estos casos.
# Lo que llegó a producción después de la revisión
def buscar_ventas(request):
cliente = request.args.get("cliente", "").strip()
if not cliente or len(cliente) > 64:
return {"error": "cliente inválido"}, 400
sql = (
"SELECT id, fecha, total FROM ventas "
"WHERE cliente = %s ORDER BY fecha DESC LIMIT 100"
)
filas = db.execute(sql, (cliente,)).fetchall()
return {"filas": filas}
Casos y artículos
El caso de IA aplicada todavía no está publicado. No lo voy a rellenar con un ejemplo inventado. Mientras tanto, los casos de sistemas en producción muestran cómo trabajo sobre código que ya existe.