likes
comments
collection
share

用最精简的代码实现可读取本地资料的AI聊天机器人

作者站长头像
站长
· 阅读数 12

本文章将通过一个最精简的案例来演示可读取本地数据的AI聊天机器人的核心开发流程。该案例通过获取vue3最新官网的一页数据,并将数据存储在Pinecone向量库中,实现聊天式学习官网最新的vue3知识。

github开源地址:github.com/GreysonHYH/…

实现背景:

1.由于ChatGPT的内容最新截止到2021年9月,而在这之后的互联网上最新的信息它是不知道的,而通过让它读取本地资料可获取到最新的数据。

2.当我们需要学习某一个特定的材料和文档时,可以让AI读取该材料,以实现聊天式学习。

3.提高我们查找本地资料的速度,以及让AI更懂用户,因为它还会对我们本地的数据信息进行总结。

4.未来开发者乃至各行各业工作者都离不开AI,有必要了解对于如何构建一个AI助手的基本实现思路。

实现思路:

一、将本地数据存进Pinecone向量数据库

1.将本地数据进行切块。

2.切块完成后经过OpenAI Embedding转换成向量,存进向量库中。

二、提问题,生成答案

1.将问题经过OpenAI Embedding转换成向量,进入到向量库中查找。

2.取出查找到的相关的数据资料,与提出的问题一起喂给GPT3.5/4。

3.GPT3.5/4根据喂给它的数据资料与提出的问题来生成答案。

用最精简的代码实现可读取本地资料的AI聊天机器人

实现步骤:

一、将本地数据库存进Pinecone向量数据库。

1.初始化项目

初始化项目,生成package.json文件,并为项目安装langchain。

npm init

npm i langchain

langchain支持python也支持node.js,该案例中我们采用node.js。 在package.json中添加type属性,值为module。

用最精简的代码实现可读取本地资料的AI聊天机器人


2.读取本地资料。

创建ingest-data.js文件,ingest-data.js文件中引入 UnstructuredLoader 用于读取本地资料。“./vue3-document.md”为本地markdown文档。unstructuredLoader.load()为一个promise,返回一个数组,数组每一项为将markdown文档拆分后的文档对象。

import { UnstructuredLoader } from "langchain/document_loaders/fs/unstructured" 
const unstructuredLoader = new UnstructuredLoader("./vue3-document.md")
const rawDocs = await unstructuredLoader.load()

3.对本地资料进行切块。

引入 RecursiveCharacterTextSplitter 用于对本地资料进行切块。参数chunkSize的值表示切分的大小,数值太大会导致查询过慢的问题,还有可能会超过大语言模型的长度限制而发生报错。如果设置太小也会导致信息太碎片化,得到的结果有点胡说八道的感觉。这个值就需要居于自身的内容进行调整。参数chunkOverlap的值表示切出来的每一块可与上一块或下一块的可重叠的大小。

import { RecursiveCharacterTextSplitter } from "langchain/text_splitter" 
const splitter = new RecursiveCharacterTextSplitter({
    chunkSize:1000,
    chunkOverlap:200
})
const docs = await splitter.splitDocuments(rawDocs)

4.将切块后的文档存入到Pinecone向量数据库中。

先创建一个.env文件,用于存放环境变量。

OPENAI_API_KEY = "xxx"
PINECONE_API_KEY = "xxx"
PINECONE_ENVIRONMENT = "xx-xxx-xx"
PINECONE_INDEX = "greyson"

回到ingest-data.js,配置环境变量。

import dotenv from 'dotenv'
dotenv.config()

安装Pinecone向量数据库。

npm install -S @pinecone-database/pinecone

引入 PineconeClient, 初始化Pinecone向量数据库。

import { PineconeClient } from "@pinecone-database/pinecone" 
const pineconeClient = new PineconeClient()
await pineconeClient.init({
    apiKey: process.env.PINECONE_API_KEY,
    environment: process.env.PINECONE_ENVIRONMENT,
})

要填写apiKey和environment的值,需要注册Pinecone,在API KEY中获取。

用最精简的代码实现可读取本地资料的AI聊天机器人

创建一个index,并拿到该index名称。

用最精简的代码实现可读取本地资料的AI聊天机器人

const pineconeIndex = pineconeClient.Index("greyson")

将本地文档存入Pinecone向量数据库。

PineconeStore.fromDocuments(docs,new OpenAIEmbeddings(),{
        pineconeIndex,
        textKey:"text",
        namespace:"vue3-document"
    })

执行代码。

node ingest-data.js

打开对应的index查看,向量总数发生改变,说明已经成功导入向量数据库。

用最精简的代码实现可读取本地资料的AI聊天机器人

以上完成将本地资料存储到Pinecone向量数据库。

二、提出问题,生成答案。

新建chat.js文件。创建OpenAI语言模型,temperature的值为控制下一个字符的准确度,如果为0就是将最准确的下一个字符匹配过来,如果数值较大,匹配的字符更随机,将有可能生成更具创造性的句子,可能更适合用来编写文章。对于本次案例来说,设置为0比较合适。

import { OpenAI } from "langchain/llms/openai"
const model = new OpenAI({
    temperature:0
})

创建Pinecone向量数据库,之后用于根据问题检索里面的数据。

const pineconeClient = new PineconeClient()
await pineconeClient.init({
    apiKey: process.env.PINECONE_API_KEY,
    environment: process.env.PINECONE_ENVIRONMENT,
})
const pineconeIndex = pineconeClient.Index(process.env.PINECONE_INDEX)
const pineconeStore = await PineconeStore.fromExistingIndex(new OpenAIEmbeddings(),{
    pineconeIndex,
    textKey:"text",
    namespace:"vue3-document"
})

创建一条聊天检索交互链,分别放入大语言模型(即OpenAI),向量数据库检索器以及配置项对象。

将returnSourceDocuments设为true,即表示返回生成的回答时,将所参考到的原材料一并返回。

const chain = ConversationalRetrievalQAChain.fromLLM(model,pineconeStore.asRetriever(),{
    returnSourceDocuments:true  
})

提问题,question值为所提出的问题,chat_history值为历史记录,默认为空数组。

const newQuestion = "我是vue新手,给我一些学习建议"
const res = await chain.call({
    question:newQuestion,
    chat_history:[]
})
console.log(res)

可以将上一次的问题和答案放进数组作为历史记录,一并喂给ChatGPT。

const secondRes = await chain.call({
    question:"还有其他建议吗?",
    chat_history:[newQuestion,res.text]
})
console.log(secondRes)

最后打印出ChatGPT返回的答案,表示成功。