记录一次将 Agent 部署到云服务的心路历程
我这次要搬到云上的是一个已经在本地做了定制的 Agent:基于 DeepSeek Harness,自己写了 dsh 插件,接入项目自己的业务数据,加上专门的查询工具、首页图表和交互。
准备让团队里的几个人试用,所以我想把这套定制好的功能放到轻量服务器上,给大家一个网址,打开就能用。
这次用了 OrcaTerm 自带的 Agent 和 Claude Code。先在 OrcaTerm 里连上服务器,再把项目的部署文档交给 Claude Code,让它通过远程工具把代码、数据和配置逐步安排好。报错了,它能接着看终端输出、找文件、改命令、重新验证,我不用在几个窗口之间来回复制日志。
下面主要聊这部分:自研插件怎么跟着 Harness 一起上线,到了服务器上有哪些容易漏的地方,以及 OrcaTerm 帮我省了哪些手工操作。
先说清楚,我们在 Harness 上定制了什么
我做的是一个数据分析 Agent。用户可以查询业务指标、比较不同对象,也可以要求整理一份分析报告。
其中,业务插件负责指标查询工具、固定数据的读取,以及领域相关的界面和提示;会话、模型调用、文件交付这些能力继续复用 Harness。比如首页展示哪些指标、给用户什么示例问题、查到的数据怎样显示,都是围绕这个项目做的调整。
所以,服务器上要准备的东西除了 Harness,还有插件源码和构建产物、指标数据快照,以及启用这套插件的 profile。以后我改了查询逻辑或首页交互,还得能把新版本更新上去,保留大家已经产生的会话和报告。
这次实际用的是一台 2 核 2GB 的 Ubuntu 26.04 轻量服务器,从系统环境开始搭。模型通过远端 API 调用,服务器不用跑大模型。用应用镜像起步的话,可以省掉不少基础安装,后面仍然需要核对插件兼容的 Harness 版本、运行用户和配置目录。
我的插件当时适配的是 @deepseek-ai/dsh@0.2.0-rc.2。部署前先对好这个版本,能少碰到一些“本地能用,服务器行为不一样”的问题。
文中的项目名、分支、变量和路径用了通用称呼,截图里的业务内容也做了遮挡;命令示例要按自己项目的实际配置替换。
给 OrcaTerm 一份按项目写的部署文档
开始前,我已经写了一份 DEPLOYMENT.md,里面除了安装步骤,还说清楚了项目分支、插件目录、数据放在哪里、服务用哪个用户运行,以及最后怎么验收。
给 Agent 的要求大意是:
按部署文档,把带业务插件的 Agent 部署到服务器。域名已经准备好,先配一个管理员账号,模型配置我之后自己绑定。数据快照保持不变,后续更新也不要覆盖会话和报告。
有了这些信息,Agent 就能继续检查服务器环境、对比项目代码、构建插件和配置服务。需要我决定的地方,比如用哪个账号、怎样处理密钥,再回来确认。
连接上也有个省事的地方:当时 OrcaTerm 已经能登录服务器,但 Mac 上直接 ssh 过去仍然被拒绝,rsync 也用不了。
首轮就先沿用已经能工作的 OrcaTerm 连接。我把仓库 clone 到服务器,Agent 接着在远程构建和部署。等后面做发布脚本了,再单独配好本机 SSH 公钥,不用一开始就卡在上传方式上。
代码和数据,先得搬对
第一个问题很快就来了:仓库 clone 完成,服务器上却没有 agent/ 目录。
Agent 对比后发现,服务器默认检出了 master,而我当前的插件代码在 feat/custom-agent 分支上。切到正确分支,才拿到了要部署的业务插件和数据快照。
这一步最好在装依赖之前就做:
git branch --show-current
git rev-parse HEAD
git status --short
接着还要看构建产物。项目里的 lib/ 和部分生成文件没有提交到 Git,clone 下来的是源码,不能直接当成一份已经装好的插件。服务器上需要按项目脚本构建,或者接收本地已经验证过的发布包。
这次选择在服务器构建,又碰到了一个很典型的问题:脚本里留着我 Mac 上的 /Users/... 绝对路径,Linux 找不到,报了 ENOENT。
Agent 读了报错和脚本,找到已有的 APP_SNAPSHOT_DIR 配置项,改用服务器实际的数据目录:
# 在同一个 Shell 或脚本中执行,替换为自己的快照目录
export APP_SNAPSHOT_DIR=/srv/agent-app/data/SNAPSHOT_ID
npm run prepare
npm run typecheck
npm test
这里还多踩了一次:构建命令带了变量,测试没带,结果构建过了,测试还在找 Mac 路径。补齐之后,服务器上的 120 项测试全部通过,7 个规范 JSON 文件的 SHA-256 也和数据清单对上了。
这一段用 OrcaTerm 比较省心。Agent 能直接看到远程报错,回到本地读脚本,再通过远程工具调整命令、重跑测试。我主要确认它用了正确的数据,没有为了让测试通过临时改掉业务内容。
*图 1:在 OrcaTerm 中回看自研插件的部署记录。找到路径问题后,通过远程工具重新运行测试,120 项全部通过。
Mac 的 node_modules 也没有整个搬过去,Linux 上重新按锁文件安装依赖。代码和数据各自确认清楚,后面出问题才好定位。
插件装到了哪里,比“安装成功”更值得看一眼
安装插件时有两个地方需要留意。
一个是 pnpm。当时 Node、npm 和 Harness 都已经装好了,添加插件时又发现缺 pnpm。这个版本的 dsh 会调用它安装插件,环境检查里得把它算上。
另一个是 DSH_HOME,也就是 Harness 保存 profile、配置、插件和会话的地方。
我用 ubuntu 登录,但服务由专门的 agentapp 用户运行。如果用登录用户装插件,没指定目录,插件可能进了 ubuntu 的 ~/.dsh;服务启动后读的却是另一个目录。安装过程看着成功,打开网页还是原来的界面。
这次统一使用 /var/lib/agent-app/dsh,创建 profile、注册插件和启动服务,都用相同的运行用户和目录。用户、目录和 profile 准备好后,注册命令类似这样:
sudo -n -u agentapp env DSH_HOME=/var/lib/agent-app/dsh \
/usr/local/bin/dsh plugin --profile business \
add /srv/agent-app/current/agent
我也没有直接套用“生产环境删掉所有 dev 依赖”的做法。当时这个插件部分运行时解析所需的依赖还在 dev/peer 声明里,先按锁文件保留,确认能加载后再考虑整理包声明。
如果用轻量服务器自带的 Harness 镜像,这一步尤其应该先查现有服务用哪个用户、哪个 profile、哪个 DSH_HOME,再把插件接进去。本例的路径是自己安排的,不需要把镜像原有目录照着改一遍。
更新插件,还得确认服务加载了新版本
第一次上线之后,我肯定还会继续改插件。比如换一组首页例题、调整数据展示,或者修一个工具参数问题。
所以部署时就把代码、固定数据和运行状态分开了:
/srv/agent-app/releases/<版本>/agent/ # 每次发布的插件代码和产物
/srv/agent-app/current # 指向当前版本
/srv/agent-app/data/<快照>/ # 固定业务数据
/var/lib/agent-app/dsh/ # Harness 配置、凭据和会话
/var/lib/agent-app/workspace/ # 工作区和生成的报告
更新时把代码放到新目录,验证好再切过去。数据没变就不用重复传,会话和报告也留在原来的位置。
这里不能只改一下 current,看服务启动了就结束。还要检查 profile 里插件实际指向哪个版本,重新注册并核对路径,再启动验证。否则就可能出现代码已经上传,运行的还是旧插件。
后面我把这些步骤整理成了项目自己的发布脚本:
./agent/scripts/deploy.sh --dry-run
./agent/scripts/deploy.sh
脚本先构建和测试,再上传新版本;切换前要求确认,停服后备份状态,再更新代码和插件注册。失败就恢复旧版本与旧插件注册,不用旧备份覆盖用户后来产生的会话和报告。后续也实际验证过正常发布和失败回滚。
这部分是在首轮部署之后,配置好本机 SSH 才继续做完的。以后日常更新,就不需要每次让 Agent 从安装环境开始重走一遍了。
给团队用,还要把入口和业务试一遍
插件部署好了,接下来才是团队实际访问的入口。
这部分用了 systemd 管服务,Caddy 配 HTTPS。OrcaTerm 的 remote_write 可以帮 Agent 写远程配置,再通过命令安装和验证,不用我把多行内容来回粘贴到编辑器里。
文件写入仍然受登录用户权限限制。这次就遇到不能直接写 root 配置目录的情况,最后先写普通配置的临时文件,再用 sudo -n install 放到目标位置。密钥文件单独处理权限。
Caddy 也踩了版本坑:实际装到的是 2.6.2,配置里却用了 basic_auth。Agent 查完后改为旧版支持的 basicauth,验证才通过。这个命名差异在官方文档里也能查到。版本说明
这些都属于让团队用起来的配套工作,基础软件怎么安装,这里就不展开了。
后续试用还补了登录体验。最初使用浏览器的账号密码弹框,再加 Harness 原生授权;Chrome 能进,Safari 却反复要密码,微信还会显示 401。后来换成普通登录页,用户只输入一次账号密码,Harness 的凭据留在服务器内部,由代理处理。Safari 和 Chrome 验证过,用户也反馈微信可以正常登录。
图 2:后续补上的团队访问入口。用户打开网址、输入账号密码,就可以进入这套带业务插件的 Agent。
最后验收时,我更关心的是:自定义界面有没有出现,查询有没有调用自己的工具,服务器上的数据是不是那份固定快照。
这次真正问问题时,还碰到过 MISSING_CREDENTIAL,模型密钥需要另外配置。处理后,在生产网页完成了一次业务查询,也把返回结果和项目快照核对了一遍。
图 3:生产网页里的一次真实业务查询
目前这套部署用于小团队共享试用,账号之间没有自动隔离会话和文件。服务稳定后观察到的内存约 109MB、峰值约 193MB。
OrcaTerm 帮我省下的,是中间这些来回操作
回头看,这次时间主要花在项目自己的事情上:拿对插件分支、处理构建路径、核对数据、注册到正确 profile,以及把后续更新做好。
这些事情单独看都不复杂,但手工做的话,经常要在本地代码、远程终端和浏览器之间来回切。OrcaTerm 把远程操作接给 Agent 后,读报错、找原因、改命令和验证可以连着做,我不用每一步都重新解释服务器现在是什么状态。