使用 Langchain 和開源 Llama AI 在 Next.js 打造 AI Bot API Part 1 - 從了解 lanchain 開始
先前我利用Langchain 來優化德國某電子商務網站的 SEO,當時使用的是 Azure AI,不過,由於月底總是預算耗盡,我開始尋找替代方案,最終找到Facebook 開源的AI 模型 llama 替代 。
其實我有用了 Python 和 Langchain 寫了一個 AI bot 的算命機器人,但考慮到團隊成員主要精通 JavaScript,而不是 Python,為了統一的技術棧,大家比較能相互備援,我決定嘗試使用 Next 的API 開發這個 AI 相關功能,最後做成 AI Agent BOT API。
Langchain 是一個可以整合多種大型 AI 模型的框架,透過它可以輕鬆調用各類大型語言模型。這個框架提供了模版、解析器、動態路由,並且可以與 Python 、node 、C# 後端語言整合。
我們都了解AI對文字非常擅長,而且非常有效率,應用程式和AI 互動,可以做到,很多的應用延伸,像是:
如果使用情境很單純,只需要與大型語言模型單純一問一答,那麼,我覺得可以不需要使用到langchain ,但如果你希望依據使用者輸入的語意讓 AI 決定要做什麼事,或是需要在一次使用請求中和大型模型語言交互多次,像是從自己的向量資料庫查不到相關資料,再與外部api 交換,那麼 langchain 這個使用情境,就非常適合。
npm install langchain @langchain/azure-openai @langchain/ollama @langchain/openai --save
import { AzureChatOpenAI } from '@langchain/openai'; import { NextApiRequest, NextApiResponse } from 'next'; export default async function handler(req: NextApiRequest, res: NextApiResponse) { const model = new AzureChatOpenAI({ azureOpenAIApiKey: process.env.AZURE_OPENAI_API_KEY, azureOpenAIApiDeploymentName: 'gpt-4', azureOpenAIApiInstanceName: 'your-instance-name', azureOpenAIApiVersion: '2023-03-15-preview', temperature: 0, // 用來調控AI 的隨機性 maxTokens: 500, }); try { const result = await model.invoke('為一個鞋店起一個好的名字。'); res.status(200).json({ result }); } catch (error) { res.status(500).json({ error: 'Failed to generate name' }); } }
現在透過 ChatOllama 來生成鞋店的店名 Langchain 是不是很方便,它把界面設計的很好,直接把 AzureChatOpenAI 換成 ChatOllama,後程式也都不用改,就把模型換掉
import { ChatOllama } from '@langchain/ollama'; import { NextApiRequest, NextApiResponse } from 'next'; export default async function handler(req: NextApiRequest, res: NextApiResponse) { const model = new ChatOllama({ model: 'llama3.2', temperature: 0, maxRetries: 2, baseUrl: 'http://localhost:11434', }); try { const result = await model.invoke('為一個鞋店起一個好的名字。'); const content = JSON.stringify(result.content); res.status(200).json(content); } catch (error) { res.status(500).json({ error: 'Failed to generate name' }); } }
import { ChatOllama } from '@langchain/ollama'; import { NextApiRequest, NextApiResponse } from 'next'; export default async function handler(req: NextApiRequest, res: NextApiResponse) { const { brandName, modelVersion = 'llama3.2', temperature = 0 } = req.body; const model = new ChatOllama({ model: modelVersion, temperature, maxRetries: 2, baseUrl: 'http://localhost:11434', }); try { const result = await model.invoke(`為一個鞋店起一個好的名字:${brandName}`); const content = JSON.stringify(result.content); res.status(200).json(content); } catch (error) { res.status(500).json({ error: 'Failed to generate name' }); } }
import { StringOutputParser } from '@langchain/core/output_parsers'; import { ChatPromptTemplate } from '@langchain/core/prompts'; import { ChatOllama } from '@langchain/ollama'; import { NextApiRequest, NextApiResponse } from 'next/types'; // 定義 API route export default async function handler(req: NextApiRequest, res: NextApiResponse) { const { modelVersion = 'llama3.2', temperature = 0 } = req.body; try { const question = 'What is the weather in Taipei?'; // 1. 初始化模型 const model = new ChatOllama({ model: modelVersion, temperature, maxRetries: 2, baseUrl: 'http://localhost:11434', }); // 2. 定義一個處理步驟的 prompt const prompt = ChatPromptTemplate.fromMessages([['human', 'Ask the weather for {question}']]); // 2. 定義 output parser const outputParser = new StringOutputParser(); // 3. 使用 pipe 來串聯步驟:prompt -> model -> parser const pipeChain = prompt.pipe(model).pipe(outputParser); // 4. 執行 chain 並取得結果 const weatherResponse = await pipeChain.invoke({ question }); // 5. 回應 API 結果 res.status(200).json({ weather: weatherResponse }); } catch (error) { res.status(500).json({ message: 'Internal Server Error' }); } }
import { ChatOllama } from '@langchain/ollama'; import { APIChain } from 'langchain/chains'; import { NextApiRequest, NextApiResponse } from 'next/types'; const OPEN_METEO_DOCS = `api document ...`; // Next.js API route export default async function handler(req: NextApiRequest, res: NextApiResponse) { const { question, modelVersion = 'llama3.2', temperature = 0 } = req.body; try { const model = new ChatOllama({ model: modelVersion, temperature, maxRetries: 2, baseUrl: 'http://localhost:11434', }); const chain = APIChain.fromLLMAndAPIDocs(model, OPEN_METEO_DOCS, { headers: { // API-specific headers if required }, }); const weatherResponse = await chain.invoke({ question }); res.status(200).json({ weather: weatherResponse }); } catch (error) { console.error('Error fetching weather:', error); res.status(500).json({ message: 'Internal Server Error' }); } }