登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  科技周边 >  人工智能

Go 接 Ollama API 做模型健康检查:版本、模型存在性与超时处理

来源:17golang原创

时间:2026-08-10 12:58:24 216浏览 收藏

所属专题:AI 流式输出可靠性实战专题

本地 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/versionAPI 可响应、版本可读目标模型是否安装
模型/api/tags模型名、大小、摘要模型能否完成生成
能力/api/generate加载与生成链路可用长文本质量和业务正确性

Go 调用 Ollama API 依次检查版本、模型清单和生成能力的三层门禁

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_unreachablemodel_missingcatalog_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
}

探针提示词越短越好,避免把健康检查变成内容生成任务。业务服务可以只在启动、发布或告警恢复时跑一次;不建议每秒对模型发探针,否则检查本身会制造负载。

Go Ollama 生成探针区分模型未安装、超时和完成状态,并结合 keep_alive 控制驻留

超时、模型未安装和常驻内存要分别处理

连接超时:服务可能没启动或地址不对

dial tcp ... connection refused 更像进程或地址问题;它不应该被标成模型质量问题。检查容器网络、OLLAMA_HOST 和实际监听地址,再决定是否告警。

模型未安装:清单检查比生成报错更早

如果 /api/tags 中没有目标模型,直接调用生成只会把故障推迟到用户请求上。发布时先执行 ollama pull 并重新跑清单检查,应用侧将状态标为 model_missing,不要无限重试。

冷启动超时:检查窗口要和模型大小匹配

第一次生成通常还包含模型加载,健康检查的超时不能照搬版本接口的 2 秒。可以把“清单通过、生成超时”记录成 model_loading_slow,并在发布或扩容阶段预热,而不是立即判定 Ollama 不可用。

Ollama 文档说明,keep_alive 可以用时长、秒数、负数或 0 控制模型驻留;设置为 0 会在本次生成后卸载,设置为较长时长则减少下一次冷启动,但会占用更多内存。这个参数应成为容量策略的一部分,而不是随手写死在探针里。

把三层结果接入发布门禁

发布脚本可以按下面的顺序执行:

  1. 用短截止时间调用 /api/version,失败则标记 api_unreachable
  2. 调用 /api/tags 查找完整模型名,缺失则标记 model_missing
  3. 用更长窗口发送一次 stream:false 探针,超时则标记 model_loading_slow
  4. 三层都通过后再放行依赖本地模型的流量,记录版本、模型名和探针耗时。

若把这些状态统一成一个绿色或红色开关,运维人员仍然要重新登录机器找原因。保留分层状态,才能知道是 Ollama 没启动、模型没拉下来,还是冷启动窗口太短。

常见问题

/api/version 返回成功,为什么生成仍然失败?

版本接口只能证明 API 进程能响应,不能证明目标模型存在,也不能证明模型已经加载成功。还要检查 /api/tags 和一次短生成探针。

健康检查应该使用 /api/generate 还是 /api/chat

检查生成能力时,两者都可以;如果业务实际使用对话接口,探针应采用同一接口和消息形状。无论哪种接口,都建议关闭流式返回,降低检查逻辑复杂度。

为什么不直接调用 ollama list

命令行适合机器本地运维,Go 服务更适合访问 HTTP API。API 返回的模型名和摘要可以直接写入结构化检查结果,也不依赖子进程环境。

keep_alive: 0 适合生产探针吗?

它能释放模型占用,但每次检查都可能触发下一次冷启动。低频发布门禁可以这样做;在线流量场景要结合模型大小和内存预算决定驻留时间。

让健康检查回答“哪里坏了”

Go 接 Ollama 时,最小可靠闭环不是一个 GET 请求,而是版本、模型清单和短生成三道门。把接口不可达、模型缺失、冷启动过慢和生成完成分别记录,再根据 keep_alive 做内存取舍,告警才能直接指向处理动作。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>