☰
华硕路由器刷Merlin后搭建Go语言AI边缘网关:提示流编排与缓存实战
2026/10/2 10:30:17 网站建设 项目流程

1. 项目缘起与整体架构设计

把 AI 推理能力塞进一台家用路由器,这个想法最早来自一个很现实的痛点:家里所有的智能设备、手机、电脑都在同一个局域网里,每次想让 AI 帮忙处理点东西,都得把数据发到云端,延迟不说,隐私也让人心里不踏实。华硕路由器刷了 Merlin 固件之后,本身就是一个带 USB 接口、能跑 Entware 的 Linux 小主机,CPU 虽然不算强,但跑一些轻量级的提示词编排、请求路由、缓存转发这类活儿,绰绰有余。这个项目的核心目标,就是在这台路由器上搭一个轻量边缘网关,让它承担 AI 请求的预处理、提示词模板管理、多引擎路由分发和结果缓存,把“AI 引擎”真正下沉到网络边缘。

先把这个项目的定位说清楚。它不是要你在路由器上跑大模型——那不现实,路由器那点内存和算力扛不住。它要做的是提示流编排:你从局域网里任何一台设备发出请求,路由器上的网关负责把请求拆解、套用预设的提示词模板、选择合适的后端 AI 服务、把结果拿回来做后处理再返回。整个过程对上层设备透明,你该用啥用啥,只是背后多了一层智能调度。这套东西适合谁?适合手里有华硕路由器、刷了 Merlin、喜欢折腾边缘计算、又想把 AI 能力私有化落地的朋友。如果你只是想调个 API,那没必要上这套;但如果你想让家里所有设备共享一套统一的 AI 入口,并且能灵活切换后端、管理提示词、做本地缓存,那这个方案就很对味。

技术选型上,我最终选了Go 语言来写这个网关。原因有几个:第一,Go 编译出来是静态二进制,扔到路由器上直接跑,不依赖一堆运行时库,Entware 环境里省心;第二,Go 的并发模型处理这种“接收请求—分发—聚合”的 IO 密集型场景非常顺手,goroutine 开起来成本低;第三,交叉编译方便,我在电脑上编译好 arm 架构的二进制,scp 到路由器就能用。整个网关的架构分四层:接入层负责监听局域网请求,编排层负责提示词模板匹配和参数注入,路由层负责选择后端引擎,缓存层负责结果复用。这四层在代码里是解耦的,每一层都可以单独替换或扩展。

为什么要在路由器上做缓存?因为很多 AI 请求其实是重复的,比如你每天问“今天天气怎么样”这种,提示词一样,结果短时间内也一样。路由器内存有限,我用的是基于 LRU 的本地缓存,配合 TTL 过期,把热点请求的结果存下来,命中就直接返回,省掉一次后端调用。这个设计在实测中能把重复请求的响应时间从秒级降到毫秒级,效果很明显。编排层的提示词模板我用的是简单的占位符替换加条件分支,没有上太复杂的 DSL,因为路由器上跑的东西,越简单越稳。模板存在路由器的一个配置文件里,改完 reload 一下就行,不用重新编译。

2. Merlin 插件环境准备与 Go 交叉编译实战

2.1 路由器端环境摸底与 Entware 安装

动手之前,先确认你的路由器型号和 Merlin 版本。不是所有华硕路由器都支持 Merlin,也不是所有支持 Merlin 的型号都能舒服地跑 Entware。我手头这台是 RT-AX88U,ARMv8 架构,512MB 内存,刷的是 Merlin 386 之后的版本。你可以在路由器管理页面的“系统信息”里看到具体的固件版本和 CPU 架构。确认支持之后,第一步是开启 JFFS 分区和 SSH。JFFS 是 Merlin 提供的可写分区,用来放自定义脚本和插件,默认可能是关闭的,在“系统管理—系统设置”里把“启用 JFFS 分区”打开,然后重启。

SSH 进去之后,先看看 /jffs 挂载了没有,df -h看一眼空间。一般 JFFS 有几十 MB,够放 Entware 和我们的网关二进制。接下来装 Entware,这是 Merlin 上跑第三方软件的标准方式。安装命令很简单,但要注意选对架构的安装脚本。ARMv8 的机器用entware-setup.sh就行,脚本会自动下载对应架构的包管理器。装完之后,/opt目录就挂上了,opkg命令可用。这时候先opkg update更新一下软件源,然后装几个基础依赖:opkg install ca-bundle ca-certificates,这两个是后面网关调 HTTPS 后端必须的证书包,不装的话 TLS 握手会失败。

注意:Entware 装在 U 盘上比装在 JFFS 里更稳妥,因为 JFFS 空间有限,而且频繁写入对闪存寿命有影响。我建议插一个质量好点的 U 盘,格式化成 ext4,挂载到 /opt。Merlin 的 entware-setup.sh 会引导你选择安装位置,选 U 盘对应的分区就行。

2.2 Go 交叉编译环境搭建与二进制瘦身

路由器上直接装 Go 工具链不现实,空间和性能都不允许。正确做法是在你的开发机上交叉编译。我的开发机是 Linux,装了 Go 1.21。交叉编译到 ARMv8 的命令是:

GOOS=linux GOARCH=arm64 CGO_ENABLED=0 go build -ldflags="-s -w" -o ai-gateway-arm64 .

这里有几个关键点。CGO_ENABLED=0是必须的,因为路由器上没有 glibc 开发环境,纯静态编译才能保证二进制在 Entware 环境下直接跑。-ldflags="-s -w"是去掉符号表和调试信息,能把二进制体积压下来不少。我实测一个功能完整的网关,编译出来大概 8MB 左右,压一压能到 6MB 出头。如果你的路由器是 ARMv7(比如一些老型号),把GOARCH换成arm,再加GOARM=7。

编译好之后,用 scp 传到路由器的 /jffs 或者 U 盘目录下:

scp ai-gateway-arm64 admin@192.168.50.1:/jffs/ai-gateway/

传上去之后chmod +x给执行权限。这时候先别急着跑,用./ai-gateway-arm64 --version试一下能不能执行。如果报“not found”或者“cannot execute binary file”,多半是架构不对或者动态链接的问题,回去检查GOARCH和CGO_ENABLED。能打印版本号,说明二进制没问题,环境准备这步就算过了。

2.3 开机自启与进程守护配置

路由器重启之后,Entware 环境和我们的网关都得自动起来。Merlin 的自启脚本放在/jffs/scripts/目录下,主要用services-start和post-mount这两个钩子。post-mount在 U 盘挂载后触发,适合启动依赖 U 盘上 Entware 的服务。我在post-mount里加了一段:

#!/bin/sh if [ -x /opt/bin/ai-gateway ]; then /opt/bin/ai-gateway -config /opt/etc/ai-gateway/config.yaml >> /opt/var/log/ai-gateway.log 2>&1 & fi

这里把网关放在/opt/bin/下,配置和日志分别放/opt/etc/和/opt/var/log/。注意post-mount脚本本身要有执行权限,而且 Merlin 对脚本的换行符敏感,必须用 LF,不能有 CRLF,否则会报奇怪的错误。进程守护方面,我没上 systemd(Entware 里也没有),而是用了一个简单的 shell 循环加crontab检查。每 5 分钟检查一次进程在不在,不在就拉起来:

*/5 * * * * pgrep -f ai-gateway > /dev/null || /opt/bin/ai-gateway -config /opt/etc/ai-gateway/config.yaml >> /opt/var/log/ai-gateway.log 2>&1 &

这个方案土是土了点,但在路由器上足够稳。实测跑了几周,没出现过进程莫名挂掉的情况。如果你追求更优雅的方案,可以看看 Entware 里的monit,但那个配置起来更重,路由器上没必要。

3. 轻量边缘网关核心模块拆解与实现

3.1 请求接入层:HTTP 服务与局域网发现

网关的接入层就是一个标准的 HTTP 服务器,监听路由器的局域网 IP 和一个自定义端口,比如 8787。为什么用 HTTP 而不是 HTTPS?因为在局域网内部,TLS 的额外开销和证书管理成本不划算,而且路由器上跑 TLS 握手会占用宝贵的 CPU。局域网内的流量本身就在你的控制范围内,安全性由网络边界保证。当然,如果你的局域网里有不可信设备,那还是建议上 HTTPS,Go 标准库的net/http加个自签证书也不麻烦。

接入层收到请求后,先做一轮基础校验:请求方法是不是 POST,body 是不是合法的 JSON,有没有超过大小限制。我设的限制是 1MB,因为提示词再长也长不到哪去,超过这个大小多半是异常请求。校验通过后,把请求交给编排层。这里有个细节:路由器的 CPU 弱,如果同时来几十个请求,goroutine 虽然能扛,但后端 AI 服务的并发限制可能先扛不住。所以我在接入层加了一个简单的令牌桶限流,默认每秒放行 10 个请求,桶容量 20。这个参数可以在配置文件里调,根据你后端服务的承受能力来定。

局域网发现这块,我做了个简单的 mDNS 广播,让局域网里的设备能自动发现这个网关。不过实测下来,大部分场景下你直接记住 IP 和端口就行,mDNS 更多是锦上添花。如果你想让手机上的快捷指令或者电脑上的脚本自动找到网关,那 mDNS 有点用。实现上用的是hashicorp/mdns这个库,注册一个_ai-gateway._tcp服务,广播路由器的 IP 和端口。

3.2 提示词编排层:模板引擎与参数注入

编排层是整个网关的灵魂。它的工作是把用户发来的原始请求,套用预设的提示词模板,生成最终发给 AI 引擎的完整提示词。模板我用的是 Go 标准库的text/template,没引入第三方模板引擎,因为标准库够用,而且没有额外依赖。模板文件放在配置目录下的templates/文件夹里,每个模板一个.tmpl文件,文件名就是模板 ID。比如translate.tmpl的内容可能是:

请将以下{{.SourceLang}}文本翻译成{{.TargetLang}},只输出翻译结果,不要解释: {{.Text}}

用户请求里带上template: "translate"和对应的参数,编排层就找到这个模板,把参数注入进去,生成最终提示词。这里有个关键设计:参数白名单。不是所有参数都能往模板里塞,我在配置里定义了每个模板允许的参数列表,防止用户注入奇怪的东西。比如translate模板只允许SourceLang、TargetLang、Text三个参数,多出来的直接忽略。

模板还支持条件分支和默认值。比如有些模板里会根据参数决定要不要加一段系统提示:

{{if .Formal}}请使用正式、专业的语气回答。{{else}}请使用轻松、口语化的语气回答。{{end}}

这种逻辑用text/template写起来很自然。编排层还负责提示词版本管理,每个模板文件可以带一个版本号注释,网关启动时加载所有模板并记录版本。如果模板更新了,reload 一下就能生效,不用重启整个网关。这个设计在迭代提示词的时候特别方便,你改完模板文件,发个 SIGHUP 信号给网关进程,它就重新加载模板,正在处理的请求不受影响。

3.3 多引擎路由层:后端选择与故障转移

路由层决定一个编排好的请求发给哪个 AI 后端。我在配置里定义了多个后端,每个后端有名称、类型、地址、API Key、超时时间、权重等属性。路由策略支持三种:按模板指定、按权重轮询、按优先级故障转移。按模板指定最简单,模板配置里写死用哪个后端;按权重轮询适合多个同质后端做负载均衡;按优先级故障转移适合主备场景,主后端挂了自动切备后端。

故障转移的实现逻辑是这样的:路由层按优先级顺序尝试后端,如果某个后端返回连接错误、超时或者 5xx,就标记为“不健康”,在接下来的一段时间内(比如 30 秒)跳过它,直接试下一个。如果所有后端都失败,返回一个统一的错误响应。这个“不健康”标记是有自动恢复的,30 秒后重新尝试,如果成功了就恢复健康状态。实测这个机制在某个后端临时抽风的时候很有用,用户基本无感知。

后端调用的超时设置很关键。路由器到公网 AI 服务的延迟本身就不低,如果超时设太短,正常请求也会被误判为失败;设太长,用户等得着急。我的经验值是:连接超时 5 秒,整体请求超时 30 秒。对于流式响应,超时逻辑要单独处理,因为流式响应是持续返回的,不能用整体超时来判断。流式场景下我用的是“空闲超时”,即如果超过 10 秒没有收到新的数据块,就认为连接断了。

3.4 结果缓存层:LRU 与 TTL 的工程取舍

缓存层的设计目标很明确:减少重复请求对后端的压力,同时控制内存占用。路由器内存有限,我这台 512MB,系统本身和 Entware 占掉一部分,留给网关的预算大概 100MB 左右。缓存不能无限增长,所以用了 LRU(最近最少使用)淘汰策略,配合 TTL(生存时间)过期。缓存 key 的生成方式是:对最终发给后端的完整提示词做 SHA256 哈希,再加上后端名称。这样同一个提示词发给不同后端,缓存是分开的,避免串味。

TTL 的设置要看场景。翻译、改写这类请求,结果相对稳定,TTL 可以设长一点,比如 1 小时;问答、生成类请求,结果可能有时效性,TTL 设短一点,比如 5 分钟。我在配置里给每个模板单独设 TTL,默认 10 分钟。缓存容量上限设的是 500 条,每条平均 2KB 左右,总共占 1MB 内存,对路由器来说毫无压力。实测下来,缓存命中率在典型使用场景下能到 30% 到 40%,效果还是不错的。

注意:缓存只对非流式请求生效。流式请求的结果是逐步返回的,缓存起来复杂且收益低,所以直接跳过缓存层。另外,带用户特定信息的请求(比如包含个人数据的提示词)不建议缓存,这个在模板配置里可以标记cache: false来关闭。

4. 实操部署全流程与关键配置详解

4.1 配置文件结构与参数说明

网关的配置文件用的是 YAML 格式,放在/opt/etc/ai-gateway/config.yaml。整个配置分四大块:server、templates、backends、cache。server块定义监听地址、端口、限流参数、日志级别。templates块定义模板目录和每个模板的元信息。backends块定义后端列表。cache块定义缓存容量和默认 TTL。下面是一个精简的配置示例:

server: listen: "0.0.0.0:8787" rate_limit: 10 burst: 20 log_level: "info" templates: dir: "/opt/etc/ai-gateway/templates" items: - id: "translate" backend: "primary" cache: true ttl: 3600 - id: "chat" backend: "auto" cache: false backends: - name: "primary" type: "openai-compatible" endpoint: "https://api.example.com/v1/chat/completions" api_key: "sk-xxxx" timeout: 30 weight: 10 - name: "backup" type: "openai-compatible" endpoint: "https://api.backup.com/v1/chat/completions" api_key: "sk-yyyy" timeout: 30 weight: 1 cache: max_items: 500 default_ttl: 600

这里backend: "auto"表示走路由层的自动策略,按权重轮询。api_key我建议不要直接写在配置文件里,而是用环境变量引用,比如api_key: "${PRIMARY_KEY}",网关启动时从环境变量读取。这样配置文件可以安全地备份和分享,不怕泄露密钥。

4.2 提示词模板编写与调试技巧

模板编写看起来简单,但实际用起来有不少门道。第一个技巧是模板要短。路由器上处理模板的开销虽然不大,但模板越长,生成的提示词越长,后端处理的 token 消耗也越多。我见过有人把整个系统提示词塞进模板,几百行,结果每次请求都发一大堆无关内容,既慢又贵。正确的做法是把模板拆细,每个模板只做一件事,需要组合的时候在请求里指定多个模板,编排层按顺序拼接。

第二个技巧是用注释做版本标记。text/template的注释语法是{{/* ... */}},我在每个模板文件开头写一行版本注释,比如{{/* v3 2024-06-01 调整了翻译语气 */}}。网关加载模板时会解析这个注释,记录版本号。这样你排查问题的时候,一眼就能看出当前用的是哪个版本的模板。

第三个技巧是本地调试。在路由器上直接调试模板很麻烦,我一般是在开发机上写一个小工具,加载模板文件,传入测试参数,看生成的提示词对不对。这个工具很简单,几十行代码,但能省掉大量来回 scp 的时间。调试通过之后再传到路由器上。

4.3 后端接入与密钥安全管理

后端接入这块,我踩过最大的坑是证书问题。Entware 环境里默认没有完整的 CA 证书链,调 HTTPS 后端的时候会报x509: certificate signed by unknown authority。解决办法就是前面说的,装ca-bundle和ca-certificates,然后在 Go 代码里显式指定证书路径,或者用SSL_CERT_FILE环境变量指向/opt/etc/ssl/certs/ca-certificates.crt。这个坑不踩一次很难想到,因为开发机上证书都是全的,交叉编译出来的二进制在路由器上跑就出问题。

密钥管理方面,我强烈建议用环境变量而不是明文写在配置文件里。Merlin 的启动脚本里可以export环境变量,或者用一个单独的.env文件,权限设成 600,只有 root 能读。网关启动时从环境变量读取密钥,配置文件里只留占位符。这样即使配置文件被误传到网上,密钥也不会泄露。另外,定期轮换密钥也是个好习惯,虽然路由器上的服务不像公网服务那样暴露,但谨慎点总没错。

4.4 性能压测与资源占用观察

部署完成之后,我做了几轮压测,看看路由器能不能扛住。压测工具用的是wrk,在局域网内的另一台电脑上跑,对网关发请求。测试场景是 10 个并发连接,持续 60 秒,请求的是缓存命中的翻译模板。结果 QPS 稳定在 800 左右,CPU 占用峰值 40%,内存占用稳定在 15MB 左右。这个成绩对于路由器来说相当不错了,说明 Go 的并发模型和 LRU 缓存在这个场景下效率很高。

如果不走缓存,直接转发到后端,QPS 就取决于后端响应速度了,网关本身的处理开销可以忽略不计。我观察了一下,网关处理一个请求(不含后端调用)的平均耗时在 2 毫秒左右,其中模板渲染占大头。内存方面,跑了一周之后,RSS 稳定在 18MB 到 22MB 之间,没有明显的内存泄漏。CPU 平时空闲时占用不到 1%,有请求的时候才会上去。整体来说,这个网关对路由器资源的占用完全在可接受范围内,不影响路由器本身的路由和 WiFi 功能。

5. 常见问题排查与避坑经验实录

5.1 二进制无法执行与依赖缺失排查

最常见的问题就是二进制传上去跑不起来。表现有好几种:not found、Permission denied、cannot execute binary file。not found通常是动态链接器找不到,说明CGO_ENABLED没设成 0,编译出来的二进制依赖了开发机上的 glibc。Permission denied是忘了chmod +x。cannot execute binary file是架构不对,比如把 x86 的二进制传到了 ARM 路由器上。排查方法很简单:file ai-gateway-arm64看一下文件类型,ldd ai-gateway-arm64看一下动态依赖(静态编译的话会显示 "not a dynamic executable")。

还有一个隐蔽的问题:Entware 的/opt/bin目录下的二进制,有时候会因为 U 盘挂载顺序问题导致启动时找不到。这个的解决办法是在启动脚本里加一个等待循环,确认/opt/bin可用了再启动网关。我一般等 5 秒,或者循环检查/opt/bin/opkg是否存在,存在了再继续。

5.2 后端连接超时与 TLS 握手失败

后端连不上的问题,排查顺序是这样的:先用curl在路由器上直接测后端地址,看能不能通。如果curl也超时,那是网络问题,检查路由器的 DNS 和出站规则。如果curl能通但网关报错,那多半是证书问题或者 API Key 问题。证书问题前面说了,装 CA 包。API Key 问题看日志,一般会返回 401 或 403,日志里会有明确提示。

TLS 握手失败还有一种可能是系统时间不对。路由器重启后如果 NTP 没同步上,系统时间可能是 1970 年,导致证书校验失败。这个问题的表现是x509: certificate has expired or is not yet valid。解决办法是确保路由器的 NTP 服务正常,或者在启动脚本里加一个ntpd -q -p pool.ntp.org强制同步一次时间。这个坑很隐蔽,因为平时你不会想到时间会影响 TLS。

5.3 缓存命中率低与内存增长异常

缓存命中率低,先看 key 的生成逻辑。如果提示词里包含了时间戳、随机数、用户 ID 这类每次都变的内容,那缓存永远命中不了。解决办法是把这些变量从缓存 key 的计算中排除,或者在模板设计上避免把易变内容放进提示词。另一个原因是 TTL 设太短,请求还没重复就过期了。可以适当调长 TTL,观察命中率变化。

内存增长异常,一般是缓存没有正确淘汰。检查 LRU 的实现,确认max_items生效了。还有一种可能是 goroutine 泄漏,比如每个请求开了一个 goroutine 但没正确退出。Go 的pprof工具可以帮忙排查,在网关上开一个 debug 端口,用go tool pprof抓一下堆和 goroutine 的快照,一目了然。我一般会在开发阶段就开 pprof,上线后关掉,需要的时候再临时开。

5.4 常见问题速查表

问题现象可能原因排查方法解决方案
二进制无法执行架构不对/动态链接file、ldd检查重新交叉编译,CGO_ENABLED=0
TLS 握手失败CA 证书缺失/时间不对curl测试、检查系统时间装 CA 包、同步 NTP
后端 401/403API Key 错误看网关日志检查环境变量和密钥配置
缓存命中率低key 含易变内容/TTL 太短打印缓存 key、观察 TTL调整 key 生成逻辑、调长 TTL
内存持续增长缓存未淘汰/goroutine 泄漏pprof 抓快照检查 LRU 配置、修复泄漏
启动时找不到二进制U 盘挂载顺序检查/opt/bin是否存在启动脚本加等待循环

这张表是我在实际运维中慢慢攒出来的,基本上覆盖了 90% 以上的常见问题。遇到新问题的时候,先往这张表上靠,能省不少排查时间。

6. 提示流编排的进阶玩法与扩展思路

6.1 多模板串联与条件路由

基础用法是一个请求对应一个模板,但实际场景里经常需要多模板串联。比如一个“总结并翻译”的请求,先走总结模板,把长文压缩成摘要,再走翻译模板,把摘要翻译成目标语言。这个在网关里可以通过在请求里指定模板链来实现:templates: ["summarize", "translate"],编排层按顺序执行,前一个模板的输出作为后一个模板的输入。这个设计让网关的灵活性上了一个台阶,你可以把复杂的处理流程拆成多个小模板,按需组合。

条件路由是另一个进阶玩法。根据请求内容或者参数,动态选择不同的后端或模板。比如检测到请求里包含代码,就路由到擅长代码的模型;检测到是中文,就路由到中文优化过的后端。这个逻辑我是在编排层加了一个简单的规则引擎,用正则匹配请求内容,命中规则就走对应的路由。规则配置也是 YAML 格式,改起来方便。

6.2 本地小模型与云端大模型的混合调度

路由器上跑不了大模型,但跑一个小的嵌入模型或者分类模型是可行的。比如用一个轻量级的文本分类模型,在本地判断请求的意图,然后决定路由到哪个云端大模型。这样能省掉一次云端调用,降低延迟和成本。本地模型我用的是 ONNX Runtime 的 Go 绑定,模型文件放在 U 盘上,加载到内存里。实测一个几 MB 的分类模型,在路由器上推理一次大概几十毫秒,完全可以接受。

