OpenMAIC v1.2.1 配置参数详解

OpenMAIC v1.2.1 配置参数详解:逐项实测数据库连接、访问口令、单用户与匿名身份、Cookie Secure、场景并发、生成队列上限与 openmaic.yml 模型槽位,给出默认值、修改方式、重启生效与验证命令及启动校验排障。

OpenMAICOpenMAIC配置参数详解PostgreSQLLLM2026/10/25

OpenMAIC v1.2.1 配置参数详解

目标:把 OpenMAIC v1.2.1 的配置拆成「环境变量」「openmaic.yml 模型文件」与「运行时设置」三类,逐项给出默认值、作用、修改方式与验证命令。文中所有回显均为本机实测(Ubuntu 24.04.5、Docker 29.9.2、Compose v5.6.1、OpenMAIC v1.2.1、PostgreSQL 16.15),取材日期 2026-10-25;部署流程见《OpenMAIC v1.2.1 Docker Compose 部署指南》,产品定位见《OpenMAIC v1.2.1 介绍与选型指南》。

一、环境信息

  • 应用版本:OpenMAIC v1.2.1,运行时 Node.js v22.23.4、Next.js 16.3.3
  • 数据库:PostgreSQL 16.15
  • 对外端口:8144(服务内 3000)
  • 配置入口:docker-compose.yml 的 environment: 段(环境变量)、src/docker-compose.defaults.env(官方默认值)、/app/openmaic.yml(模型与槽位)
  • 生效方式:环境变量随服务重建/重启生效;openmaic.yml 只在服务启动时读取,改完必须重启
  • 实测基线:单用户模式(OWNER_SINGLE_USER=true)、访问口令 q1w2e3r4、未配置任何模型

本文每个参数都按「改值 → 重启 → 用接口回显验证」的方式实测,并把结果汇总在第八章。

二、参数体系总览

OpenMAIC 的配置分成三层,职责不同,混用会导致「改了没生效」:

层位置管什么生效时机
环境变量docker-compose.yml 的 environment:、.env.local、官方默认文件数据库地址、访问口令、身份模式、并发与队列上限、密钥、代理信任、存储后端服务进程启动时读取;Compose 需 up -d 重建服务
模型文件openmaic.yml(路径由 OPENMAIC_CONFIG 指定,默认启动目录)服务商账号、允许的模型列表、每个槽位用哪个模型、锁定与用户自带密钥策略启动时读取并校验;改动后重启
运行时设置Web 界面「模型设置」用户在界面上填写的服务商与密钥写入数据库后即时生效,受 lock / allowUserKeys 约束

优先级从高到低:environment: 覆盖 env_file 中的同名键;openmaic.yml 的槽位覆盖旧版 DEFAULT_MODEL / MODEL_ROUTES;界面设置只在文件未锁定该槽位时生效。

💡 技术拓展:为什么模型配置要单独用一个文件? 环境变量适合表达「部署级开关」(数据库在哪、并发多少),而模型配置是树形结构——服务商下面挂模型列表,槽位下面挂服务商与模型,还可能有备用模型。用 YAML 能表达层级与引用,还能给密钥写 ${VAR} 占位,避免把密钥写进编排文件。两者分工明确:密钥的值放环境变量,密钥的引用关系放 YAML。

三、必填参数与启动校验

3.1 DATABASE_URL

默认值:无默认值,必填。官方编排会为内置数据库自动注入;自行部署时必须显式给出。

实测:清空该变量后重建服务,服务进入反复重启,状态为 Restarting (1):

openmaic-121-stack-openmaic-1    Restarting (1) Less than a second ago
openmaic-121-stack-postgres-1    Up 15 seconds (healthy)

日志中的拒绝启动原因完整可读:

openmaic-1  | [boot] Invalid server configuration; the server will not start: DATABASE_URL is not set. OpenMAIC stores courses in PostgreSQL and cannot start without a database. For local development, run `pnpm db:up` and set DATABASE_URL in .env.local (see .env.example). For a deployment, set DATABASE_URL to a PostgreSQL database, or use `docker compose up`, which starts one.

docker inspect 可确认退出码为 1、重启计数持续增加:

ExitCode=1 RestartCount=7

结论:空白值等同未设置;该变量没有「浏览器本地存储」兜底,缺失时服务宁可退出也不降级。

3.2 ACCESS_CODE

默认值:空(不设访问口令)。设置后,访问者必须先输入口令换取一个 7 天有效的签名令牌。

实测一:设置口令。健康接口报告已配置:

{"success":true,"status":"ok","version":"0.1.0","accessCodeConfigured":true,...}

未携带令牌访问业务接口返回 401;用示例口令换取令牌成功,响应头中带 openmaic_access(值已截断):

set-cookie: openmaic_access=1792915092831.c854b838f8dc(令牌已截断); Path=/; Expires=Sun, 01 Nov 2026 07:58:12 GMT; Max-Age=604800; Secure; HttpOnly; SameSite=lax

实测二:移除口令。健康接口立即变为 accessCodeConfigured:false,且不带任何凭据即可读写课程库:

{"success":true,"status":"ok","version":"0.1.0","accessCodeConfigured":false,...}
HTTP 200
{"folders":[]}

日志给出明确告警:

openmaic-1  | [2026-10-25T07:57:54.635Z] [WARN] [AccessCode] ACCESS_CODE is not set. The access-code gate is disabled for all API routes. Set ACCESS_CODE to a long random value (at least 16 characters) before exposing this server to a network.

实测三:口令过短。设置示例口令 q1w2e3r4(8 位)后,第一次验证时出现:

openmaic-1  | [2026-10-25T07:53:34.972Z] [WARN] [AccessCode] ACCESS_CODE is shorter than 16 characters. Use a long random value so the code cannot be brute-forced.

结论:

  • 口令只是站点级门禁,不是用户认证;所有持码者共享同一个课程库,没有按人归属。
  • 口令长度建议至少 16 位随机值;短口令不阻止启动,只会告警。
  • 验证请求默认不限流;只有 TRUST_PROXY_HEADERS=true 且确实位于可信反向代理之后时,才按客户端 10 次/60 秒限流。

四、身份与访问控制参数

4.1 OWNER_SINGLE_USER

默认值:官方编排默认 true(写在 src/docker-compose.defaults.env 中),源码运行默认关闭。

作用:所有请求解析到同一个固定所有者,多台浏览器共享同一个课程库,并允许发布课程。

实测一:开启(默认)。登录凭证接口返回固定所有者:

{"learnerKey":"local"}

新建文件夹的归属也是 local:

{"folder":{"id":"folder-2glSpJRO5GE8","name":"部署验证",...,"userKey":"local"}}

实测二:关闭(OWNER_SINGLE_USER=false)。用两个独立的 Cookie 罐模拟两台浏览器访问首页,分别得到一个匿名身份:

#HttpOnly_127.0.0.1	FALSE	/	FALSE	1827475013	anonymous_id	da462417-914c-4d64-b16b-126d1d332ceb
#HttpOnly_127.0.0.1	FALSE	/	FALSE	1827475013	anonymous_id	8d4daba6-1de4-4638-90a3-bbbd9ca6acf4

两台浏览器的所有者标识不同:

{"learnerKey":"anon:da462417-914c-4d64-b16b-126d1d332ceb"}
{"learnerKey":"anon:8d4daba6-1de4-4638-90a3-bbbd9ca6acf4"}

A 浏览器创建的文件夹,B 浏览器看不到:

{"folder":{"id":"folder-guVQH81R1t3R","name":"A 的课程",...,"userKey":"anon:da462417-914c-4d64-b16b-126d1d332ceb"}}
{"folders":[{"id":"folder-guVQH81R1t3R","name":"A 的课程",...,"userKey":"anon:da462417-914c-4d64-b16b-126d1d332ceb"}]}
{"folders":[]}

关键细节:curl 只有在带上文档导航请求头(Accept: text/html 与 Sec-Fetch-Dest: document)时,首页才会下发 anonymous_id Cookie。不带这些头时每次请求都会生成新的匿名身份,表现为「刚建的文件夹立刻消失」,这不是数据丢失。

结论:个人或小团队共用一台服务器时保持 true;需要按浏览器隔离时设为 false。切换模式后,旧所有者名下的课程不会自动迁移,OWNER_SINGLE_USER_ID 一经确定也不应再改,否则原课程库会变成「孤儿」。

4.2 PERSISTENCE_SHARED_OWNER_ID

默认值:空。

作用:把团队固定到一个共享所有者,等价于「团队版单用户」,但所有者 ID 由你命名。格式为 1–128 个 [A-Za-z0-9._-] 字符,保留前缀 anon: 会被拒绝。

互斥规则:与 OWNER_SINGLE_USER 同时设置会导致启动失败;与宿主注册的身份方法搭配时,sharedTeamAuthMethod() 必须放在最后。

4.3 OPENMAIC_PUBLISH_ADDRESS

默认值:官方编排为 127.0.0.1(仅本机可达);本文实测改为 0.0.0.0 以便同网段访问。

结论:改成对外监听前,先确认 ACCESS_CODE 已设置;两者是配套的安全边界,单独放开监听等于把课程库暴露给同网段所有人。

默认值:生产构建下为开启(Cookie 带 Secure);可用精确值 0 关闭。

实测一:默认(开启)。Cookie 带 Secure:

set-cookie: openmaic_access=1792914941967.4ea926ed2cc6(令牌已截断); Path=/; Expires=Sun, 01 Nov 2026 07:55:41 GMT; Max-Age=604800; Secure; HttpOnly; SameSite=lax

实测二:COOKIE_SECURE=0。同一接口的 Cookie 不再带 Secure:

set-cookie: openmaic_access=1792914954789.1a734ff172a3(令牌已截断); Path=/; Expires=Sun, 01 Nov 2026 07:55:54 GMT; Max-Age=604800; HttpOnly; SameSite=lax

结论:

  • 纯 HTTP 部署(无 TLS)必须设 COOKIE_SECURE=0,否则除 localhost 外的浏览器不会保存登录 Cookie,表现为反复要求输口令、写入 403。
  • 只接受精确值 0;写 false、no 都无效。
  • 关闭后 Cookie 明文传输,只能用于可信内网;上公网必须配 TLS 并恢复默认。

4.5 TRUST_PROXY_HEADERS

默认值:关闭。

作用:开启后信任 x-forwarded-for / x-real-ip,用于访问口令验证限流与渲染服务准入。

结论:只有请求确实经过会覆盖这两个头的反向代理时才开启;直接暴露端口时开启等于允许客户端伪造来源地址。

五、生成并发与队列参数

5.1 PARALLEL_SCENE_CONCURRENCY

默认值:0(串行)。取值范围:0 或 1 为串行,大于 1 时并发生成场景内容,上限被截到 10。

实测:改为 3 后重启,健康接口直接回显生效值:

{"success":true,"status":"ok","version":"0.1.0","accessCodeConfigured":true,...,"generation":{"parallelSceneConcurrency":3}}

结论:这是浏览器侧一次生成多少个场景内容的开关。它能显著缩短整堂课生成时间,但会成倍放大模型 API 的瞬时并发;Key 的每分钟并发配额较低时应保持 0。

💡 技术拓展:并发参数为什么要分「场景并发」和「任务并发」?

参数并发对象默认调大的风险
PARALLEL_SCENE_CONCURRENCY同一堂课的多个场景内容0(串行)单 Key 触发模型侧限流
OPENMAIC_MAX_ACTIVE_RUNS_PER_OWNER同一所有者同时进行的生成任务2多堂课抢占同一批模型配额
OPENMAIC_GENERATION_RUN_MAX_CONCURRENT一个服务进程同时执行的任务4CPU、内存与数据库连接吃紧

三者相乘才是峰值压力。调参顺序应是先看模型配额,再定任务并发,最后才开场景并发。

