Skip to content

plugin-llm-ollama — Ollama 本地模型 LLM ​

包名: @aalis/plugin-llm-ollama
源码: packages/plugin-llm-ollama/src/index.ts

概述 ​

Ollama 本地模型 LLM 服务提供者,通过 Ollama REST API 连接本地运行的模型。

插件声明 ​

typescript
export default definePlugin({
  name: '@aalis/plugin-llm-ollama',
  provides: [llm],
  uses: {
    config,
    logger,
    lifecycle,
    provide,
    events,
    proc: optional(processService),
  },
  apply(caps) { /* 见源码 */ },
});

每个发现的模型单独注册为一条 llm 服务条目(登记时套上 metered,拿到用量的调用发 llm:usage,见 api-llm 的记账),能力按模型解析,优先级从高到低:modelCapabilities 覆盖、Ollama /api/show 探测结果、内置模型家族表、providerCapabilities 兜底。

/api/show 探测到能力但其中没有对话能力的模型(如只报 embedding 的嵌入模型)不注册条目,不会出现在 /model 与 WebUI 的模型列表里;确需注册可用 modelCapabilities 显式声明能力。

modelCapabilities 每行按最后一个冒号切分模型 id 与能力段——Ollama 模型 id 自带 tag(qwen3:8b、bge-m3:latest),带 tag 的 id 照原样写即可(bge-m3:latest: chat,streaming)。

配置 ​

字段类型默认值说明
baseUrlstring'http://localhost:11434'Ollama 地址:本地 Ollama 服务的 HTTP 地址
customModelstextarea''自定义模型:手动添加的模型名称(每行一个或逗号分隔)。用于补充自动发现列表中未出现的模型。与自动发现重复时会提示去重。
discoverModelsbooleantrue自动发现模型:启动时请求 /api/tags 发现已安装的模型,WebUI 可刷新模型列表。服务不提供 /api/tags 时关闭:不发发现请求,只注册 customModels(此时必填),也不支持刷新。
modelCapabilitiestextarea''单模型能力覆盖:强制覆盖某模型的能力(优先级最高,高于 /api/show 自动探测与家族表),与 adapter 默认能力取并集。 格式:<modelId>: <cap1>,<cap2>,...,每行一条。如:nemotron3:33b: chat,vision,tool_calling
providerCapabilitiesstring''适配器默认能力(逗号分隔):兜底默认能力:仅当某模型既无法从 Ollama /api/show 探测、又不在内置家族表时才使用。能力现已自动探测,通常留空即可(填了反而可能给不支持的模型乱标能力)。例:chat,tool_calling,streaming
timeoutnumber120停顿超时(秒):多久收不到新的生成内容算超时(秒)。一直在输出(含思考内容)不算超时;工具调用要等 Ollama 生成完整才一次给出,生成期间不算输出;不流式的请求(含带音频的请求)要在这段时间内收到整份回复。大模型或长上下文出第一段内容慢、工具参数很长时,建议适当调大。0 = 不限制。
temperaturenumber0.7温度:0-2,越高越随机
maxTokensnumber4096最大 Token:单次回复最大生成 token 数(num_predict),须为正整数,否则实例转为出错
contextLengthnumber8192上下文长度:模型上下文窗口大小(num_ctx)
keepAlivestring'5m'模型保活时间:模型在显存中保留的时间,如 5m、1h、0(立即卸载)
thinkingselect'on'默认思考档位:报告了思考能力的模型(或单模型能力覆盖里写了 thinking 的)在请求没指定档位时用这一档,会话设置的「深度思考」压过它。可选 off(关)、on(开)。没有思考能力的模型不发 think 参数。

工作方式 ​

  1. 对话请求走 Ollama 原生 /api/chat 端点;消息含音频输入时改走 OpenAI 兼容的 /v1/chat/completions(原生 /api/chat 不支持音频)。音频的 input_audio.format 按 data URL 写明的类型给(mpeg、mp3 给 mp3,wav、x-wav、wave 给 wav;类型后面可以带参数,如 ;rate=16000),只收这两种:Ollama 的兼容接口不看 format、按文件头认音频,只认 wav 与 mp3。别的类型(如 ogg、m4a、flac)在发请求前报错、写明是哪种,不猜成 wav;不是 data URL 的(本地路径、链接、不带前缀的 base64)同样在发请求前报错,插件不读路径与链接
  2. 支持流式输出:/api/chat 以换行分隔的 JSON(NDJSON)逐块返回;带音频的请求不走流式,整段结果作为单个块交付
  3. 思考档位:能力里有 thinking 的模型声明关、开两档(off、on),默认档取实例配置 thinking;请求带了档位按请求,没带按默认档,带了别的档位拒绝。/api/chat 上翻成 think: false / think: true,能思考的模型总是明说(原生思考模型省略字段会默认思考,content 可能为空);音频走的兼容路径只认 reasoning_effort,关发 reasoning_effort: "none",开不发。没有思考能力的模型不声明档位,也不发 think。发了 think(档位开或关)时思考由 Ollama 管,只走原生的 thinking 字段,正文里字面写出的 <think> 照原样交出;没发 think 时才把正文里 <think> 与 </think> 之间的内容当思考。音频走的兼容路径同一条规则:有思考档位的模型正文照原样,没有档位的才按标签解析。/api/show 探测失败时按家族表,表里原生思考的族(qwen3、deepseek-r1、gemma4)同样带思考能力,qwen3-coder 不带
  4. 启动时经 /api/tags 发现已安装模型,与 customModels 合并后注册(发现与能力探测在停用或停机时中止);发现失败(不可达、超时、非 2xx、响应不是 JSON 或不是模型列表)时记一条 warn(带 URL 与原因),只注册 customModels。没有可注册的模型(发现失败且未配置 customModels,已连接但没有已安装的模型,或模型都是非对话模型)时实例转为出错,错误信息先写怎么修(确认 Ollama 在运行、baseUrl 写对,或 ollama pull 一个对话模型),再写原因。之后可经模型条目的 refresh(由 WebUI 触发)重新发现,按差异增删条目,无需重启插件;发现失败时刷新报错(消息带 URL 与原因),停用或停机时进行中的刷新随之中止并报错,这两种情况都不增删条目
  5. 服务不提供 /api/tags(如只转发对话接口的反向代理)时关闭 discoverModels:启动时不发发现请求、不记 warn,只注册 customModels(此时必填,留空时实例转为出错并点名该字段),能力照常经 /api/show 探测;模型条目不提供 refresh,WebUI 的「刷新」会提示该 provider 不支持运行时刷新
  6. timeout 按停顿计,规则见 api-llm 的生成请求的超时。算作新内容的是带 content(没发 think 时含 <think> 标签里的)、thinking 或 tool_calls 的帧;工具调用要等 Ollama 生成完整才一次给出,生成期间不算输出。带音频的请求不流式,timeout 秒内要收到整份回复。超时报「Ollama 请求超时:<timeout> 秒内没有收到新的生成内容,可在配置里调大 timeout」。对话请求经插件自己的连接池发出:没有 Node 自带 fetch 等响应头与读响应体各 300 秒的默认时限,也不走全局 dispatcher,经 NODE_USE_ENV_PROXY 或 setGlobalDispatcher 配的代理对它不起作用
  7. 对话请求失败时的错误信息会经 agent 发回会话,只写状态码与原因:非 2xx 时写状态码,401/403、402、404、429、5xx 各加一句提示(密钥无效或没有权限、余额不足或需要付费、模型或地址不对、请求过多或额度不足、上游服务故障),并附上游 JSON 里的说明(error.message、error 字符串或顶层 message,折成一行后截断);取不到说明(如 HTML 错误页)时写「详情见日志」。超时、连不上、插件已停用或重载(停用或重载之后还拿着旧句柄发的请求)各一句;非流式请求(带音频的请求一律走非流式)的应答是 200 但不是 JSON 时写明。响应体与底层原因(如 connect ECONNREFUSED <地址>)只记 warn 日志,响应体先把换行与连续空白折叠成一个空格,再截断到 500 个字符(按代理对安全截断)。模型发现失败的原因带响应体摘录(同样折叠与截断)
  8. 带用户名或密码(user:pass@)、带查询串或片段(? 或 # 之后的部分)或解析不了的 baseUrl 在读配置时报配置错误,实例转为出错、不发请求,错误信息不带 URL。插件不支持带凭据访问 Ollama:带凭据的 URL 本就发不出请求(fetch 拒绝),凭据还会出现在报错与 WebUI 的模型下拉里;插件在 baseUrl 后面拼路径,带查询串或片段时拼出来的地址是坏的

配置校验 ​

baseUrl 的显式无效值会使实例进入错误态;地址格式、查询串与片段及 URL 内的用户名、密码在模型发现前校验。keepAlive 中不加引号的有限数字会转为字符串(例如 0 变为 "0");timeout 的 0 或负数仍表示不限时。

文档对应 dev@c4e046e41,core 0.21.0,构建于 2026-11-02
基于 MIT 许可发布