Go 接 Ollama API 做模型健康检查:版本、模型存在性与超时处理
来源:17golang原创
时间:2026-08-10 12:58:24 216浏览 收藏
本地 Ollama 服务“能访问”不等于“能稳定生成”。实际接入 Go 服务时,常见故障是 11434 端口还在监听,但目标模型没有安装;或者模型第一次加载太慢,业务网关先把请求切断。健康检查应该分成三层:先拿版本确认服务响应,再读模型清单确认名称,最后用一个短的非流式请求验证真正的生成路径。
/api/version只证明 Ollama API 可响应,不能证明目标模型存在。/api/tags用于核对模型名,不能把本地别名和业务配置混在一起。- 短探针要设置独立超时,并把“模型未安装”和“加载太慢”分成不同状态。
keep_alive影响下一次请求的首包延迟,也直接影响显存或内存占用。
先把“服务在线”和“模型可用”拆开
Ollama 默认把本地 API 暴露在 http://localhost:11434/api。Go 程序先调用 GET /api/version,这一步适合做进程级存活检查;随后调用 GET /api/tags,从返回的 models[].name 中寻找业务配置的模型名。
这两个接口都成功时,结论仍然只是“服务和模型清单可读”。如果模型刚被删除、配置写成了错误的 tag,真正生成时仍会失败。所以健康检查要保留三个结果字段,而不是只返回一个布尔值:
| 检查层 | 接口 | 能确认什么 | 不能确认什么 |
|---|---|---|---|
| 进程 | /api/version | API 可响应、版本可读 | 目标模型是否安装 |
| 模型 | /api/tags | 模型名、大小、摘要 | 模型能否完成生成 |
| 能力 | /api/generate | 加载与生成链路可用 | 长文本质量和业务正确性 |

Go 客户端先统一地址和截止时间
不要在每个检查函数里拼接地址或各自创建超时。下面的客户端只负责 HTTP 传输,具体检查结果交给上层组合;健康接口本身可以给它 2 到 3 秒,生成探针则单独放宽到模型冷启动能够承受的时间。
type OllamaClient struct {
BaseURL string
HTTP *http.Client
}
func NewOllamaClient(base string) *OllamaClient {
return &OllamaClient{
BaseURL: strings.TrimRight(base, "/"),
HTTP: &http.Client{},
}
}
func (c *OllamaClient) getJSON(ctx context.Context, path string, out any) error {
req, err := http.NewRequestWithContext(ctx, http.MethodGet, c.BaseURL+path, nil)
if err != nil {
return err
}
res, err := c.HTTP.Do(req)
if err != nil {
return err
}
defer res.Body.Close()
if res.StatusCode = 300 {
return fmt.Errorf("ollama %s returned %s", path, res.Status)
}
return json.NewDecoder(res.Body).Decode(out)
}
这里的 http.Client 没有设置全局 Timeout,是因为每次探针的截止时间由 context.WithTimeout 控制,后续还可以按检查类型增加独立的重试或连接参数。服务端返回非 2xx 时,保留状态码和接口路径,排障时比一句“检查失败”有用得多。
版本和模型清单检查要返回可解释状态
type versionReply struct {
Version string `json:"version"`
}
type modelReply struct {
Models []struct {
Name string `json:"name"`
Size int64 `json:"size"`
} `json:"models"`
}
func (c *OllamaClient) CheckCatalog(ctx context.Context, want string) (string, bool, error) {
var ver versionReply
if err := c.getJSON(ctx, "/api/version", &ver); err != nil {
return "", false, err
}
var list modelReply
if err := c.getJSON(ctx, "/api/tags", &list); err != nil {
return ver.Version, false, err
}
for _, item := range list.Models {
if item.Name == want {
return ver.Version, true, nil
}
}
return ver.Version, false, nil
}
调用方可以把结果写成 api_unreachable、model_missing 或 catalog_ok。其中模型名要使用 Ollama 返回的完整名称,例如带 tag 的 gemma3:4b,不要用展示名称去猜测。
最后用短生成请求验证真正能力
模型清单通过后,再发一个固定且很短的探针。要显式设置 stream:false,否则 /api/generate 默认可能返回逐行 JSON 流;健康接口只需要确认最终响应里有 done:true,不需要收集一段长文本。
type generateRequest struct {
Model string `json:"model"`
Prompt string `json:"prompt"`
Stream bool `json:"stream"`
KeepAlive string `json:"keep_alive,omitempty"`
}
type generateReply struct {
Response string `json:"response"`
Done bool `json:"done"`
Reason string `json:"done_reason"`
}
func (c *OllamaClient) Probe(ctx context.Context, model string) error {
body := generateRequest{Model: model, Prompt: "只回复 OK", Stream: false, KeepAlive: "5m"}
raw, err := json.Marshal(body)
if err != nil {
return err
}
req, err := http.NewRequestWithContext(ctx, http.MethodPost, c.BaseURL+"/api/generate", bytes.NewReader(raw))
if err != nil {
return err
}
req.Header.Set("Content-Type", "application/json")
res, err := c.HTTP.Do(req)
if err != nil {
return err
}
defer res.Body.Close()
if res.StatusCode = 300 {
return fmt.Errorf("probe returned %s", res.Status)
}
var reply generateReply
if err := json.NewDecoder(res.Body).Decode(&reply); err != nil {
return err
}
if !reply.Done {
return errors.New("probe did not finish")
}
return nil
}
探针提示词越短越好,避免把健康检查变成内容生成任务。业务服务可以只在启动、发布或告警恢复时跑一次;不建议每秒对模型发探针,否则检查本身会制造负载。

超时、模型未安装和常驻内存要分别处理
连接超时:服务可能没启动或地址不对
dial tcp ... connection refused 更像进程或地址问题;它不应该被标成模型质量问题。检查容器网络、OLLAMA_HOST 和实际监听地址,再决定是否告警。
模型未安装:清单检查比生成报错更早
如果 /api/tags 中没有目标模型,直接调用生成只会把故障推迟到用户请求上。发布时先执行 ollama pull 并重新跑清单检查,应用侧将状态标为 model_missing,不要无限重试。
冷启动超时:检查窗口要和模型大小匹配
第一次生成通常还包含模型加载,健康检查的超时不能照搬版本接口的 2 秒。可以把“清单通过、生成超时”记录成 model_loading_slow,并在发布或扩容阶段预热,而不是立即判定 Ollama 不可用。
Ollama 文档说明,keep_alive 可以用时长、秒数、负数或 0 控制模型驻留;设置为 0 会在本次生成后卸载,设置为较长时长则减少下一次冷启动,但会占用更多内存。这个参数应成为容量策略的一部分,而不是随手写死在探针里。
把三层结果接入发布门禁
发布脚本可以按下面的顺序执行:
- 用短截止时间调用
/api/version,失败则标记api_unreachable。 - 调用
/api/tags查找完整模型名,缺失则标记model_missing。 - 用更长窗口发送一次
stream:false探针,超时则标记model_loading_slow。 - 三层都通过后再放行依赖本地模型的流量,记录版本、模型名和探针耗时。
若把这些状态统一成一个绿色或红色开关,运维人员仍然要重新登录机器找原因。保留分层状态,才能知道是 Ollama 没启动、模型没拉下来,还是冷启动窗口太短。
常见问题
/api/version 返回成功,为什么生成仍然失败?
版本接口只能证明 API 进程能响应,不能证明目标模型存在,也不能证明模型已经加载成功。还要检查 /api/tags 和一次短生成探针。
健康检查应该使用 /api/generate 还是 /api/chat?
检查生成能力时,两者都可以;如果业务实际使用对话接口,探针应采用同一接口和消息形状。无论哪种接口,都建议关闭流式返回,降低检查逻辑复杂度。
为什么不直接调用 ollama list?
命令行适合机器本地运维,Go 服务更适合访问 HTTP API。API 返回的模型名和摘要可以直接写入结构化检查结果,也不依赖子进程环境。
keep_alive: 0 适合生产探针吗?
它能释放模型占用,但每次检查都可能触发下一次冷启动。低频发布门禁可以这样做;在线流量场景要结合模型大小和内存预算决定驻留时间。
让健康检查回答“哪里坏了”
Go 接 Ollama 时,最小可靠闭环不是一个 GET 请求,而是版本、模型清单和短生成三道门。把接口不可达、模型缺失、冷启动过慢和生成完成分别记录,再根据 keep_alive 做内存取舍,告警才能直接指向处理动作。
-
217 收藏
-
科技周边 · 人工智能 | 4天前 | go · Context · 流式处理 · 人工智能 · openai api · sse · 重试 · OpenAI Go context 流式输出 SSE Responses API 断线重试236 收藏
-
303 收藏
-
326 收藏
-
446 收藏
-
472 收藏
-
254 收藏
-
497 收藏
-
科技周边 · 人工智能 | 2星期前 | 人工智能 · sse · 流式输出 · 接口稳定性 · 重试 · SSE 断线重连 Responses API AI流式输出 sequence_number 重复片段217 收藏
-
188 收藏
-
科技周边 · 人工智能 | 2星期前 | go · openai · AI接口 · Responses API · Go OpenAI Responses API background mode 异步轮询 大模型接口388 收藏
-
科技周边 · 人工智能 | 2星期前 | go语言 · 异步任务 · 人工智能 · openai · API工程化 · Go 异步任务 轮询 数据保留 OpenAI Responses API background mode183 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习