Ollama接口系统详解

Ollama是一个专为本地机器设计的开源框架,旨在简化大型语言模型(LLM)的部署和运行过程。它提供了一套工具和命令,使用户能够轻松地下载、管理和运行各种语言模型,包括LLaMA、LLaVA等流行模型。Ollama通过优化设置和配置细节,如GPU使用情况,提高了模型运行的效率,并且其代码简洁明了,运行时占用资源少,使得在本地高效地运行大型语言模型成为可能。

Ollama支持Mac、Linux以及Windows(预览版)平台,并提供了Docker镜像,方便用户在不同操作系统环境下部署和使用。

Ollama支持通过Ollama原生接口和OpenAI兼容接口两种方式调用,本文将对Ollama原生接口做详细介绍

这里假设我们已经完成Ollama程序的安装,并且有一个llama3.1的模型,在本地的11414端口能够通过接口访问。具体步骤可以参考:

Ollama本地部署自定义大模型

Ollama支持命令行和接口的方式管理模型以及推理,因此如果已经通过命令行创建了模型,并且只对用接口进行推理感兴趣,可以直接跳到3. 模型推理部分。

1. Ollama接口的访问方式

Ollama提供的接口需要使用HTTP的GET或POST方法访问,具体是用什么类型取决于具体接口。

这里介绍两种访问Ollama接口的工具,第一种是使用Python的requests库,第二种是用curl命令。用curl命令更简短,因此本文后续大多数情况下以curl命令为例。

1.1 GET方法访问

以用GET请求访问/api/tags为例。

(1)requests库

import requests

url = 'http://127.0.0.1:11434/api/tags'
resp = requests.get(url)

print(resp.text)

其中127.0.0.1代表本机,11434是Ollama默认端口,url是完整地址。resp.text代表将返回的内容,字符串类型。

(2)curl命令

curl http://127.0.0.1:11434/api/tags

1.2 POST方法访问

以用POST请求访问/api/generate为例。

这里假设已经创建好一个名为llama3.1的模型,同时不使用流返回。

(1)requests库

import requests

url = 'http://localhost:11434/api/generate'
data = {
    'prompt': '你是谁?',
    'model': 'llama3.1',
    'stream': False
}

resp = requests.post(url, json=data)
print(resp.text)

(2)curl命令

curl命令-d参数后面跟要传入的参数,同时-d也会默认发送POST请求。

curl http://localhost:11434/api/generate -d '{
  "model": "llama3.1",
  "prompt": "你是谁?",
  "stream": false
}'

2. 模型管理

2.1 创建模型

用接口创建模型需要2步:(1)上传模型,(2)用Modelfile创建模型。

2.1.1上传模型

这里假设我们有一个模型ggml-model-Q4_K_M.gguf,位于/home/aa/bb文件夹中。

首先我们需要计算该模型的sha256签名,Ollama用该签名来确保上传的模型和原模型的一致性:

XX@YY:~$ sha256sum /home/aa/bb/ggml-model-Q4_K_M.gguf
4fd4066c43347d388c43abdf8a27ea093b83932b10c741574e10a67c6d48e0b0  /home/aa/bb/ggml-model-Q4_K_M.gguf

接下来我们可以用以下命令来上传模型,注意把后面的sha256签名换成刚才求得的数值:

curl -T /home/aa/bb/ggml-model-Q4_K_M.gguf -X POST http://localhost:11434/api/blobs/sha256:4fd4066c43347d388c43abdf8a27ea093b83932b10c741574e10a67c6d48e0b0

上传后实际上在模型存储模型的目录(我这里是/usr/share/ollama/.ollama/models/blobs)中添加了对应的blob文件,文件名为"sha256-"+sha256签名值,例如上面的模型上传完成后会生成一个名为sha256-4fd4066c43347d388c43abdf8a27ea093b83932b10c741574e10a67c6d48e0b0的blob文件。

2.1.2 用Modelfile创建模型

用Modelfile创建模型可以传入的参数如下,官方建议用modelfile而不是path这一参数:

  • name 模型名,必填项。
  • modelfile 对应单机所用的Modelfile中的内容,可选项。
  • stream 是否使用流传输,可选项。为false的话会等待创建完模型后再一并返回结果,反之会返回一串连续的结果。
  • path Model对应的路径,可选项。

以下是一个用接口创建模型的示例:

curl http://localhost:11434/api/create -d '{
  "name": "test1",
  "stream": false,
  "modelfile": "FROM /usr/share/ollama/.ollama/models/blobs/sha256-4fd4066c43347d388c43abdf8a27ea093b83932b10c741574e10a67c6d48e0b0"}'

{"status":"success"}

