各位亲爱的码农朋友们,大家好!
欢迎来到今天的“PHP与AI联姻”特别讲座。我是你们的老朋友,一个每天都在和代码死磕,同时又在思考怎么用代码征服世界的资深编程专家。
今天我们要聊的,是一个非常性感的话题:如何让PHP——这门被称为“世界上最流行(也最让人头疼)的服务端语言”,去调用OpenAI的API,实现AI自动生成文章和摘要。
你可能会问:“老专家,PHP不是那种老掉牙的语言吗?现在不是流行Go、Python、Rust吗?”
哎,各位,肤浅!PHP的魅力就在于它的“粘性”。只要有人类写网站的地方,就有PHP的身影。而现在,AI是未来的王,把PHP和AI结合,那就是“王炸”啊!这就像给哆啦A梦装上了任意门,你想要什么,他就给你变什么。
别废话了,直接上干货。今天咱们不讲虚的,只讲怎么把OpenAI的嘴撬开,让它乖乖为你写文章、做摘要。
第一章:准备工作,别还没开始就“裸奔”
在开始写代码之前,咱们得先有个“通行证”。OpenAI的API不是在大街上发传单的,你得去OpenAI官网申请一个API Key。这玩意儿就像是你家门钥匙,别告诉任何人,更别把钥匙贴在衬衫的背面。
注意: 不同的模型(比如GPT-3.5和GPT-4)价格不一样,GPT-4那家伙比较费钱,你每敲一下键盘,它的Token计数器都在滴答作响,就像你信用卡在滴答。咱们今天的实战,主要用GPT-3.5-turbo,性价比高,适合咱们这种“穷但有追求”的开发者。
另外,PHP版本嘛,咱们得讲究点。建议PHP 7.4或者8.0以上。如果你还在用PHP 5.6,那咱们就得先聊聊“回忆杀”了,或者,直接升级吧,别让旧代码拖累你的AI梦想。
第二章:PHP与HTTP的“亲密接触”——CURL是主角
PHP要调用OpenAI接口,本质上就是发一个HTTP POST请求。在这个领域,没有比 curl 函数族更忠诚的伙伴了。虽然有些人讨厌它,觉得它太复杂,参数太多像天书,但我告诉你,它是PHP的灵魂。如果你不会用CURL,你就不是个正宗的PHP程序员。
咱们先看个最基础的例子,就像打个招呼:“嘿,OpenAI,在吗?”
<?php
// 1. 初始化,就像你拨通电话
$ch = curl_init();
// 2. 设置目标URL,OpenAI的聊天接口地址
$url = 'https://api.openai.com/v1/chat/completions';
// 3. 构造请求头,告诉人家你是谁,你想干嘛
$headers = [
'Content-Type: application/json',
'Authorization: Bearer YOUR_OPENAI_API_KEY_HERE', // 这里记得替换成你自己的Key
];
// 4. 准备要发送的数据,这就是你要喂给AI的“饲料”
$data = [
'model' => 'gpt-3.5-turbo', // 咱们用便宜的3.5
'messages' => [
['role' => 'user', 'content' => '你好,请用一句话介绍PHP语言。']
]
];
// 5. 把数据转成JSON格式,这是HTTP协议最喜欢的语言(虽然HTTP自己不懂)
$payload = json_encode($data);
// 6. 设置CURL选项
curl_setopt_array($ch, [
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true, // true表示把返回结果存到变量里,而不是直接打印出来
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $payload,
CURLOPT_HTTPHEADER => $headers,
CURLOPT_TIMEOUT => 30, // 别让请求挂太久,超过30秒你就得喝西北风了
]);
// 7. 执行请求,就像按下拨号键
$response = curl_exec($ch);
// 8. 检查有没有错误,别光顾着笑,还得检查有没有翻车
if (curl_errno($ch)) {
echo '请求出错: ' . curl_error($ch);
} else {
// 9. 打印结果,看看AI说了啥
echo $response;
}
// 10. 关闭连接,挂断电话
curl_close($ch);
?>
这段代码虽然短,但它干了一件大事:它成功地把请求发给了OpenAI。如果你运行这段代码,你会发现返回的 $response 是一大坨JSON字符串。别慌,那是AI的思考过程,里面包含了AI说的话。咱们下一章,就要教你怎么从这坨乱七八糟的字符串里,把有用的信息“抠”出来。
第三章:解析JSON与提示词工程——给AI“穿”上西装
得到JSON响应后,我们得用 json_decode 把它变成PHP能读懂的数组。然后,你会发现返回的结构里有一个 choices[0][message][content] 字段,那就是AI的回答。
但是,光会调用还不够。你想让AI写文章?那得靠提示词。
提示词(Prompt)是灵魂。就像你让厨师做菜,你说“给我做个饭”,厨师可能给你端来一盘空气;但你说“给我做个麻婆豆腐,要微辣,不要太麻,配米饭”,那出来的就是完美的菜肴。
在PHP里,我们可以把提示词放在一个变量里,甚至可以做成一个模板。
<?php
function generateSummary($text) {
$apiKey = 'YOUR_API_KEY';
$url = 'https://api.openai.com/v1/chat/completions';
// 这是提示词工程的艺术
// system角色:设定AI的人设,让它像个严肃的编辑
// user角色:具体的任务
$messages = [
['role' => 'system', 'content' => '你是一个资深的编辑,擅长撰写文章摘要。你的输出必须简洁、准确,且只包含摘要,不要有废话。'],
['role' => 'user', 'content' => "请为以下这段文字生成一个摘要:nn{$text}"]
];
$payload = json_encode([
'model' => 'gpt-3.5-turbo',
'messages' => $messages,
'temperature' => 0.7 // 这里的temperature决定了AI的“发挥空间”,0.7比较稳妥
]);
// 发送请求...(省略了重复的curl_init等代码,实际开发要封装成一个函数)
// 假设 $response 是刚才返回的JSON字符串
$decoded = json_decode($response, true);
if (isset($decoded['choices'][0]['message']['content'])) {
return $decoded['choices'][0]['message']['content'];
}
return "AI罢工了,没吐出东西。";
}
// 测试一下
$longText = "PHP(PHP: Hypertext Preprocessor)是一种通用开源脚本语言。脚本语言主要运行在服务器端,PHP代码会被处理为生成HTML等网页文档。尽管PHP最初是个人主页工具,但如今它已被广泛使用,用来开发Web应用,从简单的命令行脚本到复杂的社交网络应用。PHP语法吸收了C语言、Java和Perl的特点,利于学习,使用广泛,主要适用于Web开发领域。";
echo generateSummary($longText);
?>
看,这就是PHP调用AI的核心逻辑。你把 $longText 传进去,告诉AI“这玩意儿太长了,给我总结一下”,AI就会乖乖吐出一个简洁的摘要。
第四章:实战演练——自动生成文章
现在咱们来点更刺激的。如果只做摘要,那AI顶多是个小学生。我们要让它写文章。
写文章有个难点:上下文长度。GPT-3.5或者GPT-4都有个脾气,它一次最多只能处理一定的字数(比如4096个Token)。如果你的文章太长,直接塞给它,它会说“哎呀,我内存不够了,记不住了”。这就好比你让一个人背整本字典,他背到一半肯定会忘开头。
所以,对于长篇文章的生成,咱们得用分段处理的策略。把文章切成一段一段,让AI一段一段地写,最后再把它拼起来。
下面是一个完整的生成长文类的代码示例。为了演示效果,我封装了一个 OpenAIChat 类。
<?php
class OpenAIChat {
private $apiKey;
private $model;
private $ch; // CURL句柄,复用能提升性能
public function __construct($apiKey, $model = 'gpt-3.5-turbo') {
$this->apiKey = $apiKey;
$this->model = $model;
$this->ch = curl_init();
}
public function complete($messages, $stream = false) {
$url = 'https://api.openai.com/v1/chat/completions';
$payload = json_encode([
'model' => $this->model,
'messages' => $messages,
'stream' => $stream
]);
curl_setopt_array($this->ch, [
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $payload,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'Authorization: Bearer ' . $this->apiKey
],
CURLOPT_TIMEOUT => 60
]);
$response = curl_exec($this->ch);
if (curl_errno($this->ch)) {
throw new Exception('CURL Error: ' . curl_error($this->ch));
}
return json_decode($response, true);
}
public function close() {
curl_close($this->ch);
}
}
// ==========================================
// 主程序:生成一篇关于“PHP未来”的文章
// ==========================================
$apiKey = 'YOUR_KEY';
$ai = new OpenAIChat($apiKey);
// 1. 构建任务
$task = "请写一篇关于《PHP在2024年的未来展望》的文章,字数要求800字。要求文章结构完整,包含引言、正文和结论。";
// 2. 发起请求
try {
$result = $ai->complete([
['role' => 'system', 'content' => '你是一位知名的科技博主,擅长撰写深度技术文章。'],
['role' => 'user', 'content' => $task]
]);
$content = $result['choices'][0]['message']['content'];
echo "<h1>AI生成的文章如下:</h1>";
echo "<p>" . nl2br($content) . "</p>";
} catch (Exception $e) {
echo "哎呀,出错了: " . $e->getMessage();
}
$ai->close();
?>
这段代码展示了如何发送系统提示词(System Prompt)来设定AI的人设。告诉它“你是科技博主”,它写出来的东西就会比你那个只会喊“Hello World”的初级开发者要专业得多。
第五章:流式响应——像看视频一样看AI写作
你肯定见过那种,文字一个个蹦出来的效果,像打字机一样。这就是流式响应。
在PHP里实现流式响应,稍微有点技术含量。因为它不是一次性把结果发回来,而是数据一点点发回来。我们需要使用 CURLOPT_WRITEFUNCTION 回调函数,实时捕获数据并打印。
这对用户体验来说是革命性的。当你在写一个博客生成器时,用户不用干坐着等3秒钟,而是看着字一个一个冒出来,心里会觉得“哇,好快!好智能!”
<?php
function streamChat($apiKey, $prompt) {
$ch = curl_init('https://api.openai.com/v1/chat/completions');
$headers = [
'Content-Type: application/json',
'Authorization: Bearer ' . $apiKey
];
$data = [
'model' => 'gpt-3.5-turbo',
'messages' => [
['role' => 'user', 'content' => $prompt]
],
'stream' => true // 关键!开启流式传输
];
// 定义回调函数,每次收到数据就调用
curl_setopt($ch, CURLOPT_WRITEFUNCTION, function($ch, $chunk) {
// OpenAI的流式数据是以 "data: " 开头的JSON片段
if (strpos($chunk, 'data: ') === 0) {
$jsonStr = substr($chunk, 6); // 去掉 "data: "
if ($jsonStr === '[DONE]') {
return strlen($chunk); // 结束了
}
$json = json_decode($jsonStr, true);
if (isset($json['choices'][0]['delta']['content'])) {
$content = $json['choices'][0]['delta']['content'];
echo $content; // 实时输出
flush(); // 强制刷新缓冲区,让浏览器立马显示出来
}
}
return strlen($chunk);
});
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
curl_exec($ch);
curl_close($ch);
}
// 使用示例
streamChat('YOUR_KEY', '请流式地给我讲个笑话,讲完为止。');
?>
这段代码展示了 flush() 函数的重要性。PHP默认会把输出缓冲,导致你可能要等一大堆数据攒够了才显示出来。用了这个函数,用户就能感受到AI“正在思考”的过程。
第六章:架构之美——封装与服务层
老专家我要敲黑板了!上面的代码虽然能跑,但在生产环境中就是“地雷”。
- 安全性: API Key不能写在代码里,应该放在环境变量里。
- 重试机制: 网络是不稳定的,有时候AI服务器会抽风,你得写个
try-catch循环,失败了重试3次。 - 缓存: 别每次都问AI。如果用户看了同一篇文章两次,别再浪费钱去调用API了,直接读缓存。
- Token统计: 记得记录用了多少Token,方便算账。
咱们来构建一个稍微高级一点的 OpenAIService 类。
<?php
class OpenAIService {
private $apiKey;
private $model;
private $retryCount = 3; // 失败重试3次
public function __construct($apiKey, $model = 'gpt-3.5-turbo') {
$this->apiKey = $apiKey;
$this->model = $model;
}
/**
* 发送请求,包含重试逻辑
*/
public function sendMessage($prompt, $systemRole = 'You are a helpful assistant.') {
$messages = [
['role' => 'system', 'content' => $systemRole],
['role' => 'user', 'content' => $prompt]
];
for ($attempt = 1; $attempt <= $this->retryCount; $attempt++) {
try {
$result = $this->doRequest($messages);
return $result['content'];
} catch (Exception $e) {
echo "第 {$attempt} 次尝试失败: " . $e->getMessage() . "n";
if ($attempt < $this->retryCount) {
sleep(1 * $attempt); // 指数退避,别立刻重试,给服务器喘口气
} else {
throw new Exception("重试3次后依然失败,放弃治疗。");
}
}
}
}
private function doRequest($messages) {
// ... 这里复用之前的 curl 代码 ...
// 为了代码简洁,这里省略具体curl实现,假设调用成功返回数组 ['content' => '...']
return ['content' => "模拟AI返回的内容"];
}
}
// 使用
$service = new OpenAIService(getenv('OPENAI_API_KEY'));
$summary = $service->sendMessage("请帮我总结这段代码...");
echo $summary;
?>
这个类封装了 try-catch 和 sleep,这就是“资深”和“菜鸟”的区别。菜鸟写代码是“能跑就行”,老手写代码是“能跑、稳定、安全、可维护”。
第七章:高级玩法——结构化输出与JSON Mode
如果你想让PHP处理AI生成的内容,最头疼的是什么?是解析AI吐出来的乱七八糟的文本。AI有时候很自信,有时候会胡说八道,有时候格式还跑偏了。
现在OpenAI支持一种高级模式叫 JSON Mode。你可以告诉AI:“我只接受JSON格式,而且必须包含这些字段:title, content, tags。” 如果AI不按格式来,它就会被拒绝。
这对PHP开发者来说简直是福音!因为PHP里处理JSON比处理HTML要容易得多。
<?php
function generateStructuredContent($topic) {
$apiKey = 'YOUR_KEY';
$payload = json_encode([
'model' => 'gpt-3.5-turbo',
'response_format' => ['type' => 'json_object'], // 强制返回JSON
'messages' => [
[
'role' => 'system',
'content' => '你是一个内容生成器。你必须以JSON格式输出。JSON结构必须包含 title, description, and tags 数组。'
],
[
'role' => 'user',
'content' => "请生成一个关于 {$topic} 的博客文章元数据。"
]
]
]);
// 发送请求...
// $response = curl_exec(...);
// 解析JSON
$data = json_decode($response, true);
return $data; // 直接就是数组了,直接 foreach 就行
}
// 使用
$result = generateStructuredContent("PHP的未来");
echo "标题: " . $result['title'] . "n";
echo "标签: " . implode(', ', $result['tags']);
?>
记得,在 response_format 里指定 json_object,然后配合精心设计的System Prompt,AI会变得非常有纪律性。
第八章:常见坑与最佳实践
好了,到了咱们“扫雷”的时间。在实战中,大家经常会遇到这些问题,老专家我替你们踩过坑了:
-
Token计数错误:
PHP的strlen是算字节数的,不是算Token的。有些中文字符占3个字节,有的占1个字节。发送给OpenAI的时候,它按Token算钱,你按字节算成本,很容易超支。建议使用库如token-count或者直接在本地估算。 -
Rate Limit(速率限制):
OpenAI对免费账户有限制。如果你在一个循环里,一瞬间发了100个请求,你的IP会被封禁。一定要设置请求间隔,比如每秒最多1-2个请求。 -
提示词越界:
你问了一个超级复杂的问题,结果GPT只回复了“我无法回答”。这是因为超出了上下文窗口。这时候你要学会把大问题拆成小问题,分步回答。 -
API Key 泄露:
千万别把Key写在前端(HTML/JS)里!前端代码是给所有人看的。Key必须放在后端。
总结:PHP,永不放弃的战士
说了这么多,其实PHP调用OpenAI接口的核心原理就三步:
- 组装JSON: 把你的问题变成API能懂的语言。
- 发HTTP请求: 用CURL把它扔出去。
- 解析结果: 用
json_decode把AI的脑子拿出来。
别再说PHP老了。当Python还在忙着把AI库封装得花花绿绿时,PHP凭借其强大的Web生态,正以极简的方式深入到每一个服务器端。把AI能力塞进你的CMS里,塞进你的电商后台里,塞进你的管理系统中,这才是编程的最高境界——赋能。
今天的讲座就到这里。希望你们回去后,能写出那个让全公司都震惊的“AI文章自动生成器”。
别忘了,写代码的时候,喝口水,少点两根烟。AI是智慧,身体是本钱。咱们下期再见!