基于 LangChain + LangGraph + RAG 的企业级智能文档知识库系统(完整源码解析版)
技术栈:Next.js + Express + LangChain + LangGraph + ChromaDB + OpenAI + RAG
适用方向:AI SaaS / 企业知识库 / 私有部署问答系统 / 技术面试项目
github地址
前言
本文基于完整项目源码结构,按照真实企业级项目开发逻辑,系统性讲解如何从 0 到 1 搭建一套智能文档知识库系统。
核心目标:
用户上传文件
↓
文档解析(PDF / Word / Excel / 图片OCR)
↓
文档切片(Chunk)
↓
Embedding 向量化
↓
ChromaDB 私有知识库存储
↓
用户提问
↓
相似度召回
↓
Prompt增强
↓
OpenAI回答
↓
SSE流式输出
一、项目整体架构
src/
├── services/
│ ├── document/
│ │ ├── parser.ts
│ │ ├── chunker.ts
│ │ └── document-processing.ts
│ ├── rag/
│ │ └── retriever.ts
│ └── chatRoute.ts
│
├── frontend/
│ ├── UploadForm.tsx
│ └── ChatInterface.tsx
│
└── server.ts
二、核心源码完整解析
1. parser.ts —— 多格式文档解析中心
文件职责:
负责统一接入企业文档资产:
- Word
- Excel
- 图片 OCR
import pdf from 'pdf-parse';
import mammoth from 'mammoth';
import Tesseract from 'tesseract.js';
import * as XLSX from 'xlsx';
export interface DocumentMetadata {
source?: string;
title: string;
author?: string;
pages?: number;
wordCount?: number;
language?: string;
createdAt: Date;
}
export class DocumentParser {
async parsePDF(buffer: Buffer) {
const data = await pdf(buffer);
return {
content: data.text,
metadata: {
title: data.info?.Title || 'Untitled',
author: data.info?.Author,
pages: data.numpages,
wordCount: data.text.split(/\s+/).length,
createdAt: new Date()
}
};
}
async parseWord(buffer: Buffer) {
const result = await mammoth.extractRawText({ buffer });
return {
content: result.value,
metadata: {
title: 'Word Document',
wordCount: result.value.split(/\s+/).length,
createdAt: new Date()
}
};
}
async parseExcel(buffer: Buffer) {
const workbook = XLSX.read(buffer);
let content = '';
workbook.SheetNames.forEach(sheetName => {
const worksheet = workbook.Sheets[sheetName];
const sheetData = XLSX.utils.sheet_to_csv(worksheet);
content += `Sheet: ${sheetName}\n${sheetData}\n\n`;
});
return {
content,
metadata: {
title: workbook.Props?.Title || 'Excel Document',
createdAt: new Date()
}
};
}
async parseImage(buffer: Buffer) {
const { data: { text } } = await Tesseract.recognize(
buffer,
'chi_sim+eng'
);
return {
content: text,
metadata: {
title: 'Image Document',
wordCount: text.split(/\s+/).length,
createdAt: new Date()
}
};
}
async parseDocument(buffer: Buffer, mimeType: string) {
switch (mimeType) {
case 'application/pdf':
return this.parsePDF(buffer);
case 'application/vnd.openxmlformats-officedocument.wordprocessingml.document':
return this.parseWord(buffer);
case 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet':
return this.parseExcel(buffer);
case 'image/jpeg':
case 'image/png':
case 'image/gif':
return this.parseImage(buffer);
default:
throw new Error(`不支持的文件类型: ${mimeType}`);
}
}
}
模块总结:
作用:
这是整个系统的“知识入口层”。
技术亮点:
- 多格式统一解析
- OCR 支持扫描件
- 元数据标准化
- 企业知识沉淀入口
2. chunker.ts —— 文档切片系统
import { RecursiveCharacterTextSplitter } from "@langchain/textsplitters";
import { Document } from '@langchain/core/documents';
import { v4 as uuidv4 } from 'uuid';
export class DocumentChunker {
private textSplitter: RecursiveCharacterTextSplitter;
constructor() {
this.textSplitter = new RecursiveCharacterTextSplitter({
chunkSize: 400,
chunkOverlap: 50,
separators: ['\n\n', '\n', '。', '!','?',';','.','!', '?',';',' ',''
]
});
}
async chunkDocument(content: string, metadata: any): Promise<Document[]> {
const documents = await this.textSplitter.createDocuments(
[content],
[metadata],
{
chunkHeader: `文档: ${metadata.title}\n\n`,
appendChunkOverlapHeader: true
}
);
return documents.map((doc, index) => ({
...doc,
metadata: {
id: uuidv4(),
...doc.metadata,
chunkIndex: index,
totalChunks: documents.length
}
}));
}
}
模块总结:
核心作用:
解决大模型上下文限制问题。
为什么重要:
RAG 检索质量高度依赖 Chunk 策略。
优化点:
- 中文友好分隔符
- overlap 防断层
- UUID 唯一标识
- Metadata 增强
3. document-processing.ts —— LangGraph 工作流核心
workflow.addNode("parse", this.parseDocument.bind(this));
workflow.addNode("chunk", this.chunkDocument.bind(this));
workflow.addNode("embed", this.embedChunks.bind(this));
workflow.addNode("index", this.indexChunks.bind(this));
workflow.addNode("complete", this.completeProcessing.bind(this));
workflow.addNode("fail", this.handleFailure.bind(this));
workflow.addEdge(START, "parse");
workflow.addConditionalEdges("parse", this.checkParseResult.bind(this));
workflow.addConditionalEdges("chunk", this.checkChunkResult.bind(this));
workflow.addConditionalEdges("embed", this.checkEmbedResult.bind(this));
workflow.addEdge("index", "complete");
状态流:
START
↓
parse
↓
chunk
↓
embed
↓
index
↓
complete
失败:
任意节点 → fail
模块总结:
核心作用:
构建企业级可追踪文档处理流水线。
优势:
- 可恢复
- 可追踪
- 可扩展
- 可插入审核节点
- 工程化极强
4. retriever.ts —— RAG 向量数据库层
import { ChromaClient } from "chromadb";
import { OpenAIEmbeddings } from "@langchain/openai";
export class RAGRetriever {
private vectorStore: ChromaClient;
private embeddings: OpenAIEmbeddings;
constructor() {
this.vectorStore = new ChromaClient({
path: process.env.CHROMA_URL
});
this.embeddings = new OpenAIEmbeddings({
model: "text-embedding-3-small",
dimensions: 768,
});
}
async addDocuments(documents: any, name: string) {
const collection = await this.vectorStore.createCollection({
name: `rag_${name}`,
});
await collection.add({
ids: documents.batchIds,
embeddings: documents.batchVectors,
documents: documents.batchTexts,
metadatas: documents.batchMetas,
});
}
async similaritySearch(name: string, query: string, k = 5, filter: any) {
const queryVector = await this.embeddings.embedQuery(query);
const collection = await this.vectorStore.getCollection({
name: `rag_${name}`,
});
return await collection.query({
queryEmbeddings: [queryVector],
nResults: k,
include: ["documents", "metadatas", "distances"],
where: Object.keys(filter).length ? filter : undefined,
});
}
}
模块总结:
核心职责:
- Embedding
- 向量存储
- 检索召回
- 多租户隔离
企业价值:
rag_${userId}
实现用户级知识库隔离。
5. chatRoute.ts —— API 调度中心
router.post("/upload", upload.single("file"), chatController);
router.post("/chats", ChatInterface);
上传流程:
const app = await documentProcessingWorkflow.buildGraph();
const result = await app.invoke({
mimeType: file.mimetype,
buffer: file.path,
name: 'wqq'
});
问答流程:
const hits = await retriever.similaritySearch(
chatId,
message,
5,
{}
);
Prompt:
const prompt = PromptTemplate.fromTemplate(`
你是一个文档问答助手。
文档内容:
{content}
用户问题:
{message}
`);
SSE:
for await (const chunk of stream) {
res.write(
`data: ${JSON.stringify({
type: "chunk",
data: chunk.content,
})}\n\n`
);
}
模块总结:
核心职责:
这是整个 AI 系统的大脑调度层。
6. server.ts —— 服务启动层
import express from "express";
import cors from "cors";
import dotenv from "dotenv";
dotenv.config();
const app = express();
app.use(cors());
app.use(express.json());
app.use("/api/chat", chatRouter);
app.listen(3001, () => {
console.log("🚀 Server running");
});
模块职责:
- 服务启动
- 跨域支持
- 路由注册
- 环境管理
7. UploadForm.tsx —— 用户上传入口
const response = await fetch(
'http://localhost:3001/api/chat/upload',
{
method: 'POST',
body: formData,
}
);
功能:
- 文件上传
- 拖拽支持
- 格式校验
- 状态提示
8. ChatInterface.tsx —— 智能聊天前端
const reader = response.body.getReader();
assistantMessage.content += data.data;
setMessages(...)
实现:
- ChatGPT 式交互
- SSE 流式输出
- 实时响应
- 更佳用户体验
三、项目整体技术价值
企业级能力:
已实现:
- 多格式解析
- OCR
- RAG
- LangGraph
- ChromaDB
- OpenAI
- SSE
- SaaS架构基础
四、可扩展方向
推荐升级:
- Redis缓存
- BullMQ异步任务
- Docker
- Kubernetes
- Pinecone / Milvus
- 用户权限系统
- 支付系统
- 多租户管理
五、项目难点总结
技术难点:
1. 类型系统:
- Document 类型兼容
- Metadata 对齐
- UUID 管理
2. RAG:
- Chunk Size 设计
- Embedding 成本
- 检索精度
3. LangGraph:
- 状态流设计
- 条件边
- 故障恢复
4. SSE:
- 半包问题
- 流式拼接
- JSON解析
六、总结
这不是简单 Demo,而是一套完整的:
企业级 AI 知识中台系统
核心关键词:
- LangChain
- LangGraph
- RAG
- ChromaDB
- Next.js
- Express
- OpenAI
- 私有知识库
- 企业AI
- SaaS