Uso Idiomático de Herramientas en Go, Java, C#, PHP y Ruby
El uso de herramientas (tool_use) es el mismo protocolo en todas partes donde se ejecuta Claude, pero definir un esquema de herramienta y leer el resultado se ve diferente en cada lenguaje. Esta página compara esa sintaxis en los cinco SDKs oficiales más allá de Python y TypeScript.
Cómo Usar Esta Lista
- Lee la entrada para tu lenguaje primero, luego hojea las otras para reconocer el patrón cuando leas ejemplos entre lenguajes.
- Cada ejemplo define la misma herramienta (una función
get_weatherque toma una cadenacity) para que la comparación sea directa. - El protocolo de comunicación (lo que Claude realmente envía y espera recibir) es idéntico en los cinco; solo cambia la sintaxis del lenguaje anfitrión.
- Empareja esto con el bucle general de
tool_use(solicitud, bloquetool_use, ejecutar la herramienta, enviartool_result) si no has visto ese flujo antes.
Go: Esquemas Basados en Structs
Go describe el esquema de entrada de una herramienta como un struct tipado más un ToolInputSchemaParam explícito, y lee los resultados cambiando el tipo de los bloques de contenido.
type WeatherInput struct {
City string `json:"city"`
}
weatherTool := anthropic.ToolParam{
Name: anthropic.String("get_weather"),
Description: anthropic.String("Obtener el clima actual de una ciudad."),
InputSchema: anthropic.ToolInputSchemaParam{
Type: "object",
Properties: map[string]interface{}{
"city": map[string]string{"type": "string"},
},
Required: []string{"city"},
},
}
for _, block := range message.Content {
if toolUse, ok := block.AsAny().(anthropic.ToolUseBlock); ok {
var input WeatherInput
json.Unmarshal(toolUse.Input, &input)
}
}- El esquema se construye a partir de las etiquetas
jsonde un struct de Go más un mapaPropertiesexplícito; Go no tiene reflexión de JSON Schema incorporada, por lo que escribes ambos a mano. - Leer un resultado significa cambiar el tipo de
block.AsAny()para encontrar unToolUseBlock, luego hacerjson.Unmarshalde los bytes crudos deInputen tu propio struct tipado. - Este es el más verboso de los cinco, a cambio de la verificación de campos en tiempo de compilación en el destino de
unmarshal.
Java: Esquemas con Patrón Builder
Java expresa el mismo esquema a través de su patrón builder y lee los resultados inspeccionando objetos de bloque de contenido tipados.
Tool weatherTool = Tool.builder()
.name("get_weather")
.description("Obtener el clima actual de una ciudad.")
.inputSchema(Tool.InputSchema.builder()
.properties(JsonValue.from(Map.of(
"city", Map.of("type", "string")
)))
.putAdditionalProperty("required", JsonValue.from(List.of("city")))
.build())
.build();
for (ContentBlock block : message.content()) {
if (block.isToolUse()) {
ToolUseBlock toolUse = block.asToolUse();
String city = toolUse.input().asObject().get("city").asString().get();
}
}Tool.builder()refleja la misma convención de builder fluida que Java usa en todas partes, incluso para la solicitud de mensaje en sí.- Las propiedades del esquema de entrada se construyen como un
Mapenvuelto enJsonValue, ya que Java no tiene sintaxis nativa de literales JSON. - Leer un resultado significa verificar
block.isToolUse()antes de llamar ablock.asToolUse(), luego navegar por el JSON de entrada como un árbol genérico en lugar de hacerunmarshalautomáticamente a un POJO.
C#: Objetos de Solicitud Tipados
C# define el esquema como un objeto tipado y lee los resultados a través de la coincidencia de patrones en los tipos de bloque de contenido.
var weatherTool = new Tool
{
Name = "get_weather",
Description = "Get the current weather for a city.",
InputSchema = new
{
type = "object",
properties = new { city = new { type = "string" } },
required = new[] { "city" }
}
};
foreach (var block in response.Content)
{
if (block is ToolUseContent toolUse)
{
var city = toolUse.Input["city"].ToString();
}
}InputSchemaa menudo se construye como un objeto anónimo serializado a JSON, ya que C# no tiene un tipo JSON Schema de primera clase en el SDK.- El manejo de resultados utiliza el operador
isde coincidencia de patrones de C# para verificar el tipo en tiempo de ejecución del bloque, el equivalente en C# del switch de tipos de Go o la verificaciónisToolUse()de Java. toolUse.Inputsuele ser una estructura similar a un diccionario en la que se indexa por clave, más parecido al enfoque de PHP y Ruby que al patrón estricto deunmarshala struct de Go.
PHP: Arrays Asociativos
PHP no tiene tipado en tiempo de compilación para esto, por lo que tanto el esquema como el resultado son simples arrays asociativos.
$weatherTool = [
'name' => 'get_weather',
'description' => 'Get the current weather for a city.',
'input_schema' => [
'type' => 'object',
'properties' => [
'city' => ['type' => 'string'],
],
'required' => ['city'],
],
];
foreach ($response->content as $block) {
if ($block->type === 'tool_use') {
$city = $block->input['city'];
}
}- El esquema de la herramienta se escribe como un array asociativo anidado que refleja directamente la forma del JSON Schema, clave por clave.
- El manejo de resultados verifica
$block->type === 'tool_use'y luego indexa$block->inputcomo un array normal de PHP, ya que PHP no haceunmarshala clases tipadas por defecto. - Este es el menos ceremonioso de los cinco: sin builders, sin structs, solo arrays que coinciden casi textualmente con el formato de comunicación.
Ruby: Hashes
El enfoque de Ruby es similar al de PHP, utilizando hashes con claves simbólicas en lugar de arrays asociativos.
weather_tool = {
name: "get_weather",
description: "Get the current weather for a city.",
input_schema: {
type: "object",
properties: {
city: { type: "string" }
},
required: ["city"]
}
}
response.content.each do |block|
if block.type == "tool_use"
city = block.input["city"]
end
end- El hash del esquema utiliza claves simbólicas (
city:) en lugar de claves de cadena, lo cual es idiomático en Ruby pero aún se serializa al mismo JSON Schema que espera la API de Mensajes. - El manejo de resultados verifica
block.type == "tool_use"y leeblock.inputcomo un hash, la misma forma que PHP produce a partir de su array asociativo. - Ruby y PHP son el par más cercano aquí: ambos omiten por completo el tipado estático y dejan que la forma del hash/array haga el trabajo.
Comparación de los Cinco de un Vistazo
| Lenguaje | Forma del esquema | Acceso al resultado | Tipado |
|---|---|---|---|
| Go | Struct + ToolInputSchemaParam explícito | Cambio de tipo a ToolUseBlock, luego json.Unmarshal | Estático, más verboso |
| Java | Patrón Builder (Tool.builder()) | block.isToolUse() luego block.asToolUse() | Estático, con mucho uso de builder |
| C# | Objeto tipado / objeto anónimo | Coincidencia de patrones con is ToolUseContent | Estático, menos verboso que Go/Java |
| PHP | Array asociativo | Verificar type === 'tool_use', indexar array | Dinámico |
| Ruby | Hash con claves simbólicas | Verificar type == "tool_use", indexar hash | Dinámico |
Manejo del Resultado: La Forma Compartida
Independientemente del lenguaje, todos los SDKs esperan el mismo siguiente paso una vez que has leído un bloque tool_use: ejecutar la herramienta y luego enviar un mensaje tool_result a Claude haciendo referencia al ID del tool_use.
resultMessage := anthropic.NewUserMessage(
anthropic.NewToolResultBlock(toolUse.ID, weatherJSON, false),
)- El bloque
tool_resultsiempre lleva el ID del bloquetool_useoriginal, para que Claude pueda emparejar el resultado con la llamada que hizo. - Este requisito de coincidencia de ID es idéntico en los cinco SDKs; solo la sintaxis para construir el bloque de resultado difiere.
- Omitir este paso, o enviar un
tool_resultcon un ID que no coincide, produce una solicitud que la API de Mensajes rechaza de la misma manera en todos los lenguajes.
Preguntas Frecuentes
¿El protocolo tool_use es realmente diferente entre estos cinco SDKs?
No. El protocolo de comunicación, lo que Claude envía como un bloque tool_use y espera recibir como tool_result, es idéntico en los cinco. Solo la sintaxis del lenguaje anfitrión para construir el esquema y leer el resultado difiere.
¿Qué SDK tiene menos código repetitivo para definir una herramienta?
PHP y Ruby, ya que ambos usan arrays asociativos o hashes que se mapean casi directamente al JSON Schema que espera la API, sin ceremonia de builder o struct.
¿Qué SDK ofrece la mayor seguridad en tiempo de compilación para las entradas de herramientas?
Go, ya que json.Unmarshal apunta a un struct real de Go con campos tipados, detectando discrepancias de forma en tiempo de compilación en el lado del consumidor (aunque la definición del esquema en sí todavía se escribe a mano).
¿Tengo que usar un builder en Java, o puedo construir un Tool directamente?
El patrón builder es el punto de entrada idiomático del SDK y el que usan la mayoría de los ejemplos, coincidiendo con la forma en que Java construye las solicitudes de mensajes en general.
¿Cómo sabe C# qué tipo de bloque de contenido recibió?
A través del operador is de coincidencia de patrones de C#, verificando si un bloque de contenido is ToolUseContent antes de acceder a los campos específicos de la herramienta.
¿Validan PHP y Ruby el input_schema antes de enviarlo?
No, ninguno de los lenguajes realiza validación JSON Schema del lado del cliente. Ambos envían el array o hash tal cual; un esquema mal formado solo se detecta cuando la API de Mensajes rechaza la solicitud.
¿Qué necesita cada SDK para enviar un tool_result de vuelta a Claude?
- El ID del bloque
tool_useoriginal - La salida de la herramienta, serializada como el contenido del resultado
- Una bandera que indique si la llamada a la herramienta fue un error, en los SDKs que exponen una
¿Puedo mezclar definiciones de herramientas escritas en diferentes lenguajes en la misma conversación?
No directamente. Cada servicio que habla con Claude define y ejecuta sus propias herramientas localmente; si dos servicios en diferentes lenguajes exponen herramientas, generalmente son dos integraciones separadas, no una definición compartida.
¿La verbosidad de Go aquí significa que es la opción incorrecta para servicios con muchas herramientas?
No necesariamente. La verbosidad adicional proporciona verificación en tiempo de compilación en el destino de unmarshal, lo cual muchos equipos prefieren para servicios con muchas herramientas y contratos de entrada estrictos.
¿Dónde debería mirar si quiero el bucle completo de solicitud/respuesta, no solo la sintaxis del esquema?
Consulta el artículo del bucle general de tool_use en la sección de tool-use-function-calling, y el tutorial específico de Go en esta sección para un ejemplo completo y ejecutable.
Relacionado
- Llamando a Claude desde Go con el SDK Oficial - un ejemplo completo y ejecutable de
tool_useen Go con la solicitud de seguimiento incluida - Fundamentos de Otros SDKs Oficiales - primeras llamadas en cada uno de los cinco lenguajes antes de agregar herramientas
- Más allá de Python y TypeScript: Los Otros SDKs Oficiales de Claude - por qué estos SDKs divergen idiomáticamente a pesar de compartir un protocolo
- Construyendo un Bucle de Uso de Herramientas Multi-Turno - el flujo agnóstico al lenguaje de solicitud/tool_result/seguimiento
- Definición de Esquemas de Herramientas con Nombre, Descripción y Esquema de Entrada - la forma JSON Schema que la sintaxis de cada lenguaje produce finalmente
Versiones de Stack: Escrito contra la línea de modelos de Claude actual a partir de ~junio de 2026 - Claude Fable 5, Claude Opus 4.8, Claude Sonnet 5 (el predeterminado) y Claude Haiku 4.5 - y los SDKs oficiales actuales para Go, Java, C#, PHP y Ruby. Los nombres de modelos, versiones de SDK y precios cambian rápidamente; verifica los detalles actuales en platform.claude.com/docs antes de confiar en ellos.