This package provides an integration layer between the LangChain4j framework and Anthropic's Claude language models, enabling Java developers to seamlessly incorporate Anthropic's AI capabilities into their applications.
The langchain4j-anthropic integration supports both user-defined tools (functions the model can call) and Anthropic server-side tools (like web search executed by Anthropic's servers).
User-defined tools are configured using ToolSpecification from langchain4j-core. These tools are executed by your application code.
import dev.langchain4j.agent.tool.ToolSpecification;
import dev.langchain4j.agent.tool.ToolExecutionRequest;
import dev.langchain4j.data.message.ToolExecutionResultMessage;
import dev.langchain4j.model.chat.request.json.JsonObjectSchema;
// Define a tool
ToolSpecification weatherTool = ToolSpecification.builder()
.name("get_weather")
.description("Get current weather for a location")
.parameters(JsonObjectSchema.builder()
.addStringProperty("location", "City name")
.required("location")
.build())
.build();
// Create model with tool
AnthropicChatModel model = AnthropicChatModel.builder()
.apiKey(apiKey)
.modelName(AnthropicChatModelName.CLAUDE_SONNET_4_5_20250929)
.toolSpecifications(weatherTool)
.build();
// Chat and handle tool calls
ChatResponse response = model.chat(ChatRequest.builder()
.messages(UserMessage.from("What's the weather in Paris?"))
.build());
if (response.aiMessage().hasToolExecutionRequests()) {
for (ToolExecutionRequest request : response.aiMessage().toolExecutionRequests()) {
String toolName = request.name();
String arguments = request.arguments();
// Execute tool
String result = executeWeatherTool(toolName, arguments);
// Send result back
ChatResponse finalResponse = model.chat(ChatRequest.builder()
.messages(
UserMessage.from("What's the weather in Paris?"),
response.aiMessage(),
ToolExecutionResultMessage.from(request, result)
)
.build());
System.out.println(finalResponse.aiMessage().text());
}
}Error Handling:
RuntimeException: Tool name not found in registered toolsRuntimeException: Tool arguments don't match schema (if strictTools enabled)RuntimeException: Tool execution fails in user code (handle in application)Common Pitfalls:
❌ DON'T forget to send tool results back
if (response.aiMessage().hasToolExecutionRequests()) {
executeTools(response.aiMessage().toolExecutionRequests());
// Missing: send results back to model
}✅ DO complete the tool loop
if (response.aiMessage().hasToolExecutionRequests()) {
List<ToolExecutionRequest> requests = response.aiMessage().toolExecutionRequests();
String result = executeTools(requests);
ChatResponse nextResponse = model.chat(ChatRequest.builder()
.messages(userMsg, aiMsg, ToolExecutionResultMessage.from(requests.get(0), result))
.build());
}Performance Notes:
Control which tools the model uses.
package dev.langchain4j.model.chat.request;
/**
* Strategy for tool selection.
*/
public enum ToolChoice {
/** Model decides whether to use tools - default behavior */
AUTO,
/** Model must use at least one tool from the available set */
REQUIRED,
/** Model cannot use any tools */
NONE;
}Usage Example:
import dev.langchain4j.model.chat.request.ToolChoice;
// Auto: Model decides whether to use tools
AnthropicChatModel autoModel = AnthropicChatModel.builder()
.apiKey(apiKey)
.modelName(modelName)
.toolSpecifications(tools)
.toolChoice(ToolChoice.AUTO)
.build();
// Required: Model must use at least one tool
AnthropicChatModel requiredAnyModel = AnthropicChatModel.builder()
.apiKey(apiKey)
.modelName(modelName)
.toolSpecifications(tools)
.toolChoice(ToolChoice.REQUIRED) // Requires use of at least one tool
.build();
// Required: Model must use a specific tool
AnthropicChatModel requiredModel = AnthropicChatModel.builder()
.apiKey(apiKey)
.modelName(modelName)
.toolSpecifications(weatherTool)
.toolChoice(ToolChoice.REQUIRED)
.toolChoiceName("get_weather")
.build();
// None: Model cannot use tools
AnthropicChatModel noneModel = AnthropicChatModel.builder()
.apiKey(apiKey)
.modelName(modelName)
.toolSpecifications(tools)
.toolChoice(ToolChoice.NONE)
.build();Error Handling:
IllegalArgumentException: toolChoiceName set without REQUIRED toolChoiceRuntimeException: Specified tool name not found in toolSpecificationsRuntimeException: REQUIRED set but no tools will match user queryCommon Pitfalls:
❌ DON'T use REQUIRED without appropriate tools
.toolSpecifications(calculatorTool)
.toolChoice(ToolChoice.REQUIRED)
// User asks: "What's the weather?" - model forced to use calculator✅ DO match tools to expected use cases
.toolSpecifications(weatherTool, timeToolget, newsToolget)
.toolChoice(ToolChoice.AUTO) // Model chooses appropriate toolUse Cases by Strategy:
Control whether the model can call multiple tools in parallel.
// Enable parallel tool execution (default)
AnthropicChatModel parallelModel = AnthropicChatModel.builder()
.apiKey(apiKey)
.modelName(modelName)
.toolSpecifications(tools)
.disableParallelToolUse(false)
.build();
// Disable parallel tool execution
AnthropicChatModel sequentialModel = AnthropicChatModel.builder()
.apiKey(apiKey)
.modelName(modelName)
.toolSpecifications(tools)
.disableParallelToolUse(true)
.build();Error Handling:
Common Pitfalls:
❌ DON'T disable parallel when tools are independent
.disableParallelToolUse(true) // Wastes time on independent tool calls✅ DO enable parallel for independent tools
.disableParallelToolUse(false) // Weather and time can be fetched simultaneouslyPerformance Comparison:
When to Disable Parallel:
Enable strict validation of tool schemas.
AnthropicChatModel model = AnthropicChatModel.builder()
.apiKey(apiKey)
.modelName(modelName)
.toolSpecifications(tools)
.strictTools(true) // Enable strict schema validation
.build();Error Handling:
RuntimeException: Tool arguments fail schema validationRuntimeException: Missing required parametersRuntimeException: Type mismatch in parametersCommon Pitfalls:
❌ DON'T enable strict without thorough schema testing
.strictTools(true) // May reject valid tool calls due to schema issues✅ DO test schemas thoroughly first
// Test with strictTools(false), then enable
.strictTools(false) // Development
.strictTools(true) // Production after validationValidation Behavior:
Pass additional metadata with tool specifications. Tool metadata allows you to send custom information about tools to the model, which can help the model make better decisions about when and how to use tools.
The toolMetadataKeysToSend builder method controls which metadata keys from the ToolSpecification metadata map are sent to the Anthropic API. By default, no metadata is sent. You can specify which keys to include.
Common Use Cases:
package dev.langchain4j.agent.tool;
import java.util.Map;
/**
* Tool specification with metadata support.
*/
public class ToolSpecification {
/**
* Returns tool metadata map.
*
* @return metadata map, never null (may be empty)
*/
public Map<String, Object> metadata();
}Usage Example:
import java.util.Set;
ToolSpecification tool = ToolSpecification.builder()
.name("calculator")
.description("Perform calculations")
.parameters(schema)
.metadata(Map.of(
"category", "math",
"version", "1.0",
"cost", "low",
"priority", "high"
))
.build();
// Send specific metadata keys
AnthropicChatModel model = AnthropicChatModel.builder()
.apiKey(apiKey)
.modelName(modelName)
.toolSpecifications(tool)
.toolMetadataKeysToSend(Set.of("category")) // Only send "category"
.build();
// Or use varargs to send multiple keys
AnthropicChatModel model2 = AnthropicChatModel.builder()
.apiKey(apiKey)
.modelName(modelName)
.toolSpecifications(tool)
.toolMetadataKeysToSend("category", "version", "priority")
.build();Error Handling:
Common Pitfalls:
❌ DON'T send all metadata keys
.toolMetadataKeysToSend(tool.metadata().keySet()) // May include internal keys✅ DO explicitly control which keys to send
.toolMetadataKeysToSend("category", "version") // Only relevant keysPerformance Notes:
Tools integrate seamlessly with LangChain4j's AI Services.
import dev.langchain4j.service.AiServices;
import dev.langchain4j.agent.tool.Tool;
class Calculator {
@Tool("Add two numbers")
int add(int a, int b) {
return a + b;
}
@Tool("Multiply two numbers")
int multiply(int a, int b) {
return a * b;
}
}
interface MathAssistant {
String chat(String message);
}
AnthropicChatModel model = AnthropicChatModel.builder()
.apiKey(apiKey)
.modelName(AnthropicChatModelName.CLAUDE_SONNET_4_5_20250929)
.build();
MathAssistant assistant = AiServices.builder(MathAssistant.class)
.chatLanguageModel(model)
.tools(new Calculator())
.build();
String response = assistant.chat("What is 15 + 27 multiplied by 3?");
System.out.println(response);AI Services Benefits:
Error Handling:
Server tools are executed by Anthropic's servers (e.g., web search, code execution). These are experimental features.
Define server-side tools that Anthropic will execute.
package dev.langchain4j.model.anthropic;
import java.util.Map;
/**
* Server-side tool executed by Anthropic's infrastructure.
* EXPERIMENTAL: API may change.
*
* @since 1.0.0
*/
public class AnthropicServerTool {
/**
* Creates new builder for server tool.
*
* @return new builder instance, never null
*/
public static Builder builder();
/**
* Returns tool type identifier with version.
*
* @return type string (e.g., "web_search_20250305"), never null
*/
public String type();
/**
* Returns tool name for identification.
*
* @return tool name, never null
*/
public String name();
/**
* Returns tool configuration attributes.
*
* @return attributes map, never null (may be empty)
*/
public Map<String, Object> attributes();
/**
* Compares server tools for equality.
*
* @param o other object
* @return true if equal
*/
public boolean equals(Object o);
/**
* Returns hash code.
*
* @return hash code
*/
public int hashCode();
/**
* Returns string representation.
*
* @return string form
*/
public String toString();
/**
* Builder for AnthropicServerTool.
*/
public static class Builder {
/**
* Sets tool type with version suffix.
*
* @param type tool type identifier, must not be null
* @return this builder, never null
* @throws IllegalArgumentException if type is null
* @default no default - REQUIRED
*/
public Builder type(String type);
/**
* Sets tool name.
*
* @param name tool name, must not be null
* @return this builder, never null
* @throws IllegalArgumentException if name is null
* @default no default - REQUIRED
*/
public Builder name(String name);
/**
* Sets all attributes at once.
*
* @param attributes attribute map, may be null
* @return this builder, never null
* @default empty map
*/
public Builder attributes(Map<String, Object> attributes);
/**
* Adds single attribute.
*
* @param key attribute name, must not be null
* @param value attribute value, may be null
* @return this builder, never null
* @throws IllegalArgumentException if key is null
* @default no default
*/
public Builder addAttribute(String key, Object value);
/**
* Builds server tool instance.
*
* @return configured server tool, never null
* @throws IllegalStateException if type or name missing
*/
public AnthropicServerTool build();
}
}Configure web search as a server tool.
import dev.langchain4j.model.anthropic.AnthropicServerTool;
import java.util.List;
AnthropicServerTool webSearch = AnthropicServerTool.builder()
.type("web_search_20250305")
.name("web_search")
.addAttribute("max_uses", 5)
.addAttribute("allowed_domains", List.of(
"wikipedia.org",
"britannica.com"
))
.build();
AnthropicChatModel model = AnthropicChatModel.builder()
.apiKey(apiKey)
.modelName(AnthropicChatModelName.CLAUDE_SONNET_4_5_20250929)
.serverTools(webSearch)
.returnServerToolResults(true) // Include results in response
.build();
ChatResponse response = model.chat(ChatRequest.builder()
.messages(UserMessage.from("What is the population of Tokyo?"))
.build());
// Access server tool results
Map<String, Object> attributes = response.aiMessage().attributes();
if (attributes.containsKey("server_tool_results")) {
@SuppressWarnings("unchecked")
List<AnthropicServerToolResult> results =
(List<AnthropicServerToolResult>) attributes.get("server_tool_results");
for (AnthropicServerToolResult result : results) {
System.out.println("Tool: " + result.type());
System.out.println("Content: " + result.content());
}
}Web Search Attributes:
max_uses (Integer): Maximum searches per request (1-10 recommended)allowed_domains (List<String>): Whitelist of domains to searchError Handling:
RuntimeException: Web search not available for API keyRuntimeException: max_uses exceededRuntimeException: No results found (non-fatal, empty results returned)Common Pitfalls:
❌ DON'T set max_uses too high
.addAttribute("max_uses", 100) // Expensive, slow, often unnecessary✅ DO use reasonable limits
.addAttribute("max_uses", 3) // Usually sufficientPerformance Notes:
Configure the code execution server tool for running code snippets.
import dev.langchain4j.model.anthropic.AnthropicServerTool;
AnthropicServerTool codeExecution = AnthropicServerTool.builder()
.type("code_execution_20250305")
.name("code_execution")
.addAttribute("max_uses", 5) // Maximum number of executions per request
.build();
AnthropicChatModel model = AnthropicChatModel.builder()
.apiKey(apiKey)
.modelName(AnthropicChatModelName.CLAUDE_SONNET_4_5_20250929)
.serverTools(codeExecution)
.returnServerToolResults(true) // Include execution output
.build();
ChatResponse response = model.chat(ChatRequest.builder()
.messages(UserMessage.from("Calculate the first 10 Fibonacci numbers"))
.build());Code Execution Attributes:
max_uses (Integer): Maximum number of code executions allowed in a single requestCode Execution Results: Code execution results include:
stdout: Standard output from the executed codestderr: Standard error outputreturn_code: Exit code (0 for success)Error Handling:
RuntimeException: Code execution not available for API keyRuntimeException: max_uses exceededSecurity Notes:
Common Pitfalls:
❌ DON'T assume unlimited execution time
// Long-running code may timeout
"while True: calculate()" // Will be terminated✅ DO keep executions short
// Fast, focused computations
"result = sum(range(100))" // Completes quicklyConfigure multiple server tools simultaneously.
AnthropicServerTool webSearch = AnthropicServerTool.builder()
.type("web_search_20250305")
.name("web_search")
.addAttribute("max_uses", 3)
.addAttribute("allowed_domains", List.of("wikipedia.org", "github.com"))
.build();
AnthropicServerTool codeExecution = AnthropicServerTool.builder()
.type("code_execution_20250305")
.name("code_execution")
.addAttribute("max_uses", 2)
.build();
AnthropicChatModel model = AnthropicChatModel.builder()
.apiKey(apiKey)
.modelName(modelName)
.serverTools(webSearch, codeExecution)
.returnServerToolResults(true)
.build();
ChatResponse response = model.chat(ChatRequest.builder()
.messages(UserMessage.from("Search for Python sorting algorithms and show me an implementation"))
.build());Error Handling:
Performance Notes:
Results from server-executed tools.
package dev.langchain4j.model.anthropic;
/**
* Result from server-side tool execution.
*
* @since 1.0.0
*/
public class AnthropicServerToolResult {
/**
* Creates new builder.
*
* @return new builder, never null
*/
public static Builder builder();
/**
* Returns result type identifier.
*
* @return type string (e.g., "web_search_tool_result"), never null
*/
public String type();
/**
* Returns tool execution ID linking to original request.
*
* @return tool use ID, never null
*/
public String toolUseId();
/**
* Returns result content (type varies by tool).
* Web search: List<Map<String, Object>> with title, url, snippet.
* Code execution: Map<String, Object> with stdout, stderr, return_code.
*
* @return result content, never null
*/
public Object content();
/**
* Compares results for equality.
*
* @param o other object
* @return true if equal
*/
public boolean equals(Object o);
/**
* Returns hash code.
*
* @return hash code
*/
public int hashCode();
/**
* Returns string representation.
*
* @return string form
*/
public String toString();
/**
* Builder for server tool result.
*/
public static class Builder {
/**
* Sets result type.
*
* @param type result type identifier, must not be null
* @return this builder, never null
* @default no default - REQUIRED
*/
public Builder type(String type);
/**
* Sets tool use ID.
*
* @param toolUseId execution ID, must not be null
* @return this builder, never null
* @default no default - REQUIRED
*/
public Builder toolUseId(String toolUseId);
/**
* Sets result content.
*
* @param content result data, must not be null
* @return this builder, never null
* @default no default - REQUIRED
*/
public Builder content(Object content);
/**
* Builds result instance.
*
* @return configured result, never null
* @throws IllegalStateException if required fields missing
*/
public AnthropicServerToolResult build();
}
}Handle different types of server tool results.
@SuppressWarnings("unchecked")
List<AnthropicServerToolResult> results =
(List<AnthropicServerToolResult>) response.aiMessage()
.attributes()
.get("server_tool_results");
for (AnthropicServerToolResult result : results) {
String type = result.type();
if (type.equals("web_search_tool_result")) {
// Web search results are typically List<Map<String, Object>>
List<Map<String, Object>> searchResults =
(List<Map<String, Object>>) result.content();
for (Map<String, Object> searchResult : searchResults) {
System.out.println("Title: " + searchResult.get("title"));
System.out.println("URL: " + searchResult.get("url"));
System.out.println("Snippet: " + searchResult.get("snippet"));
}
} else if (type.equals("code_execution_tool_result")) {
// Code execution results are typically Map<String, Object>
Map<String, Object> execResult =
(Map<String, Object>) result.content();
System.out.println("Stdout: " + execResult.get("stdout"));
System.out.println("Stderr: " + execResult.get("stderr"));
System.out.println("Return code: " + execResult.get("return_code"));
}
}Error Handling:
Null Safety:
package dev.langchain4j.agent.tool;
import dev.langchain4j.model.chat.request.json.JsonSchema;
import java.util.Map;
/**
* Specification for a user-defined tool.
*/
public class ToolSpecification {
/**
* Creates new builder.
*
* @return new builder, never null
*/
public static Builder builder();
/**
* Returns tool name.
*
* @return name, never null
*/
public String name();
/**
* Returns tool description.
*
* @return description, never null
*/
public String description();
/**
* Returns parameter schema.
*
* @return JSON schema, may be null
*/
public JsonSchema parameters();
/**
* Returns tool metadata.
*
* @return metadata map, never null (may be empty)
*/
public Map<String, Object> metadata();
}package dev.langchain4j.data.message;
/**
* Request to execute a tool from the model.
*/
public class ToolExecutionRequest {
/**
* Returns unique execution request ID.
*
* @return request ID, never null
*/
public String id();
/**
* Returns tool name to execute.
*
* @return tool name, never null
*/
public String name();
/**
* Returns JSON-encoded tool arguments.
*
* @return arguments JSON string, never null
*/
public String arguments();
}package dev.langchain4j.model.chat.request;
/**
* Strategy for tool selection.
*/
public enum ToolChoice {
/** Model decides whether to use tools */
AUTO,
/** Model must use at least one tool */
REQUIRED,
/** Model cannot use tools */
NONE;
}Attributes:
max_uses (Integer): Maximum number of searches per request (validation: 1-10)allowed_domains (List<String>): Restrict searches to specific domains (validation: max 20 domains)Result Format:
List<Map<String, Object>> where each map contains:
- "title" (String): Page title, never null
- "url" (String): Page URL, never null
- "snippet" (String): Text excerpt, never nullNull Safety:
Attributes:
max_uses (Integer): Maximum number of code executions per request (validation: >= 1)Result Format:
Map<String, Object> containing:
- "stdout" (String): Standard output, never null (may be empty)
- "stderr" (String): Error output, never null (may be empty)
- "return_code" (Integer): Exit code (0 = success), never nullNull Safety:
returnServerToolResults is disabled by defaulttoolMetadataKeysToSend controls which metadata keys are sent to the APIThread Safety:
Install with Tessl CLI
npx tessl i tessl/maven-dev-langchain4j--langchain4j-anthropic@1.11.0