Skip to content

Provider 配置 ​

Provider 无关的消息、配置、服务、重试和用量契约可从 @blade-ai/agent-sdk 导入。该入口是 browser-safe 的,不加载具体 Provider SDK。

支持的 Provider ​

Providertype 值adapter 包
OpenAI'openai'内置 @ai-sdk/openai
Anthropic'anthropic'可选 peer @ai-sdk/anthropic
Azure OpenAI'azure-openai'可选 peer @ai-sdk/azure
Gemini'gemini'可选 peer @ai-sdk/google
DeepSeek'deepseek'可选 peer @ai-sdk/deepseek
OpenAI 兼容'openai-compatible'内置 @ai-sdk/openai-compatible

Provider adapter 按需加载。使用非内置 Provider adapter 时安装对应 peer,例如:

bash
pnpm add @blade-ai/agent-sdk @ai-sdk/anthropic

ProviderConnectionConfig ​

ts
type BuiltinProviderType =
  | 'openai'
  | 'anthropic'
  | 'azure-openai'
  | 'gemini'
  | 'deepseek'
  | 'openai-compatible';

interface ProviderConnectionConfig {
  id?: string;
  type: BuiltinProviderType | (string & {});
  apiKey?: string;
  baseUrl?: string;
  headers?: Record<string, string>;
  organization?: string;
  apiVersion?: string;
  projectId?: string;
  requestTimeoutMs?: number;
  streamIdleTimeoutMs?: number;
}

type 选择 wire protocol adapter;id 标识逻辑 Provider,默认等于 type。OpenAI-compatible 网关如需在模型切换和持久化 Session 恢复后保留 真实 Provider 身份,应显式设置 id;id 不会改变 adapter 选择:

ts
provider: {
  id: 'openrouter',
  type: 'openai-compatible',
  apiKey: process.env.OPENROUTER_API_KEY!,
  baseUrl: 'https://openrouter.ai/api/v1',
}

requestTimeoutMs 限制一次非流式模型操作的总时长(包括重试等待),默认 10 分钟。streamIdleTimeoutMs 限制等待下一个流式 chunk 的时长,默认 5 分钟。两者都必须是以毫秒为单位的正整数。超时会主动中止底层 provider 请求,并抛出 ModelTimeoutError;错误码分别为 MODEL_REQUEST_TIMEOUT 和 MODEL_STREAM_IDLE_TIMEOUT,不会伪装成用户取消。

重试 ​

重试由 SDK 独占。SDK 会关闭 AI SDK 自带的重试(每个请求都设置 maxRetries: 0),因此一次失败产生的请求次数与 SDK 通过 ModelRetryEvent 上报的次数一致,不会出现分层各重试一遍的情况。

两种模式的覆盖范围不同:

  • 非流式请求整体重试,重试等待时间计入 requestTimeoutMs。
  • 流式请求只在建立阶段重试。一旦已向调用方交付过 chunk,中途的 provider 失败会抛出 ModelStreamError(错误码 MODEL_STREAM_FAILED),而不是静默结束响应; 这种情况不会重试——重放已部分交付的响应会让调用方看到重复文本。请按失败请求处理, 自行决定是否重发。

assistant 历史会记录生成响应时的逻辑 Provider ID、API adapter 和模型。 只有来源三元组完全相同时,原生 reasoning block 才会按原格式回放。切换 Provider、adapter、模型,或恢复不含来源信息的旧历史时,reasoning 会降级为 普通 assistant 文本,同时保留 tool call 关联,避免把 Provider 专属 payload 发送给不兼容的 API。

内置 Provider 的选择由 services/modelProvider.ts 中唯一的 typed factory table 负责。消息、工具 schema、tool call、usage 与 provider options 的转换集中在 services/modelAdapter.ts;VercelAIModelService 只编排请求、重试和流消费。

自定义 Provider Adapter ​

ProviderRegistry 是实例级 Registry,不包含进程全局注册状态,因此不同 Session 可以为同一个 type 使用不同 adapter。

ts
import {
  createSession,
  ProviderRegistry,
  type ModelServiceConfig,
  type ModelService,
  type ProviderAdapter,
} from '@blade-ai/agent-sdk';

const adapter = {
  type: 'acme-chat',
  async create(config: Readonly<ModelServiceConfig>): Promise<ModelService> {
    return new AcmeModelService(config);
  },
} satisfies ProviderAdapter;

const session = await createSession({
  provider: {
    id: 'acme-production',
    type: 'acme-chat',
    apiKey: process.env.ACME_API_KEY!,
  },
  providerRegistry: new ProviderRegistry([adapter]),
  model: 'acme-reasoner',
});

