# @drama/llm 多厂商 LLM 网关。公共面(`src/index.js`)导出 `createLLM`、`createStaticKeyProvider`、`LLMError` 和 provider 注册表;协议差异全部圈在 `src/providers/llm..js` 子类,基类(`src/base.js`)零厂商分支。生产、诊断和验收都只调用真实 provider,不提供 fake provider 或 fetch 注入缝。 运行时会计链由 composition root 成组注入供应商成本、审计和积分结算端口。成功响应先严格构造 token 用量并记录价格快照与人民币 micros 成本,再按显式策略结算用户积分;运营探针可以三者全部省略,但不得只省略其中一部分。 ## OpenAI 兼容文本能力零文件接入 接入一个 OpenAI 兼容新厂商(DeepSeek 等)= 配置厂商主体、文本能力、key 和模型,**零代码、零新文件**: ```sql INSERT INTO model_provider (code, display_name) VALUES ('deepseek', 'DeepSeek'); INSERT INTO model_provider_capability (provider_id, code, capability, adapter, credential_source, base_url) SELECT id, 'deepseek', 'text', 'openai', 'key_pool', 'https://api.deepseek.com/v1' FROM model_provider WHERE code = 'deepseek'; INSERT INTO llm_key (vendor, api_key) VALUES ('llm:deepseek', ''); INSERT INTO llm_model (provider_capability_id, model, pricing) SELECT id, 'deepseek-chat', '' FROM model_provider_capability WHERE code = 'deepseek' AND capability = 'text'; ``` 装配从文本能力行构造实例:`createLLM({ provider: row.adapter, vendor: row.name })`。 - `adapter` 决定复用哪个 provider 子类(`openai` = Chat Completions 适配器)。 - `base_url` 经 `lease.baseUrl` 承载厂商端点,**永远优先于** `defaultBaseUrl()`。 - `vendor` 使 key 池按厂商身份隔离(同用 `openai` 适配器的两个厂商各命中自己的 key 池,详见任务 07 的 `vendor` 选项)。 仅当**帧形态或多模态形态有厂商差异**时才需新增 `llm..js`(如 `gemini`/`volcengine`);纯 OpenAI 兼容厂商只配置数据。 ## 两套 OpenAI 适配器定位 同一 OpenAI 生态的两套协议收敛为两个适配器文件,经 `model_provider_capability.adapter` 二选一,不建平行体系: | adapter | 文件 | 端点 | 用途 | |---|---|---|---| | `openai_responses` | `providers/llm.openai_responses.js` | `POST /responses` | **OpenAI 厂商默认适配器**(Responses API,`store:false`、独立 `prompt_cache_key`、缓存读写用量) | | `openai` | `providers/llm.openai.js` | `POST /chat/completions` | OpenAI 兼容厂商(Moonshot / DeepSeek / Azure / 兼容网关) | Visual Game 持续 Agent 通过独立 `prompt_cache_key` 固定缓存身份。模型参数提供 `prompt_cache_options: { mode: 'implicit' | 'explicit', ttl?: '30m' }` 时,static 消息同时发送 `prompt_cache_breakpoint`;未提供时不发送这两个公开缓存控制字段。Responses usage 统一构造 `cached_tokens` 和 `cache_write_tokens`,供应商未报告的可选明细在第三方响应入口构造为 `0`。 ## 视频支持面 视频落地/拒绝由基类 `supportsVideo()` 能力钩子驱动(`base.js` 的 `request()` 单点护栏),基类零厂商分支: | provider | 视频 | |---|---| | `gemini` | 支持(`inline_data` base64 / `file_data` url) | | `volcengine` | 支持(`video_url` 块) | | `openai` / `openai_responses` / `anthropic` / `moonshot` / `azure_foundry` | 收到 `videos` 抛 `LLMError{ reason:'badRequest', retryable:false }` | 扩展视频厂商 = 在子类覆写 `supportsVideo()` 返回 `true`,并在 `chat`/`_toOpenAIMessages` 落该厂商的视频块。