# xllm 统一大模型请求库设计文档 ## 1. 背景与目标 在 `packages/xllm` 新建一个可跨 Node 与浏览器使用的大模型请求库,满足以下核心诉求: - 支持流式输出,并可直接消费增量内容 - 提供供应商适配器,将请求和响应统一为一致结构 - 开发体验简洁,支持便捷切换供应商与模型 首版范围明确为: - 运行环境:Node + 浏览器同一套 API - 首批供应商:OpenAI-Compatible、DeepSeek - 流式消费方式:`for await...of` - 能力范围:文本对话 + 工具调用 + 多模态输入 - 配置策略:参数优先,环境变量兜底 ## 2. 非目标(首版不做) - 不引入复杂重试与熔断策略(仅保留最小错误归一化能力) - 不实现供应商专有高级能力(如某家独有推理模式)的一致化抽象 - 不做 UI 层封装,仅提供 SDK 级能力 ## 3. 总体架构 采用“核心领域模型 + 供应商插件适配器”架构(推荐方案 A)。 ### 3.1 模块划分 建议目录: - `packages/xllm/src/core/` - 统一类型定义:`XRequest`、`XMessage`、`XStreamEvent`、`XResponse`、`XToolCall`、`XUsage` - 统一错误模型:`XllmError` - `packages/xllm/src/providers/` - `openai-compatible.adapter.ts` - `deepseek.adapter.ts` - `registry.ts`(按 provider 名称注册/获取适配器) - `packages/xllm/src/client/` - `createXllm.ts`(实例创建与默认配置) - `stream.ts`(流式执行) - `generate.ts`(非流式执行) - `packages/xllm/src/runtime/` - `fetch.ts`(跨平台请求封装) - `sse.ts`(SSE 增量解析) - `env.ts`(环境变量读取) - `packages/xllm/src/index.ts` - 对外导出 API 与类型 ### 3.2 核心设计原则 - 业务入口稳定:调用方只面对 `xllm.stream()` / `xllm.generate()` - 差异内聚:供应商差异仅存在于 adapter 内 - 可扩展:新增供应商只需实现同一 adapter 契约并注册 ## 4. 统一数据模型 ### 4.1 请求模型 `XRequest`(逻辑结构): - `messages: XMessage[]` - `tools?: XToolDefinition[]` - `toolChoice?: "auto" | "none" | { name: string }` - `stream?: boolean` - `temperature?: number` - `topP?: number` - `maxTokens?: number` - `metadata?: Record` - 请求级覆盖字段: - `provider?: "openai-compatible" | "deepseek"` - `model?: string` - `apiKey?: string` - `baseURL?: string` `XMessage`: - `role: "system" | "user" | "assistant" | "tool"` - `content: XContentPart[]` - `toolCallId?: string`(role 为 `tool` 时用于关联) `XContentPart`: - `{ type: "text"; text: string }` - `{ type: "image"; image: { url: string } }` > 首版仅强制支持 `url`(包含 http(s) 与 data URL),后续可扩展 file/blob 引用。 ### 4.2 响应模型 `XResponse`: - `text: string` - `toolCalls: XToolCall[]` - `usage?: XUsage` - `provider: string` - `model: string` - `finishReason?: string` - `raw?: unknown`(可选调试字段) ## 5. 流式事件协议 `stream()` 返回 `AsyncIterable`,统一事件集合: - `response.start` - 响应开始,包含 provider/model/requestId 等元数据 - `text.delta` - 文本增量,用于直接输出 - `tool_call.delta` - 工具调用参数增量 - `tool_call.done` - 单个工具调用完成,输出完整 name/args - `response.usage` - token 使用统计 - `response.done` - 完成事件,含 finish reason 说明: - 默认将供应商 SSE 分片归一化为上述事件 - 消费侧推荐只关心 `text.delta` 与 `response.done` 即可完成常见直出场景 ## 6. 供应商适配器契约 定义统一接口 `ProviderAdapter`: - `name: string` - `toProviderRequest(input: XRequest, config: ResolvedConfig): ProviderHttpRequest` - `fromProviderResponse(raw: unknown): XResponse` - `fromProviderStreamChunk(chunk: string, state: StreamState): XStreamEvent[]` - `normalizeError(err: unknown): XllmError` 适配职责: - 请求映射:统一字段 -> 供应商字段 - 流式映射:供应商 chunk -> 统一事件 - 错误映射:供应商错误 -> 统一错误码 ## 7. 配置与切换策略 ### 7.1 配置优先级 最终配置合并顺序(高到低): 1. 请求级参数(`stream/generate` 调用时传入) 2. 实例默认参数(`createXllm`) 3. 环境变量兜底 ### 7.2 建议环境变量 - `XLLM_API_KEY` - `OPENAI_API_KEY` - `DEEPSEEK_API_KEY` - `XLLM_BASE_URL`(可选) ### 7.3 切换体验 - `createXllm({ provider, model, ... })` 设全局默认 - 单次调用可覆写 `{ provider, model, ... }` - 同一业务逻辑不变,仅替换 provider/model 参数即可切换模型后端 ## 8. 错误模型与稳定性 统一错误码建议: - `AUTH_ERROR` - `RATE_LIMIT` - `NETWORK_ERROR` - `INVALID_REQUEST` - `PROVIDER_ERROR` `XllmError` 结构包含: - `code` - `message` - `provider` - `statusCode?` - `requestId?` - `raw?` 流式错误处理约定: - 出现不可恢复错误时抛出 `XllmError` - 已发出的增量内容由调用方决定是否展示或回滚 ## 9. 测试策略 ### 9.1 单元测试 - adapter 请求映射测试 - adapter 非流式响应映射测试 - adapter 流式 chunk 解析测试(含半包、粘包、结束包) ### 9.2 集成测试 - mock fetch + mock SSE,覆盖 `stream` 与 `generate` 主流程 - 断言统一事件顺序与最终响应一致性 ### 9.3 契约测试 - 同一 `XRequest` 在不同 provider 下返回结构都满足统一断言 - 确保新增 provider 不破坏现有统一接口语义 ## 10. 包结构与发布约定(与仓库一致) 新包遵循现有 monorepo 规范: - 包名建议:`@dm/xllm` - 入口:`src/index.ts` - `package.json` 中导出: - `"development": "./src/index.ts"` - `"import": "./dist/index.js"` - `"types": "./dist/index.d.ts"` - 脚本:`"dev": "dm dev"`、`"build": "dm build"` ## 11. 里程碑与实施顺序 建议分 3 个小阶段: 1. **M1(骨架)** - 建立 core 类型、client 主入口、provider registry、基础测试框架 2. **M2(能力)** - 完成 openai-compatible 与 deepseek 的 stream/generate 适配 - 打通文本、多模态、工具调用映射 3. **M3(稳态)** - 补齐错误归一化与契约测试 - 完善 README 与示例用法 ## 12. 验收标准 - 可在 Node 与浏览器中通过同一 API 调用 - 能通过 `for await...of` 获取稳定的 `text.delta` 直出 - OpenAI-Compatible 与 DeepSeek 可通过仅修改 provider/model 切换 - 非流式返回结构与流式聚合结果语义一致 - 关键错误能归一化并携带可诊断信息