Tips & Tricks

Guía completa de harness engineering: cómo construir agentes de IA al estilo Claude Code

Un buen prompt no basta para dominar un LLM. Aprende a entrelazar herramientas, contexto y bucles de control en un harness, con código funcional y la arquitectura de Claude Code como guía.

La era de «lanzar un prompt a ChatGPT y ya está» terminó. Desde 2025, el centro de gravedad de la ingeniería de IA se ha desplazado rápidamente hacia el harness engineering. Es una de las palabras clave que más se repiten en los blogs internos de Anthropic y en la investigación sobre agentes de OpenAI.

Y aun así, pregunta a alguien «¿qué es un harness?» y pocas personas dan una respuesta contundente. En este artículo desentrañamos el harness engineering con código ejecutable y la arquitectura de Claude Code como caso de estudio. Al terminar tendrás todo lo necesario para montar tu propio agente desde cero.

Un harness es el «andamiaje» que rodea a la IA

«Harness» significaba originalmente arnés para un caballo o cinturón de seguridad para un escalador. En software pensamos en el «test harness»: la estructura externa que permite que algo funcione.

En IA, un harness es la capa envolvente alrededor del LLM. De forma concreta, agrupa todo lo que el modelo necesita para resolver tareas reales:

  • Herramientas: leer archivos, ejecutar comandos, llamar APIs, etc.
  • Gestión del contexto: qué recordar, qué olvidar, qué comprimir
  • Bucle de control: cuándo invocar, cuándo detener, cuándo reintentar
  • Permisos y salvaguardas: evitar que operaciones destructivas se ejecuten solas
  • Memoria: conocimiento que persiste entre sesiones

El prompt es solo una entrada a este harness. Con un harness débil, incluso el prompt más ingenioso choca con un techo de rendimiento. Por eso se oye cada vez más: «la ingeniería de prompts ya no es suficiente».

Por qué importa el harness: piénsalo como un bucle OODA

Un LLM por sí solo únicamente puede «generar el siguiente token». Para resolver tareas reales hay que girar un bucle OODA (Observe → Orient → Decide → Act), tomado de la estrategia militar.

FaseContenidoResponsable
Observe (Observar)Leer el entorno (archivos, consultas a BD)Harness
Orient (Orientar)Organizar la información y pasarla al LLMHarness
Decide (Decidir)Elegir el siguiente pasoLLM
Act (Actuar)Ejecutar (comandos, llamadas a API)Harness

Como ves, tres de las cuatro fases corresponden al harness. El LLM solo brilla en la decisión. La calidad del andamiaje que lo rodea determina la calidad del agente completo.

Tres niveles de harness, con ejemplos

Resolvamos la misma tarea, «generar un artículo de blog», en tres niveles crecientes.

Nivel 1: llamada cruda a la API (casi sin harness)

import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic();

const res = await client.messages.create({
  model: "claude-opus-4-6",
  max_tokens: 4096,
  messages: [{ role: "user", content: "Escribe un artículo de blog" }],
});
console.log(res.content[0].text);

Resultado: texto genérico y vacío. Tema y estructura cambian en cada ejecución.

Nivel 2: añadir herramientas (harness intermedio)

const tools = [
  {
    name: "read_existing_posts",
    description: "Obtiene la lista de artículos existentes con sus títulos",
    input_schema: { type: "object", properties: {} },
  },
  {
    name: "write_post",
    description: "Escribe un archivo MDX",
    input_schema: {
      type: "object",
      properties: {
        slug: { type: "string" },
        frontmatter: { type: "object" },
        body: { type: "string" },
      },
      required: ["slug", "frontmatter", "body"],
    },
  },
];

async function runAgent(userGoal: string) {
  let messages = [{ role: "user", content: userGoal }];
  while (true) {
    const res = await client.messages.create({
      model: "claude-opus-4-6",
      max_tokens: 4096,
      tools,
      messages,
    });
    if (res.stop_reason === "end_turn") break;

    // El harness ejecuta la llamada a la herramienta
    const toolUse = res.content.find((c) => c.type === "tool_use");
    const result = await executeTool(toolUse.name, toolUse.input);
    messages.push({ role: "assistant", content: res.content });
    messages.push({
      role: "user",
      content: [{ type: "tool_result", tool_use_id: toolUse.id, content: result }],
    });
  }
}

