Guías de SDK
Java
Usa la biblioteca openai-java con api14: configura la URL base, chat, streaming, herramientas, salida estructurada, errores, tiempos de espera y reintentos.
Usa la biblioteca oficial openai-java con api14. Establece baseUrl en el constructor del cliente y pasa los ids de modelo (por ejemplo openai/gpt-5-mini) como cadenas simples.
Instalación
Gradle:
implementation("com.openai:openai-java:4.+")
Maven:
<dependency>
<groupId>com.openai</groupId>
<artifactId>openai-java</artifactId>
<version>LATEST</version>
</dependency>
Después establece API14_API_KEY=sk-api14-... en tu entorno.
Configuración
import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
OpenAIClient client = OpenAIOkHttpClient.builder()
.baseUrl("https://api14.com/api/v1")
.apiKey(System.getenv("API14_API_KEY"))
.build();
OpenAIOkHttpClient.fromEnv() lee en su lugar OPENAI_BASE_URL y OPENAI_API_KEY, así que puedes cambiar de entorno sin modificar el código:
export OPENAI_BASE_URL="https://api14.com/api/v1"
export OPENAI_API_KEY="sk-api14-..."
Chat
import com.openai.models.chat.completions.ChatCompletion;
import com.openai.models.chat.completions.ChatCompletionCreateParams;
ChatCompletionCreateParams params = ChatCompletionCreateParams.builder()
.model("openai/gpt-5-mini")
.addUserMessage("Explain vector databases in two sentences.")
.build();
ChatCompletion completion = client.chat().completions().create(params);
completion.choices().get(0).message().content().ifPresent(System.out::println);
Streaming
import com.openai.core.http.StreamResponse;
import com.openai.models.chat.completions.ChatCompletionChunk;
ChatCompletionCreateParams params = ChatCompletionCreateParams.builder()
.model("anthropic/claude-sonnet-4.5")
.addUserMessage("Write a haiku about APIs.")
.build();
try (StreamResponse<ChatCompletionChunk> stream = client.chat().completions().createStreaming(params)) {
stream.stream()
.flatMap(chunk -> chunk.choices().stream())
.flatMap(choice -> choice.delta().content().stream())
.forEach(System.out::print);
}
Consulta Streaming.
Llamadas a herramientas
Describe una herramienta como una clase; el SDK deriva su JSON Schema y convierte los argumentos de vuelta en ella:
import com.fasterxml.jackson.annotation.JsonClassDescription;
import com.openai.models.chat.completions.*;
import java.util.Collection;
@JsonClassDescription("Current weather for a city")
static class GetWeather {
public String city;
}
ChatCompletionCreateParams.Builder builder = ChatCompletionCreateParams.builder()
.model("openai/gpt-5-mini")
.addTool(GetWeather.class)
.addUserMessage("What's the weather in Istanbul?");
while (true) {
ChatCompletionMessage message = client.chat().completions().create(builder.build())
.choices().get(0).message();
builder.addMessage(message);
if (message.toolCalls().map(Collection::isEmpty).orElse(true)) {
message.content().ifPresent(System.out::println);
break;
}
for (ChatCompletionMessageToolCall call : message.toolCalls().get()) {
GetWeather args = call.asFunction().function().arguments(GetWeather.class);
builder.addMessage(ChatCompletionToolMessageParam.builder()
.toolCallId(call.asFunction().id())
.contentAsJson(getWeather(args.city)) // tu función
.build());
}
}
El builder conserva toda la conversación: cada vuelta del bucle añade el mensaje del asistente con sus llamadas a herramientas, luego un mensaje de herramienta por llamada, y lo envía todo de nuevo. Los campos de la clase de la herramienta se convierten en las propiedades del esquema; añade @JsonPropertyDescription a un campo para indicar al modelo qué significa. Limita el número de iteraciones en código de producción para que un modelo que sigue llamando herramientas no entre en un bucle infinito. Consulta Llamadas a herramientas.
Salida estructurada
Pasa una clase a responseFormat; el SDK genera a partir de ella un JSON Schema estricto y convierte el contenido de cada choice en una instancia. Usa un modelo que incluya structured_outputs o response_format en su supported_parameters:
static class Person {
public String name;
public int born;
public String city;
}
StructuredChatCompletionCreateParams<Person> params = ChatCompletionCreateParams.builder()
.model("openai/gpt-5-mini")
.responseFormat(Person.class)
.addUserMessage("Extract: Ada Lovelace, born 1815 in London.")
.build();
client.chat().completions().create(params).choices().stream()
.flatMap(choice -> choice.message().content().stream())
.forEach(person -> System.out.println(person.name + " " + person.born));
Consulta Salidas estructuradas.
Entrada de imagen
import java.util.List;
ChatCompletionCreateParams params = ChatCompletionCreateParams.builder()
.model("google/gemini-2.5-flash")
.addUserMessageOfArrayOfContentParts(List.of(
ChatCompletionContentPart.ofText(ChatCompletionContentPartText.builder()
.text("What is in this picture?").build()),
ChatCompletionContentPart.ofImageUrl(ChatCompletionContentPartImage.builder()
.imageUrl(ChatCompletionContentPartImage.ImageUrl.builder()
.url("https://example.com/photo.jpg") // o una URL data:image/png;base64,...
.build())
.build())))
.build();
Consulta Visión y archivos.
Parámetros adicionales
Los campos de la pasarela sin setter tipado (reasoning, provider, models) se envían con putAdditionalBodyProperty:
import com.openai.core.JsonValue;
import java.util.Map;
ChatCompletionCreateParams params = ChatCompletionCreateParams.builder()
.model("anthropic/claude-sonnet-4.5")
.addUserMessage("Prove there are infinitely many primes.")
.putAdditionalBodyProperty("reasoning", JsonValue.from(Map.of("effort", "high")))
.build();
Errores
Las respuestas que no son 2xx lanzan subclases de OpenAIServiceException, que exponen el estado y las cabeceras:
import com.openai.errors.OpenAIServiceException;
try {
client.chat().completions().create(params);
} catch (OpenAIServiceException e) {
if (e.statusCode() == 402) {
System.err.println("Balance too low, add funds (insufficient_balance)");
} else if (e.statusCode() == 429) {
System.err.println("Rate limited, retry after " + e.headers().values("Retry-After") + "s");
} else {
throw e;
}
}
Consulta Errores.
Tiempos de espera y reintentos
Por defecto, el cliente reintenta dos veces los errores de conexión, 408, 409, 429 y 5xx con retroceso exponencial. Configura el número de reintentos y el tiempo de espera en el builder, o por petición:
import com.openai.core.RequestOptions;
import java.time.Duration;
OpenAIClient client = OpenAIOkHttpClient.builder()
.baseUrl("https://api14.com/api/v1")
.apiKey(System.getenv("API14_API_KEY"))
.maxRetries(4)
.timeout(Duration.ofSeconds(60))
.build();
client.chat().completions().create(params,
RequestOptions.builder().timeout(Duration.ofMinutes(5)).build());
El tiempo de espera del builder se aplica a cada intento. Las peticiones largas de razonamiento pueden tardar minutos, así que dales un tiempo de espera por petición mayor o usa streaming. Reintentar no ayuda con daily_limit_reached ni con insufficient_balance; captura RateLimitException y comprueba el código de error antes de programar otro intento. Consulta Límites de tasa.
Todas las capacidades
import OpenAI from "openai";
const client = new OpenAI({
baseURL: "https://api14.com/api/v1",
apiKey: process.env.API14_API_KEY,
});
const result = await client.chat.completions.create({
"model": "openai/gpt-5-mini",
"messages": [
{
"role": "user",
"content": "Explain vector databases in two sentences."
}
]
});
console.log(result.choices[0].message.content);