Skip to content

架构选择补遗:本地、云端与边界 ​

上线前夜,小a拿着部署方案来找老z:“我们把这个 Agent 部署到云上,让大家都用,这样省事。”顿了顿,他又补了一句:“而且云端肯定比本地安全吧?毕竟云厂商有专业团队。”

老z没有直接回答,反问道:“本地一定更安全,云端一定更省事吗?”

小a愣住了。他下意识想说“是”,但话到嘴边又觉得不对——他见过本地 Agent 误删文件的惨案,也听过云端密钥泄露的事故。安全和省事,好像都跟“在哪部署”没那么直接的关系。

“这是错误前提。”老z说,“**安全和运维成本来自具体权限、网络、密钥、隔离和操作流程,而不是部署标签。**本附录服务概念篇与实现篇,当需要决定 Agent 在哪里运行、哪些数据可以外发时查阅。这里不提供产品榜单;供应商能力、价格和地区可用性未在本附录核验。”

老z顺手把问题拆成了两类:“**‘部署在哪’是架构问题,‘部署后谁负责什么’是运营问题。**很多人把两者混成一件事,于是‘本地更安全’和‘云端更省事’这种标签式结论就出现了——它们把两套不同的问题各砍掉了一半。”小a点头:“所以本附录要做的,是把这两类问题摊开,分别给可核验的抓手。”

小a把这两个判断记在笔记本上,又划了一道竖线把两边分开。他发现,自己其实从来没把"数据流向"和"访问控制"这两件事拆开过——以前一提到"安全",脑子里浮现的就是"数据不要外泄",从来没单独问过"在我自己机器上,谁能动这些数据"。这个混淆一旦点破,后面很多讨论都好办了。

“本地更安全”为什么是错的 ​

小a不服气:“本地数据不出我的机器,怎么不安全?”

老z让他列一下本地 Agent 真能访问什么:

  • 文件系统——Agent 进程的权限就是你的用户权限,它能读你 home 目录下的一切。
  • 网络——除非你显式限制,Agent 可以访问任何内网和公网地址。
  • 环境变量与凭据——.env、~/.ssh、~/.aws,只要进程能读,Agent 就能读。
  • shell——bash 工具能执行任意命令,包括 rm -rf、curl 外发、装后门。

小a看了一眼这四条,脸有点红:“我之前真以为本地是‘天然隔离’的。”

“这个错觉来自一个混淆。”老z说,“**‘数据不出我的机器’和‘我机器内的数据安全’是两件事。**前者是数据流向问题,后者是访问控制问题。本地部署把第一件做对了(数据物理上没出门),但第二件一点没少——反而因为执行体和你的所有文件、凭据、网络同处一个用户身份下,它的攻击面比云端默认配置还要大。”

“你看,本地不等于隔离。”老z说,“本地的‘安全’依赖你怎么配权限、怎么限制工具、怎么审计日志——跟云上要做的事一模一样。把‘本地’当成安全护身符,是最危险的错觉。”

小a看了看那四条,忽然想到一个细节:“四条里都没有‘权限最小化’这条?”

“因为‘权限最小化’不是一条,是贯穿四条的原则。”老z说,“文件系统问‘它能读什么’,网络问‘它能连哪’,凭据问‘它能拿什么’,shell 问‘它能执行什么’——每条都在做同一件事:**把 Agent 的默认能力往下压。**本地部署的问题恰恰是它默认压得最松:进程用你的身份,天然能读你的一切。所以本地要核验的不是‘有没有权限控制’,而是‘权限控制是不是显式做出来的,而不是默认继承来的’。”

小a:“那本地 Agent 的安全,有没有一个最低标准?”

“有,一句话:‘我机器上的 Agent,权限不得超过我明确授予它的范围。’”老z说,“这句话看着简单,做起来要落实四件事:它读不到你没让它读的目录、连不上你没让它连的地址、拿不到你没让它碰的凭据、执行不了你没允许的命令。四件事都能答‘是’,本地才谈得上安全;答不了,它就是个装在你机器上的高权限进程,跟部署标签没关系。”

小a:“那本地真正适合什么场景?”

“适合两件事。”老z说,“一是数据不能出域的硬约束——合规要求数据物理上不出机器,这种约束只有本地能满足,没有别的选择;二是低延迟和断网可用——本地模型不用等网络,断网也能干活。但注意,这两件事都不自动带来安全。数据不出域只是满足了‘数据流向’这一维,访问控制那一维该做还得做。‘本地适合什么’是能力问题,别拿它回答安全问题。”

