通过简单curl请求调用通义千问 API,完成用户反馈的自动分类任务。本章节使用异步非阻塞 webman/openai 客户端完成用户反馈的自动分类任务。
webman/openai是一个异步非阻塞的openai客户端,配合webman可以做到同一时刻支持上万并发调用,使用简单,返回如丝般的顺滑。
传统php-fpm架构调用openai等大模型接口时只能做到阻塞调用,由于大模型接口返回速度很慢,一个php-fpm进程一分钟只能调用几次,几个人一刷系统就会明显的卡顿甚至不可用状态。
所以传统php-fpm不适合做大模型调用,而webman这类的常驻内存类型的框架非常适合大模型应用的开发。
composer require webman/openai
https://www.workerman.net/plugin/157
<?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",
]);
}
}
响应输出
{"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"}
<?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",
]);
}
}
响应输出
{
"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"
}
<?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",
]);
}
}
响应输出
{
"index":0,
"feedback":"这个手机太贵了,对于我这样的普通消费者不太友好。",
"result":"分类结果:价格过高"
}
{
"index":1,
"feedback":"客服总是找不到,售后支持根本不给力。",
"result":"分类结果:售后支持不足"
}
{
"index":2,
"feedback":"使用起来卡顿,体验很不好。",
"result":"分类结果:产品使用体验不佳"
}
{
"index":3,
"feedback":"包装有点损坏,不过可以接受。",
"result":"分类结果:其他"
}