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

Llm Chain Bundle Laravel Package

php-llm/llm-chain-bundle

php-llm/llm-chain-bundle helps PHP developers compose LLM workflows as reusable, maintainable chains. Connect prompts, tools, and model calls through a fluent API to build multi-step AI pipelines with less boilerplate and clearer orchestration.

View on GitHub
Deep Wiki
Context7

Getting Started

Read the rebrand notice first. In 0.25.0 the php-llm/llm-chain-bundle package is being rebranded to Symfony AI (symfony/ai-bundle, with the core library moving from php-llm/llm-chain to symfony/ai). This is the single most important thing to understand before you write any code.

For a Laravel app, do not install the Symfony bundle. The bundle targets Symfony's bundle/kernel lifecycle. What you actually want is the framework-agnostic core package:

# 0.25.0 and later — use the framework-agnostic core, NOT the -bundle
composer require symfony/ai

# Pre-0.25.0 equivalent (still on Packagist for now)
# composer require php-llm/llm-chain

If you are upgrading from an older php-llm/llm-chain install, pin the version in composer.json carefully — the package/namespace rename means an unconstrained ^0.x can silently pull in a namespace you haven't updated imports for yet.

Where to look first:

  • The core Platform / Chain / Message classes — these are the primitives.
  • The tool/function-calling interface (ToolInterface, ToolInput, ToolOutput) — this is where the 0.25.0 serializer change matters.
  • The model.options array — this is how you pass provider-specific settings.

First use case. A chat completion or a tool-calling agent behind a Laravel route or artisan command:

use Symfony\AI\Platform\PlatformInterface;

Route::post('/chat', function (PlatformInterface $platform) {
    $response = $platform
        ->getModel('gpt-4o-mini')
        ->invoke('Summarise this ticket: ...', [
            'temperature' => 0.2,
            'response_format' => ['type' => 'json_object'],
        ]);

    return response()->json($response->getContent());
});

Implementation Patterns

Register the platform/chain as a singleton in a service provider. Since you're not using the Symfony bundle, the container wiring is on you:

// AppServiceProvider::register()
$this->app->singleton(PlatformInterface::class, function ($app) {
    return new Platform(
        new OpenAiPlatform($app['config']->get('services.openai.key'))
    );
});

Then inject PlatformInterface (or a Chain) anywhere — controllers, jobs, commands, services.

Compose chains, don't hardcode models. Treat the model name and options as config, not literals:

$chain = new Chain([
    new Model('gpt-4o-mini'),
    new SystemPrompt('You are a support triage assistant.'),
]);

This keeps it swappable per-environment and trivially fake-able in tests.

Lean on model.options for provider-specific config. The 0.25.0 fix (PR #103) allows array arguments in model.options. Before this, nested arrays (e.g. tools, response_format, provider-specific extra_body blobs) could be mishandled. If you're on 0.24.0 and fighting with nested options, upgrade:

->invoke($prompt, [
    'tools' => [
        ['type' => 'function', 'function' => ['name' => 'lookup_order', 'parameters' => []]],
    ],
    'response_format' => ['type' => 'json_object'],
]);

Wire a serializer for tools. PR #104 makes tool input and output use an autowired serializer. In Laravel, bind Symfony's SerializerInterface (or whatever the tool layer expects) so tool arguments deserialize into DTOs and results serialize back to JSON:

$this->app->singleton(SerializerInterface::class, function () {
    return new Serializer([
        new ObjectNormalizer(),
        new JsonEncoder(),
    ], [new JsonEncoder()]);
});

If you skip this, your structured tool outputs may arrive as raw strings or throw during deserialization.

Queue long-running agent loops. Tool-calling chains can involve multiple round-trips; don't do them inside a web request. Dispatch a job, keep the conversation/state serializable, and stream or poll results.

Feature-test the chain, not the network. Inject a fake Chain/Platform in tests that returns canned Message objects. The model.options array fix means you can assert that options pass through correctly.

Gotchas and Tips

The 0.25.0 rebrand is a hard breaking change. Namespaces change (PhpLlm\... → Symfony\AI\...), package names change, and any use statements referencing the old namespaces will fatal. Do the rename as a dedicated PR, not bundled with feature work. Search-and-replace php-llm and PhpLlm before upgrading.

Don't try to use the Symfony bundle in Laravel. llm-chain-bundle (now symfony/ai-bundle) expects a Symfony kernel and bundle registration. There is no Laravel service provider shipped with it. Use the core library and wire it yourself, or check whether a community Laravel bridge has caught up to 0.25.0.

The "autowired serializer" change (PR #104) assumes a DI container that autowires SerializerInterface. Laravel's container can autowire interfaces, but only if you bind them explicitly — it won't magically provide Symfony's serializer. If tool I/O works in Symfony but not in your Laravel app after upgrading, this is why.

model.options array fix is worth the upgrade alone if you use tools or structured output. Before 0.25.0, passing arrays as values could be dropped or flattened depending on provider. Verify with a test that asserts the options reach the provider (log the outgoing payload).

Watch the Composer constraint on any transitive packages. Because the entire php-llm org is rebranding, a mix of old (php-llm/*) and new (symfony/ai-*) packages in one composer.json can produce class-not-found errors at runtime rather than install time. Run composer why <package> to audit.

Debugging tips. Log the raw provider response ($response->getRaw() or equivalent) before you try to parse it — most "parser" issues are actually provider errors. Enable provider-level debug options via model.options rather than editing library internals. Use Laravel's Http facade fake in tests only if you're going through the HTTP client; if the library uses its own client, fake at the Platform level instead.

Extension points. The chain is ChainStepInterface-driven — implement your own steps (a prompt template step, a guardrail step, a logging step) rather than subclassing the Chain. For providers, implement the platform interface and register it as a singleton. For tools, implement the tool interface and register in a container collection so the autowired serializer can resolve arguments.

Versioning note. This is still 0.x — treat every minor bump as potentially breaking. Pin exact versions ("symfony/ai": "0.25.*") and review each changelog; the org rebrand confirms the maintainers are not using semver-stable guarantees yet.

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.
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle