OpenMAIC v1.2.1 配置参数详解
OpenMAIC v1.2.1 配置参数详解:逐项实测数据库连接、访问口令、单用户与匿名身份、Cookie Secure、场景并发、生成队列上限与 openmaic.yml 模型槽位,给出默认值、修改方式、重启生效与验证命令及启动校验排障。
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.jsv22.23.4、Next.js16.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 已设置;两者是配套的安全边界,单独放开监听等于把课程库暴露给同网段所有人。
4.4 COOKIE_SECURE
默认值:生产构建下为开启(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一个服务进程同时执行的任务 4 CPU、内存与数据库连接吃紧 三者相乘才是峰值压力。调参顺序应是先看模型配额,再定任务并发,最后才开场景并发。
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_OWNER | 16 | 单个所有者在一个进程上可同时保持的事件流数量 |
OPENMAIC_GENERATION_RUN_RETENTION_HOURS | 24 | 已完成任务保留完整事件日志的小时数,之后压缩为最终快照 |
OPENMAIC_MATERIAL_EXTRACTION_CONCURRENCY | 2 | 一个进程同时解析几份上传资料 |
OPENMAIC_MATERIAL_EXTRACTION_PER_OWNER | 2 | 单个所有者跨进程同时解析的资料数 |
OPENMAIC_MATERIAL_EXTRACTION_MAX_RESULT_MB | 100 | 单份资料解析结果(文本与图片)的上限,超出返回 EXTRACTION_RESULT_TOO_LARGE |
OPENMAIC_UNUSED_MATERIAL_TTL_HOURS | 24 | 未被任务引用的上传资料保留时长 |
上传资料在附加后立即进入后台解析,生成时直接复用解析结果。资料解析并发过高会与场景生成争抢 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 | 课堂内互动对话 | 学习者提问走这里 |
agent | Pro 工作台智能体 | 要求模型支持工具调用 |
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_BYTES | 10 GiB | 单个所有者可持有的素材字节数,0 表示不限制 |
ASSET_S3_BUCKET | 空 | 设置后素材存 S3 而不是 PostgreSQL |
OPENMAIC_CLASSROOMS_DIR | 数据目录下 | 课堂文件落盘位置 |
结论:素材配额按「所有者」计,匿名模式下清 Cookie 就等于换了一个新所有者、获得一份新配额;这也是多人共用时应选单用户或共享所有者的原因之一。
八、修改与生效流程
8.1 环境变量
- 编辑
docker-compose.yml的environment:段; docker compose up -d(只restart不会应用新的环境变量定义,必须让服务重建);- 等待健康检查通过,读取回显确认生效。
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_CODE | q1w2e3r4 | 移除 | /api/health、/api/folders | accessCodeConfigured:false,无凭据返回 200 |
ACCESS_CODE 长度 | 8 位 | 8 位 | 验证时的服务日志 | shorter than 16 characters 告警 |
OWNER_SINGLE_USER | true | false | /api/persistence/learner-key | local → anon:<uuid>,两台浏览器互不可见 |
COOKIE_SECURE | 默认 | 0 | 验证接口响应头 | Secure 标记消失 |
PARALLEL_SCENE_CONCURRENCY | 0 | 3 | /api/health | parallelSceneConcurrency:3 |
OPENMAIC_MAX_ACTIVE_RUNS_PER_OWNER | 2 | 1 | /api/generation-runs?active=1 | limits.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。
十一、参考链接
- OpenMAIC 官方中文配置文档:https://github.com/THU-MAIC/OpenMAIC/blob/main/packages/docs/content/docs/configuration.zh-cn.mdx (查询日期 2026-10-25)
- 官方环境变量模板:https://github.com/THU-MAIC/OpenMAIC/blob/main/.env.example (查询日期 2026-10-25)
- 官方模型配置模板:https://github.com/THU-MAIC/OpenMAIC/blob/main/openmaic.example.yml (查询日期 2026-10-25)
- 官方中文部署文档:https://github.com/THU-MAIC/OpenMAIC/blob/main/packages/docs/content/docs/deployment.zh-cn.mdx (查询日期 2026-10-25)