Next.js + FastAPI + Agno 搭建内网知识库 Agent 的三个踩坑实录

最近用 Next.js + FastAPI + Agno 拼了一套内网知识库 Agent。整体架构并不复杂,标准的前后端分离。
不过在内网部署和测试的过程中,踩了三个非常典型、但在公网环境下很容易被忽视的坑:大文件直接被拒、流式响应到半截卡死,以及部分页面在内网加载直接白屏。
分享一下这个过程中具体的排查原因和解决方案。
搞定几十 MB 知识库文件上传被拒
传大文档(几十 MB)或者同时批量传多个文件时,接口直接拒收,导致解析入库失败。
这里的问题在于双重拦截:前端 Next.js 的代理层和后端 FastAPI 底层的表单解析层,都存在默认的极小体积限制,必须两端同时放行。(当然也可以不用 rewrites, 这样可能改动会相对大一些。)
前端 Next.js 放行配置
Next.js 的 rewrites 代理默认限制了请求体大小。需要在 next.config.ts 的 experimental 中显式调整 proxyClientMaxBodySize:
// next.config.ts
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
output: "standalone",
experimental: {
// 放宽默认上传体积限制至 250MB
proxyClientMaxBodySize: "250mb",
},
async rewrites() {
return [
{
source: "/api/v1/:path*",
destination: `${apiProxyTarget}/api/v1/:path*`,
},
];
},
};
export default nextConfig;
后端 FastAPI 放行配置
FastAPI 底层的 Starlette 对 request.form() 的 Multipart 解析有极严的限制(单 Part 默认仅 1MB)。必须在处理文件上传的接口内,显式重写解析参数:
# 知识库文件上传接口内部
form = await request.form(
max_files=settings.rag_kb_upload_max_files, # 放宽最大文件数限制
max_fields=settings.rag_kb_upload_max_fields, # 放宽表单字段限制
max_part_size=50 * 1024 * 1024, # 单个文件大小上限放宽到 50MB
)
解决流式输出 30 秒超时与内网代理干扰
当 Agent 处理长文本输出,或需要多步复杂的 RAG/Tool 调用时,前端经常吐字到一半直接断开。查日志发现,中断时间点精准发生在请求发出的第 30 秒。
这是由于 Next.js 的代理层,以及 Agno 底层调用 LLM API 的 HTTP 客户端,均设置了 30 秒的默认超时限制。
前端延长超时间隔
修改 next.config.ts 中的 proxyTimeout 属性:
// next.config.ts
const nextConfig: NextConfig = {
output: "standalone",
experimental: {
proxyClientMaxBodySize: "250mb",
proxyTimeout: 300000, // 延长至 5 分钟 (300000 ms)
},
};
后端显式设定超时并避让系统代理
Agno 初始化 OpenAILike 时,可以显式配置超时属性:
import httpx
from agno.models.openai.like import OpenAILike
timeout = 300 # 5 分钟
model = OpenAILike(
id=model_id,
api_key=api_key,
base_url=base_url,
temperature=temperature,
timeout=timeout
)
排查内网页面白屏(ChunkLoadError)
在公网测试一切正常,一搬到内网,大部分页面好好的,唯独个别路由点进去直接白屏。控制台报错 Uncaught ChunkLoadError: Loading chunk xxx failed,网络面板中对应的 .js 静态资源报 403 或 404 拒绝。
这个问题的根源在构建工具的命名策略。Next.js 默认的构建工具(Turbopack)生成 Chunk 文件名时,会携带 ~ 这类特殊字符。内网环境的防火墙或 WAF 策略通常比公网严苛得多,会将带有此类字符的 URL 判定为非法或风险请求直接拦截。
解决方案
在 package.json 中把构建命令显式切回传统的 Webpack,其生成的 Chunk 文件名只包含常规英数字符,可直接绕过内网 WAF 的字符规则拦截:
- "build": "next build",
+ "build": "next build --webpack",