Requisitos previos
Antes de empezar, asegúrate de tener instalado lo siguiente en tu máquina de desarrollo:
- Node.js (v18.0.0 o superior)
- Una API key de Anthropic (console.anthropic.com)
- TypeScript y ts-node (opcional, para ejecutar directamente)
Inicializa el proyecto e instala el SDK oficial
Crea un directorio aislado e instala el SDK oficial de Anthropic para Node.js y `dotenv` para manejar las variables de entorno de forma segura:
mkdir claude-agent && cd claude-agent
npm init -y
npm install @anthropic-ai/sdk dotenv
npm install -D typescript @types/node ts-node
Crea un archivo .env en la carpeta raíz:
ANTHROPIC_API_KEY="sk-ant-api03-..."
Define el cliente y el esquema de la herramienta
Crea index.ts. Vamos a definir una herramienta real que consulta el inventario por SKU:
import Anthropic from "@anthropic-ai/sdk";
import * as dotenv from "dotenv";
dotenv.config();
const anthropic = new Anthropic();
// 1. Definir la especificación de la herramienta con un esquema estricto
const tools: Anthropic.Tool[] = [
{
name: "lookup_inventory",
description: "Check the available warehouse stock and restock date for a product SKU.",
input_schema: {
type: "object",
properties: {
sku: {
type: "string",
description: "Product SKU identifier (e.g., 'KB-PRO-99')"
}
},
required: ["sku"]
}
}
];
Ejecuta el ciclo de llamada a la herramienta
Cuando Claude determina que para responder necesita datos externos, devuelve un bloque tool_use con stop_reason: "tool_use". Tu aplicación ejecuta la herramienta y le devuelve el resultado al modelo:
async function runAgent(userPrompt: string) {
const messages: Anthropic.MessageParam[] = [
{ role: "user", content: userPrompt }
];
// Primera llamada: Claude decide si usar la herramienta
const response = await anthropic.messages.create({
model: "claude-3-7-sonnet-20250219",
max_tokens: 1024,
tools: tools,
messages: messages
});
console.log("Claude Stop Reason:", response.stop_reason);
// Verificar si se pidió ejecutar la herramienta
if (response.stop_reason === "tool_use") {
const toolBlock = response.content.find(block => block.type === "tool_use");
if (toolBlock && toolBlock.type === "tool_use") {
console.log(`Executing tool "${toolBlock.name}" with args:`, toolBlock.input);
// Consulta simulada a la base de datos
const mockResult = {
sku: (toolBlock.input as any).sku,
in_stock: 42,
warehouse: "Austin-TX",
next_delivery: "2026-11-15"
};
// Agregar el mensaje del asistente y el mensaje tool_result
messages.push({ role: "assistant", content: response.content });
messages.push({
role: "user",
content: [
{
type: "tool_result",
tool_use_id: toolBlock.id,
content: JSON.stringify(mockResult)
}
]
});
// Segunda llamada: Claude genera la respuesta final para el usuario
const finalResponse = await anthropic.messages.create({
model: "claude-3-7-sonnet-20250219",
max_tokens: 1024,
tools: tools,
messages: messages
});
console.log("\nFinal Answer:\n", (finalResponse.content[0] as any).text);
}
}
}
runAgent("How many units of SKU 'KB-PRO-99' do we have in stock?");
Ejecuta y verifica la salida esperada
Ejecuta el script con ts-node:
$ npx ts-node index.ts
Claude Stop Reason: tool_use
Executing tool "lookup_inventory" with args: { sku: 'KB-PRO-99' }
Final Answer:
There are currently 42 units of SKU 'KB-PRO-99' in stock at the Austin, TX warehouse.
The next scheduled delivery is expected on November 15, 2026.
Valida siempre los argumentos de entrada de las herramientas con un validador en tiempo de ejecución como Zod antes de pasarlos a bases de datos internas o pasarelas de pago. Así te proteges de la manipulación de argumentos mediante prompt injection.