Add langchain4j-interop: Spring AI 2.0 and LangChain4j 1.22 side by side
Same order assistant in both frameworks against a local fake OpenAI server: starter bean collision, wire differences, tool failure and loop bounds, observability meters, MCP-first tools, and a compile check of the 2025 article's snippets and Maven coordinates. Co-Authored-By: Claude Sonnet 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01G8ikz8xdWuTP5yun8DZ1hk
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
import org.springframework.ai.chat.client.advisor.api.AdvisedRequest;
|
||||
import org.springframework.ai.chat.client.advisor.api.AdvisedResponse;
|
||||
import org.springframework.ai.chat.client.advisor.api.CallAroundAdvisor;
|
||||
import org.springframework.ai.chat.client.advisor.api.CallAroundAdvisorChain;
|
||||
|
||||
// From the original TokenBudgetAdvisor.
|
||||
class OldCallAroundAdvisor implements CallAroundAdvisor {
|
||||
@Override
|
||||
public AdvisedResponse aroundCall(AdvisedRequest request, CallAroundAdvisorChain chain) {
|
||||
return chain.nextAroundCall(request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() { return "x"; }
|
||||
|
||||
@Override
|
||||
public int getOrder() { return 0; }
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.ai.chat.client.ChatClient;
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
// The original ChatService, unchanged: this one is expected to still compile.
|
||||
class OldChatService {
|
||||
private final ChatClient chatClient;
|
||||
|
||||
OldChatService(ChatClient.Builder builder) {
|
||||
this.chatClient = builder
|
||||
.defaultSystem("You are a senior Java architect. Be precise and concise.")
|
||||
.build();
|
||||
}
|
||||
|
||||
public String ask(String userMessage) {
|
||||
return chatClient.prompt().user(userMessage).call().content();
|
||||
}
|
||||
|
||||
public Flux<String> stream(String userMessage) {
|
||||
return chatClient.prompt().user(userMessage).stream().content();
|
||||
}
|
||||
|
||||
public ArchitectureReview reviewCode(String codeSnippet) {
|
||||
return chatClient.prompt()
|
||||
.user(u -> u.text("Review this Java code for production readiness: {code}").param("code", codeSnippet))
|
||||
.call()
|
||||
.entity(ArchitectureReview.class);
|
||||
}
|
||||
|
||||
public record ArchitectureReview(String verdict, List<String> issues, List<String> suggestions, int score) { }
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
import org.springframework.ai.document.Document;
|
||||
|
||||
// From the original RAGService: Document::getContent
|
||||
class OldDocumentGetContent {
|
||||
String text(Document d) {
|
||||
return d.getContent();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import dev.langchain4j.model.openai.OpenAiChatModel;
|
||||
import dev.langchain4j.service.AiServices;
|
||||
|
||||
// From the original AgentConfig.
|
||||
class OldLangChain4jBuilder {
|
||||
interface Agent { String chat(String m); }
|
||||
|
||||
Agent agent(OpenAiChatModel model) {
|
||||
return AiServices.builder(Agent.class).chatLanguageModel(model).build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
import org.springframework.ai.chat.messages.Message;
|
||||
|
||||
// From the original TokenBudgetAdvisor.estimateTokens: m.getContent()
|
||||
class OldMessageGetContent {
|
||||
int length(Message m) {
|
||||
return m.getContent().length();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
import org.springframework.boot.actuate.autoconfigure.metrics.MeterRegistryCustomizer;
|
||||
|
||||
// From the original ObservabilityConfig.
|
||||
class OldMeterRegistryCustomizer {
|
||||
MeterRegistryCustomizer<?> unused;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
import org.springframework.ai.reader.pdf.config.PdfDocumentReaderConfig;
|
||||
|
||||
// From the original DocumentIngestionService.
|
||||
class OldPdfConfig {
|
||||
Object config() {
|
||||
return PdfDocumentReaderConfig.builder().withPageTopMargin(0).build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
import org.springframework.ai.vectorstore.SearchRequest;
|
||||
|
||||
// From the original RAGService and SemanticCacheService.
|
||||
class OldSearchRequest {
|
||||
Object build(String question, int topK) {
|
||||
return SearchRequest.query(question).withTopK(topK).withSimilarityThreshold(0.75);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
import org.springframework.ai.transformer.splitter.TokenTextSplitter;
|
||||
|
||||
// From the original DocumentIngestionService: this one is expected to still compile.
|
||||
class OldTokenTextSplitter {
|
||||
TokenTextSplitter splitter = new TokenTextSplitter(512, 50, 5, 10000, true);
|
||||
}
|
||||
Reference in New Issue
Block a user