那云端呢?小a追问。

“云端也不自动安全。”老z说,“云上的 Agent 面对的威胁面不同但不少:多租户隔离是否可靠、你的 API key 范围是否过大、日志里是否泄露了用户数据、出口控制是否真的拦住了外发。云厂商提供了能力,但‘配对了吗’是你的责任。”

小a:“云端省事省在哪?”

“省在运维外包:补丁、扩容、备份、机房,都不归你管。”老z说,“但省下来的每一件事,都换成了另一件事——你得多核验一层的信任:厂商的默认配置是不是隔离的、它的审计日志你能不能拿到、它的删除是真的删还是软删。**‘外包运维’不等于‘外包核验’。**你把运维交出去,核验还得自己来。”

老z强调两者的威胁模型形状不一样:**本地的风险集中在‘执行体权限过大’——它能干你能干的一切;云端的风险集中在‘配置默认值’——你以为默认是隔离的,实际可能是共享的。**两者要查的东西完全不同,但都不能因为部署标签就跳过核验。

小a想了想,又抛出一个具体问题:“那如果我本地用一个最小权限的专用账户跑 Agent,是不是就绕开了‘权限过大’这个坑?”

“能减轻,但绕不开。”老z说,“专用账户限制了它能动的文件范围,这是对的。但这个账户还是要持有调用模型用的 API key、还是要能访问网络、还是要在某个工作目录里执行 shell。**最小权限不是‘有没有专用账户’,是‘这个账户被授予的具体能力清单有多短’。**很多人开了个新账户就放心了,结果新账户照样能读 .env、照样能 curl 外网——只是换了个名字的‘全权账户’。”

“所以核验的动作是,”小a接道,“列出这个账户实际能做的事,一条条问‘这一条非给不可吗’。”

“对。部署标签换不来核验清单的缩短,它只换了清单上要查的项目。”老z说。

“那本地还有一条经常被漏掉的,审计日志。”老z提醒,“本地部署最容易犯的懒,是‘反正数据不出门,日志记不记无所谓’。但一旦出事,你能拿什么追溯?本地 Agent 在你机器上跑过什么命令、改过什么文件、外发过什么——这些如果不落日志,本地事故比云端事故更难查,因为云端至少有厂商侧的审计,本地什么都没有。审计日志不是云端的专利,是任何 Agent 部署都要有的最小可观测性。”

“所以本地要做的事,”老z总结,“权限清单、网络限制、日志审计、备份恢复,一个都不少——只是做的地方从厂商控制台换成了你自己这台机器。‘本地’不是少做几件事,是同一批事换人做。”

五个决策维度 ​

老z把决策维度整理成一张表。核心原则是:每一维都要问‘要核验什么’,而不是‘选哪个标签’。

决策维度本地/自托管要核验托管服务要核验
数据流哪些文件进入上下文、日志和模型请求数据保留、地域、子处理方与删除路径
身份与密钥进程用户、凭据存储、工作区权限租户隔离、令牌范围、撤销与审计
执行边界shell、网络、容器/VM 的实际限制远程工具权限、出口控制、审批
可用性本地模型、磁盘、升级与备份限流、服务故障、降级和数据导出
成本设备、维护、人力、能耗请求、存储、带宽和意外循环预算

小a盯着表问:“这张表怎么读?是不是两边都要填满才算安全?”

“不是填满,是对照取证。”老z说,“每一维不是‘选 A 还是 B’,而是‘在这一维上,我打算选的那一侧,具体要核验哪些事’。比如你决定数据流走本地,那你就要回答‘哪些文件会被读进上下文?日志会不会落盘?落盘的日志有没有 PII?退出了谁清?’——五个问题问完,你才知道本地的数据流是不是真的安全。”

“这张表还有一个用法,”老z说,“当两个方案吵架时,用表把吵架翻译成取证。‘本地更安全’和‘云端更省事’各执一词时,别争谁对,直接把五个维度摊开,把各自‘要核验什么’列出来——哪一栏列得出具体问题,哪一栏就站得住;哪一栏只能喊口号,哪一栏就在裸奔。表的价值不在填满,在逼着双方把抽象结论换成具体待办。”

