准备好 node,pnpm 环境。
初始化项目
先创建一个空的文件夹langchain-demo
,执行命令以下命令初始化一个项目。
cd langchain-demo/
pnpm init
复制代码
接下来,我们准备一个测试数据,然后将数据摄取到向量数据库中。具体步骤如下:首先在根目录下创建一个 ingest-data.js
然后在项目根目录下执行如下命令:
# 安装LangChain
pnpm i langchain
复制代码
安装完成后:修改 package.json 文件,如图所示,增加"type": "module"
。
读取数据
准备数据
先准备一个 markdown 格式的文件。可以直接在网上找一个,比如 Vue3 的官方文档。然后在页面文档选中一部分,打开 F12 通过输入命令$0.innerHTML
并回车后即可获得数据。简单如图所示:
或者自行准备数据也可。将网页中爬取的文本内容 copy 到 html-to-markdown网站上,转换成 markdown。并将转换后的文件放在项目根目录下的vue3-document.md
中,如图所示
读取数据
编辑我们在之前已经准备好的文件ingest-data.js
,文件内容如下:
// 读取markdown文件
import { UnstructuredLoader } from "langchain/document_loaders/fs/unstructured";
// 实例化 并传入数据的路径
const unstructuredLoader = new UnstructuredLoader("./vue3-document.md");
// 读取文件,这是个promise 使用await
const docs = await unstructuredLoader.load()
console.log(docs)
复制代码
然后通过如下命令进行验证:
cd langchain-demo/
node ingest-data.js
复制代码
执行成功结果如图所示:
切割数据
继续编写ingest-data.js
具体如下:
// 1. 读取markdown文件
import { UnstructuredLoader } from "langchain/document_loaders/fs/unstructured";
// 2. 文档拆分,将文档拆分成一块一块的
// 2.1 导入langchain提供的拆分工具
import { RecursiveCharacterTextSplitter } from "langchain/text_splitter"
// 1.1 实例化UnstructuredLoader 并传入数据的路径
const unstructuredLoader = new UnstructuredLoader("./vue3-document.md");
// 1.2 读取文件,这是个promise 使用await
const rawDocs = await unstructuredLoader.load()
// 1.3
console.log(rawDocs)
// 2.2 实例化 RecursiveCharacterTextSplitter
const splitter = new RecursiveCharacterTextSplitter({
// 一段文本按照1000的大小去拆分
chunkSize: 1000,
// 当前一段文本与上一段文本重叠的大小为200
chunkOverlap: 200
});
// 2.3 切分数据
const docs = await splitter.splitDocuments(rawDocs);
// 打印
console.log(docs);
复制代码
然后通过如下命令进行验证:
cd langchain-demo/
node ingest-data.js
复制代码
成功结果如图所示:对比之前多了一个 loc: [Object]
接入向量数据库
这里选择的向量数据库是:pinecone
具体可参考官网文档自行选择:
https://python.langchain.com/docs/get_started/introduction.html
根据官网安装手册进行安装
https://python.langchain.com/docs/modules/data_connection/vectorstores/integrations/pinecone
pip install pinecone-client openai tiktoken
# dotenv用来读取环境变量 安装向量数据库
pnpm install -S dotenv langchain @pinecone-database/pinecone
复制代码
将数据写入向量数据库
这里采用的是Pinecone
向量数据库。首先我们要注册一个 Pinecone 的数据库。官网地址:
https://www.pinecone.io/
注册完成后我们需要创建一个Index
,如图所示操作:
注意文中的数字 1536 不要写错。
同时我们要记住自己创建的Index Name
并找到,API Key
,以及environment
记下来,后面会用到。
完成上述操作后 接下来继续编辑ingest-data.js
文件,如下所示:
// 1. 读取markdown文件
import { UnstructuredLoader } from "langchain/document_loaders/fs/unstructured";
// 2. 文档拆分,将文档拆分成一块一块的
// 2.1 导入 langchain 提供的拆分工具
import { RecursiveCharacterTextSplitter } from "langchain/text_splitter";
// 利用这个将数据放入向量数据库里面
import { PineconeStore } from "langchain/vectorstores/pinecone"
import { OpenAIEmbeddings } from "langchain/embeddings/openai"
// 3. 导入向量数据库
import { PineconeClient } from "@pinecone-database/pinecone";
// 读取环境变量
import dotenv from "dotenv";
dotenv.config();
// 1.1 实例化UnstructuredLoader 并传入数据的路径
const unstructuredLoader = new UnstructuredLoader("./vue3-document.md");
// 1.2 读取文件,这是个promise 使用await
const rawDocs = await unstructuredLoader.load();
// 1.3
//console.log(rawDocs);
// 2.2 实例化 RecursiveCharacterTextSplitter
const splitter = new RecursiveCharacterTextSplitter({
// 一段文本按照1000的大小去拆分
chunkSize: 1000,
// 当前一段文本与上一段文本重叠的大小为200
chunkOverlap: 200
});
// 2.3 切分数据
const docs = await splitter.splitDocuments(rawDocs);
// 打印
//console.log(docs);
// 3.1 初始化 pinecone
const pineconeClient = new PineconeClient();
await pineconeClient.init({
apiKey: process.env.PINECONE_API_KEY,
environment: process.env.PINECONE_ENV,
});
const pineconeIndex = pineconeClient.Index(process.env.PINECONE_INDEX);
try {
PineconeStore.fromDocuments(docs, new OpenAIEmbeddings(),{
// 向量数据库的信息
pineconeIndex,
textKey: "text",
namespace: "teach-vue3-document",
});
}catch (e) {
console.log(e)
}
复制代码
同时在项目根目录下创建一个.env
文件,文件内容如下:
OPENAI_API_KEY="your openai key"
PINECONE_API_KEY="pinecone api key"
PINECONE_ENV="environment"
PINECONE_INDEX="index name"
复制代码
完成上述操作后,执行如下命令:
cd langchain-demo/
node ingest-data.js
复制代码
运行成功结果如图所示:
通过 Pinecone 的控制台我们可以看到,文档数据已经成功的写入到了向量数据库中。
构建 chains
创建一个chain.js
,内容如下:
import { ConversationalRetrievalQAChain } from "langchain/chains";
// 导入大语言模型
import {OpenAI} from "langchain/llms/openai"
import { PineconeClient } from "@pinecone-database/pinecone";
import { PineconeStore } from "langchain/vectorstores/pinecone"
import { OpenAIEmbeddings } from "langchain/embeddings/openai"
// 读取环境变量
import dotenv from "dotenv";
dotenv.config();
// 创建大语言模型
const model = new OpenAI({
// 准确度,越小越精准,越大越具有创造性
temperature: 0,
});
// 创建向量数据库
const pineconeClient = new PineconeClient();
await pineconeClient.init({
apiKey: process.env.PINECONE_API_KEY,
environment: process.env.PINECONE_ENV,
});
const pineconeIndex = pineconeClient.Index(process.env.PINECONE_INDEX);
const pineconeStore = await PineconeStore.fromExistingIndex(new OpenAIEmbeddings(), {
// 向量数据库的信息
pineconeIndex,
textKey: "text",
namespace: "teach-vue3-document",
});
const chain = ConversationalRetrievalQAChain.fromLLM(
model,
pineconeStore.asRetriever(),{
// 返回信息是参考了什么资料的开关 sourceDocuments:
returnSourceDocuments: true,
});
const res = await chain.call({
question: "vue3 如何为为 reactive() 标注类型 请给我写一个demo",
// 聊天历史,也就是记忆的功能
chat_history: [],
});
console.log(res);
// langchain 0.90版本这样写有问题,具体可参考:
// const secondRes = await chain.call({
// question: "能否提供更多的demo",
// // 聊天历史,也就是记忆的功能
// chat_history: [
// "vue3 如何为 ref() 标注类型 请给我写一个demo",
// res.text
// ],
// });
console.log(secondRes);
复制代码
完成上述操作后,执行如下命令:
cd langchain-demo/
node ingest-data.js
复制代码
运行结果如下:
其实我个人认为这个结果不如人意,但是至少这样做的方向是正确的。
构建后端
使用 koa-setup 构建后端
# 安装koa-setup
npm install -g koa-setup
koa-setup
复制代码
如图:
然后修改生成的server
文件夹中的package.json
文件中的 type 为 module。并添加**"dev": "nodemon index.js"**如图:
修改 server 文件夹下的index.js
文件,如下:
import Koa from "koa"
import Router from "koa-router"
import { koaBody } from "koa-body";
// const Koa = require("koa")
// const Router = require("koa-router")
// const koaBody = require("koa-body")
const app = new Koa()
app.use(koaBody({
multipart:true
}))
const router = new Router()
router.get("/",(ctx)=>{
ctx.body = "hello server"
})
app.use(router.routes())
app.listen(8080,()=>{
console.log("open server localhost:8080")
})
复制代码
安装 nodemon
cd server/
pnpm i nodemon -D
复制代码
nodemon 类似于热部署,修改代码无需重新启动。
启动项目
启动成功:
构建 API
将chat.js
ingest-data.js
vue3-document.md
.env
文件移动到 server 文件夹下,如图:
然后修改 index.js 和 chat.js,详情如下:index.js
import Koa from "koa"
import Router from "koa-router"
import { koaBody } from "koa-body";
import { chat } from "./chain.js";
// const Koa = require("koa")
// const Router = require("koa-router")
// const koaBody = require("koa-body")
const app = new Koa()
app.use(koaBody({
multipart:true
}))
const router = new Router()
router.get("/",(ctx)=>{
ctx.body = "hello server"
})
// 编写接口
router.post("/chat",async (ctx) => {
const { message } = ctx.request.body;
const result = await chat(message)
ctx.body = {
data: result,
state: 1,
}
})
app.use(router.routes())
app.listen(8080,()=>{
console.log("open server localhost:8080")
})
复制代码
chat.js
import { ConversationalRetrievalQAChain } from "langchain/chains";
// 导入大语言模型
import {OpenAI} from "langchain/llms/openai"
import { PineconeClient } from "@pinecone-database/pinecone";
import { PineconeStore } from "langchain/vectorstores/pinecone"
import { OpenAIEmbeddings } from "langchain/embeddings/openai"
// 读取环境变量
import dotenv from "dotenv";
dotenv.config();
// 创建大语言模型
const model = new OpenAI({
// 准确度,越小越精准,越大越具有创造性
temperature: 0,
});
// 创建向量数据库
const pineconeClient = new PineconeClient();
await pineconeClient.init({
apiKey: process.env.PINECONE_API_KEY,
environment: process.env.PINECONE_ENV,
});
const pineconeIndex = pineconeClient.Index(process.env.PINECONE_INDEX);
const pineconeStore = await PineconeStore.fromExistingIndex(new OpenAIEmbeddings(), {
// 向量数据库的信息
pineconeIndex,
textKey: "text",
namespace: "teach-vue3-document",
});
const chain = ConversationalRetrievalQAChain.fromLLM(
model,
pineconeStore.asRetriever(),{
// 返回信息是参考了什么资料的开关 sourceDocuments:
returnSourceDocuments: true,
});
export async function chat(message) {
const res = await chain.call({
question: message,
// 聊天历史,也就是记忆的功能
chat_history: [],
});
return res;
}
复制代码
然后启动运行pnpm dev
并使用 postman 访问接口 "/chat" 如图:
构建前端
安装组件tailwindcss
cd client/
pnpm install -D tailwindcss@latest postcss@latest autoprefixer@latest
# 执行init
npx tailwindcss init -p
# 安装axios 后续使用
pnpm i axios
# 安装 marked marked 是一个流行的 JavaScript 库,用于将 Markdown 文本转换为 HTML
pnpm install marked
pnpm install --save-dev @types/marked
pnpm install typescript --save-dev
复制代码
在tailwind.config.js
添加配置(参考官网:https://v2.tailwindcss.com/docs/guides/vue-3-vite)
purge: ["./index.html", "./src/**/*.{vue,js,ts,jsx,tsx}"],
复制代码
修改 style.css 文件(参考官网:https://v2.tailwindcss.com/docs/guides/vue-3-vite)
@tailwind base;
@tailwind components;
@tailwind utilities;
复制代码
然后在App.vue
中编写 Hello World。
<script setup>
</script>
<template>
<div class="text-blue-400">
Hello World
</div>
</template>
<style scoped>
</style>
复制代码
启动
页面如下:
接下来编写视图,(前端组件、js 等)viteproxy 文档:https://cn.vitejs.dev/config/server-options.html
源码获取:微信搜索【码上遇见你】回复【langchain-demo】
上述文章也是依据网络整理的。侵权删之。
评论