本节摘要:这是八种形态里最巧妙的一种。嵌入式 SDK 不起 HTTP 端口,而是在进程内用内存级的「假 fetch」跑同一套路由、中间件、编解码——保留了完整的 HTTP 编码边界,只是没有网络 I/O。本节讲清这套妙笔:它怎么用「同一套路由 + in-memory fetch」实现进程内复用,为什么说它「跳过了网络却保留了 HTTP 边界」,以及它适合什么场景。
考虑这个需求:你做了一个 Node/TS 应用,想把 OpenCode 内核嵌进去当 Agent 能力,但你不想为了这个单独起一个 HTTP 服务(多一个进程、多一个端口、多一层网络开销)。
朴素想法是「直接 import 内核函数调」。但这有个大问题——内核是按「HTTP 请求-响应」模型设计的(路由、鉴权、编解码都假设有 HTTP 边界)。直接调函数,就绕过了这套边界,行为会和真正的 serve 模式不一致。
嵌入式 SDK 解决的就是这个:既不起网络端口,又不绕过 HTTP 边界。
嵌入式 SDK 的核心机制是把服务端路由转成一个 Web Handler,再包成一个满足 fetch 签名的函数,注入到客户端。
服务端路由(同一套) │ ▼ 转成 Web Handler Web Handler(能处理「请求」返回「响应」) │ ▼ 包成 fetch 签名函数 in-memory fetch(req) → Response │ ▼ 注入到客户端 客户端(以为自己在调 HTTP,其实全在进程内)
关键点:
这是嵌入式 SDK 最精妙的地方,值得细说。
跳过了网络:没有 socket、没有 TCP、没有回环、没有 HTTP 序列化反序列化的网络开销。请求和响应在内存里直接传递,几乎是函数调用的开销。
保留了 HTTP 边界:虽然没走网络,但请求仍然经过完整的路由匹配、鉴权检查、请求编解码、响应编解码——这套「HTTP 边界」一个都没少。
真正 serve: 请求 ──网络──► 路由 ──鉴权──► 编解码 ──► 业务 ──► 编解码 ──网络──► 响应 嵌入式 SDK: 请求 ──内存──► 路由 ──鉴权──► 编解码 ──► 业务 ──► 编解码 ──内存──► 响应 ↑ 边界都在,只是换了传输介质
💡 为什么保留边界很重要:如果嵌入式 SDK 绕过边界直接调业务函数,它的行为会和 serve 模式不一致(鉴权可能没走、编解码可能没做)。保留边界意味着「嵌入式和 serve 行为完全一致」——你在嵌入式里测好的代码,放到 serve 里一样跑。这种一致性是工程上的巨大红利。
把整套机制串起来,嵌入式 SDK 的创建过程大致是:
create() │ ├─ 构建应用层(工具、权限等服务) ├─ 用服务端路由创建嵌入式路由(无密码,因为同进程可信) ├─ 把路由转成 Web Handler ├─ 包成 in-memory fetch 函数 ├─ 用这个 fetch 构造客户端 └─ 返回可用的嵌入式实例
注意「嵌入式路由无密码」——因为它是同进程内调用,不存在「外部攻击者」威胁,所以省掉了密码层(serve 模式才需要密码防外部)。但鉴权、编解码这些边界还在。
把两种形态放一起对比,选型就很清楚:
| 维度 | serve 模式 | 嵌入式 SDK |
|---|---|---|
| 进程关系 | 独立进程 | 同进程 |
| 通信 | HTTP(网络/回环) | 内存调用 |
| 性能 | 有 HTTP 开销 | 几乎零开销 |
| 多客户端 | 一个 serve 多客户端连 | 单进程内用 |
| 跨机器 | 支持 | 不支持 |
| 部署复杂度 | 多一个进程 | 无额外进程 |
选型原则:
几个典型场景:
⚠️ 限制:嵌入式是同进程的,所以不能跨机器。如果你想「机器 A 的程序用机器 B 的内核」,那只能用 serve(机器 B 起 serve,机器 A 通过网络调)。嵌入式只解决「同进程内复用」。
读完第 3 章四节,你应该抓住多形态设计的本质:八种形态不是八套实现,而是「一个内核 + 八个入口」。
serve 和嵌入式是这套设计最巧妙的两个点——一个用网络连接多客户端,一个用内存复用内核,二者都保留了完整的 HTTP 边界,只是传输介质不同。从第 4 章开始,我们钻进内核本身,先看 Agent 体系与权限模型。
第 3 章结束。下一章进入内核,讲 Agent 体系与权限模型——那些内置 Agent 怎么分工,权限怎么求解。