TypeScript版LlamaIndex來襲!用Agentic RAG構建智能AI代理,效率與隱私雙提升! 原創
想象一下,有一個私人研究助手不僅能理解你的問題,還能智能地決定如何找到答案。對于某些問題,它會深入你的文檔庫中查找答案,而對于其他問題,它則會生成富有創意的回應。這聽起來是不是很酷?其實,這一切都可以通過使用 Agentic RAG(檢索增強型生成) 和 LlamaIndex TypeScript 系統來實現。
無論你是想創建一個文獻分析系統、技術文檔助手,還是任何知識密集型應用,本文介紹的方法都將為你提供一個實用的基礎框架。接下來,我們將通過一個實際的動手項目,帶你一步步構建這樣一個系統,從設置本地模型到實現專門的工具,最終交付令人驚嘆的結果。
為什么選擇 TypeScript?
TypeScript 是一種強大的編程語言,它為構建基于 LLM(大型語言模型)的 AI 應用提供了諸多優勢:
- 類型安全:TypeScript 的靜態類型檢查可以在開發過程中捕捉錯誤,而不是等到運行時才發現。
- 更好的 IDE 支持:自動補全和智能提示讓開發過程更快捷。
- 提高可維護性:類型定義讓代碼更易讀,也更具自文檔性。
- 無縫 JavaScript 集成:TypeScript 可以與現有的 JavaScript 庫無縫對接。
- 可擴展性:隨著你的 RAG 應用不斷擴展,TypeScript 的結構化特性有助于管理復雜性。
- 框架支持:Vite、NextJS 等強大的 Web 框架與 TypeScript 無縫連接,讓構建基于 AI 的 Web 應用變得輕松且可擴展。
LlamaIndex 的優勢
LlamaIndex 是一個強大的框架,用于構建基于 LLM 的 AI 應用。它提供了以下優勢:
- 簡化數據加載:通過 LlamaParse,可以輕松加載和處理本地或云端的文檔。
- 向量存儲:內置支持嵌入和檢索語義信息,支持與 ChromaDB、Milvus、Weaviate 和 pgvector 等行業標準數據庫的集成。
- 工具集成:可以創建和管理多個專業工具。
- 代理插件:你可以輕松構建或插入第三方代理。
- 查詢引擎靈活性:可以根據不同的用例定制查詢處理。
- 持久化支持:可以保存和加載索引,提高重復使用的效率。
什么是 Agentic RAG?
在深入實現之前,我們先來了解一下 Agentic RAG 是什么。RAG(檢索增強型生成)是一種技術,通過從知識庫中檢索相關信息來增強語言模型的輸出,然后利用這些信息生成更準確、更符合事實的回應。而 Agentic 系統則涉及 AI 根據用戶查詢決定采取哪些行動,有效地作為一個智能助手,選擇合適的工具來滿足請求。
Agentic RAG 系統結合了這兩種方法,創建了一個既能從知識庫中檢索信息,又能根據需要使用其他工具的 AI 助手。根據用戶問題的性質,它會決定是使用內置知識、查詢向量數據庫,還是調用外部工具。
開發環境搭建
安裝 Node.js
在 Windows 上安裝 Node.js 的步驟如下:
# 下載并安裝 fnm
winget install Schniz.fnm
# 下載并安裝 Node.js
fnm install 22
# 驗證 Node.js 版本
node -v # 應輸出 "v22.14.0"
# 驗證 npm 版本
npm -v # 應輸出 "10.9.2"
其他系統可以參考 官方文檔。
從簡單數學代理開始
讓我們先從一個簡單的數學代理開始,了解 LlamaIndex TypeScript API 的基本用法。
第一步:設置工作環境
創建一個新目錄,進入該目錄并初始化一個 Node.js 項目,安裝必要的依賴:
$ md simple-agent
$ cd simple-agent
$ npm init
$ npm install llamaindex @llamaindex/ollama
我們將為數學代理創建兩個工具:
- 一個加法工具,用于計算兩個數字的和。
- 一個除法工具,用于計算兩個數字的商。
第二步:導入必要的模塊
在你的腳本中添加以下導入:
import { agent, Settings, tool } from "llamaindex";
import { z } from "zod";
import { Ollama, OllamaEmbedding } from "@llamaindex/ollama";
第三步:創建 Ollama 模型實例
實例化 Llama 模型:
const llama3 = new Ollama({
model: "llama3.2:1b",
});
現在,你可以通過 ??Settings?
? 直接為系統設置主模型,或者在代理中直接使用不同的模型。
Settings.llm = llama3;
第四步:創建數學代理工具
創建加法和除法工具:
const addNumbers = tool({
name: "SumNumbers",
description: "使用此函數計算兩個數字的和",
parameters: z.object({
a: z.number().describe("第一個數字"),
b: z.number().describe("第二個數字"),
}),
execute: ({ a, b }: { a: number; b: number }) => `${a + b}`,
});
這里我們使用了 Zod 庫來驗證工具的參數。同樣地,我們創建一個除法工具:
const divideNumbers = tool({
name: "divideNumber",
description: "使用此函數計算兩個數字的商",
parameters: z.object({
a: z.number().describe("被除數"),
b: z.number().describe("除數"),
}),
execute: ({ a, b }: { a: number; b: number }) => `${a / b}`,
});
第五步:創建數學代理
在主函數中,我們創建一個數學代理,使用這些工具進行計算:
async function main(query: string) {
const mathAgent = agent({
tools: [addNumbers, divideNumbers],
llm: llama3,
verbose: false,
});
const response = await mathAgent.run(query);
console.log(response.data);
}
// 驅動代碼,運行應用
const query = "Add two number 5 and 7 and divide by 2";
void main(query).then(() => {
console.log("Done");
});
如果你直接通過 ??Settings?
?? 設置 LLM,那么你不需要在代理中顯式指定 LLM 參數。如果你希望為不同的代理使用不同的模型,那么必須顯式指定 ??llm?
? 參數。
運行這段代碼后,你將得到如下輸出:
接下來,我們嘗試一個更復雜的查詢:
const query = "If the total number of boys in a class is 50 and girls is 30, what is the total number of students in the class?";
void main(query).then(() => {
console.log("Done");
});
輸出:
哇,我們的小 Llama3.2 1B 模型表現得相當出色,能夠準確地處理代理任務并進行計算!現在,讓我們深入到項目的主體部分。
構建 Agentic RAG 應用
開發環境搭建
按照以下步驟設置開發環境:
$ md agentic-rag-app
$ cd agentic-rag-app
$ npm init
$ npm install llamaindex @llamaindex/ollama
同時,從 Ollama 中拉取必要的模型,例如 ??Llama3.2:1b?
?? 和 ??nomic-embed-text?
?。
在我們的應用中,我們將有四個模塊:
- load-index:用于加載和索引文本文件。
- query-paul:用于查詢 Paul Graham 的文章。
- constant:用于存儲可重用的常量。
- app:用于運行整個應用。
首先,創建 ??constant.ts?
?? 文件和 ??data?
? 文件夾:
// constant.ts
const constant = {
STORAGE_DIR: "./storage",
DATA_FILE: "data/pual-essay.txt",
};
export default constant;
這是一個包含必要常量的對象,將在整個應用中多次使用。創建一個 ??data?
? 文件夾,并將文本文件放入其中。你可以從 這里 下載數據源。
實現加載和索引模塊
以下是加載和索引模塊的實現流程:
導入必要的包
import { Settings, storageContextFromDefaults } from "llamaindex";
import { Ollama, OllamaEmbedding } from "@llamaindex/ollama";
import { Document, VectorStoreIndex } from "llamaindex";
import fs from "fs/promises";
import constant from "./constant";
創建 Ollama 模型實例
const llama3 = new Ollama({
model: "llama3.2:1b",
});
const nomic = new OllamaEmbedding({
model: "nomic-embed-text",
});
設置系統模型
Settings.llm = llama3;
Settings.embedModel = nomic;
實現 ???indexAndStorage?
? 函數
async function indexAndStorage() {
try {
// 設置持久化存儲
const storageContext = await storageContextFromDefaults({
persistDir: constant.STORAGE_DIR,
});
// 加載文檔
const essay = await fs.readFile(constant.DATA_FILE, "utf-8");
constdocument = new Document({
text: essay,
id_: "essay",
});
// 創建并持久化索引
await VectorStoreIndex.fromDocuments([document], {
storageContext,
});
console.log("索引和嵌入文件已成功存儲!");
} catch (error) {
console.log("索引過程中發生錯誤:", error);
}
}
這段代碼將創建一個持久化存儲空間,用于存儲索引和嵌入文件。然后,它將從項目的數據目錄中加載文本數據,并使用 LlamaIndex 的 ??Document?
?? 方法創建一個文檔對象。最后,它將使用 ??VectorStoreIndex?
? 方法從該文檔創建一個向量索引。
導出函數
export default indexAndStorage;
實現查詢模塊
接下來,我們實現查詢模塊。創建一個名為 ??query-paul.ts?
? 的文件。
導入必要的包
import {
Settings,
storageContextFromDefaults,
VectorStoreIndex,
} from "llamaindex";
import constant from "./constant";
import { Ollama, OllamaEmbedding } from "@llamaindex/ollama";
import { agent } from "llamaindex";
創建和設置模型
創建和設置模型的方式與前面相同。
實現 ???loadAndQuery?
? 函數
async function loadAndQuery(query: string) {
try {
// 從持久化存儲中加載索引
const storageContext = await storageContextFromDefaults({
persistDir: constant.STORAGE_DIR,
});
// 加載已有的索引
const index = await VectorStoreIndex.init({ storageContext });
// 創建檢索器和查詢引擎
const retriever = index.asRetriever();
const queryEngine = index.asQueryEngine({ retriever });
const tools = [
index.queryTool({
metadata: {
name: "paul_graham_essay_tool",
description: `此工具可以回答有關 Paul Graham 文章的詳細問題。`,
},
}),
];
const ragAgent = agent({ tools });
// 查詢已索引的文章
const response = await queryEngine.query({ query });
let toolResponse = await ragAgent.run(query);
console.log("響應:", response.message);
console.log("工具響應:", toolResponse);
} catch (error) {
console.log("檢索過程中發生錯誤:", error);
}
}
在這段代碼中,我們首先從 ??STORAGE_DIR?
?? 中加載存儲上下文,然后使用 ??VectorStoreIndex.init()?
?? 方法加載已索引的文件。加載完成后,我們創建一個檢索器和查詢引擎。接下來,我們創建一個工具,該工具可以從已索引的文件中回答問題,并將其添加到名為 ??ragAgent?
? 的代理中。
然后,我們通過查詢引擎和代理分別查詢已索引的文章,并將響應輸出到終端。
導出函數
export default loadAndQuery;
實現 ???app.ts?
?
現在,我們將所有模塊整合到一個 ??app.ts?
? 文件中,方便執行。
import indexAndStorage from"./load-index";
import loadAndQuery from"./query-paul";
function main(query: string) {
console.log("======================================");
console.log("正在索引數據....");
indexAndStorage();
console.log("數據索引完成!");
console.log("請稍候,正在獲取響應或訂閱!");
loadAndQuery(query);
}
const query = "什么是生活?";
main(query);
在這里,我們導入所有模塊,按順序執行它們,并運行應用。
運行應用
在終端中運行以下命令:
$ npx tsx ./app.ts
首次運行時,可能會發生以下幾件事:
- 它會提示你安裝?
?tsx?
?,請按照提示安裝。 - 它會根據你的系統性能花費一些時間來嵌入文檔(這是一次性的操作)。
- 最后,它會返回響應。
以下是首次運行的示例:
沒有代理時,響應可能如下所示:
使用代理時,響應可能如下所示:
今天的分享就到這里。希望這篇文章能幫助你了解 TypeScript 的工作流程。
項目代碼倉庫
你可以在 這里 找到完整的項目代碼。
總結
這是一個簡單但功能強大的 Agentic RAG Using LlamaIndex TypeScript 系統。通過這篇文章,我想讓你了解除了 Python 之外,還可以使用 TypeScript 來構建 Agentic RAG Using LlamaIndex TypeScript 或其他基于 LLM 的 AI 應用。Agentic RAG 系統是基本 RAG 實現的有力進化,能夠根據用戶查詢提供更智能、更靈活的響應。使用 LlamaIndex 和 TypeScript,你可以以類型安全、可維護的方式構建這樣的系統,并且它能夠很好地與 Web 應用生態系統集成。
關鍵要點
- TypeScript + LlamaIndex為構建 RAG 系統提供了堅實的基礎。
- 嵌入文件的持久化存儲提高了重復查詢的效率。
- Agentic 方法根據查詢內容實現更智能的工具選擇。
- 本地模型執行提供了隱私和成本優勢。
- 專業工具可以針對不同領域的知識進行處理。
- Agentic RAG Using LlamaIndex TypeScript通過啟用智能、動態的響應,增強了檢索增強型生成。
常見問題解答
Q1:如何擴展這個系統以處理多個文檔源?
A1:你可以修改索引函數,從多個文件或數據源加載文檔,并將一個文檔對象數組傳遞給 ??VectorStoreIndex?
? 方法。
Q2:這種方法是否支持其他 LLM 提供商,而不僅僅是 Ollama?
A2:是的!LlamaIndex 支持多種 LLM 提供商,包括 OpenAI、Antropic 等。你可以將 Ollama 設置替換為任何支持的提供商。
Q3:如何提高特定領域問題的響應質量?
A3:可以考慮在特定領域數據上微調你的嵌入模型,或者實現自定義檢索策略,根據你的具體用例優先檢索某些文檔部分。
Q4:直接查詢和使用代理方法有什么區別?
A4:直接查詢只是檢索相關內容并生成響應,而代理方法首先決定哪個工具最適合查詢,可能會結合多個來源的信息,或者為不同類型的查詢使用專門的處理。
希望這篇文章能幫助你更好地理解和使用 TypeScript 和 LlamaIndex 構建智能應用!
本文轉載自公眾號Halo咯咯 作者:基咯咯
原文鏈接:??https://mp.weixin.qq.com/s/tOSntLc37ffZlvhoBrWmJg??
