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.yamlnpm 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 buildType '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 buildpnpm --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 传给 createHashfs.writeFileBlobResponse 的地方)。

根因 :@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_KEYDEEPSEEK_API_KEYXIAOMI_API_KEY ...
TTS 语音合成 TTS_XIAOMI_API_KEYTTS_MINIMAX_API_KEY ...
ASR 语音识别 ASR_OPENAI_API_KEYASR_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冰糖茉莉苏打白桦MiaChloeMiloDean

因此 :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_MIMOxiaomi-tts
lib/audio/provider-display.tslib/store/settings.tscomponents/settings/tts-settings.tsx 显示名、默认配置、接口路径提示
lib/i18n/locales/*.json(12 个) 新增 providerXiaomiTTS 文案
.env.example / .env.local 新增 TTS_XIAOMI_API_KEYTTS_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.nextdist*.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 适配器必然失败。
相关推荐
程序员cxuan2 小时前
为啥 Blender 突然火了?
人工智能·后端·程序员
酷酷的逗逗乐17 小时前
前端转 Agent 开发 · 第五节:Memory 会话记忆
前端·程序员
2601_9620775318 小时前
程序员会消失吗?
ai·程序员·职业发展·未来趋势·技术变革
摆烂工程师19 小时前
别只拿 GPT-6 Astra 聊天,它真正恐怖的是开始会“干活”了
人工智能·程序员·vibecoding
程序员cxuan20 小时前
GPT images 2.5 一手实测,这也太颠了。。。
后端·程序员
Hilaku1 天前
为什么技术极强的前端,往往当不好前端 Team Leader?
前端·javascript·程序员
她的男孩1 天前
AI 写完 100 万行代码没人 Review,我做了一件事:把 AI 写的代码管起来了
java·人工智能·程序员
李剑一1 天前
大环境或许真的恶劣了起来,打工人你焦虑吗?
面试·程序员·招聘
SimonKing1 天前
一文终结 Java 路径加载争议:斜杠 什么时候该加,什么时候不该加
java·后端·程序员