PHP 驱动的化学品技术文章自动生成:基于行业词库的 AI 提示词工程与组件化输出

欢迎来到化学与代码的狂欢派对:用 PHP 炼制 AI 文章

各位同学,大家晚上好!

既然你们坐在这里,手里拿着或者盯着屏幕,我猜你们要么是厌倦了写 SDS(化学品安全技术说明书)的苦逼化学家,要么是渴望给公司 AI 换个心脏的 PHP 后端开发。今天,我们不聊 MVC,不聊 PSR-12 代码规范,我们聊点更“危险”的——如何用 PHP 这个老牌战士,去驯服那些像喝多了二锅头的 LLM(大语言模型),让它们乖乖写出像模像样的化学品技术文章。

你可能会问,化学和 PHP 有什么关系?嘿,这就好比说,为什么要把蒸汽机塞进马车里?化学反应需要条件,PHP 代码需要逻辑。而我们要做的,就是给 AI 这个没长大的孩子,制定一套符合化学工业严谨标准(又不至于无聊死)的“食谱”。

准备好了吗?让我们把代码当试剂,把 AI 当小白鼠,开始这场实验。


第一部分:痛点是金矿——为什么我们需要这个?

想象一下,你是一家化工厂的技术文档部主管。你需要为刚刚研发出来的“神奇液体 A”写一份技术手册。

正常流程:

  1. 查阅文献: Google Scholar,Sci-Hub,查到凌晨三点。
  2. 整理数据: 将 CAS 号、分子式、反应机理用 Excel 搞定。
  3. 撰写文案: 面对空白的 Word 文档,你盯着屏幕发呆。引言怎么写才显得高深?反应机理怎么描述才像那么回事?安全注意事项怎么强调才不会被安全员骂死?
  4. 修改润色: 老板说“语气再专业一点”,你改了十分钟;老板说“能不能加点案例”,你加了半小时。

这就像是用烧杯去接瀑布,怎么接都接不完。这时候,AI 出现了。

但是! 别急着把所有数据喂给 ChatGPT 就完事了。你试过让 AI 写化学品 SDS 吗?我试过。它写出来的“处理注意事项”是:“请用双手轻轻捧起容器,轻声对它说‘我爱你’,然后放在通风橱里。” —— 这要是在化工厂,那就是重大安全事故。

所以,我们需要一个中转站。这个中转站要懂化学(或者至少有个化学词典),要懂 PHP(能把数据组装起来),最重要的是,它得是个严厉的老师,时刻盯着 AI 别胡言乱语。

我们的主角:PHP。为什么选它?因为它快,因为它能搞定 CMS,因为它那个 foreach 循环简直就是为了批量处理文档而生的。


第二部分:基石——行业词库的构建

AI 瞎编,是因为它脑子里没有准确的“化学词典”。如果你给它看“Hydrogen Peroxide”,它可能写“过氧化氢”,也可能写“高能水”。在化学界,差一个字,可能就是爆炸,也可能是治病救人。

在代码层面,这个“词典”就是一个结构化的数组。我们把它叫作 ChemistryVocabulary

<?php

/**
 * 化学品行业术语词典
 * 这不是什么正经类,这简直是我们的保命符
 */
class ChemistryVocabulary
{
    public static $molecules = [
        'h2o' => '水 (Water)',
        'h2so4' => '硫酸 (Sulfuric Acid)',
        'naoh' => '氢氧化钠 (Sodium Hydroxide)',
        'c6h12o6' => '葡萄糖 (Glucose)',
        // ... 这里可以塞入几百个常用化学品
    ];

    public static $reaction_types = [
        'oxidation' => '氧化反应',
        'hydrolysis' => '水解反应',
        'polymerization' => '聚合反应',
        'neutralization' => '中和反应',
        'combustion' => '燃烧/氧化反应'
    ];

    public static $safety_hazards = [
        'corrosive' => ['强腐蚀性', '可能导致皮肤烧伤'],
        'toxic' => ['有毒', '摄入或吸入有害'],
        'flammable' => ['易燃', '闪点低于60°C'],
        'oxidizer' => ['氧化剂', '强氧化性']
    ];