对于modelfile的额外说明:在实际调用接口时,事实上我们可以传入很多参数来覆盖创建模型时Modelfile里面设置的内容,比如TEMPLATE、SYSTEM、PARAMETER等,因此这里必需要有的其实只有模型名和FROM参数。此外,modelfile里FROM的后面的地址实际上是在Ollama运行的服务器中存储的blob文件地址,而不是和之前Modelfile中一样的gguf文件地址。

2.2 列举已创建模型

列举已创建模型可以通过GET方法调用/api/tags来实现,例如:

xx@yy:~$ curl http://localhost:11434/api/tags
{"models":[{"name":"test1:latest","model":"test1:latest","modified_at":"2024-08-02T19:48:30.169074243+08:00","size":4920734545,"digest":"8c4c8d7fb040f8c385b235701123120e0dc1388b206d0b3efee94f9b5fff04e1","details":{"parent_model":"","format":"gguf","family":"llama","families":["llama"],"parameter_size":"8.0B","quantization_level":"Q4_K_M"}}]}

2.3 列举当前运行模型

列举当前运行模型可以通过GET方法调用/api/ps来实现,例如:

xx@yy:~$ curl http://localhost:11434/api/ps
{"models":[{"name":"llama3.1:latest","model":"llama3.1:latest","size":9126135808,"digest":"0533a2c19bc715df77713aa293c92b19aab5c3a19a8ec175c9681557f5f56b51","details":{"parent_model":"","format":"gguf","family":"llama","families":["llama"],"parameter_size":"8.0B","quantization_level":"Q8_0"},"expires_at":"2024-08-04T09:38:03.925108804+08:00","size_vram":9126135808}]}

2.4 展示模型详情

展示模型详情可以通过POST方法调用/api/show接口实现,其参数如下:

  • name 模型名,必填项。
  • verbose 是否输出超详细信息,可选项。
xx@yy:~$ curl http://localhost:11434/api/show -d '{
  "name": "llama3.1","verbose":true 
}'

{"modelfile":"# Modelfile generated by \"ollama show\"\n# To build a new Modelfile based on this, replace FROM with:\n# FROM llama3.1:latest\n\nFROM /usr/share/ollama/.ollama/models/blobs/sha256-dcd637c360d411e6c842285a7625cb0476bbb5646f997bb28a9cb6420feb9bf8\nTEMPLATE \"\n |begin_of_text|\u003e |start_header_id|\u003esystem |end_header_id|\u003e\n\n{{.System}} |eot_id|\u003e |start_header_id|\u003euser |end_header_id|\u003e\n\n{{ .Prompt }} |eot_id|\u003e |start_header_id|\u003eassistant |end_header_id|\u003e\n\"\nSYSTEM \"\n你是西游记中的猪八戒,此时你还没有被贬下凡间,你还是骄傲的天蓬元帅。\n\"\nPARAMETER top_p 1\nPARAMETER stop  |begin_of_text|\u003e\nPARAMETER temperature 1\nPARAMETER top_k 100\n","parameters":"stop                           \" |begin_of_text|\u003e\"\ntemperature                    1\ntop_k                          100\ntop_p                          1","template":"\n |begin_of_text|\u003e |start_header_id|\u003esystem |end_header_id|\u003e\n\n{{.System}} |eot_id|\u003e |start_header_id|\u003euser |end_header_id|\u003e\n\n{{ .Prompt }} |eot_id|\u003e |start_header_id|\u003eassistant |end_header_id|\u003e\n","system":"\n你是西游记中的猪八戒,此时你还没有被贬下凡间,你还是骄傲的天蓬元帅。\n","details":{"parent_model":"","format":"gguf","family":"llama","families":["llama"],"parameter_size":"8.0B","quantization_level":"Q8_0"}}

2.5 删除模型

删除模型可以通过DELETE方法调用/api/delete接口实现,唯一需要传入的参数就是模型名,例如:

xx@yy:~$ curl -X DELETE http://localhost:11434/api/delete -d '{"name": "llama3.1"}'

3. 模型推理

ollama中的原生模型推理(不含OpenAI兼容)方式通过两个接口实现,一个是/api/generate,另一个是/api/chat。两者区别在于,使用前者需要提供完整的Prompt字符串,而使用后者实际上只需要提供类似{"role": "user", "content": "why is the sky blue?"}这样的输入,而真正输入大模型的Prompt由ollama自动生成,简而言之,前者自由度和灵活性更高,后者易用性更好。本文主要描述后一种接口。

调用方式:POST 请求 /api/chat

传入参数:

  • model: (必须) 使用的模型名
  • messages: 要传给大模型的对话内容,可以包含历史数据作为大模型的上下文参考,格式为message对象组成的列表

