---
title: "利用 Azure AI、LangChain 搭配 Next.js 提升 SEO 效益"
description: "說明如何結合 Azure OpenAI、LangChain 與 Next.js generateMetadata，自動為電商產品頁生成 SEO 標題、描述與關鍵字，並快取到 Redis 節省 AI 用量。"
canonical_url: "https://blog.markkulab.net/post/generate-seo-metadata-by-azure-ai"
author: "Mark Ku"
author_url: "https://blog.markkulab.net/author/mark-ku"
site: "Mark Ku's Blog"
date_published: "2024-06-03 01:01:35 +0800"
category: "AI"
tags: ["ai", "seo", "azure openai", "langchain", "nextjs", "metadata", "redis", "ecommerce"]
language: "zh-TW"
license: "CC BY 4.0"
license_url: "https://creativecommons.org/licenses/by/4.0/"
attribution: "轉載或引用請註明作者並附上原文連結"
---

# 利用 Azure AI、LangChain 搭配 Next.js 提升 SEO 效益

## 前言
我們都知道AI 擅長文字處理，但礙於我們的德國網站運營規模相當的小，缺乏足夠的人力來維護SEO資料，我們利用AI的文字處理能力來自動生成SEO數據（包括標題、描述和關鍵字）。這種方法不僅節省了大量人力資源，而且通過將頁面預渲染時的數據傳送給AI處理，提升了網站的搜索引擎優化效率。

## AI 帶來的變革
Bill Gates 曾說許多軟體「仍然相當愚蠢」，因為它們需要大量的人工輸入才能發揮作用，且他認為人工智慧 (AI) 代理，可以在未來五年內改變這一現狀。  

從過去的滑鼠鍵盤輸入及僅接受明確的指令，到提供不同的交互方式，檔案、圖片、聲音、影像及讀懂人類模糊的指令，AI 的出現改變了人與電腦的互動方式，人與電腦的互動方式改變，所有的應用程式都值得用AI 改寫一次。

## 這篇使用的技術：Next.js、Azure Open AI 與 LangChain

* Next.js：一個基於React的框架，專門用於構建快速的靜態和動態網頁應用程序，它允許開發者在框架內直接實現API路由，方便進行後端開發。
* Azure Open AI：大家都知道微軟投資了 OpenAI，當發佈新模型時，身為授權夥伴的微軟，也會同步取得這些模型，封裝成為企業提供客製化的AI 服務。
* LangChain：這是一個整合多個大型AI模型的框架，輕易就能調用各種大型語言的模型， 提供模版，解析器、動態路由，通常搭配 Fast api 就能和其他異質系統整合。

## Azure Open AI 的運作原理
AI 之所以能夠讀懂上下文，其實每次都要將對話回傳回去，透過這個機制，我們能夠在請求AI前封裝AI， 扮演某特定的角色及可以做什麼不可以做什麼。

```
 You are an SEO expert. Based on the page description provided below, generate an SEO-optimized title, meta description, and keywords. Ensure that the title is engaging and concise, the meta description summarizes the product effectively while enticing users to learn more, and the keywords are relevant to the product's features and market segment. Additionally, translate all content into the language specified by the given language code.
        Company:{companyDescription}
        Ecommerce Page Description: {description}
        Translate Target Language Code: {langCode}
        FormatInstructions: {formatInstructions}
```

## 生成 SEO Meta AI Api的設計概念
1. 頁面請求處理：首先，先在 Next.js 建立一個 API ，並且傳入頁面描述及要翻譯的語言
2. 語言處理： 接著，利用 LangChain 操作 Azure Chat OpenAI 根據傳入的頁面描述生成 SEO 優化的標題、描述和關鍵詞
3. 儲存結果：再來，依據頁面 Slug 儲存關鍵詞給下次預渲染使用，同時也節省 Azure AI 的用量。
4. 結果回傳： 最後將，生成的SEO標籤資料將被回傳並用於網頁的預渲染，進而在搜尋引擎中達到更好的排名。

透過結合 Next.js 的前端技術、Azure AI 的語言生成能力與 LangChain 的結構化輸出，我們能夠創建一個高效且自動化的流程來優化網站的 SEO 表現，這種方法不僅節省了人力資源，也因其精確和針對性的SEO 標籤生成，而提高了網站在搜尋引擎中的能見度和排名。

## 自動化生成符合 SEO 標籤資料

在 Next.js 中部署的 `generateSEOMetadata` 函數利用 Azure Chat OpenAI 和 LangChain 處理產品描述，並生成相應的標題、描述和關鍵詞。LangChain 的輸出解析器（Output Parser）確保從 AI 模型接收到的回應符合 SEO 的需求，只提取最關鍵的信息。

