Spring AI can send chat requests to CometAPI through Spring AI’s OpenAI-compatible model integration. The practical setup has three moving parts: add the OpenAI starter, set the CometAPI versioned base URL, and provide a current chat-capable model ID at runtime. Keep the API key in the environment rather than in Java, committed YAML, or logs. Once a short synchronous request works, you can add streaming and model-specific options deliberately.
The key idea is that Spring AI owns the application-facing ChatClient abstraction while CometAPI supplies an OpenAI-compatible wire contract. You do not need to rewrite your prompts as provider-specific payloads for the first integration. The CometAPI OpenAI-compatible quickstart
describes the chat-completions route, the versioned base URL, the model setting, and the response shape used by this approach.
Last reviewed: 2026-08-28
Direct answer
Use the Spring AI OpenAI starter and configure it with the versioned CometAPI base URL
. Bind spring.ai.openai.api-key to a runtime environment placeholder, set spring.ai.openai.chat.model to an exact CometAPI model ID that supports text chat, and inject a ChatClient.Builder into your service. Start with one short, synchronous prompt and inspect the returned assistant content before enabling extra features.
Add the starter through dependency management
Spring AI publishes a starter for its OpenAI chat integration. The Spring AI OpenAI Chat reference
names the artifact spring-ai-starter-model-openai and recommends using the project BOM so related modules stay on a compatible release train. A Gradle dependency can consequently remain versionless when the BOM is imported by your project:
dependencies {
implementation("org.springframework.ai:spring-ai-starter-model-openai")
}
Use the equivalent Maven declaration if your project is Maven-based. Check the compatibility guidance for the Spring Boot line you already run; do not mix arbitrary Spring AI and Boot versions just because both compile independently. The Spring AI project repository explains the project’s provider abstractions, starter ecosystem, portable synchronous and streaming APIs, and compatibility branches.
Configure CometAPI at runtime
Keep the endpoint, model, and secret reference in deployment configuration. This example intentionally contains no secret value:
spring:
ai:
openai:
api-key: ${COMETAPI_KEY}
base-url: ${COMETAPI_BASE_URL}
chat:
model: ${COMETAPI_MODEL}
Set COMETAPI_BASE_URL to the documented versioned base URL, set COMETAPI_KEY in the process environment or a platform secret integration, and set COMETAPI_MODEL to a current model ID from the CometAPI catalog. The placeholders are safe to commit; the values they resolve to are not. Spring Boot’s externalized configuration reference
documents properties, YAML, environment variables, command-line values, property-source precedence, and relaxed environment-variable binding. Those rules let the same application artifact use different models and endpoints in development, staging, and production.
The /v1 suffix is part of the OpenAI-compatible base URL. Let Spring AI append the operation path. Do not configure a full /chat/completions URL and do not append the path again in application code. The CometAPI base-URL guide
specifically calls out missing /v1, wrong paths, and HTML returned after a redirect as common causes of confusing failures.
Spring AI also documents chat-specific overrides such as spring.ai.openai.chat.base-url and spring.ai.openai.chat.api-key. Use those only when the chat model intentionally has a separate connection from other OpenAI-oriented model clients. For a first CometAPI integration, one common base URL and one runtime key are easier to reason about.
Create a minimal chat service
The following service keeps the network boundary small. Input validation and authorization should happen at the application boundary; the example shows a conservative length check so an accidental empty request does not become an API call.
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.stereotype.Service;
@Service
public class CometChatService {
private final ChatClient chatClient;
public CometChatService(ChatClient.Builder builder) {
this.chatClient = builder.build();
}
public String answer(String prompt) {
if (prompt == null || prompt.isBlank() || prompt.length() > 4000) {
throw new IllegalArgumentException("prompt must contain 1 to 4000 characters");
}
String content = chatClient.prompt()
.user(prompt)
.call()
.content();
return content == null ? "" : content;
}
}
Expose this service through your own controller, job, or message consumer. A successful synchronous call should yield assistant text through Spring AI’s response abstraction. The CometAPI quickstart describes the underlying completion response as a choices collection whose first message contains the assistant content. Start with a one-sentence prompt so a routing or model problem is obvious.
Run a happy-path and error-path check
Use a disposable environment for the first check. Inject the three environment values, start the application, call the service once with a short prompt such as “Reply with one sentence,” and verify that the result is non-empty. Repeat the call once without changing configuration. That second success helps distinguish a wiring error from a transient network interruption.
For the error path, change one boundary at a time and stop when the category is clear:
- Confirm the process can see the key placeholder without printing its value.
- Confirm the resolved base URL is the CometAPI host with
/v1and no operation suffix. - Confirm the model setting is an exact, current text/chat model ID.
- Send the minimal prompt with no optional sampling, token, JSON, or tool settings.
- Add one optional setting only after the minimal request succeeds.
Record a correlation ID, model label, endpoint family, HTTP status, latency, input and output character counts, stream flag, and a coarse error category. A sanitized event can look like this:
ai_chat request_id=[CORRELATION_ID] model=[CONFIGURED_MODEL] endpoint_family=chat_completions stream=false status=[HTTP_STATUS] latency_ms=[INTEGER] input_chars=[INTEGER] output_chars=[INTEGER] error_class=[NONE_OR_CATEGORY]
Never record the key, an authorization value, a complete user prompt, or an unbounded model response. If a diagnostic capture accidentally includes sensitive material, replace it with [REDACTED] before sharing and shorten its retention period.
Who this is for
This guide is for Java developers who already run a Spring Boot service and want Spring AI’s OpenAI-oriented chat abstraction to route through CometAPI. It fits a new chat endpoint, a migration from another OpenAI-compatible host, or a team that needs model selection to vary by deployment without recompiling.
You should know how to create a Spring Boot project, import a BOM, set process environment variables, and read a Java return value. The tutorial intentionally focuses on a text chat request. It does not claim that provider-native Gemini or Anthropic fields, image operations, embeddings, or tool loops can be copied into the same payload. If you need those capabilities, identify the corresponding CometAPI contract first and keep the request format separate.
The pattern also works outside HTTP controllers. Put the ChatClient in a service bean for a scheduled job or queue consumer, then apply the same validation, timeout, retry, and logging boundaries. The application code owns prompts and business rules; deployment configuration owns the endpoint, model ID, and secret reference.
Key takeaways
- Configure the documented versioned CometAPI base URL through
COMETAPI_BASE_URLand let Spring AI append the operation path. - Add
spring-ai-starter-model-openaithrough a Spring AI BOM-compatible release train. - Bind
spring.ai.openai.api-keyto a runtime placeholder such as${COMETAPI_KEY}and never hardcode its resolved value. - Set
spring.ai.openai.chat.modelto an exact CometAPI model ID that supports text chat. - Prove one short synchronous call before enabling SSE streaming or model-specific options.
- Treat authentication, path, model, request-option, timeout, and throttling errors as separate branches.
- Log only sanitized metadata: correlation ID, model label, status, latency, sizes, stream state, and error class.
- Keep token-limit and sampling options compatible with the chosen model; add them one at a time.
Sources checked
The CometAPI OpenAI-compatible API quickstart supports the route, base URL, model parameter, synchronous response behavior, streaming marker, and minimal request flow used here.
The CometAPI guide to changing the base URL
supports the /v1 requirement and the diagnostic distinction between wrong paths, HTML responses, authentication failures, and model errors.
The Spring AI OpenAI Chat reference supports the starter artifact, connection properties, chat-specific model and URL properties, streaming support, retry controls, and mutually exclusive token-limit settings.
The Spring Boot Externalized Configuration reference supports the guidance on environment variables, YAML and property files, precedence, and relaxed binding.
The Spring AI project repository supports the description of Spring AI’s portable model abstractions, starter modules, synchronous and streaming APIs, and compatibility guidance. These are public sources; the setup does not require private documentation or account data.
Contract details to verify
Before shipping, verify these boundaries against the exact deployment and model you intend to use.
Base URL and operation path. The OpenAI-compatible base is the CometAPI host with /v1. It is a base, not a complete operation URL. Keep credentials in configuration rather than a URL query or fragment. If a response is HTML, inspect the path and redirect behavior before changing JSON parsing.
Model capability and identifier. A marketing label is not necessarily an API model ID. Copy the exact current ID from the CometAPI catalog and confirm that it accepts text chat. Keep the value externalized so a catalog change does not require a source edit.
Message and response shape. Spring AI turns the prompt into the compatible messages structure. Begin with one user message. The synchronous response is exposed through the completion choices and assistant message content; treat a null or empty result as a signal to inspect the response rather than inventing fallback text.
Token and sampling options. The Spring AI reference distinguishes max-tokens for non-reasoning families from max-completion-tokens for reasoning families and says they are mutually exclusive. It also notes that some reasoning models reject temperature. Start with no optional fields, then verify each option against the selected CometAPI model.
Streaming. The compatible route accepts streaming and returns Server-Sent Events ending with a [DONE] marker. If you enable it, confirm that the client preserves event order, handles the terminal marker, and does not mark partial text as a completed answer. Keep the synchronous probe as a small health check.
Retries and side effects. Spring AI exposes retry and backoff properties. Decide which failures are transient for your workload and keep attempts bounded. Do not retry a deterministic path, key, model, or validation error, and do not place a non-idempotent business side effect inside a loop that may run again.
Failure modes
Authentication wiring fails. A 401 generally means the running process cannot resolve the configured key, is using the wrong profile, or is pointed at a different provider. Check environment injection and property names, then restart the process after changing them. Do not paste a value into source control or logs.
The route returns 404 or HTML. Recheck the /v1 suffix and remove any duplicated operation path. The CometAPI base-URL guide identifies wrong paths and redirect-generated HTML as common clues. Inspect status and content type before attempting completion deserialization.
The model is unknown or rejected. Replace a guessed name with an exact current catalog ID and confirm chat capability. Do not infer text support from an image or provider label. Keep a known-good model value in each deployment profile.
Adding options creates 400. Remove every optional field, rerun the minimal request, and add settings individually. Do not set both token-limit properties. Avoid temperature where the selected reasoning model rejects it, and verify support before requesting JSON response formatting.
Calls time out or are throttled. Record status class, elapsed time, and attempt number. Apply bounded backoff only to operations safe to repeat. A retry policy should expose a final error rather than hiding a bad route or invalid model.
A stream ends early. Reproduce the same prompt synchronously. If synchronous output works, inspect SSE buffering, proxy idle limits, connection limits, and terminal-marker handling. Keep partial and complete states distinct.
Sensitive data enters logs. Remove prompt and output fields from the logging pattern, rotate affected logs according to your policy, and retain only the sanitized dimensions shown in the operator event. A correlation ID is enough to join application and network diagnostics without storing a transcript.
FAQ
Do I need a CometAPI-specific Spring AI starter?
For the OpenAI-compatible route, start with Spring AI’s OpenAI starter and override the base URL and model settings. The application can retain the Spring AI chat abstraction while the deployment selects CometAPI.
Why does the base URL include /v1?
CometAPI documents that versioned base for OpenAI-compatible clients. Spring AI adds the operation path after it, so omitting the version can produce a 404 or a redirect to HTML.
Can a committed YAML file contain the key?
Keep only a placeholder such as ${COMETAPI_KEY} in the file and inject the value through the runtime, an IDE environment configuration, or a secret manager. A sample repository should never contain a live value.
Should every error be retried?
No. Missing configuration, an invalid path, an unknown model, and a malformed request are deterministic. Use Spring AI retry settings for genuinely transient conditions and keep the attempt count bounded.
How do I select the token-limit property?
Use the property that matches the model family and never both. The Spring AI reference describes the distinction between visible-token limits and completion-token budgets; verify the CometAPI model before setting either.
Can streaming be added later?
Yes. Keep the same base URL and model, then test SSE handling separately. Do not treat an interrupted stream as a final answer, and keep the synchronous probe available for diagnosis.
What if I need a provider-native feature?
Do not add undocumented fields to the compatible chat body. Find the CometAPI route and request format for that provider feature, then keep it in a separate integration path.
Reader next step
Run the service with a short prompt in a disposable environment. Confirm that the resolved base URL ends in /v1, the model ID is chat-capable, and the key placeholder resolves without exposing its value. Then use the CometAPI chat contract smoke-test checklist
to turn the first successful call into a repeatable probe. Before sharing the project, review how to keep CometAPI keys out of tutorial repositories
. Finally, add one capability at a time—streaming, structured output, or model-specific limits—and rerun the same happy/error-path checks after each change.