使用互联网计算机协议、Motoko 和 Node.js 构建 Motoko LLM 检索系统

社区文章 发布于 2024 年 6 月 27 日

image/webp

互联网计算机协议 (ICP) 的兴起彻底改变了开发人员构建去中心化应用程序的方式。将专为 ICP 设计的强大语言 Motoko 与 Node.js 集成,可以构建一个强大且可扩展的大型语言模型 (LLM) 检索系统。本文将引导您构建这样一个系统,重点介绍嵌入存储和检索等关键组件。

先决条件

在深入实施之前,请确保您具备以下工具和知识:

  • 对 Motoko 和 Node.js 有基本了解。
  • 机器上已安装 Node.js 和 npm。
  • 已安装 DFINITY SDK。
  • 对 RESTful API 有基本了解。

第一步:设置 Motoko Canister

首先,我们将创建一个 Motoko Canister 来存储和检索嵌入向量。

1.1 定义 EmbeddingStore Actor

创建一个名为 EmbeddingStore.mo 的新文件,并按如下方式定义 EmbeddingStore actor:

import Array "mo:base/Array";
import Nat "mo:base/Nat";
import Time "mo:base/Time";
import Error "mo:base/Error";

actor EmbeddingStore {
    type Embedding = {
        text: Text;
        embedding: [Float];
        createdAt: Int;
    };

    stable var embeddings: [Embedding] = [];
    stable let secretKey: Text = "8529741360"; // Replace with your actual secret key

    public shared func storeEmbedding(key: Text, text: Text, embedding: [Float]) : async () {
        if (key == secretKey) {
            let timestamp = Time.now();
            embeddings := Array.append(embeddings, [{
                text = text;
                embedding = embedding;
                createdAt = timestamp;
            }]);
        } else {
            throw Error.reject("Invalid key. Access denied.");
        }
    };

    public query func getEmbeddings() : async [Embedding] {
        return embeddings;
    };
};

1.2 部署 Canister

EmbeddingStore Canister 部署到互联网计算机:

  1. 打开终端并导航到项目目录。
  2. 运行 dfx start 启动本地副本。
  3. 通过将 EmbeddingStore 配置添加到 dfx.json 文件来创建新的 Canister。
  4. 使用 dfx deploy 部署 Canister。

第二步:设置 Node.js 服务器

接下来,我们将设置一个 Node.js 服务器,用于与 Motoko Canister 进行交互。

2.1 初始化项目

  1. 为您的 Node.js 项目创建一个新目录。
  2. 运行 npm init -y 初始化项目。
  3. 安装必要的依赖项:
npm install express body-parser @dfinity/agent dotenv

2.2 创建服务器脚本

创建一个名为 server.js 的新文件,并添加以下代码:

const express = require('express');
const bodyParser = require('body-parser');
const { HttpAgent, Actor } = require('@dfinity/agent');
const { idlFactory } = require('./idl/embedding_store.did.js');
require('dotenv').config();

const app = express();
const port = 3000;

app.use(bodyParser.json());

const canisterId = process.env.CANISTER_ID;
const host = process.env.HOST;

// Initialize the agent
const agent = new HttpAgent({ host });
agent.fetchRootKey(); // Necessary for local development

// Create an actor instance
const embeddingStore = Actor.createActor(idlFactory, {
    agent,
    canisterId,
});

// Helper function to convert BigInt to a string for JSON serialization
const serializeBigInt = (obj) => {
    if (typeof obj === 'bigint') {
        return obj.toString();
    } else if (Array.isArray(obj)) {
        return obj.map(serializeBigInt);
    } else if (typeof obj === 'object' && obj !== null) {
        return Object.fromEntries(
            Object.entries(obj).map(([k, v]) => [k, serializeBigInt(v)])
        );
    }
    return obj;
};

app.post('/storeEmbedding', async (req, res) => {
    const { key, text, embedding } = req.body;
    try {
        if (key !== process.env.SECRET_KEY) {
            throw new Error('Invalid key');
        }
        // Convert embedding to float64 if not already
        const embeddingFloat64 = embedding.map(Number);
        await embeddingStore.storeEmbedding(key, text, embeddingFloat64);
        res.status(200).send('Embedding stored successfully.');
    } catch (error) {
        res.status(500).send(`Error: ${error.message}`);
    }
});

app.get('/getEmbeddings', async (req, res) => {
    try {
        const embeddings = await embeddingStore.getEmbeddings();
        res.status(200).json(serializeBigInt(embeddings));
    } catch (error) {
        res.status(500).send(`Error: ${error.message}`);
    }
});

app.listen(port, () => {
    console.log(`Server is running on https://:${port}`);
});

2.3 环境变量配置

在项目目录中创建一个 .env 文件,并添加以下环境变量:

CANISTER_ID=<your-canister-id>
HOST=https://:8000
SECRET_KEY=8529741360

<your-canister-id> 替换为从部署步骤中获得的实际 canister ID。

第三步:测试系统

Canister 部署完成,服务器设置完毕后,是时候测试嵌入向量存储和检索功能了。

3.1 存储嵌入向量

使用 curl 或 Postman 等工具存储嵌入向量:

curl -X POST https://:3000/storeEmbedding \
     -H "Content-Type: application/json" \
     -d '{"key": "8529741360", "text": "example text", "embedding": [0.1, 0.2, 0.3]}'

3.2 检索嵌入向量

通过访问以下端点检索已存储的嵌入向量:

curl https://:3000/getEmbeddings

结论

恭喜!您已成功使用互联网计算机协议、Motoko 和 Node.js 构建了一个 Motoko LLM 检索系统。该系统允许您安全地存储和检索文本嵌入向量,利用互联网计算机的去中心化能力。下一步,可以考虑添加更多功能,例如高级搜索功能、身份验证机制以及与前端应用程序的集成。

社区

注册登录以评论