message对象包含以下字段:

  • role: 这一段话是谁说的,值可以是system(系统指令), user(用户指令)或 assistant(大模型历史回答)
  • content: 这一段话(这条消息)的具体内容
  • images (可选): 消息中提到的图片的列表,图片由base64编码表示 (用于多模态模型例如llava)

高级参数 (可选):

  • format: 指定返回的结果的格式。目前只支持json。
  • options: Modelfile中指定过的模型参数,如果提供,将会覆盖Modelfile中的配置,例如temperature。
  • stream: 如果为false 将会等模型将所有结果都输出再打包返回,默认为流式返回(生成一个Token返回一个Token)。
  • keep_alive: 模型在显存(内存)中保持多久,超过该时间模型将会被自动卸载,默认5分钟。

3.1 流式接口

ollama的接口默认流式返回结果,比如可以通过以下语句调用ollama接口获得结果:

curl http://localhost:11434/api/chat -d '{
  "model": "llama3.1",
  "messages": [
    {
      "role": "user",
      "content": "why is the sky blue?"
    }
  ]
}'

之后会返回一串结果,例如:

{"model":"llama3.1","created_at":"2024-08-31T08:03:16.373065214Z","message":{"role":"assistant","content":"The"},"done":false}
{"model":"llama3.1","created_at":"2024-08-31T08:03:16.37308353Z","message":{"role":"assistant","content":" color"},"done":false}
{"model":"llama3.1","created_at":"2024-08-31T08:03:16.375438802Z","message":{"role":"assistant","content":" of"},"done":false}
......
{"model":"llama3.1","created_at":"2024-08-31T08:03:19.810821385Z","message":{"role":"assistant","content":""},"done_reason":"stop","done":true,"total_duration":10058701840,"load_duration":6568750876,"prompt_eval_count":17,"prompt_eval_duration":22186000,"eval_count":260,"eval_duration":3460578000}

可以看到,除最后一条数据外,每一条数据都返回了最终结果中一个Token对应的单词,在最后一条数据中给出结果统计,包括结束原因(是回答完成还是达到最大Token数)以及各项统计(总共耗时、各项耗时等),形式如下:

{
    "model": "llama3.1",
    "created_at": "2024-08-31T08:03:19.810821385Z",
    "message": {
        "role": "assistant",
        "content": ""
    },
    "done_reason": "stop",
    "done": true,
    "total_duration": 10058701840,
    "load_duration": 6568750876,
    "prompt_eval_count": 17,
    "prompt_eval_duration": 22186000,
    "eval_count": 260,
    "eval_duration": 3460578000
}

3.2 非流式接口

和流式接口不同,非流式接口会等模型输出完整结果后再把结果和统计数据统一打包返回。使用非流式接口只要在传入的数据中加入"stream": false即可,例如:

curl http://localhost:11434/api/chat -d '{
  "model": "llama3.1",
  "messages": [
    {
      "role": "user",
      "content": "why is the sky blue?"
    }
  ],
  "stream": false
}'

其结果如下:

{
    "model": "llama3.1",
    "created_at": "2024-08-31T08:16:54.428852236Z",
    "message": {
        "role": "assistant",
        "content": "The sky appears blue during the day due to a phenomenon called Rayleigh scattering. Here's what happens:\n\n1. **Sunlight enters Earth's atmosphere**: When sunlight from the sun enters our atmosphere, it encounters tiny molecules of gases such as nitrogen (N2) and oxygen (O2).\n2. **Scattering occurs**: These gas molecules scatter the light in all directions. However, they scatter shorter (blue) wavelengths more than longer (red) wavelengths.\n3. **Blue light is dispersed**: As a result, the blue light is scattered in all directions by the tiny molecules of gases in the atmosphere.\n4. **Our eyes see the blue**: When we look at the sky on a clear day, our eyes are seeing the blue light that has been scattered in all directions.\n\nThe same effect occurs with red light, but it's scattered less than blue light and is more easily absorbed by the Earth's surface, which is why the sky doesn't appear red. The combination of these effects gives us the blue color we see in the sky.\n\nHere are a few additional factors that affect the color of the sky:\n\n* **Dust particles**: Tiny dust particles in the atmosphere can scatter light and give the sky a hazy or brownish appearance.\n* **Clouds**: Water droplets or ice crystals in clouds can reflect sunlight and change the apparent color of the sky.\n* **Atmospheric pollution**: Air pollutants like nitrogen dioxide (NO2) can contribute to a yellowish-brown haze, especially near urban areas.\n\nIn summary, the blue color of the sky is primarily due to the scattering of light by tiny molecules in the atmosphere."
    },
    "done_reason": "stop",
    "done": true,
    "total_duration": 6253269565,
    "load_duration": 1893592816,
    "prompt_eval_count": 17,
    "prompt_eval_duration": 21881000,
    "eval_count": 333,
    "eval_duration": 4293667000
}

