首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >AI编程0X02〡PHP 异步非阻塞 AI 客户端

AI编程0X02〡PHP 异步非阻塞 AI 客户端

作者头像
Tinywan
发布2025-09-11 19:26:32
发布2025-09-11 19:26:32
11300
代码可运行
举报
文章被收录于专栏:开源技术小栈开源技术小栈
运行总次数:0
代码可运行

上一章节:AI编程0X01〡调用 API 完成内容分类

通过简单curl请求调用通义千问 API,完成用户反馈的自动分类任务。本章节使用异步非阻塞 webman/openai 客户端完成用户反馈的自动分类任务。

webman/openai是一个异步非阻塞的openai客户端,配合webman可以做到同一时刻支持上万并发调用,使用简单,返回如丝般的顺滑。

传统php-fpm架构调用openai等大模型接口时只能做到阻塞调用,由于大模型接口返回速度很慢,一个php-fpm进程一分钟只能调用几次,几个人一刷系统就会明显的卡顿甚至不可用状态。

所以传统php-fpm不适合做大模型调用,而webman这类的常驻内存类型的框架非常适合大模型应用的开发。

入门使用

安装

代码语言:javascript
代码运行次数:0
运行
复制
composer require webman/openai

https://www.workerman.net/plugin/157

流式返回

代码语言:javascript
代码运行次数:0
运行
复制
<?php

declare(strict_types=1);

namespace app\home\v1\controller;

usesupport\Request;
usesupport\Response;
useWebman\Openai\Chat;
useWorkerman\Protocols\Http\Chunk;

class ChatController
{
    publicfunction completions(Request $request): Response
    {
        $connection = $request->connection;
        $chat = new Chat([
            'apikey' => 'sk-xxxxxxxxxxxxxxxxxxxxx',
            'api' => 'https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions'
        ]);
        $chat->completions(
            [
                'model' => 'qwen-plus',
                'stream' => true,
                'messages' => [
                    ['role' => 'system', 'content' => 'You are a helpful assistant for classifying user feedback.'],
                    ['role' => 'user', 'content' => '请介绍一下webman框架!']
                ],
            ], [
            'stream' => function ($data) use ($connection) {
                $connection->send(new Chunk(json_encode($data, JSON_UNESCAPED_UNICODE) . "\n"));
            },
            'complete' => function ($result, $response) use ($connection) {
                if (isset($result['error'])) {
                    $connection->send(new Chunk(json_encode($result, JSON_UNESCAPED_UNICODE) . "\n"));
                }
                $connection->send(new Chunk(''));
            },
        ]);
        returnresponse()->withHeaders([
            "Transfer-Encoding" => "chunked",
        ]);
    }
}

响应输出

代码语言:javascript
代码运行次数:0
运行
复制
{"choices":[{"delta":{"content":" 是"},"finish_reason":null,"index":0,"logprobs":null}],"object":"chat.completion.chunk","usage":null,"created":1755878877,"system_fingerprint":null,"model":"qwen-plus","id":"chatcmpl-b9e9b019-d573-9c51-81b6-74e82d81c3b4"}

{"choices":[{"delta":{"content":"一个基于 PHP"},"finish_reason":null,"index":0,"logprobs":null}],"object":"chat.completion.chunk","usage":null,"created":1755878877,"system_fingerprint":null,"model":"qwen-plus","id":"chatcmpl-b9e9b019-d573-9c51-81b6-74e82d81c3b4"}

{"choices":[{"delta":{"content":" Swoole 的"},"finish_reason":null,"index":0,"logprobs":null}],"object":"chat.completion.chunk","usage":null,"created":1755878877,"system_fingerprint":null,"model":"qwen-plus","id":"chatcmpl-b9e9b019-d573-9c51-81b6-74e82d81c3b4"}

{"choices":[{"delta":{"content":"高性能 Web 快速开发"},"finish_reason":null,"index":0,"logprobs":null}],"object":"chat.completion.chunk","usage":null,"created":1755878877,"system_fingerprint":null,"model":"qwen-plus","id":"chatcmpl-b9e9b019-d573-9c51-81b6-74e82d81c3b4"}

{"choices":[{"delta":{"content":"框架,由 Work"},"finish_reason":null,"index":0,"logprobs":null}],"object":"chat.completion.chunk","usage":null,"created":1755878877,"system_fingerprint":null,"model":"qwen-plus","id":"chatcmpl-b9e9b019-d573-9c51-81b6-74e82d81c3b4"}

{"choices":[{"delta":{"content":"erman 的作者开发"},"finish_reason":null,"index":0,"logprobs":null}],"object":"chat.completion.chunk","usage":null,"created":1755878877,"system_fingerprint":null,"model":"qwen-plus","id":"chatcmpl-b9e9b019-d573-9c51-81b6-74e82d81c3b4"} 

非流式返回

代码语言:javascript
代码运行次数:0
运行
复制
<?php

declare(strict_types=1);

namespace app\home\v1\controller;

usesupport\Request;
usesupport\Response;
useWebman\Openai\Chat;
useWorkerman\Protocols\Http\Chunk;

