# LLM 環境建置與開發 ## LLM 簡介 (大型語言模型) LLM(Large Language Model,大型語言模型)是一種基於深度學習技術的自然語言處理模型,它通過分析大量文本資料進行訓練,能夠理解和生成人類語言。 ## 目前主流別人已做好的 LLM ### GPT 系列(由 OpenAI 開發) * GPT-3.5(支持 ChatGPT) * GPT-4(更強大的多模態模型) * GPT-4o (OpenAI 最新的語言模型)` ### Claude 系列 * Claude 3 Opus * Claude 3.5 Sonnet * Claude 3.7 Sonnet ### Gemini 系列(由 Google 開發) * Gemini Ultra * Gemini Pro * Gemini Nano ### Llama 系列(由 Meta 開發的開源模型) * Llama 2 * Llama 3 ## 用別人訓練好的 LLM ![截圖 2025-04-07 下午5.01.40](https://hackmd.io/_uploads/SJMYVz-C1x.png) 通過 OpenAI API,開發者可以將 GPT 等 LLM 整合到自己的應用中,試著去做: 1. 客製化 AI 解決方案 2. 增強用戶體驗:提供智能交互和個性化服務 3. 自動化流程:減少人工處理,提高效率 4. 創新應用:開發全新的 AI 賦能產品和服務 ## 建立 Node + express 環境 1. 建立 Node.js 後端環境 2. 整合 OpenAI API 實現自然語言處理 3. Function Calling 技術處理結構化資料 ## 建立環境流程 1. 建立 Node 環境 (`npm init`) 2. 申請 OpenAI API 金鑰 ([官網](https://openai.com/)) 3. 安裝 NPM 套件 ``` npm init -y npm install axios dotenv express openai npm install --save-dev nodemon ``` ## Function calling 介紹 ([文件](https://platform.openai.com/docs/guides/function-calling?api-mode=responses))、response API([文件](https://platform.openai.com/docs/api-reference/responses/create)) ## 純 BMI 範例 ![截圖 2025-04-08 下午1.03.25](https://hackmd.io/_uploads/Sk5VAmz01x.png) ## input 跟 output 累積結果 ![截圖 2025-04-08 中午12.37.31](https://hackmd.io/_uploads/SJ3G_XMCyg.png) ```=javascript const express = require("express"); const OpenAI = require("openai"); require("dotenv").config(); // 初始化 Express 應用程式 const app = express(); const PORT = process.env.PORT || 3000; // 中間件設定 app.use(express.json()); app.use(express.urlencoded({ extended: true })); // 初始化 OpenAI const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY, }); /** * 計算 BMI * @param {number} height - 身高(公分) * @param {number} weight - 體重(公斤) * @returns {Object} - BMI 值 */ function calculateBMI(height, weight) { const heightInMeters = height / 100; const bmi = weight / (heightInMeters * heightInMeters); const roundedBMI = parseFloat(bmi.toFixed(2)); let category; if (bmi < 18.5) category = "體重過輕"; else if (bmi < 24) category = "正常體重"; else if (bmi < 27) category = "過重"; else if (bmi < 30) category = "輕度肥胖"; else if (bmi < 35) category = "中度肥胖"; else category = "重度肥胖"; return { bmi: roundedBMI, category: category }; } /** * 處理 AI 查詢 * @param {string} query - 客戶的查詢 * @returns {Promise<Object>} - 包含回答和相關數據 */ async function processAIQuery(query) { try { // 定義可用的 const tools = [ { type: "function", name: "calculate_bmi", description: "計算用戶的身體質量指數(BMI)", parameters: { type: "object", properties: { height: { type: "number", description: "用戶的身高(公分),例如 170", }, weight: { type: "number", description: "用戶的體重(公斤),例如 65", }, }, required: ["height", "weight"], additionalProperties: false, }, }, ]; // 準備輸入 const input = [{ role: "user", content: query }]; console.log(`處理查詢: "${query}"`); // 第一次 AI 回應 const response = await openai.responses.create({ model: "gpt-4o", instructions: `你是一個助手,可以回答 BMI 計算的問題。 當用戶詢問 BMI 相關問題時,呼叫 calculate_bmi 。 使用繁體中文回答,簡潔友善。`, input, tools, tool_choice: "auto", }); // 檢查是否有被呼叫 if (response.output && response.output.length > 0) { // 檢查是否是 BMI 計算 const bmiCall = response.output.find( (call) => call.name === "calculate_bmi" ); if (bmiCall) { // 計算 BMI const args = JSON.parse(bmiCall.arguments); const bmiResult = calculateBMI(args.height, args.weight); // 將結果傳回 AI input.push(bmiCall); input.push({ type: "function_call_output", call_id: bmiCall.call_id, output: JSON.stringify(bmiResult), }); // 獲取最終回答 const finalResponse = await openai.responses.create({ model: "gpt-4o", instructions: "根據 BMI 數據回答問題,提供健康建議,提供純文字。", input, }); return finalResponse.output_text; } } // 如果沒有呼叫,直接返回 AI 回答 return response.output_text; } catch (error) { console.error("處理查詢出錯:", error); throw error; } } // API 端點 app.post("/chat", async (req, res) => { try { const { message } = req.body; if (!message) { return res.status(400).json({ error: "請提供訊息內容" }); } const answer = await processAIQuery(message); if (!answer) { return res.status(500).json({ error: "無法生成回答" }); } res.json({ response: answer }); } catch (error) { console.error("API 錯誤:", error); res.status(500).json({ error: error.message || "處理查詢時發生錯誤" }); } }); // 啟動伺服器 app.listen(PORT, () => { console.log(`伺服器運行在 http://localhost:${PORT}`); }); ``` ## 範例二:BMI 檢查跟今天吃什麼餐廳 多增加一個 tools,讓 AI 自行判斷要呼叫哪個函式 範例 Code: ```=javascript const express = require("express"); const OpenAI = require("openai"); require("dotenv").config(); // 初始化 Express 應用程式 const app = express(); const PORT = process.env.PORT || 3000; // 中間件設定 app.use(express.json()); app.use(express.urlencoded({ extended: true })); // 初始化 OpenAI const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY, }); /** * 計算 BMI * @param {number} height - 身高(公分) * @param {number} weight - 體重(公斤) * @returns {Object} - BMI 值 */ function calculateBMI(height, weight) { const heightInMeters = height / 100; const bmi = weight / (heightInMeters * heightInMeters); const roundedBMI = parseFloat(bmi.toFixed(2)); let category; if (bmi < 18.5) category = "體重過輕"; else if (bmi < 24) category = "正常體重"; else if (bmi < 27) category = "過重"; else if (bmi < 30) category = "輕度肥胖"; else if (bmi < 35) category = "中度肥胖"; else category = "重度肥胖"; return { bmi: roundedBMI, category: category }; } /** * * @returns {Object} - 推薦的餐廳列表 */ function recommendFood() { const restaurants = [ "鼎泰豐", "添好運點心專門店", "乾杯燒肉", "藏壽司", "涓豆腐", "金子半之助", "屋馬燒肉", "貳樓餐廳", "樂福餐廳", ]; // 隨機選擇3家餐廳 const shuffled = restaurants.sort(() => 0.5 - Math.random()); const selected = shuffled.slice(0, 3); return { recommendations: selected }; } /** * 處理 AI 查詢 * @param {string} query - 客戶的查詢 * @returns {Promise<Object>} - 包含回答和相關數據 */ async function processAIQuery(query) { try { // 定義可用的 const tools = [ { type: "function", name: "calculate_bmi", description: "計算用戶的身體質量指數(BMI)", parameters: { type: "object", properties: { height: { type: "number", description: "用戶的身高(公分),例如 170", }, weight: { type: "number", description: "用戶的體重(公斤),例如 65", }, }, required: ["height", "weight"], additionalProperties: false, }, }, { type: "function", name: "recommend_food", description: "隨機推薦幾家餐廳", parameters: { type: "object", properties: {}, additionalProperties: false, }, }, ]; // 準備輸入 const input = [{ role: "user", content: query }]; console.log(`處理查詢: "${query}"`); // 第一次 AI 回應 const response = await openai.responses.create({ model: "gpt-4o", instructions: `你是一個助手,可以回答 BMI 計算和餐廳推薦的問題。 當用戶詢問 BMI 相關問題時,呼叫 calculate_bmi 。 當用戶詢問餐廳推薦時,呼叫 recommend_food 。 使用繁體中文回答,簡潔友善。`, input, tools, tool_choice: "auto", }); // 檢查是否有被呼叫 if (response.output && response.output.length > 0) { // 檢查是否是 BMI 計算 const bmiCall = response.output.find( (call) => call.name === "calculate_bmi" ); if (bmiCall) { // 計算 BMI const args = JSON.parse(bmiCall.arguments); const bmiResult = calculateBMI(args.height, args.weight); // 將結果傳回 AI input.push(bmiCall); input.push({ type: "function_call_output", call_id: bmiCall.call_id, output: JSON.stringify(bmiResult), }); // 獲取最終回答 const finalResponse = await openai.responses.create({ model: "gpt-4o", instructions: "根據 BMI 數據回答問題,提供健康建議,提供純文字。", input, }); return finalResponse.output_text; } // 檢查是否是餐廳推薦 const foodCall = response.output.find( (call) => call.name === "recommend_food" ); if (foodCall) { // 獲取餐廳推薦 const foodResult = recommendFood(); // 將結果傳回 AI input.push(foodCall); input.push({ type: "function_call_output", call_id: foodCall.call_id, output: JSON.stringify(foodResult), }); // 獲取最終回答 const finalResponse = await openai.responses.create({ model: "gpt-4o", instructions: "根據餐廳列表回答問題,介紹餐廳特色。", input, }); return finalResponse.output_text; } } // 如果沒有呼叫,直接返回 AI 回答 return response.output_text; } catch (error) { console.error("處理查詢出錯:", error); throw error; } } // API 端點 app.post("/chat", async (req, res) => { try { const { message } = req.body; if (!message) { return res.status(400).json({ error: "請提供訊息內容" }); } const answer = await processAIQuery(message); if (!answer) { return res.status(500).json({ error: "無法生成回答" }); } res.json({ response: answer }); } catch (error) { console.error("API 錯誤:", error); res.status(500).json({ error: error.message || "處理查詢時發生錯誤" }); } }); // 啟動伺服器 app.listen(PORT, () => { console.log(`伺服器運行在 http://localhost:${PORT}`); }); ``` ![截圖 2025-04-08 上午11.48.28](https://hackmd.io/_uploads/ry293MfCJe.png) ## 第二堂課程,介接天氣 API 做整合 ![截圖 2025-04-07 下午5.12.08](https://hackmd.io/_uploads/SyHlwMW0yl.png)