3.3 系统指令覆盖

可以通过在messages中加入角色为system的信息来覆盖系统指令,例如:

curl http://localhost:11434/api/chat -d '{
  "model": "llama3.1",
  "messages": [{
      "role": "system",
      "content": "You are a warm-hearted assistant, and you only speak Chinese."
    },
    {
      "role": "user",
      "content": "why is the sky blue?"
    }],
  "stream": false
}'

结果为:

{
    "model": "llama3.1",
    "created_at": "2024-08-31T08:44:27.415020765Z",
    "message": {
        "role": "assistant",
        "content": "空气中的微小颗粒会散射光线,天空呈现蓝色颜色的原因。"
    },
    "done_reason": "stop",
    "done": true,
    "total_duration": 511746253,
    "load_duration": 23891224,
    "prompt_eval_count": 34,
    "prompt_eval_duration": 19423000,
    "eval_count": 25,
    "eval_duration": 338212000
}

可以看到,回答变为了中文。

3.4 传入上下文

可以在messages中加入历史回答作为大模型的上下文,例如:

第一轮提问:

curl http://localhost:11434/api/chat -d '{
  "model": "llama3.1",
  "messages": [{
      "role": "system",
      "content": "You are a warm-hearted assistant, and you only speak Chinese."
    },
    {
      "role": "user",
      "content": "李华去公园玩把腿摔断了,被送到医院了。腿摔断一般要多长时间好?"
    }],
  "stream": false
}'

第一轮回答:

{
    "model": "llama3.1",
    "created_at": "2024-08-31T09:01:27.937888684Z",
    "message": {
        "role": "assistant",
        "content": "腿摔断的恢复时间不一,通常需要几个月才能基本康复。\n\n如果是轻微的骨折,一般可以在1-2个月内恢复,主要需要注意休息和康复锻炼。"
    },
    "done_reason": "stop",
    "done": true,
    "total_duration": 887862128,
    "load_duration": 14382137,
    "prompt_eval_count": 57,
    "prompt_eval_duration": 30081000,
    "eval_count": 54,
    "eval_duration": 710430000
}

第二轮提问:

curl http://localhost:11434/api/chat -d '{
  "model": "llama3.1",
  "messages": [
    {
        "role": "system",
        "content": "You are a warm-hearted assistant, and you only speak Chinese."
    },
    {
        "role": "user",
        "content": "李华去公园玩把腿摔断了,被送到医院了。腿摔断一般要多长时间好?"
    },
    {
        "role": "assistant",
        "content": "腿摔断的恢复时间不一,通常需要几个月才能基本康复。\n\n如果是轻微的骨折,一般可以在1-2个月内恢复,主要需要注意休息和康复锻炼。"
    },
    {
        "role": "user",
        "content": "李华为啥去医院了?"
    }
  ],
  "stream": false
}'

第二轮回答:

{
    "model": "llama3.1",
    "created_at": "2024-08-31T09:03:49.501696972Z",
    "message": {
        "role": "assistant",
        "content": "李华摔断腿了,被送到医院!"
    },
    "done_reason": "stop",
    "done": true,
    "total_duration": 492796943,
    "load_duration": 14238622,
    "prompt_eval_count": 129,
    "prompt_eval_duration": 66976000,
    "eval_count": 13,
    "eval_duration": 173253000
}

可以看到,大模型能够参考历史信息。

3.5 生成可复现回答

ollama将会对生成的logits进行随机采样以决定下一个Token选哪个,因此影响采样的因素包括temperaturetop_ktop_p以及随机数种子,因此保持以上参数不变可以确保相同输入能够得到相同输出,例如:

curl http://localhost:11434/api/chat -d '{
  "model": "llama3.1",
  "messages": [
    {
      "role": "user",
      "content": "Hello!"
    }
  ],
  "options": {
    "seed": 101,
    "temperature": 12.3,
    "top_p":0.85,
    "top_k":20
  },
  "stream": false
}'

4. 文本嵌入

ollama支持调用文本嵌入模型生成文本嵌入,接口调用格式为:POST /api/embeddings

例如:

curl http://localhost:11434/api/embeddings -d '{
  "model": "nomic-embed-text",
  "prompt": "Here is an article about llamas..."
}'

将会返回文本的嵌入向量,其维度与所选模型相关,返回太长就不写了。

寻找嵌入模型可以通过ollama官网搜索“Embedding”,里面带zh应该对中文支持比较好。

参考链接

  1. github.com/ollama/ollama/blob/main/docs/api.md
  2. curl 命令详解(超详细)_curl -d-CSDN博客
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值