    /**
     * 核心功能:规范化术语
     * 把用户随便输的 '硫酸' 统一变成 'Sulfuric Acid (CAS: 7664-93-9)'
     */
    public static function normalize($input)
    {
        // 先匹配 CAS 号 (简单的正则)
        if (preg_match('/d{2,4}-d{2}-d{2}/', $input, $matches)) {
            return "CAS: {$matches[0]}";
        }

        // 再匹配分子式
        foreach (self::$molecules as $key => $val) {
            if (stripos($input, $key) !== false) {
                return $val;
            }
        }

        // 最后匹配中文
        foreach (self::$molecules as $key => $val) {
            if (stripos($val, $input) !== false) {
                return $val;
            }
        }

        return $input; // 如果都不认识,就原样返回,让 AI 去猜(或者报错)
    }
}

// 测试一下
echo ChemistryVocabulary::normalize("7664-93-9"); // 输出: CAS: 7664-93-9
echo "<br>";
echo ChemistryVocabulary::normalize("硫酸");     // 输出: 硫酸

设计思路: 这个词库不是死的。它是动态的。我们可以把它存在数据库里,通过 PHP 定时从 PubChem 或者 ChemSpider 抓取数据更新它。有了这个,AI 就不会把“苯”说成“巧克力”了。


第三部分:灵魂——提示词工程的艺术

有了词库,怎么喂给 AI?这就是提示词工程。在化学领域,提示词就是实验配方

很多新手写提示词就像写请假条:“帮我写个关于苯的介绍。”
AI 回复:“苯是一种芳烃,有着独特的六边形结构……”

太无聊了!我们要的是“深度技术文章”。我们需要告诉 AI 它的角色任务限制输出格式

我们构建一个 PHP 类 PromptGenerator,专门负责把数据组装成高质量的提示词。

<?php

class PromptGenerator
{
    public static function generateArticlePrompt($chemicalName, $properties)
    {
        // 获取 CAS 号
        $cas = $properties['cas'] ?? '未知';

        // 构建系统提示词 - 这是给 AI 的“出厂设置”
        $systemPrompt = <<<PROMPT
你是一位资深的化学工程师和科普作家。你的任务是基于提供的信息,撰写一篇不少于 1500 字的专业技术文章。
风格要求:严谨、客观、数据详实,同时要避免枯燥,使用生动的比喻。
输出格式要求:Markdown 格式,包含标题、摘要、正文(分章节)、结论。
安全红线:如果涉及危险化学品的操作,必须详细列出防护措施(PPE)。

现在开始工作。
PROMPT;

        // 构建用户提示词 - 这是“实验原料”
        $userPrompt = <<<PROMPT
请以 **{$chemicalName} (CAS: {$cas})** 为主题撰写文章。

需包含以下章节:
1. **分子背景**:介绍该化学品的基本性质、物理状态及用途。
2. **合成/制备机理**:简述其工业合成路径或实验室制备方法。
3. **反应动力学**:分析其在不同条件下的化学行为(如热稳定性、与其他物质的反应性)。
4. **工业应用**:列举 3 个具体的工业应用场景。
5. **安全与合规**:重点强调 MSDS 中的关键危害(如毒性、腐蚀性)及应急处置措施。

附加信息:
- 分子量:{$properties['molecular_weight']}
- 沸点:{$properties['boiling_point']}
- 危害等级:{$properties['hazard_level']}
PROMPT;

        return [
            'system' => $systemPrompt,
            'user'   => $userPrompt
        ];
    }
}

关键点解析:

  1. 角色设定: 告诉 AI 它是“资深化学工程师”,它就会表现得像个专家,而不是个只会写小学生作文的实习生。
  2. 格式约束: 明确要求 Markdown,这在 PHP 处理时非常方便,我们只需要正则提取 Markdown 标题即可。
  3. 安全红线: 这里的代码逻辑非常重要。PHP 负责把“氢氟酸”标记为“剧毒”,然后把这个标记塞进提示词里。AI 就不敢乱写了。

第四部分:骨架——组件化输出

如果一次让 AI 写一篇 2000 字的文章,你可能会得到一篇逻辑混乱、甚至前后矛盾的“大杂烩”。就像把所有食材扔进锅里,结果煮成了一锅粥。

我们要用组件化的思维。把文章拆解成“原子”和“分子”。

  • 原子组件:小段落,比如“安全警告”、“反应方程式”。
  • 分子组件:段落组合,比如“合成工艺步骤”。

让我们在 PHP 里实现一个简单的组件加载器。