Resultado: se escoge un tema no duplicado y se produce un MDX con formato correcto. Solo añadir herramientas cambia radicalmente la calidad.

Nivel 3: un harness completo al nivel de Claude Code

  • Bucle autónomo (aprobación del usuario, reintentos ante errores)
  • Compresión de contexto (resumir conversaciones largas para ahorrar tokens)
  • Delegación a subagentes (traducir en contexto aislado)
  • Prompt caching (no reenviar la parte estática)
  • Hooks (lint automático antes del commit)

Armar todo esto a mano es un proyecto mayor. Por eso estudiar Claude Code como implementación de referencia resulta tan valioso.

Desmontando el harness de Claude Code

Claude Code es el harness de agente más pulido dentro de Anthropic. Se descompone en estas cinco capas.

Capa 1: diseño de herramientas

De fábrica vienen Read, Edit, Write, Bash, Glob, Grep, Agent, etc. Presta atención a la granularidad:

  • Grep no es un simple grep, sino un envoltorio de ripgrep: preciso y veloz
  • Edit no reescribe el archivo completo, sino que sustituye cadenas concretas: diff mínimo
  • Agent crea un subagente con contexto aislado

La calidad de las herramientas se refleja directamente en la del agente. «Con que funcione basta» no vale. Diseña las herramientas con idempotencia, mensajes de error claros y una única responsabilidad.

Capa 2: contexto por capas

~/.claude/CLAUDE.md         ← reglas globales
./CLAUDE.md                 ← reglas del proyecto (carga automática)
~/.claude/memory/           ← memoria a largo plazo (entre sesiones)
  ├── user_profile.md
  ├── feedback_xxx.md
  └── project_xxx.md
historial de la conversación ← turnos recientes
tareas/plan                  ← progreso de la sesión actual

Cada capa tiene una vida útil y un rol distintos. Escribir donde no toca hace que la información se pierda o, peor aún, que datos obsoletos sobrevivan. «Solo esta sesión» va en tareas; «se usará siempre» va en memoria.

Capa 3: delegación a subagentes

Con la herramienta Agent puedes lanzar otro agente en un contexto propio.

# El principal solo da instrucciones; el trabajo pesado va al subagente
Agent(
  subagent_type: "general-purpose",
  prompt: "Traduce blog/harness.mdx al inglés y a otros 8 idiomas,
           guarda cada versión en blog-{lang}/ y reporta"
)

Así el contexto principal no se contamina con logs ruidosos. Logs de compilación, traducciones intermedias, volcados de búsqueda… cualquier trabajo del que solo necesitas el resultado final se delega sin problema.

Capa 4: hooks (procesamiento determinista)

En .claude/settings.json puedes enganchar comandos de shell antes y después de las llamadas a herramientas.

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          { "type": "command", "command": "npx tsc --noEmit" }
        ]
      }
    ]
  }
}

Tras cada edición se ejecuta automáticamente la comprobación de tipos. Todo lo que deba gestionarse de forma determinista en lugar de pedírselo al LLM cada vez pertenece a un hook.

Capa 5: modos de permisos

{
  "permissions": {
    "allow": ["Read", "Grep", "Glob"],
    "deny": ["Bash(rm -rf*)", "Bash(git push --force*)"],
    "ask": ["Write", "Edit", "Bash"]
  }
}

Deniega de forma explícita los comandos destructivos y exige aprobación para las escrituras. Los accidentes ocurren cuando algo se ejecuta sin supervisión, así que esta capa define tu seguridad operativa.

Cinco trampas frecuentes

1. Demasiadas herramientas Si le das 30 herramientas al modelo se pierde al elegir y la precisión cae. Regla empírica: entre 5 y 15. Lo que sobre, llévalo a subagentes.

2. No aprovechar el prompt caching Sin usar cache_control de la API de Claude, reenvías el system prompt largo completo en cada turno y la factura se dispara. Ten presente el TTL de 5 minutos y cachea la parte estática.

