AI之Ollama
介绍
什么是llama
LLaMA(Large Language Model Meta AI)是Meta开发的大规模预训练语言模型,基于Transformer架构,具有强大的自然语言处理能力。它在文本生成、问答系统、机器翻译等任务中表现出色。LLaMA模型有多个规模,从几亿到上千亿参数,适用于不同的应用场景。用户可以通过开源平台如Hugging Face获取LLaMA模型,并根据需要进行微调。LLaMA的灵活性和可扩展性使其在自然语言处理领域具有广泛的应用前景。
什么是 ollama
Ollama是一款用于本地安装和管理大规模预训练语言模型的工具。它简化了模型的下载、安装和使用流程,支持多种流行的模型如GPT-4和llama。Ollama通过易于使用的命令行界面和API,帮助用户快速部署和运行自然语言处理任务。它还支持多GPU配置和模型微调,适应各种计算资源和应用需求。总之,Ollama为研究人员和开发者提供了一个高效、灵活的本地化大模型解决方案。
下载
ollama 官网提供了各种平台的安装包,以下是下载地址:https://ollama.com/download
安装模型
ollama安装完成后就可以开始安装模型,先选择一个模型安装,ollama提供了一个页面供用户查询可以安装的开源模型。
在页面查询到想要安装的模块之后使用如下命令安装模型并启动:
ollama run [模型id]
安装示例
这里以llama3:latest为例:
ollama run llama3:latest
对话
安装完成后会自动跳转到对话,等待输入,可以输入帮助命令\?查看帮助;
添加UI
这里介绍如何给上面运行起来的大模型添加UI,我们选择open-webui给ollama添加UI,ollama安装大模型后会启动一个服务端,这里使用open-webui调用服务;
什么是Open-WebUI
Open-WebUI 是一个开源的用户界面框架,旨在提供简便的工具和接口,帮助用户轻松地访问和管理各种深度学习模型,尤其是大规模预训练语言模型。以下是对Open-WebUI的简要介绍:
开源框架:
Open-WebUI是一个开源项目,提供了灵活且可定制的用户界面,用于与各种深度学习模型进行交互。模型管理: 通过
Open-WebUI,用户可以方便地加载、配置和管理多个深度学习模型,包括GPT-4、BERT等大规模预训练模型。用户友好: 它提供了直观的界面,简化了模型使用过程,使非技术用户也能轻松上手进行自然语言处理任务。
集成支持:
Open-WebUI支持与多种后端深度学习框架(如TensorFlow、PyTorch)集成,提供高效的推理和训练功能。扩展性强: 用户可以根据需求自定义和扩展界面功能,以适应不同的应用场景和任务需求。
总之,Open-WebUI为用户提供了一个高效、直观的界面,使得大规模深度学习模型的使用更加便捷和高效。
下载
以下是Open-WebUI的Github地址,从这里将项目下到本地
https://github.com/open-webui/open-webui
部署
这里使用的是Docker部署,只需要在项目文件下使用Docker命令启动一个容器即可,当ollama与Open-WebUI部署在一台机器上,只需要运行:
docker run -d -p 3000:8080 --add-host=host.docker.internal:host-gateway -v open-webui:/app/backend/data --name open-webui --restart always ghcr.io/open-webui/open-webui:main
如果ollama部署在服务器上,可以使用如下命令在启动Docker容器时指定ollama的地址
docker run -d -p 3000:8080 -e OLLAMA_BASE_URL=https://example.com -v open-webui:/app/backend/data --name open-webui --restart always ghcr.io/open-webui/open-webui:main
OLLAMA_BASE_URL是指ollama暴露的API地址,一般为服务器地址加 11434。如:OLLAMA_BASE_URL=<http://192.168.0.111:11434>
使用
部署完成后在浏览器打开http://localhost:3000,展示的是Open-WebUI的界面,第一次加载可能有点慢,然后注册一个用户就可以开始使用;
模型选择
在对话框的左上角有下拉框,可以看到已下载的所有模型,也可以搜索其他模型直接安装;
接入应用
本节介绍如何使用代码与AI进行交互,由于使用的是.net技术栈,这里使用Microsoft的SemanticKernel框架对接Ollama的聊天服务,SemanticKernel基于Open-Api协议,所以只要是遵循Open-Api的AI都可以接入,如:GPT、Cohere等;
LLM(大语言模型)的OpenAPI协议是一种用于描述和调用大语言模型服务的接口规范。OpenAPI(Open API Specification)是一个定义了如何描述、生产、消费和可视化RESTful风格的Web服务的规范。它提供了一种标准的、语言无关的方式来描述API,使得开发人员和机器能够理解API的功能和如何与之交互。
在LLM的上下文中,OpenAPI协议可以用来定义大语言模型的输入和输出格式、调用方式、参数设置等。通过遵循OpenAPI协议,开发人员可以更容易地将大语言模型集成到自己的应用程序中,而不需要了解模型的具体实现细节。
例如,一个遵循OpenAPI协议的LLM服务可能会定义以下接口:
输入:用户提供的文本、上下文信息等。
输出:模型生成的文本、预测结果等。
调用方式:通过HTTP POST请求发送输入数据,并接收返回的输出数据。
参数设置:如模型的超参数、生成文本的长度限制等。
通过这种方式,开发人员可以使用任何支持HTTP请求的编程语言来调用LLM服务,从而实现各种自然语言处理任务,如文本生成、文本分类、机器翻译等。
总之,LLM的OpenAPI协议为开发人员提供了一种标准的方式来与大语言模型进行交互,使得大语言模型的集成变得更加简单和高效。
Nuget
创建一个项目,这里使用的是WebApi项目,先安装SemanticKernel以及ollama connector包
注意:ollama connector 还是 alpha 版本,请勿用于生产,搜索时勾选
包括预发布版
配置服务
在Program.cs文件中添加如下代码,添加一个Ollama客户端OllamaApiClient,并初始化Ollama服务地址和使用的模型Id,模型Id是下载时的模型名称,这里使用的是llama3:latest;
Program.cs
var endpoint = new Uri("http://localhost:11434");
var modelId = "llama3:latest";
builder.Services.AddSingleton(new OllamaApiClient(endpoint, modelId));
接入接口
注入客户端
创建一个AIChatController,将OllamaApiClient客户端注入到控制器中;
[Route("api/[controller]")]
[ApiController]
public class AIChatController : ControllerBase
{
private readonly OllamaApiClient _ollamaApiClient;
public AIChatController(OllamaApiClient ollamaApiClient)
{
_ollamaApiClient = ollamaApiClient;
}
}
创建接口
创建一个接口用于接收客户端参数,这个接口需要有几点需求:
- 接口接收数据的同时接收用户id,以辨别是哪个用户发送的消息;
- 同时需要将客户的消息关联上下文,使对话可以关联起来,而不是简单、毫无联系的一问一答,所以需要记录历史消息;
- 由于AI的返回都是逐字逐句的流式返回,这里使用推送的形式响应客户端请求,所以使用SSE推送数据给客户端;
参数
先实现第一点需求,接收用户id和消息,这里简单使用一个model接收数据,正式做法是使用jwt解析token获取id;
/// <summary>
/// 聊天参数
/// </summary>
public class AIChatParam
{
/// <summary>
/// 用户id
/// </summary>
public int UserId { get; set; }
/// <summary>
/// 数据
/// </summary>
public string Data { get; set; }
}
历史记录
接下来实现第二点需求,将聊天的上下文做关联,这就需要将历史消息记录到某个媒介,然后打包发送到模型中,模型就可以根据上下文接着回答问题;
这里简单的创建了一个类,使用一个Dictionary在应用内存中维护这些历史消息,如果需要可以将消息记录放到数据库;
/// <summary>
/// 历史记录
/// </summary>
public static class AIChatHistory
{
/// <summary>
/// 数据
/// </summary>
private static Dictionary<int, List<Message>> _data = new Dictionary<int, List<Message>>();
/// <summary>
/// 获取历史记录
/// </summary>
/// <param name="userId">用户id</param>
/// <returns></returns>
public static List<Message>? GetHistory(int userId)
{
return _data.GetValueOrDefault(userId)??new List<Message>();
}
/// <summary>
/// 最新记录
/// </summary>
/// <param name="userId">用户id</param>
/// <returns></returns>
public static Message GetLatestHistory(int userId)
{
Message msg = null;
if (_data.TryGetValue(userId, out var userData))
{
msg = userData.Last();
}
return msg;
}
/// <summary>
/// 添加
/// </summary>
/// <param name="userId">用户id</param>
/// <param name="msg">消息</param>
public static bool Add(int userId, Message msg)
{
if (_data.TryGetValue(userId, out var userData))
{
userData.Add(msg);
}
else
{
var list = new List<Message>();
list.Add(new Message(ChatRole.System, "以下对话请使用中文"));
list.Add(msg);
_data.Add(userId, list);
}
return true;
}
/// <summary>
/// 移除
/// </summary>
/// <param name="userId">用户id</param>
/// <returns></returns>
public static bool Clear(int userId)
{
if (_data.TryGetValue(userId, out _))
{
_data.Remove(userId);
}
return true;
}
}
接入
做好了准备这里就可以接入了,这里创建一个接口,用于接收用户输入的参数,接口获取到模型的回答后将响应推送给客户端,步骤如下:
- 设置Content-Type;
- 载入历史记录;
- 调用
ollama提供的接口; - 获取回答后开始推送消息
- 将回答存到用户的历史记录中;
[Route("api/[controller]")]
[ApiController]
public class AIChatController : ControllerBase
{
private readonly OllamaApiClient _ollamaApiClient;
public AIChatController(OllamaApiClient ollamaApiClient)
{
_ollamaApiClient = ollamaApiClient;
}
/// <summary>
/// Chat
/// </summary>
/// <param name="param">问答参数</param>
/// <returns></returns>
[HttpPost]
public async Task Chat(AIChatParam param)
{
Response.ContentType = "text/event-stream";
Response.Headers.Add("Cache-Control", "no-cache");
Response.Headers.Add("Connection", "keep-alive");
var userId = param.UserId;
AIChatHistory.Add(userId, new Message { Role = ChatRole.User, Content = param.Data });
var history = AIChatHistory.GetHistory(userId);
var req = new OllamaSharp.Models.Chat.ChatRequest()
{
Messages = history,
Stream = true
};
Console.OutputEncoding = Encoding.UTF8;
Console.WriteLine("User:" + param.Data);
var sb = new StringBuilder();
var content = _ollamaApiClient.ChatAsync(req);
Console.Write("Asist:");
await foreach (var chatMessageContent in content)
{
var msg = chatMessageContent?.Message.Content;
sb.Append(msg);
Console.Write(msg);
await Response.WriteAsync($"data: {msg}\n\n");
await Response.Body.FlushAsync();
}
AIChatHistory.Add(userId, new Message { Role = ChatRole.Assistant, Content = sb.ToString() });
Console.WriteLine();
}
}
通过以上逻辑就可以实现获取模型的回答,同时推送到客户端;
清除上下文
有时,在对话的过程中我们可能需要重新问新的问题,不需要再关联之前的上下文了,这就需要将历史记录重新载入,由于这里使用的是Dictionary,我们只需要将用户的历史记录移除即可,如果历史记录存在数据库中就需要额外的逻辑控制历史记录;最终代码如下:
[Route("api/[controller]")]
[ApiController]
public class AIChatController : ControllerBase
{
private readonly OllamaApiClient _ollamaApiClient;
public AIChatController(OllamaApiClient ollamaApiClient)
{
_ollamaApiClient = ollamaApiClient;
}
/// <summary>
/// Chat
/// </summary>
/// <param name="param">问答参数</param>
/// <returns></returns>
[HttpPost]
public async Task Chat(AIChatParam param)
{
Response.ContentType = "text/event-stream";
Response.Headers.Add("Cache-Control", "no-cache");
Response.Headers.Add("Connection", "keep-alive");
var userId = param.UserId;
AIChatHistory.Add(userId, new Message { Role = ChatRole.User, Content = param.Data });
var history = AIChatHistory.GetHistory(userId);
var req = new OllamaSharp.Models.Chat.ChatRequest()
{
Messages = history,
Stream = true
};
Console.OutputEncoding = Encoding.UTF8;
Console.WriteLine("User:" + param.Data);
var sb = new StringBuilder();
var content = _ollamaApiClient.ChatAsync(req);
Console.Write("Asist:");
await foreach (var chatMessageContent in content)
{
var msg = chatMessageContent?.Message.Content;
sb.Append(msg);
Console.Write(msg);
await Response.WriteAsync($"data: {msg}\n\n");
await Response.Body.FlushAsync();
}
AIChatHistory.Add(userId, new Message { Role = ChatRole.Assistant, Content = sb.ToString() });
Console.WriteLine();
}
/// <summary>
/// 清除上下文
/// </summary>
/// <param name="userId">用户id</param>
/// <returns></returns>
[HttpGet]
public async Task<IActionResult> Clear(int userId)
{
var res = AIChatHistory.Clear(userId);
Console.WriteLine("清除上下文");
return Ok(res);
}
}
AI之Ollama的更多相关文章
- 马里奥AI实现方式探索 ——神经网络+增强学习
[TOC] 马里奥AI实现方式探索 --神经网络+增强学习 儿时我们都曾有过一个经典游戏的体验,就是马里奥(顶蘑菇^v^),这次里约奥运会闭幕式,日本作为2020年东京奥运会的东道主,安倍最后也已经典 ...
- 普通程序员如何转向AI方向
眼下,人工智能已经成为越来越火的一个方向.普通程序员,如何转向人工智能方向,是知乎上的一个问题.本文是我对此问题的一个回答的归档版.相比原回答有所内容增加. 一. 目的 本文的目的是给出一个简单的,平 ...
- AI人工智能系列随笔
初探 AI人工智能系列随笔:syntaxnet 初探(1)
- 游戏AI系列内容 咋样才能做个有意思的AI呢
游戏AI系列内容 咋样才能做个有意思的AI呢 写在前面的话 怪物AI怎么才能做的比较有意思.其实这个命题有点大,我作为一个仅仅进入游戏行业两年接触怪物AI还不到一年的程序员来说,来谈这个话题,我想我是 ...
- MySQL Workbench建表时 PK NN UQ BIN UN ZF AI 的含义
[转自网络]https://my.oschina.net/cers/blog/292191 PK Belongs to primary key 作为主键 NN Not Null 非空 UQ Uniqu ...
- 【AI开发第一步】微软认知服务API应用
目录 介绍 API分类 使用‘视觉’API完成的Demo 点击直接看干货 介绍 从3月份Google家的阿尔法狗打败韩国围棋冠军选手李世石,到之后微软Build2016大会宣布的“智能机器人”战略.种 ...
- 扎克伯格开发的家用AI: Jarvis
扎克伯格本周二在facebook发布了一篇文章,介绍自己利用个人时间开发的一套在自己家里使用的AI系统,并将它命名为Jarvis,对!就是电影钢铁侠里的AI助手Jarvis. 文章并没有讲细节的技术c ...
- 趣说游戏AI开发:对状态机的褒扬和批判
0x00 前言 因为临近年关工作繁忙,已经有一段时间没有更新博客了.到了元旦终于有时间来写点东西,既是积累也是分享.如题目所示,本文要来聊一聊在游戏开发中经常会涉及到的话题--游戏AI.设计游戏AI的 ...
- 自动绘图AI:程序如何画出动漫美少女
序 全新的图形引擎与AI算法,高效流畅地绘出任何一副美丽的图像. IDE:VisualStudio 2015 Language:VB.NET/C# Graphics:EDGameEngine 第一节 ...
- 微软要如何击败Salesforce?Office365、Azure、Dynamics365 全面布局AI | 双语
微软在上月宣布组建自己的 AI 研究小组.该小组汇集了超过 5000 名计算机科学家和工程师,加上微软内部研究部门,将共同挖掘 AI 技术. 与此同时,亚马逊,Facebook,Google,IBM ...
随机推荐
- DDCA —— 内存一致性
1. 同步(Synchronization) 1.1 构造锁(Locks) 原子(atomic)执行:应用程序的某些部分必须独占执行(原子性),这意味着在这些部分执行期间,其他并行进程无法访问或修改相 ...
- 【Amadeus原创】docker安装TOMCAT,并运行本地代码
1,docker 下载tomcat [root@it-1c2d ~]# docker pull tomcat ... [root@it-1c2d ~]# docker images REPOSITOR ...
- 12C++循环结构-for循环(2)
一.循环变量为字符型 试编一程序,按字典顺序输出26个字母. 流程图: 程序代码如下: #include <iostream> //包含输入输出流头文件iostream using nam ...
- 腾讯云 CHDFS 助力微信秒级异常检测
微信全景监控平台介绍 微信全景监控平台,是微信的多维指标 OLAP 监控以及数据分析平台.支持自定义多维度指标上报,海量数据实时上卷下钻分析,提供了秒级异常检测告警能力. 项目高效支撑了视频号.微信支 ...
- 更改 macOS 用户帐户和个人文件夹的名称
https://support.apple.com/zh-cn/HT201548 您可以对创建 macOS 用户帐户时命名的用户帐户和个人文件夹进行重命名. 您的 macOS 用户帐户名称和您个人 ...
- Qt/C++编写物联网组件/支持modbus/rtu/tcp/udp/websocket/mqtt/多线程采集
一.功能特点 支持多种协议,包括Modbus_Rtu_Com/Modbus_Rtu_Tcp/Modbus_Rtu_Udp/Modbus_Rtu_Web/Modbus_Tcp/Modbus_Udp/Mo ...
- Qt音视频开发20-vlc内核动态保存录像文件(不需要重新编译源码)
一.前言 在vlc默认提供的保存文件方式中,通过打开的时候传入指定的参数来保存文件,直到关闭播放生成文件,这种方式简单暴力,但是不适用大部分的场景,大部分时候需要的是提供开始录制和停止录制的功能,也就 ...
- 这是我见过最通俗易懂的SVD(奇异值分解)算法介绍
线性代数是机器学习领域的基础,其中一个最重要的概念是奇异值分解(SVD),本文尽可能简洁的介绍SVD(奇异值分解)算法的基础理解,以及它在现实世界中的应用. SVD是最广泛使用的无监督学习算法之一,它 ...
- OGC——WFS服务
一.WFS简介 OGC的WMS和WMTS规范都是有关空间数据显示的标准,而WFS(Web Feature Service)则允许用户在分布式的环境下通过HTTP对空间数据进行增.删.改.查. 具 ...
- new idea
如何我希望将url链接作为大语言模型的输入,同时通过大模型的能力来学习与认识url网页链接中的文本.图片.语音等元素,应该怎么做? 要将URL链接作为输入来学习与识别URL中的文本.图片.语音等元素, ...