部署指南
在 Rust Web Service 中部署 Runifold
构建完整 Axum API,把凭证和策略放在服务端边界,并在流式响应与持久后台任务之间选择。
把 Runifold 放在应用服务边界之后
Web Service 应负责 Provider 凭证、用户认证、Admission、Run 构建、错误映射与可观测性。 浏览器只把产品输入发送给你的服务,不能持有长期密钥直接调用模型 Provider。
client → authentication → admission → RunContext → Agent → Provider
↘ journal / metrics / tracesProvider Client 与 Runtime 在启动时创建一次。请求级策略使用新的 Agent 或 RunContext。
构建完整的 Axum 服务
cargo new runifold-api
cd runifold-api
cargo add runifold@0.9.0
cargo add runifold-providers@0.9.0 --features openai
cargo add axum@0.8
cargo add serde@1 --features derive
cargo add tokio@1 --features macros,rt-multi-thread,net替换 src/main.rs:
use axum::{Json, Router, extract::State, http::StatusCode, routing::post};
use runifold::{ProviderModelExt, ProviderRuntime};
use runifold_providers::openai::OpenAiClient;
use serde::{Deserialize, Serialize};
#[derive(Clone)]
struct AppState { runtime: ProviderRuntime }
#[derive(Deserialize)]
struct PromptRequest { prompt: String }
#[derive(Serialize)]
struct PromptResponse { answer: String }
async fn prompt(
State(state): State<AppState>,
Json(request): Json<PromptRequest>,
) -> Result<Json<PromptResponse>, (StatusCode, String)> {
let answer = state.runtime
.agent("http-assistant")
.system("Answer precisely and expose uncertainty.")
.prompt_text(request.prompt)
.await
.map_err(|error| (
StatusCode::BAD_GATEWAY,
format!("model request failed: {error}"),
))?;
Ok(Json(PromptResponse { answer }))
}
#[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 app = Router::new()
.route("/prompt", post(prompt))
.with_state(AppState { runtime });
let listener = tokio::net::TcpListener::bind("127.0.0.1:3000").await?;
axum::serve(listener, app).await?;
Ok(())
}设置 OPENAI_API_KEY,运行 cargo run,然后向 POST /prompt 发送 JSON。这个完整服务
会在文档 CI 中编译。
对外开放前增加请求策略
最小服务只能证明集成成功,还不是生产安全边界。请补充:
- 已认证的 Tenant 与 Actor Identity;
- 输入长度和 Body Size 限制;
- 按租户的 Admission 与并发限制;
- 包含 Token、Turn、Tool 和 Wall Time 预算的显式
RunContext; - 由授权结果派生的 Capability,绝不能来自请求 JSON;
- 客户端断连时取消 Run;
- 不泄露 Provider Body 的稳定公开错误码。
请求信封请继续阅读 RunContext、 预算与 Capability 安全。
选择流式响应或后台任务
用户等待增量输出时使用 SSE 或 WebSocket。必须保留成功、拒绝、用量与失败终态,不能把 Stream 简化成纯文本 Chunk。
任务需要跨进程恢复、等待 Signal 或在 HTTP 请求结束后继续运行时,使用持久 Workflow。 HTTP 层返回 Task ID,由 Worker 接管执行;不要为了数小时任务一直保持连接。
通过部署检查
上线前确认:
- Secret 只从部署环境进入;
- Health Check 不调用付费模型;
- Graceful Shutdown 会取消或交接活跃 Run;
- 只有被标记为安全的错误才重试;
- 日志能关联 Tenant、Run、Provider 与模型且不包含敏感内容;
- 延迟、错误、拒绝、预算与饱和度指标有告警;
- 一个 Live Smoke Request 验证了部署后的真实网络路径。