<?php

/**
 * 文章组件工厂
 * 负责生成文章的各个模块
 */
class ArticleComponents
{
    /**
     * 生成标题组件
     */
    public static function getTitle($chemicalName)
    {
        $titles = [
            "深度解析:{$chemicalName} 的工业制备与安全应用",
            "从分子结构到工业实践:关于 {$chemicalName} 的全面技术综述",
            "揭秘 {$chemicalName}:反应机理、工艺优化与风险管控"
        ];
        return $titles[array_rand($titles)]; // 随机挑一个听起来很厉害的
    }

    /**
     * 生成安全警告组件 (这是一个原子组件)
     */
    public static function getSafetyAlert($hazard)
    {
        $hazardText = match($hazard) {
            'high' => '【高危警告】该物质具有极高的毒性和腐蚀性,操作必须在负压通风橱内进行,操作人员必须佩戴全套防化服。一旦泄漏,切勿直接用水冲洗!',
            'medium' => '【中等风险】该物质具有易燃性和刺激性,需远离火源,佩戴护目镜和耐化学品手套。',
            default => '【一般风险】请按照标准实验室安全规范操作。',
        };

        return "<div class='alert alert-warning'>n  <strong>安全提示:</strong>n  $hazardTextn</div>";
    }

    /**
     * 生成反应机理描述组件 (这是一个分子组件)
     */
    public static function getMechanismBlock($reactionType, $description)
    {
        return <<<HTML
<div class="mechanism-block">
    <h3>反应机理分析</h3>
    <p><strong>反应类型:</strong> {$reactionType}</p>
    <p>{$description}</p>
</div>
HTML;
    }
}

为什么这么做?
因为在 PHP 的世界里,我们可以先组装好 HTML 结构,把空位留给 AI 填充。这样生成的文章结构非常稳固,就像乐高积木一样。


第五部分:实战——PHP 驱动的自动化流水线

好了,理论都讲完了,现在上干货。我们写一个完整的脚本,模拟从数据库读取化学品数据,调用 AI,组装文章,最后保存到文件的过程。

我们将使用 curl 来模拟调用 OpenAI 的 API(当然,你也可以换成兼容的 SDK)。

<?php

// 假设我们已经加载了 Composer 的 GuzzleHttp 或者直接用原生 curl
// 这里为了演示独立运行,我们模拟一下 API 调用函数

function callOpenAI($systemPrompt, $userPrompt) {
    // 实际场景中,这里会是一个 HTTP POST 请求
    // $response = file_get_contents('http://api.openai.com/v1/chat/completions', ...);

    // 为了让代码能跑通,我们这里模拟返回一段文本
    // 真实世界请删除下面的 return,换成真实的 curl 代码
    return "模拟返回:{$userPrompt} 的深度技术分析(这是 AI 撒谎生成的占位符)...";
}

// ==========================================
// 主流程控制
// ==========================================

class ChemicalArticleGenerator
{
    private $apiKey;
    private $baseModel = "gpt-4";

    public function __construct($apiKey)
    {
        $this->apiKey = $apiKey;
    }

    public function generate($chemicalData)
    {
        echo "开始处理化学品:{$chemicalData['name']}...n";

        // 1. 术语标准化
        $normalizedName = ChemistryVocabulary::normalize($chemicalData['name']);
        echo " -> 术语标准化完成: $normalizedNamen";

        // 2. 生成提示词
        $prompts = PromptGenerator::generateArticlePrompt($normalizedName, $chemicalData);

        // 3. 调用 AI (核心)
        $rawContent = $this->invokeAI($prompts['system'], $prompts['user']);
        echo " -> AI 内容生成完成n";

        // 4. 组件化组装 (这里做一个简单的拼接演示)
        $articleStructure = [
            'meta' => [
                'title' => ArticleComponents::getTitle($normalizedName),
                'author' => 'AI Assistant',
                'date' => date('Y-m-d')
            ],
            'body' => [
                'safety' => ArticleComponents::getSafetyAlert($chemicalData['risk']),
                'content' => $rawContent // AI 生成的长文本
            ]
        ];

        // 5. 输出 Markdown 文件
        return $this->renderMarkdown($articleStructure);
    }