“五个维度里还有一个经常被整个忘掉的项目——删除路径。”老z提醒,“大家都会核验数据怎么进来,很少核验数据怎么出去。日志里的 PII、缓存里的旧版本、云端的备份副本——这些数据‘进来了’之后,什么时候删、谁来删、删了能验证吗?**删除路径没核验,等于数据在你这儿没有生命周期。**这在哪一侧都成立,但云端因为多一层‘数据在别人硬盘上’,尤其要单独问。”

老z提醒小a注意表里容易踩的三个取舍:

  • 数据流 vs 可用性——把数据留在本地更稳,但一旦本地磁盘坏了、备份没做,数据恢复的代价全压在你身上。云端冗余更好,但前提是你接受数据出域。
  • 执行边界 vs 成本——本地用容器/VM 沙箱,隔离强但运维和算力都贵;云端把运维外包,但出口控制要靠厂商的配置,而厂商的默认值不一定对你有利。
  • 身份与密钥 vs 可用性——本地能做最细粒度的凭据隔离,但谁来轮换、谁来撤销,这事得你自己扛;云端有托管密钥服务,但你又多了一个‘密钥服务的访问范围’要核验。

“这三个取舍,”老z说,“**说明没有任何一栏是‘免费午餐’。**你拿走一边的好处,就要在另一边补上对应的核验成本。表格不是给你选答案,是给你列出每一选都要付的代价。”

小a盯着“执行边界 vs 成本”那一行:“这一行是不是经常被‘用一个 Docker 容器就解决了’糊弄过去?”

“是,而且糊弄得很常见。”老z说,“Docker 确实是隔离手段,但‘用了 Docker’不等于‘配好了隔离’——容器的 root 用户、挂载的宿主机目录、没设 limits 的 CPU/内存,任何一条都是绕过点。**核验的是‘容器跑起来后,进程到底还能碰到什么’,而不是‘docker run 这句话里有没有 docker’。**这跟本地/云端的道理一模一样:容器也是一种边界,它同样需要逐条核验,而不是贴个标签就算数。”

小a把三个取舍在脑子里过了一遍,问了一个反向问题:“那有没有一种组合,是三对取舍都站在我这边、代价都最小的?”

“没有,但有一种接近的做法——按资产分层。”老z说,“把你的数据按敏感度分三档:公开的(可以随便外发)、内部用的(不出域但要可用)、敏感的(只能本地、且最小权限)。然后让每一层各自选最合适的边界——敏感数据走本地严格隔离,内部数据走本地或可信区域,公开数据可以任意走云端模型。分层的代价是配置复杂度上升、要维护多套边界——但比起‘把所有东西塞进一个笼子然后祈祷’,分层是更诚实的做法。”

“这个分层听起来跟 zero-trust 网络的思路很像。”小a说。

“思路相通,但落地不同。”老z说,“zero-trust 是网络层的‘永不信任,持续验证’,这里是 Agent 层的‘每个数据流各有边界,各自核验’。别把名字当方案,关键是那个‘按资产分别核验’的动作。”

“分层的落点还要再补一刀,”老z说,“**每档数据不仅要选边界,还要写清‘降级时的去处’。**公开数据走云端,云端挂了怎么办——退回本地小模型,还是直接失败给用户?敏感数据走本地,本地空间不足怎么办——删旧备份,还是停下等人工?**没有降级路径的边界,遇到故障时会自动做出一个你从未核验过的决定。**而那个决定,往往正是安全事故的开始。”

“还有最后一层容易被忽略,”老z补充,“**分层不是一次性的,是随数据流动的。**一个文件今天按‘公开’走云端,明天被标记成‘敏感’,它的路径就要跟着换——换的过程里有没有哪个副本忘了收回来?这就是为什么分层要求‘删除路径’和‘降级路径’一起写:数据会变敏感,敏感数据该有的边界要能接得住它。”

小a看完全表,问:“那‘本地更安全’到底该怎么验证?”

“别问‘哪个更安全’,问可验证的问题。”老z说。空泛的结论(“本地安全”“云端省事”)无法证伪;具体的问题可以。

可验证问题比结论更有用 ​

老z让小a把“本地更安全”翻译成四个可验证的问题:

  • 不可信仓库能否读到工作区外文件?——如果 read 工具的 workspacePath 检查能被 .. 绕过,那“本地”一点也不安全。
  • 外发时 UI 是否显示实际目的地和参数?——如果模型要 curl 一个地址,用户能不能在执行前看到并拒绝?
  • 断线后是否有幂等策略?——如果一次请求因为网络中断执行了一半,重试会不会重复扣款或重复发邮件?
  • 删除源文档后,索引和备份何时删除?——数据残留是隐私风险,本地和云端都要回答。

