riceprompt-engine:把 Agent 工作流写进一个 YAML 文件
YAML-native agent workflow execution engine, written in Rust
秒懂
- 它是什么?
- 这个 Rust 引擎把节点、边、提示词、数据源和 MCP 工具全部收进一份声明式 YAML,解析依赖后按图执行。它适合已经在用 RicePrompt 或愿意手写工作流定义的团队,但 0.1.x 的 API 会随规范变动,锁死版本是前提。
- 适合谁用?
- 适合的读者是两类人:已经在用 RicePrompt 的可视化编辑器、需要把导出的 YAML 在服务端跑起来的团队,以及愿意为多 provider 编排和维护一份 YAML 规范、并且能接受 API 在 0.1.x 阶段变动的工程团队。不适合的人同样明确:不想读 docs/FLOW_SPEC.md 就想上手的人,或者需要稳定 API 承诺、准备把引擎嵌进长期产品的人,README 自己就建议 pin 一个精确版本。
- 能商用吗?
- 可以。Apache-2.0 是宽松许可证:你可以使用、修改并销售基于它的软件,只需保留版权和许可证声明。
- 还在维护吗?
- 在维护。仓库最近一次提交在 141 天前。
- 用什么语言写的?
- 主要是 Rust(依据 GitHub 的语言统计)。
以上回答依据项目的 GitHub 数据(最近同步于 2026年9月15日)和我们的分析,不构成法律意见。
开源项目深度解析
它解决的是工作流定义的散落问题
多数 Agent 项目的编排逻辑散在代码里:节点顺序写在函数调用链中,提示词存在字符串常量或模板表里,数据源连接参数放在环境变量和配置文件的混合体中。换一个模型供应商,要改的是代码。riceprompt-engine 的取舍是把这些全部外化成一份 YAML,README 的原话是整个工作流(图、提示词、数据源、provider)都在一个声明式文件里,权威规范在 docs/FLOW_SPEC.md。
目标用户不是终端用户,而是构建 Agent 产品的工程团队。README 里有一句关键交代:这个引擎驱动 RicePrompt,一个可视化 Agent IDE,用户在图编辑器里设计工作流、在浏览器里运行、再导出成同样的 YAML。也就是说 YAML 是引擎和 IDE 之间的接口格式,引擎本身是可独立依赖的 crate,包名 riceprompt-engine,版本 0.1。Rust 加上声明式格式,意味着工作流可以被版本控制、被 diff、被非 Rust 开发者阅读,这是把编排从代码里剥离出来的直接收益。
节点类型和边构成的执行图
工作流的结构由 nodes 和 edges 两个顶层字段描述。README 列出的节点类型包括 generate、transform、iterator、supervisor、subgraph、data_connector、skill_set,以及 mcp 和 mcp_tools。generate 负责 LLM 调用,transform 用 Rhai 脚本做数据变换,iterator 遍历数据,supervisor 做多 Agent 路由,subgraph 允许工作流嵌套,data_connector 对接内置数据源,skill_set 被描述为渐进式披露的知识包,mcp 系列节点用于 Model Context Protocol 工具调用。
数据在节点之间通过 variables 映射传递,写法是字符串路径,比如 start.name 或 greet.output。这不是类型化的数据流,而是一套约定俗成的引用语法,写错路径的代价取决于引擎的校验时机,README 没有说明这一点。provider 配置在顶层 providers 段声明,示例里 openai 的 api_key 用 ${OPENAI_API_KEY} 形式从环境变量取值。templates 段单独存放提示词,用 {{name}} 做插值,节点通过 template 字段引用模板名。
执行结果方面,README 提到 ExecutionResult 可以带上源 YAML,这样下游工具只凭一个文件就能渲染拓扑结构和每个节点的结果。这个设计对调试和可视化很有用,代价是结果体积会随工作流变大。
最小的三节点工作流长什么样
README 给的 hello_world 例子值得逐段看。version 固定为 "1.0",name 是 hello_world。providers 段里 openai 只声明了 api_key。nodes 有三个:start 节点类型为 start,不带 config;greet 节点类型为 generate,config 里指定 provider: openai、model: gpt-4o-mini、template: tpl_greet,variables 把 name 映射到 start.name;response 节点类型为 response,config.output 里把 greeting 映射到 greet.output。edges 是两条直线连接,start 到 greet,greet 到 response。templates 段的 tpl_greet 只有一行 user_prompt:Greet {{name}} warmly in one sentence.
运行入口是 Rust 代码。Engine::builder().build() 构造引擎实例,engine.run_yaml(&yaml, json!({ "name": "Ada" })) 传入 YAML 字符串和初始输入,返回的结果用 serde_json 序列化打印。依赖声明是 riceprompt-engine = "0.1"。README 说 examples/ 目录下有更多可运行的例子,但没有列出具体文件名。
这里有一个容易被忽略的细节:run_yaml 接收的是 YAML 文本而不是文件路径,所以工作流可以从数据库、HTTP 响应或构建产物里来,不限于本地文件。这对把工作流定义集中托管的场景是必要的。
多 provider 与内置连接器的实际覆盖范围
README 列出的 LLM 供应商包括 OpenAI、Anthropic、Gemini、DeepSeek、Qwen、Zhipu、Moonshot、MiniMax、xAI、Huoshan,以及任何 OpenAI 兼容端点。最后一项是关键:真正的覆盖面来自 OpenAI 兼容协议,而不是逐个适配的列表长度。流式输出、工具调用和结构化输出被描述为跨 provider 的一等能力,但 README 没有给出各 provider 在结构化输出上的行为差异,这类差异在真实项目里往往是踩坑点。
数据连接器包括 PostgreSQL、MySQL、MongoDB、Redis、Qdrant、S3 兼容对象存储和 REST API。Qdrant 的出现说明向量检索被当作一等数据源而非外挂,这对 RAG 类工作流是合理的默认。但连接器列表只说明了能连什么,没有说明连接池、超时、重试和凭据轮换怎么配置,这些只能去 docs/FLOW_SPEC.md 里找。
harness 层是另一个值得单独看的机制:工作流级别的指令,README 类比为 CLAUDE.md 风格,会被注入到每一个 generate 节点,并支持持久化记忆。这是一种全局上下文注入,好处是不用在每个模板里重复系统提示,风险是它会影响所有 generate 节点的行为,调试单个节点时容易忽略这层注入的存在。
0.1.x 的版本承诺与升级成本
README 的项目状态段落写得很直白:0.1.x 阶段,规范稳定之前 API 可能在次版本之间变化,如果需要稳定性请 pin 一个精确版本。这句话决定了引入方式。在 Cargo.toml 里写 riceprompt-engine = "0.1" 会接受 0.1.x 内的所有补丁和次版本,而 README 明确说次版本可能破坏 API,所以更稳妥的写法是锁定到具体版本号。
升级成本不只来自 Rust API。YAML 本身也是接口,docs/FLOW_SPEC.md 是权威规范,贡献指南要求改动 YAML 表面的 PR 必须在同一个 PR 里更新这份规范。这意味着 YAML 字段名和节点类型也会演进,工作流文件需要跟着改。对于把工作流 YAML 存进数据库或对象存储的团队,升级引擎时还要考虑存量工作流的迁移,而 README 没有提到任何迁移工具或兼容层。
许可证方面,README 的 License 段落说按 Apache-2.0 或 MIT 双许可,由使用者选择,仓库元数据标注的是 Apache-2.0。贡献条款里写明,除非明确声明,任何有意提交的贡献都按上述双许可授权。这是常见的 Rust 项目双许可模式,具体义务需要自行核对 LICENSE-APACHE 和 LICENSE-MIT 文件,这里不构成法律意见。
什么时候它不合适
最明显的不合适场景是只需要单次 LLM 调用。如果任务就是一次 prompt 进、一次文本出,引入一个图引擎、一份 YAML 规范和一套模板引用语法,换来的是额外的抽象层和调试路径。直接用供应商 SDK 更短。
第二类不合适是要求稳定 API 承诺的嵌入式场景。README 自己建议 pin 精确版本,这等于承认当前不提供稳定性保证。把 0.1.x 的引擎嵌进一个要维护数年的产品,每次升级都要读规范变更并迁移存量 YAML,这个成本需要提前算进去。
第三类是数据流需要强类型校验的场景。variables 和 output 都用字符串路径表达引用,README 没有说明引擎在解析阶段是否会校验路径存在、类型是否匹配。如果工作流复杂到几十个节点,路径写错可能要到运行时才暴露,而且错误信息是否指向具体节点也不确定。这一点在采用前应该用 examples/ 里的例子实测,而不是假设。
还有一个诚实的空白:README 提到面向用户的使用指南(skill guide)会单独发布,说明当前文档的重心是规范而不是教程。只有 docs/FLOW_SPEC.md 和 examples/ 目录可用,学习曲线主要靠读规范。
和直接写代码编排的差别在哪
一个自然的替代方案是不用引擎,直接用 Rust 异步代码加供应商 SDK 手写编排。两者的差别不在能力而在边界位置。手写代码时,控制流是 Rust 的,条件分支、循环、错误处理都用语言本身的机制,类型检查在编译期完成,调试用常规的断点和日志。代价是工作流定义和实现绑死,非 Rust 开发者改不了,可视化工具也没法从代码反向生成图。
riceprompt-engine 把这条边界推到了 YAML 上。控制流变成 edges 和节点类型,数据传递变成路径字符串,条件判断和循环要靠 iterator、supervisor 这类节点表达。收益是同一份 YAML 可以被 RicePrompt 的图编辑器读取和生成,可以被版本控制 diff,可以被引擎的 ExecutionResult 连同拓扑一起回传。损失是编译期检查让位给解析期或运行期校验,具体到哪一层,README 没有交代。
这个取舍对谁划算,取决于工作流是否需要被非工程师编辑,以及是否需要一个可视化前端。如果两个答案都是否,手写代码编排的反馈回路更短。如果答案都是是,YAML 作为中间格式的价值就体现出来了,因为它同时是引擎的输入和 IDE 的输出。
编辑结论
适合的读者是两类人:已经在用 RicePrompt 的可视化编辑器、需要把导出的 YAML 在服务端跑起来的团队,以及愿意为多 provider 编排和维护一份 YAML 规范、并且能接受 API 在 0.1.x 阶段变动的工程团队。不适合的人同样明确:不想读 docs/FLOW_SPEC.md 就想上手的人,或者需要稳定 API 承诺、准备把引擎嵌进长期产品的人,README 自己就建议 pin 一个精确版本。动手前先确认三件事:docs/FLOW_SPEC.md 是否覆盖你要用的节点类型,harness 层的持久化记忆存在哪里,以及 checkpoint/resume 的恢复语义是否满足你的中断场景。
社区笔记