# AI 提供商插件
Deft 的 AI 层遵循一切皆插件模型:提供商框架本身(`deft/stdext/ai`)对任何具体的 LLM 厂商
一无所知。每个提供商——DeepSeek、Anthropic、OpenAI、Ollama、Z.AI 或第三方提供商——都是一个
独立的包,由框架在运行时发现并加载。
## 发现机制如何工作
1. 包在其清单中声明标签:
%Package{
owner "deft" name "ai-deepseek" version "0.1.0"
tags @{ "ai" "ai-provider" }
main "src/ai-deepseek.dft" }
2. 首次 AI 调用时,`deft/stdext/ai/plugins` 扫描所有已配置的包根目录(`pkg/list`),求值每个
`package.dft`,并挑选带有 `"ai-provider"` 标签的包。
3. 每个命中的包会被挂载(`ai-<name>`)并在运行时导入。其入口模块声明
`implements AiProviderExtension`;在提供商加入注册表之前,VM 会依据契约校验导出。
缺少契约字段会导致加载明确失败。
4. `ai/refresh` 会重新扫描,从而能发现会话中途安装的提供商(已加载的模块会被复用)。
开发检出会遮蔽同名的已安装副本,重复的提供商键按先到者优先解析。通用宿主是
`deft/stdext/plugin`——未来的插件类型(工具、技能、循环等)可复用它,并带上各自的标签和契约类型。
## 契约:`AiProviderExtension`
该契约声明于 `deft/stdext/types`,模块导出:
| 字段 | 类型 | 用途 |
|---|---|---|
| `key` | keyword | 注册表键(`:deepseek`) |
| `label` | string | 菜单显示名称 |
| `version` | string | 插件版本 |
| `base-url` | string | 默认 API 基础 URL |
| `env-var` | string? | 保存 API 密钥的环境变量(`nil` = 无) |
| `default-model` | string | cfg 未指定时使用的模型 |
| `extensions` | map? | 由 `build-cfg` 合并的默认 cfg 字段(例如思考模式) |
| `Provider` | any | `AiProvider` 协议实例 |
## 协议:`AiProvider`
该协议定义于 `deft/stdext/ai`,方法分为三组:
- 请求构造——`models`、`url`、`headers`、`body`、
`messages-with-user`、`tool-format`
- 响应解析——`extract-content`、`extract-reasoning`、
`extract-usage`、`has-tool-use`、`extract-tool-calls`、
`build-tool-results`、`finish-reason`、`scavenge-tool-calls`
- 策略/能力——`context-window`、`cost`、`compact-message`,
以及可选的 `balance` / `refresh-models` 能力(桩实现返回
`nil`;消费者对它们使用 `await`,普通值会直接透传)
`deft/stdext/ai` 驱动工具使用循环,`ai/budget` 根据 `context-window` 推导 token
上限,`ai/config` 从描述符构建 cfg 映射。消费者——聊天应用、编辑器的 AI 扩展、
帮助浏览器——只导入 `deft/stdext/ai/registry` 并传入 cfg。
## 易用 API
import "deft/stdext/ai/registry" as ai [ai/list-providers] # @{ :deepseek :anthropic ... } [ai/provider-label :deepseek] # "DeepSeek" [ai/provider-models :ollama] # @{ "llama3.2" ... } [ai/tool-format :anthropic] # :anthropic set cfg [ai/default-cfg] # :deepseek if installed, else first set cfg [ai/build-cfg :openai "gpt-4o-mini" :temperature 0.2] set reply [await [ai/ask $cfg "Explain this function."]]
## 编写提供商
复制 `packages/ai-deepseek`(本地服务器则用 `ai-ollama`),重命名包目录,然后:
1. 更新 `package.dft`:`name`、`main`、`exports`,保留
`"ai-provider"` 标签。
2. 在入口模块中 `implements AiProviderExtension`,导出契约字段,并
`defimpl YourType ai/AiProvider { ... }`。
3. 为你的模型添加 `context-window` 行、一个 `tool-format`,并在适用时添加
`cost`/`balance`/`refresh-models`。
4. 将包放入预置文件的 `:pkgs` 根目录下(或安装它)——
框架会在下次扫描时找到它。
添加提供商永远无需修改 `deft/stdext/ai`。