FastGPT 性能优化教程|附源码
在企业知识库、智能客服、内部流程助手等场景中,FastGPT 已经成为很多团队快速落地 AI 应用的重要工具。它把大模型、知识库、工作流、插件调用、对话管理等能力整合在一起,让开发者和业务团队可以更低成本地搭建智能应用。
不过,当 FastGPT 从“能用”走向“高并发、低延迟、稳定运行”时,性能问题就会逐渐显现:接口响应变慢、知识库检索耗时较高、模型调用排队、MongoDB 或 PostgreSQL 压力上升、向量检索结果不稳定、文件解析任务堆积、并发对话时资源占用过高等。
本文将围绕 FastGPT 的典型性能瓶颈,系统讲解如何进行优化,并附上一些可直接参考的源码示例。文章适合已经部署 FastGPT,或准备将 FastGPT 用于生产环境的开发者、运维人员和技术负责人阅读。
一、FastGPT 性能优化的核心思路
在优化 FastGPT 之前,我们需要先明确一点:性能优化不是单纯“加服务器”或者“换更大的模型”。FastGPT 的性能取决于多个环节,包括:
- 前端页面加载速度
- 后端 API 响应速度
- 数据库查询效率
- 向量数据库检索性能
- 知识库分块与召回质量
- 大模型接口响应速度
- 工作流节点执行效率
- 文件解析和索引构建速度
- 缓存策略和并发控制
- Docker、Nginx、Node.js 等运行环境配置
一个 FastGPT 请求从用户输入到返回答案,大致会经过以下流程:
- 用户在前端发起对话请求;
- 后端接收请求并解析应用配置;
- 根据应用编排执行工作流;
- 如果涉及知识库,则进行问题向量化;
- 在向量数据库中检索相关内容;
- 对召回内容进行重排、过滤和拼接;
- 调用大模型生成回答;
- 将结果以流式或非流式方式返回给前端;
- 保存对话记录、Token 用量和日志。
只要其中某个环节耗时过长,用户就会感觉“整个系统很慢”。因此,优化时要坚持一个原则:
先定位瓶颈,再针对性优化,而不是盲目调参。
二、性能瓶颈一:大模型响应慢
FastGPT 的回答速度很大程度上取决于大模型接口。如果你使用的是外部模型服务,例如 OpenAI、Azure OpenAI、通义千问、DeepSeek、智谱、Moonshot 等,接口延迟主要受以下因素影响:
- 模型本身的生成速度;
- 请求上下文长度;
- 网络链路质量;
- 服务商限流策略;
- 是否开启流式响应;
- 当前并发请求数量;
- Prompt 是否过长;
- 知识库召回内容是否过多。
1. 开启流式响应
对于对话类应用,建议优先使用流式输出。流式输出并不会显著减少模型整体生成时间,但能大幅降低用户感知延迟。
非流式响应时,用户必须等模型完整生成完毕后才能看到结果;流式响应时,模型生成第一个 token 后即可开始展示内容。
如果你的 FastGPT 应用面向客服、问答助手、销售助手等交互场景,流式响应几乎是必选项。
2. 控制上下文长度
很多性能问题来自“上下文过长”。例如,系统提示词写了几千字,知识库召回了十几段长文本,再加上历史对话记录,很容易导致单次请求上下文超过几万 token。
上下文越长,模型处理越慢,费用也越高。优化建议如下:
- 精简系统提示词;
- 限制历史对话轮数;
- 控制知识库召回数量;
- 对知识库片段进行摘要;
- 避免把无关内容塞入 Prompt;
- 根据任务选择合适模型,不要所有场景都使用最强模型。
例如,对于简单分类、意图识别、格式转换任务,可以使用轻量模型;对于复杂推理、长文生成,再使用更强模型。
3. 使用模型分层策略
在生产环境中,不建议所有请求都调用同一个大模型。更推荐使用“模型分层”:
- 简单任务:使用速度快、价格低的小模型;
- 中等任务:使用通用对话模型;
- 复杂任务:使用推理能力更强的大模型;
- 向量化任务:使用专门的 embedding 模型;
- 重排任务:使用 rerank 模型或轻量排序逻辑。
这样可以显著降低成本,并提升整体吞吐量。
三、性能瓶颈二:知识库检索慢
FastGPT 的知识库问答通常依赖向量检索。一个典型 RAG 流程包括:
- 用户问题向量化;
- 向量数据库检索相似片段;
- 根据相似度过滤;
- 可能进行重排;
- 拼接上下文;
- 发送给大模型。
如果知识库规模较大,检索速度和召回质量就非常关键。
1. 优化知识库分块策略
分块过大,会导致召回内容冗余、上下文变长、模型生成变慢;分块过小,则可能导致语义不完整,模型拿不到足够信息。
比较推荐的分块策略是:
- 普通知识文档:每块 500~1000 中文字;
- FAQ 文档:一问一答作为一个完整片段;
- 技术文档:按标题层级切分;
- 法律、合同、制度类文档:按条款切分;
- 表格类数据:按行、业务对象或字段组切分;
- 长篇 PDF:先清洗目录、页眉页脚和重复噪音。
分块不是越细越好,也不是越大越好,而是要尽量保持“单个片段能独立表达一个完整语义”。
2. 降低无效召回数量
很多人会把知识库召回数量设置得很高,例如一次召回 20 条甚至 50 条。这样看似可以提高命中率,实际会带来三个问题:
- 检索耗时变长;
- Prompt 上下文过长;
- 模型更容易被噪音干扰。
一般建议:
- 小型知识库:召回 3~5 条;
- 中型知识库:召回 5~8 条;
- 大型知识库:召回 8~12 条,并配合重排;
- 对准确率要求高的场景:启用 rerank,但要注意额外耗时。
3. 使用重排优化召回质量
向量检索擅长找语义相似内容,但不一定能找到最适合回答问题的内容。重排模型可以对初步召回结果再次排序,提高最终输入给大模型的上下文质量。
不过,重排也会增加耗时。因此建议:
- 先召回较多片段,例如 15 条;
- 使用 rerank 选出前 3~5 条;
- 只把高质量片段传给大模型;
- 对低价值场景关闭 rerank;
- 对复杂知识问答场景开启 rerank。
四、性能瓶颈三:数据库查询压力大
FastGPT 常见部署中会使用 MongoDB 存储应用、会话、用户、知识库等数据,也可能使用 PostgreSQL 或向量数据库扩展来处理向量检索。
当用户量上升后,数据库压力会明显增加。典型表现包括:
- 对话列表加载慢;
- 应用配置读取慢;
- 知识库文档管理页面卡顿;
- 后端接口偶发超时;
- CPU 和 I/O 使用率升高;
- MongoDB 慢查询增多。
1. 为高频字段添加索引
数据库优化的第一步是检查慢查询,并为高频查询字段建立索引。常见需要关注的字段包括:
- 用户 ID;
- 应用 ID;
- 团队 ID;
- 知识库 ID;
- 会话 ID;
- 创建时间;
- 状态字段;
- 删除标记字段。
下面是一个 MongoDB 索引示例:
db.chats.createIndex({ appId: 1, userId: 1, updateTime: -1 });
db.messages.createIndex({ chatId: 1, createTime: 1 });
db.datasets.createIndex({ teamId: 1, createTime: -1 });
db.dataset_collections.createIndex({ datasetId: 1, parentId: 1 });
db.dataset_datas.createIndex({ datasetId: 1, collectionId: 1 });
需要注意的是,索引不是越多越好。索引会提升查询速度,但也会增加写入成本和存储空间。因此应该基于真实慢查询日志添加索引。
2. 避免一次性加载大量数据
管理后台经常出现一个问题:列表页一次性加载过多字段或过多记录。例如对话记录、知识库数据、文件列表等,如果不分页或分页过大,就会导致接口响应变慢。
优化建议:
- 所有列表接口必须分页;
- 默认分页大小控制在 20~50;
- 大字段按需加载;
- 列表页不返回完整正文;
- 文件内容、对话详情、知识库原文使用详情接口单独加载;
- 后台管理接口也要做权限和分页限制。
3. 使用投影减少字段返回
MongoDB 查询时可以通过 projection 只返回需要的字段。例如列表页通常只需要标题、状态、时间和 ID,不需要完整内容。
示例代码:
const chats = await ChatModel.find(
{
appId,
userId
},
{
_id: 1,
title: 1,
updateTime: 1,
createTime: 1
}
)
.sort({ updateTime: -1 })
.limit(30)
.lean();
这里有两个关键点:
- 第二个参数限制返回字段;
.lean()可以避免 Mongoose 创建完整文档对象,减少内存开销。
在高并发接口中,.lean() 是非常常见且有效的优化手段。
五、性能瓶颈四:Node.js 服务吞吐不足
FastGPT 后端通常运行在 Node.js 环境中。Node.js 适合 I/O 密集型应用,但如果处理不当,也容易出现 CPU 阻塞、内存增长、请求排队等问题。
1. 使用多进程部署
Node.js 单进程默认只能使用一个 CPU 核心。生产环境建议使用多实例部署,例如通过 Docker Compose、Kubernetes、PM2 或云平台副本数扩展。
如果使用 PM2,可以参考:
pm2 start server.js -i max
如果使用 Docker Compose,可以通过多个服务副本或负载均衡实现扩容。
Kubernetes 中可以使用:
apiVersion: apps/v1
kind: Deployment
metadata:
name: fastgpt
spec:
replicas: 3
selector:
matchLabels:
app: fastgpt
template:
metadata:
labels:
app: fastgpt
spec:
containers:
- name: fastgpt
image: fastgpt:latest
ports:
- containerPort: 3000
多副本部署后,需要确保会话状态、文件存储和数据库连接不会依赖单个实例本地内存。
2. 避免 CPU 密集任务阻塞主线程
文件解析、长文本清洗、批量向量化、复杂数据转换都可能占用较多 CPU。如果这些任务直接在 API 请求线程中执行,会影响普通对话请求。
优化思路:
- 文件解析任务异步化;
- 批量向量化放入任务队列;
- 大文件处理拆分成小任务;
- 使用 worker 或独立服务处理重任务;
- API 接口只负责提交任务和查询状态。
下面是一个简单任务队列示例:
type Job = {
id: string;
type: 'embedding';
payload: {
datasetId: string;
textList: string[];
};
};
const queue: Job[] = [];
let running = false;
export function addEmbeddingJob(job: Job) {
queue.push(job);
runQueue();
}
async function runQueue() {
if (running) return;
running = true;
while (queue.length > 0) {
const job = queue.shift();
if (!job) continue;
try {
await handleEmbeddingJob(job);
} catch (error) {
console.error('Embedding job failed:', error);
}
}
running = false;
}
生产环境不建议使用内存队列,因为服务重启会丢任务。更推荐 Redis、BullMQ、RabbitMQ、Kafka 等成熟队列方案。
六、性能瓶颈五:向量化任务堆积
在 FastGPT 中,知识库导入通常需要解析文档、切分文本、调用 embedding 模型、写入向量数据库。这个过程如果处理不当,很容易造成任务堆积。
尤其是用户批量上传 PDF、Word、Excel 时,系统可能同时触发大量 embedding 请求,导致模型服务限流或数据库写入压力过大。
1. 控制并发数量
向量化任务应该限制并发,而不是无限制同时执行。下面是一个简单并发控制函数:
export async function runWithConcurrency(
list: T[],
limit: number,
handler: (item: T, index: number) => Promise
): Promise {
const results: R[] = [];
let cursor = 0;
async function worker() {
while (cursor < list.length) {
const currentIndex = cursor++;
results[currentIndex] = await handler(list[currentIndex], currentIndex);
}
}
const workers = Array.from(
{ length: Math.min(limit, list.length) },
() => worker()
);
await Promise.all(workers);
return results;
}
使用方式:
const vectors = await runWithConcurrency(chunks, 5, async (chunk) => {
return createEmbedding(chunk.text);
});
这样可以把同时进行的 embedding 请求控制在 5 个以内,避免打爆模型服务。
2. 批量写入向量数据
如果每生成一个向量就写一次数据库,写入效率会很低。更好的方式是批量写入:
await VectorModel.insertMany(
vectors.map((item) => ({
datasetId,
collectionId,
text: item.text,
embedding: item.embedding,
createTime: new Date()
})),
{ ordered: false }
);
批量写入可以减少数据库连接开销,但单批数量也不能过大。一般可以控制在 100~500 条之间,根据数据库性能调整。
七、性能瓶颈六:Prompt 设计不合理
很多 FastGPT 应用性能差,并不是服务器不够强,而是 Prompt 写得太重。
典型问题包括:
- 系统提示词过长;
- 每次请求都塞入大量固定背景;
- 多个工作流节点重复调用大模型;
- 模型输出格式约束过度复杂;
- 不必要地要求模型解释推理过程;
- 历史对话保留过多;
- 知识库内容未经筛选直接拼接。
1. 压缩系统提示词
系统提示词应该清晰、直接、可执行。不要把产品介绍、公司背景、所有规则都塞进去。如果确实需要大量业务规则,可以把规则放入知识库,通过检索动态召回。
示例:
你是企业内部知识库助手。请根据提供的知识库内容回答问题。
如果知识库中没有相关信息,请明确说明“当前知识库未找到相关信息”,不要编造。
回答应简洁、准确,必要时使用条目列表。
这个提示词虽然不长,但已经包含了角色、依据、边界和输出风格。
2. 减少重复模型调用
一些复杂工作流中,可能会出现多个连续 AI 节点:
- 第一个节点判断意图;
- 第二个节点改写问题;
- 第三个节点检索知识库;
- 第四个节点总结答案;
- 第五个节点润色回复。
这会显著增加延迟。如果业务允许,可以合并节点,或者将部分任务改成规则判断。
例如,简单意图识别可以用关键词、正则或分类模型,不一定要每次调用大语言模型。
八、缓存优化:降低重复计算
缓存是提升 FastGPT 性能的重要手段。适合缓存的数据包括:
- 应用配置;
- 用户权限;
- 模型配置;
- 知识库元信息;
- 高频问答结果;
- embedding 结果;
- 文件解析结果;
- 工作流静态配置。
1. 应用配置缓存
应用配置通常不会频繁变化,但每次对话都会读取。如果每次都查数据库,会造成不必要压力。
示例代码:
type CacheItem = {
value: T;
expireAt: number;
};
const appCache = new Map>();
export async function getCacheOrLoad(
key: string,
ttlMs: number,
loader: () => Promise
): Promise {
const cached = appCache.get(key);
if (cached && cached.expireAt > Date.now()) {
return cached.value as T;
}
const value = await loader();
appCache.set(key, {
value,
expireAt: Date.now() + ttlMs
});
return value;
}
使用方式:
const appConfig = await getCacheOrLoad(
`app:${appId}`,
60 * 1000,
() => AppModel.findById(appId).lean()
);
需要注意,如果是多实例部署,内存缓存只在单个实例内有效。生产环境可以使用 Redis 做分布式缓存。
2. 高频问题答案缓存
对于客服场景,很多问题高度重复,例如:
- “怎么重置密码?”
- “发票怎么开?”
- “如何联系客服?”
- “支持哪些付款方式?”
这类问题可以缓存最终答案,减少知识库检索和模型调用。
不过,答案缓存要谨慎使用,尤其是涉及价格、合同、政策、库存等动态信息时,需要设置较短 TTL,或者在数据变更时主动失效。
九、Nginx 与网络层优化
如果 FastGPT 部署在公网环境,通常会在前面挂 Nginx、Ingress 或云负载均衡。网络层配置不当,也会影响流式响应和并发能力。
1. 支持流式输出
Nginx 默认缓冲可能导致流式响应变成“攒一段再返回”,影响用户体验。可以参考以下配置:
location /api/ {
proxy_pass http://fastgpt_backend;
proxy_http_version 1.1;
proxy_set_header Connection '';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_buffering off;
proxy_cache off;
chunked_transfer_encoding on;
proxy_read_timeout 300s;
proxy_send_timeout 300s;
}
其中 proxy_buffering off 对流式响应非常关键。
2. 开启 gzip 或 brotli
对于前端静态资源,可以开启压缩:
gzip on;
gzip_comp_level 5;
gzip_min_length 1024;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml image/svg+xml;
这可以减少 JS、CSS、JSON 等资源传输体积,提升页面加载速度。
十、Docker 部署优化
很多团队使用 Docker Compose 部署 FastGPT。默认配置适合快速体验,但生产环境还需要关注资源限制、日志、健康检查和重启策略。
1. 设置合理资源限制
示例:
services:
fastgpt:
image: fastgpt:latest
restart: always
deploy:
resources:
limits:
cpus: '2'
memory: 4G
reservations:
memory: 1G
资源限制可以防止单个容器异常占满整台机器,但也不能设置过低,否则 Node.js 可能频繁 GC,反而变慢。
2. 配置健康检查
services:
fastgpt:
image: fastgpt:latest
healthcheck:
test: ['CMD', 'wget', '-qO-', 'http://localhost:3000/api/system/health']
interval: 30s
timeout: 5s
retries: 3
健康检查可以帮助容器平台及时发现异常实例,并配合重启策略恢复服务。
十一、监控与日志:优化前必须先可观测
没有监控的性能优化,基本都是猜。生产环境至少应该关注以下指标:
- API 平均响应时间;
- P95、P99 响应时间;
- 大模型调用耗时;
- embedding 调用耗时;
- 知识库检索耗时;
- MongoDB 慢查询;
- 向量数据库查询耗时;
- Node.js 内存使用;
- CPU 使用率;
- 请求错误率;
- 队列积压数量;
- Token 消耗量。
1. 简单接口耗时日志
可以在服务端增加请求耗时日志:
export function withCostLog Promise>(
name: string,
fn: T
): T {
return (async (...args: Parameters) => {
const start = Date.now();
try {
return await fn(...args);
} finally {
const cost = Date.now() - start;
console.log(`[cost] ${name}: ${cost}ms`);
}
}) as T;
}
使用方式:
const searchDatasetWithLog = withCostLog('dataset.search', searchDataset);
const callLLMWithLog = withCostLog('llm.chat', callLLM);
当你能看到每个环节的耗时后,就能判断到底是数据库慢、检索慢,还是模型慢。
十二、推荐的生产环境优化清单
下面给出一份比较实用的 FastGPT 生产优化清单。
1. 应用层
- 开启流式响应;
- 精简 Prompt;
- 限制历史对话轮数;
- 控制知识库召回数量;
- 对复杂场景启用 rerank;
- 减少不必要的大模型节点;
- 按任务选择不同模型;
- 对高频问题使用缓存。
2. 知识库层
- 文档导入前先清洗;
- 按语义合理分块;
- 删除重复、无效、过期内容;
- 控制 chunk 大小;
- 批量执行 embedding;
- 限制向量化并发;
- 大知识库使用重排;
- 定期评估召回命中率。
3. 数据库层
- 为高频查询字段建索引;
- 所有列表接口分页;
- 使用 projection 减少字段返回;
- 高频只读数据加缓存;
- 关注慢查询日志;
- 定期清理无效会话和临时数据;
- 大表按业务拆分或归档。
4. 服务层
- 多实例部署;
- 配置合理连接池;
- 使用任务队列处理重任务;
- 限制单用户并发;
- 设置接口超时时间;
- 避免 CPU 密集任务阻塞主线程;
- 使用 Redis 做分布式缓存和锁。
5. 运维层
- 配置 Nginx 流式转发;
- 开启静态资源压缩;
- 设置容器健康检查;
- 配置日志轮转;
- 监控 P95、P99 延迟;
- 监控模型调用错误率;
- 监控队列积压;
- 定期压测核心接口。
十三、一个完整的优化示例
假设你的 FastGPT 知识库问答接口平均耗时为 12 秒,用户反馈“回答很慢”。你可以按以下步骤排查:
- 记录整体接口耗时;
- 拆分记录 embedding 耗时;
- 记录向量检索耗时;
- 记录 rerank 耗时;
- 记录大模型首 token 时间;
- 记录完整生成时间;
- 查看 Prompt token 数量;
- 查看知识库召回条数;
- 查看数据库慢查询;
- 检查 Nginx 是否缓冲流式响应。
如果排查结果如下:
- embedding:800ms;
- 向量检索:300ms;
- rerank:1500ms;
- 大模型首 token:2500ms;
- 大模型完整生成:9000ms;
- Prompt 长度:18000 token;
- 知识库召回:20 条。
那么主要瓶颈并不是数据库,而是上下文过长和模型生成慢。可以这样优化:
- 召回数量从 20 降到 10;
- rerank 后只保留前 4 条;
- 历史对话从 10 轮降到 4 轮;
- 压缩系统提示词;
- 使用更快的模型;
- 开启流式响应;
- 对常见问题增加缓存。
优化后,Prompt 可能从 18000 token 降到 6000 token,完整生成时间也可能从 9 秒降到 3~5 秒,用户体验会明显改善。
十四、总结
FastGPT 性能优化的关键,不是单点调参,而是对整条链路进行系统治理。一次对话请求背后,涉及前端、后端、数据库、向量检索、知识库质量、大模型调用、网络代理和运行环境。任何一个环节设计不合理,都可能拖慢整体体验。
如果你正在把 FastGPT 用于生产环境,建议优先做好三件事:
第一,建立可观测能力。没有日志和监控,就无法判断真正瓶颈在哪里。至少要记录模型调用耗时、知识库检索耗时、接口总耗时和错误率。
第二,控制上下文规模。Prompt、历史对话和知识库召回内容越长,模型响应越慢,成本越高。合理分块、精准召回、适当重排和精简提示词,是优化 RAG 应用的核心。
第三,异步化重任务。文件解析、批量向量化、大规模导入等任务不应该阻塞普通对话接口。通过任务队列、并发控制和批量写入,可以显著提升系统稳定性。
FastGPT 的优势在于快速构建 AI 应用,而真正把它用好,则需要工程化能力。只要你按照本文的方法逐步排查和优化,就能让 FastGPT 在更高并发、更复杂知识库和更严肃的业务场景中保持稳定、快速和可控。
Label:
- FastGPT性能优化
- 知识库检索
- 大模型响应
- 生产环境部署