## Next js 程式碼　
```
import { BaseOutputParser } from '@langchain/core/output_parsers';
import { ChatPromptTemplate } from '@langchain/core/prompts';
import { AzureChatOpenAI } from '@langchain/openai';
import { LogLevel } from '@utils/log/const-logging';
import { serverSideLog } from '@utils/log/server-side-log';
import { genOnceEncodedURI } from '@utils/product/gear';
import { RedisBase } from '@utils/redis/redis-base';
import { NextApiRequest, NextApiResponse } from 'next';


class CustomOutputParser extends BaseOutputParser<string[]> {
    async parse(output: any) {
        const result = output.replaceAll('```json', '').replaceAll('```', ''); // for gpt4
        const json = await JSON.parse(result);

        return json;
    }

    getFormatInstructions() {
        return 'Only the title, description and keywords of the json structure are returned. example :{"title":"","description":"","keywords":""} Please delete any other unnecessary information. Such as python code, Python Flask API, etc.  Give me json result. Do not send back any other information such as python code, Python Flask API, etc.';
    }
}

async function generateSEOMetadata(description: string, langCode: string) {
    // https://{InstanceName}.openai.azure.com/openai/deployments/my-openai-deployment/
    const model = new AzureChatOpenAI({
        azureOpenAIApiKey: 'YOUR_AZURE_OPENAI_API_KEY',
        azureOpenAIApiDeploymentName: 'YOUR_DEPLOYMENT_NAME', // gpt4
        azureOpenAIApiInstanceName: 'YOUR_INSTANCE_NAME',　
        azureOpenAIApiVersion: '2024-02-01', // '2024-02-01',
        temperature: 0,　// 控制模型生成的隨機性或創造性
        maxTokens: 500, // 指定模型生成的回應中最大可用的 token（詞的數量)
    });

    const prompt = ChatPromptTemplate.fromTemplate(
        `
        You are an SEO expert. Based on the page description provided below, generate an SEO-optimized title, meta description, and keywords. Ensure that the title is engaging and concise, the meta description summarizes the product effectively while enticing users to learn more, and the keywords are relevant to the product's features and market segment. Additionally, translate all content into the language specified by the given language code.
        Company:{companyDescription}
        Ecommerce Page Description: {description}
        Translate Target Language Code: {langCode}
        FormatInstructions: {formatInstructions}
        `
    );
    const parser = new CustomOutputParser();

    const companyDescription = `NXPower GmbH markets iBUYPOWER® Computer products in Germany, aiming to offer high-quality products at reasonable prices without compromising service.
We produce custom-made PC systems tailored to individual or business needs, ensuring the best possible system within your budget. Each PC is built with care, reflecting our passion and profession.
Every custom PC includes a 3-year pickup and return warranty, extensive testing, and a 24-hour burn-in test. Our sales team ensures you only pay for components you need, and our top IT technicians provide quick assistance for any issues.
We create dream computers to impress and delight you for years. Partnering with experienced and successful online retailers, we benefit from excellent support.
`;

    const chain = prompt.pipe(model).pipe(parser);

    const response = await chain.invoke({
        companyDescription: companyDescription,
        description: description,
        langCode: langCode,
        formatInstructions: parser.getFormatInstructions(),
    });
    
    return response;
}


export default async function handler(req: NextApiRequest, res: NextApiResponse) {
    try {
        const { description = '', slug = '', forceUpdate = false, langCode = 'en' } = req.query;

        if (!description || !slug) {
            return res.status(400).json({ error: 'Description must be a valid string.' });
        }

        const redis = new RedisBase();
        const seoKey = 'SeoMata:' + langCode + ':' + genOnceEncodedURI(slug as string);

        const seoResult = await redis.get(seoKey);

        if (seoResult && !forceUpdate) {
            return res.status(200).json(JSON.parse(seoResult));
        }

        // Process the description with Langchain and Azure AI
        const metadata = await generateSEOMetadata(description as string, langCode as string);

        await redis.setCacheKey(seoKey, JSON.stringify(metadata), -1);
        // Save the metadata by slug to the database

        // return data for pre-rendering
        res.status(200).json(metadata);
    } catch (err) {
        serverSideLog('SEO Schema Error' + JSON.stringify(err), LogLevel.Error);
        return res.status(500).json({ error: err });
    }
}

```

