iii 入门:用 Worker、Trigger、Function 三个原语重构服务集成方式
2026/9/13 8:07:28 网站建设 项目流程

iii 入门:用 Worker、Trigger、Function 三个原语重构服务集成方式

【免费下载链接】iiiEffortlessly compose, extend, and observe every service in real-time for the first time ever.项目地址: https://gitcode.com/GitHub_Trending/mo/iii

本文基于 iii 官方文档的入门篇(Welcome to iii)撰写,解释 iii 将软件组织为 Worker、Trigger、Function 三个原语的设计动机,说明"新增能力即新增 Worker"的扩展模型与跨语言、跨运行时的一致性契约,并结合仓库中的引擎源码、配置文件与 Quickstart 实操流程,帮助读者建立对 iii 系统的完整心智模型并动手运行第一个项目。

问题背景:集成成本为何随规模二次方增长

现代系统中的每个服务都自带一套内部实现、一套生命周期、一套集成方式和一套故障模式。文档用组合数学给出了一个直观的数字:4 个服务意味着 6 条可能的集成边,20 个服务意味着 190 条。这里的"边"指任何一次新集成带来的跨系统交互——例如引入一个 Agent 框架,带来的不只是它与你现有系统之间的单个集成点,还有它的众多下游消费者。

结论是:每增加一个新能力,都会让栈中已有所有内容之间的协调成本按二次方复合增长。这种摩擦不止发生在两个系统对接的地方,它还会向下游扩散到日志、调试和升级环节,向上游阻塞新业务、新方向的探索。

仓库 README(README.md)中"Before iii / After iii"一节对这个问题做了呼应:

  • 引入新的可观测性工具:无法计数的集成工作;
  • 引入新的 Agent 框架:独立的重试配置、独立的追踪、独立的超时;
  • 引入新的队列:供应商评估、采购和数周的集成工作。

而在 iii 的模型下,这些事情收敛为:在worker-compose.yaml中声明 Worker、用iii compose --up运行,Worker 即进入系统、可追踪、可调用。

解决方案:Worker、Trigger、Function 三个原语

iii 把软件组织为三个原语:WorkerTriggerFunction。一句话概括分工:某物承载工作(Worker)、某物触发工作(Trigger)、某物执行工作(Function)。文档给出的论断是:系统中的所有能力都可以由这三样东西构成——队列、cron、流式传输、沙箱、可观测性、Agent、业务逻辑、设备,甚至前端浏览器 UI。

README.md 的"Three Primitives"一节给出了与源码一致的定义:

  • Worker是向 iii 引擎注册、进而注册 Trigger 和 Function 的进程。TypeScript API 服务、Python 数据管道、Rust 微服务都可以是 Worker;Compose 机制还支持在运行时动态添加 Worker,让 Agent 和应用在系统运行中扩展系统本身;
  • Trigger是让 Function 运行的一切原因:对 Function 的直接调用、HTTP 端点、cron 计划、队列订阅、状态变更、流事件等。Trigger 是声明式的——Worker 定义"当某事发生时运行这个 Function",由 iii 负责路由、序列化和投递;
  • Function是带稳定标识符(如content::classifyorders::validate)的工作单元,接收输入、执行工作、可选地返回输出,且必须存在于某个 Worker 内。

从二次方到零:加入系统是"单连接"操作

iii 把上述集成成本降到零的方式,是让"加两个 Worker"和"加两百个 Worker"成为同一种操作。一个新 Worker 加入系统只需要打开一条到引擎的 WebSocket 连接,从那一刻起它立即对系统中的其他所有 Worker 可见。

仓库中这一模型有直接的实现对应。引擎侧的 Worker 管理逻辑集中在 engine/src/workers/ 目录下,其中的 registry.rs 维护已连接 Worker 的注册表;引擎的默认配置 engine/config.yaml 展示了 Worker 声明形态——每个 Worker 有nameconfig,例如iii-stream声明 Redis 适配器监听127.0.0.1:3112

workers: - name: iii-stream config: port: ${STREAM_PORT:3112} host: 127.0.0.1 adapter: name: redis config: redis_url: redis://localhost:6379

配置文件还注明了一条重要的职责边界:只有属于引擎生命周期本身的 Worker 才写进config.yaml,而项目级 Worker(http、state、cron、queue、pubsub、bridge 等)应放进worker-compose.yaml——这正是"加 Worker 是运行期操作"的落地。

文档在"加入系统"之外还强调了一个拓扑性质(可在 understanding-iii 概览 中验证):Worker 之间没有直连流量caller-worker调用math::add时,调用经由引擎完成,引擎在其注册表中查找math::add的当前持有者并路由过去。每条边都是"Worker 与引擎之间"的 WebSocket,而不是 Worker 与 Worker 之间的私有协议。

