第 13 章:为什么 Agent 一旦产品化,迟早会走向服务化
本章目标:讲清 Agent 为什么常常会从本地助手演化成服务端系统,以及服务化到底带来了哪些新能力、哪些新成本、哪些新边界。
本章对应总纲:docs/ebook-outline.md中“第 13 章正文写作提纲(2026-03-31 归档)”。
13.1 为什么本地跑得动,不等于系统就到头了
很多 Agent 一开始都是从本地形态长出来的:
- 一个 CLI
- 一个 IDE 内助手
- 一个桌面端入口
- 一个能调本地工具的个人工作台
这很自然。
因为本地形态最容易起步:
- 离用户近
- 调本地环境方便
- 权限边界清楚
- 原型成本低
但只要系统真的开始被多人使用、被多端接入、被远程触发,你很快就会碰到一个问题:
这个 Agent 还只是一个本地工具,还是已经开始变成一个服务?
一旦后者成立,很多原来可以偷懒的地方就全得重做。
13.2 Agent 为什么会自然走向服务化
13.2.1 因为调用入口会变多
一开始可能只是本地命令。
后来很快就会冒出这些需求:
- Web 端也要调
- IDE 插件也要调
- 自动化系统也要调
- 其他服务也要调
- 远程任务也要触发
这时如果还是把 Agent 绑死在本地交互壳层里,整个系统就会很别扭。
13.2.2 因为任务会变长
很多 Agent 任务不是一秒钟结束的请求,而是:
- 要读很多上下文
- 要调很多工具
- 要等待外部系统
- 要让用户中途确认
- 要持续回传状态
这类任务天然更像一个长生命周期服务,而不是一次同步函数调用。
13.2.3 因为状态不再只属于本地进程
一旦多个客户端都可能接同一个任务,你就不能再假设:
- 状态只在当前终端里
- 输出只给一个用户看
- 中断只靠 Ctrl+C
到这一步,服务化几乎不是选择题,而是现实后果。
13.3 服务化到底带来了什么新东西
13.3.1 请求和会话被分开了
在本地 CLI 里,一次运行往往天然绑定一个终端会话。
但服务化之后,你必须区分:
- 一个 HTTP 请求是什么
- 一个 Agent 会话是什么
- 一个长任务实例是什么
- 一个用户连接是什么
这几个东西如果混写,系统很快就会乱。
13.3.2 同步和异步被分开了
有些动作适合同步返回,例如:
- 参数校验失败
- 快速只读查询
- 简单状态检查
但很多 Agent 行为更适合异步:
- 长时间执行
- 多步工具调用
- 中途等待授权
- 持续推送事件流
服务化本质上逼你把这两类路径拆清。
13.3.3 结果不再只是“一段最终文本”
本地对话经常让人误以为 Agent 输出就是最后那段回答。
服务化以后你会发现,真正重要的往往是这些:
- 当前阶段
- 正在做什么
- 调了哪些能力
- 哪一步卡住了
- 是否等待用户确认
- 最终产物在哪
也就是说,服务化会逼系统把“中间状态”作为一等公民暴露出来。
13.4 服务化之后,系统会立刻多出四种新成本
13.4.1 并发成本
本地跑一个任务和服务端同时跑很多任务,不是一个量级的问题。
你得开始处理:
- 任务排队
- 资源争用
- 工具调用隔离
- 模型配额竞争
- 外部服务限流
13.4.2 生命周期成本
任务开始、暂停、恢复、取消、超时、失败回收,这些在本地原型里常常是模糊的;一旦服务化,就全得明确。
13.4.3 连接成本
服务化以后,经常会出现:
- 请求发起和结果消费不在同一连接里
- 客户端断了,但任务没结束
- 任务结束了,但客户端还要补拉结果
这类问题不属于模型能力,而属于系统连接设计。
13.4.4 安全与治理成本
只要 Agent 变成服务,它就更接近共享基础设施。
于是这些问题马上变硬:
- 谁能发起任务
- 谁能读任务结果
- 谁能中断任务
- 谁能访问哪些工具
- 哪些租户彼此隔离
这时安全不再只是“别写危险命令”,而是系统级权限治理。
13.5 为什么服务化会逼你重做接口设计
在本地形态里,很多接口偷懒都能活。
例如:
- 输入格式不太稳定也能忍
- 中间状态不结构化也能看懂
- 错误只吐文本也能人工判断
但服务化以后,这些偷懒会立刻变成问题。
因为服务端接口至少要回答:
- 如何创建任务
- 如何查询状态
- 如何消费流式输出
- 如何提交确认或补充信息
- 如何取消任务
- 如何获取最终产物
所以服务化不是把 CLI 外面包一层 HTTP 就完了。
真正的服务化,意味着你要把 Agent 的运行过程显式建模出来。
13.6 流式输出为什么会变得越来越重要
Agent 系统一旦服务化,流式输出几乎会从“体验优化”变成“结构需要”。
因为长任务如果只有最终结果,用户会立刻遇到这些问题:
- 不知道系统是不是卡死了
- 不知道现在走到哪一步
- 不知道是不是在等确认
- 不知道什么时候该介入
所以服务化之后,系统通常需要暴露事件流,例如:
- 任务已创建
- 当前步骤更新
- 工具调用开始/结束
- 请求用户确认
- 任务完成/失败
这也是为什么很多 Agent 服务最后都会走向 SSE、WebSocket 或其他事件流机制。
不是因为它们更潮,而是因为单次请求-单次响应装不下真实 Agent 的生命周期。
13.7 服务化和持久化为什么总是靠得很近
一旦 Agent 变成服务,就很难继续假设所有状态都只活在内存里。
因为现实里很快就会出现这些场景:
- 服务重启后任务不能全失忆
- 客户端稍后还要回来补看结果
- 多端要共享同一个会话
- 人工审核要回看执行轨迹
- 异步任务要跨进程继续推进
这说明服务化会自然把系统推向下一个问题:
哪些状态必须落下来,才能让系统不像一次性脚本?
所以服务化后面,几乎总会跟着持久化。
13.8 用 Claude Code 反着看服务化的边界
Claude Code 本身是一个很强的本地 Agent 环境,这恰好适合拿来反着理解服务化边界。
从当前仓库就能看见它明显更偏本地壳层,而不是完整远程服务:
- 根级
package.json主要暴露的是docs:dev、docs:build、docs:preview这种本地开发与构建脚本,而不是一套任务 API docs/README.md写的是本地开发、预览和部署静态站点,这说明当前这个仓库的“产品化面”更多还是内容交付,而不是一个通用 Agent 服务端.github/workflows/deploy-docs.yml虽然提供了自动化构建与部署链路,但它编排的是文档交付,不是 Agent 任务生命周期 APIplugins/README.md展示了大量命令、Hook、Agent、Skill 与.mcp.json的插件结构,这说明系统已经在能力层和扩展层上很丰富,但并没有因此自动变成“服务化完成”
它很多优势都来自本地形态:
- 直接接用户当前仓库
- 直接看到本地文件和终端
- 权限确认离用户很近
- 会话上下文天然跟当前工作目录绑定
但你也能顺着它看到一旦走向远程化会冒出的那些问题:
- 本地工具怎么远程代理
- 权限确认怎么跨端传递
- 长任务状态怎么被外部系统消费
- 会话与连接怎么分离
这说明服务化不是“把本地壳子搬到服务器”这么简单,而是整套运行时边界都会变化。
13.9 什么时候你真的该考虑服务化
不是所有 Agent 都值得一开始就做成服务。
但通常出现这些信号时,就该认真想了:
- 不止一个入口要调用它
- 任务明显变长,不能再靠单次同步返回
- 多人要共享状态或结果
- 需要远程触发或定时触发
- 需要统一治理权限、审计和配额
- 本地进程退出不该等于任务彻底消失
如果这些信号已经很明显,你还坚持把系统当成本地小工具硬扛,后面只会越来越别扭。
13.10 服务化不是更高级,只是系统进入了新阶段
这一点也必须说清。
很多人会把服务化理解成“更成熟”“更高级”。
这不准确。
服务化只是说明系统面对的问题变了:
- 从单用户到多用户
- 从单入口到多入口
- 从短任务到长任务
- 从本地交互到远程协作
它不是自动更好,只是自动更复杂。
如果你的任务根本不需要这些能力,硬服务化就是在给自己找麻烦。
但如果系统已经明显跨进了这些场景,不服务化反而是在拖后腿。
13.11 本章小结
这一章真正想讲清的是:Agent 一旦产品化,常常会自然走向服务化。因为多入口、长任务、异步状态、远程调用和共享治理,都会逼系统从本地工具演化成服务端系统。
你现在应该记住六件事:
- 本地 Agent 能跑,不代表系统边界就已经稳定。
- 多入口、长任务和共享状态,会自然把 Agent 推向服务化。
- 服务化会逼你把请求、会话、连接和任务实例拆开。
- 并发、生命周期、连接和权限治理,是服务化后的新增成本。
- 真正的服务化不是包一层 HTTP,而是把运行过程显式建模出来。
- 服务化通常会把系统进一步推向持久化,因为状态不能再只活在内存里。
但这里先把边界说死:服务化把系统推向持久化,主要是因为它需要状态连续性;这还不等于第 19 章要讲的“能长期活着”的整圈工程闭环。
下一章我们继续往下走,讲持久化:不是把聊天记录顺手存一下,而是为什么一个想长期运行、可恢复、可审计的 Agent 系统,必须认真处理状态落盘这件事。