配置
配置全部通过环境变量读取。从 .env.example 开始:
cp .env.example .env
.env.example 中的每个变量都在本页有文档,分组与文件一致。表中默认值即
.env.example 中的值;"未设置"表示默认为空,对应功能在填入前保持关闭。
真实部署必改项
将 Manor AI 暴露到本地评估之外前,务必修改:
| 变量 | 用途 |
|---|---|
JWT_SECRET_KEY | 签名用户会话。使用足够长的随机值。 |
DATABASE_URL | 异步 PostgreSQL 连接串。 |
DATABASE_URL_SYNC | Alembic 使用的同步 PostgreSQL 连接串。 |
REDIS_URL | Redis 缓存与 broker 地址。 |
MINIO_ACCESS_KEY / MINIO_SECRET_KEY | 对象存储凭据。 |
PUBLIC_BASE_URL | Webhook 与生成媒体回调使用的公网 URL。 |
APP_URL | 浏览器访问的 Web URL。 |
部署模式与默认模型
| 变量 | 默认值 | 说明 |
|---|---|---|
DEPLOYMENT_MODE | oss | oss 即自托管模式。所有自托管部署保持 oss 不变。 |
LLM_MODEL | anthropic/claude-sonnet-4 | 默认模型 id。用户和实体可在 设置中覆盖。 |
自托管 Manor AI 采用 BYOK(自带密钥):模型调用只使用在设置中配置的 提供商凭据。不要把模型 API 密钥写进镜像或源码仓库。
实时语音通话
普通 Chat、Workspace Chat 和公开 Webchat 的麦克风输入按钮旁提供开始语音通话。 接通后可连续说话,停顿后 AI 自动回复,回复按句生成并播放;再次开口即可打断播放。 通话面板包含字幕、静音和挂断。对话文字保存在原聊天中,工具执行和审批仍走现有聊天运行时。 涉及复杂工具操作时,回复可能需要更长时间。 Workspace 暂停后仍可直接聊天,受暂停限制的操作不会恢复;公开渠道通话要求 Workspace 处于活跃状态。
自托管 Realtime 通话需在“账户 → 模型”为Primary AI 配置原生 OpenAI BYOK。 语音识别和语音合成角色的密钥只用于轮次式 STT/Chat/TTS,不会被提升为整段 Realtime 凭据。 服务端自动检测说话、调用现有 Chat,再播放回复,延迟取决于模型与工具执行时间。 公开 Webchat 使用渠道所有者的凭据和计费范围,不会使用访客的密钥。
除 localhost 外,麦克风访问需要 HTTPS。自定义反向代理需为 /api/v1/audio/live
允许 WebSocket 升级,并为应用页面设置 Permissions-Policy: microphone=(self);
文档预览框架继续禁止麦克风。嵌入 Webchat 时,宿主页面也需允许聊天来源使用麦克风,
生成的嵌入脚本已包含 iframe 权限。
音频由语音服务商处理,服务端保存对话文字、通过统一语音计 费流程记录费用,并在通话中复查权限。 挂断会立即停止采集、取消请求准备并阻止新的重试;已经提交的语音网关请求可能在通话结束后返回,并记录实际用量。
统一语音链路先在本地检测人声,减少背景噪声造成的误识别和误打断。疑似发声只暂时暂停播放,识别出新的话语后才正式打断;空识别会恢复原来的声音。 已完成的回复会保留在通话面板中,不因打断而清空。首句单独合成,后续语音在播放期间准备。 面板分别显示语音识别、Chat 思考和语音生成阶段,并在声音生成前显示 Chat 回复。通话面板显示麦克风音量, 并提供不调用服务商的“测试扬声器”提示音。没有声音时,先检查音量条、扬声器测试、浏览器输出设备和音量, 再检查服务器到语音网关的网络连接。
挂断、离开页面、切换聊天、失去权限或达到 30 分钟上限都会结束通话。
断线后需手动重新呼叫,已完成的操作不会自动重放。
旧的 /chat/voice-session 和 /chat/voice-save 接口由经过认证的服务端中继取代。
数据库
| 变量 | 默认值 | 说明 |
|---|---|---|
DATABASE_URL | postgresql+asyncpg://manor:manor_secret@postgres:5432/manor | API 与 worker 使用的异步 SQLAlchemy URL。 |
DATABASE_URL_SYNC | postgresql://manor:manor_secret@postgres:5432/manor | Alembic 迁移使用的同步 URL,须与 DATABASE_URL 指向同一数据库。 |
DATABASE_POOL_SIZE | 5 | 每个 API 进程保持的连接数。 |
DATABASE_MAX_OVERFLOW | 2 | 突发负载下允许超出池大小的额外连接数。 |
DATABASE_POOL_TIMEOUT | 10 | 等待空闲连接的秒数,超时报错。 |
DATABASE_POOL_RECYCLE | 1800 | 池中连接的回收周期(秒)。 |
DATABASE_ADMISSION_LIMIT | 0 | 每个进程/事件循环允许的并发 Session 事务数。0 对本地连接池和直连 PostgreSQL 的 worker 保留池大小 + overflow − 1,最小为 1;PgBouncer 下取 app 4 / worker 1,其他应用 NullPool 取 4。 |
DATABASE_MAX_WAITERS | 14 | 并发事务已满时最多排队的事务数。 |
DATABASE_ADMISSION_TIMEOUT | 2 | 排队等待上限(秒)。过载返回 HTTP 503,包含 detail.code=database_busy 和 Retry-After。 |
DATABASE_HOLD_WARN_SECONDS | 5 | 连接占用超过此秒数后,记录带 request ID 的警告。 |
DATABASE_STATEMENT_TIMEOUT_MS | 0 | 可选的 PostgreSQL 事务内语句时限(毫秒)。0 保持数据库默认值。 |
DATABASE_LOCK_TIMEOUT_MS | 0 | 可选的事务内等待数据库锁时限(毫秒)。 |
DATABASE_IDLE_TRANSACTION_TIMEOUT_MS | 0 | 可选的事务内空闲时限(毫秒)。 |
须计算所有 API/chat 副本与进程:连接池上限为
sum(副本数 × 进程数 × (DATABASE_POOL_SIZE + DATABASE_MAX_OVERFLOW))。
另外计入各 Celery 进程的事务预算、迁移/运维连接和安全余量,总和应低于 PostgreSQL 的
max_connections。Celery 使 用一次性 NullPool 引擎;准入名额只在同一事件
循环内共享,不跨 worker 进程,可保守按并发进程数 × 准入上限计算。
直连 PostgreSQL 的 worker 虽然使用 NullPool,仍保留原有自动额度(默认池参数下为 6),
避免将已有嵌套 Session 缩减为单名额。这是兼容性默认值,不代表本地连接池。
显式额度为 1 时,调用方持有事务期间仍无法让第二个 Session 同时查询。
NullPool 的正数显式额度不受未使用的 DATABASE_POOL_SIZE/MAX_OVERFLOW 限制。
PgBouncer 客户端预算应计入副本 × 进程 × 事务额度、独立探针、滚动更新、退出中的 Pod 和 Job;
服务端连接池另行约束 PostgreSQL 总连接数,也须设置后端排队时限。两层容量不能混为一谈。
名额按数据库事务持有,不按整个请求、WebSocket、LLM 调用或文件流持有。
使用实际本地连接池时,自动限制在池容量至少为 2 时,为有时限的就绪探针保留一个名额。显式限制不能
超过池大小 + overflow。过载不会自动重放写入;重试应遵守 Retry-After,
并使用对应操作的幂等约定。
启用可选时限前,须审计任务/审批中长时间持锁的流程。设置仅在当前事务内生效,
兼容 PgBouncer,不会终止已经释放数据库连接的慢 LLM 或 sandbox 工作。
自托管模式的 /health/deep 提供连接占用/长占用次数、活跃事务、排队/拒绝次数
和最长等待时间。queue_full 表示队列已满、尚未进入排队就被拒绝的次数;
wait_timeouts 表示已排队但超过准入时限的次数。peak_active_transactions
和 peak_waiters 是当前进程/事件循环的峰值,不代表整个部署的容量,重启会清零。
长占用日志只记录 request ID,不记录 SQL 参数或凭据。
Redis
| 变量 | 默认值 | 说明 |
|---|---|---|
REDIS_URL | redis://redis:6379/0 | 缓存、Celery broker、限流后端与在线状态存储。 |
REDIS_MAXMEMORY | 0 | Redis 服务内存上限。0 为不限制;共享主机建议设置如 512mb 的上限。 |
REDIS_MAXMEMORY_POLICY | noeviction | 达到上限后的淘汰策略。若能接受缓存淘汰,可将有限的 REDIS_MAXMEMORY 搭配 allkeys-lru。 |
同一 Redis 实例的 /1 库存放 JuiceFS 元数据(见
存储);若指向外部 Redis,请保持 /0 与
/1 分离。
API 服务调优
单机应急控制项。默认值保守、适合评估;调高前先测量 CPU、p95 延迟和数据库 连接数。
| 变量 | 默认值 | 说明 |
|---|---|---|
API_WORKERS | 1 | Uvicorn worker 进程数。 |
API_LIMIT_CONCURRENCY | 120 | 单 worker 并发连接上限,超出即拒绝请求。 |
API_BACKLOG | 256 | 等待连接的 socket backlog。 |
API_TIMEOUT_KEEP_ALIVE | 5 | Keep-alive 超时(秒)。 |
共享 WebSocket 推送管理器每进程最多同时发送 32 条帧,每次发送和失败连接的 关闭操作分别有 2 秒时限。同一 socket 的发送串行化,组织索引仅定位目标组织的 候选连接,不缓存权限;内容推送前仍校验当前成员关系、可见范围和 Token 版本。 慢连接会被关闭,重连后须与已落库消息对齐。实时推送是尽力交付,不是持久化的 送达回执。这些上限不等于可支持的用户数;调整进程、副本或连接预算前,须一起 压测真实 socket、消息频率、数据库延迟和后台任务。
限流
所有限流器默认关闭(便于本地评估)。任何面向真实用户的共享部署都应启用。
| 变量 | 默认值 | 说明 |
|---|---|---|
RATE_LIMIT_ENABLED | false | 通用 API 限流总开关。 |
API_RATE_LIMIT_REQUESTS | 200 | 每窗口每客户端允许的请求数。 |
API_RATE_LIMIT_WINDOW_SECONDS | 60 | 通用限流窗口长度。 |
CHAT_RATE_LIMIT_ENABLED | false | 聊天路由(成本最高)的独立限流器。 |
CHAT_RATE_LIMIT_REQUESTS | 30 | 每窗口允许的聊天请求数。 |
CHAT_RATE_LIMIT_WINDOW_SECONDS | 60 | 聊天限流窗口长度。 |
REDIS_RATE_LIMIT_ENABLED | false | 将限流状态存入 Redis,使限额在所有 API worker 间共享(而非按进程独立)。API_WORKERS > 1 时务必启用。 |