有新需求?加一个 Worker

文档用一节"Have a Need? Add a Worker"给出了 iii 最核心的操作范式:

  • 需要队列?加一个 Worker。
  • 需要实时流、调度、沙箱、可观测性、Agent、CRM 集成,甚至一个以 Worker 身份参与的浏览器标签页?加一个 Worker。
  • 有些 Worker 是确定性代码,有些 Worker 是概率性的 Agent——在系统层面没有区别。

iii worker add被文档称为"系统领域的 npm 时刻":它安装的不是库,而是一个完整的运行中的服务——队列 Worker、沙箱 Worker、分类器,一条命令换来一项完整能力,且立即可被系统中其他所有 Worker 使用。

这一命令在 Quickstart(docs/0-13-0/quickstart.mdx)中的完整实操流程可以完整继承:

# 1. 安装引擎 curl -fsSL https://install.iii.dev/iii/main/install.sh | sh iii --version # 2. 脚手架一个跨语言示例项目 iii project init quickstart --template quickstart cd quickstart # 3. 启动引擎(默认监听 ws://localhost:49134) iii --config config.yaml

quickstart模板生成两个 Worker:一个注册math::add、把求和结果写入 state 的 Python Worker,以及一个暴露 HTTP 端点并通过引擎调用 Python Worker 的 TypeScript Worker:

workers/ math-worker/ math_worker.py # Python worker caller-worker/ src/worker.ts # TypeScript worker

然后逐条增量扩展,全程不需要重启系统:

# 添加并自动启动本地 Worker iii worker add ./workers/math-worker # 跨语言调用:TypeScript -> 引擎 -> Python iii trigger math::add a=2 b=3 iii trigger math::add_two_numbers a=10 b=20 # => { "c": 30 } # 增量添加注册表中的平台能力 Worker iii worker add iii-state # 为所有 Function 提供持久化键值存储 iii worker add iii-http # 把 Function 暴露为 REST 端点

添加iii-state后,Quickstart 展示了如何零停机给已有 Worker"接上"状态能力——在 Python 处理函数中直接触发state::get/state::set

running_total = worker.trigger( { "function_id": "state::get", "payload": {"scope": "math", "key": "running_total"}, } ) new_total = (running_total or 0) + result["c"] worker.trigger( { "function_id": "state::set", "payload": {"scope": "math", "key": "running_total", "value": new_total}, } )

调用iii trigger math::add a=10 b=20即可看到{"c": 30, "running_total": 35}——累加值在每次调用间持久化,包括经由math::add_two_numbers转发的调用。类似地,添加iii-http后,同一批 Function 无需改动处理函数本身即可响应POST /math/add-two-numbers

这里有一个值得注意的细节(Quickstart 的 Tip 指出):Worker 被添加后需要几秒安装运行时依赖,过早调用会看到"message": "Function math::add not found",稍等重试即可。另外,iii worker add的输出会显示Using cached deps (use --force to reinstall),说明依赖有缓存机制,可用--force强制重装。

同一份契约,两个方向

文档"Same Contract, Both Sides"一节描述了 iii 对团队分工的重新切分:

  • 应用团队:注册 Function、声明 Trigger,专注于业务逻辑;
  • 平台团队:发布 Worker,专注于自己提供什么能力;
  • 双方履行同一份契约:不需要定制的 SDK、不需要内部客户端库、不需要逐服务定义 API 契约。过去活在团队之间的那部分工作直接消失。

README.md 的"What Changes"一节用三行总结了这一分工:"Platform teams publish workers. Application teams register functions and declare triggers. Agents use the same catalog and the same function calls."——Agent 与应用团队使用的是同一个目录、同一套函数调用,这一点是后文"为 Agent 而生"的基础。

任意语言、任意运行时

文档"Any Language, Any Runtime"一节的论断是:Docker 里的 Worker、Kubernetes 上的 Worker、边缘节点、浏览器标签页、树莓派、硬件隔离 microVM 里的 Worker,是同一种 Worker。迁移工作负载是一次重新部署,而不是一次重写;引擎负责序列化和路由。

仓库中这一"任意运行时"主张有三处实现层面的佐证:

  1. Worker 契约小到任何语言都能实现。understanding-iii/workers 明确写道:"worker 契约小到任何能使用 WebSocket 和 JSON 的语言都能实现"。仓库同时提供 Node(sdk/packages/node)、Python(sdk/packages/python)、Rust(sdk/packages/rust)和 Go(sdk/packages/go)四套 SDK,且文档强调引擎与 SDK 应保持同一 minor 版本线(例如0.11.x),见 install 指南。
  2. 路由对语言、运行时和位置无感知。understanding-iii/engine 指出引擎对"Function 由笔记本上的 Python Agent、浏览器标签页里的 TypeScript Worker、microVM 里的 Rust 二进制还是 Kubernetes 上的 OCI 镜像承载"应用同一条路由路径。
  3. 隔离性由进程边界保证。Worker 被设计为独立进程:一个 Worker 崩溃不影响其他 Worker;引擎对每个 Worker 维持独立 WebSocket,只把调用路由给当前在线的 Worker。崩溃 Worker 的 Function 和 Trigger 在断连时从路由表移除,其余 Worker 继续服务。

为 Agent 而生:Agent 就是 Worker

文档"Built for Agents"一节是全文最有观点的部分,其核心论证可以拆成四点:

  1. 多数 Agent 框架只解决了问题的一片:聊天循环、工具调用沙箱、链式工作流。iii 不是给 Agent 用的框架(harness),它更好用的原因在于——它就是整个系统本来就运行的那个运行时,因此 iii 是"天然 Agent 化"的。

  2. Agent 即 Worker。在 iii 中,一个 Agent 是一个 Worker,可以在获得权限后作用于系统的每一部分,而不是被关进一个专为 Agent 造出来的隔离运行时。Agent 的工具就是 Function,它的记忆就是 state,它的编排就是 Trigger。Agent 不需要调用一个独立的"Agent 运行时"来干活——运行时就是系统的其余部分。

  3. 系统可以在运行中被 Agent 扩展。一个 Agent 遇到超出当前能力的任务时,可以运行时注册一个新 Worker、暴露新的 Function,从而扩展它所运行的系统本身。README 中给出的 compose 示例正是这条路径的最小演示:

    iii compose --namespace dev --up iii trigger -n dev compose::add worker=queue iii trigger -n dev compose::add worker=agent iii trigger -n dev compose::add worker=<anything>

    每次compose::add之后,新 Worker 加入实时目录,其余所有 Worker 被通知并可立即调用它。

  4. 人与 Agent 共享同一心智模型。新工程师第一天就能上手,因为从一种能力切换到下一种能力时心智模型不变;AI Agent 之所以能在单个上下文窗口内可靠地推理整个系统,是因为只有一套原语需要学习,并且存在一个"关于系统里到底有什么"的永远准确的真相来源(即引擎的实时注册表,见 understanding-iii/engine 的"Discovery and the live registry"一节)。文档最后的推论是:随着 Agent 承担越来越多构建与运维工作,原语集合的大小会成为复利变量——越小的原语集意味着越容易上手、越便宜的提示词、更快的扩展、更简的维护。

动手上手:安装、Quickstart 与继续学习

文档"Getting Started"一节的建议是:理解 iii 最好的方式是动手。安装引擎后按 Quickstart 创建第一个项目。完整路径为:

  1. 安装引擎:见 docs/0-13-0/install.mdx,核心命令为curl -fsSL https://install.iii.dev/iii/main/install.sh | sh,随后用iii --version验证;
  2. 跑通 Quickstart:见 docs/0-13-0/quickstart.mdx——脚手架一个 Python + TypeScript 双 Worker 项目,跨语言调用 Function,增量添加iii-state获得持久化状态、添加iii-http暴露 REST 端点,全程零停机;
  3. 建立概念模型:understanding-iii 概览 以 Quickstart 项目为例,逐一拆解 Worker、Trigger、Function、Engine 四个部件,包括"Worker 声明 Trigger 有registeredactiveinvokedunregistered四个状态""一个 Function 可挂任意多个 Trigger"等细节;
  4. 观察运行中的系统:在新终端运行iii console,打开交互式 Console,实时查看 Worker、Function、Trigger、日志、追踪和 state,参见 docs/0-13-0/using-iii/console.mdx。

小结

iii 入门篇(docs/0-13-0/index.mdx)传递的技术主张可以浓缩为三句话:

  • 集成边的数量随服务数二次方增长,iii 的答案是让新服务只维护"到引擎的一条 WebSocket"这条边,把 N² 问题降为 N 条同构连接;
  • 一切能力(队列、调度、沙箱、可观测性、Agent、业务逻辑)统一表达为 Worker,用iii worker add/iii compose增量装配,用service::name形式的 Function 标识符跨语言寻址;
  • 应用团队与平台团队(以及 Agent)在同一个契约上协作:注册 Function、声明 Trigger、发布 Worker,引擎负责注册表、路由与故障隔离。

仓库中 engine/ 目录(含 engine/config.yaml、engine/src/workers/ 的注册表与 Worker 生命周期实现)与四套语言 SDK(sdk/packages/)共同支撑了这些主张;而 docs/0-13-0/understanding-iii/ 系列页面则是从概念走向实现细节的直接入口。

【免费下载链接】iiiEffortlessly compose, extend, and observe every service in real-time for the first time ever.项目地址: https://gitcode.com/GitHub_Trending/mo/iii

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询