45 分钟掌握 Runifold
建立正确心智模型,完成真实运行,加入类型契约与执行约束,并选择下一步学习路线。
五个检查点,建立一套可工作的心智模型。
本课程用一个 Agent 作为贯穿执行内核与模型层的紧凑纵向示例。Runifold 也可以直接作为 模型协议、持久 Workflow Runtime、MCP 边缘、评测系统或可观测层使用。其他入口见 完整平台地图。
建立心智模型
理解 Runifold 最快的方法,是先记住一条执行路径:
- Provider:转换某个模型服务商的传输协议。
- Runtime:围绕模型身份加入路由与安全传输行为。
- Agent:组合指令、可调用工具与轮次策略。
- Run:携带身份、生命周期、预算、权限与 Journal 事件。
- Outcome:同时保留可见文本、用量和执行事实。
最值得记住的一句话是:模型提出要做的工作;Run 决定什么可以发生,以及如何记账。
**检查点:**不看上文,回答认证、工具、预算和最终文本分别属于哪一层。如果答案依次是 Provider、Agent、Run 与 Outcome,就可以继续。
完成第一次运行
创建项目,加入稳定运行时,并只选择真正使用的 Provider Adapter:
cargo new hello-runifold
cd hello-runifold
cargo add runifold@0.9.0
cargo add runifold-providers@0.9.0 --features openai
cargo add tokio --features macros,rt-multi-thread
export OPENAI_API_KEY="your-api-key"用下面的完整程序替换 src/main.rs:
use runifold::ProviderModelExt;
use runifold_providers::openai::OpenAiClient;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let runtime = OpenAiClient::from_api_key(
std::env::var("OPENAI_API_KEY")?
)?
.runtime("gpt-5")?;
let answer = runtime
.agent("assistant")
.system("Answer precisely and expose uncertainty.")
.prompt_text("Explain one benefit of durable execution.")
.await?;
println!("{answer}");
Ok(())
}执行 cargo run。进程正常退出并打印一段回答就表示成功。模型输出并不确定,因此不要把
具体措辞当作测试结果。
**从外向内阅读代码:**Client 负责认证,runtime 选择模型边缘,agent 定义行为,
prompt_text 创建一个便捷的根 Run。
建立类型化契约
文本适合直接展示给用户,应用逻辑通常应该接收 Rust 值。加入:
cargo add serde --features derive
cargo add schemars先定义契约,再构建结构化 Agent:
use runifold::JsonSchema;
use serde::Deserialize;
#[derive(Debug, Deserialize, JsonSchema)]
struct Triage {
category: String,
urgent: bool,
explanation: String,
}
let agent = runtime
.agent("triage")
.system("Classify the request. Keep the explanation short.")
.build_structured::<Triage>("triage_result")?;
let run = agent.agent().default_run_context();
let result = agent.run("Payment failed twice", &run).await?;
println!("{:?}", result.output);Schema 约束模型侧格式,反序列化建立 Rust 边界。解码之后仍然要用普通 Rust 执行业务 校验。契约失败时,不要悄悄退回未经验证的文本。
**检查点:**临时把 urgent 改成字符串。外围应用应该明确暴露契约不匹配,而不是猜测。
约束整次执行
默认 Context 很适合探索。在 HTTP 请求、后台任务或工作流入口处,应该换成显式
RunContext:
use std::time::{Duration, Instant};
use runifold::{Budget, BudgetTracker, CapabilitySet, RunContext};
let run = RunContext::root(
BudgetTracker::new(Budget {
tokens: Some(20_000),
turns: Some(8),
tool_calls: Some(4),
..Budget::default()
}),
CapabilitySet::new(),
)
.with_deadline(Instant::now() + Duration::from_secs(20));它为所有后代建立一个共享执行信封。子 Agent 与 Tool 从同一棵记账树消费预算、观察取消, 并且只得到显式授予的 Capability。
分清下面三组概念,可以避免大多数设计错误:
| 不要混淆 | 正确边界 |
|---|---|
| 聊天记录与执行状态 | Transcript 是模型上下文;RunContext 是控制状态 |
| 已注册工具与执行权限 | 注册说明什么存在;Capability 说明本次 Run 可以用什么 |
| 网络 Timeout 与 Deadline | Timeout 限制一次操作;Deadline 限制整棵 Run 树的有效寿命 |
通过上线检查点
现在你已经掌握稳定内核。只选择产品真正需要的分支:
| 产品需求 | 接着阅读 | 可以暂缓 |
|---|---|---|
| 面向用户的聊天 | 会话与记忆 | 工作流 |
| 调用应用函数 | 类型化工具,写操作再读 Effect | 委派 |
| 协调多个专业角色 | Agent 委派 | 持久工作流 |
| 跨重启或长时间等待 | 工作流,再读持久工作流 | 流式输出 |
| 必须满足质量基线 | 测试,再读质量评估 | 更多 Provider |
| 需要生产证据 | 可观测性、可靠性 | Edge 与 WASM |
上线一个功能前,回答六个问题:
- 根 Run 的边界在哪里?
- 已验证哪个模型与 Provider 行为?
- 本次 Run 可以使用哪些 Capability?
- 什么限制 Token、轮次、工具调用和总时长?
- 哪些外部写操作是幂等或可恢复的?
- 如何解释并复现一次失败的 Run?
如果任何答案是“Prompt 会处理”,上线前先把这份责任移到类型化 Rust 策略中。