How to Fine-Tune Embabel-Agent Models: A Complete Configuration Guide
Fine-tuning Embabel-Agent models requires exposing your custom model as a Spring AI ChatModel and configuring an Llm bean with specific options via LlmOptions to override default model IDs and generation parameters.
Embabel-Agent provides a flexible integration layer for Large Language Models (LLMs) through Spring AI, making it straightforward to incorporate fine-tuned models into your agent workflows. Because the framework delegates model management to Spring AI providers, you can use fine-tuned versions from OpenAI, Anthropic, or local deployments by updating configuration rather than modifying core logic. This guide demonstrates how to point your Embabel-Agent application to custom fine-tuned models using the official embabel/embabel-agent repository patterns.
Understanding the Architecture
Spring AI ChatModel Integration
Embabel-Agent relies on Spring AI's ChatModel interface to communicate with LLM providers. In embabel-agent-openai/src/main/kotlin/com/embabel/agent/openai/OpenAiConfiguration.kt, the framework defines beans that connect to provider APIs, using the model ID specified in your configuration.
When you fine-tune a model through a cloud provider, you receive a custom model identifier (e.g., ft:gpt-3.5-turbo-0613:my-org::MY_FINE_TUNED_MODEL). By substituting this ID for the default model name in your configuration, Spring AI routes requests to your fine-tuned endpoint automatically.
The LlmOptions Configuration Layer
The LlmOptions class, located in embabel-agent-common/embabel-agent-ai/src/main/kotlin/com/embabel/common/ai/model/LlmOptions.kt, provides a fluent builder for per-call hyperparameters. This includes temperature, topP, maxTokens, and crucially, the model identifier. When building an Llm bean, you can set default options that specify your fine-tuned model ID, ensuring all agent actions use the correct weights without manual intervention.
Step-by-Step Fine-Tuning Workflow
1. Prepare Your Fine-Tuned Model
First, create your fine-tuned model through your provider's standard workflow. For OpenAI, use the dashboard or CLI to initiate training, then note the resulting model ID. For local deployments using Ollama or LM Studio, ensure your fine-tuned weights are loaded and the service is accessible via base URL.
2. Add the Embabel-Agent Starter
Include the appropriate starter dependency in your pom.xml or build.gradle. For OpenAI models:
<dependency>
<groupId>com.embabel.agent</groupId>
<artifactId>embabel-agent-starter</artifactId>
<version>0.3.0</version>
</dependency>
For local Ollama deployments, use the Ollama-specific starter instead:
<dependency>
<groupId>com.embabel.agent</groupId>
<artifactId>embabel-agent-starter-ollama</artifactId>
<version>0.3.0</version>
</dependency>
3. Configure API Credentials
Set your provider API keys as environment variables or in application.properties:
OPENAI_API_KEY=sk-your-key-here
ANTHROPIC_API_KEY=sk-ant-your-key-here
4. Update Application Configuration
Modify src/main/resources/application.yml to reference your fine-tuned model ID instead of the base model:
spring:
ai:
openai:
api-key: ${OPENAI_API_KEY}
chat:
model: ft:gpt-3.5-turbo-0613:my-org::MY_FINE_TUNED_MODEL
temperature: 0.7
max-tokens: 2000
This configuration directs the Spring AI ChatModel bean—defined in OpenAiConfiguration.kt—to use your custom model for all chat completions.
5. (Optional) Define Custom Llm Beans
For applications requiring multiple models (e.g., a base model for quick tasks and a fine-tuned model for specialized generation), declare explicit beans:
@Configuration
class CustomLlmConfig {
@Bean
fun fineTunedLlm(openAiChatModel: ChatModel): Llm {
return Llm.builder()
.chatModel(openAiChatModel)
.defaultOptions(
LlmOptions.withModel("ft:gpt-3.5-turbo-0613:my-org::MY_FINE_TUNED_MODEL")
.withTemperature(0.8)
.withMaxTokens(1500)
)
.build()
}
@Bean
fun baseLlm(openAiChatModel: ChatModel): Llm {
return Llm.builder()
.chatModel(openAiChatModel)
.defaultOptions(
LlmOptions.withModel("gpt-3.5-turbo")
.withTemperature(0.2)
)
.build()
}
}
6. Implement Agent Actions
Inject your custom Llm bean into agent classes and invoke it using ai.withLlm():
@Agent(description = "Generate specialized reports using fine-tuned knowledge")
class ReportAgent(
private val fineTunedLlm: Llm
) {
@Action
fun createReport(input: UserInput, ai: Ai): Report {
return ai.withLlm(fineTunedLlm)
.createObject(
"Generate a technical summary for: ${input.content}",
Report::class.java
)
}
}
The ai.withLlm() method overrides the default LLM for that specific action, routing the prompt to your fine-tuned model with the parameters specified in your LlmOptions.
Configuration Examples
YAML-Based Configuration
For simple deployments where all agents should use the same fine-tuned model, YAML configuration suffices:
spring:
ai:
openai:
api-key: ${OPENAI_API_KEY}
chat:
model: ft:gpt-4-0613:my-org::CUSTOM_MODEL_ID
temperature: 0.6
top-p: 0.9
This approach requires no additional code changes; the default Llm bean automatically inherits these settings.
Programmatic Bean Definition
When you need dynamic model selection or different parameters for different agent types, use explicit bean configuration:
@Configuration
class LlmBeans {
@Bean
fun cheapLlm(openAiChatModel: ChatModel): Llm =
Llm.builder()
.chatModel(openAiChatModel)
.defaultOptions(
LlmOptions.withModel("gpt-3.5-turbo")
.withTemperature(0.2)
)
.build()
@Bean
fun premiumFineTunedLlm(openAiChatModel: ChatModel): Llm =
Llm.builder()
.chatModel(openAiChatModel)
.defaultOptions(
LlmOptions.withModel("ft:gpt-4-0613:my-org::PREMIUM_TUNED")
.withTemperature(0.7)
.withMaxTokens(4096)
)
.build()
}
Multi-Model Agent Implementation
Create agents that intelligently select models based on context or budget:
@Agent(description = "Cost-aware recommendation engine")
class CostAwareAgent(
private val cheapLlm: Llm,
private val premiumFineTunedLlm: Llm
) {
@Action
fun recommend(request: RecommendationRequest, ai: Ai): Recommendation {
val selectedLlm = if (request.budget < 0.05) cheapLlm else premiumFineTunedLlm
return ai.withLlm(selectedLlm)
.createObject(
"Generate recommendation for ${request.topic}",
Recommendation::class.java
)
}
}
Summary
- Embabel-Agent delegates model management to Spring AI, meaning you fine-tune through your provider (OpenAI, Anthropic, etc.) and reference the custom model ID in configuration.
LlmOptionsprovides the fluent interface for setting model IDs, temperature, and token limits, located inembabel-agent-common/embabel-agent-ai/src/main/kotlin/com/embabel/common/ai/model/LlmOptions.kt.- YAML configuration in
application.ymlis sufficient for single-model deployments usingspring.ai.openai.chat.model. - Explicit
Llmbeans allow you to maintain multiple model configurations simultaneously and inject them into specific agent actions viaai.withLlm(). - The
OpenAiConfiguration.ktfile inembabel-agent-openaidemonstrates how the framework wires Spring AI beans, which automatically respect your fine-tuned model identifiers.
Frequently Asked Questions
How do I switch between a base model and a fine-tuned model in the same application?
Define separate Llm beans for each model variant, injecting different LlmOptions with distinct model IDs. Autowire both beans into your agent class, then use conditional logic within your @Action methods to select the appropriate model via ai.withLlm(baseLlm) or ai.withLlm(fineTunedLlm).
Can I use fine-tuned models from local providers like Ollama?
Yes. Add the embabel-agent-starter-ollama dependency and configure the base URL pointing to your local Ollama instance. Specify your fine-tuned model tag in LlmOptions.withModel("your-model-tag"), ensuring the model files are available locally.
Where do I set the temperature and max-tokens for a fine-tuned model?
Use the LlmOptions builder when constructing your Llm bean. Methods like withTemperature(), withMaxTokens(), and withModel() allow you to customize generation parameters. These settings apply to all calls made through that Llm instance, overriding any defaults from application.yml.
Do I need to modify the Embabel-Agent source code to use a custom fine-tuned model?
No. The framework is designed to accept any Spring AI-compatible ChatModel. You simply configure the model ID in your YAML or Java/Kotlin configuration classes. The OpenAiConfiguration.kt source demonstrates this extensibility by creating beans that respect external configuration properties.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →