03 一次用户操作的控制流旅程 本节摘要:前两节讲了拓扑和哲学,这一节把它们串成一条河——用一次具体的用户操作(「在界面发起一次会话」),追踪控制流如何从渲染进程穿越主进程、服务端、引擎,再带着结果返回。这是第 2 章的收尾,也是对前两节知识的综合检验:读完它,抽象的拓扑和哲学就会变成可见的数据流,后续每一章你都能在这趟旅程里找到自己关注的那一段。 一、场景设定 假设你在桌面界面里,针对当前工作区发起一条会话消息:「这个项目大概做什么?」。我们追踪这条消息从输入到回显的完整控制流。 二、旅程全景图 先看全貌,再分步拆: 三、分步拆解 第 1 步:渲染进程接住输入 你在界面敲下消息,渲染进程(React 单页应用)接住它。渲染进程做的事很薄:把消息封装成一个对服务端的 API 调用。
本节摘要:前两节讲了拓扑和哲学,这一节把它们串成一条河——用一次具体的用户操作(「在界面发起一次会话」),追踪控制流如何从渲染进程穿越主进程、服务端、引擎,再带着结果返回。这是第 2 章的收尾,也是对前两节知识的综合检验:读完它,抽象的拓扑和哲学就会变成可见的数据流,后续每一章你都能在这趟旅程里找到自己关注的那一段。
假设你在桌面界面里,针对当前工作区发起一条会话消息:「这个项目大概做什么?」。我们追踪这条消息从输入到回显的完整控制流。
先看全貌,再分步拆:
你在界面输入消息 │ ▼ [渲染进程] 接住输入,准备调服务端 API │ ▼ [渲染进程→主进程] 通过 IPC 桥接 │ ▼ [主进程] 转发到服务端(或直接由渲染进程调服务端 HTTP) │ ▼ [服务端] 接收请求,路由匹配 │ ▼ [服务端] 鉴权(第 4 章) │ ▼ [服务端] 代理到引擎 / 执行能力(第 3、7 章) │ ▼ [引擎] 真正干活(读文件、调模型、调工具) │ ▼ 结果原路返回 │ ◄─ 你在界面看到结果
你在界面敲下消息,渲染进程(React 单页应用)接住它。渲染进程做的事很薄:把消息封装成一个对服务端的 API 调用。它不自己处理「会话逻辑」——那是服务端的事(服务端消费优先,第 02 节)。
💡 记住:渲染进程永远很薄。它的职责是「把用户操作翻译成服务端 API 调用 + 把服务端返回渲染出来」,不亲自干业务逻辑。
桌面形态下,渲染进程有些操作需要通过 IPC(进程间通信)走主进程——尤其是涉及桌面专属能力的(窗口、文件对话框、运行时管理)。不过对服务端的常规 API 调用,渲染进程通常直接走 HTTP(服务端就是个 HTTP 服务)。
这里有个细节:渲染进程通过一个「桌面桥接代理」(desktopBridge,第 10 章)访问桌面专属能力,通过 HTTP 访问服务端。两条路各管一摊。
请求到达服务端,服务端用它的自研路由引擎(第 3 章)匹配路径。匹配到「会话」相关路由后,进入对应的处理器。
⚠️ 这里有个第 3 章的伏笔:服务端不用任何 Web 框架,路由是正则编译式的。怎么做到的、为什么这么做,第 3 章详讲。
服务端在执行业务前,先做鉴权(第 4 章)——这个请求是哪个令牌来的?它是什么 scope(所有者/协作者/查看者)?它有权做这件事吗?鉴权不通过,直接拒绝。
在我们的场景里(工作区所有者本人发起会话),鉴权通过,继续。
这是旅程里最关键的分叉。服务端拿到一个合法的会话请求后,要么:
在我们的场景里(发起会话),走的是「代理到引擎」。
请求到达引擎(OpenCode),真正的 Agent 运行时启动:
引擎干完活,把结果(通常是流式的事件)经服务端原路返回。
结果从引擎 → 服务端 →(HTTP/IPC)→ 渲染进程。渲染进程把流式结果实时渲染到界面,你看到模型一段段吐出回答。
把这趟旅程和前两节对照,几个关键认知被验证:
| 认知 | 在旅程里的体现 |
|---|---|
| 服务端是中枢 | 第 3~6 步都在服务端或经服务端 |
| 服务端消费优先 | 渲染进程只调 API,不自己干业务(第 1 步) |
| 引擎被代理 | 对引擎的访问经服务端代理(第 5 步) |
| 权限贯穿 | 第 4 步鉴权,且引擎内还有工具级权限(OpenCode 教程第 4 章) |
| 多客户端复用 | 同样的服务端 API,CLI Agent / 企业云也能调 |
这趟旅程是全书的「导航线」。后续每一章都能在旅程里找到对应:
💡 建议:把这张旅程图记住,读到后面章节时回头看一眼,你会一直清楚「我现在在旅程的哪一段」。
拓扑、哲学、旅程都清楚了,最后一节点出全书最精巧的设计——能力四源与 meta-MCP,作为第 2 章的高光收尾,也为第 7 章埋伏笔。