5.2 OPENMAIC_MAX_ACTIVE_RUNS_PER_OWNER

默认值:2。排队等待确认大纲、或因失败暂停的任务不计入。

实测:改为 1 后重启,任务列表接口回显新上限:

{"success":true,"runs":[],"limits":{"maxActive":1,"maxWaiting":10}}

基线值为:

{"success":true,"runs":[],"limits":{"maxActive":2,"maxWaiting":10}}

结论:超过上限时,新建、确认或重试任务会返回 429 ACTIVE_RUN_LIMIT。个人服务器建议 1–2,避免一次开多堂课把模型配额打满。

5.3 OPENMAIC_MAX_WAITING_RUNS_PER_OWNER

默认值:10。限定同一所有者同时等待大纲确认的任务数;超出后同样拒绝新建。

5.4 OPENMAIC_GENERATION_RUN_MAX_CONCURRENT

默认值:4。一个服务进程同时执行几个任务。启动日志会把它打印出来,实测:

[2026-10-25T07:53:21.705Z] [INFO] [GenerationRunner] generation runner 1:b56db764-fbe7-468c-84bf-756a8af92ec1 started (scan=1000ms, heartbeat=2000ms, leaseTtl=10000ms, maxConcurrent=4)

日志同时给出租约参数:每 1000 ms 扫描一次,每 2000 ms 续约一次,租约 10000 ms 过期;进程崩溃后,租约到期由其他进程接管。

5.5 其余生成相关参数

参数默认作用
OPENMAIC_GENERATION_RUN_STREAMS_PER_OWNER16单个所有者在一个进程上可同时保持的事件流数量
OPENMAIC_GENERATION_RUN_RETENTION_HOURS24已完成任务保留完整事件日志的小时数,之后压缩为最终快照
OPENMAIC_MATERIAL_EXTRACTION_CONCURRENCY2一个进程同时解析几份上传资料
OPENMAIC_MATERIAL_EXTRACTION_PER_OWNER2单个所有者跨进程同时解析的资料数
OPENMAIC_MATERIAL_EXTRACTION_MAX_RESULT_MB100单份资料解析结果(文本与图片)的上限,超出返回 EXTRACTION_RESULT_TOO_LARGE
OPENMAIC_UNUSED_MATERIAL_TTL_HOURS24未被任务引用的上传资料保留时长

上传资料在附加后立即进入后台解析,生成时直接复用解析结果。资料解析并发过高会与场景生成争抢 CPU,低配机器上建议保持默认甚至调低。

六、模型配置 openmaic.yml

6.1 文件结构与启动校验

openmaic.yml 由三块组成:

providers:
  openai:
    preset: openai
    apiKey: ${OPENAI_API_KEY}
    models: [gpt-5.5]

slots:
  llm: openai:gpt-5.5
  course.outline: openai:gpt-5.5

lock: []
allowUserKeys: true
  • providers:服务商账号与允许调用的模型白名单。带密钥的服务商必须给出 models,未列入的模型不会被服务端使用。
  • slots:AI 用途到模型的映射。llm 是根槽位,未单独指定的对话槽位跟随它。
  • lock:固定槽位,用户不可改。
  • allowUserKeys:是否允许用户在界面添加自己的服务商与密钥。

服务在启动时做完整校验,出错即拒绝启动。实测一:未知槽位。写入 slots.notARealSlot 后重启:

openmaic-1  | [boot] Invalid server configuration; the server will not start: Invalid model configuration in /app/openmaic.yml:
openmaic-1  |   - slots.notARealSlot: unknown slot

docker inspect 同时显示:

ExitCode=1 Restarting=true RestartCount=7

实测二:引用未设置的环境变量。把 apiKey 写成 ${OPENMAIC_TEST_MISSING_KEY}:

openmaic-1  | [boot] Invalid server configuration; the server will not start: Invalid model configuration in /app/openmaic.yml:
openmaic-1  |   - providers.openai.apiKey: environment variable OPENMAIC_TEST_MISSING_KEY is not set

