OpenMAIC 运行踩坑与经验

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

启动命令:

powershell 复制代码
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 就不存在。

解决:

powershell 复制代码
pnpm --filter @openmaic/renderer run build
pnpm --filter @openmaic/editor run build

随后确认 packages/@openmaic/<包名>/dist 存在即可。之后正常 pnpm install 会自动完成这一步。


3.2 Tailwind 版本错配导致页面 500

现象:首页首次编译直接 500,日志:

typescript 复制代码
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 不匹配。

解决:

powershell 复制代码
pnpm update -D tailwindcss @tailwindcss/postcss   # 统一到 4.3.3

后续坑 :更新完仍然报 @tailwindcss+postcss@4.0.0 的路径。原因是 dev server 还在运行,Windows 下旧目录被文件锁住删不掉,加上 Turbopack 的 .next 缓存仍指向旧路径。

powershell 复制代码
# 先停掉 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 时:

sql 复制代码
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。

解决:

powershell 复制代码
pnpm update @langchain/core    # 1.1.16 -> 1.2.9

验证:

powershell 复制代码
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 阶段失败:

python 复制代码
./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 会做全量类型检查直接失败。

解决:

  1. package.json 开发依赖改为:
json 复制代码
"@types/node": "^22"
  1. 升级依赖:
powershell 复制代码
pnpm update @types/node      # 20.0.0 -> 22.20.1
  1. 验证(全量类型检查 0 错误 + 生产构建成功):
powershell 复制代码
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,日志里会明确写:

arduino 复制代码
⚠ Port 3000 is in use by process xxxx, using available port 3001 instead.

排查与验证:

powershell 复制代码
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 配置

powershell 复制代码
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

官方接口形态(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 配置与验证

env 复制代码
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。


五、复制项目给别人(不带密钥)

复制时排除个人密钥与运行期数据:

powershell 复制代码
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 读取):

powershell 复制代码
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 方案

bash 复制代码
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)

bash 复制代码
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 守护:

bash 复制代码
npm i -g pm2
pm2 start pnpm --name openmaic -- start
pm2 save && pm2 startup

6.3 Nginx 反代配置要点

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。


七、常用命令速查

powershell 复制代码
# 启动 / 构建
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

八、经验总结

  1. 先 pnpm install 再启动 ;postinstall 会构建全部子包,中断了就用 pnpm --filter <包> run build 补。
  2. pnpm-lock 是唯一依赖真相;不要用 npm 安装,不要手工改 node_modules 里的版本号。
  3. 改依赖前先停 dev server ,改完清一次 .next,能避开 Windows 文件锁和 Turbopack 陈旧缓存这两类"假故障"。
  4. dev 不查类型、build 才查类型 ;本地能跑不代表 pnpm build 能过,交付前一定跑一次完整构建。
  5. 报错先看进程与端口(Port ... in use),再看依赖树,最后才怀疑业务代码。
  6. 区分编译期与运行时环境变量 :NEXT_PUBLIC_* 在构建时写进前端 bundle,改完必须重新 build,只改 .env.local 不生效。
  7. 第三方能力要核对真实协议 :MiMo TTS 表面是"OpenAI 兼容",实际走 chat/completions 的 audio 通道,套用通用 TTS 适配器必然失败。
相关推荐
爱敲代码的小黄9 小时前
神经网络入门指南:从 CNN、RNN 到 Attention
人工智能·面试·程序员
陈随易13 小时前
纯 Go 写的 JS 引擎,跑分超过了 C 语言的 QuickJS
前端·后端·程序员
陈随易15 小时前
专注飞机 FocusFlight,两个人把番茄钟做成了一趟航班
前端·后端·程序员
爱勇宝17 小时前
忙不是勋章,身体才是职场人唯一的长期资产
程序员
kyriewen19 小时前
我扫了 422 个仓库,近一半 CI 在裸装依赖
前端·javascript·程序员
致力于划水第一线20 小时前
现在矿石每天签到只送一个了吗
程序员
Thneonl21 小时前
桌宠穿透不是一行 SetWindowLong
windows·程序员
Captaincc1 天前
永别了,程序员!(转)
程序员
深蓝AI1 天前
GPT-6.1 Terra 在 Bedrock 全面可用:便宜一半快三倍,日常任务选型要重算
人工智能·程序员
陈随易1 天前
Node.js 2026上半年都有哪些性能提升?
前端·后端·程序员