在 Next 14 app route , 在頁面中的 generateMetadata 呼叫封裝好的　Ａｚｕｒｅ AI 的 api 
```
export async function generateMetadata({ params }: Props): Promise<Metadata> {
    // 構建URL

    const pathname = new URL(headers().get('x-url')!).pathname;

    const productData: IStoreModel | null = await getStoreModelData(params.locale, params.slug);

    const description = generateTitleAndDescription(productData);

    if (description === '') {
        return generateDefaultMetadata(params.locale, params.slug);
    }

    const imageUrl = (productData && getAbsoluteImageUrl(productData.desc.info.image)) || '';

    try {
        const baseUrl = process.env.NEXT_PUBLIC_BASE_URL;
        const queryParams = new URLSearchParams({
            description: description,
            langCode: params.locale,
            slug: pathname,
            // forceUpdate: 'true',
        });

        const url = `${baseUrl}/api/lang-chain/seo-schema?${queryParams.toString()}`;

        // 獲取數據
        const response = await fetch(url);
        const seoMeta = await response.json();

        const image: ImageProps = {
            url: imageUrl,
            width: 640,
            height: 640,
            alt: seoMeta.title,
        };

        // 返回Metadata
        return {
            title: seoMeta.title,
            keywords: seoMeta.keywords,
            description: seoMeta.description,
            openGraph: {
                title: seoMeta.title,
                description: seoMeta.description,
                ...(imageUrl && {
                    images: image,
                }),
            },
            twitter: {
                title: seoMeta.title,
                description: seoMeta.description,
                card: 'summary_large_image',
            },
        };
    } catch (e) {
        return generateDefaultMetadata(params.locale, pathname);
    }
}

```
並在　Middleware 取得slug，並在header中傳遞
```
export default function middleware(request: NextRequest) {
    const pathname = request.nextUrl.pathname;

    request.headers.set('x-url', request.nextUrl.href);
      

    return nextIntlMiddleware(request);
}
```

PS. Langchain在JS 版本的，並不是太穩定，文件蠻多都有誤的或功能和python 比有少的，且在不同模型中會跑額外的字元，得自定解析器去處理，生態也不是這麼完整，如果複雜情境使用 python 版本會比較好。  

## How to use
```
http://ｗｗｗ.xxxx.de/api/lang-chain/seo-schema?description={page description }&langCode={translate to lang code}
```

## Example
```
http://ｗｗｗ.xxxx.de/api/lang-chain/seo-schema?description=Case:%20NZXT%20H5%20Flow%20Gaming%20Geh%C3%A4use%20-%20Schwarz%20Processor:%20AMD%20Ryzen%205%205600X%20Processor%20(6x%203.7GHz/32MB%20L3%20Cache)%20Memory:%2016GB%20DDR4/3200MHz%20Memory(G.Skill%20,Corsair,Kingston)%20Storage:%20Video%20Card:%20NVIDIA%20GeForce%20RTX%203050%20-%208GB%20GDDR6X%20(VR-Ready)%20Motherboard:%20ASRock%20B450%20PRO%204%20ATX%20USB%203.1,%20SATA3,%201x%20M.2&langCode=tw
```

## Result 
```
{"title":"頂級遊戲體驗：NZXT H5 Flow 黑色遊戲機殼配備 AMD Ryzen 5 與 RTX 3050","meta_description":"探索 NZXT H5 Flow 遊戲機殼，搭載 AMD Ryzen 5 5600X 處理器、16GB DDR4 記憶體、NVIDIA GeForce RTX 3050 顯示卡，為您的遊戲體驗帶來革命性提升。立即了解更多。","keywords":"NZXT H5 Flow, 遊戲機殼, AMD Ryzen 5 5600X, 16GB DDR4, NVIDIA GeForce RTX 3050, VR準備, ASRock B450 PRO 4, 高性能遊戲電腦"}
```

---

## 關於本文與作者

