跳到主要内容

身份验证

提供商需要一种方式来向其后端验证请求。凭据从哪里来由应用决定:环境变量、密钥存储、现有的用户登录,或组织专用的凭据服务。这个选择不应该要求改动智能体的操作或对话格式。

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。