本文迁移自 mindcarver/91ai · 原始位置
docs/evaluation/fastgpt-architecture.md· 由 @阿新聊ai 整理。
FastGPT 技术架构与实现原理
FastGPT 是四家里前端体验最好、模型层最复杂的一个。它的定位是"对话式知识问答 + 工作流编排",中文生态成熟、检索质量高。但它的模型系统是三层叠加(aiproxy + mongo 注册表 + plugin daemon),PDF 解析还有个静默失败的坑。本文拆解它的技术栈、三层模型架构、数据流与那些隐蔽的 API 坑——所有结论来自对其 Next.js 源码(projects/app/src/...)、MongoDB 集合、aiproxy postgres、API 行为的一手观察。
一、技术栈
| 层 | 选型 | 说明 |
|---|---|---|
| 前端 + BFF | Next.js(Node) | 实测运行 next-server (v16.2.6),API 路由在 projects/app/src/pages/api/ |
| 主数据库 | MongoDB | 知识库、文档、切片、训练队列、模型注册全在 mongo |
| 向量库 | PgVector(fastgpt-pg 容器) | 存 embedding 向量 |
| 对象存储 | MinIO | 存上传的原始文件 |
| 缓存/队列 | Redis | 训练/embedding 队列 |
| 模型代理 | aiproxy(独立 Go 服务 + 自己的 postgres) | 路由 LLM/embedding 请求到后端(如 Ollama) |
| 插件守护 | plugin daemon(独立进程) | 提供 builtin 模型列表、插件运行 |
| 部署 | docker-compose,10 个容器 | 服务最分散(app/plugin/code-sandbox/mcp-server/aiproxy/pg/mongo/redis/minio) |
FastGPT 的"服务多"源于它把模型代理(aiproxy)、插件(plugin daemon)、代码沙箱(code-sandbox)、MCP server 都拆成了独立服务。这种解耦让它扩展性强,但也让配置(一堆 token/key)非常密。
二、三层模型系统(FastGPT 最复杂的部分)
FastGPT 的模型管理是三层叠加,理解这三层是理解 FastGPT 的关键:
┌─────────────────────────────────────────────────┐
│ FastGPT app (Next.js) │
│ └─ global.systemModelList (从下面两处汇总) │
└─────────────────────────────────────────────────┘
│ │
▼ pluginClient ▼ MongoSystemModel
┌───────────────┐ ┌──────────────────┐
│ plugin daemon │ │ mongo: │
│ (builtin 模型)│ │ system_models │
│ listModels() │ │ (custom 模型/覆盖)│
└───────────────┘ └──────────────────┘
│
▼ 推理时
┌───────────────┐
│ aiproxy (Go) │ → Ollama / OpenAI / ...
│ postgres: │
│ channels │
│ model_configs│
└───────────────┘
- plugin daemon:提供 builtin 模型列表(标准目录,如 OpenAI 的 text-embedding-3-small、bge 系列,实测共 278 个 builtin 模型,默认只 2 个 active)。
- mongo
system_models:存自定义模型或对 builtin 的覆盖。文档结构{model, metadata},metadata 是完整模型定义(type/provider/defaultToken/maxToken 等)。custom 模型带requestUrl直连后端(绕过 aiproxy)。 - aiproxy:实际路由推理请求的 Go 服务,有自己的 postgres(
channels/model_configs/groups表)。channel 定义"哪个后端提供哪些模型"。
loadSystemModels 的合并逻辑
FastGPT 启动时 loadSystemModels 把三处合并:
- 先取 plugin daemon 的 builtin 模型(
pluginClient.listModels())。 - 再叠加 mongo
system_models里不与 builtin 重名的 custom 模型。 - 默认模型(
systemDefaultModel.embedding/llm)从 active 列表里选。
关键坑:custom 模型能被 pushModel 列出,但 getSystemModelConfig(实际使用时取配置)对 custom 模型直接 reject 'Custom model not data'——custom 模型能列出但不能用。要让 custom 模型可用,必须配 requestUrl 直连后端(不经过 aiproxy/plugin 的标准路径)。这是 FastGPT 接 Ollama 自定义模型的核心机制。
三、数据流:从文本/PDF 到可检索
FastGPT 的灌库分"文本灌库"和"文件灌库"两条路:
[文本] POST /api/core/dataset/collection/create/text {datasetId, name, text, trainingType, chunkSize}
→ 创建 collection + 异步 training(embedding)
[文件] POST /api/core/dataset/collection/create/localFile (multipart: file + data)
→ 上传文件 → readFile worker 解析 → 切块 → training
trainingType 支持 chunk(按规则切)和 qa(用 LLM 生成 Q&A 对)。文件解析走 readFile worker,根据扩展名分发:
- PDF:默认
readPdfByLiteParse(@llamaindex/liteparse原生二进制),失败回退readPdfByPdfJs(pdfjs)。 - docx/xlsx/pptx:各自的 extension handler。
- txt/md/html/csv:原生解析。
异步训练队列
灌库后,chunks 进入 dataset_trainings 集合排队。FastGPT 有两个并发循环:
- Parse queue(切片):解析文件 → 生成 training rows。
- Vector queue(embedding):取 training rows → 调 embedding → 写
dataset_datas。
实测 Vector queue 并发上限 10(max: 10)。embedding 完成后 dataset_trainings 该条删除、dataset_datas 增加。检索就绪 = trainings 为 0。
四、PDF 解析的静默失败坑(LiteParse vs pdfjs)
这是 FastGPT 最隐蔽的坑,实测中卡了很久:
FastGPT 默认用 LiteParse(@llamaindex/liteparse,原生二进制 liteparse.linux-x64-gnu.node + libpdfium.so)解析 PDF。但 LiteParse 对真实复杂 PDF(如 SEC 合同)会报 "PDF error: invalid PDF format",且重传稳定复现(不是偶发)。
FastGPT 内置了 pdfjs 兜底(readPdfByPdfJs),但 readPdfFile 的回退逻辑(extension/pdf.ts)只在特定错误下触发:
LITE_PARSE_NATIVE_ERROR_PATTERNS = [
/failed to load native module/i,
/cannot find module ['"]@llamaindex\/liteparse-/i,
/liteparse.*native/i, ...
]
注释明说:"只有部署环境不兼容导致的 native/optional dependency 错误才回退 PDF.js;PDF 内容解析失败等业务错误继续抛出,避免 fallback 掩盖真实问题。"
所以 LiteParse 报 "invalid PDF format"(内容错误)→ 不回退,直接抛错 → 该 PDF 解析失败。实测 39/50 份 CUAD PDF 失败,且不报错给用户(只在 dataset_trainings.errorMsg 里),灌库看着成功,实则大半文档没切出 chunk。
解法:禁用 LiteParse(把 .node 和 libpdfium.so 改名),让它走 "native load failed" 分支 → 自动用 pdfjs。pdfjs 是纯 JS,对复杂 PDF 更宽容(实测禁用后 50/50 解析成功)。但这是个 hack,FastGPT 没提供"强制用 pdfjs"的配置开关。
五、鉴权:token header 的坑
FastGPT 的 API 鉴权有个极容易踩的坑:
# ❌ 错误:会报 514 unAuthApiKey
headers = {"Authorization": f"Bearer {user_token}"}
# ✅ 正确:user token 放 token header
headers = {"token": user_token}
原因在 parseHeaderCert(packages/service/support/permission/auth/common.ts):
const { cookie, token, rootkey, authorization } = req.headers;
if (authApiKey && authorization) { // ← Authorization 走 apikey 路径
return parseAuthorization(authorization); // 把 user token 当 apikey 查库 → 失败 → 514
}
if (authToken && (token || cookie)) { // ← user token 要从这里进
return authCookieToken(cookie, token);
}
很多路由(如 dataset create)同时设了 authToken: true 和 authApiKey: true。如果你用 Authorization: Bearer <user_token>,它会优先匹配 apikey 路径,把 user token 当 apikey 去 MongoOpenApi 查,查不到 → 514 unAuthApiKey。必须用 token: header。这个坑浪费了大量调试时间。
另外登录本身也有反爬:preLogin(GET 拿一次性 6 位 code,30 秒过期)+ 密码 sha256 → loginByPassword。
六、检索:searchTest 与 top-1 限制
FastGPT 的检索端点是 POST /api/core/dataset/searchTest:
{
"datasetId": "...",
"text": "查询",
"limit": 5, // 实测无效
"similarity": 0.0,
"searchMode": "embedding" // 也支持 mixed / fullText(需建全文索引)
}
实测 searchTest 恒返回 top-1(无论 limit=5/10,embedding 模式只回 1 条 chunk)。这是"测试预览"端点的设计,真正的 top-K 检索在 chat/workflow 里。这导致横评中 FastGPT 是 top-1 口径(87.5% / 68% / 95% / 0%),与其他三家 top-5 不完全可比——但 top-1 就到这个数,反而说明其首条命中质量高。
返回的 chunk 带 sourceName(来源文件名)、q(内容)、score、collectionId。sourceName 可直接用于 recall 计算。
七、为什么 FastGPT "检索强但摩擦中等"
回到横评,FastGPT 的画像:
- 文本检索强(TechQA 87.5% top-1、CMRC 95% top-1)——单条命中质量高。
- PDF 解析有坑(默认 LiteParse 失败、需禁用走 pdfjs)——这是它最需要警惕的边界。
- 无 OCR(DocVQA 0%)。
- 延迟最低(0.41s)——PgVector + 轻量检索链路。
- 模型层最复杂(三层)——配置心智负担重,但跑通后体验好。
FastGPT 适合"对话式知识问答为主、要中文好、要工作流"的场景。它的痛点在 PDF(需手动解 LiteParse 坑)和模型配置复杂度(三层)。
八、API 自动化友好度
FastGPT 的 API 自动化摩擦中等偏上:
- 登录:反爬码 + sha256。
- 建库/灌库:
tokenheader(坑)。 - 模型配置:aiproxy channel + mongo system_models(坑:custom 模型要 requestUrl)。
- 检索:searchTest(top-1 限制)。
跑通后可重复,但初次集成要踩好几个坑(token header、aiproxy channel 类型、custom 模型 requestUrl、PDF LiteParse)。比 MaxKB 难、比 Dify 容易。
九、扩展性
FastGPT 的多服务架构(10 容器)让它扩展性不错——aiproxy 可独立扩、plugin daemon 可多实例、MongoDB 可副本集。但它的向量库是单 PgVector 实例(fastgpt-pg),大规模向量检索可能成瓶颈(不如 RAGFlow 的 ES 集群)。
FastGPT 的设计重心在用户体验和工作流(Next.js 前端 + 可视化编排),不在超大规模检索。对"几百人到几千人用、知识库几万到几十万篇"的场景,它很合适;再往上,向量库和检索链路可能需要替换。
评论
还没有评论
欢迎留下第一条评论,帮助这篇内容更快形成讨论。