halilcosdu/laravel-chatbot 问题修复 & 功能扩展

解决BUG、新增功能、兼容多环境部署,快速响应你的开发需求

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

halilcosdu/laravel-chatbot

Composer 安装命令:

composer require halilcosdu/laravel-chatbot

包简介

A Laravel-native OpenAI chatbot powered by the Responses and Conversations APIs.

README 文档

README

Latest Version on Packagist Total Downloads License

A Laravel-native, stateful chatbot built on OpenAI's Responses and Conversations APIs. It manages the remote conversation, keeps a local Eloquent transcript, scopes threads to your users, and supports both synchronous and streamed responses through one facade.

Version 2.x does not use the deprecated Assistants API. If you are upgrading from 1.x, read the upgrade guide and migrate before the Assistants API shuts down on August 26, 2026.

What you get

  • Responses + Conversations API integration through openai-php/laravel.
  • Local Thread and ThreadMessage models with configurable model classes.
  • Create, continue, search, paginate, inspect, and delete conversations.
  • Single-use text streams for both new and existing threads.
  • Automatic transcript persistence after a response completes successfully.
  • Per-request Responses API options without allowing callers to replace managed input or conversation state.
  • Optional owner scoping for multi-user applications.
  • Raw Conversation and Response methods when you need the underlying SDK objects.
  • An idempotent command for migrating 1.x Assistants threads from their local transcript.

Compatibility

Laravel Supported PHP versions Testbench
11.x (11.29+, legacy) 8.2, 8.3, 8.4 9.x
12.x (12.12+) 8.2, 8.3, 8.4, 8.5 10.x
13.x 8.3, 8.4, 8.5 11.x

The CI matrix tests every compatible combination above with both lowest and stable dependency sets. Laravel 11 reached upstream security end-of-life on March 12, 2026. Version 2.1 retains Laravel 11 runtime compatibility for migrations, but production applications should upgrade to Laravel 12 or 13. The Laravel 11 CI jobs use Composer's --no-blocking option solely to resolve that end-of-life framework; the package does not weaken a consuming application's Composer security policy.

Laravel 11 is not listed with PHP 8.5 because Laravel's support policy ends its PHP range at 8.4; use Laravel 12 or 13 when deploying on PHP 8.5.

Additional requirements:

  • openai-php/laravel ^0.20
  • An OpenAI API key
  • A database supported by your Laravel version

Installation

Install the package with Composer:

composer require halilcosdu/laravel-chatbot

Publish its configuration and migrations, then migrate:

php artisan vendor:publish --tag=chatbot-config
php artisan vendor:publish --tag=chatbot-migrations
php artisan migrate

Laravel discovers the service provider and ChatBot facade automatically.

Environment

At minimum, configure your API key:

OPENAI_API_KEY=sk-...
OPENAI_MODEL=gpt-5.4-mini
OPENAI_TIMEOUT=30

Optional values:

OPENAI_INSTRUCTIONS="You are a concise support assistant."
OPENAI_ORGANIZATION=
OPENAI_PROJECT=

OPENAI_PROMPT_ID remains available for applications already using reusable prompt objects. OpenAI's deprecation schedule says reusable prompts will shut down on November 30, 2026, so new integrations should keep instructions in application configuration instead.

Configuration

The published config/chatbot.php contains:

use HalilCosdu\ChatBot\Models\Thread;
use HalilCosdu\ChatBot\Models\ThreadMessage;

return [
    'model' => env('OPENAI_MODEL', 'gpt-5.4-mini'),
    'instructions' => env('OPENAI_INSTRUCTIONS'),
    'prompt_id' => env('OPENAI_PROMPT_ID'),

    'api_key' => env('OPENAI_API_KEY'),
    'organization' => env('OPENAI_ORGANIZATION'),
    'project' => env('OPENAI_PROJECT'),
    'request_timeout' => (int) env('OPENAI_TIMEOUT', 30),

    'response_options' => [],

    'models' => [
        'thread' => env('CHATBOT_THREAD_MODEL', Thread::class),
        'thread_messages' => env('CHATBOT_THREAD_MESSAGE_MODEL', ThreadMessage::class),
    ],
];

Put options shared by every managed response in response_options:

'response_options' => [
    'max_output_tokens' => 1200,
    'reasoning' => ['effort' => 'low'],
],

The package always supplies input and conversation, and it chooses streaming internally. Those keys cannot be replaced through managed thread methods.

