在私域场景下,利用LangChain与LLM模型搭建个性化服务平台的思考
缘起
4月份裸辞开始,原计划给自己几个月的修整期,去看看祖国的大好山河,来一场说走就走的旅行,结果万万没想到AIGC
爆火,我的修整计划基本GG思密达,这一段时间,录了一套基础教程,基于chatgpt做了几个项目,微信机器人,公众号,套壳网站,英语陪练,MJ,等等 最近在和一些朋友聊天,聊到一个新的变现方向:私域垂类助手
应用场景如下
- 电商客服系统
- 政务问答系统
- 法律顾问助手
- 教培咨询机器人
当然现在类似的机器人助手都是已经有的,但是大多是通过字符串匹配实现的。这种方式,问不到关键词,系统就答不上。所以我们可以把助手和chatgpt 或者其他的LLM模型进行关联,但是同样也会出现一些问题,比如在大语言模型中,存在的关键词都属于普适知识
,但是如果我去询问一些私有的知识,比如我的名字就GG,
所以本文去探讨一种 私域场景下的垂类问答系统思考
(chatPDF)
先看结果
- 我准备一个
李狗蛋的高级前端开发工程师简历
如下
因为这种LLM 基础训练的都是普适知识
,所以当我们询问 who is 李狗蛋
他是没有办法回复的如下:
接着我们测试下本地知识库
询问三个问题
- 请介绍下李狗蛋
- 李狗蛋的技术栈是什么
- 李狗蛋的缺点是什么
async function test(q:string) {
/** 从 本地 文件初始化 仓库, (从本地缓存文件初始数据库会省 token 消耗) */
const vectorStore = await initVectorStoreFromLocalTempFiles();
/** 本地向量搜索并向 LLM 发问 */
const answer = await searchAndAsk(vectorStore, q);
}
test("请介绍下李狗蛋")
test("李狗蛋的技术栈是什么")
test("李狗蛋的缺点是什么")
结果如下
技术栈
Nodejs + TS
实现思路
Fine-Tuning(微调)
Fine-Tuning,也称为微调,在机器学习中指通过训练预先训练的模型来适应特定任务的过程。通常情况下,Fine-Tuning需要针对特定任务准备一个小型数据集,并使用该数据集对预训练模型进行微调。这个过程通常只需要很少的数据和计算资源,可以使得原有的预训练模型在特定任务上得到更好的表现。
Embedding(嵌入)
Embedding(嵌入)是将高维数据向量化的技术。在自然语言处理中,嵌入通常用于将单词、短语或文档转换成密集的低维向量。这些向量通常具有语义相关性,可以用于实现单词相似度比较、文本分类、翻译等任务。在LangChain中,利用Document Loaders、Text Splitters、Vector Stores等工具,可以将本地文档嵌入到向量数据库中,并在进入GPT之前通过相似度搜索找到与输入问题最相似的答案嵌入到提问中,从而避免了GPT3.5 API长度限制带来的问题。
实际上,用 LangChain 来解决复杂问题并不需要训练大语言模型(LLM),我们只是将本地知识库和问题作为prompt的一部分输入到LLM中。这种做法非常轻量级, LLM 只需要专注于它最擅长的工作:翻译和总结。因此,如果您在目录中放置的是英文文档,那么您可以通过中文与应用程序进行对话,并且 LangChain 会像一个聪明的助手一样快速准确地回答您的问题。
核心代码实现
1. 本地训练内容读取
这里我们直接通过LangChain
api实现本地文件读取
/** 本地默认文件路径 */
const LOCAL_FILE_PATH = 'files';
const LOCAL_VENCTOR_DATA_PATH = "./vectorData/";
/** 获取本地文件 */
async function getLocalFiles(){
const directoryLoader = new DirectoryLoader(LOCAL_FILE_PATH, {
'.pdf': (path) => new CustomPDFLoader(path),
".json": (path) => new JSONLoader(path, "/texts"),
".txt": (path) => new TextLoader(path),
".csv": (path) => new CSVLoader(path, "text"),
});
/** 文件执行加载,得到 Document */
const fileDocs = await directoryLoader.load();
return fileDocs;
}
2.将读取到的本地文件进行切片
chunkSize:切片尺寸
chunkOverlap: 为了保证上下文连续 重复量级
/** 文件执行加载,得到 Document */
const rawDocs = await getLocalFiles();
/* 文字 转 切片 */
const textSplitter = new RecursiveCharacterTextSplitter({
chunkSize: 1000,
chunkOverlap: 200,
});
/** 切片文档 */
const docs = await textSplitter.splitDocuments(rawDocs);
3.通过Embedding方式 初始化向量数据库
LangChain确实为用户提供了多种向量数据库可供选择,其中包括HNSWLib
、Annoy
、Faiss
等。这些不同的向量数据库具有各自的优势和适用场景,可以根据用户需求进行选择。
在这里,我们选择了HNSWLib
作为向量数据库,原因是它支持Node.js、轻巧便捷、支持离线运行,并且无需单独启动数据库程序,只需将其作为模块导入即可运行。
当然,在生产环境中,建议使用更高级的云端数据库以确保性能和可靠性,例如Pinecone
、Supabase
等。这些云端数据库提供全球分布式部署、高效查询、强大的数据安全性等特点,并且可以方便地与其他云服务集成使用。
将把切片文档传入HNSWLib类中,同时使用OpenAIEmbeddings类来生成向量数据。
/** 创建和存储 vectorStore 嵌入, 这个步骤会生成向量数据(按 token 计费,给 openai 送钱) */
const vectorStore = await HNSWLib.fromDocuments(docs, new OpenAIEmbeddings({
verbose: true,
}));
/** 初始化完数据库后,存成本地文件 */
await vectorStore.save(LOCAL_VENCTOR_DATA_PATH);
console.log('向量数据库初始化成功!');
4. 用户提问优先近似向量内容检索
/** 先本地执行相似搜索,再向 LLM 发问 */
async function searchAndAsk(loadedVectorStore: HNSWLib, question: string) {
/** 向量相似搜索 */
const referenceContextDocuments = await loadedVectorStore.similaritySearch(question, 1);
/** 向量搜索相似结果string化 */
const contextString = (referenceContextDocuments || []).map(docItem => `[${getFileName(docItem.metadata.source)}] ${docItem.pageContent}`).join('/n')
/** 带着本地信息, 向 LLM 发问 */
const llmAnswer = await askLLM({
question,
referenceContext: contextString
});
return llmAnswer;
}
5. 向LLM 发起问题
在这一步将向量搜索到的内容,结合问题用户的问题添加到prompt
里丢给LLM,让他来帮助我们总结提炼
/** 调用 LLM 接口 */
async function askLLM({question, referenceContext}: IAsk) {
// LLM 用 openai
const model = new OpenAI({ temperature: 0 });
/** prompt 模板 */
const prompt = PromptTemplate.fromTemplate(
`作为一位专业的文档工程师,你的任务是从给定的上下文回答问题。
你的回答应该基于我提供的上下文回答我的问题,并以对话的形式呈现。
问题如下:
{question}
给定的上下文:
{context}
`,
);
// 通过 PromptTemplate + LLM 创建 chain
const chain = new LLMChain({
llm: model,
prompt,
// verbose: true
});
const res = await chain.call({ question, context: referenceContext });
console.log('res log:', res);
return res;
}
结束语
在当今信息爆炸的时代,如何从无数信息中筛选出有价值的内容成为了人们不可或缺的技能。然而,特定领域的专业知识往往受限于私密性和专业性等因素,传统问答系统难以满足用户的需求。为此,本文提出了一种基于LangChain与LLM模型的私有知识库方案,为垂类问答服务带来了新的发展思路和前景。
该方案不仅可以应用于企业内部知识库管理,还可以运用于教育、司法、医疗等领域,提供智能便捷的信息服务。通过Fine-Tuning与Embedding技术的结合运用,垂类问答系统在私域场景下实现更加高效精准的回答,大大提升了用户的使用体验。同时,本文也探索了如何利用LangChain实现本地知识库的嵌入式搜索,进一步提高了系统的效率和准确性。
最终我们不会被AI取代,而是被掌握AI的人取代,拥抱AI吧
前端开发在AIGC的探索之路,共同努力