配置模型 Provider
DotCraft Harness 内置 OpenAI 与 Anthropic 两套 Provider 集成。Host 通过 AppConfig 选择 Provider 和模型,再把最终生效的配置传给 AddDotCraftHarness。
配置 OpenAI
使用同一个稳定的 Provider ID 定义 Provider 记录与模型偏好:
using DotCraft.Configuration;
const string providerId = "openai";
var appConfig = new AppConfig
{
ProviderId = providerId,
ProviderPreferences =
{
[providerId] = new ModelPreference
{
Model = "gpt-5.1"
}
},
Providers =
{
[providerId] = new AppConfig.ModelProviderConfig
{
DisplayName = "OpenAI",
Protocol = ModelProviderProtocols.OpenAIResponses,
ApiKey = Environment.GetEnvironmentVariable("OPENAI_API_KEY")
?? throw new InvalidOperationException("Set OPENAI_API_KEY.")
}
}
};端点实现 Chat Completions 协议时用 ModelProviderProtocols.OpenAIChatCompletions,实现 Responses 协议时用 ModelProviderProtocols.OpenAIResponses。
用 ChatGPT 订阅认证
OpenAI Provider 还支持第二种认证方式。AuthMethod = "chatgptOAuth" 用 OpenAI 的 Sign in with ChatGPT 流程代替静态 API key,请求以 ChatGPT 订阅账号的身份认证:
appConfig.Providers["openai"] = new AppConfig.ModelProviderConfig
{
DisplayName = "OpenAI (ChatGPT)",
Protocol = ModelProviderProtocols.OpenAIResponses,
AuthMethod = ModelProviderAuthMethods.ChatGptOAuth
};这种模式下 Provider 的解析规则不同:
- 协议必须是 OpenAI 协议。
anthropic搭配chatgptOAuth会在解析 Provider 时抛出ModelProviderConfigurationException,最终生效的协议始终是openai-responses。 ApiKey与EndPoint会被忽略,请求发往 ChatGPT 后端https://chatgpt.com/backend-api/codex。- 每个请求都会附带最新的 access token,来自用户数据目录下
auth.json中保存的 token 包。token 自动刷新,收到401时会先采用其他进程轮换后的凭据,再向签发方刷新。
登录只需一次,且发生在 Provider 配置之外。与 OpenAI Provider 一同注册的 IOpenAIAuthService 通过 LoginAsync 执行 PKCE 浏览器登录并持久化 token。装有 DotCraft 应用的机器上,dotcraft auth openai login 完成同样的事,还会把 Provider 条目写进全局配置。ChatGptAccountId 与 ChatGptPlanType 由该流程写入,当作只读元数据即可。用 LogoutAsync 或 dotcraft auth openai logout 退出登录会删除 token,并把 Provider 还原为 apiKey。
配置 Anthropic
Anthropic 使用相同的 Provider 注册表与偏好结构:
const string providerId = "anthropic";
var appConfig = new AppConfig
{
ProviderId = providerId,
ProviderPreferences =
{
[providerId] = new ModelPreference
{
Model = "claude-sonnet-4-5"
}
},
Providers =
{
[providerId] = new AppConfig.ModelProviderConfig
{
DisplayName = "Anthropic",
Protocol = ModelProviderProtocols.Anthropic,
ApiKey = Environment.GetEnvironmentVariable("ANTHROPIC_API_KEY")
?? throw new InvalidOperationException("Set ANTHROPIC_API_KEY.")
}
}
};EndPoint 为空时会使用所选协议的内置默认端点。
使用兼容端点
如果 OpenAI 兼容或 Anthropic 兼容的 Provider 由其他服务转发,可以设置 EndPoint:
appConfig.Providers["company-models"] = new AppConfig.ModelProviderConfig
{
DisplayName = "Company models",
Protocol = ModelProviderProtocols.OpenAIChatCompletions,
ApiKey = secretStore.Get("company-models"),
EndPoint = "https://models.example.com/v1"
};
appConfig.ProviderId = "company-models";
appConfig.ProviderPreferences["company-models"] = new ModelPreference
{
Model = "engineering-agent"
};端点必须实现 Protocol 选中的协议。自定义 Provider ID 只是给配置记录起名,不会定义新的传输协议——可选协议只有上面这三个。
为单个 Thread 选择模型
新建 Thread 时会捕获当前 workspace 最终生效的 Provider 与模型。用 ThreadConfiguration 可以只为这一个 Thread 覆盖它们:
var thread = await sessions.CreateThreadAsync(
identity,
new ThreadConfiguration
{
ProviderId = "anthropic",
Model = "claude-sonnet-4-5"
},
ct: cancellationToken);Host 配置发生变化时,不会改写已有 Thread 的模型快照。
TIP
不要在 workspace 配置中保存 API key。请在 Host 中解析 Secret,并在组合前构造最终生效的 AppConfig。
Provider 注册
AddDotCraftHarness 以幂等方式注册两个内置 Provider 实现,重复注册不会产生重复项。
每个协议只能有一个 IModelProvider。同一协议出现多个实现时,Runtime 会在组合期间抛错,Host 启动失败。
相关文档
连接模型服务
在 Harness 选项中设置连接,通过普通配置选择 provider ID 和模型。此 Runtime 的所有模型操作都使用这个服务。
using DotCraft.Agents.Remote;
using DotCraft.Harness;
builder.Services.AddDotCraftHarness(appConfig, options =>
{
options.WorkspacePath = workspacePath;
options.UserDataPath = userDataPath;
options.ModelService = new ModelServiceConnection(
new Uri("https://models.example/model-service/"),
Environment.GetEnvironmentVariable("MODEL_SERVICE_TOKEN")!);
});Harness 包含远程传输,原生历史、工具、重试和会话持久化由 Runtime 管理。提供商配置和客户端凭据操作见部署模型服务。
嵌入服务
在 ASP.NET Core 宿主中引用 DotCraft.ModelService,注册负责调用方授权和上游快照的 IModelServiceAccess。文件实现使用与 CLI 相同的状态目录:
using DotCraft.ModelService;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddSingleton<IModelServiceAccess>(new FileModelServiceAccess("model-state"));
builder.Services.AddDotCraftModelService();
var app = builder.Build();
app.MapDotCraftModelService();
await app.RunAsync();服务注册不创建工作区、Session 或工具。通过 IModelServiceObserver 接收请求完成和规范化用量,回调失败不改变模型响应。数据库存储的订阅为每个凭据身份绑定一个 OpenAIAuthManager,实现 IOpenAITokenStore,其中 TryReplace 需要原子写入轮换后的令牌。