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 Usage Laravel Package

spaanproductions/laravel-ai-usage

A Laravel package for tracking AI model usage, token consumption, and costs across your application. It helps log requests from AI providers, monitor spending, and gain visibility into usage through a simple, configurable integration.

View on GitHub
Deep Wiki
Context7

Getting Started

The package records AI/LLM usage (tokens, cost, model, and related metadata) in an ai_usage_records table and stores budget thresholds/breaches in an ai_usage_budget_alerts. Day-to-day, it is the ledger you query when you need to answer "what did this feature/user/tenant cost us this month?"

Minimal setup:

  1. Install: composer require <vendor>/ai-usage (check the README for the exact vendor name).
  2. Publish config and migrations: php artisan vendor:publish --tag=ai-usage-migrations (plus whatever config tag the package exposes).
  3. Run php artisan migrate.
  4. Wrap your existing LLM call sites so each completion/embedding writes a usage row.

Where to look first:

  • The package config/ file — model/table names, cost per 1k tokens, and any default alert thresholds.
  • The published migrations — these define the columns you will be querying and grouping by.
  • The service provider — for the container binding you inject into your own services.

First use case: instrument one AI-backed controller action, confirm a row lands in ai_usage_records, then add a monthly budget alert. That small loop (record → query → alert) is the whole package in miniature.

Implementation Patterns

Centralise recording behind one service. Do not sprinkle the package's recorder across controllers. Instead create something like App\Services\AiUsageRecorder that your feature code calls, and let it handle user/tenant attribution, model naming, and error swallowing. This is the seam you will need when the package's API changes or you swap in a queue.

Attribute usage explicitly. Every record should carry a user_id, tenant_id, or a morphable subject. Retrofitting attribution later means backfilling rows you cannot reconstruct. Pass a Billable-style subject into the recorder rather than relying on auth()->id(), which breaks in jobs and artisan commands.

Record from a queued job, not the request path. Writing a row per LLM call is cheap, but wrapping it in a dispatch() keeps usage persistence failures from breaking a user-facing response, and it makes retries explicit. Give the job a tries = 3 and log a warning on final failure.

Query with aggregates, not row dumps. Day-to-day reporting should group by day and subject:

AiUsageRecord::query()
    ->where('created_at', '>=', now()->startOfMonth())
    ->selectRaw('subject_type, subject_id, SUM(total_tokens) as tokens, SUM(cost) as cost')
    ->groupBy('subject_type', 'subject_id')
    ->orderByDesc('cost')
    ->get();

Add a covering index on (subject_type, subject_id, created_at) in your own migration if the package's table lacks one — you will feel it at a few hundred thousand rows.

Wire budget alerts into existing notification channels. Let the package detect threshold breaches, then fan out through your own Notification classes (Slack, mail, or a users relation). Treat the alert record as an event source, not as the delivery mechanism.

Expose a read-only dashboard early. A simple Filament resource or Livewire table over ai_usage_records grouped by day is usually the first thing stakeholders ask for. Build it against the aggregate query above so it stays cheap.

Integration tips:

  • Tag every AI call with a logical feature or operation string at the call site; it makes later cost attribution possible without joining application tables.
  • In tests, use RefreshDatabase and assert on the recorder's record() call count rather than on row contents, so column changes do not break your suite.
  • If you operate multi-tenant, resolve the tenant key from an explicit parameter — never from the ambient request context inside queued jobs.

Gotchas and Tips

Migration publishing is now additive only. As of v0.1.6, vendor:publish --tag=ai-usage-migrations copies only new migration files. Previously every update re-published all migrations under a fresh timestamp, so migrate collided with already-existing tables (ai_usage_records, ai_usage_budget_alerts). If you followed the v0.1.4 upgrade note, check database/migrations/ for duplicated create_ai_usage_records_table and create_ai_usage_budget_alerts_table files, delete the ones that have not yet run, and then php artisan migrate. Leaving them in place is harmless until someone runs a fresh migration order that includes them.

Never hand-edit published migrations you have already shipped. The publishing behaviour assumes published files are committed and stable. If you need schema changes, add a new migration in your own database/migrations directory rather than modifying the package's.

migrate:fresh in CI will hide the duplicate problem. Local setups running migrate:fresh succeed on duplicate creation migrations; production does not. Run php artisan migrate --pretend against a production-shaped schema before deploying an upgrade.

Config cache. After composer update, run php artisan config:cache (or config:clear in dev). Stale cached config is the most common cause of "my threshold changes did nothing."

Cost drift. If the package computes cost from a bundled price table, model prices will lag reality. Override the pricing map in your published config and treat the package's numbers as a starting point; reconcile against the provider's billing export monthly.

Token counts are estimates. Provider SDKs sometimes report different usage than the package captures (streaming responses are a frequent gap). Do not bill customers directly off these rows without a reconciliation step.

Extension points. The package's recorder and alert evaluator are typically resolvable from the container — rebind them in a service provider to add custom fields (e.g. request_id, prompt_version) or to change alert routing. Rebinding is preferable to forking, because it survives composer update.

Debugging checklist. Missing row? Check the queue worker is running, then that the recorder is injected (not new'd), then the config's table name. Wrong totals? Check timezone handling on created_at and whether any records are soft-deleted. Alerts not firing? Confirm the evaluator runs on a schedule and that the alert threshold is expressed in the same unit as the stored cost.

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.
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox