Ollama API 全量响应模式接入指南:从接口规范到 C++ 实现
Ollama API 基础认知
Ollama 是一个用于在本地运行大语言模型的服务,它通过统一的 REST API 屏蔽了不同模型的底层差异。对于聊天场景,核心接口是 /api/chat,该接口支持两种响应模式:流式(逐块返回)和全量(一次性返回完整结果)。本文聚焦于后者,即设置 stream: false 的使用方式。

模型命名与时长单位
调用时需指定模型名称,格式为 模型名:标签,例如 deepseek-r1:1.5b。所有时间相关的字段(如加载耗时、推理耗时)均以纳秒为单位返回,这在做性能分析时需要注意单位换算。
/api/chat 全量返回接口规范
接口基本信息
- 方法:
POST - 路径:
/api/chat - 地址: 默认为
http://127.0.0.1:11434 - Content-Type:
application/json
请求参数
请求体是一个 JSON 对象,包含必选和可选参数。
必选参数:
model: 字符串,指定要使用的模型。messages: 数组,包含对话历史。每条消息有role(system/user/assistant/tool)和content字段。
关键可选参数:
stream: 设为false以获取全量响应。options: 一个对象,用于传递模型超参数。temperature: 控制输出随机性,范围 0~1。num_ctx: 上下文窗口大小(注意,Ollama 用的是num_ctx,不是常见的max_tokens)。
format: 可设为json或一个 JSON Schema,强制模型输出结构化数据。
响应结构
全量模式下,服务器会返回一个完整的 JSON 对象,而非多个数据块。其核心结构如下:
{
"model": "deepseek-r1:1.5b",
"created_at": "2026-08-28T04:56:59.195988466Z",
"message": {
"role": "assistant",
"content": "..."
},
"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
}其中,message.content 就是我们需要的模型回复文本。其他字段如 *_duration 和 *_count 对于监控和调试非常有用,分别记录了各阶段的耗时(纳秒)和处理的 token 数量。
环境验证与常见排障
在编写代码前,最好先用 curl 命令行工具验证本地 Ollama 服务是否正常工作。
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}
}'执行这条命令,如果能立刻看到一个完整的 JSON 响应,说明环境是通的。
常见问题
代理冲突:如果你的系统配置了 HTTP 代理,curl 可能会尝试通过代理连接 127.0.0.1,导致请求失败或超时。解决方法是临时取消代理设置,或者在 curl 命令中显式指定不使用代理(--noproxy "*")。
首次请求慢:第一次调用某个模型时,Ollama 需要从磁盘将模型加载到内存,这个过程可能很慢。这是正常现象,后续请求会快很多。可以通过 keep_alive 参数让模型在内存中多驻留一段时间。
C++ 全量返回实现流程
下面是一个基于 C++ 的完整实现思路,使用了 httplib 作为 HTTP 客户端,JsonCpp 处理 JSON 数据。
1. 构造请求体
首先,将内部的消息列表和超参数转换成 Ollama 要求的 JSON 格式。
// 构建历史消息数组
Json::Value messageArray(Json::arrayValue);
for (const auto& message : messages) {
Json::Value msg;
msg["role"] = message._role;
msg["content"] = message._content;
messageArray.append(msg);
}
// 构建options
Json::Value options;
options["temperature"] = temperature; // 从配置中读取
options["num_ctx"] = numCtx; // 注意字段名是 num_ctx
// 构建完整请求体
Json::Value requestBody;
requestBody["model"] = _modelName;
requestBody["messages"] = messageArray;
requestBody["options"] = options;
requestBody["stream"] = false; // 关键!关闭流式
// 序列化为字符串
Json::StreamWriterBuilder builder;
std::string requestBodyStr = Json::writeString(builder, requestBody);这里的关键点是确保 stream 字段为 false,并且上下文窗口参数使用 num_ctx 而非 max_tokens。

2. 发送 HTTP 请求

使用 httplib::Client 创建客户端,配置合理的超时时间(模型推理可能较慢),然后发送 POST 请求。
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"}};
auto response = client.Post("/api/chat", headers, requestBodyStr, "application/json");
if (!response || response->status != 200) {
// 处理网络错误或HTTP错误
return "";
}3. 解析响应
收到响应后,将其反序列化为 JSON 对象,并从中提取 message.content 字段。
Json::Value responseBody;
Json::CharReaderBuilder reader;
std::string errors;
std::istringstream stream(response->body);
if (!Json::parseFromStream(reader, stream, &responseBody, &errors)) {
// JSON解析失败
return "";
}
// 提取回复内容
if (responseBody.isMember("message") &&
responseBody["message"].isObject() &&
responseBody["message"].isMember("content")) {
return responseBody["message"]["content"].asString();
} else {
// 响应格式不符合预期
return "";
}整个流程的核心在于正确地构造请求和稳健地处理响应,尤其是对各种可能的错误(网络、HTTP状态码、JSON格式)进行妥善处理。
单元测试与工程配置
为了保证代码质量,编写单元测试是必不可少的。可以使用 Google Test 框架来模拟调用过程。
TEST(OllamaLLMProviderTest, sendMessage) {
auto provider = std::make_shared<OllamaLLMProvider>();
// ... 初始化模型参数 ...
provider->initModel(modelParam);
ASSERT_TRUE(provider->isAvailable());
std::vector<Message> messages = {{"user", "你是谁?"}};
std::map<std::string, std::string> requestParam = {
{"temperature", "0.7"},
{"max_tokens", "2048"}
};
std::string response = provider->sendMessage(messages, requestParam);
ASSERT_FALSE(response.empty());
// 可以进一步断言response是否包含预期关键词
}对应的 CMakeLists.txt 需要链接必要的库,如 jsoncpp、httplib(通常作为头文件库)、OpenSSL(用于 HTTPS)以及 gtest。
# ... 其他配置 ...
target_link_libraries(testLLM
jsoncpp
fmt
spdlog
gtest
OpenSSL::SSL
OpenSSL::Crypto
)扩展知识点
推理思考字段
像 DeepSeek-R1 这样的推理模型,有时会在回复中包含类似 `` 的标记,里面是模型的“思维链”。SDK 通常直接返回原始内容,是否解析和展示这部分内容,应由上层应用决定。
结构化输出
如果业务需要模型返回固定格式的数据(比如一个 JSON 对象),可以在请求中加入 format 字段。设为 "json" 可以让模型尽量输出合法 JSON;更进一步,传入一个完整的 JSON Schema,则能约束输出的具体结构,这对于自动化处理非常有用。