- Prerequisites
- Project Overview
- Understanding the Code
- How It All Works Together
- Setting Up Foundry Local
- Running the Application
- Expected Output
- Next Steps
- Troubleshooting
Before starting this tutorial, make sure you have:
- Java 21 or higher installed on your system
- Maven 3.6+ for building the project
- Foundry Local installed and running
Note: Foundry Local CLI is available on Windows and macOS only. Linux is supported via the Foundry Local SDKs (Python, JavaScript, C#, Rust).
# Windows
winget install Microsoft.FoundryLocal
# macOS
brew tap microsoft/foundrylocal
brew install foundrylocalVerify the installation:
foundry --versionThis project consists of four main components:
- Application.java - The main Spring Boot application entry point
- FoundryLocalService.java - Service layer that handles AI communication
- application.properties - Configuration for Foundry Local connection
- pom.xml - Maven dependencies and project configuration
File: src/main/resources/application.properties
foundry.local.base-url=http://localhost:5273/v1
# foundry.local.model is auto-detected from Foundry Local. Set it here to override:
# foundry.local.model=Phi-4-mini-instruct-cuda-gpu:5What this does:
- base-url: Specifies where Foundry Local is running, including the
/v1path for OpenAI API compatibility. The default port is5273. If the port differs, check it withfoundry service status. - model (optional): Names the AI model to use for text generation. By default, the application auto-detects the model by querying the Foundry Local
/v1/modelsendpoint at startup, so you don't need to set this. You can still set it explicitly to override auto-detection if needed.
Key concept: Spring Boot automatically loads these properties and makes them available to your application using the @Value annotation.
File: src/main/java/com/example/Application.java
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication app = new SpringApplication(Application.class);
app.setWebApplicationType(WebApplicationType.NONE); // No web server needed
app.run(args);
}What this does:
@SpringBootApplicationenables Spring Boot auto-configurationWebApplicationType.NONEtells Spring this is a command-line app, not a web server- The main method starts the Spring application
The Demo Runner:
@Bean
public CommandLineRunner foundryLocalRunner(FoundryLocalService foundryLocalService) {
return args -> {
System.out.println("=== Foundry Local Demo ===");
System.out.println("Calling Foundry Local service...");
String testMessage = "Hello! Can you tell me what you are and what model you're running?";
System.out.println("Sending message: " + testMessage);
String response = foundryLocalService.chat(testMessage);
System.out.println("Response from Foundry Local:");
System.out.println(response);
System.out.println("=========================");
};
}What this does:
@Beancreates a component that Spring managesCommandLineRunnerruns code after Spring Boot starts upfoundryLocalServiceis automatically injected by Spring (dependency injection)- Sends a test message to the AI and displays the response
File: src/main/java/com/example/FoundryLocalService.java
@Service
public class FoundryLocalService {
@Value("${foundry.local.base-url:http://localhost:5273/v1}")
private String baseUrl;
@Value("${foundry.local.model:}")
private String model; // Auto-detected if emptyWhat this does:
@Servicetells Spring this class provides business logic@Valueinjects configuration values from application.properties- The model defaults to empty, which triggers auto-detection from Foundry Local at startup. This means the app works with any model loaded in Foundry Local without manual configuration.
@PostConstruct
public void init() {
// Auto-detect the model from Foundry Local if not explicitly configured
if (model == null || model.isBlank()) {
model = detectModel();
}
this.openAIClient = OpenAIOkHttpClient.builder()
.baseUrl(baseUrl) // Base URL already includes /v1 from configuration
.apiKey("not-needed") // Local server doesn't need real API key
.build();
}What this does:
@PostConstructruns this method after Spring creates the service- If no model is configured, it queries Foundry Local's
/v1/modelsendpoint and picks the first loaded model - Creates an OpenAI client that points to your local Foundry Local instance
- The base URL from
application.propertiesalready includes/v1for OpenAI API compatibility - API key is set to "not-needed" because local development doesn't require authentication
public String chat(String message) {
try {
ChatCompletionCreateParams params = ChatCompletionCreateParams.builder()
.model(model) // Which AI model to use
.addUserMessage(message) // Your question/prompt
.maxCompletionTokens(150) // Limit response length
.temperature(0.7) // Control creativity (0.0-1.0)
.build();
ChatCompletion chatCompletion = openAIClient.chat().completions().create(params);
// Extract the AI's response from the API result
if (chatCompletion.choices() != null && !chatCompletion.choices().isEmpty()) {
return chatCompletion.choices().get(0).message().content().orElse("No response found");
}
return "No response content found";
} catch (Exception e) {
throw new RuntimeException("Error calling chat completion: " + e.getMessage(), e);
}
}What this does:
- ChatCompletionCreateParams: Configures the AI request
model: Specifies which AI model to use (must match the exact ID fromfoundry model list)addUserMessage: Adds your message to the conversationmaxCompletionTokens: Limits how long the response can be (saves resources)temperature: Controls randomness (0.0 = deterministic, 1.0 = creative)
- API Call: Sends the request to Foundry Local
- Response Handling: Extracts the AI's text response safely
- Error Handling: Wraps exceptions with helpful error messages
Key Dependencies:
<!-- Spring Boot - Application framework -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<!-- OpenAI Java SDK - For AI API calls -->
<dependency>
<groupId>com.openai</groupId>
<artifactId>openai-java</artifactId>
<version>2.12.0</version>
</dependency>
<!-- Jackson - JSON processing -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.17.0</version>
</dependency>What these do:
- spring-boot-starter: Provides core Spring Boot functionality
- openai-java: Official OpenAI Java SDK for API communication
- jackson-databind: Handles JSON serialization/deserialization for API calls
Here's the complete flow when you run the application:
- Startup: Spring Boot starts and reads
application.properties - Service Creation: Spring creates
FoundryLocalServiceand injects configuration values - Model Detection: If no model is configured, the service queries Foundry Local's
/v1/modelsendpoint and uses the first available model automatically - Client Setup:
@PostConstructinitializes the OpenAI client to connect to Foundry Local - Demo Execution:
CommandLineRunnerexecutes after startup - AI Call: The demo calls
foundryLocalService.chat()with a test message - API Request: Service builds and sends OpenAI-compatible request to Foundry Local
- Response Processing: Service extracts and returns the AI's response
- Display: Application prints the response and exits
-
Install Foundry Local using the instructions in the Prerequisites section.
-
Start the service (if not already running):
foundry service start
-
Check the service status to confirm it is running and note the port:
foundry service status
-
Download and run a model (downloads on first run, cached for subsequent runs):
foundry model run phi-4-mini
This opens an interactive chat session. You can exit with
Ctrl+C. The model stays loaded in the service.Tip: Run
foundry model listto see all available models. Replacephi-4-miniwith any alias from the catalog (e.g.,qwen2.5-0.5bfor a smaller/faster model). -
Verify the model is loaded:
foundry service ps
-
Update
application.propertiesif needed:- The default
base-url(http://localhost:5273/v1) matches the default CLI port. Update only iffoundry service statusshows a different port. - The model is auto-detected at startup — no configuration needed.
foundry.local.base-url=http://localhost:5273/v1 # Model is auto-detected. Uncomment below to override: # foundry.local.model=Phi-4-mini-instruct-cuda-gpu:5
- The default
foundry service psIf no models are listed, load one:
foundry model run phi-4-miniIn a separate terminal:
cd 04-PracticalSamples/foundrylocal
mvn spring-boot:runOr build and run as a JAR:
mvn clean package
java -jar target/foundry-local-spring-boot-0.0.1-SNAPSHOT.jar=== Foundry Local Demo ===
Calling Foundry Local service...
Sending message: Hello! Can you tell me what you are and what model you're running?
Response from Foundry Local:
Hello! I'm Phi, an AI developed by Microsoft. I can assist with a wide variety of
tasks including answering questions, helping with analysis, creative writing, coding,
and general conversation. How can I help you today?
=========================
For more examples, see Chapter 04: Practical samples
"Connection refused" or "Service unavailable"
- Check the service:
foundry service status - Restart if needed:
foundry service restart - Verify the port in
application.propertiesmatchesfoundry service statusoutput - Ensure the URL ends with
/v1:http://localhost:5273/v1
"No model found" at startup
- The application auto-detects the model. Ensure at least one model is loaded:
foundry service ps - If no models are loaded:
foundry model run phi-4-mini - If you overrode the model name in
application.properties, verify it matchesfoundry model list
"400 Bad Request" errors
- Verify the base URL includes
/v1:http://localhost:5273/v1 - Ensure you're using
maxCompletionTokens()in your code (not the deprecatedmaxTokens())
Maven compilation errors
- Ensure Java 21 or higher:
java -version - Clean and rebuild:
mvn clean compile - Check internet connection for dependency downloads
Service connection problems
- If you see
Request to local service failed, run:foundry service restart - Check loaded models:
foundry service ps - View service logs:
foundry service diag