Chapter 2: Models — Choosing Your LLM¶
← Back to Table of Contents | ← Previous: The Basics
The models section defines named LLM configurations. Each model has a provider, a model_id, and optional params.
models:
fast:
provider: bedrock
model_id: us.anthropic.claude-sonnet-4-6-v1:0
creative:
provider: openai
model_id: gpt-4o
params:
temperature: 0.9
local:
provider: ollama
model_id: llama3.2
params:
ctx_size: 8192
Built-in Providers¶
| Provider | Package Required | Example model_id |
|---|---|---|
bedrock |
(included) | us.anthropic.claude-sonnet-4-6-v1:0 |
openai |
pip install kaboo-workflows[openai] |
gpt-4o |
ollama |
pip install kaboo-workflows[ollama] |
llama3.2 |
gemini |
pip install kaboo-workflows[gemini] |
gemini-2.0-flash |
How Agents Reference Models¶
Agents reference models by name — the key you defined in the models section:
models:
smart:
provider: bedrock
model_id: us.anthropic.claude-sonnet-4-6-v1:0
agents:
analyst:
model: smart # <-- references the "smart" model above
system_prompt: "You analyze data."
Inline Models¶
Don't want to name a model? Define it inline directly on the agent:
agents:
analyst:
model:
provider: bedrock
model_id: us.anthropic.claude-sonnet-4-6-v1:0
system_prompt: "You analyze data."
This is handy when only one agent uses a specific model — no need to pollute the models section. But if two agents share the same model config, use a named model to avoid duplication.
An inline model is also the simplest choice in a config submitted per run (Chapter 13): the agents in an overlay replace the base's, but a named model has to exist somewhere, either in the base's models or in the overlay's own. Inline needs neither.
Custom Model Providers¶
If the built-in four providers aren't enough, you can point provider to a custom Model subclass:
models:
my_custom:
provider: my_package.models:CustomModel
model_id: my-model-v1
params:
api_key: ${API_KEY}
The class must be a subclass of strands.models.Model. The model_id and params are passed to its constructor.
The params Dict¶
params is a pass-through dictionary — whatever you put in it gets forwarded as **kwargs to the model constructor. This means you can set any provider-specific parameter:
models:
tuned:
provider: bedrock
model_id: us.anthropic.claude-sonnet-4-6-v1:0
params:
max_tokens: 4096
temperature: 0.7
top_p: 0.9
OpenAI client defaults: timeout and max_retries¶
For the openai provider, params.client_args is forwarded to the OpenAI SDK
client. kaboo fills two keys when you don't set them: timeout: 180 (seconds)
and max_retries: 2. Without a timeout, a stalled connection to the provider
(or a router like OpenRouter) hangs the run forever with no error; with these
defaults it fails visibly and retries. Override either key to tune:
models:
default:
provider: openai
model_id: anthropic/claude-sonnet-4-6
params:
client_args:
api_key: ${OPENROUTER_API_KEY}
base_url: https://openrouter.ai/api/v1
timeout: 300 # long-running document analysis
max_retries: 1
Bedrock client settings: client_config¶
For the bedrock provider, params.client_config sets the timeouts and retry
policy of the boto client the model reaches Bedrock through. kaboo turns it into
a botocore Config and passes it to strands' BedrockModel as
boto_client_config. Only these keys are accepted; a misspelt one fails when the
config loads rather than being ignored.
| Key | Value | Meaning |
|---|---|---|
read_timeout |
seconds, > 0 | How long to wait for data on the response stream. Unset, it stays at strands' Bedrock default of 120 (botocore's own is 60). |
connect_timeout |
seconds, > 0 | How long to wait for a connection. Unset, botocore's 60. |
retries.max_attempts |
integer, ≥ 0 | Retries after the first attempt. |
retries.mode |
legacy | standard | adaptive |
botocore's retry mode. |
models:
claude:
provider: bedrock
model_id: us.anthropic.claude-sonnet-4-6-v1:0
params:
client_config:
read_timeout: 840 # long generations on a slow stream
connect_timeout: 10
retries: {max_attempts: 4, mode: adaptive}
Thinking¶
Claude models on Bedrock can think before they answer. thinking: says whether
they do: on a model, as the default for every agent that uses it, and on an
agent, as an override of its model's.
models:
sonnet:
provider: bedrock
model_id: us.anthropic.claude-sonnet-5
thinking: {effort: high, display: summarized}
agents:
planner:
model: sonnet # thinks, as its model does
worker:
model: sonnet
thinking: false # answers without thinking
checker:
model: sonnet
thinking: {effort: low} # thinks less, with the model's display
| Value | Sent to Bedrock |
|---|---|
false (or off) |
thinking: {type: disabled} |
true |
thinking: {type: adaptive} |
{effort, display} |
thinking: {type: adaptive, display} and output_config: {effort}, each only when set |
| unset | nothing, so the model's own default applies |
effortislow,medium,high,xhighormax.display: summarizedreturns a readable summary of the thinking, which streams asREASONINGevents;omittedreturns none of it. Thinking is billed the same either way.
An agent's false wins over its model's setting, a mapping replaces only the
fields it sets, and true takes the model's settings. The fields reach strands'
BedrockModel as additional_request_fields, so a model takes thinking: or
params.additional_request_fields.thinking, not both. Other providers reject
thinking: when the config loads.
Agents whose setting differs from their named model's run on a variant of it, one per setting, built for the first such agent and reused by every agent and session after it.
Which settings a model accepts is the provider's business: some Claude models
think by default, some reject type: disabled, and older ones have no adaptive
thinking. Check the model's documentation.
Tips & Tricks
- When combined with
vars, you can swap models at runtime:MODEL=gpt-4o python main.py. See Chapter 3.- If you omit
modelon an agent entirely, strands picks its built-in default (Bedrock). This is fine for quick tests but explicit is better for production.- The
paramsdict preserves types from YAML — integers stay integers, floats stay floats. This matters for parameters likemax_tokensthat must be an int.