    private function invokeAI($system, $user) {
        // 实际代码示例:
        /*
        $payload = [
            'model' => $this->baseModel,
            'messages' => [
                ['role' => 'system', 'content' => $system],
                ['role' => 'user', 'content' => $user]
            ],
            'temperature' => 0.7 // 0.7 代表有创造性,但不会乱来
        ];
        return $this->makeCurlRequest($payload);
        */
       return "这是 AI 生成的关于 $normalizedName 的文章内容...";
    }

    private function renderMarkdown($data) {
        $markdown = "# {$data['meta']['title']}nn";
        $markdown .= "**生成日期:** {$data['meta']['date']}nn";
        $markdown .= "---nn";
        $markdown .= $data['body']['safety'] . "nn";
        $markdown .= $data['body']['content'];

        return $markdown;
    }
}

// ==========================================
// 模拟数据
// ==========================================

$chemicalData = [
    'name' => '7664-93-9', // 这是个 CAS 号,或者是 "甲苯" 或者 "7664-93-9"
    'risk' => 'medium',
    'boiling_point' => '110.6 °C',
    'molecular_weight' => '92.13 g/mol'
];

// 运行
$generator = new ChemicalArticleGenerator("sk-xxxxxxxxxxxx");
$result = $generator->generate($chemicalData);

// 保存文件
file_put_contents("output_article.md", $result);

echo "文章已生成,请查看 output_article.mdn";

这段代码说明了什么?

  1. 解耦: 数据层($chemicalData)与逻辑层分离。
  2. 复用: PromptGeneratorArticleComponents 可以在不同的项目中反复使用。
  3. 流程清晰: 标准化 -> 提示 -> 生成 -> 渲染。

第六部分:进阶——防御幻觉与向量数据库

AI 很聪明,但也很容易“喝高”。在化学领域,这是致命的。

假设 AI 写道:“苯在 1000 度下会发生核裂变。” —— 这虽然是笑话,但在代码里必须防御。

策略一:结构化约束
在提示词里,强制要求 AI 以 JSON 格式输出。
然后,在 PHP 里,我们用 json_decode 解析它。
如果解析失败(PHP 返回 null),说明 AI 胡说八道了,直接报错,重试。

// PHP 侧的防御
$aiResponse = "这是 JSON: { "formula": "C6H6", "melting_point": 5.5 }";
$data = json_decode($aiResponse, true);

if (!$data) {
    // 记录日志,调用人工审核
    Log::error("AI 幻觉检测:{$aiResponse}");
    return false;
}

// 检查数据范围是否合理
if ($data['melting_point'] < -273.15) {
    Log::error("物理参数异常");
}

策略二:RAG(检索增强生成)
这是目前的行业趋势。不要让 AI 凭空想象化学性质。给它一份 PDF 文档作为“参考书”。
PHP 在这里可以扮演“图书管理员”的角色。

  1. 嵌入:使用 PHP 调用 Embedding API,把化学品手册里的段落转成向量。
  2. 检索:当用户问“关于 X 的反应机理”时,PHP 在向量数据库里搜索最相关的 3 个段落。
  3. 上下文注入:把这些段落塞进 Prompt 里,告诉 AI:“请基于以下提供的参考资料回答问题:……”
// 模拟 RAG 上下文注入
function augmentPrompt($query, $referenceContext) {
    return "参考文档内容:n$referenceContextnn请基于以上内容回答问题:$query";
}

第七部分:动态词库与数据清洗

我们之前说的词库是静态的。但在现实世界,数据是脏的。

化工数据库里的数据可能是:

  1. “Acid, Sulfuric (98%)” -> 需要清洗成 “Sulfuric Acid (98%)”
  2. “H2SO4” -> 需要清洗成 “Sulfuric Acid”
  3. “H2SO4(98%)” -> 需要清洗成 “Sulfuric Acid (98%)”

PHP 的字符串处理函数在这里大显身手。

class DataCleaner
{
    public static function cleanChemicalName($dirtyString)
    {
        // 移除括号里的杂质信息,只保留核心名称
        $clean = preg_replace('/s*([^)]*)s*/', '', $dirtyString);

        // 替换缩写(简单示例)
        $clean = str_replace(['(aq)', '(s)', '(l)'], ['', '', ''], $clean);

        return trim($clean);
    }
}

// 使用
echo DataCleaner::cleanChemicalName("Sulfuric Acid (98%)"); // 输出: Sulfuric Acid

