tags:
- OpenMAIC
- Next.js
- 部署
- 排错
created: 2026-09-10
project: G:\\vibing\\OpenMAIC-main
OpenMAIC 运行踩坑与经验
本文记录把 OpenMAIC(Next.js 16 多智能体互动课堂)从源码跑到可用、以及打包分发、部署过程中实际遇到的问题、根因和解决办法。

一、环境与版本
| 操作系统 | Windows(开发),Linux + 宝塔(Nginx / Docker 部署) |
| Node.js | v22.19.0(engines 要求 >= 22.19.0) |
| 包管理器 | pnpm 10.28.0(packageManager 声明,不要用 npm 安装) |
| Next.js | 16.2.11(Turbopack) |
| React | 19.2.3 |
| TypeScript | 5.9.3 |
| 关键依赖 | tailwindcss 4.3.3、@langchain/core 1.2.9、@types/node 22.20.1 |
启动命令:
pnpm install # 首次安装,会执行 postinstall 构建全部 workspace 包
pnpm dev # 开发模式,默认 3000 端口被占用时自动改用 3001
pnpm build # 生产构建(会做完整 TypeScript 类型检查)
pnpm start # 生产模式启动
[!warning] 用 pnpm,不要用 npm
项目是 pnpm workspace,postinstall 里用的是 pnpm run build,而且锁文件是 pnpm-lock.yaml。
npm install 不会正确构建 @openmaic/* 子包,后续必然报模块找不到。
npm run build 只是执行脚本本身没问题,但依赖必须由 pnpm 安装。
二、问题速查表
| 启动后访问页面 500,Missing field 'negated' on ScannerOptions.sources | 锁文件把 tailwindcss 4.0.0 与 4.3.3 的 oxide 扫描器混装 | pnpm update -D tailwindcss @tailwindcss/postcss 统一到 4.3.3 |
| CSS 错误修完仍然报旧路径 @tailwindcss+postcss@4.0.0 | 旧版本目录被运行中的 dev server 锁住未清理 + Turbopack 缓存 | 停服务 → 删 .next 和残留 .pnpm 目录 → 重启 |
| Module not found: Can't resolve '@langchain/core/utils/uuid' | @langchain/core 1.1.16 太旧,langgraph-checkpoint@1.1.5 需要 ^1.1.48 | pnpm update @langchain/core(升到 1.2.9) |
| npm run build 报 Type 'Buffer' is not assignable to 'BinaryLike' | @types/node 锁在 20.0.0,与 TypeScript 5.9 不兼容 | package.json 改 "@types/node": "^22" 后 pnpm update @types/node |
| 找不到 @openmaic/renderer / @openmaic/editor 的模块 | 两个 workspace 包缺少 dist 构建产物 | pnpm –filter @openmaic/renderer run build、pnpm –filter @openmaic/editor run build |
| 端口 3000 打不开,日志提示改用 3001 | 3000 被本机其他程序(grafana)占用 | 用日志里的端口访问;部署时让应用只监听 127.0.0.1:3000 |
| 页面能打开,但生成课程/语音失败 | .env.local 没有配置任何 LLM 服务商 Key | 从 .env.example 复制并至少填一个 *_API_KEY |
| 想用小米 MiMo TTS,填自定义 TTS 却调不通 | MiMo TTS 走 /v1/chat/completions + audio 参数,不是 /v1/audio/speech | 源码内新增原生 xiaomi-tts provider(见第四节) |
| 日志里 instrumentation.ts: A Node.js API is used 警告 | Edge Runtime 检查提示,非致命 | 忽略,不影响启动和功能 |
三、问题详解
3.1 工作区包缺少 dist 产物
现象:启动或构建时报找不到 @openmaic/renderer、@openmaic/editor 的模块(它们的 main 指向 dist/…)。
原因:这两个包在 postinstall 里构建,如果安装过程被中断(或只跑了部分脚本),dist 就不存在。
解决:
pnpm —filter @openmaic/renderer run build
pnpm —filter @openmaic/editor run build
随后确认 packages/@openmaic/<包名>/dist 存在即可。之后正常 pnpm install 会自动完成这一步。
3.2 Tailwind 版本错配导致页面 500
现象:首页首次编译直接 500,日志:
Error evaluating Node.js code
Error: Missing field `negated` on ScannerOptions.sources
at …/@tailwindcss+postcss@4.0.0/…/dist/index.js
根因:锁文件里 @tailwindcss/postcss@4.0.0 被解析成依赖 @tailwindcss/node@4.3.3、@tailwindcss/oxide@4.3.3,4.0.0 的 JS 与 4.3.3 的原生扫描器 API 不匹配。
解决:
pnpm update –D tailwindcss @tailwindcss/postcss # 统一到 4.3.3
后续坑:更新完仍然报 @tailwindcss+postcss@4.0.0 的路径。原因是 dev server 还在运行,Windows 下旧目录被文件锁住删不掉,加上 Turbopack 的 .next 缓存仍指向旧路径。
# 先停掉 pnpm dev,再执行:
node –e "const fs=require('fs'); for (const p of ['.next','node_modules/.pnpm/@tailwindcss+postcss@4.0.0']) { if (fs.existsSync(p)) { fs.rmSync(p,{recursive:true,force:true}); console.log('removed',p); } }"
pnpm dev
经验:更新/删除依赖前先停 dev server;改完依赖后清一次 .next 最省事。
3.3 @langchain/core/utils/uuid 找不到
现象:访问 /api/chat 或执行 next build 时:
Module not found: Can't resolve '@langchain/core/utils/uuid'
./node_modules/.pnpm/@langchain+langgraph-checkpoint@1.1.5_@langchain+core@1.1.16/…
根因:langgraph-checkpoint@1.1.5 的 peer 依赖是 @langchain/core@^1.1.48,但锁文件把 core 固定在 1.1.16,该版本没有导出 utils/uuid。
解决:
pnpm update @langchain/core # 1.1.16 -> 1.2.9
验证:
node –e "import('@langchain/core/utils/uuid').then(m=>console.log('ok',typeof m.v5,typeof m.v6))"
再清一次 .next 缓存并重启。修复后 POST /api/chat 返回 400(参数校验)而不是 500(模块缺失),说明路由编译通过。
3.4 npm run build 的 Buffer 类型错误(重点)
现象:npm run build 在 TypeScript 阶段失败:
./app/api/materials/route.ts:341:48
Type error: Argument of type 'Buffer' is not assignable to parameter of type 'BinaryLike'.
Type 'Buffer' is not assignable to type 'Uint8Array<ArrayBufferLike> | DataView<ArrayBufferLike>'.
Type 'SharedArrayBuffer' is missing the following properties from type 'ArrayBuffer': …
类似错误全项目有几百处(凡是把 Buffer 传给 createHash、fs.writeFile、Blob、Response 的地方)。
根因:@types/node 被锁在 20.0.0(很旧的版本),与 TypeScript 5.9 的 TypedArray/Buffer 类型定义不兼容。next dev 不做类型检查所以察觉不到,next build 会做全量类型检查直接失败。
解决:
"@types/node": "^22"
pnpm update @types/node # 20.0.0 -> 22.20.1
pnpm exec tsc —noEmit –p tsconfig.json
pnpm build
结果:修复前 tsc 有 370+ 处 Buffer 相关错误,修复后 0 错误;pnpm build 完整通过(编译成功、TypeScript 通过、52 个页面/接口全部生成)。
[!tip] 判断技巧
只要看到 Type 'Buffer' is not assignable to … 且伴随 SharedArrayBuffer is missing …,基本就是 @types/node 与 TypeScript 版本不匹配,而不是业务代码写错。
3.5 端口占用
本机 3000 端口被 grafana 常驻占用,Next.js 会自动改用 3001,日志里会明确写:
⚠ Port 3000 is in use by process xxxx, using available port 3001 instead.
排查与验证:
Get-NetTCPConnection –LocalPort 3000 –State Listen | Select-Object LocalPort,OwningProcess
(Invoke-WebRequest –Uri http://localhost:3001 –UseBasicParsing).StatusCode
部署到服务器时建议把容器/进程端口绑定为 127.0.0.1:3000,对外只通过 Nginx 暴露 80/443。
3.6 .env.local 配置
copy .env.example .env.local
- 所有变量都“可选”,但至少要有一个 LLM 服务商 Key,否则界面能开、生成课程必失败。
- 建议同时指定 DEFAULT_MODEL=provider:model,例如 openai:gpt-5.5。
- 共享部署建议设置 ACCESS_CODE 做站点级密码保护。
- 改完 .env.local 建议重启 pnpm dev / pnpm build 后再访问。
各服务商 Key 与 TTS/ASR 是分开的变量族:
| LLM 对话 | OPENAI_API_KEY、DEEPSEEK_API_KEY、XIAOMI_API_KEY … |
| TTS 语音合成 | TTS_XIAOMI_API_KEY、TTS_MINIMAX_API_KEY … |
| ASR 语音识别 | ASR_OPENAI_API_KEY、ASR_FUNASR_BASE_URL … |
四、小米 MiMo TTS 接入经验
4.1 关键结论:MiMo TTS 不是 OpenAI 的 /audio/speech
官方接口形态(https://mimo.mi.com/docs):
- 请求:POST https://api.xiaomimimo.com/v1/chat/completions
- 认证头:api-key: $MIMO_API_KEY(OpenAI SDK 的 Authorization: Bearer 同样可用)
- 待合成文本放在 role: "assistant" 的 message 里(不是 user)
- 音频参数:"audio": { "format": "wav", "voice": "mimo_default" }
- 返回:base64 音频在 choices[0].message.audio.data
模型:mimo-v2.5-tts(预置音色)、mimo-v2.5-tts-voicedesign(文本设计音色)、mimo-v2.5-tts-voiceclone(音色复刻)。
预置音色: mimo_default、冰糖、茉莉、苏打、白桦、Mia、Chloe、Milo、Dean。
因此:OpenMAIC 里“添加自定义语音合成(OpenAI 兼容)”按钮只支持 /audio/speech,对 MiMo 无效,必须写原生 provider。
4.2 新增原生 provider 的改动点
| lib/audio/types.ts | BuiltInTTSProviderId 增加 'xiaomi-tts' |
| lib/audio/constants.ts | 注册 provider(模型 mimo-v2.5-tts、9 个音色、默认值、图标) |
| lib/audio/tts-providers.ts | 新增 generateXiaomiMiMoTTS():chat/completions + audio 参数 + base64 解码 |
| lib/server/provider-config.ts | 环境变量映射 TTS_XIAOMI / TTS_MIMO → xiaomi-tts |
| lib/audio/provider-display.ts、lib/store/settings.ts、components/settings/tts-settings.tsx | 显示名、默认配置、接口路径提示 |
| lib/i18n/locales/*.json(12 个) | 新增 providerXiaomiTTS 文案 |
| .env.example / .env.local | 新增 TTS_XIAOMI_API_KEY、TTS_XIAOMI_BASE_URL 说明 |
4.3 配置与验证
TTS_XIAOMI_API_KEY=你的MiMo密钥
TTS_XIAOMI_BASE_URL=https://api.xiaomimimo.com/v1
# Token Plan 区域端点(按需替换):
# TTS_XIAOMI_BASE_URL=https://token-plan-cn.xiaomimimo.com/v1
# TTS_XIAOMI_BASE_URL=https://token-plan-sgp.xiaomimimo.com/v1
# TTS_XIAOMI_BASE_URL=https://token-plan-ams.xiaomimimo.com/v1
TTS_MIMO_* 是 TTS_XIAOMI_* 的别名,两者等价。
验证:重启 → 设置 → 语音合成 → 选 “Xiaomi MiMo TTS” → 选音色 → 点试听。
[!note] 注意
已为对话模型配置的 XIAOMI_API_KEY 不会自动用于语音合成,必须单独配置 TTS_XIAOMI_API_KEY。
五、复制项目给别人(不带密钥)
复制时排除个人密钥与运行期数据:
robocopy "G:\\vibing\\OpenMAIC-main" "G:\\vibing\\OpenMAIC-copy" /E `
/XD node_modules .next .codegraph data dist `
/XF .env.local .env.*.local *.tsbuildinfo
| .env.local | 含 API Key |
| data/ | 运行期产生的本地数据 |
| node_modules、.next、dist、*.tsbuildinfo | 构建产物/缓存,对方重新安装即可 |
复制后校验没有残留密钥(把 $key 换成你的 key 值,或从 .env.local 读取):
rg –l –F —hidden —no-ignore $key "G:\\vibing\\OpenMAIC-copy"
无输出即安全;最后打包 Compress-Archive 成 zip,并附上一份安装说明(.env.example 必须保留)。
六、部署要点(宝塔 + Nginx / Docker)
两套方案共用同一个架构:应用只监听 127.0.0.1:3000,Nginx 负责 80/443 与 SSL。
6.1 Docker 方案
cd /www/wwwroot/openmaic
cp .env.example .env.local
# 国内网络加速
ALPINE_MIRROR=mirrors.tuna.tsinghua.edu.cn \\
NPM_REGISTRY=https://registry.npmmirror.com \\
docker compose up -d –build
curl http://127.0.0.1:3000/api/health
- 建议把 docker-compose.yml 的端口改为 '127.0.0.1:3000:3000',避免 3000 直接暴露公网。
- 需要服务端持久化(课程/会话入库)时加 –profile server-persistence,并在构建时传入 NEXT_PUBLIC_PERSISTENCE=1 与一致的 NEXT_PUBLIC_PERSISTENCE_TOKEN(编译期开关,写进浏览器 bundle)。
- 需要 MP4 导出时加 –profile video-export,该服务含 Chromium + FFmpeg,内存需要 ≥ 8GB,否则会自动降级为下载 ZIP。
[!warning] 持久化鉴权
项目内置的是开发级 token 认证,NEXT_PUBLIC_PERSISTENCE_TOKEN 会暴露在前端 JS 中,拿到即可读写所有学习者数据。只适合可信网络 + ACCESS_CODE 的单用户部署;公开多用户必须自行替换为真正的会话鉴权。
6.2 Nginx + Node(不用 Docker)
cd /www/wwwroot/openmaic
node -v # 必须 >= 22.19
npm i -g pnpm@10
pnpm install
NODE_OPTIONS=–max-old-space-size=3072 pnpm build
pnpm start
用 pm2 守护:
npm i -g pm2
pm2 start pnpm –name openmaic — start
pm2 save && pm2 startup
6.3 Nginx 反代配置要点
server_name maic.example.com;
client_max_body_size 200m; # 上传课程材料
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade"; # WebSocket / SSE 必需
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_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 300s;
proxy_send_timeout 300s;
proxy_buffering off; # 流式输出必需
}
安全组/防火墙只放行 80、443。
七、常用命令速查
# 启动 / 构建
pnpm dev
pnpm build
pnpm start
# 类型检查与 i18n 校验
pnpm exec tsc —noEmit –p tsconfig.json
node scripts/check-i18n-keys.mjs
# 单独构建 workspace 包
pnpm —filter @openmaic/renderer run build
pnpm —filter @openmaic/editor run build
# 清理缓存(先停 dev server)
node –e "require('fs').rmSync('.next',{recursive:true,force:true})"
# 健康检查
(Invoke-WebRequest http://localhost:3001/api/health –UseBasicParsing).Content

八、经验总结






