Llamar a Claude desde Go con el SDK oficial
anthropic-sdk-go es el cliente oficial de Go para la API de Mensajes de Claude, que proporciona a los servicios Go solicitudes tipadas, un iterador de streaming y soporte estructurado para tool_use sin necesidad de llamadas HTTP manuales.
Resumen
anthropic-sdk-go envuelve la misma API de Mensajes utilizada por todos los demás SDK oficiales de Claude, pero construida en torno a las convenciones de Go: structs de solicitud y respuesta tipadas, opciones funcionales para la configuración del cliente y errores devueltos como valores en lugar de excepciones.
Un cliente es un único objeto de larga duración que construyes una vez por proceso y reutilizas en las solicitudes, ya que contiene el transporte HTTP y la clave API.
Las tres cosas que la mayoría de los servicios Go necesitan de Claude son una llamada simple de solicitud/respuesta, una llamada de streaming para salida incremental y un bucle tool_use para permitir que Claude llame a funciones en tu servicio.
Las tres residen en la misma interfaz client.Messages, difiriendo solo en qué método llamas y cómo consumes el resultado.
Esta página cubre las tres, en el orden en que la mayoría de los servicios Go las adoptan.
Receta
Tarjeta de receta de referencia rápida, lista para copiar y pegar.
client := anthropic.NewClient(
option.WithAPIKey(os.Getenv("ANTHROPIC_API_KEY")),
)
message, err := client.Messages.New(context.Background(), anthropic.MessageNewParams{
Model: anthropic.ModelClaudeSonnet5,
MaxTokens: 1024,
System: anthropic.String("Eres un asistente conciso."),
Messages: []anthropic.MessageParam{
anthropic.NewUserMessage(anthropic.NewTextBlock("Resume el planificador de Go en dos frases.")),
},
})
if err != nil {
log.Fatal(err)
}
fmt.Println(message.Content[0].Text)Cuándo recurrir a esto:
- Estás construyendo un servicio Go (API HTTP, CLI, trabajador en segundo plano) que necesita acceso tipado a Claude.
- Quieres comprobación en tiempo de compilación en los campos de solicitud en lugar de un cuerpo JSON crudo.
- Necesitas transmitir salida parcial a un cliente, o permitir que Claude llame a funciones en tu proceso a través de
tool_use. - Estás consolidando múltiples clientes HTTP ad hoc en una dependencia compartida y tipada.
Ejemplo de trabajo
Un único programa Go que construye un cliente, envía una solicitud de streaming e imprime tokens a medida que llegan.
package main
import (
"context"
"fmt"
"log"
"os"
"github.com/anthropics/anthropic-sdk-go"
"github.com/anthropics/anthropic-sdk-go/option"
)
func main() {
client := anthropic.NewClient(
option.WithAPIKey(os.Getenv("ANTHROPIC_API_KEY")),
)
ctx := context.Background()
stream := client.Messages.NewStreaming(ctx, anthropic.MessageNewParams{
Model: anthropic.ModelClaudeSonnet5,
MaxTokens: 512,
Messages: []anthropic.MessageParam{
anthropic.NewUserMessage(anthropic.NewTextBlock("Enumera tres beneficios de las goroutines de Go.")),
},
})
message := anthropic.Message{}
for stream.Next() {
event := stream.Current()
if err := message.Accumulate(event); err != nil {
log.Fatal(err)
}
switch delta := event.AsAny().(type) {
case anthropic.ContentBlockDeltaEvent:
if textDelta, ok := delta.Delta.AsAny().(anthropic.TextDelta); ok {
fmt.Print(textDelta.Text)
}
}
}
if err := stream.Err(); err != nil {
log.Fatal(err)
}
fmt.Println()
fmt.Println("razón de parada:", message.StopReason)
}Lo que esto demuestra:
client.Messages.NewStreamingdevuelve un iterador que controlas constream.Next()ystream.Current(), la forma estándar de iterador de Go.message.Accumulateconstruye elMessagefinal y completo a medida que llegan los eventos, por lo que obtienes tanto texto incremental como un objeto completo al final.- Los deltas de texto llegan como valores
ContentBlockDeltaEventsobre los que haces untype switch, coincidiendo con la estructura de los eventos enviados por el servidor subyacentes. stream.Err()debe comprobarse después de que finalice el bucle, ya que un error a mitad de transmisión no necesariamente aparece dentro del propio bucle.
Inmersión Profunda
Cómo funciona
- El SDK traduce cada struct Go tipado al mismo cuerpo JSON que espera la API de Mensajes; nada sobre el formato de transmisión cambia porque estés usando Go.
client.Messages.Newemite una única solicitud HTTP bloqueante y devuelve unMessagecompletamente poblado.client.Messages.NewStreamingabre una conexión de eventos enviados por el servidor y expone cada evento a través del iterador; la conexión permanece abierta hastamessage_stopo un error.tool_usees solo otrostop_reasonen la respuesta: cuando Claude decide llamar a una herramienta, elContentde la respuesta incluye un bloquetool_useen lugar de (o junto con) texto, yStopReasones"tool_use".
Uso de herramientas en Go
Definir una herramienta significa describir su esquema de entrada como un struct tipado, y luego comprobar la respuesta en busca de un bloque tool_use.
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"},
},
}
message, err := client.Messages.New(ctx, anthropic.MessageNewParams{
Model: anthropic.ModelClaudeSonnet5,
MaxTokens: 512,
Tools: []anthropic.ToolUnionParam{{OfTool: &weatherTool}},
Messages: []anthropic.MessageParam{
anthropic.NewUserMessage(anthropic.NewTextBlock("¿Cuál es el clima en Denver?")),
},
})
if err != nil {
log.Fatal(err)
}
for _, block := range message.Content {
if toolUse, ok := block.AsAny().(anthropic.ToolUseBlock); ok {
var input WeatherInput
if err := json.Unmarshal(toolUse.Input, &input); err != nil {
log.Fatal(err)
}
fmt.Println("Claude quiere el clima para:", input.City)
// Ejecuta tu búsqueda real aquí, luego envía un mensaje tool_result de vuelta.
}
}Opciones de configuración del cliente
| Opción | Propósito |
|---|---|
option.WithAPIKey(key) | Establece la clave API explícitamente en lugar de leer ANTHROPIC_API_KEY |
option.WithBaseURL(url) | Apunta el cliente a una URL base diferente (raro; principalmente para proxies o pruebas) |
option.WithHTTPClient(httpClient) | Proporciona un *http.Client personalizado, útil para el pooling de conexiones compartidas o tiempos de espera personalizados |
option.WithMaxRetries(n) | Anula el número de reintentos predeterminado del SDK para fallos transitorios |
Notas de Go
// Reutiliza un cliente en todo tu servicio; es seguro para uso concurrente.
var claudeClient = anthropic.NewClient(
option.WithAPIKey(os.Getenv("ANTHROPIC_API_KEY")),
)
func handleRequest(ctx context.Context, prompt string) (string, error) {
message, err := claudeClient.Messages.New(ctx, anthropic.MessageNewParams{
Model: anthropic.ModelClaudeSonnet5,
MaxTokens: 1024,
Messages: []anthropic.MessageParam{
anthropic.NewUserMessage(anthropic.NewTextBlock(prompt)),
},
})
if err != nil {
return "", fmt.Errorf("la solicitud de claude falló: %w", err)
}
return message.Content[0].Text, nil
}- El cliente es seguro para compartir entre goroutines; constrúyelo una vez al inicio y reutilízalo en las solicitudes.
- Pasa siempre un
context.Contextpara que los tiempos de espera y la cancelación de la solicitud se propaguen correctamente bajo carga. - Envuelve los errores con
%wal devolverlos en la pila de llamadas, para que los llamadores aún puedan usarerrors.Aspara acceder al tipo de error subyacente del SDK.
Trampas
- Construir un nuevo cliente por solicitud - crear
anthropic.NewClientdentro de un manejador de solicitudes descarta el pooling de conexiones y añade latencia. Solución: construye un cliente al inicio y reutilízalo. - Ignorar
stream.Err()después del bucle - un stream que termina prematuramente debido a un error de red aún sale del buclefor stream.Next()normalmente. Solución: siempre compruebastream.Err()después del bucle, no solo dentro de él. - Asumir que
Content[0]es siempre texto - una respuesta contool_usepone unToolUseBlockenContent, no un bloque de texto, y indexar ciegamente provoca un pánico. Solución: comprueba el tipo deblock.AsAny(), o compruebaStopReasonantes de leerContent[0].Text. - Olvidar que
MaxTokenses obligatorio - omitirlo produce un error de validación en tiempo de solicitud en lugar de un valor predeterminado sensato. Solución: establece siempre unMaxTokensexplícito del tamaño de tu respuesta esperada. - No pasar un contexto cancelable bajo carga - usar
context.Background()en todas partes significa que una solicitud lenta o colgada no puede ser cancelada por un tiempo de espera anterior. Solución: pasa uncontext.Contextcon un plazo o cancelación, con ámbito de solicitud, a través de cada llamada. - Tratar
tool_usecomo la respuesta final - recibir un bloquetool_usesignifica que Claude está esperando untool_result, no que la tarea esté terminada. Solución: ejecuta la herramienta, luego envía el resultado de vuelta en una llamadaMessages.Newde seguimiento antes de considerar la conversación completa.
Alternativas
| Alternativa | Usar cuando | No usar cuando |
|---|---|---|
| Capa de compatibilidad de OpenAI con un cliente Go con forma de OpenAI | Estás migrando rápidamente un servicio Go existente integrado con OpenAI y puedes tolerar una superficie de parámetros más estrecha | Necesitas funciones completas de la API de Mensajes como tool_use extendido o los últimos tipos de bloques de contenido |
Llamadas net/http crudas a la API de Mensajes | Necesitas algo sin dependencias en un binario mínimo | Quieres que las solicitudes tipadas, los reintentos y el análisis de streaming se manejen por ti |
| Un SDK oficial diferente (Java, C#, PHP, Ruby) | Tu servicio no está realmente escrito en Go | Estás trabajando específicamente en una base de código Go |
Preguntas frecuentes
¿Necesito construir un nuevo cliente para cada solicitud?
No. Construye anthropic.NewClient una vez al inicio y reutilízalo en las solicitudes; es seguro para uso concurrente.
¿Cómo funciona el streaming en anthropic-sdk-go?
client.Messages.NewStreaming devuelve un iterador. Llama a stream.Next() en un bucle, lee stream.Current() para cada evento y comprueba stream.Err() después de que finalice el bucle para detectar fallos a mitad de transmisión.
¿Cómo sé cuándo Claude quiere llamar a una herramienta?
Comprueba message.StopReason para "tool_use", luego busca un ToolUseBlock dentro de message.Content. El bloque contiene el nombre de la herramienta y una entrada codificada en JSON que descomprimes en tu propia struct.
¿anthropic-sdk-go reintenta automáticamente las solicitudes fallidas?
Sí, por defecto reintenta fallos transitorios como límites de tasa y errores de red un número limitado de veces. Puedes anular el recuento con option.WithMaxRetries(n).
¿Qué sucede si olvido establecer MaxTokens?
La solicitud falla la validación, ya que MaxTokens no tiene un valor predeterminado implícito. Siempre establécelo explícitamente a un valor del tamaño de tu respuesta esperada.
¿Puedo usar anthropic-sdk-go con un cliente HTTP personalizado?
Sí. Pasa option.WithHTTPClient(httpClient) al construir el cliente para proporcionar tu propio *http.Client, útil para pools de conexión compartidos o comportamiento de tiempo de espera personalizado.
¿Es seguro usar el cliente desde múltiples goroutines a la vez?
Sí, un único anthropic.Client es seguro para uso concurrente, por lo que debes construirlo una vez y compartirlo en lugar de crear uno por solicitud.
¿Cómo se manifiestan los errores en Go, en comparación con las excepciones en otros SDK?
Los errores se devuelven como un valor error normal de Go desde cada método, siguiendo la convención de Go. No hay pánico ni excepción; comprueba err != nil después de cada llamada de la misma manera que lo harías para cualquier otra API de Go.
¿Necesito pasar context.Background() a todas partes?
Solo en scripts desechables. En un servicio real, pasa un context.Context con un plazo o cancelación, con ámbito de solicitud, para que una llamada lenta a Claude pueda ser cancelada de la misma manera que cualquier otra llamada descendente.
¿Puede el mismo cliente llamar a múltiples modelos?
Sí. Model es un campo por solicitud, no una configuración a nivel de cliente, por lo que un solo cliente puede enviar solicitudes a Claude Fable 5, Claude Opus 4.8, Claude Sonnet 5 o Claude Haiku 4.5 según sea necesario.
Relacionados
- Conceptos básicos de otros SDK oficiales - una primera llamada en cada uno de los cinco idiomas, incluido un ejemplo más simple de Go
- Uso idiomático de herramientas en Go, Java, C#, PHP y Ruby - compara este patrón de
tool_usecon los otros cuatro SDK - Más allá de Python y TypeScript: Los otros SDK oficiales de Claude - la descripción conceptual en la que se basa este artículo
- Construcción de un bucle de uso de herramientas de múltiples turnos - el bucle completo de solicitud/resultado de herramienta/seguimiento, en términos generales
- Cómo los eventos enviados por el servidor potencian las respuestas de streaming de Claude - el protocolo de streaming que consume este ejemplo de Go
Versiones de pila: 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 SDK oficiales actuales para Go, Java, C#, PHP y Ruby. Los nombres de los modelos, las versiones de los SDK y los precios cambian rápidamente; verifica los detalles actuales en platform.claude.com/docs antes de confiar en ellos.