“这四个问题,翻译的秘诀是**‘断言 → 测试’两步**:先把对方的结论拆成一个断言(‘本地是安全的’),再给每个断言配一个能推翻它的测试。推翻不了,结论暂时成立;一推就翻,结论当场作废。”老z说,“一句安全结论,翻译不出至少一个可执行测试,那它就不是结论,是信仰。”

“这四个问题,”老z说,“任何一个答不上来,部署就不该上线——无论它在本地还是云端。”

小a:“这四个问题,是按什么顺序排的?”

“按‘最容易被忽略’排的。”老z说,“第一个问题大家都会问(越界读取最直观),第二个开始就少一半人问(外发可见性要跑 UI 才看得见),第三个再少一半(幂等策略要出事才想起),第四个几乎没人问(删除是‘最后一公里’,验收时早忘了)。这个顺序本身就是一张检查表:回答前两个,你防的是‘被偷’(数据被读走);回答后两个,你防的是‘被错用’(重复扣款)和‘被残留’(删除不彻底)。四种风险,四种答法。”

小a追问:“为什么‘翻译成可验证问题’这么管用?”

“因为结论是黑盒,问题是探针。”老z说,“‘本地更安全’这句话既不能证实也不能证伪,谁都能坚持自己的版本,谁也说服不了谁;但‘.. 能不能绕过 workspacePath’这个问题,你跑一次测试就知道了——要么能绕过(有漏洞),要么不能(暂时安全)。把结论翻译成问题,就是把你从‘吵嘴’拽到‘跑测试’——这是核验之所以是核验、而不是空谈的根本原因。”

“还有一个补充,”老z说,“可验证问题的答案会过期。‘.. 绕不过 workspacePath’是今天绕不过,换个版本、换个文件系统、换个 URL 解码方式,可能就绕过了。所以翻译成问题之后,还要把‘什么时候重新验证’写进日历——**验证不是一次性的,是有有效期的。**这跟实验室里‘结论要能复现’是同一个要求,只是把周期从‘提交时’拉长到了‘每次环境变动时’。”

pi-mono 的代码能证明什么 ​

小a问了一个具体问题:“那 pi-mono 的代码能证明部署安全吗?”

“它只能说明某些边界,不能证明整个部署安全。”老z逐条列出 pi-mono 可见的边界:

  • Provider 认证在 packages/ai/src/models.ts 的 applyAuth 解析——这证明凭据被合并,不证明凭据存储安全。
  • 工具和会话由宿主装配——这证明能力是显式声明的,不证明声明一定最小权限。
  • 协议 decoder 有大小限制——这证明不会被超大 frame 打爆内存,不证明协议层免疫所有攻击。
  • mutation 有队列序列化——这证明同一路径的写入不会并发踩踏,不证明写入内容本身正确。

“它不能单独证明某种部署满足合规或隔离要求。”老z强调,“代码边界是部署安全的一部分,但合规(如 GDPR、SOC 2)、网络隔离、密钥轮换、审计日志保留——这些都要在部署层面另行核验。”

小a:“怎么判断一条安全声明,是该拿代码核验,还是该拿部署核验?”

“看那条声明的主语是谁。”老z说,“主语是代码的,拿代码核验;主语是环境的,拿部署核验。‘模型请求前会合并认证’——主语是 applyAuth,查代码;‘这个部署只允许内网访问’——主语是网络配置,查防火墙和路由;‘密钥会定期轮换’——主语是运营流程,查排期和告警。**把声明的主语找出来,你就知道该翻开哪一层的证据。**拿代码去证明环境声明,是跨层取证,证明不了。”

小a:“所以代码读得再细,也不能‘证明安全’。”

“对。代码能告诉你有些边界存在,但完整的安全证据链还包括:运行时配置怎么生效、密钥怎么注入、谁有访问权、出事怎么追溯。代码是证据的一环,不是证据的全部——少了任何一环,部署声明就站不住。”

“再补一条容易踩的,”老z说,“**‘代码里做了’不等于‘部署时做了’。**代码里有路径检查,不代表线上进程跑的就是那套检查——它可能被环境变量关掉了,可能被绕过了,可能是旧版本。**读代码是建立‘应该是什么’,跑部署核验才是确认‘实际是什么’。**两者之间,隔着配置和版本这两层最容易出意外的地方。”

混合边界才是常态 ​