messages: [{
  role: "system",
  content: [
    { type: "text", text: longStaticInstructions,
      cache_control: { type: "ephemeral" } },   // ← esto
    { type: "text", text: dynamicContext },
  ],
}]

3. Mensajes de error que el LLM no puede interpretar Si una herramienta devuelve únicamente Error: undefined, el modelo no puede autocorregirse. Explica qué falló y cómo arreglarlo.

throw new Error(
  `El archivo '${path}' no existe. ` +
  `Archivos actualmente en scripts/: ${list.join(", ")}`
);

4. Saltarse la aprobación humana Autorizar de manera automática acciones destructivas (borrar, force push, actualizaciones de BD) garantiza un desastre tarde o temprano. Por defecto: preguntar para escritura, denegar borrados.

5. No ordenar la memoria La información vieja empuja al agente hacia suposiciones erróneas. La memoria también necesita limpiezas periódicas (en Claude Code mediante /compact o edición manual).

Pon a correr tu mini harness

Para terminar, un harness mínimo en Node.js + TypeScript.

// mini-harness.ts
import Anthropic from "@anthropic-ai/sdk";
import { readFileSync, writeFileSync } from "fs";

const client = new Anthropic();

const tools = [
  { name: "read_file",
    description: "Leer un archivo de texto",
    input_schema: { type: "object", properties: { path: { type: "string" } }, required: ["path"] } },
  { name: "write_file",
    description: "Escribir un archivo de texto",
    input_schema: { type: "object", properties: { path: { type: "string" }, content: { type: "string" } }, required: ["path", "content"] } },
];

const executors = {
  read_file: ({ path }) => readFileSync(path, "utf-8"),
  write_file: ({ path, content }) => { writeFileSync(path, content); return `written ${path}`; },
};

async function loop(goal: string, maxSteps = 10) {
  const messages: any[] = [{ role: "user", content: goal }];
  for (let i = 0; i < maxSteps; i++) {
    const res = await client.messages.create({
      model: "claude-opus-4-6", max_tokens: 4096, tools, messages,
    });
    messages.push({ role: "assistant", content: res.content });
    if (res.stop_reason === "end_turn") return res.content;

    const toolUse = res.content.find((c: any) => c.type === "tool_use") as any;
    if (!toolUse) return res.content;
    const result = executors[toolUse.name](toolUse.input);
    messages.push({
      role: "user",
      content: [{ type: "tool_result", tool_use_id: toolUse.id, content: String(result) }],
    });
  }
}

await loop("Lee README.md y guarda un resumen de 3 líneas en TL;DR.md");

Con esto ya tienes un miniagente que puede leer un archivo existente y escribir otro nuevo. Añade herramientas como Grep, Bash y Agent, y tendrás una versión reducida de Claude Code.

Conclusión: del redactor de prompts al arquitecto de harness

Enfoque anteriorEnfoque actual
Buen prompt, buen resultadoBuen harness, buen resultado
Elegir un modeloDiseñar modelo + herramientas + contexto + permisos
Preguntas puntualesOperación continua en bucle

Claude Code es el mejor material didáctico para asimilar este cambio de perspectiva. No te limites a usarlo: desmóntalo e incorpora las ideas a tu propio agente. Esa es la actitud que se exige a los ingenieros de IA desde 2026.

Copia y pega el mini harness de arriba y ejecútalo. Diez minutos después habrás dado el primer paso hacia tu agente personal.

Artículos relacionados

Referencias

#claude-code #agent-sdk #harness #prompt-engineering #llm #anthropic

Lleva tu flujo con Claude Code al siguiente nivel

50 plantillas de prompts probadas en producción, listas para copiar y pegar en Claude Code.

Gratis

PDF gratuito: Hoja de trucos de Claude Code en 5 minutos

Solo deja tu correo y te enviaremos al instante la hoja de trucos en una página A4.

Cuidamos tus datos personales y nunca enviamos spam.

Masa

Sobre el autor

Masa

Ingeniero apasionado por Claude Code. Dirige claudecode-lab.com, un medio tecnológico en 10 idiomas con más de 2.000 páginas.