--- name: langchain4j-review description: "Use when reviewing LangChain4j Java/Kotlin application code (AI Services, tools, memory, guardrails, observability, Spring wiring). Do not invoke for MCP client-protocol deep review (use langchain4j-mcp-client), MCP server design/review (use langchain4j-mcp-server), greenfield agent design/build (use langchain4j-agent-design for design, or langchain4j-scaffold for build), or provider-specific OpenAI/Anthropic SDK setup (use langchain4j-openai-sdk/langchain4j-anthropic-sdk)." allowed-tools: Read, Grep, Glob, Bash(git diff *), Bash(git log *) --- # LangChain4j Code Review Review Git-tracked changes (or the specified file/directory) across **9 dimensions**. For each finding, cite the file path and line, classify severity (critical / warning / suggestion), and provide the fix. > **Version baseline**: LangChain4j 1.18.1 / 1.18.1-beta28, Spring Boot 3.5+ / 4.0.5+, Java 17+ (August 2026) ## Scope If `$ARGUMENTS` is provided, review those files. Otherwise, review recent changes: ``` !`git diff --name-only HEAD -- '*.java' '*.kt' 2>/dev/null | head -20 || echo "no changes"` ``` ## Review Dimensions ### 1. AI Services (High-Level API) - Use `AiServices.builder(Interface.class)` over raw `ChatModel` calls for conversational agents - `@SystemMessage` on interface / method for system prompts; `@UserMessage` for user prompt templates - `@MemoryId` parameter for per-user/session memory isolation — **never share memory across users** - Concurrent calls for the same `@MemoryId` **corrupt ChatMemory** — flag missing synchronization - `Result` return type to inspect `ToolExecution` list alongside text response - `@AiService` on interfaces for Spring Boot auto-wiring (Boot 3.5+); use `wiringMode = EXPLICIT` with multiple models - Don't use `@Value` annotations for models — prefer Spring Boot auto-configuration - **Persistent execution state**: `AgenticScope` must be persisted and recoverable for long-running agentic workflows — verify a durable `AgenticScopeStore` is wired, not in-memory - **Optional agents**: verify optional agents are declared with `Optional` return / injection so missing agents fail fast at startup, not at runtime ### 2. Tools & Function Calling - `@Tool` with a clear, LLM-readable description (the description is what the model reads, not comments) - `@P` on every parameter with a description; use `required = false` or `Optional` for optional params - `@ToolMemoryId` to pass memory context into tools that need per-user state - `ReturnBehavior.IMMEDIATE` for deterministic tools that don't need LLM re-processing - `ReturnBehavior.IMMEDIATE_IF_LAST` when a deterministic tool should short-circuit only if it is the final tool call in the turn - Polymorphic return types and tool parameters are supported in 1.14.0; verify subtype schemas are explicit and not raw `Map` - `.executeToolsConcurrently()` for parallel tool execution when tools are independent - `.toolExecutionErrorHandler(...)` and `.toolArgumentsErrorHandler(...)` for graceful tool failures — don't let raw exceptions leak to the LLM - `.hallucinatedToolNameStrategy(...)` to handle non-existent tool calls - `ToolProvider` (dynamic) over static `.tools(obj)` when tools vary per request (e.g. user-specific permissions) - **`@P` name + description**: when parameter names are ambiguous or compiled without debug info, explicitly set both `name` and `description` on `@P` — relying on bytecode parameter names alone is fragile - **Image-returning tools**: tools that produce images must return `dev.langchain4j.data.image.Image` (or `Content` containing `ImageContent`) — returning raw bytes or a URL string bypasses multimodal handling ### 3. MCP Integration - **Transport choice**: prefer `StreamableHttpMcpTransport` for production remote servers; `StdioMcpTransport` for local/subprocess servers - `DefaultMcpClient` must have a `.key("...")` set — used in filters and name mappers - `McpToolProvider.cacheToolList(true)` (default) is fine; set `false` only when tools change frequently - `failIfOneServerFails(false)` for resilience when using multiple MCP clients - Use `.toolNameMapper((client, spec) -> client.key() + "_" + spec.name())` when multiple MCP clients may have name collisions - MCP stdio server: **log to `System.err`, never `System.out`** — writing to stdout corrupts the JSON-RPC protocol - MCP server imports: use `dev.langchain4j.community.mcp.server.*` — **`dev.langchain4j.mcp.server.*` is wrong** - For HTTP MCP servers in Spring Boot: no official LangChain4j module — use stdio JAR, CDI-MCP microservice, or FastMCP (see `langchain4j-mcp-server` for implementation-path selection) - Close `McpClient` instances on application shutdown (implements `Closeable`) - 1.15.0+: use `maxToolCallingRound` not deprecated `maxSequentialToolsInvocations` ### 4. Memory Management - Use `TokenWindowChatMemory` over `MessageWindowChatMemory` in production (precise token budgeting) - `ChatMemoryStore` must be backed by persistent storage (DB/Redis) for multi-instance deployments — in-memory is for single-node only - Use `ChatMessageSerializer` / `ChatMessageDeserializer` for JSON serialization in custom stores - System messages are always retained; do not explicitly remove or re-add them - `ChatMemoryAccess` interface on the AI Service to expose `getChatMemory(id)` / `evictChatMemory(id)` for session cleanup ### 5. Guardrails - `InputGuardrail.fatal(reason)` for security violations (stops immediately); `.failure(reason)` for accumulated soft errors - `OutputGuardrail.retry(reason)` for LLM format errors (up to `maxRetries`); `reprompt(reason, additionalPrompt)` for corrective guidance - Don't use `.failure(...)` in `OutputGuardrail` when `retry` or `reprompt` is more appropriate — failure alone does not fix the output - Set `maxRetries` explicitly (`@OutputGuardrails(maxRetries = 3)`) — default of 2 may be insufficient for complex outputs - Built-in: `MessageModeratorInputGuardrail` for content moderation; `JsonExtractorOutputGuardrail` for JSON validation ### 6. Observability - Use `MicrometerMetricsChatModelListener` for token usage metrics (`gen_ai.client.token.usage`) - `AgentMonitor` for monitoring agentic workflows; call `monitor.successfulExecutions()` after completion - `AiServiceCompletedListener` / `AiServiceErrorListener` for AI service lifecycle events — don't use raw `ChatModelListener` for AI service tracking - `ChatModelListener.onRequest()` and `onResponse()` for low-level request/response logging; use `requestContext.attributes()` to pass data between callbacks - `HtmlReportGenerator.generateReport(monitor, path)` for visual debugging of agent execution - 1.14.0 can generate topology and execution HTML reports independently; keep topology reports for design review and execution reports for run diagnostics ### 7. Spring Boot Integration - `@AiService` on the interface (not the implementation) — Spring auto-creates the bean - Auto-wired: `ChatModel`, `StreamingChatModel`, `ChatMemoryProvider`, `ContentRetriever`, `RetrievalAugmentor`, `ToolProvider`, and `@Component` beans with `@Tool` methods - Use `@AiService(wiringMode = EXPLICIT, chatModel = "beanName")` when multiple models coexist - `@Tool` beans (`@Component`) are auto-registered as tools — they must be Spring-managed for dependency injection to work - `langchain4j.{provider}.chat-model.*` properties for model config; don't hardcode API keys — use `${ENV_VAR}` references - **Spring Boot 4 compatibility**: when targeting Spring Boot 4.0.5+, use `-spring-boot4-starter` artifact suffix (e.g. `langchain4j-spring-boot4-starter`, `langchain4j-open-ai-spring-boot4-starter`) — the `-spring-boot-starter` artifacts target Boot 3.x only ### 8. Skills System (`langchain4j-skills:1.18.1-beta28`) - Treat the native Skills API as experimental; Tool Mode is the production default and has no inference-time filesystem access. - Verify static `ClassPathSkillLoader.loadSkills("skills")` or `FileSystemSkillLoader.loadSkills(Path)` usage, then `Skills.from(loaded).toolProvider()` plus an available-skills system message. - Verify each `SKILL.md` has only the required `name` and `description` frontmatter and bounded resources; tools must be attached to `Skill` builders, not inferred from prose. - A filtered `McpToolProvider` may be attached to a skill so remote tools appear after activation; validate this is deliberate and authorization remains at the tool/server boundary. - Flag `ShellSkills` outside a tightly sandboxed, trusted environment: it executes host commands without built-in sandboxing. ### 9. A2A Typed Agents (`langchain4j-agentic-a2a`) - When reviewing A2A agent code, verify that message argument types are explicit interfaces or records — using raw `Map` or `Object` prevents compile-time safety and bypasses the actual-argument-type fixes - Agent task payloads must be serializable; custom types must be Jackson-compatible (no raw generics without type info) ## Output Format ```markdown ### [SEVERITY] Dimension — Short title **File**: `path:line` **Issue**: Description **Fix**: Corrected code block ``` End with: Files reviewed | Critical | Warning | Suggestion. For detailed patterns and code examples, see [reference.md](reference.md).