Build and demo Java AI agent systems with langchain4j-agentic: workflow patterns, supervisor, custom Planner strategies (incl. the flagship typed-verdict / CriticResult-style critic pattern), plus MCP tools, A2A remote agents, build setup, and conference-demo storylines. Pinned to 1.15.0 / 1.15.0-beta25.
84
89%
Does it follow best practices?
Impact
100%
4.76xAverage score across 2 eval scenarios
Passed
No known issues
Everything needed to get a real, tool-using agent compiling and running — the non-obvious bits that bite in new projects and live demos.
There is no agentic-specific tool annotation. Tools use @Tool / @P from langchain4j-core (dev.langchain4j.agent.tool.Tool). The same tool object works in a plain AiService and in an agentic agent — agents are just AI services with orchestration on top.
public class FileSystemTools {
@Tool("Read a UTF-8 text file from the local filesystem")
public String readFile(@P("Absolute or repo-relative path") String path) throws IOException {
return Files.readString(Path.of(path));
}
@Tool("List entries in a directory, one per line")
public String listDirectory(@P("Directory path") String path) throws IOException { ... }
}
var agent = AgenticServices.agentBuilder(MyAgent.class)
.chatModel(claude)
.tools(new FileSystemTools(), new ShellTool()) // static tools
.maxSequentialToolsInvocations(10) // see below — mandatory
.build();.tools(...) for static tool objects; .toolProviders(...) for dynamic tools (MCP) — see mcp-and-a2a.md..maxSequentialToolsInvocations(int) is mandatory for any tool-using agent. Without it, a model that keeps calling tools can loop unbounded — a hung demo and a runaway token bill. Default to 10; 3–5 for simple tasks, 20+ only for known-bounded workflows..executeToolsConcurrently() runs a turn's tool calls in parallel; .toolExecutionErrorHandler(ctx -> ToolErrorHandlerResult.text("...")) recovers from a throwing tool. (Builder extras — verify against 1.15.0-beta25 if you rely on them.).chatMemory(MessageWindowChatMemory.withMaxMessages(20)) // single conversation
.chatMemoryProvider(memoryId -> MessageWindowChatMemory.withMaxMessages(20)) // per-conversationKeep windows modest (≈20) — large windows balloon token counts, especially under a supervisor.
Restriction: sub-agents of a parallelMapperBuilder must not have ChatMemory (the framework throws). Each mapped invocation is stateless by design; share cross-item state via AgenticScope keys instead.
SolutionCritic), smaller/faster for sub-agents (e.g. Claude Opus planner + Claude Sonnet workers, or gpt-4o-mini workers).ChatModel is supported, so you can mix providers freely across one system. Also see dynamic per-invocation selection in agent-configuration.md.gpt-4o-mini) instantiated and ready to hot-swap on a 429 during Q&A..cacheSystemMessages(true) on Anthropic reduces input-token cost within the prompt-cache TTL (5 min standard).ChatModel claude = AnthropicChatModel.builder()
.apiKey(System.getenv("ANTHROPIC_API_KEY"))
.modelName("claude-sonnet-4-5")
.maxTokens(4096)
.logRequests(true).logResponses(true) // dev only
.build();Run scripts/check_versions.sh (bundled with this skill). Confirmed current as of 2026-05-25 via maven-metadata.xml:
| Artifact | Version | Source |
|---|---|---|
dev.langchain4j:langchain4j-bom | 1.15.0 | GA |
dev.langchain4j:langchain4j / -anthropic / -open-ai | 1.15.0 | from BOM |
dev.langchain4j:langchain4j-agentic | 1.15.0-beta25 | pin explicitly |
dev.langchain4j:langchain4j-agentic-a2a | 1.15.0-beta25 | pin explicitly |
dev.langchain4j:langchain4j-agentic-patterns | 1.15.0-beta25 | pin explicitly |
dev.langchain4j:langchain4j-mcp | 1.15.0-beta25 | pin explicitly |
langchain4j-bom:1.15.0 aligns the stable modules only. The -agentic, -agentic-a2a, -agentic-patterns, and -mcp betas are not in the BOM — pin each independently. Mixing a transitively-pulled 1.16.x-beta agentic with BOM-managed 1.15.0 core surfaces as NoSuchMethodError on ChatModel/AiMessage at first invocation (the worst live-demo failure mode). Verify with ./gradlew dependencies | grep langchain4j — expect a single langchain4j-core version.
-parameters (silent-failure prevention)Without it, @V("topic") binds null silently (reflection sees arg0, arg1). No error — just wrong output.
Gradle (Kotlin DSL):
tasks.withType<JavaCompile>().configureEach {
options.compilerArgs.add("-parameters")
}Maven: <parameters>true</parameters> in the compiler plugin.
Verify: javap -p YourAgent.class shows real names, not arg0.
assets/build.gradle.kts — working Gradle Kotlin DSL build (Java 21, BOM + explicit beta pins, both LLM clients, -parameters). Copy and adjust application.mainClass.assets/App.java — ~80-line runnable bootstrap (one @Agent, two @Tools, AnthropicChatModel, AgentMonitor, HtmlReportGenerator). Runs with ANTHROPIC_API_KEY set.scripts/check_versions.sh — queries Maven Central (GitHub Releases fallback) for current GA + beta of every artifact.Maven equivalents and Spring Boot 4 / Quarkus notes: a Maven dependencyManagement import of the BOM plus explicit beta <version>s mirrors the Gradle setup; on Quarkus prefer the io.quarkiverse.langchain4j extensions when you need a hosted server (e.g. the A2A server side).
Use plain AiService (skip agentic) for: a single-agent chatbot with tools+memory, RAG, or structured-output extraction. The agentic module exists for multiple agents that compose — that's its only reason to be.