家里那台 Mac mini 吃灰大半年之后,我终于给它找到一个全职岗位:7×24 小时不关机的 AI 助手。整套方案说简单也简单:一台基础款 Mac mini 常开,跑一个叫 OpenClaw 的开源助手框架,模型请求统一走一层自己搭的 API 网关/聚合接入服务,也就是标题里说的“中转 API”。算下来硬件一次性投入不高,日常用电几乎可以忽略,却能同时承担早晨简报、定时巡检、消息自动回复、资料整理这些杂活。这篇文章就把我完整跑通的路径拆开写出来,包括设备选型、系统设置、网关转发、日志安全、坑点排查,适合手里正好有闲置 Mac mini、又想低成本挂一个个人 AI 助手的人。
先说最重要的一句话:凡是涉及模型 API 的地方,都必须使用合规、有授权的接入方式。所谓“中转 API”我按工程意义上的“API 中间接入层/API 网关”来理解,它接收请求、统一加密钥、转发到上游模型服务商,再把结果返回。它可以自己维护,也可以选择条款清晰的第三方 API 聚合服务,前提都是遵守对应服务商的使用条款和法律法规。下面所有内容都建立在这个前提上。
1. 这套方案的整体运转逻辑
1.1 为什么要把 AI 助手固定在一台常开的设备上
手机里的 AI 助手随叫随到,但它做不到“没人叫的时候也在干活”。大部分个人场景里,真正有价值的是定时任务:每天早上生成一份项目简报,每小时检查一下某个服务是否在线,每十分钟抓一次网页价格变动,有邮件进来时自动分类摘要。这些事依赖一个稳定的常驻进程,而手机应用的后台调度往往不可控,云服务器又需要持续花钱。
Mac mini 在闲置设备里几乎是完美的常开底座。功耗低,风扇声音很小,放在书架上不占地方。相比自己攒的迷你主机,它的系统休眠策略更好控制,而且 I/O 稳定。我实际测试下来,整机待机功耗几乎可以忽略,长期下来电费远低于一台小型云服务器的月租。对只是跑个助手进程的人来说,性能也绰绰有余,基础款的芯片处理常规文本任务完全不会成为瓶颈。
这套方案的本质,是把“AI 助手”从一次性的网页对话,改造成一个本地常驻的自动化节点。它不是替代云端服务的思路,而是把那些不需要高并发、不需要公网暴露、纯粹为个人或小团队服务的任务,从云服务器搬回到手边这台设备上。
1.2 OpenClaw 这类开源框架在方案里的角色
“OpenClaw”这个叫法,在社区里并不特指某一个官方产品,而是一类开源 AI 助手框架的习惯代称。这类框架做的事情很明确:帮你管理“什么时候该调用模型”“模型返回之后怎么执行工具”“对话上下文怎么保存”。它不像商业产品那样给你一个聊天界面,而是给你一套可配置的骨架,你往里面填模型接口、填任务、填工具,剩下的调度逻辑由框架替你跑。
我测试用的框架就属于这一类型:支持配置多个模型服务端地址,内置了定时任务、多轮对话记忆、工具调用等基础模块。你可以把 OpenClaw 理解成一个“会自己看表的秘书”,它负责在正确的时间点把问题丢给大模型,拿到答案后再按你预设的规则去执行下一步。比如早晨八点它调一次模型生成天气和日程摘要,然后把结果通过邮件发出来;又比如收到团队协作工具的消息回调后,它把消息内容包装成一次对话,再调模型生成回复,整个过程不需要人肉介入。
要特别说明的是,OpenClaw 本身不提供大模型能力。它只是个编排器,真正的对话和生成能力来自你配置的 API 服务。所以方案里必须有一个稳定的 API 接入层,这就是下一节要展开的内容。
1.3 统一 API 网关解决了什么问题
很多人不理解为啥要平白多一层“中转”。其实这层的作用不是绕什么路,而是把多个不同的模型服务统一成一个入口。我自己的场景里,有的任务适合用响应更快的轻量模型,有的任务需要更强的长文本能力,还有的任务希望固定成本。我既不想在每个脚本里都写一遍密钥读取和错误处理,也不想因为某个模型临时不可用就得改全部代码。
自建一个极简的 API 网关放在中间,全部任务只跟这个网关说话。网关统一负责三件事:把本机保存的密钥加到上游请求头上;把不同模型供应商的请求格式归一化;把超时、重试、错误码转换这些通用逻辑收拢到一个地方。这样我切换模型供应商时,只需要改网关的配置,OpenClaw 和各个任务脚本完全不动。听起来简单,但在实际维护里能省下大量时间。
另外,只要你愿意,你也可以换成有资质的第三方 API 聚合服务,本质上是一样的逻辑:拿到一个统一入口,管理密钥和计费。选择标准我会在后面补充,核心原则就一条,接入方式和授权必须正规,别为了省几块钱去碰来源不明的接口。
2. 设备与环境准备
2.1 硬件怎么选最省心
我手上这台是最基础款的 Mac mini。对跑个人 AI 助手来说,内存尽量上到 16GB 会比较从容,因为框架本身、Python 进程、可能还挂着浏览器自动化任务,这些加起来内存容易吃紧。8GB 不是不能用,但长周期多任务并发时,系统会开始用交换空间,响应就会迟钝,所以预算允许的话选择 16GB 版本。
存储方面,256GB 起步够用,但最好外接一块移动硬盘用来放日志和备份。日志文件看起来不起眼,几个月不清理也能攒出好几个 GB,而且 Mac mini 内置磁盘一旦写满,整个系统都会进入不可控状态。我是把/opt/assistant/logs这个目录直接放到外接盘上,这样即使日志膨胀也不影响系统盘。
另外,Mac mini 的电源管理比笔记本简单,因为没有电池和合盖逻辑,适合 7×24 跑。唯一要留意的是散热环境,别把它塞在密闭柜子里。放在通风的书架层板或桌面上,风扇几乎不会吵到你。这些都是我踩过或者见过别人踩过的实际问题。
2.2 macOS 上的常开设置
Mac mini 虽然本身没有电池,但 macOS 默认依然会在一段时间无操作后进入睡眠。必须把睡眠策略关掉。具体路径是“系统设置”里的“能源”或“电池”面板,把“在此时间后关闭显示器”调成“永不”,同时关闭“如果可能,使硬盘进入睡眠”。注意这里的“关闭显示器”不要选成“系统睡眠”,显示器关闭不影响计算任务继续跑,但硬盘睡眠会导致某些定时任务唤醒时出现奇怪延迟。
另一个容易被忽略的点是自动登录。如果系统意外重启,停在登录界面,助手就起不来了。可以在“用户与群组”里开启自动登录,把当前账户设为自动进入桌面。配合第三小节要讲的 launchd 配置,系统启动后会自动拉起全部任务,实现真正意义上的无人值守。我还要把电源连接保持稳定,建议单独配一个 UPS 或者至少插在带浪涌保护的插线板上,市电瞬时抖动不至于直接重启。
2.3 运行环境:我用 Docker 还是裸跑
个人助手这种常驻进程,我强烈建议裸跑而不是用 Docker 套一层。原因是这类框架往往要调用本地工具、读写用户目录下的配置文件、偶尔还要执行 shell 命令,容器化之后权限和路径映射会变得非常繁琐。省下的隔离性对个人设备来说意义不大,反而增加了排错成本。
裸跑环境的准备无非是三步:装好 Python 运行时和相关编译工具,用系统包管理器把依赖装齐,然后把 OpenClaw 这类框架拉下来。我不在这里贴具体的安装命令,因为不同分支的启动方式差异很大,但整体套路是一致的:先装依赖,再初始化配置目录,最后用 launchd 创建一个守护任务,让系统保证进程常驻。
macOS 上不要依赖 cron 做定时任务,一是权限不够,二是网络和环境变量经常不生效。正确做法是 launchd,它能在进程崩溃时自动拉起来,还能设置重启间隔,比任何外部 supervisor 都可靠。后面的配置我会直接给 plist 示例。
3. 核心配置与实操要点
3.1 OpenClaw 的初始化与模型接入配置
先讲框架的整体配置文件长什么样。大多数开源助手框架都会有一个 YAML 配置,里面划分成几个段落:助手名称与记忆开关、可用工具列表、模型接入地址、系统提示词。记忆开关我建议打开,它能让框架把历史对话摘要存到本地数据库里,这样多轮任务之间有连续性,而不是每一轮都从头开始。
模型接入这段是核心,每个框架叫法不同,但参数逻辑基本一致。我这里给一个抽象过的例子:
assistant: name: home-ai memory: enable: true storage: sqlite models: primary: base_url: "http://127.0.0.1:8899/v1" api_key_env: "UPSTREAM_API_KEY" model: "primary-chat" temperature: 0.3 max_tokens: 2048这里面的base_url指向我自建的本地 API 网关,api_key_env表示密钥从环境变量里读,而不是直接写进配置文件。temperature是采样温度,对自动化任务来说低一点好,我一般保持在 0.2 到 0.4,这样输出更稳定、更少随机发挥。max_tokens控制单次生成长度,定太小会截断,定太大会浪费资源和时间。
初始化的时候要特别留意模型名是否与上游接口对应。不同服务商对模型标识的写法不一样,而且有些聚合服务会要求特定的模型名格式。我把这条经验写在这里:先在命令行里直接用 curl 测试一次模型接口,确认返回 200 后再把地址写进框架配置。跳过这一步直接改 YAML,后面出了错很难分清是网络问题还是模型名写错。
3.2 自己搭一个轻量 API 网关
下面这条路径是我反复调整后觉得最适合个人使用的方案:用 Python 标准库写一个极小的转发服务。它不需要任何依赖,也不会被框架的第三方库版本冲突影响,跑起来占用的内存可以忽略。核心函数大概长这样:
import json import urllib.request def forward_chat_body(body: dict, upstream_url: str, api_key: str) -> dict: req = urllib.request.Request( upstream_url, data=json.dumps(body).encode("utf-8"), headers={ "Content-Type": "application/json", "Authorization": "Bearer " + api_key, }, method="POST", ) with urllib.request.urlopen(req, timeout=120) as resp: return json.loads(resp.read().decode("utf-8"))这个函数接收一个完整的 chat 请求体,向上游地址发起 POST,然后把上游返回的 JSON 原样返回。网关启动时只需要绑定本机回环地址,不要监听公网。你可以用 Python 自带的 HTTP 服务模块快速起一个本地端口,接住框架发来的请求,调用上面这个转发函数,再把结果写回。
别嫌这个网关简陋,它的价值全在“统一”两个字上。你可以在转发函数外面加超时控制、错误码映射、按 API key 区分任务优先级。等到哪一天你想把主模型换成另一个服务商,只需要改函数开头的upstream_url和api_key,框架和其他任务完全不需要动。
我不建议个人用户直接购买来源不明的“无限额度/超低价”接口,那种服务稳定性没有保证,而且很可能是盗用或违规转售,风险远大于省下的那点钱。合规思路下,自建网关 + 正规渠道密钥是最省心的组合。
3.3 密钥、日志与安全三件套
密钥管理是第一优先级。不要把 API 密钥写死在配置文件里,更不要提交到任何版本仓库。我用的是环境变量注入:在 launchd 的 plist 里用EnvironmentVariables字典把密钥传进去,这样进程一启动就能读到,同时磁盘上只有一个 plist 文件有敏感信息。这个 plist 我会加上权限限制,保证只有当前用户能读。
日志是排障的生命线。OpenClaw 本身会输出运行日志,我额外让网关把每一次转发的时间、状态码、耗时、token 用量写到一个独立的日志文件里。这样即使助手回答质量出现问题,我也能快速判断是模型侧的问题,还是网关超时,还是任务脚本本身报错。日志需要定期轮转,我用的是系统自带的日志滚动方案,按天切分并压缩旧日志,避免单个文件无限增长。
安全层面,我坚持两条底线:网关只监听本机,不在公网暴露任何端口;凡是涉及外部回调的场景,一定要在回调 URL 里带上随机 token,并在接收端校验。7×24 常驻的机器最忌讳的就是图省事开一堆端口,一旦被扫描到,后面所有努力都白费。
4. 场景实测:从定时任务开始
4.1 第一个任务:每天早上八点生成一份简报
先从最简单的定时任务说起:每天早上八点让助手拉取天气、检查日程,再生成一份文本摘要发给指定邮箱。我是用 launchd 的StartCalendarInterval来触发,这样进程在后台跑,即使整个 Mac mini 刚刚重启,到点也会自动执行。
launchd 的 plist 大概配置是这样的:ProgramArguments里指定框架命令行入口和参数,StartCalendarInterval设置成{"Hour": 8, "Minute": 0},RunAtLoad设为 false。任务执行时,脚本会先走一遍天气和日程插件,把结果汇总后拼成一个 prompt,交给框架调用模型生成摘要,最后通过邮件发送。整个过程大概半分钟,完全不用开浏览器。
这个任务本身不复杂,但它验证了整条链路:launchd 触发、框架调度、工具插件执行、模型生成、结果推送。链路跑通后,后面加任何新任务都只是往这个模板里填空。
实操心得是,第一版任务里把“固定时间”改成“工作日”会更实用,节假日不必打扰自己。launchd 的日历配置里不支持复杂的“跳过周末”逻辑,我的做法是让脚本自己判断当天是不是周末,是就直接退出。这样避免在 launchd 层把事情搞复杂。
4.2 第二个任务:团队协作机器人自动应答
如果只有定时任务,还体现不出 7×24 的威力。更自然的用法是把它接入一个团队协作工具的自定义机器人,让群里有人 @ 它时能自动回复。这里的链路是:外部消息通过 webhook 推到本地的一个小 HTTP 服务,服务校验 token 后把消息内容转成一次对话请求,丢给 OpenClaw 生成回复,再按消息来源的地址发回去。
这个环节最容易踩的坑是超时。大模型单次生成可能需要十几秒,而外部 webhook 往往只会等几秒。我的处理方式是先把消息原样接收并存起来,立刻返回一个“收到,处理中”的占位响应,随后在后台异步调用模型,模型返回后再主动把结果推送到对话里。这样用户侧体验是“稍等几秒出回复”,而不是“请求失败”。
安全上,webhook 地址一定不能裸奔。我加了一层简单的 token 校验,只有在 query 参数或者 header 里出现正确 token 的请求才会被接受。这个 token 定期轮换,并且只在内部通讯录里分享。对外暴露的端口也只会映射到这台路由器的内部局域网,不开放远程访问。
4.3 日常维护:怎么看它状态好不好
常驻服务最需要的是“可观测性”。我每天会看一眼几个关键指标:网关日志里最近一次请求是否成功,OpenClaw 有没有异常退出的记录,磁盘剩余空间是否充足。这些东西不用专门搭监控系统,一条命令就能看到。但 7×24 跑了几个月之后我发现,真正决定体验的不是某个单点的状态,而是能不能第一时间发现问题。
所以我给自己写了一个十分钟一次的健康检查任务:尝试请求一次网关的轻量模型接口,如果连续三次失败,就向备用邮箱发一封告警邮件。这里要特别说明,健康检查的拨测请求和真实业务请求要分开记录,否则日志会混在一起,排障时一眼分不清哪个是模拟、哪个是真用户请求。
长跑下来我还有一个习惯:每次修改配置都先复制原文件再改动,并把改动日期写在注释里。遇到行为异常时,回滚成本非常低。别小看这个习惯,它救过我很多次。
5. 常见问题与排查技巧实录
5.1 请求超时、重试与并发控制
我在实际跑的过程中,遇到过最典型的两个问题:超时和限流。超时的原因是模型生成速度受上下文长度影响很大,如果 prompt 很长,单次响应可能超过我个人网关里的 120 秒超时限制。解决办法是分两层设置:第一层在网关把 timeout 调大,第二层在 OpenClaw 里把请求 max_tokens 压低,并控制上下文轮数,防止累积过长的历史。
限流则是上游服务商对请求频率有约束,短时间大量请求会触发 429。我的重试策略是:遇到 429 或 5 开头错误时,按指数退避重试,第一次等 2 秒,第二次等 4 秒,最多重试 4 次。超过次数就放弃,并把错误记录到日志里供事后分析。
并发控制也要刻意做。个人任务虽然频率不高,但多个定时任务可能在同一分钟触发,瞬间会打出多个请求。我在网关层用一个简单的信号量限制最大同时请求数为 2,避免上游被自己打爆,也避免 Mac mini 的小内存扛不住太多并发连接。
5.2 常见的状态码和错误日志到底在说什么
| 状态码 | 含义 | 我的处理方式 |
|---|---|---|
| 401 | 密钥无效或缺失 | 检查环境变量是否注入、密钥是否过期,重新生成并替换 |
| 403 | 权限不足或调用被拒绝 | 检查模型标识是否在当前套餐授权范围内 |
| 429 | 请求太频繁 | 触发指数退避,减少同时请求数或升级限流配置 |
| 500 | 上游服务内部错误 | 记录下来稍后重试,通常属于服务商侧波动 |
| 503 | 上游暂时不可用 | 采用熔断策略,暂停该模型地址一小段时间后自动恢复 |
把状态码映射表贴在网关旁边,出了问题先看表,再查日志,能省掉大量无效排查。我在这一步最大的收获是意识到,错误日志里最需要关注的不是某个状态码本身,而是它出现的频率曲线。如果每天固定时间出现 429,多半是定时任务扎堆;如果随机出现 500,则更可能是上游波动,重试就好,不用过度紧张。
5.3 长跑之后会遇到哪些坑
第一个坑是内存缓慢增长。任何一个常驻进程跑几个月,都可能会出现缓慢的句柄泄漏或缓存累积。OpenClaw 这类框架更明显,因为它会缓存聊天历史和工具调用的结果。我的应对是把框架进程设计成“每天凌晨自动重启一次”,重启损耗只有十几秒,但内存状态会立刻回归干净。launchd 的KeepAlive可以配合ExitTimeOut来做定时重启。
第二个坑是磁盘被日志写满。这个我在前面说过,配置了日志轮转之后基本不会再发生。但如果你用了外接硬盘,还要留意硬盘本身有没有休眠策略,macOS 对内置盘外置盘的处理逻辑不一样,外接盘一旦休眠,第一次读写会有明显卡顿,可能让定时任务误判为超时。
第三个坑是密钥轮换。服务商定期要求重新生成密钥很常见,如果你的密钥保存在多个位置,轮换时容易漏改。我把所有密钥集中在网关的环境变量里统一管理后,这个问题几乎消失了。只要记得修改完网关配置重启一次网关进程就好。
最后一个容易被忽略的问题是模型输出的“退化”。人工智能模型跑同样的 prompt,时间长了输出格式可能细微漂移。我为自己每个自动化任务都加了输出格式校验,比如简报必须包含某些关键字段,如果缺失就重新生成一次。这个策略虽然不能保证 100%,但能把异常结果挡在推送用户之前,避免发生后知后觉的尴尬。
我个人的体会是,这套方案真正让 AI 助手变得可信赖的,不是模型参数选得多强,而是周围那些工程细节:可靠的网关、干净的日志、克制的重试、以及一整套已跑通的排查方法。OpenClaw 这类框架把调度逻辑做得再完善,也替代不了这些基本功。如果你想复现这条路径,我的建议是别急着做出一堆炫酷功能,先花一个下午把“每天一句天气问候”跑通,再逐级加任务。整个体系不是靠某个惊天配置一次搭好的,而是靠每天看五分钟日志,一点点调出来的。