结论:配置错误是「快速失败」,不会带病运行。报错会精确到 slots.<名称> 或 providers.<名称>.<字段>,按提示修即可。

6.2 槽位清单

槽位用途备注
llm所有未单独指定的对话槽位根槽位,至少配一个可用模型
course.outline课程大纲未配置时生成课程报 MISSING_MODEL,实测见第六章 6.3
course.content.*幻灯片、测验、互动组件、PBL 等场景内容可按场景类型分别指定
course.actions教师讲解动作与白板脚本影响课堂演出效果
course.agents教师与同学人设影响角色多样性
classroom课堂内互动对话学习者提问走这里
agentPro 工作台智能体要求模型支持工具调用
tts / asr语音合成 / 识别未配置时健康接口对应能力为 false
image / video插图 / 视频同上
webSearch / webFetch联网搜索 / 抓取同上
document文档解析同上

实测:未配置模型时,健康接口的四项能力全为 false:

"capabilities":{"webSearch":false,"imageGeneration":false,"videoGeneration":false,"tts":false}

6.3 缺失槽位的运行时表现

curl -s -X POST http://127.0.0.1:8144/api/generate-classroom \
  -H "Cookie: openmaic_access=$TOK" -H 'Content-Type: application/json' \
  --data '{"requirement":"用 10 分钟讲清 TCP 三次握手"}'

实测回显:

{"success":false,"errorCode":"MISSING_MODEL","error":"No model is configured for course.outline. Set one in the model settings, or assign the slot (or an ancestor) in openmaic.yml."}

结论:llm 配了但 course.outline 没配、且没有可继承的祖先时,生成会被精确拦在第一步,不会产生半成品课程。

6.4 备用模型

语言模型槽位可写 fallback。当主模型返回可重试错误(超时、网络错误、配额 429、容量 503)或空输出时,共享调用层会改用备用模型重试一次;内容安全拒绝与其他 4xx 不会触发备用。

6.5 服务商预设与自建服务

  • preset 可选官方内置的服务商标识(OpenAI、Anthropic、Google、DeepSeek、Qwen、Kimi、MiniMax、GLM、SiliconFlow、Doubao、OpenRouter、Grok、Azure OpenAI、AtlasCloud 等)。
  • 任意 OpenAI 兼容端点可填自定义 baseUrl;自建推理服务(如 Ollama)需要 ALLOW_LOCAL_NETWORKS=true,否则对私有网段的请求会被拦截。
  • 平台内置的实例元数据地址(如 169.254.169.254)即使在允许内网时也会被拒。

七、密钥与存储参数

7.1 OPENMAIC_SECRET_KEY

默认值:空。未设置时,首次在界面保存模型密钥会在数据目录生成 data/instance-secret.key,用它加密保存在数据库里的服务商密钥。

实测:本文全程未在界面保存密钥,数据目录中只有上传资料目录,密钥文件尚未生成:

total 4
drwxr-xr-x    3 nextjs   nogroup       4096 Oct 25 07:34 materials

结论:

  • 多实例部署、数据目录不持久、或文件系统只读时,必须显式设置该变量(可用 openssl rand -base64 32 生成)。
  • 它必须与数据库一起备份;丢失后,界面上保存过的模型密钥无法解密。
  • 密钥在数据库中用不同 secret 加密时,服务启动会告警。

7.2 OPENMAIC_CONFIG

默认值:启动目录下的 openmaic.yml(发行内为 /app/openmaic.yml)。

结论:设为相对路径时按启动目录解析;一旦设置,文件必须存在,否则启动失败。多个部署共用一份配置文件时用绝对路径挂载并只读。

7.3 素材与存储

参数默认作用
ASSET_QUOTA_BYTES10 GiB单个所有者可持有的素材字节数,0 表示不限制
ASSET_S3_BUCKET空设置后素材存 S3 而不是 PostgreSQL
OPENMAIC_CLASSROOMS_DIR数据目录下课堂文件落盘位置

