Custom Config
Presets are the recommended way to configure Polyglot. They live in YAML files, keep secrets in
environment variables, and let you switch providers without touching application code. However,
there are situations where presets are not sufficient -- when configuration values are dynamic,
generated at runtime, or sourced from your own application's settings. In these cases, you can
build LLMConfig or EmbeddingsConfig objects directly.
The Configuration Files¶
Polyglot ships with YAML preset files organized in two directories:
config/llm/presets/-- one file per inference provider (e.g.openai.yaml,anthropic.yaml)config/embed/presets/-- one file per embeddings provider
A typical preset file looks like this:
# config/llm/presets/openai.yaml
driver: openai
apiUrl: 'https://api.openai.com/v1'
apiKey: '${OPENAI_API_KEY}'
endpoint: /chat/completions
metadata:
organization: ''
project: ''
model: gpt-4.1-nano
maxTokens: 1024
contextLength: 1000000
maxOutputLength: 16384
Environment variable references like ${OPENAI_API_KEY} are resolved automatically at load
time. Polyglot searches for preset files in the following directories, in order:
config/llm/presets/(your project root)packages/polyglot/resources/config/llm/presets/(monorepo layout)vendor/cognesy/instructor-php/packages/polyglot/resources/config/llm/presets/vendor/cognesy/instructor-polyglot/resources/config/llm/presets/
The first directory that exists wins. You can override the search path by passing a $basePath
argument to Inference::using().
Configuration Parameters¶
Each LLM configuration includes these parameters:
| Parameter | Type | Description |
|---|---|---|
driver |
string |
The protocol driver to use (e.g. openai, anthropic, openai-compatible) |
apiUrl |
string |
Base URL for the provider's API |
apiKey |
string |
API key for authentication |
endpoint |
string |
The API endpoint path (e.g. /chat/completions) |
queryParams |
array |
Optional query string parameters appended to the URL |
metadata |
array |
Provider-specific settings (organization, API version, etc.) |
model |
string |
Default model name |
maxTokens |
int |
Default maximum tokens for responses |
contextLength |
int |
Maximum context window supported by the model |
maxOutputLength |
int |
Maximum output length supported by the model |
options |
array |
Default request options passed to every call |
pricing |
array |
Optional token pricing information for cost tracking |
Embeddings configurations use a similar structure with dimensions and maxInputs instead of
the token-related fields.
Runtime Configuration with LLMConfig¶
When you need to build a configuration programmatically, use the LLMConfig class:
<?php
use Cognesy\Messages\Messages;
use Cognesy\Polyglot\Inference\Config\LLMConfig;
use Cognesy\Polyglot\Inference\Inference;
$config = new LLMConfig(
driver: 'openai',
apiUrl: 'https://api.openai.com/v1',
apiKey: (string) getenv('OPENAI_API_KEY'),
endpoint: '/chat/completions',
model: 'gpt-4.1-nano',
maxTokens: 2048,
contextLength: 1000000,
maxOutputLength: 16384,
);
$text = Inference::fromConfig($config)
->withMessages(Messages::fromString('Say hello.'))
->get();
Note: Messages is imported from Cognesy\Messages\Messages. You can create messages from a
string with Messages::fromString() or from an array of role/content pairs with
Messages::fromArray().
This is useful when your application stores provider credentials in a database, rotates API keys at runtime, or needs to construct configurations for providers not included in the bundled presets.
Creating Configurations from Arrays¶
You can also create an LLMConfig from an associative array, which is convenient when loading
configuration from a database or external source:
<?php
use Cognesy\Polyglot\Inference\Config\LLMConfig;
$config = LLMConfig::fromArray([
'driver' => 'openai',
'apiUrl' => 'https://api.openai.com/v1',
'apiKey' => $apiKeyFromDatabase,
'endpoint' => '/chat/completions',
'model' => 'gpt-4.1-nano',
'maxTokens' => 1024,
]);
Overriding Configuration Values¶
If you need to modify an existing configuration, use withOverrides() to create a new
instance with specific values changed:
<?php
use Cognesy\Polyglot\Inference\Config\LLMConfig;
$baseConfig = LLMConfig::fromPreset('openai');
// Create a variant with a different model and higher token limit
$highCapConfig = $baseConfig->withOverrides([
'model' => 'gpt-4.1',
'maxTokens' => 4096,
]);
Embeddings Configuration¶
The embeddings equivalent follows the same pattern:
<?php
use Cognesy\Polyglot\Embeddings\Config\EmbeddingsConfig;
use Cognesy\Polyglot\Embeddings\Embeddings;
$embeddings = Embeddings::fromConfig(new EmbeddingsConfig(
driver: 'openai',
apiUrl: 'https://api.openai.com/v1',
apiKey: (string) getenv('OPENAI_API_KEY'),
endpoint: '/embeddings',
model: 'text-embedding-3-small',
dimensions: 1536,
maxInputs: 2048,
));
The embeddings configuration parameters are:
| Parameter | Type | Description |
|---|---|---|
driver |
string |
The driver to use (e.g. openai, cohere, gemini, jina) |
apiUrl |
string |
Base URL for the provider's API |
apiKey |
string |
API key for authentication |
endpoint |
string |
The API endpoint path (e.g. /embeddings) |
model |
string |
The embedding model name |
dimensions |
int |
The dimensionality of the embedding vectors |
maxInputs |
int |
Maximum number of inputs per batch request |
metadata |
array |
Provider-specific settings |
DSN Input¶
Both LLMConfig and EmbeddingsConfig support a lightweight DSN (Data Source Name) format
for quick inline configuration:
<?php
use Cognesy\Messages\Messages;
use Cognesy\Polyglot\Inference\Config\LLMConfig;
use Cognesy\Polyglot\Inference\Inference;
$config = LLMConfig::fromDsn('openai://api.openai.com/v1?model=gpt-4.1-nano&apiKey=sk-...');
$response = Inference::fromConfig($config)
->withMessages(Messages::fromString('Hello!'))
->get();
The DSN format encodes the driver as the scheme, the host and path as the API URL, and query parameters for the remaining configuration values.
Managing API Keys¶
API keys should never be committed to your codebase. Polyglot preset files use environment
variable references (${OPENAI_API_KEY}) that are resolved at load time. Store your keys in
a .env file:
OPENAI_API_KEY=sk-your-key-here
ANTHROPIC_API_KEY=sk-ant-your-key-here
GEMINI_API_KEY=your-key-here
MISTRAL_API_KEY=your-key-here
Load them with a package like vlucas/phpdotenv, or rely on your framework's built-in
environment handling (Laravel loads .env automatically).
Security Tip: The
apiKeyparameter onLLMConfigis marked with PHP's#[SensitiveParameter]attribute, which prevents it from appearing in stack traces. Polyglot also redacts sensitive values from event payloads and debug output.
Provider-Specific Options¶
Different providers support unique request parameters. You can pass these through the
options parameter on each request:
<?php
use Cognesy\Messages\Messages;
use Cognesy\Polyglot\Inference\Inference;
// OpenAI-specific options
$response = Inference::using('openai')
->with(
messages: Messages::fromString('Generate a creative story.'),
options: [
'temperature' => 0.8,
'top_p' => 0.95,
'frequency_penalty' => 0.5,
'presence_penalty' => 0.5,
'stop' => ["\n\n", "THE END"],
],
)
->get();
For Anthropic, the available options differ:
<?php
use Cognesy\Messages\Messages;
use Cognesy\Polyglot\Inference\Inference;
// Anthropic-specific options
$response = Inference::using('anthropic')
->with(
messages: Messages::fromString('Generate a creative story.'),
options: [
'temperature' => 0.7,
'top_p' => 0.9,
'top_k' => 40,
],
)
->get();
Polyglot passes these options through to the provider's API without modification, so consult each provider's documentation for the full list of supported parameters.
You can also set default options in the preset YAML file so they apply to every request made with that preset:
# config/llm/presets/creative-openai.yaml
driver: openai
apiUrl: 'https://api.openai.com/v1'
apiKey: '${OPENAI_API_KEY}'
endpoint: /chat/completions
model: gpt-4.1
maxTokens: 2048
options:
temperature: 0.9
top_p: 0.95
Environment-Based Configuration¶
You can create custom presets for different deployment environments. For example, use a local Ollama instance in development and a cloud provider in production:
# config/llm/presets/dev-local.yaml
driver: openai-compatible
apiUrl: 'http://localhost:11434/v1'
apiKey: ''
endpoint: /chat/completions
model: llama3
maxTokens: 1024
Then select the preset based on your application's environment:
<?php
use Cognesy\Messages\Messages;
use Cognesy\Polyglot\Inference\Inference;
$preset = getenv('APP_ENV') === 'production' ? 'openai' : 'dev-local';
$response = Inference::using($preset)
->withMessages(Messages::fromString('Hello!'))
->get();
This pattern keeps your application code completely environment-agnostic. The only thing that changes between environments is which preset name is selected.
Creating Custom Preset Files¶
To add a new provider or a custom configuration, create a new YAML file in your project's
config/llm/presets/ directory:
# config/llm/presets/my-proxy.yaml
driver: openai-compatible
apiUrl: 'https://my-proxy.example.com/v1'
apiKey: '${MY_PROXY_API_KEY}'
endpoint: /chat/completions
model: gpt-4.1-nano
maxTokens: 2048
contextLength: 128000
maxOutputLength: 16384
Then reference it by name:
<?php
use Cognesy\Messages\Messages;
use Cognesy\Polyglot\Inference\Inference;
$response = Inference::using('my-proxy')
->withMessages(Messages::fromString('Hello from my proxy!'))
->get();
Polyglot will find your custom preset file before falling back to the bundled presets, so you can override any built-in preset by creating a file with the same name in your project's configuration directory.