The chatbot client is container-isolated from openai-php/laravel's application-level ClientContract. Your application's own OpenAI binding and config/openai.php can therefore coexist without replacing the credentials or timeout used by this package.

Quick start

use HalilCosdu\ChatBot\Facades\ChatBot;

$thread = ChatBot::createThread(
    'Explain why the sky is blue.',
    ownerId: auth()->id(),
);

$assistantMessage = ChatBot::updateThread(
    'Why does it turn red at sunset?',
    id: $thread->getKey(),
    ownerId: auth()->id(),
);

echo $assistantMessage->content;

The package creates one remote Conversation and stores the user and assistant messages locally. Later calls reuse the remote conversation ID so OpenAI retains the conversation state.

Managed API

Method Result Purpose
createThread($subject, $ownerId, $options) Eloquent thread Create a conversation and wait for the first answer.
createThreadStreamed($subject, $ownerId, $options) StreamedThreadResponse Create a conversation and iterate its first answer as text deltas.
updateThread($message, $id, $ownerId, $options) Eloquent message Continue a conversation and wait for the answer.
updateThreadStreamed($message, $id, $ownerId, $options) StreamedThreadResponse Continue a conversation and iterate text deltas.
listThreads($ownerId, $search, $appends) paginator List newest threads, optionally scoped and searched.
thread($id, $ownerId) Eloquent thread Retrieve a thread with its messages.
deleteThread($id, $ownerId) void Delete the remote Conversation and local thread.

Per-request options

The final $options argument is merged over response_options. It is useful for changing a model, token budget, reasoning effort, metadata, or supported tools for one request:

$message = ChatBot::updateThread(
    message: 'Give me the short version.',
    id: $thread->getKey(),
    ownerId: auth()->id(),
    options: [
        'model' => 'gpt-5.4-mini',
        'max_output_tokens' => 300,
        'reasoning' => ['effort' => 'low'],
        'metadata' => ['feature' => 'support-chat'],
    ],
);

Passing a model explicitly bypasses a configured prompt_id. Passing a prompt uses that prompt and omits model and instructions, matching the package's existing prompt behavior.

Streaming responses

Streaming uses the Responses API's semantic events internally and exposes only text deltas. The returned object also gives you the local thread immediately:

$stream = ChatBot::createThreadStreamed(
    'Write a short welcome message.',
    ownerId: auth()->id(),
);

$threadId = $stream->thread->getKey();

foreach ($stream as $delta) {
    echo $delta;
}

// Available only after the stream has completed.
$savedMessage = $stream->assistantMessage();
$completed = $stream->completed();

StreamedThreadResponse is intentionally single-use. A successful terminal response.completed event is required before the package stores the assistant message. If the stream fails, ends early, or the consumer disconnects, the user message remains in the local transcript but no incomplete assistant message is invented.

Laravel streamed HTTP response

use HalilCosdu\ChatBot\Facades\ChatBot;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;

Route::post('/chat', function (Request $request) {
    $stream = ChatBot::createThreadStreamed(
        subject: $request->string('message')->toString(),
        ownerId: $request->user()->getAuthIdentifier(),
    );

    return response()->stream(function () use ($stream): void {
        foreach ($stream as $delta) {
            echo $delta;

            if (ob_get_level() > 0) {
                ob_flush();
            }

            flush();
        }
    }, 200, [
        'Cache-Control' => 'no-cache, no-transform',
        'Content-Type' => 'text/plain; charset=utf-8',
        'X-Accel-Buffering' => 'no',
        'X-Chatbot-Thread' => (string) $stream->thread->getKey(),
    ]);
});

Reverse proxies may buffer output even when PHP flushes it. Disable buffering for this endpoint in your web server or proxy configuration. Streaming partial output also makes moderation harder than moderating a completed answer; account for that in production applications.

Listing and owner isolation

$threads = ChatBot::listThreads(
    ownerId: auth()->id(),
    search: 'invoice',
    appends: request()->query(),
);

$thread = ChatBot::thread($id, ownerId: auth()->id());
ChatBot::deleteThread($id, ownerId: auth()->id());

Pass the authenticated owner's ID to every read, update, stream, and delete call. The package applies the owner condition in the database query, including valid IDs such as 0; a mismatched owner receives Laravel's normal ModelNotFoundException.

Local data and custom models

threads stores the owner, short subject, and remote Conversation ID. thread_messages stores the ordered local transcript and is deleted with its parent thread.

