Ollama
Ollama 本地部署 Deepseek R1 模型
Ollama项目介绍
Ollama是在Github上的一个开源项目,其项目定位是:一个本地运行大模型的集成框架,目前主要针对主流的LLaMA架构的开源大模型设计,通过将模型权重、配置文件和必要数据封装进由Modelfile定义的包中,从而实现大模型的下载、启动和本地运行的自动化部署及推理流程。此外,Ollama内置了一系列针对大模型运行和推理的优化策略,目前作为一个非常热门的大模型托管平台,基本主流的大模型应用开发框架如LangChain、AutoGen、Microsoft GraphRAG及热门项目AnythingLLM、OpenWebUI等高度集成。
Ollama通过将大模型运行的所有必要组件(如权重文件、配置设置和相关数据)封装在一个单一的文件或包中,`Modelfile 允许用户更容易地下载、安装、配置和启动模型。这种方法类似于其他软件或应用程序的安装包,它们将所有必要的文件打包在一起,以便用户可以通过简单的安装过程将软件添加到他们的系统中。
Ollama官方地址:https://ollama.com/
Ollama Github开源地址:https://github.com/ollama/ollama
Ollama项目本地安装
Ollama项目本地安装的方法极为简单,这里我们以Linux系统为例,先进入命令行终端,执行如下一条命令行即可自动化完成:
curl -fsSL https://ollama.com/install.sh | sh
Ollama下载 DeepSeek R1 及启动
需要说明的一点是:Ollama项目虽然提供了本地化大模型的能力,但这并不意味着所有大模型都可以通过它下载和使用,其支持的大模型的详细列表可在Ollama的官方模型库页面查看:https://ollama.com/library。
ollama run deepseek-r1:32b
Ollama 多GPU部署及serve启动
如果想加载多张显卡且做到负载均衡,可以去修改 ollama 的SystemD配置服务,首先找到当前服务器上GPU的 ID,执行命令如下:
nvidia-smi
如果想加载多张显卡且做到负载均衡,可以去修改 ollama 的SystemD配置服务,执行如下代码:
systemctl edit ollama.service
编辑并填写如下内容:
Environment="CUDA_VISIBLE_DEVICES=0,1,2,3" # 这里根据你自己实际的 GPU标号来进行修改
Environment="OLLAMA_SCHED_SPREAD=1" # 这个参数是做负载均衡
保存退出后,重新加载systemd并重新启动Ollama服务使其配置生效,执行如下命令:
systemctl daemon-reload
systemctl restart ollama
Ollama REST API 服务启动及调用
Ollama run xxx命令启动模型后,不仅仅是可以在命令行终端与启动的大模型进行对话,更重要的是它还会同步启动Ollama REST API,这个REST API服务简单理解:我们可以通过某种方式在代码环境中调用到使用Ollama模型启动的大模型,从而和大模型进行对话。默认绑定的 IP + Port 是:http://localhost:11434,所以,如果启动Ollama的服务和当前的代码环境是同一台机器的话,可以使用如下代码进行快速的调用测试:
from openai import OpenAI
client = OpenAI(
base_url='http://localhost:11434/v1/',
api_key='ollama', # 这里随便写,但是api_key字段一定要有
)
chat_completion = client.chat.completions.create(
model='deepseek-r1:32b', # 这里要修改成 你 ollama 启动模型的名称
messages=[
{
'role': 'user',
'content': '你好,请你介绍一下你自己',
}
],
)
print(chat_completion)
Ollama每个命令参数非常容易理解,大家可以自行进行尝试,其参数说明如下所示:
|
命令 |
描述 |
|
serve |
启动 Ollama 服务 |
|
create |
从 Modelfile 创建一个模型 |
|
show |
显示模型的信息 |
|
run |
运行一个模型 |
|
stop |
停止正在运行的模型 |
|
pull |
从注册表中拉取一个模型 |
|
push |
将一个模型推送到注册表 |
|
list |
列出所有模型 |
|
ps |
列出正在运行的模型 |
|
cp |
复制一个模型 |
|
rm |
删除一个模型 |
|
help |
显示关于任何命令的帮助信息 |
Ollama REST API
Ollama 服务启动后会提供一系列原生 REST API 端点。通过这些Endpoints可以在代码环境下与ollama启动的大模型进行交互、管理模型和获取相关信息。其中两个endpoint 是最重要的,分别是:
- POST /api/generate
- POST /api/chat
其他端点情况:
- POST /api/create
- POST /api/tags
- POST /api/show
- POST /api/copy
- DELETE /api/delete
- POST /api/pull
- POST /api/push
- POST /api/embed
- GET /api/ps
/api/generate 接口参数概览
常规参数
|
参数名 |
类型 |
描述 |
|
model |
(必需) |
模型名称,必须遵循 model:tag 格式,如果不提供,则将默认为 latest。 |
|
prompt |
(必需) |
用于生成响应的提示。 |
|
suffix |
(可选) |
模型响应后的文本。 |
|
images |
(可选) |
base64 编码图像的列表(适用于多模态模型,如 llava)。 |
高级参数 (可选)
|
参数名 |
类型 |
描述 |
|
format |
(可选) |
返回响应的格式。格式可以是 json 或 JSON 模式。最主要的问题是避免产生大量空格 |
|
options |
(可选) |
文档中列出的其他模型参数,例如 temperature。 |
|
system |
(可选) |
系统消息,用于覆盖 Modelfile 中定义的内容。 |
|
template |
(可选) |
要使用的提示模板,覆盖 Modelfile 中定义的内容。 |
|
stream |
(可选) |
如果为 false,响应将作为单个响应对象返回,而不是对象流。 |
|
raw |
(可选) |
如果为 true,则不会对提示应用格式。 |
|
keep_alive |
(可选) |
控制模型在请求后保持加载的时间(默认:5分钟)。 |
|
context |
(可选) |
(已弃用) 从先前请求返回的上下文参数,用于保持简短的对话记忆。 |
import requests # type: ignore
import json
# 设置 API 端点
generate_url = "http://192.168.110.131:11434/api/generate" # 这里需要根据实际情况进行修改
# 示例数据
generate_payload = {
"model": "deepseek-r1:7b", # 这里需要根据实际情况进行修改
"prompt": "请生成一个关于人工智能的简短介绍。", # 这里需要根据实际情况进行修改
"stream": False, # 默认使用的是True,如果设置为False,则返回的是一个完整的响应,而不是一个流式响应
}
# 调用生成接口
response_generate = requests.post(generate_url, json=generate_payload)
if response_generate.status_code == 200:
generate_response = response_generate.json()
print("生成响应:", json.dumps(generate_response, ensure_ascii=False, indent=2))
else:
print("生成请求失败:", response_generate.status_code, response_generate.text)
api/chat 接口详解
该接口使用提供的模型在聊天中生成下一条消息。与 /api/generate 的参数基本一致,但是在请求的参数上会根据聊天场景进行调整。主要调整的是:
- 不再使用
prompt参数,而是使用messages参数。 - 新增了
tools参数,用于支持工具调用。
常规参数
|
参数名 |
类型 |
描述 |
|
model |
(必需) |
模型名称。 |
|
messages |
(必需) |
聊天的消息,用于保持聊天记忆。 |
|
tools |
(可选) |
JSON 中的工具列表,供模型使用(如果支持)。 |
消息对象字段
|
字段名 |
描述 |
|
role |
消息的角色,可以是 system、user、assistant 或 tool。 |
|
content |
消息的内容。 |
|
images |
(可选) 要在消息中包含的图像列表(适用于多模态模型,如 llava)。 |
|
tool_calls |
(可选) 模型希望使用的 JSON 中的工具列表。 |
高级参数 (可选)
|
参数名 |
描述 |
|
format |
返回响应的格式。格式可以是 json 或 JSON 模式。 |
|
options |
文档中列出的其他模型参数,例如 temperature。 |
|
stream |
如果为 false,响应将作为单个响应对象返回,而不是对象流。 |
|
keep_alive |
控制模型在请求后保持加载的时间(默认:5分钟)。 |
# 提取 <think> 标签中的内容
think_start = generate_response["response"].find("<think>")
think_end = generate_response["response"].find("</think>")
if think_start != -1 and think_end != -1:
think_content = generate_response["response"][think_start + len("<think>"):think_end].strip()
else:
think_content = "No think content found."
# 提取正常的文本内容
normal_content = generate_response["response"][think_end + len("</think>"):].strip()
# 打印结果
print("思考内容:\n", think_content)
print("\n正常内容:\n", normal_content)
OpenAI Compatibility
本节内容我们来看一下 OpenAI Compatibility。 OpenAI 的 API 接口是大模型应用开发中最常用、且集成度最高的 API 接口规范,其兼容接口主要包括:
chat/completionscompletionsmodelsembeddings
我们上两节课程内容中介绍的/api/generate 和 /api/chat 接口,其实就是 Ollama 兼容 OpenAI 的 REST API 接口的底层实现。其中:
/api/generate接口对应OpenAI的completions接口;/api/chat接口对应OpenAI的chat/completions接口;
因此我们现在再来看ollama 中的OpenAI compatibility 的 API 接口调用,就非常容易理解了。
import requests
import json
# 设置 API 端点
chat_url = "http://192.168.110.131:11434/api/chat" # 这里需要根据实际情况进行修改
# 示例数据
chat_payload = {
"model": "deepseek-r1:32b", # 这里需要根据实际情况进行修改
"messages": [
{
"role": "user", # 消息角色,用户发送的消息
"content": "请生成一个关于人工智能的简短介绍。" # 用户的消息内容
}
],
"tools": [], # 如果有工具可以在这里添加
"stream": False, # 默认使用的是True,如果设置为False,则返回的是一个完整的响应,而不是一个流式响应
}
# 调用聊天接口
response_chat = requests.post(chat_url, json=chat_payload)
if response_chat.status_code == 200:
chat_response = response_chat.json()
print("生成响应:", json.dumps(chat_response, ensure_ascii=False, indent=2))
else:
print("生成请求失败:", response_chat.status_code, response_chat.text)
在OpenAI Compatibility 规范下,目前Ollama 支持的模型参数如下:
支持的功能
|
功能 |
描述 |
|
聊天完成 |
Chat completions |
|
流媒体 |
Streaming |
|
JSON模式 |
JSON mode |
|
可再现的输出 |
Reproducible outputs |
|
视觉 |
Vision |
|
工具 |
Tools |
支持的请求字段
|
请求字段 |
描述 |
|
model |
模型 |
|
messages |
消息 |
|
frequency_penalty |
频率惩罚 |
|
presence_penalty |
存在惩罚 |
|
response_format |
响应格式 |
|
seed |
种子 |
|
stop |
停止 |
|
stream |
流式输出 |
|
stream_options |
流式选项 |
|
include_usage |
包含使用情况 |
|
temperature |
温度 |
|
top_p |
Top-p 采样 |
|
max_tokens |
最大令牌数 |
|
tools |
工具 |
Ollama 服务接口压力测试
对于企业级应用来说,尤其是后台服务,考虑的因素会非常多。比如大模型问答的响应速度,系统服务的稳定性,业务请求的错误率,资源的利用率等等多个方面。不同应用场景,考虑的因素也会有所不同。像我们正在做的智能客服问答功能,更关注响应速度和稳定性,这就导致高吞吐量和高并发能力比较重要,直接影响服务承载能力和效率,往往是优化的重点。吞吐量通常指系统在单位时间内处理的请求数量,而并发量则是系统同时处理的请求数。
因为企业需要处理大量用户或设备的请求,尤其是在高峰时段。如果服务吞吐量低,可能导致延迟增加,用户体验下降,甚至服务崩溃。如果并发量不足,用户可能会遇到等待或超时;吞吐量低的话,处理速度慢,整体效率低下。
我们基于Ollama 模型服务启动的 REST API接口,每秒生成的 Token 数量可以被视为系统的吞吐量,因此我们需要一些方法,来根据实际的业务需求来评估当前的硬件资源是否满足需求,或者应该如何去采购硬件资源。
我们测试 Ollama 模型服务的吞吐量和并发量,需要核心关注的是以下几点:
- 使用
REST API接口进行测试,可以尝试使用/api/generate或者/api/chat,真实模拟用户在实际使用中的请求模式,帮助评估系统在真实场景下的表现。 Ollama原生的REST API接口支持多个控制Ollama行为的参数,可以更灵活的控制测试流程,其中:
-
num_predict参数来控制生成的token数量keep_alive设置为0,使用完模型后立即卸载temperature参数来控制生成文本的多样性,很多情况下,希望生成的文本尽可能保持一致,会将其设置为0,
- 根据
Ollama的REST API接口返回响应体中的eval_count和eval_duration来计算每秒生成的Token数量,即吞吐量,而不是用resquest发起和接收到响应的时间差值来计算,将模型服务和网络延迟解耦,更准确的评估模型服务的吞吐量。
  单次调用的伪代码如下:
```python
# 调用 ollama 的 generate 接口
async with session.post(
f"{self.url}/api/generate",
json={
"model": self.model,
"prompt": prompt, # 使用随机选择的问题
"stream": False,
# "keep_alive":0, # 使用完模型后立即卸载
"options": {
"temperature": 0.7,
"num_predict": 300, # 限制生成token数量,以尽可能保证单个请求的生成时间一致
}
}
) as response:
result = await response.json()
# 从响应中获取性能指标
eval_count = result.get("eval_count", 0) # 生成的token数
eval_duration = result.get("eval_duration", 0) # 生成时间(纳秒)
total_duration = result.get("total_duration", 0) # 总时间(纳秒)
# 计算 tokens/second
tokens_per_second = (eval_count / eval_duration * 1e9) if eval_duration > 0 else 0
本地服务器上测试 DeepSeek-R1:1.5B 模型分别在 双卡负载和四卡负载下的吞吐量和并发量,测试结果如下:
并发测试结果
|
测试类型 |
并发数 |
成功率 |
总token数 |
平均生成时间 (秒) |
平均总时间 (秒) |
平均每秒token数 |
实际总耗时 (秒) |
系统吞吐量 (tokens/s) |
|
两张卡 |
2 |
100% |
2742 |
3 |
4.03 |
91.96 |
23.84 |
115.01 |
|
两张卡 |
3 |
100% |
2686 |
3.61 |
3.71 |
73.56 |
14.78 |
181.75 |
|
两张卡 |
4 |
100% |
2665 |
4.48 |
4.59 |
59.75 |
14.16 |
188.19 |
|
两张卡 |
5 |
100% |
2556 |
4.8 |
4.91 |
53.34 |
12.39 |
206.27 |
|
单请求性能测试 |
- |
- |
300 |
2.44 |
2.52 |
123 |
- |
- |
|
四张卡 |
2 |
100% |
2526 |
2.64 |
4.16 |
96.77 |
25.38 |
99.51 |
|
四张卡 |
3 |
100% |
2456 |
3.34 |
3.44 |
72.44 |
14.51 |
169.28 |
|
四张卡 |
4 |
100% |
2781 |
4.54 |
4.65 |
62.27 |
14.59 |
190.57 |
|
四张卡 |
5 |
100% |
3000 |
6.53 |
6.65 |
45.93 |
14.42 |
208.07 |
|
单请求性能测试 |
- |
- |
300 |
2.52 |
2.59 |
119.31 |
- |
- |
从测试结果能够得出的一些关键结论是:
- 并发会导致单个请求的处理时间变长;
- 并发因为是并行处理,虽然单个请求时间变长,但是系统整体吞吐量会得到提升;
- 不一定用更多的卡就可以获得更高的吞吐量,需要根据实际情况去调整。
因此,大家在实际测试的时候,要尝试在不同的硬件配置和并发级别下进行测试,以找到最佳的性能平衡点。
更多推荐



所有评论(0)