ai4j: a JDK 8 agentic SDK for teams that cannot move off Java 8
Java 8+ agentic SDK: unified LLM access (OpenAI/Anthropic/DashScope/Doubao/DeepSeek...), Tool Calling, MCP, RAG, Agent Runtime, and a built-in Coding Agent CLI/TUI/ACP.
At a glance
- What is it?
- ai4j wraps OpenAI, Anthropic, DashScope, Doubao, DeepSeek and others behind one Java service interface, and adds Tool Calling, MCP, RAG and an Agent Runtime. The interesting part is not the feature list but the JDK 8 baseline and the platform swap that leaves calling code untouched.
- Who is it for?
- Adopt ai4j if you are maintaining a JDK 8 or 11 service and need Tool Calling or MCP without introducing a second runtime, or if you want a Coding Agent CLI that ships inside the same dependency. Do not adopt it if you need a framework that manages bean lifecycles, retries and observability for you, because ai4j is a service layer and those concerns stay in your code.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 3 days ago.
- What is it written in?
- Mainly Java, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
The JDK 8 constraint is the whole pitch
Most Java LLM libraries assume you can move to JDK 17 or 21. ai4j does not. The README labels the project as targeting JDK 8+, and the badge row repeats it. That single decision reframes everything else in the repository. Enterprise Java services in banking, insurance and internal platform teams often sit on JDK 8 or 11 because the upgrade is blocked by an application server, a vendor library, or a build pipeline nobody wants to touch. Those teams can still call an HTTP API. What they cannot easily do is pull in a framework that requires records, sealed interfaces or virtual threads.
The audience follows from that. This is for a backend engineer who already has a Spring Boot service, wants to add a chat completion call or a tool-calling loop, and does not want to stand up a Python sidecar just to talk to a model. The README's own example is deliberately small: build a config, build a service, send one request, print the text. There is no annotation processor, no application context requirement, no code generation step described in the material.
One service interface, many providers
The mechanism visible in the README is a service factory keyed by platform. You construct an AiService from a Configuration object, then call getChatService with a PlatformType. The returned IChatService exposes chatCompletion, which takes a ChatCompletion request and returns a ChatCompletionResponse. Provider-specific settings live in their own config classes, such as OpenAiConfig with setApiKey.
What makes this more than a thin wrapper is the claim that switching providers means replacing PlatformType and the corresponding Config while the rest of the code stays the same. The README states this directly for DashScope, DeepSeek and Ollama. If that holds, the request and response entities are normalized across providers, which is the actual engineering work here. Tool Calling, MCP, A2A, RAG and the Agent Runtime are listed as capabilities on top of that same layer.
The README does not describe how normalization handles provider-specific fields that have no equivalent elsewhere, and it does not show a tool-calling example. Treat the unified surface as the documented contract and check the feature map before assuming a given provider exposes every capability.
Getting a first request out
Installation is a single coordinate. Gradle: implementation 'io.github.lnyo-cly:ai4j:2.4.2'. Maven uses groupId io.github.lnyo-cly, artifactId ai4j, version 2.4.2.
The README's 30-second example sets OPENAI_API_KEY in the environment, reads it with System.getenv, assigns it via openAiConfig.setApiKey, puts the config on a Configuration object with setOpenAiConfig, and constructs AiService. From there the call is chatService.chatCompletion(request) with a builder that takes model and message, where the message comes from ChatMessage.withUser. The response is read as response.getChoices().get(0).getMessage().getContent().getText().
Two details matter for anyone wiring this into an existing service. First, the API key path is explicit, so secret management stays your problem rather than being hidden behind a Spring property. Second, the example uses gpt-4o-mini and prints to stdout, which tells you the library is usable outside a container-managed lifecycle. The README does not document timeouts, retry behaviour or connection pooling, so those are questions to answer from the source before production use.
Where the abstraction will leak
A unified interface across OpenAI, Anthropic, DashScope, Doubao, DeepSeek and the rest is a promise about the intersection of those APIs, not the union. Anything only one provider supports either gets a provider-specific escape hatch or gets dropped. The README does not say which. If your product depends on a feature that exists in one vendor's API and not others, the normalized request entity is the first place to look for friction.
The second limitation is scope. ai4j is an SDK, not a framework. There is no mention of dependency injection integration, no retry policy, no circuit breaker, no metrics export. The topics list includes spring-boot, but the README does not show a starter or auto-configuration. In a Spring service you will likely wrap AiService in your own bean and handle failure yourself.
The third is the Coding Agent CLI, TUI and ACP. These are bundled, which is unusual for an SDK and cuts both ways: you get a terminal agent without a separate install, and you also get a larger dependency surface than a pure client library would have.
How this differs from Spring AI
Spring AI is the obvious comparison for a Java team, and the difference is architectural rather than cosmetic. Spring AI builds on the Spring ecosystem: auto-configuration, the application context, property binding, and the assumption that your application is already a Spring application on a supported JDK. Its value comes from fitting into that lifecycle.
ai4j inverts the dependency. You construct services manually, pass config objects explicitly, and the library has no stated requirement on a container. That makes it usable in a plain main method, a legacy servlet application, or a batch job, and it is what allows the JDK 8 baseline to be credible. The trade-off is that everything Spring AI would give you for free (bean wiring, configuration binding, health indicators) is code you write.
If your project is modern Spring Boot on JDK 17 or later, Spring AI is the more natural fit and you gain the ecosystem. If your project cannot move, or if you want the Coding Agent CLI in the same artifact, ai4j's approach is the one that does not force a platform migration first.
Release cadence and what Apache-2.0 leaves you to do
Three releases landed within days of each other in July 2026: v2.4.0 on 21 July, v2.4.1 the same day, v2.4.2 on 23 July. The latest push to the repository is dated 2026-09-09. A cadence that tight suggests active development, and it also means the version you pin matters more than usual. Pin 2.4.2 explicitly in Gradle or Maven rather than using a dynamic version, and read CHANGELOG.md before each bump.
The licence is Apache-2.0. That permits commercial use, modification and redistribution, and it includes a patent grant. It also means there is no vendor SLA, no support contract and no compatibility guarantee across minor versions. If your organisation requires a support channel, this project does not provide one. That is not a legal opinion, just the shape of the licence text; check it against your own policy.
Upgrade cost is dominated by the provider config classes. If you touch OpenAiConfig, AnthropicConfig or their equivalents directly, a rename or a new required field is a compile error on upgrade. Keeping provider configuration in one place in your codebase limits the blast radius.
Who should pick it up, and what to check first
The case for ai4j is strongest when two conditions hold at once: your service is pinned to JDK 8 or 11, and you need something beyond a single chat call, such as Tool Calling or MCP. Under those conditions the alternative is usually a Python service behind an HTTP boundary, which adds a deployment target and a second language to the on-call rotation. ai4j removes that boundary.
The case is weakest when you are already on a modern Spring Boot stack and want managed configuration and observability. Building that on top of a manual service factory is work Spring AI already did.
Before adopting, verify against the repository rather than the README: confirm your provider appears in the feature map with the capabilities you need, confirm the MCP transport you require is implemented, and check CHANGELOG.md for breaking changes between 2.4.0 and 2.4.2 to see how the project treats compatibility. The README does not answer those questions, and they are the ones that decide whether the integration is a day or a quarter.
Editorial conclusion
Adopt ai4j if you are maintaining a JDK 8 or 11 service and need Tool Calling or MCP without introducing a second runtime, or if you want a Coding Agent CLI that ships inside the same dependency. Do not adopt it if you need a framework that manages bean lifecycles, retries and observability for you, because ai4j is a service layer and those concerns stay in your code. Before committing, verify three things against the repository: that the PlatformType and Config pair you need covers your provider, that the MCP transport you require is implemented rather than listed, and that the release cadence in CHANGELOG.md matches your upgrade window, since three releases landed in the same week in July 2026.
Community notes