[course] Build AI-Powered Apps with OpenAI and Node.js
此篇為 Advanced AI Application Development with OpenAI and Node.js | Hands-On Course with Scott Moss @ FEM 之課程筆記整理,非原創內容,資料來源:
- ai-nodejs @ GitHub
- AI App Node.js @ notion
FEM-openai-nodejs @ pjchender GitLab
Intro to LLMS
LLM (Large Language Model) 可以想成是一個超級聰明的文字機器,它們被用極大量的資料訓練,一次可以理解和用人類可以理解的方式輸出。LLM 其實就像是 ChatGPT 的大腦。
Getting Started
import 'dotenv/config';
import OpenAI from 'openai';
const openai = new OpenAI();
const results = await openai.chat.completions.create({
model: 'gpt-3.5-turbo',
// temperature 越高,openAI 就會發揮越多創意
temperature: 0,
messages: [
{
// role:
// - system: the background of the AI
// - user: human talking to the AI
// - assistant: AI talking to the human
role: 'system',
content: 'You are an AI assistant, answer any questions to the best of your ability.',
},
{
role: 'user',
content: 'Hi! ',
},
],
});
console.log(results);
// {
// id: 'chatcmpl-8bk5JfZ1c3btxV6uryDVUTIGEjYln',
// object: 'chat.completion',
// created: 1704005977,
// model: 'gpt-3.5-turbo-0613',
// choices: [
// {
// index: 0,
// message: [Object],
// logprobs: null,
// finish_reason: 'stop'
// }
// ],
// usage: { prompt_tokens: 30, completion_tokens: 9, total_tokens: 39 },
// system_fingerprint: null
// }
Simple Chat UX
import { openai } from './openai.js';
import readline from 'node:readline';
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
const newMessage = async (history, message) => {
const results = await openai.chat.completions.create({
model: 'gpt-3.5-turbo',
messages: [...history, message],
});
return results.choices[0].message;
};
const formatMessage = (userInput) => ({
role: 'user',
content: userInput,
});
const chat = () => {
const history = [
{
role: 'system',
content: 'You are an AI assistant. Answer questions or else!',
},
];
const start = () => {
rl.question('You: ', async (userInput) => {
if (userInput.toLowerCase() === 'exit') {
rl.close();
return;
}
const message = formatMessage(userInput);
const response = await newMessage(history, message);
history.push(message, response);
console.log(`\n\nAI: ${response.content}\n\n`);
start();
});
};
start();
};
console.log('Chatbot initialized. Type "exit" to quit.');
chat();
和 LLM 互動的邏輯
Embeddings and Vectors
Introducing text and code embeddings
比起文字電腦更擅長處理數字, 為了讓電腦學習單字和他們的意義,我們將文字轉換成一系列的數字(vectors), 這一系列 LLM 可以理解的向量,就稱作 embeddings。
Embeddings are the numerical vectors that represent text in a format understandable by machine learning models.
所以我們會做的事情是:
- 先將文字(內容可以來自影片、文件、書籍等)轉成 Langchain 的 Document
- 把 Document 轉成 Embeddings
- 建立一個 Vector Store
- 透過這個 Vector Store 把使用者 query 的內容和裡面的資料做比對
Semantic search and Langchain
Creating a Semantic Search
Semantic Search 的邏輯是將要被索引的內容,轉成一連串的數字(向量),又稱作 Embedding,接著把它保存成一個叫做 Vector Store 的東西;再來,把使用者輸入的 query 一樣轉成向量;最後,將這個向量和 Vector Store 裡的其他向量做比較,找到 Vector Store 中最靠近這個 query 的資料並回傳。
Search 的這個過程並不需要對 OpenAI 下任何 prompt。
以下程式碼使用的 LangChain 舊版 import 路徑(如 langchain/document、langchain/vectorstores/memory、langchain/embeddings/openai)已在 LangChain v0.2+ 中棄用。新版應改用 @langchain/openai(for OpenAIEmbeddings)與 langchain/vectorstores/memory(從 @langchain/community)。請參考 LangChain Migration Guide。
import { openai } from './openai.js';
import { Document } from 'langchain/document';
import { MemoryVectorStore } from 'langchain/vectorstores/memory';
import { OpenAIEmbeddings } from 'langchain/embeddings/openai';
const movies = [
{
id: 1,
title: 'Stepbrother',
description: `Comedic journey full of adult humor and awkwardness.`,
},
// ...
];
// store 會 indexed 我們的 documents
const createStore = () =>
MemoryVectorStore.fromDocuments(
movies.map(
(movie) =>
new Document({
// 希望轉成向量的文字內容
pageContent: `Title: ${movie.title}\n${movie.description}`,
// 被 query 到後可以用這個取得結構化的資料
metadata: { source: movie.id, title: movie.title },
}),
),
new OpenAIEmbeddings(),
);
/**
*
* @param {string} query:使用者輸入的 query
* @param {number} count:要回傳幾筆結果
* @returns
*/
const search = async (query, count = 1) => {
const store = await createStore();
/**
* similaritySearch 會把 query 轉成向量,然後跟 store 裡面的 documents 做比較
*/
return store.similaritySearch(query, count);
};
console.log(await search('a movie that will make me feel like I am crazy'));
Document QA
什麼是 Document QA
QA system 會根據它的資料,針對你的問題給予回覆,你可以想像成 AI 幫你把文章訊息閱讀完後,根據這篇文章內容來回答你的提問,因此它的精確性是更高的。和 Search Engine 不同,Search Engine 會以條列的方式給予回應,但 QA System 則會回覆精確的答案。
Document QA 適用在使用者碰到某一個問題,不需要一個一個閱讀文章內容,而是直接得到解法或建議的作法,適合用在官方文件、Customer Support 的網站、或者請它幫你閱讀文章後回答你的問題。