欢迎光临
我们一直在努力

【AI大模型接入SDK】Ollama API 全量响应实现

头像

🎬 个人主页:艾莉丝努力练剑

❄专栏传送门:《C语言》《数据结构与算法》《C/C++干货分享&学习过程记录》 《Linux操作系统编程详解》《笔试/面试常见算法:从基础到进阶》《Python干货分享》

⭐️为天地立心,为生民立命,为往圣继绝学,为万世开太平


🎬 艾莉丝的简介:

在这里插入图片描述


文章目录

  • 1 ~> Ollama API 基础认知
    • 1.1 核心能力与接口定位
    • 1.2 通用约定
      • 1.2.1 模型命名规则
      • 1.2.2 时长单位
      • 1.2.3 流式响应约定
  • 2 ~> /api/chat 全量返回接口规范
    • 2.1 接口基本信息
    • 2.2 请求参数体系
      • 2.2.1 必选参数
      • 2.2.2 可选高级参数
    • 2.3 响应报文结构
    • 2.4 响应核心字段说明
  • 3 ~> 环境验证与常见排障
    • 3.1 curl 接口验证命令
    • 3.2 常见故障排查
      • 3.2.1 代理冲突问题
      • 3.2.2 首次请求慢问题
  • 4 ~> C++ 全量返回实现流程
    • 4.1 实现总流程
    • 4.2 模型有效性检测
    • 4.3 请求参数构造
      • 4.3.1 超参数提取
      • 4.3.2 历史消息构建
    • 4.4 请求体构建与序列化
    • 4.5 HTTP 客户端配置与请求发送
    • 4.6 响应反序列化与内容提取
  • 5 ~> 单元测试与工程配置
    • 5.1 测试用例编写
    • 5.2 CMake 构建配置
  • 6 ~> 扩展知识点
    • 6.1 推理模型思考字段
    • 6.2 结构化输出支持
  • 结尾

在这里插入图片描述


1 ~> Ollama API 基础认知

1.1 核心能力与接口定位

  • Ollama 是本地大模型部署与推理服务,通过标准化 REST API 封装屏蔽不同模型的参数差异,对外提供统一的调用入口。
  • 聊天补全场景核心接口为 /api/chat,支持流式响应与全量响应两种模式,本次聚焦全量返回模式(stream: false)。

1.2 通用约定

1.2.1 模型命名规则

  • 采用 模型名:标签 格式,例如 deepseek-r1:1.5b,标签用于标识具体版本与参数量。

1.2.2 时长单位

  • 所有时间类字段统一以纳秒为单位返回。

1.2.3 流式响应约定

  • 接口默认启用流式响应,逐块返回 JSON 对象;通过 stream: false 可关闭流式,一次性返回完整响应对象。

2 ~> /api/chat 全量返回接口规范

2.1 接口基本信息

  • 请求方法:POST
  • 接口路径:/api/chat
  • 默认服务地址:http://127.0.0.1:11434
  • Content-Type:application/json

2.2 请求参数体系

2.2.1 必选参数

  • model:字符串类型,指定调用的模型名称,符合模型命名约定。
  • messages:数组类型,存储对话历史消息,用于维持对话上下文记忆。
    • 单条消息对象字段:
      • role:消息角色,取值为 system、user、assistant、tool。
      • content:字符串类型,消息文本内容。
      • images:可选,数组类型,多模态模型传入的图片列表。
      • tool_calls:可选,数组类型,模型发起的工具调用请求列表。

2.2.2 可选高级参数

  • stream:布尔类型,控制是否启用流式响应,false 为全量返回模式。
  • format:字符串类型,指定响应返回格式,支持 json 或自定义 JSON Schema,用于实现结构化输出。
  • options:JSON 对象,模型推理超参数,核心字段包括:
    • temperature:浮点型,控制生成随机性,取值范围 0~1,值越高创造性越强。
    • num_ctx:整型,上下文窗口大小,默认值 2048,对应其他平台的 max_tokens 语义。
    • 支持 Modelfile 中定义的其他模型参数。
  • keep_alive:字符串类型,控制模型在请求后保留在内存中的时长,默认 5 分钟。
  • tools:数组类型,模型可调用的工具列表,JSON 格式,需模型支持。

