Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Ai Attributes Laravel Package

parselynk/laravel-ai-attributes

Bring AI-ready metadata to your Laravel code with native PHP attributes. Annotate classes and methods to describe their intent and expose structured hints for AI agents, tools, and LLM integrations—declarative, discoverable, and colocated with your code.

View on GitHub
Deep Wiki
Context7

Getting Started

  1. Install the package and its new foundation:
composer require parselynk/laravel-ai-attributes:^2.0

This pulls in laravel/ai automatically. Confirm you have the required runtime: PHP 8.3+, Laravel 12.62+ or 13.x. Laravel 11 is no longer supported.

  1. Configure the default provider through laravel/ai’s config file, not the old package config:
php artisan vendor:publish --provider="Laravel\AI\AIServiceProvider"

Set your provider and credentials in .env:

AI_ATTRIBUTES_PROVIDER=openai
OPENAI_API_KEY=sk-...
  1. Add the trait and declare the attributes you want on an Eloquent model:
use Parselynk\AiAttributes\Traits\HasAIAttributes;

class Article extends Model
{
    use HasAIAttributes;

    protected array $aiAttributes = [
        'ai_summary' => [
            'provider' => 'openai',
            'prompt' => 'Summarize this article in two sentences.',
            'format' => 'text',
        ],
    ];
}
  1. Use the generated attribute like any normal model property:
$article = Article::find(1);

echo $article->ai_summary;

The first access generates and persists the value. Subsequent accesses for the same content hash return the cached result.

Where to look first: start with the package README for $aiAttributes examples, then inspect laravel/ai’s config/ai.php for provider/model defaults. The first practical use case is summarising or classifying existing Eloquent content without writing custom prompt plumbing.

Implementation Patterns

Declarative model attributes

Keep AI-generated fields beside the model they belong to. The package’s main value is that $article->ai_summary, $product->ai_category, and $ticket->ai_sentiment behave like normal Eloquent attributes:

protected array $aiAttributes = [
    'ai_summary' => [
        'provider' => 'anthropic',
        'prompt' => 'Summarize the following article for a technical audience.',
        'format' => 'text',
    ],
    'ai_tags' => [
        'provider' => 'openai',
        'prompt' => 'Return 5 short tags for this article as JSON.',
        'format' => 'json',
    ],
    'ai_is_actionable' => [
        'provider' => 'openai',
        'prompt' => 'Is this support ticket actionable? Answer true or false.',
        'format' => 'bool',
    ],
];

Formats handle casting automatically:

  • text returns a string.
  • json returns a decoded array/object.
  • number returns a numeric value.
  • bool returns a boolean.

This lets you use the values directly in Blade, API resources, filters, and validation without extra decoding code.

Synchronous access for simple, fast attributes

Direct property access is best for short prompts and low-latency use cases:

$summary = $article->ai_summary;
$tags = $article->ai_tags; // already an array

Because generation happens on first access, avoid using this inside large collection loops unless you intentionally want to generate for every model. For existing records, consider an explicit backfill or regeneration pass.

Queued generation for expensive prompts

For longer content, batch jobs, or user-facing requests where latency matters, use the queued job:

use Parselynk\AiAttributes\Jobs\GenerateAiAttributeJob;

GenerateAiAttributeJob::dispatch($article, 'ai_summary');

This is the safer default for production workflows. Generate asynchronously, then expose only populated attributes. A common pattern is to dispatch the job after model creation/update and display the attribute only once it exists.

Peek before you trigger

Use the peek helpers when you need to avoid accidental generation:

if ($article->hasAiAttribute('ai_summary')) {
    echo $article->ai_summary;
}

$summary = $article->aiAttributeOrNull('ai_summary');

This is especially useful in API resources and Blade views, where merely accessing $article->ai_summary would otherwise trigger a remote call.

Runtime persona overrides

Personas are useful when the same model field needs different tone or audience in different contexts:

$marketingSummary = $article->aiPersona('marketing')->ai_summary;
$technicalSummary = $article->aiPersona('technical')->ai_summary;