结论:素材配额按「所有者」计,匿名模式下清 Cookie 就等于换了一个新所有者、获得一份新配额;这也是多人共用时应选单用户或共享所有者的原因之一。

八、修改与生效流程

8.1 环境变量

  1. 编辑 docker-compose.yml 的 environment: 段;
  2. docker compose up -d(只 restart 不会应用新的环境变量定义,必须让服务重建);
  3. 等待健康检查通过,读取回显确认生效。
cd /opt/openmaic
docker compose up -d
for i in $(seq 1 30); do
  code=$(curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:8144/api/health)
  [ "$code" = "200" ] && break
  sleep 2
done
curl -s http://127.0.0.1:8144/api/health

8.2 openmaic.yml

改完文件后重启服务,并检查是否有启动校验报错:

docker compose restart openmaic
docker compose logs openmaic --since 2m | grep -E 'Invalid server configuration|GenerationRunner'

只有看到 GenerationRunner ... started 且没有 Invalid server configuration,才说明配置通过校验。

8.3 运行时设置

在界面「模型设置」中保存的服务商与密钥写入数据库,立即生效。若 openmaic.yml 中 lock 固定了该槽位,界面改动会被忽略;allowUserKeys=false 时用户不能添加自己的密钥。

九、实测参数对照表

参数基线值实测值验证接口观测结果
DATABASE_URL正常连接清空启动日志Restarting (1),ExitCode=1,报 DATABASE_URL is not set
ACCESS_CODEq1w2e3r4移除/api/health、/api/foldersaccessCodeConfigured:false,无凭据返回 200
ACCESS_CODE 长度8 位8 位验证时的服务日志shorter than 16 characters 告警
OWNER_SINGLE_USERtruefalse/api/persistence/learner-keylocal → anon:<uuid>,两台浏览器互不可见
COOKIE_SECURE默认0验证接口响应头Secure 标记消失
PARALLEL_SCENE_CONCURRENCY03/api/healthparallelSceneConcurrency:3
OPENMAIC_MAX_ACTIVE_RUNS_PER_OWNER21/api/generation-runs?active=1limits.maxActive:1
openmaic.yml 未知槽位合法slots.notARealSlot启动日志unknown slot,退出码 1
openmaic.yml 未设变量合法${OPENMAIC_TEST_MISSING_KEY}启动日志environment variable ... is not set,退出码 1

全部实测完成后已恢复基线:parallelSceneConcurrency 回到 0、maxActive 回到 2、Cookie 重新带 Secure、learnerKey 回到 local,并删除测试期间创建的文件夹与临时 openmaic.yml。

十、常见问题

Q1:改了环境变量但接口回显没变

用 docker compose restart openmaic 只会重启进程,不会应用 docker-compose.yml 中新的 environment: 定义。改用 docker compose up -d 让服务按新配置重建。

Q2:设置了 COOKIE_SECURE=0 仍然反复要求输口令

检查值是否精确为 0;false 与 no 都不会关闭 Secure。若前面有反向代理,确认它没有把响应头改写。

Q3:单用户模式开启后,多人看到的是同一个课程库

这是 OWNER_SINGLE_USER=true 的设计行为:所有请求归同一个所有者,访问口令只控制「能不能进」,不区分「是谁」。需要按人隔离时关闭该模式并接入真实身份方法。

Q4:生成课程总是 400 MISSING_MODEL

读报错里的槽位名(如 course.outline),在 openmaic.yml 的 slots 中补上该槽位,或补上可继承的 llm 根槽位,然后重启。

Q5:openmaic.yml 改了但服务仍用旧模型

该文件只在启动时读取。执行 docker compose restart openmaic,并确认挂载路径与 OPENMAIC_CONFIG 一致。

Q6:调大舞台并发后出现模型限流报错

PARALLEL_SCENE_CONCURRENCY 放大的是同一堂课的瞬时请求数,且只在浏览器侧生效。先确认模型服务商的并发配额,必要时退回 0 串行,再考虑降低 OPENMAIC_MAX_ACTIVE_RUNS_PER_OWNER。

十一、参考链接