基于LLM的企业知识库AI助手实现
在企业内部通常有各类知识库,例如IT手册、产品文档、制度规范、培训材料等。在AI技术火热的今天,将知识库与LLM大语言模型结合,可以实现“类ChatGPT”的问答体验,AI可以识别用户意图,从知识库中检索相关信息,并生成通俗易懂的回答,显著提升知识获取效率和用户体验。本文介绍博主为公司内部搭建的企业AI知识库实现过程。
效果展示
一、架构设计
1.1 架构设计图
1.2 组件说明:
FastGPT:基于 LLM 大语言模型的知识库问答平台
OneAPI:聚合各类 AI API,支持多模型调用
MongoDB\PostgreSQL:Fastgpt依赖组件,用于存储核心配置数据和向量数据
OpenAI API:LLM模型接口,支持各种公共模型(如ChatGPT、Deepseek、Claude等)或自建模型OpenAI接口
1.3 流程描述
在整体设计中,我们主要依赖FastGPT、OneAPI组件实现,大致流程如下:首先在OneAPI中配置接入LLM模型接口,然后FastGPT通过OneAPI调用语言模型用于用户对话,调用向量模型用于拆解知识库文档,最后再将FastGPT生成的应用窗口,通过iFrame形式嵌入到我们自有的服务台中,实现用户交互。
二、部署实施
2.1 FastGPT部署
这里采用官网推荐的Docker Compose方式部署,官方文档:https://doc.fastgpt.cn/docs/development/docker/,示例Docker-Compose文件如下:
# 数据库的默认账号和密码仅首次运行时设置有效
# 如果修改了账号密码,记得改数据库和项目连接参数,别只改一处~
# 该配置文件只是给快速启动,测试使用。正式使用,记得务必修改账号密码,以及调整合适的知识库参数,共享内存等。
# 如何无法访问 dockerhub 和 git,可以用阿里云(阿里云没有arm包)
version: '3.3'
services:
pg:
image: pgvector/pgvector:0.7.0-pg15 # docker hub
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/pgvector:v0.7.0 # 阿里云
container_name: pg
restart: always
ports: # 生产环境建议不要暴露
- 5432
networks:
- fastgpt
environment:
# 这里的配置只有首次运行生效。修改后,重启镜像是不会生效的。需要把持久化数据删除再重启,才有效果
- POSTGRES_USER=username
- POSTGRES_PASSWORD=password
- POSTGRES_DB=postgres
volumes:
- ./pg/data:/var/lib/postgresql/data
mongo:
# image: mongo:5.0.18 # dockerhub
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/mongo:5.0.18 # 阿里云
image: mongo:4.4.29 # cpu不支持AVX时候使用
container_name: mongo
restart: always
ports:
- 27017
networks:
- fastgpt
command: mongod --keyFile /data/mongodb.key --replSet rs0
environment:
- MONGO_INITDB_ROOT_USERNAME=myusername
- MONGO_INITDB_ROOT_PASSWORD=mypassword
volumes:
- ./mongo/data:/data/db
entrypoint:
- bash
- -c
- |
openssl rand -base64 128 > /data/mongodb.key
chmod 400 /data/mongodb.key
chown 999:999 /data/mongodb.key
echo 'const isInited = rs.status().ok === 1
if(!isInited){
rs.initiate({
_id: "rs0",
members: [
{ _id: 0, host: "mongo:27017" }
]
})
}' > /data/initReplicaSet.js
# 启动MongoDB服务
exec docker-entrypoint.sh "$$@" &
# 等待MongoDB服务启动
until mongo -u myusername -p mypassword --authenticationDatabase admin --eval "print('waited for connection')" > /dev/null 2>&1; do
echo "Waiting for MongoDB to start..."
sleep 2
done
# 执行初始化副本集的脚本
mongo -u myusername -p mypassword --authenticationDatabase admin /data/initReplicaSet.js
# 等待docker-entrypoint.sh脚本执行的MongoDB服务进程
wait $$!
fastgpt:
container_name: fastgpt
image: ghcr.io/labring/fastgpt:v4.8 # git
# image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.8 # 阿里云
ports:
- 3000:3000
networks:
- fastgpt
depends_on:
- mongo
- pg
restart: always
environment:
# root 密码,用户名为: root。如果需要修改 root 密码,直接修改这个环境变量,并重启即可。
- DEFAULT_ROOT_PSW=Password@12345
# AI模型的API地址哦。务必加 /v1。这里默认填写了OneApi的访问地址。
- OPENAI_BASE_URL=http://oneapi:3000/v1
# AI模型的API Key。(这里默认填写了OneAPI的快速默认key,测试通后,务必及时修改)
- CHAT_API_KEY=sk-fastgpt
# 数据库最大连接数
- DB_MAX_LINK=30
# 登录凭证密钥
- TOKEN_KEY=any
# root的密钥,常用于升级时候的初始化请求
- ROOT_KEY=root_key
# 文件阅读加密
- FILE_TOKEN_KEY=filetoken
# MongoDB 连接参数. 用户名myusername,密码mypassword。
- MONGODB_URI=mongodb://myusername:mypassword@mongo:27017/fastgpt?authSource=admin
# pg 连接参数
- PG_URL=postgresql://username:password@pg:5432/postgres
volumes:
- ./config.json:/app/data/config.json
- ./fastgpt/tmp:/app/tmp
mysql:
image: mysql:8.0.36
container_name: mysql
restart: always
ports:
- 3306
networks:
- fastgpt
command: --default-authentication-plugin=mysql_native_password
environment:
# 默认root密码,仅首次运行有效
MYSQL_ROOT_PASSWORD: oneapimmysql
MYSQL_DATABASE: oneapi
volumes:
- ./mysql:/var/lib/mysql
oneapi:
container_name: oneapi
image: ghcr.io/songquanpeng/one-api:latest
ports:
- 3001:3000
depends_on:
- mysql
networks:
- fastgpt
restart: always
environment:
# mysql 连接参数
- SQL_DSN=root:oneapimmysql@tcp(mysql:3306)/oneapi
# 登录凭证加密密钥
- SESSION_SECRET=oneapikey
# 内存缓存
- MEMORY_CACHE_ENABLED=true
# 启动聚合更新,减少数据交互频率
- BATCH_UPDATE_ENABLED=true
# 聚合更新时长
- BATCH_UPDATE_INTERVAL=10
# 初始化的 root 密钥(建议部署完后更改,否则容易泄露)
- INITIAL_ROOT_TOKEN=fastgpt
volumes:
- ./oneapi:/data
networks:
fastgpt:
根据官网描述,我们还需要创建一个config.json文件,用于配置模型相关,配置如下:
{
"feConfigs": {
"lafEnv": "https://laf.dev"
},
"systemEnv": {
"openapiPrefix": "fastgpt",
"vectorMaxProcess": 15,
"qaMaxProcess": 15,
"pgHNSWEfSearch": 100
},
"llmModels": [
{
"model": "gpt-3.5-turbo",
"name": "gpt-3.5-turbo",
"maxContext": 16000,
"avatar": "/imgs/model/openai.svg",
"maxResponse": 4000,
"quoteMaxToken": 13000,
"maxTemperature": 1.2,
"charsPointsPrice": 0,
"censor": false,
"vision": false,
"datasetProcess": true,
"usedInClassify": true,
"usedInExtractFields": true,
"usedInToolCall": true,
"usedInQueryExtension": true,
"toolChoice": true,
"functionCall": true,
"customCQPrompt": "",
"customExtractPrompt": "",
"defaultSystemChatPrompt": "",
"defaultConfig": {}
},
{
"model": "gpt-4-0125-preview",
"name": "gpt-4-turbo",
"avatar": "/imgs/model/openai.svg",
"maxContext": 125000,
"maxResponse": 4000,
"quoteMaxToken": 100000,
"maxTemperature": 1.2,
"charsPointsPrice": 0,
"censor": false,
"vision": false,
"datasetProcess": false,
"usedInClassify": true,
"usedInExtractFields": true,
"usedInToolCall": true,
"usedInQueryExtension": true,
"toolChoice": true,
"functionCall": false,
"customCQPrompt": "",
"customExtractPrompt": "",
"defaultSystemChatPrompt": "",
"defaultConfig": {}
},
{
"model": "gpt-4-vision-preview",
"name": "gpt-4-vision",
"avatar": "/imgs/model/openai.svg",
"maxContext": 128000,
"maxResponse": 4000,
"quoteMaxToken": 100000,
"maxTemperature": 1.2,
"charsPointsPrice": 0,
"censor": false,
"vision": true,
"datasetProcess": false,
"usedInClassify": false,
"usedInExtractFields": false,
"usedInToolCall": false,
"usedInQueryExtension": false,
"toolChoice": true,
"functionCall": false,
"customCQPrompt": "",
"customExtractPrompt": "",
"defaultSystemChatPrompt": "",
"defaultConfig": {}
}
],
"vectorModels": [
{
"model": "text-embedding-3-large",
"name": "Embedding-2",
"avatar": "/imgs/model/openai.svg",
"charsPointsPrice": 0,
"defaultToken": 512,
"maxToken": 3000,
"weight": 100,
"dbConfig": {},
"queryConfig": {},
"defaultConfig": {
"dimensions": 1024
}
},
{
"model": "text-embedding-3-small",
"name": "Embedding-2",
"avatar": "/imgs/model/openai.svg",
"charsPointsPrice": 0,
"defaultToken": 512,
"maxToken": 3000,
"weight": 100,
"dbConfig": {},
"queryConfig": {}
},
{
"model": "text-embedding-ada-002",
"name": "Embedding-2",
"avatar": "/imgs/model/openai.svg",
"charsPointsPrice": 0,
"defaultToken": 512,
"maxToken": 3000,
"weight": 100,
"dbConfig": {},
"queryConfig": {}
}
],
"reRankModels": [],
"audioSpeechModels": [
{
"model": "tts-1",
"name": "OpenAI TTS1",
"charsPointsPrice": 0,
"voices": [
{
"label": "Alloy",
"value": "alloy",
"bufferId": "openai-Alloy"
},
{
"label": "Echo",
"value": "echo",
"bufferId": "openai-Echo"
},
{
"label": "Fable",
"value": "fable",
"bufferId": "openai-Fable"
},
{
"label": "Onyx",
"value": "onyx",
"bufferId": "openai-Onyx"
},
{
"label": "Nova",
"value": "nova",
"bufferId": "openai-Nova"
},
{
"label": "Shimmer",
"value": "shimmer",
"bufferId": "openai-Shimmer"
}
]
}
],
"whisperModel": {
"model": "whisper-1",
"name": "Whisper1",
"charsPointsPrice": 0
}
}
配置文件准备完成后,docker-compose up启动容器
2.2 配置OneAPI
这里博主使用了公司自研的大模型运维平台LLMOPS作为示例,其他公有模型接口参考FastGPT或OneAPI官方文档即可
首先进入LLMOPS平台,我们选择Qwen3-30B-A3B-128k-nothink(无CoT)模型,在服务列表-服务详情-查看调用示例中,创建API-Key,然后从调用示例中获取API baseURL和model名称
调用示例
curl -k -X POST '{API_BASEURL}' \
-H "Content-type: application/json" \
-H "Authorization: Bearer {API_KEY}" \
-d '{
"messages": [
{
"role": "system",
"content": "你是一个很有用助手"
},
{
"role": "user",
"content": "请简单介绍一下自己的作用"
}
],
"model": "atom", //MODEL_NAME
"stream": true
}'
进入OneAPI后台配置页面,配置渠道-新增渠道,类型选择自定义渠道,将LLMOPS调用示例中获取的API_BASEURL、API_KEY、MODEL_NAME分别填写到OneAPI渠道中的BaseURL、密钥、模型字段,然后保存并测试渠道
若测试有报错,可以在LLMOPS后台调用记录中查看接口调用详情
2.3 配置FastGPT
我们的自有模型添加完成后,还需要集成到FastGPT中供其调用,编辑config.json文件,在llmModels和vectorModels列表中添加我们自定义的模型,其中参数配置可参考官方配置手册。
"llmModels": [
{
"model": "atom", // 模型名(对应OneAPI中渠道的模型名)
"name": "llmops_atom", // 模型别名
"maxContext": 128000, // 最大上下文
"maxResponse": 16000, // 最大回复
"quoteMaxToken": 120000, // 最大引用内容
"maxTemperature": 1.2, // 最大温度
"charsPointsPrice": 0, // n积分/1k token(商业版)
"censor": false, // 是否开启敏感校验(商业版)
"vision": true, // 是否支持图片输入
"datasetProcess": true, // 是否设置为文本理解模型(QA),务必保证至少有一个为true,否则知识库会报错
"usedInClassify": true, // 是否用于问题分类(务必保证至少有一个为true)
"usedInExtractFields": true, // 是否用于内容提取(务必保证至少有一个为true)
"usedInToolCall": true, // 是否用于工具调用(务必保证至少有一个为true)
"toolChoice": true, // 是否支持工具选择(分类,内容提取,工具调用会用到。)
"functionCall": false, // 是否支持函数调用(分类,内容提取,工具调用会用到。会优先使用 toolChoice,如果为false,则使用 functionCall,如果仍为 false,则使用提示词模式)
"customCQPrompt": "", // 自定义文本分类提示词(不支持工具和函数调用的模型
"customExtractPrompt": "", // 自定义内容提取提示词
"defaultSystemChatPrompt": "", // 对话默认携带的系统提示词
"defaultConfig": {}, // 请求API时,挟带一些默认配置(比如 GLM4 的 top_p)
"fieldMap": {} // 字段映射(o1 模型需要把 max_tokens 映射为 max_completion_tokens)
}
],
"vectorModels": [
{
"model": "atom", // 模型名(与OneAPI对应)
"name": "atom", // 模型展示名
"charsPointsPrice": 0, // n积分/1k token
"defaultToken": 700, // 默认文本分割时候的 token
"maxToken": 3000, // 最大 token
"weight": 100, // 优先训练权重
"defaultConfig": {}, // 自定义额外参数。例如,如果希望使用 embedding3-large 的话,可以传入 dimensions:1024,来返回1024维度的向量。(目前必须小于1536维度)
"dbConfig": {}, // 存储时的额外参数(非对称向量模型时候需要用到)
"queryConfig": {} // 参训时的额外参数
},
],
配置文件准备完毕后,docker compose restart重启FastGPT服务,启动完成后进入FastGPT后台
2.3.1 创建知识库
左侧菜单栏-新建知识库,索引模型和文件处理模型都选择为我们自定义的模型,创建知识库
进入知识库,选择导入数据集,这里选择通过网页+选择器方式来导入数据集,确认数据导入后,知识库就准备完毕了
2.3.2 创建AI应用
点击应用-新建应用,场景选择知识库+对话引导,AI模型选择我们自定义的llmops_atom模型,提示词和对话开场白可自定义,以下是我的提示词和对话模板,可供参考:
你是一个基于星环科技内部IT知识库和星环LLMOPS平台训练的面向内部员工的AI助手
回答要求:
- 请使用简洁且专业的语言来回答用户的问题。
- 如果你不知道答案,请回答“没有在知识库中查找到相关信息,建议咨询相关技术支持或参考[IT知识库](http://it-kb.transwarp.io/)文档进行操作”。
- 避免提及你是从已知信息中获得的知识。
- 请保证答案与已知信息中描述的一致。
- 请使用 Markdown 语法优化答案的格式。
- 已知信息中的图片、链接地址和脚本语言请直接返回。
- 请使用与问题相同的语言来回答。
🤯你好,我是IT-AI小助手,帮助你解答公司内IT相关问题。
你可以向我提问:
[介绍一下你自己]
[如何配置远程办公VPN]
[如何配置代理服务器]
***
🧠知识库未覆盖到的问题会根据记录逐步标注完善
🤖GPT 也可能会犯错,重要信息请务必核查
在关联知识库中,选择我们刚刚创建完成的知识库,搜索模式选择语义检索并开启问题优化,优化模型同样选择我们创建的atom模型
配置完成后,我们在调试预览中与AI对话测试,不出意外的话AI已经可以正常回答知识库问题啦!
三、发布应用
我们最终的使用场景是在已有的IT服务台中进行AI对话,这里我选择最简单的实现方式——iFrame窗口嵌入
3.1 导出应用
在FastGPT应用窗口中,选择发布应用,选择免登录窗口,创建新链接,使用方式选择iFrame,然后复制出iframe代码块。
3.2 嵌入窗口
在IT服务台前端代码中,新建Vue视图,调整iFrame窗口宽高和边框样式,即可完成嵌入,将视图发布出来即可实现最终效果啦!
<template>
<iframe
src="http://172.16.20.41:3000/chat/share?shareId=tg8ci9osgnf2zvzwz1lpp12k"
style="width: 100%; height: calc(100vh - 126px);"
frameborder="0"
allow="*"
/>
</template>