# Step 09 — Phase 4.1: AI Provider 基础设施 **依赖**: Step 01(配置模块) **参考设计**: §5.2 ## 目标 实现 AI Provider 策略模式基础设施:抽象基类、2 个 Provider 实现、工厂函数。 ## 新建文件 | # | 文件 | 说明 | |---|------|------| | 1 | `src/ai/providers/base.ts` | `AIProvider` 抽象基类 + `ChatOptions` | | 2 | `src/ai/providers/deepseek.ts` | `DeepSeekProvider` | | 3 | `src/ai/providers/openai.ts` | `OpenAIProvider` | | 4 | `src/ai/factory.ts` | `createProvider()` 工厂 | --- ## 1. `src/ai/providers/base.ts` ```typescript export interface ChatOptions { model: string; temperature: number; timeoutMs: number; } export abstract class AIProvider { abstract id: string; abstract name: string; constructor( protected apiKey: string, protected baseUrl: string ) {} abstract chat( systemPrompt: string, userPrompt: string, options: ChatOptions ): Promise; } ``` --- ## 2. `src/ai/providers/deepseek.ts` ```typescript import { AIProvider, ChatOptions } from './base'; export class DeepSeekProvider extends AIProvider { id = 'deepseek'; name = 'DeepSeek'; async chat(systemPrompt: string, userPrompt: string, options: ChatOptions): Promise { const url = `${this.baseUrl}/chat/completions`; const body = JSON.stringify({ model: options.model, temperature: options.temperature, messages: [ { role: 'system', content: systemPrompt }, { role: 'user', content: userPrompt }, ], }); const controller = new AbortController(); const timeout = setTimeout(() => controller.abort(), options.timeoutMs); try { const response = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${this.apiKey}`, }, body, signal: controller.signal, }); if (!response.ok) { const errorText = await response.text(); if (response.status === 401) { throw new Error('API Key 无效,请重新设置'); } throw new Error(`API 请求失败 (${response.status}): ${errorText}`); } const data = await response.json() as { choices: Array<{ message: { content: string } }>; }; return data.choices[0]?.message?.content ?? ''; } finally { clearTimeout(timeout); } } } ``` --- ## 3. `src/ai/providers/openai.ts` ```typescript import { AIProvider, ChatOptions } from './base'; export class OpenAIProvider extends AIProvider { id = 'openai'; name = 'OpenAI'; async chat(systemPrompt: string, userPrompt: string, options: ChatOptions): Promise { const url = `${this.baseUrl}/chat/completions`; const body = JSON.stringify({ model: options.model, temperature: options.temperature, messages: [ { role: 'system', content: systemPrompt }, { role: 'user', content: userPrompt }, ], }); const controller = new AbortController(); const timeout = setTimeout(() => controller.abort(), options.timeoutMs); try { const response = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${this.apiKey}`, }, body, signal: controller.signal, }); if (!response.ok) { const errorText = await response.text(); if (response.status === 401) { throw new Error('API Key 无效,请重新设置'); } throw new Error(`API 请求失败 (${response.status}): ${errorText}`); } const data = await response.json() as { choices: Array<{ message: { content: string } }>; }; return data.choices[0]?.message?.content ?? ''; } finally { clearTimeout(timeout); } } } ``` --- ## 4. `src/ai/factory.ts` ```typescript import { AIProvider } from './providers/base'; import { DeepSeekProvider } from './providers/deepseek'; import { OpenAIProvider } from './providers/openai'; type ProviderConstructor = new (apiKey: string, baseUrl: string) => AIProvider; const registry: Record = { deepseek: DeepSeekProvider, openai: OpenAIProvider, }; export function createProvider(providerId: string, apiKey: string, baseUrl: string): AIProvider { const Cls = registry[providerId]; if (!Cls) { throw new Error(`未知的 Provider: ${providerId}`); } return new Cls(apiKey, baseUrl); } export function getProviderIds(): string[] { return Object.keys(registry); } ``` --- ## 关键逻辑 - Provider 统一实现 `chat(systemPrompt, userPrompt, options): Promise` - 支持 AbortController 超时控制 - HTTP 401 → 抛出 "API Key 无效" 错误 - 工厂函数通过注册表字符串查找,便于添加新的 Provider - 两个 Provider 实现几乎相同(都是 openai 兼容 API),可考虑后续合并 --- ## 验收 - [ ] 4 个文件创建完成 - [ ] `npm run compile` 通过 - [ ] `npm run lint` 通过