2.3 响应报文结构

全量模式下返回单一 JSON 对象,标准结构如下:

{
"model": "deepseek-r1:1.5b",
"created_at": "2026-08-28T04:56:59.195988466Z",
"message": {
"role": "assistant",
"content": "\\n\\n您好!我是由中国的深度求索(DeepSeek)公司开发的智能助手DeepSeek-R1。如您有任何问题,我会尽我所能为您提供帮助。"
},
"done": true,
"done_reason": "stop",
"total_duration": 39751163910,
"load_duration": 1337544202,
"prompt_eval_count": 6,
"prompt_eval_duration": 1795779000,
"eval_count": 40,
"eval_duration": 35587041000
}

2.4 响应核心字段说明

  • model:本次响应使用的模型名称。
  • created_at:响应生成时间戳,ISO 8601 格式。
  • message:模型回复消息对象,包含 role 与 content 字段。
  • done:布尔类型,标识响应是否完成,全量模式下恒为 true。
  • done_reason:结束原因,stop 表示正常结束。
  • total_duration:请求总耗时,单位纳秒。
  • load_duration:模型加载耗时,单位纳秒。
  • prompt_eval_count:输入 Prompt 的 Token 数量。
  • prompt_eval_duration:输入 Prompt 推理耗时,单位纳秒。
  • eval_count:输出回复的 Token 数量。
  • eval_duration:输出生成耗时,单位纳秒。

3 ~> 环境验证与常见排障

3.1 curl 接口验证命令

标准全量返回验证请求命令:

curl -s -X POST "http://127.0.0.1:11434/api/chat" \\
-H "Content-Type: application/json" \\
-d '{
"model": "deepseek-r1:1.5b",
"stream": false,
"messages": [
{
"role": "user",
"content": "你是谁?"
}
],
"options": {
"temperature": 0.7,
"num_ctx": 2048
}
}'

3.2 常见故障排查

3.2.1 代理冲突问题

  • 现象:请求无响应、连接超时或失败。
  • 成因:系统环境变量配置了 HTTP 代理,curl 默认继承代理配置,导致本地请求被代理转发。
  • 排查步骤:
    • 检查并关闭终端代理环境变量,执行 source ~/.bashrc 重新加载环境配置。
    • 检查 curl 配置文件 ~/.curlrc,注释掉代理配置行。
    • 重启终端后重新执行请求。

3.2.2 首次请求慢问题

  • 现象:首次调用接口耗时显著高于后续调用。
  • 成因:Ollama 需要将模型从磁盘加载到内存中,属于冷启动开销。
  • 说明:属于正常现象,模型加载完成后后续请求速度显著提升;可通过 keep_alive 参数延长模型驻留时间。

4 ~> C++ 全量返回实现流程

