Deploying an AI agent is not the same as releasing application code. Models, prompts, and agent orchestration change behavior in ways that tests and traditional deployments don't always catch. This article lays out practical patterns for CI/CD for AI agents in Laravel: how to pin models and prompt artifacts for reproducibility, run safe canary rollouts for new models or prompt changes, and build automated regression tests that catch behavioral drift before users notice.
Why CI/CD for AI agents needs its own rules
When you change code, standard unit and integration tests often tell you whether you broke functionality. When you change a model, a tiny prompt tweak, or the way your agent chains tools, failures can be semantic — subtle correctness errors, hallucinations, or degraded user experience. The CI/CD surface expands to include:
- Model versions and provider metadata (not just package versions).
- Prompt templates and prompt component versions used by agents.
- Agent orchestration logic and tool-access rules (RBAC, rate limits).
Treat these artifacts as first-class deployment inputs so rollbacks are straightforward and replicable.
Model pinning: make each release reproducible
Model pinning means recording exactly which model (provider and model id) an agent used at release time. Pinning prevents a later provider-side model update from silently changing behavior in production.
Where to pin
- Per agent: pin the default model used by that agent.
- Per prompt template: if you maintain versions of prompt components, record which prompt version pairs with which model.
- Per environment: test and production pinning should be separate so experiments don't leak into prod.
How to store pins
Use a simple, auditable store:
- Source control for prompt templates and prompt metadata (commit hash + semantic version).
- A database table for runtime pins (agent_id, provider, model_name, model_version, pinned_at, release_tag). This makes reads fast at runtime and lets you change pins via migrations or release scripts.
- Environment variables for global fallbacks (only for emergency overrides).
Practical Laravel pattern
Create a small Eloquent model (AgentModelPin) that the agent resolver consults at runtime. Resolve the effective model by checking, in order: agent-specific pin → prompt-template pin → environment fallback. This keeps behaviour explicit and traceable in logs.
// pseudo-code example
$pin = AgentModelPin::where('agent', $agent)->latest()->first();
$effectiveModel = $pin ? $pin->model_identifier : config('ai.default_model');
$agent->setModel($effectiveModel);Record the pin's release_tag or git commit in the same row; that makes reproducing a request's context straightforward during debugging.
Safe rollouts and canary release LLM patterns
Full-traffic switches are risky. Canary release LLM deployments let you validate a new model or prompt change on a subset of traffic before promoting it.
Deterministic bucketing for canaries
Assign each request or user to a stable bucket so an individual sees consistent behavior. A simple hash-based bucket is robust and easy to implement:
// pseudocode
$bucket = crc32($userId) % 100; // value 0..99
if ($bucket < $canaryPercentage) {
useModel('new-model-id');
} else {
useModel('pinned-stable-model');
}This guarantees the same user consistently sees the canary model and avoids flapping.
What to measure during the canary
- API error rate and latency.
- Simple correctness signals (structured-field presence, classification labels matching gold data).
- Domain-specific heuristics (e.g., code generation compile success, number of follow-up clarifying questions generated).
- User experience metrics: NPS, task success, or conversion events tied to agent outcomes.
Automate short-running checks in CI and longer-running signal collection in production monitoring. If any critical metric regresses beyond thresholds, remove the canary automatically or alert on-call engineers.
Promotion and rollback mechanics
Promotion should be a controlled operation: update the model pin for the agent (or the rollout percentage), tag the deployment, and run post-promotion checks. Rollback should be equally simple — reapply the previous pin or set rollout back to 0% — and ideally executable by an automated job triggered by failed metrics.
Automated regression tests for agents
Automated regression tests for agents catch behavioral regressions early. Tests should cover the agent's business expectations, not just raw token outputs.
Test types and where they belong in CI
- Unit tests: validate prompt assembly, function wiring, and small deterministic logic (no external calls).
- Mocked integration tests: run agent flows with the LLM client mocked to return canned responses so you can assert orchestration and error paths quickly in CI.
- Golden (regression) tests: run the agent against a curated dataset of inputs and assert structured outputs or scoring thresholds against saved expected results. These can run in CI against a pinned test model or against a mock that returns recorded real responses.
- Smoke tests in staging: small set of end-to-end scenarios executed on staging with the exact model pin intended for production canaries.
Golden file strategy and tolerances
Store golden outputs (structured JSON) alongside tests. Compare agent outputs using structured assertions rather than token-level equality. For example, if an agent returns a JSON with a "summary" field, assert the summary length, presence of key facts, and that a small set of important entities appear — not exact wording.
Example PHPUnit-style regression test
public function test_agent_returns_expected_invoice_fields()
{
$input = file_get_contents(__DIR__ . '/fixtures/invoice_prompt.json');
$expected = json_decode(file_get_contents(__DIR__ . '/fixtures/invoice_expected.json'), true);
// Run the agent using a pinned test model or a mocked LLM client
$result = $this->agentService->run($input, ['model' => 'test-pinned-model']);
$this->assertArrayHasKey('amount_due', $result);
$this->assertEquals($expected['currency'], $result['currency']);
$this->assertTrue(strpos($result['summary'], $expected['key_phrase']) !== false);
}Keep golden fixtures small and focused so tests remain fast and informative.
Putting it together: a pragmatic CI flow for Laravel
A CI pipeline for AI agents should combine code and artifact checks. A minimal practical flow:
- Code build and static checks (lint, composer audit).
- Unit tests and prompt-template validation (lint prompt components and verify template versions).
- Mocked integration tests (fast, run on every push).
- Regression suite (golden tests) — run on pull requests and nightly for main branch.
- Deploy to staging with pinned staging model; run staging smoke tests.
- Deploy to production with a canary rollout of the pinned model; monitor metrics for a predefined window.
- Promote or rollback based on automated checks and alerts.
Where possible, keep the model pin in source control or as part of the deployment artifact so the same commit that changes code also records the model/prompt state.
Monitoring, alerts, and automated rollback
Testing catches many failures, but observability catches production regressions. Track both technical and semantic signals:
- Technical: latency, error rate, provider-side 429/5xx counts.
- Semantic: task completion rate, extraction accuracy, confidence scores if the model provides them.
- Behavioral: escalation rate to human agents, unexpected increases in follow-ups.
Automate a decision threshold: if key metrics exceed tolerances within the canary window, trigger an automated rollback that resets the pin or reduces rollout percentage and notify the on-call team with the deployment tag and the failing metric snapshot.
Checklist before promoting a canary to full production
- All CI tests (unit, mocked integration, golden regression) passed for the release commit.
- Staging smoke tests passed against the pinned staging model.
- Canary metrics stayed within thresholds for the monitoring window.
- Runbook prepared with rollback steps and contact points.
- Audit records: model pin, prompt commit, rollout tag stored with the release.
Next steps you can do today
- Start by adding a simple AgentModelPin table and a resolver in Laravel so every request logs the effective model.
- Create three golden regression fixtures that capture the agent's most important behaviors and add them to your CI golden suite.
- Implement deterministic bucketing for a 1–5% canary and wire a dashboard to the key semantic metrics so the first rollout is observable.
For teams building reusable prompt components, the patterns in Building Reusable Prompt Components in Laravel pair naturally with model pinning. If you need evaluation frameworks for your golden tests, see A Practical Testing and Evaluation Framework for LLM-Powered Features for ideas on structured test datasets and scoring.
Make models and prompts first-class artifacts in your release process: when they are explicit, rollbacks are quick and behavior is reproducible.
Frequently Asked Questions
What is model pinning and why is it necessary?
Model pinning records the exact provider and model identifier used by an agent at release time. It prevents silent behavior changes when providers update models or defaults, and makes rollbacks and reproductions simple.
How do I run a canary release for a new LLM without a feature flag service?
Use deterministic bucketing based on a stable user or request identifier (e.g., crc32(userId) % 100). Route a configured percentage of buckets to the canary model and keep the rest on the pinned stable model. This approach requires no external feature-flag service and gives consistent user experience.
What should automated regression tests for agents assert?
Prefer structured assertions: presence of required fields, entity extraction accuracy, classification labels, and tolerance-based checks on text fields (length, presence of key phrases). Avoid token-level equality; rely on golden files and scoring thresholds for semantic checks.
Can I run golden regression tests in CI without calling the live API?
Yes. Use recorded responses (cassettes) or mocked LLM clients in CI to compare runtime output against stored golden fixtures. For final validation, run a smaller smoke suite against a pinned staging model to validate provider behavior.