正在统计访客…
浏览全部文档
开始 · 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 存储管理兼容性与可信发布
文档/构建 Agent
第一次使用?通过 45 分钟核心课程建立完整心智模型
构建 Agent

为 Agent 添加类型化工具

通过 JSON Schema 暴露异步 Rust 函数,同时避免授予环境中的隐式权限。

实践指南·12 min

定义工具

Runifold Tool 具有稳定描述、JSON 输入 Schema、副作用分类与异步执行边界。普通的 类型化函数优先使用 #[runifold::tool] 宏。

先加入派生宏依赖:

cargo add serde --features derive
cargo add schemars
use runifold::{JsonSchema, ToolContext, ToolError, tool};
use serde::{Deserialize, Serialize};
 
#[derive(Debug, Deserialize, JsonSchema)]
struct WeatherInput {
    city: String,
}
 
#[derive(Debug, Serialize, JsonSchema)]
struct Weather {
    city: String,
    celsius: i32,
}
 
#[tool(description = "Get the current temperature for a city")]
async fn current_weather(
    input: WeatherInput,
    _context: ToolContext,
) -> Result<Weather, ToolError> {
    weather_service::lookup(&input.city).await
}

输入应该使用领域类型,而不是到处传递字符串集合。校验应发生在边界上,并且早于 任何外部工作。

注册工具

只在真正需要它的 Agent 上注册工具:

let agent = runtime
    .agent("travel-planner")
    .tool(current_weather_tool())
    .max_turns(6)
    .build()?;

重复名称,以及与子 Agent 路由同名,都会产生构建错误。工具被注册后也不会自动对 所有子 Run 可用;执行时仍然需要对应的 Capability 授权。

返回富结果

0.9.0 开始,手写 Tool 返回 ToolOutput,不再把所有结果压成一个标量。应根据 真实边界选择构造器:

需求构造器语义
普通 JSON 或文本ToolOutput::model_visible(value)同时保留结构化 JSON 与文本回退
有序文本、图片、音频、文档或资源ToolOutput::rich(parts)保留与 Provider 无关的内容顺序
可恢复的领域失败ToolOutput::model_error(parts)Tool 已执行,但应用拒绝请求;模型可以处理
仅宿主可见的数据ToolOutput::host_only(parts)如果代码试图暴露给模型,会失败关闭

with_structured_content 附加独立验证的输出,用带命名空间的 with_metadata 保存 应用侧注释。ToolError 仍表示 Tool Runtime 执行失败;model_error 则是已经完成、允许 模型看到的应用结果。

0.3.x 升级时,手写的 ToolOutput { value, ... } 必须迁移到上述构造器之一。

让二进制 Artifact 远离 Transcript

大型 Tool 输出在 Conversation 与 Checkpoint 中应该保存引用,而不是 Base64。先在 Agent 上配置一个 ArtifactStore 与经过校验的 Scope:

use std::sync::Arc;
use runifold::{ArtifactScope, InMemoryArtifactStore};
 
let artifact_store = Arc::new(InMemoryArtifactStore::new());
let agent = runtime
    .agent("report-analyst")
    .artifacts(ArtifactScope::parse("tenant.acme")?, artifact_store)
    .tool(render_chart_tool())
    .build()?;

Tool 内部从 ToolContext 取得 Store 与 Scope,使用稳定的幂等键写入,再把生成的 ArtifactRef 作为 MediaSource::Artifact 返回。Runifold 只会在最终 Provider 传输边界 加载并校验字节。

测试使用 InMemoryArtifactStore,单个持久进程使用 SqliteStore,共享生产 Worker 使用 PostgresStore。每个引用都会绑定 Scope、MIME、字节长度、SHA-256、可选名称与过期时间; 分页、删除和过期清理也不会越过 Scope。

Provider 支持是显式的:OpenAI Responses 与 Gemini 保留原生多模态 Tool Result;Anthropic 支持文本、图片和资源;Bedrock 支持 JSON、图片和文档。纯文本 Chat Completions 与 Ollama 遇到不支持的媒体会明确报错,不会悄悄转成字符串。

权限与副作用

工具注册回答“这个 Agent 可能调用什么”,RunContext Capability 回答“这次执行 允许调用什么”,两者必须同时满足。

外部动作应该被准确分类:

  • 纯读取通常可以安全重试;
  • 幂等写入需要稳定的幂等键;
  • 非幂等写入在传输结果不确定时必须失败关闭;
  • 删除或高风险操作应该通过应用策略审核。

需要恢复的写操作应使用预写 Effect 边界:先记录执行意图,再进行外部调用,并在 结果已经完成时直接重放结果,而不是重复执行动作。

处理工具错误

ToolErrorPolicy 决定工具失败是作为模型可见输入,还是直接终止 Agent。模型可见 错误不能包含 Secret、原始凭证、数据库 URL 或内部堆栈。

运维错误应该保留足够结构,让应用能够决定重试、补偿、请求人工介入或终止 Run。