本文出自 [Mark Ku's Blog](https://blog.markkulab.net/post/generate-seo-metadata-by-azure-ai)

授權條款： [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/) — 轉載或引用請註明作者並附上原文連結

### 關於作者

**[Mark Ku](https://blog.markkulab.net/author/mark-ku)** — Software Solution Provider

- 10+ 年資深軟體工程師，現為 AI 應用 Builder
- 專注大型平台架構設計，從北美電商到AI SaaS訂閱收費系統
- 結合 AI Agent 與自動化，打造高效可演進的產品技術基礎

### 作者開發的免費工具

以下工具皆可免費使用：

- [免費 PDF 簽名工具](https://blog.markkulab.net/tools/pdf-sign): 線上 PDF 簽名工具，瀏覽器內完成手繪、打字、上傳簽名，可拖曳放置、縮放、下載。所有處理都在你的裝置完成，檔案不會上傳。
- [VS Code Refactory](https://blog.markkulab.net/tools/refactory): Refactory 是一款 VS Code 重構擴充套件：34 個重構動作、37 條 code smell 檢查、Code Health 儀表板、18 種語言、534 支測試。懂你的專案慣例：介面放哪、DI 註冊寫在哪、'use client' 該不該加；還會用 git 修改頻率 × 複雜度排出「該先修哪個檔案」，並一鍵把壞味道交給你自己電腦上的 Claude Code 修。免費使用，原始碼不離開你的機器。
- [DB-Kit 資料庫管理工具](https://blog.markkulab.net/tools/db-kit): DB-Kit 是一個用 Tauri + Rust + React 打造的輕量跨平台資料庫管理工具，用單一一致的介面同時管理 MySQL、MariaDB、PostgreSQL、SQL Server、Oracle、SQLite、MongoDB、Redis、Kafka、Elasticsearch 與 RabbitMQ 十一種資料來源：連線密碼以 OS keychain 加密、SSH Tunnel、完整 CRUD、視覺化查詢建構器、多結果集同時顯示、跨連線資料傳輸與比對同步、Excel / CSV 匯入匯出、執行計畫視覺化、ER 圖、排程備份、SQL 壓力測試（p50～p99 延遲百分位）、15 條規則的 SQL 審查、Kafka 訊息瀏覽與監控告警；繁中 / 英文雙語介面，內建 AI 助手（自然語言生成 SQL、AI 審查與調校建議）與命令列工具 dbk。免費開源（MIT），提供 Windows / macOS / Linux 安裝檔。
- [VS Code Super Mermaid](https://blog.markkulab.net/tools/super-mermaid): Super Mermaid 是一款 VS Code 擴充套件：開箱即用的漂亮 Mermaid 圖表，自動上色、即時預覽、滑鼠平移縮放、PNG / SVG 高解析匯出，內建 21 種範本與多種主題。免費開源（MIT）。
- [React Super Mermaid](https://blog.markkulab.net/tools/react-super-mermaid): react-super-mermaid 是一個開源 React 元件庫：一行 <MermaidViewer> 即可渲染漂亮的 Mermaid 圖表，內建 colorful / sketch 主題、平移縮放、圖內搜尋、SVG / PNG 高解析匯出。輕量、SSR 安全、完整 TypeScript 型別。免費開源（MIT）。
- [Jira / Confluence Super Mermaid](https://blog.markkulab.net/tools/jira-super-mermaid): Atlassian Forge app：在 Jira issue 與 Confluence 內文直接寫 Mermaid 語法，畫流程圖、時序圖、狀態機與甘特圖。11 種圖表、SVG / PNG 匯出、明暗主題、完整中日韓文字支援。取得 Runs on Atlassian 資格：圖表存在你自己的站台，app 不呼叫任何第三方服務。免費，即將上架 Atlassian Marketplace。
- [Mermaid 線上預覽](https://blog.markkulab.net/tools/mermaid-preview): 在瀏覽器裡寫 Mermaid、即時看圖，整張圖表壓進網址就能分享。免註冊、不上傳伺服器，相容 mermaid.live 的分享連結。
- [React Intl Phone Number](https://blog.markkulab.net/tools/react-intl-phone-number): react-intl-phone-number 是一個開源 React 元件：framework-agnostic、不依賴 antd，提供 E.164 進出、可搜尋國旗 / 國碼下拉、可配置驗證等級（strict / mobile-strict / loose）、可主題化 CSS 與 i18n，電話邏輯由 google-libphonenumber 驅動。輕量、完整 TypeScript 型別。免費開源（MIT）。
- [Uptime Kuma Cluster](https://blog.markkulab.net/tools/uptime-kuma-cluster): 把單機版 Uptime Kuma 改造成高可用叢集：OpenResty + Lua 智慧負載平衡、MariaDB 共享狀態、健康檢查與自動 Failover，附叢集管理 REST API，一行 Docker Compose 啟動。免費開源（MIT）。
- [特教專案](https://blog.markkulab.net/education): 為特殊教育學生製作的學習教材

### 每日 Podcast

- [科技新鮮事](https://blog.markkulab.net/category/tech-news): 每日精選 AI 與科技趨勢，透過語音摘要快速掌握最新技術動態，涵蓋 AI 應用、軟體架構、DevOps 與工程實戰。 — RSS: https://blog.markkulab.net/feed.xml
- [AI股市蝦聊](https://blog.markkulab.net/category/ai-stock-chat): 每個交易日用 AI 分析台股盤勢，以雙人對話聊當天的盤中觀察與隔日預測。 — RSS: https://blog.markkulab.net/ai-stock-chat/feed.xml

### 電子報

[訂閱電子報](https://blog.markkulab.net/subscribe) — 第一時間收到新文章通知，無垃圾信、隨時可取消訂閱。
