正在统计访客…
浏览全部文档
开始 · 9找到适合你的 Runifold 学习路径45 分钟掌握 Runifold理解完整的 Runifold 平台第一次可信运行选择正确的执行 API选择 Crate 与 Cargo Feature构建常见 Runifold 应用Runifold 常见问题排查 Runifold 应用故障
执行内核 · 7理解 RunContext安全协调外部副作用使用预算与取消限制工作安全地处理错误与重试事件、Journal 与执行证据设计 Capability 安全执行从 Checkpoint 安全恢复
模型与服务商 · 7在避免重复输出的前提下路由模型选择并配置模型服务商使用服务商中立的模型协议基于 Provider Runtime 契约构建使用 OpenAI 控制面与 Realtime API测试与 Benchmark Provider Adapter配置 OpenAI、Anthropic、Gemini 与 Ollama
Agent · 7构建并配置 Agent为 Agent 添加类型化工具加入会话与语义记忆安全地委派给子 Agent返回结构化 Rust 值在不丢失语义的前提下流式输出使用检索为 Agent 提供事实依据
持久工作流 · 7组合确定性工作流让工作流持久化运行持久工作流 Worker协调 Timer、Signal 与持久等待运行多租户工作流基础设施运行并行 Branch 与安全 Race对持久 Workflow 进行版本管理
集成 · 7通过 MCP 连接外部能力选择存储与持久化边界通过 MCP Tasks 暴露持久工作构建并评估检索流水线使用 MCP Resources、Prompts 与 Sampling在不跨越权限的前提下缓存 MCP 响应在 Rust Web Service 中部署 Runifold
质量与运维 · 10在没有网络的情况下测试评估质量并阻止回归观测完整运行树在浏览器与边缘环境安全运行准确理解可靠性声明在 CI 中运行可复现评测使用 SLO 运维 Runifold治理 Task 保留与删除把审计证据归档到 S3-Compatible WORM 存储管理兼容性与可信发布
文档/生产实践
第一次使用?通过 45 分钟核心课程建立完整心智模型
生产实践

在没有网络的情况下测试

使用脚本模型、确定性辅助工具、协议 cassette 与评估门槛。

实践指南·16 min

测试分层

使用精简的测试金字塔:

  1. 策略、Schema 与工作流条件的纯单元测试;
  2. 使用脚本模型和工具的确定性 Agent 测试;
  3. 使用脱敏 Cassette 的协议契约测试;
  4. 少量真实服务商在线冒烟;
  5. 版本化质量评测。

大部分应用正确性不应该依赖真实模型或网络。

脚本模型

添加 runifold-testkit 开发依赖,使用 ScriptedModel 返回已知模型响应序列。断言最终 结果、Transcript、工具调用、事件与用量。

Cargo.toml
[dev-dependencies]
anyhow = "1"
runifold = "=0.9.0"
runifold-testkit = "=0.9.0"
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }

下面的测试不会访问网络,也不需要 API Key:

tests/agent.rs
use std::{collections::BTreeMap, sync::Arc};
 
use runifold::{
    Agent, ContentPart, FinishReason, ModelRef, ModelStreamEvent,
};
use runifold_testkit::ScriptedModel;
 
#[tokio::test]
async fn agent_returns_the_scripted_answer() -> anyhow::Result<()> {
    let model = ScriptedModel::new();
    model.enqueue([
        ModelStreamEvent::ResponseStarted {
            id: Some("response-1".into()),
            model: ModelRef::new("test", "scripted"),
        },
        ModelStreamEvent::ContentPartCompleted {
            index: 0,
            part: ContentPart::text("approved"),
        },
        ModelStreamEvent::ResponseCompleted {
            finish_reason: FinishReason::Stop,
            provider_metadata: BTreeMap::new(),
        },
    ]);
    let observed = model.clone();
    let agent = Agent::builder(
        "reviewer",
        Arc::new(model),
        ModelRef::new("test", "scripted"),
    )
    .system("Return one review decision.")
    .build()?;
 
    let answer = agent.prompt_text("Review order 42").await?;
 
    assert_eq!(answer, "approved");
    assert_eq!(observed.recorded_requests().len(), 1);
    Ok(())
}

cargo test --test agent 只运行这项集成测试。如果需要在执行后检查模型收到的 Request 或调用上下文,应先 Clone ScriptedModel,再把另一个实例交给 Agent。

除正常路径外,还要覆盖工具参数损坏、权限拒绝、预算耗尽、取消、服务商拒绝与最大 轮次。

服务商 Cassette

Cassette 可以验证 HTTP 编解码,而不让 CI 依赖服务商。提交前必须移除认证信息、 Cookie、请求 ID 与用户正文。

把 Cassette 格式与端点版本视为测试 Fixture。协议行为变化时显式刷新,不能在测试 中自动更新。

质量评测

模型行为具有概率性,应评估可观察的产品属性:分类正确性、引用依据、拒答行为、工具 选择、延迟与成本。

Prompt、数据集、Grader、模型标识和验收阈值应一起版本化。需要查看失败案例,不能 只相信一个总分。

CI 门禁

每次修改运行格式化、Clippy、单元测试、文档示例、协议契约与离线评测。在线冒烟应 在受保护环境中运行,并设置严格预算。

必要能力变为 Unknown,或已验证服务商组合失去证据时,应阻止发布。

每个边界应该断言什么

边界应断言不应依赖
Agent最终 Outcome、Request 形状、轮次除非措辞就是契约,否则不要逐字匹配
Tool参数解析、Capability 检查、结构化结果让模型决定写操作是否安全
Stream事件顺序且只有一个终止事件拼接可见 Delta 作为最终答案
Workflow稳定 Step 输出、Usage、失败策略分支完成的实际时钟顺序
Provider Adapter规范请求与响应映射每个 PR 都访问真实端点
Evaluation单 Case 失败和阈值不检查失败样本的单一平均分

复现故障与恢复

runifold-testkit 0.9 提供可复用的断连、具名 Tool 失败、Runtime 重建与标准化 Golden Trace 边界:

use runifold_testkit::{FaultScenario, RecoveryHarness};
 
let faults = FaultScenario::new()
    .disconnect_after_tool_call()
    .fail_tool_on_invocation("charge", 2, injected_error);
let model = faults.model(scripted_model);
let mut runtime = RecoveryHarness::new(runtime_factory, faults.clone());
 
runtime.restart();
faults.assert_tool_executed_exactly("charge", 1)?;

对 0.9 Review Gate,要分别在 Review Ready、Review In-flight 与 Approved Plan Checkpoint 杀进程。断言 Ready Candidate 不会重新生成、已批准的 Tool Plan 只回放一次, 而不确定的 In-flight Review 在应用授予显式重试权限前会失败。Golden Trace 会去掉随机 ID 与时间戳,同时保留第一个因果差异。

测试失败排查

如果 ScriptedModel 提示没有排队的调用,先计算路径实际会调用模型几次:重试、 Tool 后续轮次和 Fallback 都会多消耗一个 Script。如果 Stream 无法完成,确认恰好包含 一个终止 ResponseCompleted 事件。如果在线测试不稳定,把协议正确性移入 Cassette 测试,只把在线测试保留为有严格预算的 Canary。