然后,将这些清洗后的数据放入我们的词库中。


第八部分:模板引擎的艺术——不是写,是填空

虽然 AI 能写,但有时候我们需要排版。比如,我们要生成一个 HTML 页面。

不要把 HTML 标签直接塞进 Prompt 让 AI 写,太难伺候了。我们应该用 PHP 的模板引擎(比如原生 include 或者 Blade)写好骨架,把 AI 生成的内容像填空题一样填进去。

// templates/article.blade.php
<article>
    <header>
        <h1>{{ $title }}</h1>
        <div class="meta">
            <span>来源: {{ $source }}</span>
            <span>更新时间: {{ $date }}</span>
        </div>
    </header>

    <section class="safety-box">
        {{ $safety_content }}
    </section>

    <section class="content">
        {{ $ai_generated_body }}
    </section>

    <footer>
        <p>本文由 PHP AI System 自动生成,仅供参考,请以官方 MSDS 为准。</p>
    </footer>
</article>

PHP 的处理逻辑:

$template = file_get_contents('templates/article.blade.php');
$finalHtml = str_replace(
    ['{{ $title }}', '{{ $safety_content }}', '{{ $ai_generated_body }}'],
    [$title, $safetyBox, $aiBody],
    $template
);

这种“预制菜”+“现炒”的模式,既保证了格式的统一性,又保留了 AI 的内容创造力。


第九部分:为什么 PHP 这么适合干这事儿?

有人可能会说:“Python 才是 AI 的主流啊!”

没错,Python 确实更适合搞深度学习模型本身。但是,当你需要把 AI 嵌入到一个Web 系统、一个CMS 或者一个API 服务中时,PHP 就像那个穿着拖鞋也能把活干完的意大利面师傅。

  1. 性能: PHP 的 FPM 模型处理并发请求非常快,如果是生成静态 HTML 文章,甚至可以做成“命令行脚本”,跑完就关,资源占用极低。
  2. 生态: 你的化学品数据可能在 MySQL 里,你的用户在 Laravel 后台操作,你的文章要发到 WordPress 里。PHP 无缝连接所有这些。
  3. 上手快: 逻辑清晰。foreach 循环遍历词库,preg_match 炸掉幻觉,file_put_contents 保存文章。不需要像 Python 那样处理各种装饰器和异步 IO 的地狱模式。

第十部分:最后的拼图——错误处理与重试机制

AI API 不是万无一失的。网络抖动、Token 限流、AI 发疯,都会导致请求失败。

PHP 的 try-catch 和循环重试机制是必不可少的。

function retryGenerate($maxRetries = 3) {
    for ($i = 0; $i < $maxRetries; $i++) {
        try {
            // 尝试调用 AI
            $content = callOpenAI();
            if ($content) return $content;
        } catch (Exception $e) {
            // 记录日志:尝试次数 $i
            echo "出错了,重试中... ($i)n";
            sleep(2); // 睡眠 2 秒,别把 API 搞崩了
        }
    }
    throw new Exception("AI 疯了,尝试了 {$maxRetries} 次都失败了");
}

总结:从代码到化学的融合

你看,我们用 PHP 编写的这个系统,本质上就是一个智能的填空题机器

  1. 输入: 一堆混乱的 CAS 号、分子式和危险等级(数据层)。
  2. 清洗: 用正则和字符串函数把数据理顺(PHP 逻辑层)。
  3. 增强: 喂给 AI 一个精心设计的提示词,带着安全红线和结构要求(提示词工程)。
  4. 输出: 生成一篇结构严谨、术语规范、甚至带有幽默感的技术文章(组件化层)。

这不仅仅是一个脚本,这是一种工作流。它解放了化学家的双手,让他们从枯燥的文字录入中解脱出来,去思考更复杂的化学反应机理;它也解放了开发者的眼睛,让他们不再盯着屏幕数“H2SO4”和“H2SO4(99%)”的区别。

现在的代码已经把骨架搭好了,词库扩充了,组件也写好了。剩下的,就是把你数据库里那成千上万条化学品数据喂给这个 PHP 脚本。

去吧,用你的 PHP 代码,去炼制你的第一篇 AI 技术文章。如果生成了有毒有害的内容,那不是代码的问题,那是你喂给 AI 的“数据”有问题。多查查 PubChem,别让模型喝高了。

祝你的化学反应顺利!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注