Inteligência artificial
1Introdução
O Temma fornece uma fonte de dados unificada \Temma\Datasources\Ai para consultar modelos de linguagem (LLMs) de diversos provedores através de uma única interface.
Essa fonte de dados suporta:
- Troca de texto (prompt / resposta)
- Prompts de sistema e configuração de temperatura
- Conversas com múltiplos turnos (histórico de conversa)
- Anexos de entrada (imagens, áudio, vídeo, PDF)
- Saída JSON estruturada
Seis provedores são integrados (OpenAI, Claude, Gemini, Mistral, OpenRouter, Ollama), e qualquer serviço compatível com OpenAI pode ser usado por meio da sintaxe de colchetes.
Para a documentação de referência da fonte de dados, veja a página da fonte de dados AI.
Em um assunto completamente diferente, o Temma também oferece skills para agentes de codificação com IA, que lhes ensinam as convenções do framework para facilitar seus desenvolvimentos. Veja a página das skills de IA.
2Configuração
2.1Formato do DSN
O DSN de conexão (Data Source Name) é escrito da seguinte forma:
ai://PROVIDER/MODEL#API_KEY
- PROVIDER: nome do provedor (veja a lista abaixo).
- MODEL: identificador do modelo de linguagem. Pode conter os caracteres / e :.
- API_KEY: sua chave de API (opcional para alguns provedores, como o Ollama).
2.2Exemplo de configuração
No arquivo etc/temma.php:
<?php
return [
'application' => [
'dataSources' => [
// conectar à OpenAI
'ai' => 'ai://openai/gpt-4o#sk-proj-xxxxxxxxxxxxx',
// ou ao Claude
'ai' => 'ai://claude/claude-sonnet-4-20250514#sk-ant-xxxxxxxxxxxxx',
// ou a um modelo local via Ollama
'ai' => 'ai://ollama/llama3:70b',
],
],
];
3Provedores integrados
3.1Tabela resumo
| Provedor | Texto | Imagens | Áudio | Vídeo | JSON | |
|---|---|---|---|---|---|---|
| openai | sim | sim | sim | sim | ||
| claude | sim | sim | sim | sim | ||
| gemini | sim | sim | sim | sim | sim | sim |
| mistral | sim | sim | sim | sim | sim | |
| openrouter | sim | sim | sim | sim | sim | |
| ollama | sim | sim | sim |
O suporte real também depende do modelo utilizado. Por exemplo, nem todos os modelos da OpenAI suportam visão.
3.2Exemplos de DSN
# OpenAI
ai://openai/gpt-4o#sk-proj-XXX
# Claude (Anthropic)
ai://claude/claude-sonnet-4-20250514#sk-ant-XXX
# Google Gemini
ai://gemini/gemini-2.5-flash#AIza-XXX
# Mistral
ai://mistral/mistral-small-latest#XXX
# OpenRouter (o nome do modelo contém "/" separando o provedor do modelo)
ai://openrouter/openai/gpt-4o#sk-or-XXX
ai://openrouter/anthropic/claude-sonnet-4#sk-or-XXX
# Ollama (local, sem chave de API)
ai://ollama/llama3:70b
ai://ollama/mistral:latest
4Serviços compatíveis com OpenAI
4.1Sintaxe de colchetes (URL)
Muitos serviços oferecem uma API compatível com OpenAI. Para usá-los, coloque a URL do endpoint entre colchetes no DSN:
ai://[ENDPOINT_URL]/MODEL#API_KEY
Alguns serviços comuns:
| Serviço | URL do endpoint |
|---|---|
| Groq | https://api.groq.com/openai/v1/chat/completions |
| Together AI | https://api.together.xyz/v1/chat/completions |
| Fireworks AI | https://api.fireworks.ai/inference/v1/chat/completions |
| DeepInfra | https://api.deepinfra.com/v1/openai/chat/completions |
Exemplos:
# Groq
ai://[https://api.groq.com/openai/v1/chat/completions]/llama-3.3-70b#gsk-XXX
# Together AI (nome do modelo com "/")
ai://[https://api.together.xyz/v1/chat/completions]/meta-llama/Meta-Llama-3-70B#XXX
# LiteLLM auto-hospedado
ai://[https://my-litellm.internal/v1/chat/completions]/model#key
4.2Provedores personalizados
Você também pode fornecer um nome de classe PHP entre colchetes. Essa classe será instanciada e usada como provedor:
ai://[\App\MyProvider]/model#key
A classe deve implementar os métodos buildPayload() e parseResponse(), assim como os provedores integrados (veja as classes em \Temma\Datasources\Ai\*).
5Uso
5.1Acesso como array
A notação de array envia um prompt e retorna a resposta como texto bruto.
$response = $this->ai['What is the capital of France?'];
// $response contém "The capital of France is Paris."
5.2Método read()
O método read() retorna uma resposta em texto bruto. O segundo parâmetro é um valor padrão (escalar ou callback) usado em caso de erro. O terceiro parâmetro é um array de opções.
// prompt simples
$response = $this->ai->read('What is the capital of France?');
// com um valor padrão
$response = $this->ai->read('Translate to French: Hello', 'Bonjour');
// com um callback em caso de erro
$response = $this->ai->read('Translate to French: Hello', function() {
return 'Fallback value';
});
// com opções
$response = $this->ai->read('Explain photosynthesis', null, [
'system' => 'You are a biology teacher.',
'temperature' => 0.3,
]);
5.3Método get()
O método get() ativa automaticamente o modo JSON: o LLM é instruído a responder com um JSON válido, e a resposta é automaticamente decodificada em um array PHP.
// solicitar dados estruturados
$data = $this->ai->get('List the 3 largest cities in France with their population');
// $data contém um array PHP, por exemplo:
// [
// ['city' => 'Paris', 'population' => 2161000],
// ['city' => 'Marseille', 'population' => 873076],
// ['city' => 'Lyon', 'population' => 522250],
// ]
// com opções
$recipe = $this->ai->get("Create a recipe using: eggs, tomatoes, cheese", null, [
'system' => "You are a chef. Return JSON with keys: title, difficulty (1-5), ingredients (list), steps (list).",
]);
6Opções
Os métodos read() e get() aceitam um terceiro parâmetro $options, um array associativo:
- system: (string) Prompt de sistema que define o comportamento do assistente.
- messages: (array) Histórico de mensagens anteriores para conversas com múltiplos turnos (veja abaixo).
- temperature: (float) Temperatura de amostragem, entre 0 e 2. Valores mais baixos tornam as respostas mais determinísticas; valores mais altos as tornam mais criativas.
- max_tokens: (int) Número máximo de tokens na resposta.
- attachments: (array) Anexos a serem enviados com o prompt (veja a próxima seção).
- output: (string) Formato de saída desejado. Pode ser um alias ('json', 'csv', 'audio', 'image', 'pdf', 'video', 'html', 'xml', 'wav') ou um tipo MIME completo ('application/json', 'audio/ogg', etc.).
Exemplo completo:
$response = $this->ai->read('Describe this image in detail', null, [
'system' => 'You are an image analysis expert.',
'temperature' => 0.5,
'max_tokens' => 1000,
'attachments' => ['/path/to/photo.jpg'],
]);
7Anexos
7.1Formatos aceitos
A opção attachments aceita um array de anexos. Cada elemento pode ser:
- Uma string: caminho de arquivo (se file_exists() retornar true) ou conteúdo binário. O tipo MIME é detectado automaticamente.
-
Um array associativo com as chaves:
- path: caminho do arquivo.
- data: conteúdo binário.
- mime: (opcional) tipo MIME explícito.
Exemplos:
// caminho de arquivo (MIME detectado automaticamente)
'attachments' => ['/path/to/photo.jpg']
// conteúdo binário (MIME detectado automaticamente)
'attachments' => [$binaryContent]
// binário com MIME explícito
'attachments' => [
['data' => $binaryContent, 'mime' => 'image/png'],
]
// caminho de arquivo com MIME explícito
'attachments' => [
['path' => '/path/to/document.pdf', 'mime' => 'application/pdf'],
]
// múltiplos anexos
'attachments' => [
'/path/to/image1.jpg',
['data' => $pdfContent, 'mime' => 'application/pdf'],
]
7.2Tipo MIME
Se o tipo MIME não for fornecido explicitamente, ele é detectado automaticamente via finfo. Quando você já tem o conteúdo binário em memória, é recomendável fornecer o tipo MIME explicitamente para evitar uma detecção desnecessária.
O suporte a anexos depende do provedor e do modelo utilizado (veja a tabela resumo acima). Se um tipo de anexo não for suportado pelo provedor, ele será ignorado.
8Saída JSON
Existem duas abordagens para obter JSON estruturado:
Método get(): ativa automaticamente o modo JSON. O LLM recebe uma instrução de sistema pedindo que responda com um JSON válido. A resposta é automaticamente decodificada em um array PHP.
$data = $this->ai->get('The 5 most popular programming languages');
// $data é um array PHP
Método read() com a opção output: permite solicitar JSON usando read(). A resposta permanece uma string JSON bruta (não decodificada).
$json = $this->ai->read('The 5 most popular programming languages', null, [
'output' => 'json',
]);
// $json é uma string JSON bruta
$data = json_decode($json, true);
9Conversa com múltiplos turnos
A opção messages permite fornecer o histórico das trocas anteriores. Cada mensagem é um array associativo com uma chave user ou ai:
$response = $this->ai->read('And the capital of Italy?', null, [
'system' => 'You are a geography assistant.',
'messages' => [
['user' => 'What is the capital of France?'],
['ai' => 'The capital of France is Paris.'],
],
]);
// $response contém "The capital of Italy is Rome."
As mensagens do histórico também podem conter anexos:
$response = $this->ai->read('And this one?', null, [
'messages' => [
['user' => 'Describe this image', 'attachments' => ['/path/to/photo1.jpg']],
['ai' => 'It is a ginger cat sitting on a sofa.'],
],
'attachments' => ['/path/to/photo2.jpg'],
]);