class ChatController
{
    publicfunction completions(Request $request): Response
    {
        $connection = $request->connection;
        $chat = new Chat([
            'apikey' => 'sk-xxxxxxxxxxxxxxxxxxxxx',
            'api' => 'https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions'
        ]);
        $chat->completions(
            [
                'model' => 'qwen-plus',
                'messages' => [
                    ['role' => 'system', 'content' => 'You are a helpful assistant for classifying user feedback.'],
                    ['role' => 'user', 'content' => '请介绍一下webman框架!']
                ],
            ], [
            'complete' => function ($result, $response) use ($connection) {
                $connection->send(new Chunk(json_encode($result, JSON_UNESCAPED_UNICODE) . "\n"));
                $connection->send(new Chunk(''));
            },
        ]);
        returnresponse()->withHeaders([
            "Transfer-Encoding" => "chunked",
        ]);
    }
}

响应输出

代码语言:javascript
代码运行次数:0
运行
复制
{
    "choices": [
        {
            "message": {
                "role": "assistant",
                "content": "Webman 是一个基于 Workerman 的高性能 Web 快速开发框架,由 Workerman 的作者出品。
它结合了 Swoole 的协程能力和现代 PHP 框架的设计理念,
适用于构建高性能的 Web 应用和服务,尤其适合需要长连接、高并发的场景,如 API 服务、即时通讯、微服务等。\"
            },
            "finish_reason": "stop",
            "index": 0,
            "logprobs": null
        }
    ],
    "object": "chat.completion",
    "usage": {
        "prompt_tokens": 34,
        "completion_tokens": 893,
        "total_tokens": 927,
        "prompt_tokens_details": {
            "cached_tokens": 0
        }
    },
    "created": 1755879065,
    "system_fingerprint": null,
    "model": "qwen-plus",
    "id": "chatcmpl-5dc8ddbe-7500-9132-a9f4-086837d405be"
}

内容分类(非流式)

代码语言:javascript
代码运行次数:0
运行
复制
<?php

declare(strict_types=1);

namespace app\home\v1\controller;

usesupport\Log;
usesupport\Request;
usesupport\Response;
useWebman\Openai\Chat;
useWorkerman\Protocols\Http\Chunk;

class ChatController
{
    publicfunction completions(Request $request): Response
    {
        $connection = $request->connection;
        $chat = new Chat([
            'apikey' => 'sk-xxxxxxxxxxxxxxx',
            'api' => 'https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions'
        ]);
        $userFeedbacks = [
            "这个手机太贵了,对于我这样的普通消费者不太友好。",
            "客服总是找不到,售后支持根本不给力。",
            "使用起来卡顿,体验很不好。",
            "包装有点损坏,不过可以接受。"
        ];

        // 存储所有反馈的分类结果
        $results = [];

        // 对每个反馈进行非流式分类
        foreach ($userFeedbacks as $index => $feedback) {
            $chat->completions(
                [
                    'model' => 'qwen-plus',
                    'stream' => false, // 非流式调用
                    'messages' => [
                        ['role' => 'system', 'content' => '你是一个用于分类用户反馈的助手。'],
                        ['role' => 'user', 'content' => "请将以下用户反馈按原因分类:价格过高、售后支持不足、产品使用体验不佳、其他。反馈内容:{$feedback}\n回答格式:分类结果:"]
                    ],
                    'temperature' => 0
                ],
                [
                    'complete' => function ($result, $response) use ($connection, $index, &$results, $userFeedbacks) {
                        // 记录完整响应到日志
                        Log::info("Responseforfeedback $index: " . json_encode($result, JSON_UNESCAPED_UNICODE));
                        // 检查响应
                        if (isset($result['error'])) {
                            $error_message = "Error for feedback $index: " . $result['error']['message'];
                            $results[$index] = $error_message;
                            Log::info($error_message);
                        } elseif (isset($result['choices'][0]['message']['content']) && strpos($result['choices'][0]['message']['content'], '分类结果:') === 0) {
                            $results[$index] = trim($result['choices'][0]['message']['content']);
                        } else {
                            $error_message = "Error for feedback $index: Empty or invalid response from API";
                            $results[$index] = $error_message;
                            Log::info($error_message);
                        }

                        // 发送结果
                        $connection->send(new Chunk(json_encode([
                                'index' => $index,
                                'feedback' => $userFeedbacks[$index],
                                'result' => $results[$index]
                            ], JSON_UNESCAPED_UNICODE) . "\n"));

                        // 当所有反馈都处理完成时,发送结束信号
                        if (count($results) === count($userFeedbacks)) {
                            $connection->send(new Chunk(''));
                            Log::info('All feedbacks processed');
                        }
                    }
                ]
            );
        }

        // 返回 HTTP 头,数据通过异步流式返回
        returnresponse()->withHeaders([
            "Transfer-Encoding" => "chunked",
        ]);
    }
}

响应输出

代码语言:javascript
代码运行次数:0
运行
复制
{
  "index":0,
  "feedback":"这个手机太贵了,对于我这样的普通消费者不太友好。",
  "result":"分类结果:价格过高"
}

{
   "index":1,
   "feedback":"客服总是找不到,售后支持根本不给力。",
   "result":"分类结果:售后支持不足"
}

{
   "index":2,
   "feedback":"使用起来卡顿,体验很不好。",
   "result":"分类结果:产品使用体验不佳"
}

{
   "index":3,
   "feedback":"包装有点损坏,不过可以接受。",
   "result":"分类结果:其他"
}
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2025-08-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 开源技术小栈 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 入门使用
    • 安装
    • 流式返回
    • 非流式返回
  • 内容分类(非流式)
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档