Adapter 返回现有 ModelService 契约,因此 model middleware、request/stream idle deadline、durable model attempt、subagent 和 compaction 会继续走同一运行时链路。 自定义 adapter 也可以只在当前 Registry 实例中覆盖内置 type。重复、非法注册 以及未注册的未知 adapter type 都会以 ProviderRegistryError fail-closed。

配置示例 ​

OpenAI ​

ts
{ type: 'openai', apiKey: 'sk-xxx' }

Anthropic ​

ts
{ type: 'anthropic', apiKey: 'sk-ant-xxx' }

Azure OpenAI ​

ts
{
  type: 'azure-openai',
  apiKey: 'xxx',
  baseUrl: 'https://my-resource.openai.azure.com',
  apiVersion: '2024-02-15-preview',
}

Gemini ​

ts
{ type: 'gemini', apiKey: 'xxx' }

DeepSeek ​

ts
{
  type: 'deepseek',
  apiKey: process.env.DEEPSEEK_API_KEY!,
  // 可省略,默认使用 https://api.deepseek.com
  baseUrl: 'https://api.deepseek.com',
}

DeepSeek 使用原生 provider 分支,默认模型建议使用 deepseek-v4-pro。旧别名 deepseek-chat、deepseek-reasoner 会继续兼容,但 SDK 会优先按当前 V4 模型路由。

ts
const session = await createSession({
  provider: { type: 'deepseek', apiKey: process.env.DEEPSEEK_API_KEY! },
  model: 'deepseek-v4-pro',
});

Thinking mode 可通过模型配置的 providerOptions 透传:

ts
{
  id: 'deepseek-pro',
  name: 'DeepSeek V4 Pro',
  provider: 'deepseek',
  model: 'deepseek-v4-pro',
  providerOptions: {
    deepseek: {
      thinking: { type: 'enabled' },
    },
  },
}

DeepSeek Context Caching 默认由官方服务端启用,SDK 不需要额外开关。响应 usage 会保留缓存命中与未命中口径:cacheReadInputTokens 对应 prompt_cache_hit_tokens,cacheMissInputTokens / billableInputTokens 对应 prompt_cache_miss_tokens。成本策略属于应用配置,SDK 不内置会随服务端 价格变化而过期的定价表。

DeepSeek 缓存命中优化 ​

DeepSeek 服务端会自动缓存 prompt 前缀。SDK 会在 DeepSeek provider 下对带稳定缓存标记的首轮上下文做安全重排:保留开头 system 消息不动,把首个 assistant/tool 消息之前标记为稳定的 user 上下文提前,使多次请求共享更长的相同前缀。

ts
import {
  optimizeDeepSeekCachePrefix,
} from '@blade-ai/agent-sdk';

const messages = optimizeDeepSeekCachePrefix([
  { role: 'system', content: 'You are a repository assistant.' },
  { role: 'user', content: '本轮问题:解释构建流程' },
  {
    role: 'user',
    content: '大型、稳定、跨请求复用的仓库摘要...',
    providerOptions: { deepseek: { cache: 'stable' } },
  },
]);

这项优化不会重排已经进入多轮对话的 assistant/tool 历史,避免破坏 tool call 因果关系。

OpenAI 兼容 ​

适用于 Ollama、vLLM、LiteLLM 等兼容 OpenAI API 的服务:

ts
{
  type: 'openai-compatible',
  baseUrl: 'http://localhost:11434/v1',
  apiKey: 'ollama',
}

运行时切换模型 ​

ts
const session = await createSession({
  provider: { type: 'openai', apiKey: process.env.OPENAI_API_KEY! },
  model: 'gpt-4o-mini',
});

// 简单任务用小模型
await session.send('列出 src 目录下的文件');
for await (const event of session.stream()) { /* ... */ }

// 复杂任务切换到大模型
await session.setModel('gpt-4o');
await session.send('重构这些文件的架构');
for await (const event of session.stream()) { /* ... */ }

查看支持的模型 ​

ts
const models = await session.supportedModels();
for (const m of models) {
  console.log(`${m.id}: ${m.name}`);
}

日志 ​

SDK 不内置日志实现,通过 AgentLogger 接口接受外部注入:

ts
import type { AgentLogger, LogEntry } from '@blade-ai/agent-sdk';

const logger: AgentLogger = {
  log(entry: LogEntry) {
    const prefix = `[${entry.timestamp}][${entry.level.toUpperCase()}][${entry.category}]`;
    console.log(`${prefix} ${entry.message}`);
  },
};

const session = await createSession({
  provider: { type: 'openai', apiKey: process.env.OPENAI_API_KEY! },
  model: 'gpt-4o',
  logger,
});

LogEntry ​

ts
interface LogEntry {
  level: 'debug' | 'info' | 'warn' | 'error';
  category: string;
  message: string;
  timestamp: string;
  sessionId?: string;
  args?: unknown[];
}

Released under the MIT License.