ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

把 AI Agent 托管到家里电脑:UU远程端口映射与CLI实测记录

把 AI Agent 托管到家里电脑:UU远程端口映射与CLI实测记录 起因Agent 跑在本地人却不在本地我手上这套 Agent 不复杂就是一个用 LangGraph 串起来的小流程接收任务 → 调用本地 Ollama 做推理 → 需要检索时走一次向量库 → 返回结构化结果。模型是本地跑的数据不出机器这也是我一开始选择把它放在家里那台旧主机上的原因。问题出在使用方式上。这套东西平时我在家直接python main.py起一个 FastAPI 服务浏览器或者 curl 调一下就行。但一旦出差事情就变得别扭家里宽带是动态 IP没有固定公网地址路由器上也没开端口转发公司网络对出站端口管得比较严很多非常规端口直接连不上Agent 不是跑一次就完向量库要常驻会话状态要保留不能每次远程登录重新拉起。所以我的目标很明确让家里的那台机器变成一个可以随时从外面连进去、并且能把本地 Agent 的接口暴露出来的常驻节点。工具我选了 UU 远程主要原因是它同时提供了远程终端CLI和端口映射这两块能力不用我再单独折腾一套内网穿透。需要先说明一点UU 远程本身是商业软件它的具体功能、免费额度、端口映射的并发数和带宽限制会随版本和政策变化。我下面写的是我这次实际用到的部分具体套餐和限制请以你安装时的官方说明为准我没有去逐条核对它的计费规则。先把远程终端打通第一步不是端口映射而是先能稳定登进那台机器。端口映射是建立在你能操作远端主机的前提上的顺序反了会很难排查。我在家里主机上装了 UU 远程的客户端登录同一个账号然后在设置里开启 SSH 相关的远程终端能力。这里有个细节值得说不同版本的 UU 远程对远程终端的入口叫法不完全一样有的是在设备列表里点进去直接开一个终端窗口有的是给一个本地端口让你用系统自带的 ssh 连。我这次用的是后者它会在本地起一个转发端口我再用 ssh 连过去。假设本地转发出来的端口是2222这个端口号以你软件里实际显示为准不要照抄我的连接命令大概长这样ssh-p2222your_user127.0.0.1这里your_user是家里主机上的系统用户名。第一次连会提示确认指纹正常接受即可。连上之后我做的第一件事是确认环境还在# 确认 Python 和虚拟环境python3--versionsource~/agent-env/bin/activate pip list|grep-Efastapi|langgraph|ollama这一步看着多余其实很关键。远程终端和本地终端最大的区别是环境变量、工作目录、shell 初始化文件不一定一致。我遇到过远程进去python3是系统自带的 3.10而 Agent 依赖装在 conda 环境里的情况。所以每次远程进来先确认自己在哪个 Python 上比后面报错再回头查要省事。CLI 会话保活别让 Agent 跟着 SSH 一起断这是我实际踩到的一个点。最开始我用最朴素的方式ssh 进去直接python main.py前台跑。结果只要网络抖一下、连接断一次进程就跟着没了向量库重新加载会话状态全丢。解决办法是让进程脱离终端会话。有两种常见做法我都试了方式一tmux# 远程登进去之后tmux new-sagentsource~/agent-env/bin/activate python main.py# 按 CtrlB 然后按 D 脱离下次进来tmux attach -t agent就能回到原来的会话进程一直在跑。tmux 的好处是你还能看到实时输出调试阶段很舒服。方式二systemd 用户服务如果 Agent 已经稳定我更推荐把它做成服务开机自启崩了自动重启。写一个用户级 unit 文件~/.config/systemd/user/agent.service[Unit] DescriptionLocal AI Agent Service Afternetwork.target [Service] Typesimple WorkingDirectory/home/your_user/agent ExecStart/home/your_user/agent-env/bin/python main.py Restarton-failure RestartSec5 [Install] WantedBydefault.target然后systemctl--userdaemon-reload systemctl--userenable--nowagent.service systemctl--userstatus agent.service【踩坑提醒】用户级 systemd 服务默认在用户完全登出后可能被回收需要开 lingeringsudologinctl enable-linger your_user这条命令我一开始漏了表现为ssh 断开后服务还在但过一阵子就没了查日志才反应过来。这是我这次真正花时间的地方不是网络问题是服务生命周期问题。端口映射把 Agent 的 HTTP 接口暴露出来Agent 跑起来了但它监听的127.0.0.1:8000只有本机能访问。我在外面就算连进远程终端也只能用 curl 在本机调没法从我的笔记本直接请求。这时候需要端口映射。UU 远程的端口映射我的理解是它在本地开一个监听端口把流量转发到远端主机的指定端口。配置时填两个东西——远端主机的端口比如 Agent 的 8000和本地映射出来的端口。假设本地映射到18000那么我在笔记本上就能这样请求curlhttp://127.0.0.1:18000/health如果 Agent 服务正常会返回类似{status:ok,model:loaded}这里有几个必须注意的点我逐个说第一Agent 服务要监听对地址。如果 FastAPI 里写的是uvicorn.run(app, host127.0.0.1, port8000)那从映射进来的流量可能到不了。稳妥起见改成监听所有网卡# main.pyimportuvicornfromfastapiimportFastAPI appFastAPI()app.get(/health)defhealth():return{status:ok,model:loaded}if__name____main__:uvicorn.run(app,host0.0.0.0,port8000)host0.0.0.0意味着监听所有网络接口。这在纯内网无所谓但既然要映射出去就得考虑暴露面后面我会讲怎么加一层保护。第二端口映射不等于公网开放。我这次的用法是映射到本地回环只有我这台笔记本能通过本地端口访问不是把 8000 端口挂到公网上让谁都能扫。如果你把映射配成对公网开放那 Agent 就等于裸奔了这一点务必确认清楚你软件里的实际行为我没有去验证 UU 远程在公网暴露方面的默认策略。第三映射的稳定性和带宽。端口映射走的是中继延迟和带宽都会比直连差。我这边做的是文本类 Agent 调用请求和响应都是几百 KB 级别体感可以接受。但如果你要传大文件或者做流式视频这个方案不一定合适具体带宽上限我没测出准确数字只能说文本场景够用。网络代理绕开出站限制到这一步从我的笔记本能访问家里的 Agent 了。但还有一层家里的那台主机自己需要访问外网。比如 Agent 要调用某个云端模型的 API或者拉取依赖、更新向量库。我这次遇到的情况是家里主机所在网络对某些出站请求有限制。解决办法是在主机上配置代理。这里我要强调代理配置是环境相关的我下面给的是通用写法具体地址和端口要换成你自己的。Python 层面requests和httpx都会读环境变量exportHTTP_PROXYhttp://127.0.0.1:7890exportHTTPS_PROXYhttp://127.0.0.1:7890exportNO_PROXY127.0.0.1,localhostNO_PROXY那行别漏否则 Agent 自己访问本地向量库或者本地 Ollama 的请求也会被塞进代理轻则变慢重则直接失败。我就吃过这个亏Agent 调本地 Ollama 一直超时查了半天才发现是代理把127.0.0.1:11434也代理走了。如果是 systemd 服务环境变量要写在 unit 文件里光在 shell 里 export 是没用的[Service] EnvironmentHTTP_PROXYhttp://127.0.0.1:7890 EnvironmentHTTPS_PROXYhttp://127.0.0.1:7890 EnvironmentNO_PROXY127.0.0.1,localhost改完systemctl --user daemon-reload systemctl --user restart agent.service。这里有个取舍要讲清楚代理和端口映射是两回事方向相反。端口映射是让外面能进来代理是让里面能出去。很多人会把这两个混在一起配置的时候方向搞反然后怎么都不通。记住进来的流量看映射出去的流量看代理。加一层访问保护把 Agent 接口映射出来之后我加了一个简单的鉴权不是因为这次映射到公网而是习惯问题——万一哪天配置改了至少不至于完全敞开。最轻量的做法是在 FastAPI 里加一个依赖fromfastapiimportFastAPI,Header,HTTPException appFastAPI()API_TOKENyour-secret-token# 实际使用请从环境变量读取defcheck_token(authorization:strHeader(None)):ifauthorization!fBearer{API_TOKEN}:raiseHTTPException(status_code401,detailunauthorized)app.get(/health,dependencies[Depends(check_token)])defhealth():return{status:ok}【注意】上面API_TOKEN直接写在代码里只是示意真实使用一定要从环境变量读别提交到仓库importos API_TOKENos.environ[AGENT_API_TOKEN]然后在 systemd 的 unit 里用EnvironmentAGENT_API_TOKENxxx注入。整体链路和我最终的运行方式把上面几步串起来我现在的完整链路是这样家里主机开机UU 远程客户端自启agent.service用户服务自启Agent 监听0.0.0.0:8000代理环境变量通过 unit 注入Agent 出站走代理NO_PROXY放行本地我在外面用 UU 远程的端口映射把远端 8000 映射到本地 18000笔记本上带 token 请求http://127.0.0.1:18000拿到 Agent 结果。日常运维我留了 tmux 会话需要看实时日志时 attach 进去不用停服务。环节我用的方案解决的问题远程登录UU 远程终端 ssh无公网 IP 也能进主机进程保活systemd 用户服务断连不掉、崩溃自启接口暴露UU 远程端口映射从外网访问 Agent HTTP出站访问环境变量代理 NO_PROXY绕开出站限制、放行本地访问控制FastAPI token 鉴权防止接口裸奔哪些地方我没验证清楚写技术文章最怕把不确定的东西说成确定的所以这里我明确标出来UU 远程端口映射的具体并发数、带宽上限、免费额度我没有逐项测试只说文本场景可用它的公网暴露默认策略我没有验证所以反复强调要自己确认不同版本 UU 远程的远程终端入口和端口号显示方式可能有差异我的命令里的端口号都是示意代理部分的具体地址、端口完全是环境相关我给的是通用的环境变量写法不是某个特定服务的配置。另外这套方案本质上是用商业软件做内网穿透。如果你对数据链路有更严格的要求或者不想依赖第三方中继可以考虑自建 WireGuard、Tailscale 这类方案但那需要另一套配置不在这次实践范围内。我选 UU 远程纯粹是因为它把终端和映射做在一起省事。写在最后这次折腾下来最耗时间的不是端口映射也不是代理而是服务生命周期那一段——tmux 和 systemd 的选择、lingering 的坑、环境变量在服务里不生效。这些跟AI Agent本身没关系但恰恰是把 Agent 托管到家里这件事上最容易被忽略的部分。如果你的 Agent 只是偶尔跑一次那 ssh 进去手动启动就够了没必要上 systemd。但如果你希望它像一个小服务一样常驻随时能调那进程管理和环境隔离这两件事值得先花时间做对。至于穿透工具选哪个反而不是最关键的能稳定连上、能映射端口剩下的都是配置问题。
返回列表