小a最后问:“那到底选本地还是云端?”

“大多数真实系统是混合的。”老z说,“模型推理在云端(因为本地跑不动大模型),会话存储在本地(因为数据不出域),工具执行在本地(因为要改你的代码)。每一层都有自己的边界,都要单独核验。”

“先澄清一个常见的误会,”老z说,“**‘混合’不是‘两头都要的折中方案’,而是‘不同数据各走各的最优路径’。**折中是同一个数据在中间地带妥协;混合是不同数据走各自的边界,互不干扰。判断标准很简单:你给每一类数据都画了一条明确的路径吗?画得出,是混合;画不出,只是‘到处都放一点’的大杂烩。”

“还有一个常见反例,”老z补了一句,“**别让‘会话存本地’变成一句空话。**如果会话确实存本地,但本地进程的日志又把整个会话内容发给了厂商做遥测,那你的‘会话不出域’就是名义上的。核验数据落在哪,要核验的是它的每一份副本落在哪——原文件、日志、备份、遥测,一个都不能漏。”

老z给小a画了一下数据在混合系统里走的路径:用户的请求 → 本地工具执行(改文件)→ 本地组装上下文 → 云端模型推理(代码可能外发)→ 云端返回 → 本地写回工作区 → 本地落日志。这条链上每一跳都是个边界:从本地到云端那一跳,数据出域了;从云端回本地那一跳,返回内容进了你的文件系统。两跳的威胁模型不一样,核验方法也不一样——出域时要问“发了什么?够不够最小化?”,回来时要问“返回内容会被当成代码执行吗?”。

小a盯着“本地落日志”那一跳:“日志这一跳也要算一条边界?”

“要,而且经常被漏掉。”老z说,“日志是数据的第三份副本——文件里一份,模型那边一份,日志里一份。很多系统把前两份核验得很仔细,日志这份却默认‘反正在本地,没关系’。结果日志里存了完整对话、完整命令、甚至密钥明文,变成一份没人看守的敏感数据副本。核验数据流向,要连‘日志记了什么’一起核验,这跟混合不混合无关,但混合系统里尤其容易漏——因为它看起来最不起眼。”

“混合的好处是各取所长,”老z说,“代价是边界数量翻倍——每多一跳,就多一个‘这跳做了什么核验’的待办。很多人觉得混合是‘两边的便宜都占’,实际上是‘两边的核验都要做’。”

小a:“那混合的边界,从哪一跳开始核验?”

“从数据出域那一跳开始。”老z说,“混合系统里,绝大多数风险集中在一两个关键跳——本地到云端(数据外发)、云端回本地(内容回写)。先把这两跳的核验做扎实,其余跳按‘价值密度’排:哪一跳改坏了后果最重,就先核验哪一跳。别追求所有跳一次核完,那是不可持续的;按风险排序,是可持续的。”

“还有一条针对混合的经验,”老z补充,“**每一跳都要能独立开关。**比如‘把上下文发给云端模型’这一跳,要能用一个配置单独关掉——关了之后 Agent 还能不能退化成纯本地模式?能,说明边界是真实存在的;不能,说明你所谓的混合是单向绑定,敏感数据根本没得选。能独立关闭的边界,才是你声称的边界。”

决策原则

先明确资产(什么数据、什么权限、什么副作用)、威胁模型(谁能攻击、从哪攻、损失多大)和可接受损失,再选择每一层的边界——本地、云端或混合。部署位置不能替代授权、审批和核验。

“这套决策原则,其实可以压缩成一个更朴素的问法,”老z说,“**‘这份资产,我接受它出现在哪、谁能碰它、出事我能接受多惨?’**三个答案都写清楚,部署位置是自动浮现的结果,不是需要拍的脑袋。反过来,先选位置再谈资产的人,通常会在上线前夜发现:这个位置根本承担不起这份资产的威胁模型。”

回到全书目标:Agent 的安全不是“选对部署位置”,而是“每一层都有可验证的边界”。安全边那一章建立的威胁模型、信任边界、最小权限和审批,在这里要落到具体的部署决策上——而且每一条决策,都得能被翻译成一个可执行的问题去核验,而不是停在“我们选了云端”这种结论上。

小a把笔记本翻回第一页,给“本地更安全”“云端更省事”各划了一道删除线,在旁边写下了同一个问句:“哪一维、核验什么、多久重验一次?”——他知道,下一次再有人拿部署标签说服他时,这句问话比任何架构图都管用。