
使用 Langchain 和開源 Llama AI 在 Next.js 打造 AI Bot API Part 4 - AI產品推薦 API
上一篇,談到透過向量資料庫,我們讓AI 擁有自己的知識庫,這篇想要做產品推薦的API。
http://localhost:6333/dashboard
發現有趣事,居然動物和水餃相似度居然有 0.8,動物和HP筆電的相似度是0.06,難不成因為水餃是用動物做的嗎? XD
有趣的是真實的世界裡,水餃和動物,並不太相關,資料間的相似度是模型透過特定演算法得出,且看起來是不能修改,因此,必須透過其他方式解決查詢精準度的問題,以下是我整理出可行的方式 :
qdrantClient.filter({
collection_name: 'products_collection',
filter: {
must: [
{ key: 'price', range: { gte: 50, lte: 150 } }, // 價格範圍查詢
{ key: 'category', match: { value: '筆記型電腦' } } // 分類查詢
]
},
limit: 5
});
...
async function adjustSimilarity(results) {
for (let result of results) {
if (result.payload.productName === "動物") {
result.score *= 0.5; // 調整「動物」的相似度
}
}
return results;
}
// 進行相似度搜尋
const query = "水餃";
const topK = 10;
const results = await client.search(query, {
vector: queryEmbedding,
limit: topK,
});
// 調整特定結果中的相似度
const adjustedResults = await adjustSimilarity(results);
// 打印調整後的結果
console.log(adjustedResults);
...
...
const searchResults = await qdrantClient.search(collectionName, {
vector: vector,
limit: 5, // 查詢最相似的 5 條結果
});
const faqContext = searchResults
.map((result: any) => `Q: ${result.payload.question}\nA: ${result.payload.answer} score: ${result.score}`)
.join('\n\n');
// 初始化 ChatOllama
const model = new ChatOllama({
model: 'llama3.2',
temperature: 0,
maxRetries: 2,
baseUrl: 'http://localhost:11434',
});
// 使用 ChatOllama 根據用戶問題進行進一步分析
const response = await model.invoke(
`Here is a list of FAQs and their answers:\n\n${faqContext}\n\nBased on the question "${text}", which answer is the most relevant? Please choose the best one.`
);
...
import { OllamaEmbeddings } from '@langchain/ollama';
import { QdrantClient } from '@qdrant/js-client-rest'; // 引入 Qdrant 客戶端
import { NextApiRequest, NextApiResponse } from 'next';
// 初始化 Qdrant 客戶端
const qdrantClient = new QdrantClient({ url: 'http://localhost:6333' });
// 初始化 OllamaEmbeddings
const embeddings = new OllamaEmbeddings({
model: 'llama3.2',
baseUrl: 'http://localhost:11434',
});
// 定義集合名稱
const collectionName = 'product_vectors';
// 定義向量點的界面
interface VectorPoint {
id: number | string;
vector: number[];
payload: { text: string; price: number; rating: number; reviews: number };
}
// 定義產品數據
const products = [
{
ProductID: 1,
ProductName: 'Dell XPS 15',
Category: '筆記型電腦',
SalesUnits: 120,
Revenue: 240000,
Price: 2000,
Rating: 4.5,
Reviews: 300,
SaleDate: '1/1/2024',
LastRestockDate: '1/15/2024',
StockLevel: 50,
Supplier: 'Dell Inc.',
URL: 'https://www.dell.com/XPS15',
},
{
ProductID: 2,
ProductName: 'Logitech MX Master 3',
Category: '配件',
SalesUnits: 200,
Revenue: 180000,
Price: 900,
Rating: 4.8,
Reviews: 500,
SaleDate: '1/2/2024',
LastRestockDate: '1/12/2024',
StockLevel: 150,
Supplier: 'Logitech',
URL: 'https://www.logitech.com/MX3',
},
{
ProductID: 3,
ProductName: 'HP Spectre x360',
Category: '筆記型電腦',
SalesUnits: 180,
Revenue: 270000,
Price: 1500,
Rating: 4.7,
Reviews: 450,
SaleDate: '1/3/2024',
LastRestockDate: '1/14/2024',
StockLevel: 80,
Supplier: 'HP',
URL: 'https://www.hp.com/SpectreX360',
},
{
ProductID: 4,
ProductName: 'Lenovo ThinkPad X1',
Category: '筆記型電腦',
SalesUnits: 130,
Revenue: 195000,
Price: 1500,
Rating: 4.6,
Reviews: 400,
SaleDate: '1/4/2024',
LastRestockDate: '1/13/2024',
StockLevel: 70,
Supplier: 'Lenovo',
URL: 'https://www.lenovo.com/ThinkPadX1',
},
{
ProductID: 5,
ProductName: 'Apple MacBook Pro',
Category: '筆記型電腦',
SalesUnits: 250,
Revenue: 500000,
Price: 2000,
Rating: 4.8,
Reviews: 600,
SaleDate: '1/5/2024',
LastRestockDate: '1/10/2024',
StockLevel: 100,
Supplier: 'Apple',
URL: 'https://www.apple.com/MacBookPro',
},
{
ProductID: 6,
ProductName: 'Asus ROG Strix',
Category: '合式機',
SalesUnits: 90,
Revenue: 180000,
Price: 2000,
Rating: 4.5,
Reviews: 350,
SaleDate: '1/6/2024',
LastRestockDate: '1/6/2024',
StockLevel: 40,
Supplier: 'Asus',
URL: 'https://www.asus.com/ROGStrix',
},
{
ProductID: 7,
ProductName: 'Acer Predator Helios',
Category: '筆記型電腦',
SalesUnits: 75,
Revenue: 150000,
Price: 2000,
Rating: 4.4,
Reviews: 320,
SaleDate: '1/7/2024',
LastRestockDate: '1/9/2024',
StockLevel: 40,
Supplier: 'Acer',
URL: 'https://www.acer.com/PredatorHelios',
},
{
ProductID: 8,
ProductName: 'Dell UltraSharp',
Category: '顯示器',
SalesUnits: 300,
Revenue: 210000,
Price: 700,
Rating: 4.5,
Reviews: 500,
SaleDate: '1/8/2024',
LastRestockDate: '1/20/2024',
StockLevel: 200,
Supplier: 'Dell Inc.',
URL: 'https://www.dell.com/UltraSharp',
},
{
ProductID: 9,
ProductName: 'Logitech G Pro X',
Category: '鍵盤',
SalesUnits: 150,
Revenue: 300000,
Price: 200,
Rating: 4.7,
Reviews: 450,
SaleDate: '1/9/2024',
LastRestockDate: '1/12/2024',
StockLevel: 50,
Supplier: 'Logitech',
URL: 'https://www.logitech.com/GProX',
},
{
ProductID: 10,
ProductName: 'HP Omen',
Category: '筆記型電腦',
SalesUnits: 100,
Revenue: 150000,
Price: 1500,
Rating: 4.5,
Reviews: 370,
SaleDate: '1/10/2024',
LastRestockDate: '1/11/2024',
StockLevel: 60,
Supplier: 'HP',
URL: 'https://www.hp.com/Omen',
},
];
// 定義 Next.js API 處理器
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
try {
// 遍歷產品,將每個產品插入 Qdrant
for (const product of products) {
const text = `${product.ProductName} - ${product.Category}`;
// 生成文本的嵌入向量
const vector: number[] = await embeddings.embedQuery(text);
// 定義要插入的點
const points: VectorPoint[] = [
{
id: Date.now(), // 使用當前時間作為唯一 ID
vector: vector, // 插入生成的向量
payload: {
text, // 存放文本數據
price: product.Price,
rating: product.Rating,
reviews: product.Reviews,
},
},
];
// 檢查集合是否已存在,若不存在則創建
try {
const collectionExists = await qdrantClient.getCollection(collectionName);
if (!collectionExists) {
await qdrantClient.createCollection(collectionName, {
vectors: {
size: 1000, // 向量大小
distance: 'Cosine', // 距離度量使用 Cosine
},
});
}
} catch (error) {
console.log(`集合 ${collectionName} 不存在,正在創建...`);
await qdrantClient.createCollection(collectionName, {
vectors: {
size: vector.length,
distance: 'Cosine',
},
});
}
// 將向量插入 Qdrant
await qdrantClient.upsert(collectionName, { points });
}
res.status(200).json({ message: '所有產品向量已成功插入 Qdrant' });
} catch (error) {
console.error('插入向量時發生錯誤:', error);
res.status(500).json({ message: '插入向量時發生錯誤', error: error });
}
}
API 執行
curl -X GET http://localhost:3001/api/lang-chain/insert-products-vector-database
import { OllamaEmbeddings } from '@langchain/ollama';
import { QdrantClient } from '@qdrant/js-client-rest'; // 引入 Qdrant 客戶端
import { NextApiRequest, NextApiResponse } from 'next';
// 初始化 Qdrant 客戶端
const qdrantClient = new QdrantClient({ url: 'http://localhost:6333' });
// 初始化 OllamaEmbeddings
const embeddings = new OllamaEmbeddings({
model: 'llama3.2',
baseUrl: 'http://localhost:11434',
});
// 定義集合名稱
const collectionName = 'product_vectors';
// 定義 Next.js API 查詢處理器
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
try {
const { text, category } = req.body;
// 檢查是否有文本內容
if (!text) {
return res.status(400).json({ message: '文本內容為必填項' });
}
// 生成文本的嵌入向量
const vector: number[] = await embeddings.embedQuery(text);
// 構建搜索參數
const searchParams: any = {
vector: vector,
limit: 5, // 查詢的最大結果數量
};
// 如果提供了 category,則添加過濾條件
if (category) {
searchParams.filter = {
must: [
{
key: 'category',
match: { value: category }, // 動態應用類別過濾
},
],
};
}
// 使用生成的向量在 Qdrant 中查詢相似的向量
const searchResults = await qdrantClient.search(collectionName, searchParams);
// 格式化查詢結果,返回產品詳細信息
const formattedResults = searchResults.map((result: any) => {
const { payload, score } = result;
return {
productName: payload.text, // 使用生成時的產品名稱
price: payload.price, // 產品價格
rating: payload.rating, // 產品評分
reviews: payload.reviews, // 產品評論數量
similarityScore: score, // 相似度分數
};
});
res.status(200).json({ results: formattedResults });
} catch (error) {
console.error('查詢向量時發生錯誤:', error);
res.status(500).json({ message: '查詢向量時發生錯誤', error: error });
}
}
curl -X POST http://localhost:3001/api/lang-chain/query-products-vector-database \
-H "Content-Type: application/json" \
-d '{
"text": "幫我推薦一台筆電",
"category": "筆記型電腦"
}'
{
"results": [
{
"productName": "Acer Predator Helios - 筆記型電腦",
"price": 2000,
"rating": 4.4,
"reviews": 320,
"similarityScore": 0.7771975
},
{
"productName": "HP Spectre x360 - 筆記型電腦",
"price": 1500,
"rating": 4.7,
"reviews": 450,
"similarityScore": 0.7680249
},
{
"productName": "Dell XPS 15 - 筆記型電腦",
"price": 2000,
"rating": 4.5,
"reviews": 300,
"similarityScore": 0.7658051
},
{
"productName": "HP Omen - 筆記型電腦",
"price": 1500,
"rating": 4.5,
"reviews": 370,
"similarityScore": 0.7594989
},
{
"productName": "Apple MacBook Pro - 筆記型電腦",
"price": 2000,
"rating": 4.8,
"reviews": 600,
"similarityScore": 0.73970205
}
]
}
透過前面幾篇的實驗,因此我們得出,如何用Langchain 打造更精準的產品推薦的AI代理機器人。
代理 (Agent)
使用者輸入 > AI解析用戶的意圖,依據動態路由,AI決定採用什麼工具 > 執行自訂工具(產品推薦) > 回傳結果給最終用戶。
客製產品推薦工具 (Custom Tool)
產品推薦工具的實作,則可以讓AI依據使用者輸入,解析成產品分類、產品價錢、品牌的查詢條件,最後查詢向量資料庫。

