Tools, RAG & Agents in LangChain4j
Give a LangChain4j AiService the same superpowers this roadmap built with Spring AI — tool calling, retrieval-augmented generation, and LangChain4j's own composable agentic workflow builders.
What the Fraud-Signals Team Actually Needs
A chat interface that only talks isn't a fraud-signals assistant — it needs to pull real transaction data mid-conversation (tools), answer from the team's fraud-pattern playbook instead of guessing (RAG), and coordinate more than one kind of check before reaching a verdict (agents). This guide builds all three with LangChain4j, in the same order this roadmap covered them with Spring AI, so every section has something concrete to compare against.
1. Tools
class TransactionTools {
@Tool("Look up recent transaction history for a customer")
List<Transaction> recentTransactions(long customerId) {
return transactionRepository.findRecentByCustomer(customerId);
}
@Tool("Calculate the average transaction amount for a customer over the last 30 days")
double averageAmount(long customerId) {
return transactionRepository.averageAmountLast30Days(customerId);
}
}FraudRiskAssessor assessor = AiServices.builder(FraudRiskAssessor.class)
.chatModel(model)
.tools(new TransactionTools())
.build();The shape is identical to Spring AI's tool calling from this roadmap's fourth phase: annotate a method, register the instance, and the model decides when to call it as part of answering. Two differences worth internalizing, not just noting in passing:
@Tool in LangChain4j is dev.langchain4j.agent.tool.Tool — a same-named but entirely different annotation from Spring AI's org.springframework.ai.tool.annotation.Tool. They don't interoperate, and your IDE will happily auto-import the wrong one if both libraries are on the classpath (exactly the combination the next guide builds). The description also moves: LangChain4j's is the annotation's value (@Tool("description")), not a named attribute (@Tool(description = "...")).
Registration is per-AiServices builder call, not per-request like Spring AI's .tools() on a single ChatClient.prompt() — if a service needs different tools per call, build separate AiServices instances rather than trying to vary tools per invocation of the same one.
2. RAG: EmbeddingStore and Retrieval
Ingestion
List<Document> documents = FileSystemDocumentLoader.loadDocuments("/data/fraud-playbook");
EmbeddingStoreIngestor ingestor = EmbeddingStoreIngestor.builder()
.documentSplitter(DocumentSplitters.recursive(1000, 200))
.embeddingModel(embeddingModel)
.embeddingStore(embeddingStore)
.build();
ingestor.ingest(documents);DocumentSplitters.recursive(1000, 200) — chunk size, then overlap — is LangChain4j's equivalent of TokenTextSplitter from this roadmap's third phase. EmbeddingStore is the interface every one of LangChain4j's 30+ supported vector stores implements; swapping Chroma for Pinecone or PGVector is a different implementation behind the same interface, the same portability promise VectorStore makes on the Spring AI side.
Simple retrieval
ContentRetriever retriever = EmbeddingStoreContentRetriever.builder()
.embeddingStore(embeddingStore)
.embeddingModel(embeddingModel)
.maxResults(5)
.minScore(0.75)
.build();
FraudPlaybookAssistant assistant = AiServices.builder(FraudPlaybookAssistant.class)
.chatModel(model)
.contentRetriever(retriever)
.build();This is the direct equivalent of QuestionAnswerAdvisor from this roadmap's third phase — one retriever, one similarity search, attached with one builder call.
Advanced retrieval: the same four stages, different names
Recognize this shape from the advanced-RAG guide earlier in this roadmap — pre-retrieval transformation, retrieval, aggregation/re-ranking, all composed into one pipeline:
RetrievalAugmentor augmentor = DefaultRetrievalAugmentor.builder()
.queryTransformer(CompressingQueryTransformer.builder()
.chatModel(model)
.build())
.contentRetriever(retriever)
.contentAggregator(ReRankingContentAggregator.builder()
.scoringModel(scoringModel)
.build())
.build();
FraudPlaybookAssistant assistant = AiServices.builder(FraudPlaybookAssistant.class)
.chatModel(model)
.retrievalAugmentor(augmentor)
.build();Spring AI (RetrievalAugmentationAdvisor) | LangChain4j (DefaultRetrievalAugmentor) | Purpose |
|---|---|---|
RewriteQueryTransformer | — (no direct equivalent) | Rewrite a vague query |
CompressionQueryTransformer | CompressingQueryTransformer | Fold conversation history into one standalone query |
| — | ExpandingQueryTransformer | Generate multiple query variants |
MultiQueryExpander + DocumentJoiner | (built into query expansion + aggregation) | Search multiple query angles, merge results |
VectorStoreDocumentRetriever + FilterExpressionBuilder | EmbeddingStoreContentRetriever + metadata filter | Retrieval with metadata filtering |
DocumentPostProcessor (bring your own) | ReRankingContentAggregator (built-in, needs a ScoringModel) | Re-rank retrieved chunks |
ContextualQueryAugmenter | DefaultContentInjector | Inject retrieved content into the prompt |
The genuinely interesting difference is the last row: Spring AI ships no built-in cross-encoder reranker (this roadmap's advanced-RAG guide covered that gap explicitly), while LangChain4j's ReRankingContentAggregator is built-in — provided you supply a ScoringModel (a Cohere reranker is a common choice). If reranking quality is the deciding factor for a RAG-heavy project, that's a real, concrete point in LangChain4j's favor worth weighing in the next guide's decision framework.
3. Agents: AgenticServices
This is the one area with no direct Spring AI equivalent covered elsewhere in this roadmap — the langchain4j-agentic module (marked experimental by the project, expect API changes) provides composable workflow builders for coordinating multiple @Agent-annotated services.
Defining individual agents
interface TransactionAnomalyChecker {
@UserMessage("Check this transaction for anomalies: {{transaction}}")
@Agent("Checks a single transaction for anomalous patterns")
AnomalyResult checkAnomaly(@V("transaction") String transaction);
}
interface CustomerHistoryChecker {
@UserMessage("Compare this transaction against the customer's history: {{transaction}}")
@Agent("Compares a transaction against customer history")
HistoryResult checkHistory(@V("transaction") String transaction);
}Composing them: sequential and conditional workflows
// Run history check, then feed its result into the anomaly check
FraudPipeline pipeline = AgenticServices
.sequenceBuilder(FraudPipeline.class)
.subAgents(historyChecker, anomalyChecker)
.outputKey("verdict")
.build();// Route to a specialist check based on transaction category
UntypedAgent specialistRouter = AgenticServices.conditionalBuilder()
.subAgents(
scope -> scope.readState("category", Category.UNKNOWN) == Category.WIRE_TRANSFER,
wireTransferSpecialist)
.subAgents(
scope -> scope.readState("category", Category.UNKNOWN) == Category.CARD_PRESENT,
cardPresentSpecialist)
.build();AgenticServices also ships parallelBuilder() (run independent checks concurrently — LangChain4j's built-in answer to this roadmap's hand-rolled CompletableFuture fan-out from the agentic-patterns guide), loopBuilder() (repeat an agent until an exitCondition on the shared AgenticScope is met — comparable to this roadmap's hand-rolled Reflection pattern), and supervisorBuilder(), where an LLM plans which agents to invoke rather than you wiring the sequence yourself — the closest thing in LangChain4j to Embabel's planner from the previous phase, though the two take genuinely different approaches (an LLM proposing a plan vs. GOAP computing one deterministically from typed pre/postconditions).
AgenticServices is explicitly experimental, and the recently-added Belief-Desire-Intention (BDI) planning strategy — mentioned in this roadmap's LangChain4j overview — sits inside this same module without documented usage syntax at the time of writing. Treat this section as a map of what exists and roughly how it fits together, not a stable API to build production code against without checking the current docs and release notes first.
What's Next
Tools, RAG, and composable agent workflows, all with a concrete point of comparison to what this roadmap already built with Spring AI. The final guide in this phase turns those comparisons into an actual decision framework — including the one combination that matters most: using both frameworks in the same application.
Frequently asked questions
Can EmbeddingStoreIngestor use the same vector store Spring AI's VectorStore already writes to?
Only if you're deliberate about the schema — EmbeddingStore and VectorStore are separate abstractions with their own storage conventions, even against the same underlying database like PGVector. Treat them as separate indexes rather than assuming interchangeability; migrating data between them means re-ingesting through whichever framework will own it going forward, not pointing both at the same table.
Does ReRankingContentAggregator require a specific reranking provider?
It requires a ScoringModel implementation, and LangChain4j ships integrations for several providers (Cohere is the most commonly used) rather than a single fixed choice. This is the concrete built-in answer to the gap Spring AI's advanced-RAG guide flagged — DocumentPostProcessor there is an interface you implement yourself.
Is the langchain4j-agentic module a replacement for AiServices?
No — it composes AiServices interfaces (or plain @Agent-annotated interfaces) into larger workflows; it doesn't replace the declarative interface style from the first guide in this phase. Think of it as sitting a layer above AiServices, similar to how Embabel sits a layer above plain Spring AI ChatClient calls.
Should I wait for the agentic module to stabilize before using it?
That depends on your tolerance for API churn, the same judgment call this roadmap raised about Embabel's own pace of change. For a learning project or an internal tool, experimenting now is reasonable; for something customer-facing and hard to redeploy quickly, hand-rolling the equivalent pattern (this roadmap's agentic-patterns guide) or waiting for the module to graduate out of experimental status are both defensible choices.