Treat personas as an extension point for context-specific generation rather than hard-coding multiple near-identical attributes. Be explicit about whether the persona affects cache identity; if the same content and attribute produce different outputs under different personas, validate that the generated values are stored/cached as expected in your workflow.

Artisan regeneration

When prompts or upstream content change, use the command to regenerate:

php artisan ai:regenerate

Check the command’s options in the package for targeting models or attributes. In day-to-day work, this is the tool for backfills and for recovering from stale generated values after a prompt change.

Testing with laravel/ai fakes

Because the package delegates provider calls to laravel/ai, tests should use AnonymousAgent::fake():

use Laravel\AI\AnonymousAgent;

AnonymousAgent::fake([
    'summary response',
]);

$article->ai_summary; // returns faked response

Assert that your code reads the attribute correctly, handles cached values, and dispatches queued jobs. Avoid testing provider-specific HTTP details; that coverage now belongs to laravel/ai.

Gotchas and Tips

v2.0.0 is a breaking release

This version is a rebase onto laravel/ai, not a drop-in patch. Upgrade work includes:

  • Laravel 11 support dropped. Move to Laravel 12.62+ or 13.x and PHP 8.3+.
  • Provider config moved. Use config/ai.php published by laravel/ai, not config/ai-attributes.php.
  • Rename driver to provider in every $aiAttributes definition.
  • Remove max_tokens and temperature from attribute definitions. Those concerns now belong to laravel/ai.
  • Set the default provider via AI_ATTRIBUTES_PROVIDER in .env.

Do a project-wide search for driver, max_tokens, temperature, and ai-attributes.php before upgrading.

Accessing an attribute can make a network call

The magic property is convenient, but it is not lazy in the “cheap” sense. If the attribute has not been generated or cached, $article->ai_summary will trigger generation. In Blade loops, API resources, and serialization, prefer:

$article->aiAttributeOrNull('ai_summary')

or check hasAiAttribute() first. This avoids surprising latency and cost.

Content-hash caching is your friend — and a debugging variable

Same input should mean free repeat calls. That is excellent for cost control, but it also means prompt or model changes may not invalidate cached values unless part of the hashed input changes. When changing prompts or personas, explicitly regenerate the affected attributes with ai:regenerate or a targeted job dispatch.

Queued generation changes your UX contract

If you dispatch GenerateAiAttributeJob, the attribute may not exist immediately after the request. Design your UI and API around that:

  • Show a pending state.
  • Hide the attribute with aiAttributeOrNull() until generated.
  • Poll or refresh after the job completes.
  • Use broadcasting or a simple “refresh” flow for longer jobs.

Do not assume an attribute is populated just because a record was saved.

Format casting expectations

json format gives you decoded values, but the model may still return malformed JSON depending on the prompt. Keep prompts explicit about output shape. For bool and number, validate that provider responses match expectations in your own application tests, since the package cannot guarantee model output.

Use provider defaults deliberately

The package now supports all providers available through laravel/ai, including OpenAI, Anthropic, Gemini, Groq, Mistral, DeepSeek, xAI, Ollama, Azure OpenAI, Cohere, OpenRouter, Jina, VoyageAI, and ElevenLabs. You can set a global default with AI_ATTRIBUTES_PROVIDER, but per-attribute provider overrides are useful when one attribute needs a cheaper/faster model and another needs higher quality.

Extension points

The practical extension points are the $aiAttributes definitions, runtime personas, queued jobs, and the ai:regenerate command. If you need custom provider behaviour, configure it through laravel/ai rather than expecting the old package-level driver system. The old AIManager, AIDriver contract, and HttpRetrier are gone.

Debugging checklist

When an attribute is not behaving as expected:

  1. Confirm the attribute is listed in $aiAttributes.
  2. Confirm you renamed driver to provider.
  3. Confirm config/ai.php has valid provider credentials.
  4. Check whether the value is already cached by using hasAiAttribute().
  5. If using queues, confirm the job ran and the queue worker is processing the right connection.
  6. For stale output, regenerate explicitly rather than assuming a prompt change invalidates the cache.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core