Co-Authored-By: Claude Sonnet 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01JXVi2GMQ7bR5EmbUFdDj7N
45 lines
2.8 KiB
Markdown
45 lines
2.8 KiB
Markdown
# providers
|
|
|
|
Companion code for [Anthropic Claude vs OpenAI vs Gemini in Spring AI 2.0: Switching Providers and Comparing Cost](https://ankurm.com/spring-ai-claude-vs-openai-vs-gemini-switch-providers-compare-cost/), part of the [Spring AI series](../README.md) on ankurm.com.
|
|
|
|
One small application (`TicketService`, which summarises a support ticket) runs on the real `OpenAiChatModel`, `AnthropicChatModel` and `GoogleGenAiChatModel`, and the tests look at what each one does differently.
|
|
|
|
**No vendor API was called, and no claim is made about any vendor's behaviour.** `FakeProviderServer` is a local HTTP server that answers in the three wire formats. It records every request the real Spring AI classes send, which is the evidence for the "what is different on the wire" results. Three things in it are simulation: token counts are characters / 4, the answer is a fixed JSON string, and cache hits follow the rules the vendors document (thresholds and prefix matching, read on 2026-10-09) applied to the request that really arrived. So the cost table is a worked example of the price sheets, not a bill, and **latency is not measured at all**.
|
|
|
|
## Versions
|
|
|
|
| Component | Version |
|
|
|---|---|
|
|
| Spring Boot | 4.1.1 (parent) |
|
|
| Spring AI | 2.0.1 (`spring-ai-openai`, `spring-ai-anthropic`, `spring-ai-google-genai`) |
|
|
| Models named in the examples | `gpt-6.1-sol`, `claude-sonnet-5-5`, `gemini-3.8-flash` |
|
|
| Java | 25 (LTS) |
|
|
|
|
## Quickstart
|
|
|
|
```bash
|
|
scripts/run-all.sh # runs the suite, regenerates output/01 .. 05
|
|
```
|
|
|
|
Two consecutive runs produce byte-identical files.
|
|
|
|
## What's here
|
|
|
|
| File | What it is |
|
|
|---|---|
|
|
| [`ProviderModels.java`](src/main/java/com/ankurm/providers/ProviderModels.java) | The one class that knows which vendor is behind a `ChatModel` |
|
|
| [`TicketService.java`](src/main/java/com/ankurm/providers/TicketService.java) | The application; sees only `ChatModel` |
|
|
| [`FallbackChatModel.java`](src/main/java/com/ankurm/providers/FallbackChatModel.java) | Tries providers in order on transient failures |
|
|
| [`Failures.java`](src/main/java/com/ankurm/providers/Failures.java) | Reads an HTTP status out of three unrelated exception families |
|
|
| [`Cost.java`](src/main/java/com/ankurm/providers/Cost.java) | Usage to dollars, with the per-provider meaning of "prompt tokens" |
|
|
|
|
## Output files
|
|
|
|
| File | Written by |
|
|
|---|---|
|
|
| [`01-wire.txt`](output/01-wire.txt) | `WireTest`: the same call as each provider's HTTP request |
|
|
| [`02-options.txt`](output/02-options.txt) | `OptionsTest`: portable and provider-specific options, and the per-call trap |
|
|
| [`03-caching.txt`](output/03-caching.txt) | `CachingTest`: breakpoints sent, cache tokens reported, text order |
|
|
| [`04-cost.txt`](output/04-cost.txt) | `CostTest`: 100 requests priced on three price sheets |
|
|
| [`05-fallback.txt`](output/05-fallback.txt) | `FallbackTest`: which failures fail over, and requests per plan |
|