混合调度的策略是:简单请求(比如分类、关键词提取)走本地小模型,复杂请求(比如生成、推理)走云端大模型。这个分界线可以根据实际效果调整。本地模型的好处是零延迟、零成本、数据不出局域网;云端大模型的好处是能力强、知识广。两者结合,既保证了响应速度,又保证了处理质量。

6.3 日志审计与请求追踪

网关作为所有 AI 请求的入口,天然适合做日志审计。我在网关里加了一个请求日志模块,记录每个请求的时间、来源 IP、模板 ID、后端名称、耗时、缓存命中情况、token 消耗(如果后端返回的话)。这些日志写到/opt/var/log/ai-gateway.log,按天切割,保留 7 天。日志格式是 JSON Lines,方便后续用脚本分析。

请求追踪方面,我给每个请求生成了一个唯一的 trace ID,放在响应头里返回给客户端。这样如果用户反馈某个请求有问题,你可以拿 trace ID 去日志里搜,快速定位到具体的请求和处理过程。这个功能在排查偶发问题时特别有用,因为路由器上的服务不像开发环境那样可以随时打断点,只能靠日志回溯。

6.4 安全加固与访问控制

局域网虽然相对安全,但基本的访问控制还是要做。我在网关上加了 IP 白名单,只有配置里列出的 IP 段才能访问。默认只允许局域网网段,比如192.168.50.0/24。如果路由器有公网暴露的风险,那更要严格限制。另外,网关的 API 加了一个简单的 Bearer Token 认证,客户端请求时带上Authorization: Bearer <token>,token 在配置里设置。这个认证不是为了防黑客,而是防止局域网里的误操作或者恶意设备乱调。

还有一点是请求体大小限制和超时控制。前面提过 1MB 的限制,这个能防止大请求把路由器内存打满。超时控制除了后端调用超时,还有客户端连接超时,防止慢速攻击。Go 的http.Server有ReadTimeout和WriteTimeout配置,我设的是 10 秒和 60 秒。这些参数看起来不起眼,但在资源受限的设备上,是保证服务稳定的关键。

7. 实际运行数据与个人经验体会

这套网关在我家路由器上跑了大概三个月,日均处理请求 200 到 300 次,主要是家里几台设备上的翻译、总结、问答类调用。缓存命中率稳定在 35% 左右,后端调用的平均延迟从原来的 1.2 秒降到了 800 毫秒(缓存命中时是 5 毫秒以内)。路由器本身的 CPU 和内存占用没有明显变化,WiFi 和路由功能一切正常。最让我满意的是,所有设备的 AI 请求都统一走了这个网关,提示词管理、后端切换、日志审计都在一个地方搞定,省心很多。

踩过的坑里,印象最深的是证书问题和时间同步问题。这两个问题在开发环境里根本不会遇到,但在路由器这种精简系统上就是拦路虎。解决之后回头看,其实都很简单,但第一次遇到的时候确实折腾了不少时间。所以我在文章里反复强调这两个点,希望后来的人能少走弯路。

如果让我给想动手的朋友一个建议,那就是先把最小可用版本跑起来。不要一上来就搞多模板、多后端、本地模型这些高级功能。先写一个最简单的网关,能接收请求、转发到单个后端、返回结果,跑通了再逐步加功能。这样每一步都有正反馈,遇到问题也容易定位。我见过不少人一上来就搭复杂架构,结果卡在某个环境问题上就放弃了,很可惜。

这个项目后续还可以往几个方向扩展。一个是支持更多后端类型,比如本地部署的推理服务、其他云厂商的 API,只要接口兼容 OpenAI 格式,接入都很简单。另一个是提示词版本管理和 A/B 测试,让不同版本的模板同时在线,按比例分流,对比效果。还有一个是和家庭自动化系统集成,让 AI 网关成为智能家居的“大脑”,处理语音指令、场景联动这些。这些扩展我在后续的文章里会陆续展开,感兴趣的朋友可以持续关注。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询