To add casts, relationships, or tenant behavior, extend the package models:

namespace App\Models;

use HalilCosdu\ChatBot\Models\Thread as BaseThread;

class ChatThread extends BaseThread
{
    protected $table = 'threads';
}

Then configure the class:

CHATBOT_THREAD_MODEL="App\Models\ChatThread"
CHATBOT_THREAD_MESSAGE_MODEL="App\Models\ChatThreadMessage"

Custom classes must be Eloquent models. Extending the package models is recommended so their relationship methods and bundled factories remain available. The package always uses the stable thread_id foreign key, even when your custom class has a different name.

Raw OpenAI access

Raw methods return the SDK's typed response objects and do not write local models:

ChatBot::createConversationAsRaw(['metadata' => ['tenant' => 'acme']]);
ChatBot::conversationAsRaw($conversationId);
ChatBot::updateConversationAsRaw($conversationId, ['metadata' => ['state' => 'active']]);
ChatBot::listConversationItemsAsRaw($conversationId, ['limit' => 20]);
ChatBot::deleteConversationAsRaw($conversationId);

ChatBot::createResponseAsRaw([
    'model' => 'gpt-5.4-mini',
    'input' => 'Hello',
]);

$events = ChatBot::createResponseStreamedAsRaw([
    'model' => 'gpt-5.4-mini',
    'input' => 'Hello',
]);

foreach ($events as $event) {
    // Inspect $event->event and the typed $event->response payload.
}

ChatBot::responseAsRaw($responseId);

Use the managed methods when you want conversation continuity and local persistence. Use the raw methods when you need API features that the managed text workflow does not interpret.

Migrating from 1.x

Version 1.x used Assistants threads (thread_*); version 2.x uses Conversations (conv_*). These IDs are not interchangeable.

After publishing and running the 2.x migrations, inspect and migrate your local transcripts:

php artisan chatbot:migrate-to-conversations --dry-run
php artisan chatbot:migrate-to-conversations

Useful options:

php artisan chatbot:migrate-to-conversations --limit=100

The command:

  • selects only threads without remote_conversation_id;
  • reconstructs user messages as input_text and assistant messages as output_text;
  • skips empty transcripts;
  • continues after individual API failures and returns a failing exit code if any fail;
  • is idempotent, so it can be run again safely.

See UPGRADE.md for the complete 1.x to 2.x migration guide.

Error handling

Managed responses throw HalilCosdu\ChatBot\Exceptions\ChatBotException when OpenAI returns a failed or incomplete response, produces no text, or ends a stream without a completion event.

use HalilCosdu\ChatBot\Exceptions\ChatBotException;

try {
    $message = ChatBot::updateThread('Hello', $threadId, auth()->id());
} catch (ChatBotException $exception) {
    report($exception);

    return back()->withErrors(['chat' => 'The assistant could not complete its response.']);
}

Transport and authentication errors from the underlying SDK are not hidden. Laravel's ModelNotFoundException is also preserved for missing or incorrectly scoped threads.

Testing and quality

Run the complete local quality gate:

composer test-all

Or run checks independently:

composer test
composer analyse
composer format-test
composer test-coverage

The GitHub compatibility workflow covers PHP 8.2 through 8.5 across Laravel 11, 12, and 13 using each framework's supported PHP range.

Security

Please do not publish API keys, prompts containing secrets, or sensitive transcript data in issues. Report vulnerabilities privately using the process in SECURITY.md.

Changelog

See CHANGELOG.md for release history.

Credits

License

Laravel Chatbot is open-sourced software licensed under the MIT license.

halilcosdu/laravel-chatbot 适用场景与选型建议

halilcosdu/laravel-chatbot 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 5.75k 次下载、GitHub Stars 达 65, 最近一次更新时间为 2024 年 04 月 17 日, 在 PHP 生态内属于活跃度较高的组件。

它主要适用于以下技术方向: 「laravel」 「ai」 「chatbot」 「openai」 「laravel-chatbot」 「responses-api」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。

我们在过去多个企业项目中使用过 halilcosdu/laravel-chatbot 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 halilcosdu/laravel-chatbot 我们能提供哪些服务?
定制开发 / 二次开发

基于 halilcosdu/laravel-chatbot 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 5.75k
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 65
  • 点击次数: 25
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 65
  • Watchers: 2
  • Forks: 6
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2024-04-17