从通义到智谱、从裸跑 RAG 到企业级平台:RAG 平台 V2 升级全记录
前置阅读:本文是 [Claude Code + 通义千问,从零搭出生产级 RAG 要花多少钱?) 的续篇。V1 版本记录了「Claude Code 写规格 + 通义千问做推理」从零搭建生产级 RAG 的全过程(14 个 Bug、约 100 元 API 成本)。V2 在 V1 基础上完成了模型切换、安全加固、可观测性补全与前端企业级改造。
说明:当前升级全部使用claude code + 智普Coding plan来完成,当前文档也是claude cod + 智普GLM5.1来生成的。
升级背景与动机
V1 跑通后暴露了几个明确的短板:
- 无认证、无审计:任何能访问后端端口的人都能操作全部 API,无法满足企业部署合规要求
- 评测只有面板壳子:前端有评估面板 UI,但后端没有真正的评测管道,指标全靠手填
- 模型侧隐患:LangChain
OpenAIEmbeddings对通义 API 返回零向量的 Bug 虽然绕过了(用configuration.baseURL),但长期来看 LangChain 对国内 API 的兼容性不可控 - 缺少监控:生产系统需要实时知道「请求延迟多少、错误率多少、缓存命中多少」,V1 全靠 console.log
- 没有用户反馈闭环:产品侧无法收集「这个回答有没有帮助」,无法量化模型表现
升级全景:从 V1 到 V2 的变更总览
V1(第一版) V2(升级版)
┌──────────────────────┐ ┌──────────────────────┐
│ 通义 qwen3.6-plus │ ──切换──→ │ 智谱 GLM-4.5-Air │
│ text-embedding-v3 │ │ embedding-3 (2048维) │
│ (1024维) │ │ │
├──────────────────────┤ ├──────────────────────┤
│ 无认证 │ ──新增──→ │ JWT + 角色控制 │
│ 无审计 │ │ 完整审计日志 │
│ console.log │ │ Prometheus 指标 │
│ 无用户反馈 │ │ 用户反馈系统 │
├──────────────────────┤ ├──────────────────────┤
│ 评测面板(空壳) │ ──实现──→ │ 端到端评测管道 │
│ │ │ HitRate/MRR/忠实度等 │
│ │ │ A/B 测试能力 │
├──────────────────────┤ ├──────────────────────┤
│ LangChain Embeddings │ ──重写──→ │ 直接 fetch 调 API │
│ (兼容性不可控) │ │ (绕过 LangChain) │
├──────────────────────┤ ├──────────────────────┤
│ 5 种文档解析器 │ ──新增──→ │ + GLM-OCR 图片解析 │
│ │ │ (保留表格/公式/版式) │
├──────────────────────┤ ├──────────────────────┤
│ 前端四面板 │ ──扩展──→ │ + 登录/注册 │
│ │ │ + 管理员审计日志 │
│ │ │ + 实时监控面板 │
│ │ │ + 配置调参面板增强 │
└──────────────────────┘ └──────────────────────┘
一、模型切换:从通义到智谱
1.1 切换原因
V1 使用通义千问 qwen3.6-plus 作为对话模型,text-embedding-v3 作为向量模型(经阿里百炼 OpenAI 兼容接口调用)。升级时切换到智谱 AI 的原因:
买了智普的coding plan,想试试包月Pro的token量是否能满足日常的工作需求,同时开通了两个体验资源包,Embedding-3、GLM-OCR。
1.2 模型对应关系
| 功能 | V1 | V2 |
|---|---|---|
| 对话/生成 | qwen3.6-plus(通义) |
GLM-4.5-Air(智谱) |
| 向量嵌入 | text-embedding-v3(1024维) |
embedding-3(2048维) |
| API 基地址 | dashscope.aliyuncs.com/compatible-mode/v1 |
open.bigmodel.cn/api/paas/v4 |
| OCR | 无 | glm-ocr(智谱布局解析) |
| Rerank | Cohere | Cohere(未变) |
1.3 Embedding 客户端重写
这是本次升级改动最核心、踩坑最深的一处。
V1 的 Embedding 客户端使用 LangChain 的 OpenAIEmbeddings:
// V1 写法(已废弃)
new OpenAIEmbeddings({
model: 'text-embedding-v3',
apiKey: 'sk-...',
configuration: { baseURL: 'https://dashscope.aliyuncs.com/compatible-mode/v1' },
dimensions: 1024,
});
切换到智谱后,OpenAIEmbeddings 对智谱 API 返回零向量——不是报错,而是静默返回 [0, 0, 0, ...]。这个 Bug 比 V1 的 baseUrl 问题更隐蔽:V1 至少是超时或 0 条结果,这次是「向量全零但入库成功、检索永远不匹配」。
解决方案:完全绕过 LangChain,直接用 fetch 调用智谱 /v4/embeddings 端点:
// V2 写法 — 直接 fetch,不依赖 LangChain
export async function callEmbeddingAPI(
input: string[],
apiKey: string,
baseURL: string,
model: string,
): Promise<number[][]> {
const res = await fetch(`${baseURL}/embeddings`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ model, input }),
});
const data = await res.json();
return data.data
.sort((a, b) => a.index - b.index)
.map(d => d.embedding);
}
新增的 OpenAIEmbeddingProvider 类支持:
embed(texts)— 单批嵌入embedMany(texts)— 分批嵌入(每批 50 条,避免 API 限流)embedQuery(text)— 单条查询嵌入(供retrieve.node.ts使用)
1.4 向量维度从 1024 升到 2048
智谱 embedding-3 默认输出 2048 维向量,Milvus 集合需要重建:
// vectorstore/schema.ts — V1 写死 1024,V2 从配置读取
export function getDenseVectorDim(): number {
return getConfig().EMBEDDING_DIMENSION; // 从 .env 读取,当前为 2048
}
操作步骤:
- 修改
.env中EMBEDDING_DIMENSION=2048 - 删除旧 Milvus 集合(维度不可修改)
- 重启后端自动重建集合
- 重新上传文档入库
经验:维度变更意味着全量重建。生产环境应在设计时考虑「维度可变」策略,或在切换模型前评估重建成本。
1.5 LLM 客户端调整
LLM 侧改动较小,ChatOpenAI 对智谱 API 兼容性良好,只需调整 base URL:
// llm/openai.ts — 支持 OpenAI 兼容 API(阿里百炼、智谱等通过 LLM_BASE_URL 切换)
instance = new ChatOpenAI({
model: resolvedModel, // GLM-4.5-Air
apiKey: config.LLM_API_KEY,
configuration: { baseURL: config.LLM_BASE_URL }, // open.bigmodel.cn/api/paas/v4
temperature: resolvedTemp,
maxTokens: config.LLM_MAX_TOKENS,
streaming: true,
});
增加了实例缓存(按 模型名:温度 做 key),避免重复创建连接。
二、认证与授权系统
2.1 JWT 认证流程
用户注册/登录 → 签发 Access Token (15min) + Refresh Token (7d)
↓
每次请求携带 Access Token → auth 中间件验证 → 设置 request.user
↓
Token 过期 → 前端自动用 Refresh Token 刷新 → 获取新 Access Token
↓
登出 → 服务端清除 Refresh Token
2.2 实现细节
新增文件:
services/auth.service.ts— JWT 签发/验证、密码哈希、用户 CRUDserver/middleware/auth.ts— FastifypreHandler钩子server/routes/auth.ts— 注册/登录/刷新/登出/用户信息 5 个端点db/migrations/002_auth.sql—users表 +refresh_tokens表
角色控制:
// 中间件用法
app.post('/api/v1/query', { preHandler: [requireAuth] }, handler); // 需登录
app.get('/api/v1/admin/audit', { preHandler: [requireAuth, requireRole('admin')] }, handler); // 需管理员
前端集成:
stores/authStore.ts— Zustand 管理登录状态、自动刷新、localStorage 持久化api/client.ts— Axios 拦截器自动注入 Token、401 时自动刷新LoginPage.tsx— 登录/注册二合一界面
2.3 多租户数据隔离
002_auth.sql 为 documents、chunks、eval_results 等表添加 user_id 字段:
- 普通用户只能看到自己的文档和评估结果
- 管理员可以查看所有数据
- API 层通过
request.user.id过滤查询
三、审计日志系统
3.1 自动记录
审计日志通过 Fastify 的 onResponse 钩子自动记录所有 API 请求:
// server/middleware/audit.ts — 自动记录,不影响业务逻辑
app.addHook('onResponse', async (request, reply) => {
// 跳过健康检查和认证路由,避免自我审计
if (request.url.startsWith('/health') || request.url.startsWith('/api/v1/auth')) return;
await auditService.log({
userId: request.user?.id,
action: parseAction(request.method), // create/read/update/delete/execute
resource: parseResource(request.url), // documents/query/eval/...
resourceId: parseResourceId(request.url),
ip: request.ip,
userAgent: request.headers['user-agent'],
statusCode: reply.statusCode,
duration: reply.elapsedTime,
});
});
3.2 存储与查询
db/migrations/003_audit.sql—audit_logs表,含user_id、action、resource、ip、duration等字段services/audit.service.ts— 异步写入(不阻塞请求)、管理端分页查询components/admin/AuditLog.tsx— 前端审计日志查看界面,支持按操作类型过滤
四、端到端评测管道
4.1 V1 vs V2 评测对比
| 维度 | V1 | V2 |
|---|---|---|
| 指标展示 | 前端面板有 UI 但数据是假的 | 真实运行 RAG 管道并计算指标 |
| 检索指标 | 无 | HitRate@K、MRR |
| 生成指标 | 无 | 上下文精确度、上下文召回、忠实度、答案相关性 |
| 测试方法 | 无 | 提交评测数据集 + 配置,自动运行 |
| A/B 测试 | 无 | 同一数据集分别用两组配置运行并对比 |
4.2 指标体系
检索指标(基于文档 ID 匹配,无需 LLM):
- HitRate@K:检索结果中是否包含任一 ground truth 文档(0 或 1)
- MRR:第一个匹配 ground truth 的排名倒数
生成指标(LLM 评估,调用 GLM-4.5-Air 打分):
- Context Precision:检索到的上下文是否包含回答所需的关键信息
- Faithfulness:答案中的论断是否都有上下文支持
- Answer Relevance:答案是否直接、完整地回答了用户的问题
- Context Recall:上下文是否覆盖了标准答案中的所有关键信息
每个指标通过 LLM 评估返回 0.0–1.0 的分数和评估理由。
4.3 LLM 评估实现
// 通用 LLM 评估 — 调用 LLM 获取 0-1 分数
private async llmEval(systemPrompt: string, userMessage: string): Promise<number> {
const llm = getLLM(undefined, 0);
const response = await llm.invoke([
new SystemMessage(systemPrompt),
new HumanMessage(userMessage),
]);
const jsonMatch = response.content.match(/\{[^}]+\}/s);
if (jsonMatch) {
const parsed = JSON.parse(jsonMatch[0]);
return Math.max(0, Math.min(1, parsed.score));
}
return 0;
}
4.4 A/B 测试
// 同一数据集,两组不同配置并行评测
const { metricsA, metricsB } = await evaluationService.abTest(
dataset, // 评测数据集
{ topK: 5, chunkSize: 512 }, // 配置 A
{ topK: 10, chunkSize: 1000 }, // 配置 B
userId,
);
五、Prometheus 监控指标
5.1 新增依赖
metrics.service.ts— 内存中的指标注册中心server/middleware/metrics.ts— 自动采集 HTTP 请求指标server/routes/metrics.ts—GET /metrics返回 Prometheus 文本格式
5.2 采集的指标
| 指标 | 类型 | 说明 |
|---|---|---|
http_requests_total |
Counter | HTTP 请求总数 |
http_request_duration_seconds |
Histogram | 请求延迟分布 |
http_errors_total |
Counter | 错误请求数 |
cache_hits_total / cache_misses_total |
Counter | 缓存命中/未命中 |
process_uptime_seconds |
Gauge | 进程运行时间 |
5.3 前端监控面板
components/admin/MetricsDashboard.tsx 每 10 秒自动刷新,展示:
- 总请求数、错误率(颜色编码)
- 缓存命中率
- 系统运行时间
- 请求路径分布
六、GLM-OCR 图片与扫描件解析
6.1 新增能力
V1 支持的文档格式:PDF、DOCX、Excel、HTML、Markdown(5 种文本格式解析器)
V2 新增:图片解析器(image.parser.ts)+ GLM-OCR 客户端(glm-ocr.ts),支持:
- JPEG、PNG、BMP、TIFF、WebP(单图 ≤ 10MB)
- 扫描件 PDF(≤ 50MB,最大 100 页)
- 输出保留表格、公式、版式的 Markdown 文本
6.2 实现要点
// parsers/glm-ocr.ts — 调用智谱 GLM-OCR 布局解析 API
async parseFile(buffer: Buffer, mimeType: string) {
const base64 = buffer.toString('base64');
const dataUri = `data:${mimeType};base64,${base64}`;
const response = await fetch(`${this.baseUrl}/layout_parsing`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${this.apiKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ model: 'glm-ocr', file: dataUri }),
});
// 返回 Markdown 格式文本
}
多页 PDF 处理:逐页渲染为 PNG → 逐页调用 GLM-OCR → 合并为带页码标记的 Markdown。
七、用户反馈系统
7.1 反馈收集
services/feedback.service.ts— 记录用户对每个回答的反馈(赞/踩 + 文字评论)server/routes/feedback.ts—POST /api/v1/feedback提交反馈- 存储当时的 RAG 配置快照(
config_snapshot),便于分析「哪种配置得分高」
7.2 前端反馈组件
ChatWindow.tsx 中每条 AI 回复附带:
- 赞/踩按钮
- 置信度徽章
- 引用来源展开面板
- 复制按钮
八、前端企业级改造
8.1 新增页面与组件
| 组件 | V1 | V2 | 说明 |
|---|---|---|---|
LoginPage.tsx |
无 | 有 | 登录/注册,密码可见切换 |
AuditLog.tsx |
无 | 有 | 管理员审计日志,操作类型过滤 |
MetricsDashboard.tsx |
无 | 有 | 实时监控面板,10 秒刷新 |
EvalDashboard.tsx |
壳子 | 完整 | 真实指标 + 7 天趋势 + 运行评测按钮 |
ConfigPanel.tsx |
基础 | 增强 | 三 Tab(检索/模型与分块/高级),4 种检索策略 + 4 种分块策略 |
8.2 App.tsx 路由与权限
┌─ 侧边栏 ──────────────────────────────────┐
│ [对话] → ChatWindow.tsx │
│ [文档] → DocumentManager.tsx │
│ [评测] → EvalDashboard.tsx │
│ [配置] → ConfigPanel.tsx │
│ ─── 管理员 ─── │
│ [监控] → MetricsDashboard.tsx (admin) │
│ [审计] → AuditLog.tsx (admin) │
├────────────────────────────────────────────┤
│ 用户状态 · Admin 徽章 · 退出 │
└────────────────────────────────────────────┘
- 未登录 → 显示
LoginPage.tsx - 普通用户 → 隐藏管理员菜单项
- 管理员 → 显示全部菜单
8.3 配置面板增强
V2 的配置面板支持更精细的调参:
检索策略(4 种):
standard— 标准检索adaptive— 自适应检索corrective— 纠正性检索multi-hop— 多跳检索
分块策略(4 种):
recursive— 递归分块(默认)markdown— 按标题层级semantic— 语义边界hierarchical— 父子结构
LLM 模型可选(智谱系列):
GLM-4.5-Air(默认)GLM-4-PlusGLM-4-Flash
九、环境配置变更
9.1 新增环境变量
| 变量 | 默认值 | 说明 |
|---|---|---|
EMBEDDING_BASE_URL |
https://open.bigmodel.cn/api/paas/v4 |
智谱 Embedding API |
EMBEDDING_MODEL |
embedding-3 |
智谱向量模型 |
EMBEDDING_DIMENSION |
2048 |
向量维度 |
RERANKER_PROVIDER |
cohere |
Reranker 提供商 |
RERANKER_API_KEY |
空 | Reranker API Key |
RERANKER_MODEL |
rerank-v3-multilingual |
Reranker 模型 |
JWT_SECRET |
— | JWT 签名密钥(≥16 字符) |
JWT_ACCESS_EXPIRES_IN |
15m |
Access Token 有效期 |
JWT_REFRESH_EXPIRES_IN |
7d |
Refresh Token 有效期 |
RATE_LIMIT_PER_MINUTE |
30 |
API 限流 |
STORAGE_PATH |
./data/uploads |
文件存储路径 |
MAX_FILE_SIZE |
104857600 (100MB) |
上传文件大小上限 |
9.2 变更的环境变量
| 变量 | V1 值 | V2 值 |
|---|---|---|
LLM_MODEL |
qwen3.6-plus |
GLM-4.5-Air |
LLM_BASE_URL |
dashscope.aliyuncs.com/... |
open.bigmodel.cn/api/paas/v4 |
RAG_SIMILARITY_THRESHOLD |
0.7 → 0.2 |
0.2 |
十、后端依赖变更
10.1 新增依赖
| 包 | 版本 | 用途 |
|---|---|---|
bcryptjs |
^2.4.3 | 密码哈希 |
bullmq |
^5.77.6 | 后台任务队列 |
canvas |
^3.2.3 | PDF 页面渲染为图片 |
ioredis |
^5.4.0 | Redis 客户端(替代 BullMQ 内置) |
jsonwebtoken |
^9.0.0 | JWT 签发/验证 |
pdfjs-dist |
^5.7.284 | PDF 页面提取(配合 GLM-OCR) |
tesseract.js |
^7.0.0 | 本地 OCR(备选方案) |
10.2 前端新增依赖
| 包 | 版本 | 用途 |
|---|---|---|
react-markdown |
^10.0.0 | Markdown 渲染(AI 回复) |
rehype-highlight |
^7.0.0 | 代码高亮 |
十一、数据库迁移
11.1 002_auth.sql
-- 用户表
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
email VARCHAR(255) UNIQUE NOT NULL,
password_hash VARCHAR(255) NOT NULL,
name VARCHAR(100),
role VARCHAR(20) DEFAULT 'user' CHECK (role IN ('admin', 'user')),
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- Refresh Token 表
CREATE TABLE refresh_tokens (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID REFERENCES users(id) ON DELETE CASCADE,
token_hash VARCHAR(255) NOT NULL,
expires_at TIMESTAMPTZ NOT NULL,
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- 为已有表添加 user_id
ALTER TABLE documents ADD COLUMN user_id UUID REFERENCES users(id);
ALTER TABLE chunks ADD COLUMN user_id UUID REFERENCES users(id);
11.2 003_audit.sql
CREATE TABLE audit_logs (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID,
action VARCHAR(50) NOT NULL,
resource VARCHAR(100),
resource_id VARCHAR(255),
detail JSONB,
ip VARCHAR(45),
user_agent TEXT,
status_code INTEGER,
duration_ms INTEGER,
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE INDEX idx_audit_user ON audit_logs(user_id);
CREATE INDEX idx_audit_action ON audit_logs(action);
CREATE INDEX idx_audit_resource ON audit_logs(resource);
CREATE INDEX idx_audit_created ON audit_logs(created_at);
十二、升级踩坑记录
坑 1:LangChain OpenAIEmbeddings 返回零向量(智谱 API)
表现:文档入库日志显示成功(8 chunks → 8 embeddings → 8 indexed),但检索永远返回 0 条。检查 Milvus 数据发现向量全为 0。
排查过程:
- Milvus count = 8 ✓
- 采样向量 → 全是
[0, 0, 0, ...]✗ - 写独立脚本测试
OpenAIEmbeddings+ 智谱 API → 仍然是零向量 - 用
curl直接调智谱 API → 返回正常 2048 维向量 ✓
根因:LangChain OpenAIEmbeddings 内部对非 OpenAI API 的响应格式解析存在 Bug,将实际向量丢弃后填充零值。
解决:完全绕过 LangChain,用原生 fetch 调用智谱 API(见 1.3 节代码)。
教训:对于非 OpenAI 的兼容 API,不要盲目信任 LangChain 的封装。先用 curl 或原生 fetch 验证 API 本身是否正常,再决定是否走 SDK。
坑 2:向量维度 1024 → 2048 后 Milvus 集合不兼容
表现:修改 .env 中 EMBEDDING_DIMENSION=2048 后重启,Milvus 插入报错「向量维度不匹配」。
根因:Milvus 集合一旦创建,向量维度不可修改。
解决:
# 删除旧集合
node -e "
const { MilvusClient } = require('@zilliz/milvus2-sdk-node');
const client = new MilvusClient({ address: 'localhost:19530' });
await client.dropCollection({ collection_name: 'rag_chunks' });
await client.dropCollection({ collection_name: 'rag_document_summaries' });
"
# 重启后端 → 自动重建集合 → 重新上传文档
教训:生产环境应在集合创建时记录维度到元数据,并在启动时校验维度一致性。
坑 3:JWT 密钥长度不足导致签名失败
表现:jsonwebtoken.sign() 抛出 Error: secret or private key must be at least 16 characters。
解决:Zod schema 中添加 .min(16) 校验:
JWT_SECRET: z.string().min(16, 'JWT_SECRET must be at least 16 characters'),
坑 4:审计日志自我审计(循环写入)
表现:审计日志表疯狂增长,每秒写入数条——审计中间件在记录「写入审计日志」的请求,形成循环。
解决:在审计中间件中排除审计和健康检查路由:
if (request.url.startsWith('/health') || request.url.startsWith('/api/v1/audit')) return;
坑 5:前端 Token 刷新竞态
表现:多个并发请求同时遇到 401 时,各自发起刷新 Token 请求,导致第一个刷新成功后第二个刷新因旧 Token 已失效而报错。
解决:在 api/client.ts 中添加刷新锁:
let isRefreshing = false;
let refreshPromise: Promise<string> | null = null;
async function refreshToken(): Promise<string> {
if (isRefreshing && refreshPromise) return refreshPromise;
isRefreshing = true;
refreshPromise = /* 实际刷新逻辑 */;
try { return await refreshPromise; }
finally { isRefreshing = false; refreshPromise = null; }
}
十三、LangGraph 图结构变化
V2 的 LangGraph 图从 V1 的 10 节点扩展为 12 节点(新增 decompose 的显式路由),并增加了 MemorySaver 支持对话状态持久化。
START → classify
├─ comparative / 长 factual → decompose → retrieve
└─ 其他 → rewrite
├─ enableHyDE=true → hyde → retrieve
└─ enableHyDE=false → retrieve
retrieve → rerank → compress → generate → evaluate
├─ pass/ambiguous → format → END
└─ fail + 重试未满 → rewrite(循环)
关键变化:
decompose从 V1 的条件分支升级为显式节点,支持多跳检索MemorySaver替代无状态调用,支持多轮对话上下文config字段从前端请求体传入,覆盖默认 RAG 配置
十四、升级后的架构总览
┌─────────────────────────────────────────────────────────────┐
│ 前端 (5173) │
│ Vite + React 19 + TypeScript + TailwindCSS 4 │
│ Zustand 状态管理 · React Query · Lucide 图标 │
│ ┌────────┬────────┬────────┬────────┬──────┬──────┐ │
│ │ 登录 │ 对话 │ 文档 │ 评测 │ 监控 │ 审计 │ │
│ │ 注册 │ SSE流式│ 上传 │ A/B测 │ 实时 │ 日志 │ │
│ └────────┴────────┴────────┴────────┴──────┴──────┘ │
├─────────────────────────────────────────────────────────────┤
│ 后端 (3000) │
│ Node.js + Fastify 5 + TypeScript + LangGraph │
│ ┌──────────┬──────────┬──────────┬──────────┐ │
│ │ JWT 认证 │ 审计日志 │ 评测管道 │ 指标采集 │ │
│ │ 角色控制 │ 异步写入 │ LLM打分 │ Prometheus│ │
│ └──────────┴──────────┴──────────┴──────────┘ │
│ ┌────────────────────────────────────────────┐ │
│ │ LangGraph 12 节点 RAG 管道 │ │
│ │ classify→rewrite→hyde→retrieve→rerank→ │ │
│ │ compress→generate→evaluate→format │ │
│ │ MemorySaver 对话持久化 · 自纠正循环 │ │
│ └────────────────────────────────────────────┘ │
├──────┬──────────┬──────────┬────────────────────────────────┤
│Milvus│PostgreSQL│ Redis │ 外部 API │
│2.5.4 │ 16 │ 7 │ 智谱 AI │
│2048维│ 用户/审计│ 缓存/限流│ LLM: GLM-4.5-Air │
│+BM25 │ 评测数据 │ 队列 │ Embedding: embedding-3 2048维 │
│ │ │ │ OCR: glm-ocr │
└──────┴──────────┴──────────┴────────────────────────────────┘
十五、升级成本与收益
15.1 新增依赖统计
- 后端新增 7 个运行时依赖 + 2 个开发依赖
- 前端新增 2 个运行时依赖
- 数据库新增 3 张表(users、refresh_tokens、audit_logs)
15.2 收益对照
| 维度 | V1 | V2 |
|---|---|---|
| 安全性 | 无认证,裸 API | JWT + 角色 + 审计 + 限流 |
| 可观测性 | console.log | Prometheus + 审计日志 + 用户反馈 |
| 评测能力 | 空壳面板 | 端到端评测 + A/B 测试 + 6 项指标 |
| 文档解析 | 5 种文本格式 | 5 种文本 + 图片/扫描件(GLM-OCR) |
| 向量稳定性 | LangChain 封装(不可控) | 原生 fetch(可控) |
| 模型成本 | 通义 API | 智谱 API(价格相当) |
| 多租户 | 无 | user_id 隔离 |
十六、给正在升级 RAG 平台的团队的建议
- 先验证 Embedding 再写代码:切换向量模型前,先用
curl或原生fetch测试 API 返回的向量是否正常,不要信任 SDK 封装 - 维度变更 = 全量重建:生产环境在切换 Embedding 模型前,评估重建集合和重新入库的成本
- 审计日志要防循环:审计中间件必须排除自身路由,否则会自我审计导致写入爆炸
- Token 刷新加锁:前端并发请求遇到 401 时,只发起一次刷新请求,其他请求排队等待
- 评测先于上线:V1 的教训是「没有评测就无法证明效果」,V2 补全了评测管道后,调参有了数据依据
- LLM 评估的 Prompt 要稳定:评测管道中 LLM 打分的 Prompt 格式要固定(如「仅输出 JSON:{"score": 0.0-1.0}」),避免解析失败
附录:升级后完整文件清单(新增部分)
packages/backend/src/
├── server/
│ ├── middleware/
│ │ ├── auth.ts ← 新增:JWT 认证
│ │ ├── audit.ts ← 新增:审计日志
│ │ └── metrics.ts ← 新增:指标采集
│ └── routes/
│ ├── auth.ts ← 新增:认证端点
│ ├── audit.ts ← 新增:审计查询
│ └── metrics.ts ← 新增:Prometheus 端点
├── services/
│ ├── auth.service.ts ← 新增:用户管理
│ ├── audit.service.ts ← 新增:审计服务
│ ├── evaluation.service.ts ← 新增:评测管道
│ ├── feedback.service.ts ← 新增:反馈服务
│ └── metrics.service.ts ← 新增:指标服务
├── parsers/
│ ├── glm-ocr.ts ← 新增:GLM-OCR 客户端
│ └── image.parser.ts ← 新增:图片解析器
├── db/migrations/
│ ├── 002_auth.sql ← 新增:认证表
│ └── 003_audit.sql ← 新增:审计表
├── embeddings/
│ └── openai.ts ← 重写:绕过 LangChain
└── llm/
└── openai.ts ← 增强:实例缓存
packages/frontend/src/
├── components/
│ ├── auth/
│ │ └── LoginPage.tsx ← 新增:登录注册
│ └── admin/
│ ├── AuditLog.tsx ← 新增:审计日志
│ └── MetricsDashboard.tsx ← 新增:监控面板
└── store/
└── authStore.ts ← 新增:认证状态

浙公网安备 33010602011771号