身份验证
提供商需要一种方式来向其后端验证请求。凭据从哪里来由应用决定:环境变量、密钥存储、现有的用户登录,或组织专用的凭据服务。这个选择不应该要求改动智能体的操作或对话格式。
GDK 把 HTTP 身份验证机制与提供商的请求格式分开。ApiClient 接受一个 AuthMethod;自定义方法可以在每次准备请求时向你的应用索取当前凭据。当服务有需要时,提供商实现也可以有自己的身份验证流程。
身份验证机制
下面这些机制定义在 goose-providers::api_client 中:
| 机制 | 用途 |
|---|---|
AuthMethod::NoAuth | 不需要身份验证的端点,例如隔离得当的本地服务。 |
AuthMethod::BearerToken | 通过 Authorization: Bearer ... 请求头发送的令牌。 |
AuthMethod::ApiKey | 通过指定名称的请求头发送的凭据。 |
AuthMethod::Custom | 由 AuthProvider 在请求时提供请求头名称和值。 |
例如,应用可以直接传入密钥,而不依赖 goose CLI 的配置:
let client = ApiClient::new_with_tls(
"https://api.openai.com".into(),
AuthMethod::BearerToken(std::env::var("OPENAI_API_KEY")?),
None,
)?;
这里配置的是凭据的发送方式;它不会安装密钥存储,也不会启动登录流程。TLS 参数与 HTTP 身份验证无关。HTTPS 请使用启用了 TLS 的构建;如果你的环境需要自定义证书颁发机构或客户端证书,请提供 TlsConfig。
特定于提供商的身份验证与声明式身份验证
Databricks 实现通过 DatabricksAuth 支持令牌和 OAuth 配置。它的认证提供者接受由应用提供的回调来获取令牌;GDK 不假定每个宿主都有相同的浏览器登录或凭据存储方式。
声明式提供商可以指定一个 API 密钥变量,并通过 KeyResolver 解析它。自带的 EnvKeyResolver 使用进程环境变量。定义也可以改为配置一条获取凭据的命令,并带有缓存和刷新设置。这些命令属于可执行的配置,所以只加载你信任的定义。
提供你自己的身份验证
当凭据在应用生命周期内可能变化,或来自内置机制未覆盖的来源时,请使用 AuthProvider。例如,宿主可以把自己登录流程得到的令牌保存在共享状态中:
use std::sync::{Arc, RwLock};
use anyhow::Result;
use async_trait::async_trait;
use goose_providers::api_client::AuthProvider;
struct AppAuth {
token: Arc<RwLock<String>>,
}
#[async_trait]
impl AuthProvider for AppAuth {
async fn get_auth_header(&self) -> Result<(String, String)> {
let token = self.token.read().unwrap();
Ok(("Authorization".into(), format!("Bearer {token}")))
}
}
把它以 AuthMethod::Custom(Box::new(AppAuth { token })) 的形式传给 ApiClient。登录或令牌轮换之后,宿主可以更新共享令牌,而无需重新构建智能体。真正的凭据存储可以替换这个共享字符串,同时保持相同的 trait 边界。
AuthProvider 还有一个 refresh_credentials 方法。它的默认实现会报告不支持刷新;如果你的流程能够刷新凭据,请实现它。何时调用它由提供商或应用决定。仅靠一个自定义请求头回调,并不能实现 OAuth 或自动刷新。
保持边界清晰
凭据不应出现在对话、提示词、工具输出或已保存的效果中。请把它们放在应用自己的凭据处理流程里,并避免在日志中记录它们的值。工作目录并不是智能体或其工具可访问范围的边界。
对模型请求进行身份验证,也不同于对连接到 goose 的客户端连接进行身份验证。如果你的应用通过 ACP 使用预构建的二进制文件,后端的提供商凭据应放在后端;goose serve 连接有它自己的身份验证。这条路径请参阅用 goose 构建应用。
完整的 HTTP 身份验证和 TLS API 见 goose-providers::api_client。