简体中文 | English
面向 TypeSafe AI HTTP API 的非官方异步 Rust binding。 使用 Tokio + reqwest,默认启用 rustls。
通过 crates.io 添加依赖:
cargo add jevapi
cargo add tokio --features macros,rt-multi-thread或者在 Cargo.toml 中配置:
[dependencies]
jevapi = "0.1"
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }将密钥放入 TYPESAFE_API_KEY 环境变量,然后调用:
use jevapi::{Answer, Client, EvaluationRequest, Question};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client = Client::from_env()?;
let request = EvaluationRequest::new("生产环境支付服务中断,请立即处理。")
.question("urgent", Question::noul("是否需要立即处理?"))
.question("team", Question::choice("应该分配给哪个团队?", [
("engineering", Some("故障和技术问题".into())),
("sales", None),
]))
.question("severity", Question::score("问题有多严重?", [
"轻微影响", "部分功能不可用", "生产服务中断",
]));
let response = client.evaluate(&request).await?;
if let Some(Answer::Noul { noul }) = response.answers.get("urgent") {
println!("紧急概率:{noul:.3}");
}
println!("实际模型:{},用量:{:?}", response.model, response.usage);
Ok(())
}Client:复用连接池,可廉价克隆,支持Send + Sync;evaluate(&request).await借用请求,便于重复使用。运行时需要 Tokio 的 I/O 和时间驱动。ClientBuilder:显式配置 API key、base URL、整体超时、重试策略和自定义reqwest::Client。构建返回Result,不因配置错误主动 panic。Client::new(key)使用显式密钥;Client::from_env()读取TYPESAFE_API_KEY。EvaluationRequest:构造函数要求提供 state,默认模型为jev-latest,可通过.model(...)指定任意版本。链式.question(...)添加问题,同名键会替换已有值。也可直接操作公开字段或通过 Serde 反序列化。Question/Answer:带type标签的枚举,分别完整表达 Noul、Choice、Score。用match提取结果,避免字符串类型判断及无关可选字段。Score 的 legend 和概率保留 API 的字符串索引;模型返回的数字使用f64。Content:仅允许顶层字符串、对象、数组;对象和数组内部可包含任意 JSON 值。Content::try_from(serde_json::json!(...))?用于结构化输入。state、instructions、criteria 均支持结构化内容。- 本地校验:模型非空、至少一个问题、Choice 1–255 个选项、Score 2–10 个等级。其中非空规则属于 SDK 基础校验;官方文档明确给出 Choice 上限和 Score 范围。每次发送前都校验,因此直接修改字段或反序列化不会绕过校验。
Error:区分配置、参数校验、HTTP 传输、API 状态、成功响应解码和整体超时。ApiError保留状态码、响应头和文本正文,可用.json()读取未预设结构的错误详情。
Noul 的可选准则:
use jevapi::{NoulCriteria, Question};
let question = Question::noul_with_criteria(
"是否紧急?",
NoulCriteria::default().yes("必须立即处理").no("可以稍后处理"),
);use std::time::Duration;
use jevapi::{Client, RetryPolicy};
# fn main() -> Result<(), jevapi::Error> {
let client = Client::builder()
.base_url("https://api.typesafe.ai/v1")
.timeout(Duration::from_secs(30))
.retry_policy(RetryPolicy {
max_retries: 2,
initial_delay: Duration::from_millis(500),
max_delay: Duration::from_secs(4),
})
.build()?;
# Ok(())
# }默认整体超时 60 秒,涵盖所有 HTTP 尝试、响应体读取和重试等待。
仅对文档要求重试的 429、529 自动重试,最多额外尝试 3 次。
退避上限从 500ms 开始翻倍,最高 8 秒;每次等待采用上限的 50%–100% 随机抖动。
若响应提供 Retry-After(整数秒或 HTTP 日期),等待至少该时长,但仍受整体超时限制。
RetryPolicy::none() 关闭重试。
401、422、其他 HTTP 错误、网络错误及无效成功响应直接返回。 默认禁用 HTTP 重定向及 reqwest 内建传输重试,防止隐式重放 POST。 自定义 HTTP 客户端的重定向、传输重试及超时设置由调用方控制。 取消 future 会停止本地请求/等待,但服务端已开始的处理可能继续执行。
共享客户端即可并发,通常无需再套一层 Arc:
# async fn example(client: jevapi::Client, a: jevapi::EvaluationRequest, b: jevapi::EvaluationRequest) -> Result<(), jevapi::Error> {
let (a, b) = tokio::try_join!(client.evaluate(&a), client.evaluate(&b))?;
# Ok(())
# }API key 在客户端和构造器的 Debug 中隐藏。API 错误的 Display 不包含响应正文;
Debug 和公开的正文/响应头字段仍可能包含业务数据。
默认 feature 为 rustls-tls。如需系统 TLS:
jevapi = { version = "0.1", default-features = false, features = ["native-tls"] }禁用所有 TLS feature 时只提供 HTTP;实际 TypeSafe 端点使用 HTTPS,需要 TLS 后端。
本库实现当前文档中的 POST /v1/systemone。文档未定义流式接口,因此没有 SSE/streaming API。
当前目标为原生 Tokio 应用,未声明 WASM 支持。
cargo run --example evaluate
cargo run --example concurrent
cargo test --locked
cargo fmt --check
cargo clippy --all-targets --all-features --locked -- -D warnings
cargo doc --no-deps --locked
两个示例会请求真实 API,需要环境变量密钥。普通测试使用本地模拟 HTTP 服务,不需要密钥。
evaluate 示例在一次请求中覆盖三类问题;concurrent 示例演示两个并发请求。
2026-09-22 使用 evaluate 示例完成真实 API 验证:返回模型 jev-1.13.0,
三种答案均成功解析,消耗 418 个输入 token 和 68 个输出 token。
该结果记录单次验证,模型别名指向和推理结果可能随时间变化。
API 对照来源:API reference、 Models。
本项目使用 MIT 许可证。