4.1 实现总流程

  • 模型有效性检测
  • 构造请求参数(温度、上下文窗口、历史消息)
  • 构建并序列化 JSON 请求体
  • 创建 HTTP 客户端并配置超时
  • 发送 POST 请求
  • 响应状态校验
  • JSON 反序列化
  • 提取模型回复内容
  • 4.2 模型有效性检测

    // 发送消息-全量返回
    std::string OllamaLLMProvider::sendMessage(const std::vector<Message>& messages,
    const std::map<std::string, std::string>& requestParam)
    {
    // 检查模型是否可用
    if (!isAvailable()) {
    ERR("OllamaLLMProvider::sendMessage: model is not available");
    return "";
    }

    4.3 请求参数构造

    4.3.1 超参数提取

    从请求参数中提取温度与上下文窗口大小,未配置则使用默认值:

    // 构造温度值和上下文Token数
    float temperature = 0.7f;
    int numCtx = 2048;

    if (requestParam.find("temperature") != requestParam.end()) {
    temperature = std::stof(requestParam.at("temperature"));
    }
    if (requestParam.find("max_tokens") != requestParam.end()) {
    numCtx = std::stoi(requestParam.at("max_tokens"));
    }

    4.3.2 历史消息构建

    将内部消息结构转换为 JSON 数组格式:

    // 构建历史消息数组
    Json::Value messageArray(Json::arrayValue);
    for (const auto& message : messages) {
    Json::Value messageObject(Json::objectValue);
    messageObject["role"] = message._role;
    messageObject["content"] = message._content;
    messageArray.append(messageObject);
    }

    4.4 请求体构建与序列化

    **注意:**Ollama 接口中上下文窗口参数字段为 num_ctx,而非通用的 max_tokens。

    // 构建options超参数对象
    Json::Value options(Json::objectValue);
    options["temperature"] = temperature;
    options["num_ctx"] = numCtx;

    // 构建完整请求体
    Json::Value requestBody(Json::objectValue);
    requestBody["model"] = _modelName;
    requestBody["messages"] = messageArray;
    requestBody["options"] = options;
    requestBody["stream"] = false;

    // 序列化请求体为字符串
    Json::StreamWriterBuilder writerBuilder;
    std::string requestBodyStr = Json::writeString(writerBuilder, requestBody);

    4.5 HTTP 客户端配置与请求发送

    // 创建HTTP客户端,配置超时时间
    httplib::Client client(_endpoint.c_str());
    client.set_connection_timeout(30, 0); // 连接超时30秒
    client.set_read_timeout(60, 0); // 读取超时60秒

    // 设置请求头
    httplib::Headers headers = {
    {"Content-Type", "application/json"}
    };

    // 发送POST请求
    auto response = client.Post("/api/chat", headers, requestBodyStr, "application/json");
    if (!response) {
    ERR("OllamaLLMProvider::sendMessage: failed to send request, error: {}",
    to_string(response.error()));
    return "";
    }

    INFO("OllamaLLMProvider::sendMessage: response status: {}", response->status);
    INFO("OllamaLLMProvider::sendMessage: response body: {}", response->body);

    // 校验响应状态码
    if (response->status != 200) {
    ERR("OllamaLLMProvider::sendMessage: failed to send request, status: {}",
    response->status);
    return "";
    }

    4.6 响应反序列化与内容提取

    // 响应JSON反序列化
    Json::Value responseBody;
    Json::CharReaderBuilder reader;
    std::string errors;
    std::istringstream responseStream(response->body);

    if (!Json::parseFromStream(reader, responseStream, &responseBody, &errors)) {
    ERR("OllamaLLMProvider::sendMessage: failed to parse response body, errors: {}",
    errors);
    return "";
    }

    // 提取模型回复内容
    std::string modelResponse;
    if (responseBody.isMember("message") &&
    responseBody["message"].isObject() &&
    responseBody["message"].isMember("content")) {

    modelResponse = responseBody["message"]["content"].asString();
    INFO("OllamaLLMProvider::sendMessage: modelResponse: {}", modelResponse);
    return modelResponse;
    }

    // 响应格式异常处理
    ERR("OllamaLLMProvider::sendMessage: invalid response format");
    return "";
    }


    5 ~> 单元测试与工程配置

    5.1 测试用例编写

    基于 Google Test 框架的标准测试用例:

    TEST(OllamaLLMProviderTest, sendMessage) {
    auto provider = std::make_shared<ai_chat_sdk::OllamaLLMProvider>();
    ASSERT_TRUE(provider != nullptr);

    // 模型配置
    std::map<std::string, std::string> modelParam;
    modelParam["model_name"] = "deepseek-r1:1.5b";
    modelParam["model_desc"] = "本地部署deepseek-r1:1.5b模型,采用专家混合架构,专注于深度理解与推理";
    modelParam["endpoint"] = "http://localhost:11434";

    provider->initModel(modelParam);
    ASSERT_TRUE(provider->isAvailable());

    // 请求参数配置
    std::map<std::string, std::string> requestParam = {
    {"temperature", "0.7"},
    {"max_tokens", "2048"}
    };

    // 构造测试消息
    std::vector<ai_chat_sdk::Message> messages;
    messages.push_back({"user", "你是谁?"});

    // 调用接口
    std::string fullData = provider->sendMessage(messages, requestParam);
    ASSERT_FALSE(fullData.empty());
    }

    5.2 CMake 构建配置

    project(testLLM)

    # 设置C++标准
    set(CMAKE_CXX_STANDARD 17)
    set(CMAKE_CXX_STANDARD_REQUIRED ON)

    # 设置构建类型
    set(CMAKE_BUILD_TYPE Debug)

    # 添加可执行文件
    add_executable(testLLM
    testLLM.cpp
    ../sdk/src/util/myLog.cpp
    ../sdk/src/DeepSeekProvider.cpp
    ../sdk/src/ChatGPTProvider.cpp
    ../sdk/src/GeminiProvider.cpp
    ../sdk/src/OllamaLLMProvider.cpp
    )

    # 设置输出目录
    set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR})

    # 添加头文件搜索路径
    include_directories(${CMAKE_PROJECT_INCLUDE_DIR}/../sdk/include)

    # 依赖库配置
    find_package(OpenSSL REQUIRED)
    include_directories(${OPENSSL_INCLUDE_DIR})

    # 编译宏定义
    target_compile_definitions(testLLM PRIVATE CPPHTTPLIB_OPENSSL_SUPPORT)

    # 链接依赖库
    target_link_libraries(testLLM
    jsoncpp
    fmt
    spdlog
    gtest
    OpenSSL::SSL
    OpenSSL::Crypto
    )


    6 ~> 扩展知识点

    6.1 推理模型思考字段

    • 部分推理增强模型(如 DeepSeek-R1)会在回复内容中包含 `` 标签,内部存储模型推理思考过程。
    • SDK 默认直接返回完整内容,思考字段的解析与过滤由上层业务自行处理。

    6.2 结构化输出支持

    • 通过 format 参数传入 JSON Schema,可强制模型输出符合指定结构的 JSON 数据。
    • 适用于需要固定格式返回的业务场景,如分类、信息提取、结构化生成等。

    结尾

    uu们,本文的内容到这里就全部结束了,艾莉丝在这里再次感谢您的阅读!

    艾莉丝努力练剑

    C/C++ & Linux 底层探索者 | 一个正在努力练剑的技术博主


    👀
    【关注】 跟随我一起深耕技术领域,见证每一次成长。

    ❤️
    【点赞】 让优质内容被更多人看见,让知识传递更有力量。


    【收藏】 把核心知识点存好,在需要时随时查、随时用。

    💬
    【评论】 分享你的经验或疑问,评论区一起交流避坑!

    不要忘记给博主“一键四连”哦!

    “今日练剑达成!”

    “技术之路难免有困惑,但同行的人会让前进更有方向。”

    结语:希望对学习Linux相关内容的uu有所帮助,不要忘记给博主“一键四连”哦!

    往期回顾:

    【AI大模型接入SDK】Ollama大模型接入架构对比与实现

    🗡博主在这里放了一只小狗,大家看完了摸摸小狗放松一下吧!🗡

    ૮₍ ˶ ˊ ᴥ ˋ˶₎ა

    在这里插入图片描述

    赞(0)
    未经允许不得转载:171主机测评 » 【AI大模型接入SDK】Ollama API 全量响应实现
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址