Webman命令行调用openai需绕开$connection,直接用echo或$output->writeln()输出;stream回调中禁用$connection->send(),complete回调避免检查error再发Chunk;Chat::completions()天然异步,勿加yield或co::sleep();国内访问应换兼容API地址而非改SDK;Assistant API不支持流式,需自行封装HTTP轮询。

Webman命令行里调用webman/openai必须绕开$connection
命令行环境没有HTTP连接上下文,$connection对象在Command类里根本不存在——硬要new TcpConnection会卡死或报错Invalid argument。你不需要它,也不该模拟它。
真正该做的,是直接用echo或$output->writeln()输出结果,而不是往HTTP流里写Chunk。示例里那个stream回调里的echo才是正路:
['stream' => function($data) {
echo json_encode($data, JSON_UNESCAPED_UNICODE) . "\n";
}, 'complete' => function($result) {
echo "done. total tokens: " . ($result['usage']['total_tokens'] ?? 0) . "\n";
}]
-
stream回调里别用$connection->send(),那是控制器专属 -
complete回调里也别检查$result['error']再发Chunk,直接print_r($result)或提取关键字段 - 如果想结构化输出,用
$output->success()或$output->error()(需继承Command并注入OutputInterface)
Chat::completions()在Webman里默认就是异步的,别手动套async/await
Webman基于Workerman,所有网络I/O天然异步。你调用Chat::completions()时传的stream和complete回调,本身就是事件循环注册的监听器,不是同步阻塞等待。强行加yield或co::sleep()反而会打断流程。
常见错误是看到PHP协程文档就条件反射加go或co::create——webman/openai内部已用Workerman\Timer和ReactPHP\HttpClient封装了异步HTTP,你只管传回调。
- 控制器里直接
new Chat([...])+completions(..., [...])即可,无需go包裹 - 命令行里同理,但注意回调内不要依赖
Request或Response对象 - 若需并发多个请求,用
array_map+多个Chat实例,别用Promise——Workerman不兼容Promise链
国内访问OpenAI官方API失败?优先换兼容地址,别改SDK源码
https://api.openai.com在国内多数环境直连超时或被重置,但webman/openai支持任意兼容OpenAI格式的API地址,包括阿里云通义、百度千帆、月之暗面等。硬改SDK的base_uri或加代理容易破坏重试逻辑。
正确做法是在构造Chat时直接指定api参数:
$chat = new Chat([
'apikey' => 'sk-xxx',
'api' => 'https://dashscope.aliyuncs.com/compatible-mode/v1'
]);
- 阿里云通义:用
qwen-plus或qwen-max模型,api填https://dashscope.aliyuncs.com/compatible-mode/v1 - 百度千帆:用
ERNIE-Bot-4,api填https://aip.baidubce.com/rpc/2.0/ai_custom/v1 - 自建Ollama:用
llama3,api填http://localhost:11434/v1
所有兼容地址都要求Content-Type: application/json且响应结构一致,webman/openai不做额外适配就能跑通。
Assistant API不支持流式?那就别用stream回调
webman/openai当前版本(v2.3.0)只封装了/chat/completions和/images/generations等基础接口,Assistants API(/threads、/runs)需自行封装HTTP请求。它的stream参数对beta.assistants.runs.create无效——这个接口本身不返回流式chunk,而是返回run对象,后续要轮询retrieve。
如果你非要上Assistant能力,得自己用GuzzleHttp\Client或Workerman\Http\Client发请求:
$client = new \GuzzleHttp\Client();
$response = $client->post('https://api.openai.com/v1/threads', [
'headers' => ['Authorization' => 'Bearer sk-xxx'],
'json' => ['messages' => [['role'=>'user','content'=>'hello']]]
]);
$thread_id = json_decode($response->getBody(), true)['id'];
-
webman/openai不提供assistant、thread、run等类,别在命名空间里找Webman\Openai\Assistant - 流式输出仅适用于
completions和chat/completions,Assistant的run状态轮询必须用同步HTTP - 轮询间隔建议设为
1s,避免429错误;状态为completed后,再查/threads/{id}/messages拿最终回复
真正难的不是调通接口,而是把Assistant的多步状态机(queued → in_progress → completed → failed)稳稳落地到Workerman的异步事件循环里——这里没现成轮子,得手写状态管理器。


















