C#整合Ollama实现本地LLMs调用
前言
近两年AIGC
发展的非常迅速,从刚开始的只有ChatGPT
到现在的很百家争鸣。从开始的大参数模型,再到后来的小参数模型,从一开始单一的文本模型到现在的多模态模型等等。随着一起进步的不仅仅是模型的多样化,还有模型的使用方式。大模型使用的门槛越来越低,甚至现在每个人都可以在自己的电脑上运行模型。今天我们要说的就是大模型工具中的佼佼者Ollama
,并演示如何通过C#
来使用Ollama
。
Ollama
Ollama
是一个开源的大语言模型(LLM)服务工具,它允许用户在本地PC环境快速实验、管理和部署大型语言模型。它支持多种流行的开源大型语言模型,如 Llama 3.1
、Phi 3
、Qwen 2
、GLM 4
等,并且可以通过命令行界面轻松下载、运行和管理这些模型。Ollama
的出现是为了降低使用大型语言模型的门槛,是让大型语言模型更加普及和易于访问。一言以蔽之就是Ollama让使用模型更简单
。无论是CPU
或是GPU
都可以,算力高的话推理速度更快,算力不足的话推理的慢,而且容易胡言乱语。
安装
Ollama
的安装方式常用的有两种,一种是去官网下载,另一种是去GitHub下载,可以选择对应的系统版本进行下载
- 官网首页直接下载 https://ollama.com/
- Github Relase下载 https://github.com/ollama/ollama/releases
我的是Windows操作系统,所以直接下载一路Next就可以,默认安装在C盘
无法更改,强迫症的话可以通过mklink
做链接,但是自动更新之后还是在C盘
。自动升级这一块不用太担心,联网的情况,如果有新版本Ollama
会推送更新。
安装完成之后可以修改常用的环境变量
- 通过
OLLAMA_MODELS
环境变量设置模型下载的位置,默认是在C盘
,可以换成其他地址。 - 通过
OLLAMA_HOST
设置Ollama
服务监听的端口,默认的是11434
。
安装完成之后通过version
查看,如果显示版本号则安装成功。
ollama --version
比较常用的指令不多,也很简单
ollama list
列出本地下载的模型ollama ps
查看正在运行的模型ollama pull 模型标识
下载模型到本地,比如我要下载qwen2 7b
则使用ollama pull qwen2:7b
ollama run 模型标识
运行模型,如果已下载则直接运行,如果没下载则先下载再运行。比如我要运行qwen2 7b
可以直接运行ollama run qwen2:7b
也可以将本地已有的GGUF
模型导入到Ollama
中去,操作也很简单。
- 编写一个名为
Modelfile
的文件,写入以下内容
FROM 模型路径/qwen2-0_5b-instruct-q8_0.gguf
- 通过
Ollama
创建模型
ollama create qwen2:0.5b -f Modelfile
- 运行刚创建的模型
ollama run qwen2:0.5b
需要注意的是运行7B
至少需要8GB
的内存或显存,运行13B
至少需要16GB
内存或显存。我电脑的配置信息如下
型号: 小新Pro16 AI元启
CPU: AMD Ryzen 7 8845H
内存: 32.0 GB
AMD Ryzen 7 8845H
内置NPU
,整体算力还可以, 运行运行13B
及以下的模型没太大问题。当然这种级别参数大小的模型不会是一个无所不能的模型,这种量级的模型运行成本相对较低,适合做一些特定场景的推理任务。如果需要无所不能的模型建议还是直接使用ChatGPT
这种商业模型。
命令启动
下载模型完成之后可以测试运行,通过cmd
运行指令,比如我运行起来qwen2:7b
模型
这种方式比较简单,只能是文字对话的方式而且没有样式,简单粗暴。
接口访问
Ollama
提供服务的本质还是http
接口,我们可以通过http接口的方式来调用/api/generate
接口
curl http://localhost:11434/api/generate -d '{"model": "qwen2:7b","prompt": "请你告诉我你知道的天气有哪些?用json格式输出","stream": false
}'
model
设置模型的名称prompt
提示词stream
设置为false
要求不要流式返回
因为是一次性返回所有内容,所以需要等待一会,如果需要流式输出可以设置为true
。等待一会后接口返回的信息如下所示
{"model": "qwen2:7b","created_at": "2024-09-04T06:13:53.1082355Z","response": "```json\n{\n \"常见天气\": [\n {\n \"类型\": \"晴\",\n \"描述\": \"天空无云或有少量高薄云,日间阳光充足。\",\n \"符号\": \"☀️\"\n },\n {\n \"类型\": \"多云\",\n \"描述\": \"大部分天空被云层覆盖,但能见蓝天,太阳时隐时现。\",\n \"符号\": \"🌤️\"\n },\n {\n \"类型\": \"阴天\",\n \"描述\": \"全天或大部分时间云量较多,几乎看不到阳光,光线较暗。\",\n \"符号\": \"☁️\"\n },\n {\n \"类型\": \"雨\",\n \"子类型\": [\n {\n \"类型\": \"小雨\",\n \"描述\": \"降水量不大,通常不会形成积水。\",\n \"符号\": \"🌦️\"\n },\n {\n \"类型\": \"中雨\",\n \"描述\": \"降水量适中,可能会有局部积水。\",\n \"符号\": \"🌧️\"\n },\n {\n \"类型\": \"大雨\",\n \"描述\": \"降水量大,可能伴有雷电和强风。\",\n \"符号\": \"⛈️\"\n }\n ]\n },\n {\n \"类型\": \"雪\",\n \"子类型\": [\n {\n \"类型\": \"小雪\",\n \"描述\": \"积雪较轻,地面可能仅局部有薄雪覆盖。\",\n \"符号\": \"❄️\"\n },\n {\n \"类型\": \"中雪\",\n \"描述\": \"降雪量中等,地面和部分植被可能有积雪。\",\n \"符号\": \"🌨️\"\n },\n {\n \"类型\": \"大雪\",\n \"描述\": \"降雪量很大,地面积雪深厚,交通和生活受严重影响。\",\n \"符号\": \"❄️💨\"\n }\n ]\n },\n {\n \"类型\": \"雾\",\n \"描述\": \"大气中的水汽在地面或近地面凝结形成大量悬浮的微小水滴或冰晶的现象。\",\n \"符号\": \"🌫️\"\n },\n {\n \"类型\": \"雷阵雨\",\n \"描述\": \"突然而短暂的强降雨伴有闪电和雷鸣,通常持续时间较短。\",\n \"符号\": \"⚡🌧️\"\n }\n ]\n}\n```","done": true,"done_reason": "stop","context": [151644,872,198,//...省略...73594],"total_duration": 70172634700,"load_duration": 22311300,"prompt_eval_count": 19,"prompt_eval_duration": 151255000,"eval_count": 495,"eval_duration": 69997676000
}
还有一种比较常用的操作就是大家比较关注的嵌入模型
,通俗点就是对文本或者图片、视频等信息进行特征提取转换成向量的方式,这时候需要使用/api/embed
接口,请求格式如下所示,这里使用的向量化模型是nomic-embed-text
大家可以自行去用ollama pull
这个模型
curl http://localhost:11434/api/embed -d '{"model": "nomic-embed-text:latest","input": "我是中国人,我爱我的祖国"
}'
嵌入接口返回的数据格式如下所示
{"model": "nomic-embed-text:latest","embeddings": [[0.012869273,0.015905218,-0.13998738,//...省略很多...-0.035138983,-0.03351391]],"total_duration": 619728100,"load_duration": 572422600,"prompt_eval_count": 12
}
当然Ollama
提供的接口还有很多,比如对话、模型管理等待,这里我们就不一一介绍了,有需要的同学可以自行查阅接口文档地址https://github.com/ollama/ollama/blob/main/docs/api.md
可视化UI
上面我们提到了两种方式访问Ollama
服务,一种是命令行的方式,另一种是接口的方式。这两种虽然方式原始,但是并没有界面操作显得直观,如果你想通过界面的方式通过Ollama
完成对话服务,官方Github
推荐的也比较多,有兴趣的同学可以自行查看文档https://github.com/ollama/ollama?tab=readme-ov-file#web–desktop,我选用的是第一个Open WebUI,简单的方式是通过Docker
直接运行
docker run -d -p 3000:8080 -e OLLAMA_BASE_URL=https://你的ollama服务ip:11434 -v open-webui:/app/backend/data --name open-webui --restart always ghcr.io/open-webui/open-webui:main
亦或者可以通过构建源码的方式构建启动,按照下面的命令一步一步来
- git clone https://github.com/open-webui/open-webui.git
- cd open-webui/
- cp -RPp .env.example .env(复制一份
.env.example
文件重命名为.env
。Windows系统的话使用copy .env.example .env) - npm install
- npm run build
- cd ./backend
- conda create --name open-webui-env python=3.11(用conda创建一个名为pen-webui-env的虚拟环境)
- conda activate open-webui-env(激活虚拟环境)
- pip install -r requirements.txt -U(安装python依赖)
- bash start.sh( Windows操作系统的话直接启动start_windows)
如你所见,它是依赖NodeJs
和Python
的,还需要安装Conda
- 🐰 Node.js >= 20.10
- 🐍 Python >= 3.11
- conda我用的是24.5.0
启动成功后,在浏览器上输入http://localhost:8080/
,注册一个用户名登陆进来之后界面如下所示
可以直接选择模型进行对话,类似ChatGPT
那种对话风格。
C#整合Ollama
上面我们了解到了Ollama
的基本安装和使用,明白了它的调用是基于Http接口
来完成的。其实我也可以参考接口文档自行封装一套调用,但是没必要, 因为有很多现成的SDK可以直接使用。
使用Ollama Sdk
这里使用的C#的SDK就叫0llama,它的Github地址是https://github.com/tryAGI/Ollama, 为什么选择它呢,其实也很简单,因为它支持function call
,这方便我们更早的体验新功能。安装它非常简单,相信同学们都会
dotnet add package Ollama --version 1.9.0
简单对话
简单的对话功能上手也没什么难度,都是简单代码
string modelName = "qwen2:7b";
using var ollama = new OllamaApiClient(baseUri: new Uri("http://127.0.0.1:11434/api"));Console.WriteLine("开始对话!!!");
string userInput = "";
do
{Console.WriteLine("User:");userInput = Console.ReadLine()!;var enumerable = ollama.Completions.GenerateCompletionAsync(modelName, userInput);Console.WriteLine("Agent:");await foreach (var response in enumerable){Console.Write($"{response.Response}");}Console.WriteLine();} while (!string.Equals(userInput, "exit", StringComparison.OrdinalIgnoreCase));
Console.WriteLine("对话结束!!!");
模型名称是必须要传递的,而且默认的是流式输出
,如果想一次返回同样的是设置stream为false
。示例使用的是qwen2:7b
模型。执行起来之后便可以直接对话,如下所示
整体来说国产模型里面qwen2:7b
整体的效果还是不错的,至少还不是扭曲事实。
多轮对话
如果需要进行分角色的多轮对话,要换一个方式使用,使用提供的Chat
方式,如下所示
string modelName = "glm4:9b";
using var ollama = new OllamaApiClient(baseUri: new Uri("http://127.0.0.1:11434/api"));
Console.WriteLine("开始对话!!!");
string userInput = "";
List<Message> messages = [];
do
{//只取最新的五条消息messages = messages.TakeLast(5).ToList();Console.WriteLine("User:");userInput = Console.ReadLine()!;//加入用户消息messages.Add(new Message(MessageRole.User, userInput));var enumerable = ollama.Chat.GenerateChatCompletionAsync(modelName, messages, stream: true);Console.WriteLine("Agent:");StringBuilder builder = new();await foreach (var response in enumerable){string content = response.Message.Content;builder.AppendLine(content);Console.Write(content);}//加入机器消息messages.Add(new Message(MessageRole.Assistant, builder.ToString()));Console.WriteLine();} while (!string.Equals(userInput, "exit", StringComparison.OrdinalIgnoreCase));
Console.WriteLine("对话结束!!!");
这次换了另一个国产模型glm4:9b
, 多轮对话和完全对话使用的对象不同。
- 完全对话使用的是Completions对象,多轮对话使用的是
Chat
对象。 - 多轮对话需要用
List<Message>
存储之前的对话记录,这里模型才能捕获上下文。
运行起来,执行效果如下所示
第一次我问他会c#吗,它说了一堆表示会。第二句我让它写一个简单的示例,但是我并没有说写c#示例,但是它可以通过上面的对话了解到意图,所以直接用c#给我写了一个示例。
function call
高版本的Ollama
支持function call
,当然这也要求模型也必须支持,如果模型本身不支持,那也是没有效果的,其中llama3.1
支持的比较好,美中不足是llama3.1
对中文支持的不太好,所以我们简单的演示一下,这里使用的是llama3.1:8b
模型,首先需要定义方法,这样和模型对话的时候,框架会把方法的元信息抽出来发给模型,让模型判断调用哪个,这里我简单定义了一个计算增删改查的接口,并实现这个接口。
//定义一个接口,提供元信息
[OllamaTools]
public interface IMathFunctions
{[Description("Add two numbers")]int Add(int a, int b);[Description("Subtract two numbers")]int Subtract(int a, int b);[Description("Multiply two numbers")]int Multiply(int a, int b);[Description("Divide two numbers")]int Divide(int a, int b);
}//实现上面的接口提供具体的操作方法
public class MathService : IMathFunctions
{public int Add(int a, int b) => a + b;public int Subtract(int a, int b) => a - b;public int Multiply(int a, int b) => a * b;public int Divide(int a, int b) => a / b;
}
有了上面的接口和实现类之后,我们就可以通过Ollama
使用它们了,使用方式如下
string modelName = "llama3.1:8b";
using var ollama = new OllamaApiClient(baseUri: new Uri("http://127.0.0.1:11434/api"));
var chat = ollama.Chat(model: modelName,systemMessage: "You are a helpful assistant.",autoCallTools: true);//给Ollama注册刚才定义的类
var mathService = new MathService();
chat.AddToolService(mathService.AsTools(), mathService.AsCalls());while (true)
{try{Console.WriteLine("User>");var newMessage = Console.ReadLine();var msg = await chat.SendAsync(newMessage);Console.WriteLine("Agent> " + msg.Content);}finally{//打印本次对话的所有消息Console.WriteLine(chat.PrintMessages());}
}
这里需要设置autoCallTools
为true
才能自动调用方法,PrintMessages()
方法用来打印本轮会话中所有的消息, 一般自动调用function call
的时候会产生多次请求,但是我们使用的时候是无感知的,因为框架已将帮我自动处理了,比如我的提示词是一个数学计算公式(12+8)*4/2=?
,如下所所示
通过PrintMessages()
方法打印的对话消息可知,虽然我只提供了一句提示词,但是Ollama SDK
因为支持自动调用工具,llama3.1:8b
将提示词算式(12+8)*4/2)
进行了拆分,计算步骤如下所示
- 先拆分了括号里的逻辑
12+8
并调用Add
方法得到结果20 - 然后第二步用上一步得到的结果调用
Multiply
计算20*4
得到80 - 再用上一步的结果调用
Divide
计算80/2
得到结果40 - 最后把Tools调用的步骤及结果一起在通过对话发送给
llama3.1
模型,模型得到最终的输出
如果我们不打印过程日志的话,模型只会输出
Assistant:
The correct calculation is:
(12+8)=20
20*4=80
80/2=40
Therefore,the answer is:40.
嵌入模型
上面我们提到过Ollama
不仅可以使用对话模型还可以使用嵌入模型
的功能,嵌入模型
简单的来说就是对文本、图片、语音等利用模型进行特征提起,得到向量数据的过程。通过Ollama SDK
可以使用Ollama
的嵌入功能,代码如下所示
string modelName = "nomic-embed-text:latest";HttpClient client = new HttpClient();client.BaseAddress = new Uri("http://127.0.0.1:11434/api");client.Timeout = TimeSpan.FromSeconds(3000);using var ollama = new OllamaApiClient(client);var embeddingResp = await ollama.Embeddings.GenerateEmbeddingAsync(modelName, "c#是一门不错的编程语言");Console.WriteLine($"[{string.Join(",", embeddingResp.Embedding!)}]");
得到的就是如下所示的向量信息
向量数据是可以计算相似度的,利用余弦夹角
的概念可以计算向量的空间距离,空间距离越近,两个向量的相似度便越高。如果大家了解颜色表RGB
的话就比较容易理解,举个例子(255, 0, 0)
就是纯红色,(255, 10, 10)
也是红色,但是不是纯红色。如果把(255, 0, 0)
和(255, 10, 10)
映射到一个三维的空间坐标图上它们的距离就很近,但是它们和纯蓝色(0, 0, 255)
的空间距离就很远,因为一个贴近X
轴,一个贴近Z
轴。现在大家锁熟知的向量数据库,大概采用的就是类似的原理。也是现在流行的RAG
检索增强生成的基础。
比如我把下面两句话嵌入模型得到向量值,然后通过计算余弦夹角
来比较它们的相似度
var embeddingResp = await ollama.Embeddings.GenerateEmbeddingAsync(modelName, "c#是一门不错的编程语言");
var embeddingResp2 = await ollama.Embeddings.GenerateEmbeddingAsync(modelName, "c#是很好的语言");
Console.WriteLine("相似度:" + CosineSimilarity([.. embeddingResp.Embedding!], [.. embeddingResp2!.Embedding]));//计算余弦夹角
public static double CosineSimilarity(double[] vector1, double[] vector2)
{if (vector1.Length != vector2.Length)throw new ArgumentException("向量长度必须相同");double dotProduct = 0.0;double magnitude1 = 0.0;double magnitude2 = 0.0;for (int i = 0; i < vector1.Length; i++){dotProduct += vector1[i] * vector2[i];magnitude1 += vector1[i] * vector1[i];magnitude2 += vector2[i] * vector2[i];}magnitude1 = Math.Sqrt(magnitude1);magnitude2 = Math.Sqrt(magnitude2);if (magnitude1 == 0.0 || magnitude2 == 0.0)return 0.0; // 避免除以零return dotProduct / (magnitude1 * magnitude2);
}
上面的得到的相似度结果是
相似度:0.9413230998586363
因为它们两句话表达的含义差不多,所以相似度很高。但是如果我要计算下面的两句话的相似度
var embeddingResp = await ollama.Embeddings.GenerateEmbeddingAsync(modelName, "c#是一门不错的编程语言");
var embeddingResp2 = await ollama.Embeddings.GenerateEmbeddingAsync(modelName, "我喜欢吃芒果和草莓");
那么利用余弦值计算出来它们的相似度只有0.59
,因为这两句话几乎没有任何关联。
相似度:0.5948448463206064
多模态模型
刚开始的对话模型都比较单一,都是简单的文本对话,随着不断的升级,有些模型已经支持多种格式的输入输出而不仅仅是单一的文本,比如支持图片、视频、语音等等,这些模型被称为多模态模型。使用Ollama
整合llava
模型体验一把,这里我是用的是llava:13b
。我在网上随便找了一张图片存放本地
用这张图片对模型进行提问,代码如下所示
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http://127.0.0.1:11434/api");
client.Timeout = TimeSpan.FromSeconds(3000);
using var ollama = new OllamaApiClient(client);
string modelName = "llava:13b";
string prompt = "What is in this picture?";
System.Drawing.Image image = System.Drawing.Image.FromFile("1120.jpg");
var enumerable = ollama.Completions.GenerateCompletionAsync(modelName, prompt, images: [BitmapToBase64(image)], stream: true);
await foreach (var response in enumerable)
{Console.Write($"{response.Response}");
}//Image转base64
public static string BitmapToBase64(System.Drawing.Image bitmap)
{MemoryStream ms1 = new MemoryStream();bitmap.Save(ms1, System.Drawing.Imaging.ImageFormat.Jpeg);byte[] arr1 = new byte[ms1.Length];ms1.Position = 0;ms1.Read(arr1, 0, (int)ms1.Length);ms1.Close();return Convert.ToBase64String(arr1);
}
我用提示词让模型描述图片里面的内容,然后把这张图片转换成base64
编码格式一起发送给模型,模型返回的内容如下所示
确实够强大,描述的信息很准确,措词也相当不错,如果让人去描述图片中的内容,相信大部分人描述的也没这么好,不得不说模型越来越强大了。
使用SemanticKernel
除了整合Ollama SDK
以外,你还可以用Semantic Kernel
来整合Ollama
,我们知道默认情况下Semantic Kernel
只能使用OpenAI
和Azure OpenAI
的接口格式,但是其他模型接口并不一定和OpenAI
接口格式做兼容,有时候甚至可以通过one-api
这样的服务来适配一下。不过不用担心Ollama
兼容了OpenAI
接口的格式,即使不需要任何的适配服务也可以直接使用,我们只需要重新适配一下请求地址即可。
using HttpClient httpClient = new HttpClient(new RedirectingHandler());
httpClient.Timeout = TimeSpan.FromSeconds(120);var kernelBuilder = Kernel.CreateBuilder().AddOpenAIChatCompletion(modelId: "glm4:9b",apiKey: "ollama",httpClient: httpClient);
Kernel kernel = kernelBuilder.Build();var chatCompletionService = kernel.GetRequiredService<IChatCompletionService>();
OpenAIPromptExecutionSettings openAIPromptExecutionSettings = new()
{ToolCallBehavior = ToolCallBehavior.AutoInvokeKernelFunctions
};var history = new ChatHistory();
string? userInput;
do
{Console.Write("User > ");userInput = Console.ReadLine();history.AddUserMessage(userInput!);var result = chatCompletionService.GetStreamingChatMessageContentsAsync(history,executionSettings: openAIPromptExecutionSettings,kernel: kernel);string fullMessage = "";System.Console.Write("Assistant > ");await foreach (var content in result){System.Console.Write(content.Content);fullMessage += content.Content;}System.Console.WriteLine();history.AddAssistantMessage(fullMessage);
} while (userInput is not null);public class RedirectingHandler : HttpClientHandler
{protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken){var uriBuilder = new UriBuilder(request.RequestUri!) { Scheme = "http", Host = "localhost", Port = 11434 };//对话模型if (request!.RequestUri!.PathAndQuery.Contains("v1/chat/completions")){uriBuilder.Path = "/v1/chat/completions";request.RequestUri = uriBuilder.Uri;}//嵌入模型if (request!.RequestUri!.PathAndQuery.Contains("v1/embeddings")){uriBuilder.Path = "/v1/embeddings";request.RequestUri = uriBuilder.Uri;} return base.SendAsync(request, cancellationToken);}
}
这里我们使用的是国产模型glm4:9b
,需要注意的是因为这里我们使用的是本地服务,所以需要适配一下服务的地址,通过编写RedirectingHandler
类,并用其构造一个HttpClient
实例传递给Kernel
。细心的同学可能已经发现了,这里我转发的Ollama
服务的路径也变成了和OpenAI
服务一样的路径,但是上面我调用Ollama
服务用的是/api/chat
和/api/embed
这种地址的接口。这是因为Ollama
为了兼容OpenAI
的标准,专门开发了一套和OpenAI
路径和参数都一样的接口,这一点是需要注意的。当然Ollama
暂时还没有全部兼容OpenAI
接口的全部特征,有兴趣的同学可以去看一下https://github.com/ollama/ollama/blob/main/docs/openai.md文档地址,了解更详细的内容。
上面的服务运行起来,我们同样可以进行对话,效果如下所示
同样的你可以通过SemanticKernel
使用嵌入模型的功能,如下所示
using HttpClient httpClient = new HttpClient(new RedirectingHandler());
httpClient.Timeout = TimeSpan.FromSeconds(120);var kernelBuilder = Kernel.CreateBuilder().AddOpenAITextEmbeddingGeneration(modelId:"nomic-embed-text:latest",apiKey:"ollama",httpClient: httpClient);
Kernel kernel = kernelBuilder.Build();
var embeddingService = kernel.GetRequiredService<ITextEmbeddingGenerationService>();
var embeddings = await embeddingService.GenerateEmbeddingsAsync(["我觉得c#是一门不错的编程语言"]);
Console.WriteLine($"[{string.Join(",", embeddings[0].ToArray())}]");
这里休要注意的是AddOpenAITextEmbeddingGeneration
方法是评估方法,将来版本有可能会删除的,所以默认的用VS使用该方法会有错误提醒,可以在csproj
的PropertyGroup
标签中设置一下NoWarn
来忽略这个提醒。
<PropertyGroup><OutputType>Exe</OutputType><TargetFramework>net8.0</TargetFramework><NoWarn>SKEXP0010;SKEXP0001</NoWarn>
</PropertyGroup>
总结
本文介绍了如何通过C#
结合Ollama
实现本地大语言模型的部署与调用,重点演示了在C#
应用中集成该功能的具体步骤。通过详细的安装指南与代码示例,帮助开发者快速上手。
- 首先我们介绍了
Ollama
的安装及基本设置和命令的使用。 - 然后介绍了如何通过
Ollama
调用大模型,比如使用命令行
、Http接口服务
、可视乎界面
。 - 再次我们我们通过
C#
使用了Ollama SDK
来演示了对话模式
、文本嵌入
、多模态模型
如何使用,顺便说了一下相似度计算相关。 - 最后,我们展示了通过
Semantic Kernel
调用Ollama
服务,因为Ollama
对OpenAI
的接口数据格式做了兼容,虽然还有部分未兼容,但是日常使用问题不大。
通过本文希望没有了解过大模型的同学可以入门或者大概了解一下相关的基础,毕竟这是近两年或者未来几年都比较火的一个方向。即使我们不能深入的研究他,但是我们也得知道它了解它的基本原理与使用。我们为什么要持续学习,因为这些东西很多时候确实是可以给我们提供方便。接触它,了解它,才能真正的知道它可以帮助我解决什么问题。
相关文章:

C#整合Ollama实现本地LLMs调用
前言 近两年AIGC发展的非常迅速,从刚开始的只有ChatGPT到现在的很百家争鸣。从开始的大参数模型,再到后来的小参数模型,从一开始单一的文本模型到现在的多模态模型等等。随着一起进步的不仅仅是模型的多样化,还有模型的使用方式。…...
C++基于opencv的视频质量检测--图像抖动检测
文章目录 0.引言1. 原始代码分析2. 优化方案3. 优化后的代码4. 代码详细解读 0.引言 视频质量图像抖动检测已在C基于opencv4的视频质量检测中有所介绍,本文将详细介绍其优化版本。 1. 原始代码分析 首先,我们来看图像抖动检测的原始代码: …...
Cuda By Example - 11 (Texture Memory 2-D)
跟1D一样,2D的代码也没有运行过。旧的方法看看就好。 声明二维Texture texture<float, 2> texConstSrc; texture<float, 2> texIn; texture<float, 2> texOut; 访问二维Texture 使用2D的Texture的便利性体现在blend_kernel函数里。不再需要通…...
Go匿名结构体使用场景
1. 定义 在 Go 语言中,匿名结构体(Anonymous Struct)是一种没有显式命名的结构体类型。你可以直接在代码中定义并使用匿名结构体,而不需要为其定义一个单独的类型名称。匿名结构体通常用于临时数据结构或一次性使用的场景。 匿名…...

Vue 发布十年了!你知道我这十年是怎么过的吗?
2014 年 2 月 3 日,Vue 在 Hacker News 上首次亮相。十年后的今天,Vue 已经成为使用最广泛的前端框架之一,拥有了一个非常丰富的生态系统。本文来梳理一下 Vue.js 十年以来的重要里程碑! 尤雨溪,无疑是 Vue.js 背后的灵…...

Unity 6 来袭
这里写自定义目录标题 1.提升渲染性能1.1 降低CPU开销 Lower CPU overhead1.2.减少内存带宽1.3.高档低分辨率帧2.多人游戏创作3.扩大多平台覆盖范围3.1.增进Android平台开发4.使用Runtime AI解锁各种可能性4.1.Unity Muse4.2.Unity Sentis5.实现更具吸引力的视觉效果5.1.自适应…...

SpringMVC课时1
一:SpringMVC Spring MVC 是 Spring 提供的一个基于 MVC 设计模式的轻量级 Web 开发框架,本质上相当于 Servlet,负责表述层(控制层)实现简化。 由于 Spring MVC 本身就是 Spring 框架的一部分,和 Spring 框架是无缝集成。 二:SSM的主要作用 三:SpringMVC的原理架构图 …...
【小白学机器学习30】样本统计的核心参数:均值/期望,方差,标准差,标准值。
目录 1 为什么我们要搞出来这么多指标/参数? 1.1 描述统计学为啥要搞出来这么多复杂的参数?什么平均值等 1.2 所以,需要用少数几个关键数据代表1群数据 1.2.1 平均值 1.2.2 平均值的问题:方差 2 代表性的数据1:…...
flink1.17.2安装和使用
版本:flink1.17.2 单机模式 配置 # 为了在别处连接flink-web rest.bind-address: 0.0.0.0命令 # 启动集群 bin/start-cluster.sh # 关闭集群 bin/stop-cluster.sh使用 使用浏览器连接 ip:8081 使用flink-web...

C向C++入门-- C语言填坑
1.c参考文档 我们在学习c中需要查找参照信息到是从这些文档中得到。 https://legacy.cplusplus.com/reference/ 标准只更新到C11,但是以头⽂件形式呈现,内容⽐较易看好懂。 https://zh.cppreference.com/w/cpp https://en.cppreference.com/w/ 后两…...

扫雷游戏(C语言详解)
扫雷游戏(C语言详解) 放在最前面的1、前言(扫雷游戏的简介)2、扫雷游戏的规则(简易版)3、代码实现(3.1)提醒一下:( i ) 提醒1:( ii ) 提醒2: &…...

信刻全自动光盘摆渡系统
随着各种数据传输、储存技术、信息技术的快速发展,保护信息安全是重中之重。各安全领域行业对跨网数据交互需求日益迫切。针对于业务需要与保密规范相关要求,涉及重要秘密信息,需做到安全的物理隔离,并且保证跨网数据高效安全传输…...
计算机网络的数据链路层
计算机网络的数据链路层 数据链路层是OSI参考模型中的第二层,它位于物理层之上,网络层之下。数据链路层的主要功能是在物理层提供的服务的基础上向网络层提供服务,其最基本的服务是将源自网络层来的数据可靠地传输到相邻节点的目标机网络层。…...

从0开始搭建一个生产级SpringBoot2.0.X项目(三)SpringBoot接口统一返回和全局异常处理
前言 最近有个想法想整理一个内容比较完整springboot项目初始化Demo。 SpringBoot接口统一返回和全局异常处理,使用ControllerAdvice ExceptionHandler 的组合来实现。 一、pom文件新增依赖 <dependency><groupId>com.alibaba</groupId><ar…...

Mybatis-plus-扩展功能
Mybatis-plus-扩展功能 一:代码生成器 AutoGenerator 是 MyBatis-Plus 的代码生成器,通过 AutoGenerator 可以快速生成 Entity、Mapper、Mapper XML、Service、Controller 等各个模块的代码,极大的提升了开发效率。 功能的演示:…...

【AI辅助】AWS Toolkit+AmazonQ
#偶然看到网上某up主用的这个AI工具,感觉还挺实用的,推荐大家~我们不可阻挡AI的攻势,但是成为利用它的人,也是反侵占的方式呢# AWS toolkit Amazon Q 安装 VScode--Extensions--搜索工具--安装 安装后,工具栏会多出对…...
云手机简述(概况,使用场景,自己部署云手机)
背景 最近经常会看到云手机的相关广告,手痒难耐,了解一下。 我的主要需求: Android 已 root,能够做一些自动化等高级功能。能够通过 远程adb 控制手机。能够尽量的少花钱,最好是能够提供动态创建删除手机的方式&…...

Java已死,大模型才是未来?
作者:不惑_ 引言 在数字技术的浪潮中,编程语言始终扮演着至关重要的角色。Java,自1995年诞生以来,便以其跨平台的特性和丰富的生态系统,成为了全球范围内开发者们最为青睐的编程语言之一 然而,随着技术的…...

NCCL安装(Ubuntu等)
目录 一、NCCL的定义二、安装NCCL的原因1、加速多GPU通信2、支持流行的深度学习框架3、提高计算效率4、易于使用和集成5、可扩展性 三、NCCL安装方法1、下载安装包2、更新APT数据库3、使用APT安装libnccl2包,另外,如果需要使用NCCL编译应用程序ÿ…...

加载视频显示 - python 实现
#-*-coding:utf-8-*- # date:2021-03-21 # Author: DataBall - Xian # Function: 加载视频并显示import cv2 if __name__ "__main__":#加载视频cap cv2.VideoCapture(./video/1.mp4)while True:ret, img cap.read()# 获取相机图像if ret True:# 如果 ret 返回值为…...
vscode里如何用git
打开vs终端执行如下: 1 初始化 Git 仓库(如果尚未初始化) git init 2 添加文件到 Git 仓库 git add . 3 使用 git commit 命令来提交你的更改。确保在提交时加上一个有用的消息。 git commit -m "备注信息" 4 …...

基于FPGA的PID算法学习———实现PID比例控制算法
基于FPGA的PID算法学习 前言一、PID算法分析二、PID仿真分析1. PID代码2.PI代码3.P代码4.顶层5.测试文件6.仿真波形 总结 前言 学习内容:参考网站: PID算法控制 PID即:Proportional(比例)、Integral(积分&…...
PHP和Node.js哪个更爽?
先说结论,rust完胜。 php:laravel,swoole,webman,最开始在苏宁的时候写了几年php,当时觉得php真的是世界上最好的语言,因为当初活在舒适圈里,不愿意跳出来,就好比当初活在…...

Linux相关概念和易错知识点(42)(TCP的连接管理、可靠性、面临复杂网络的处理)
目录 1.TCP的连接管理机制(1)三次握手①握手过程②对握手过程的理解 (2)四次挥手(3)握手和挥手的触发(4)状态切换①挥手过程中状态的切换②握手过程中状态的切换 2.TCP的可靠性&…...

HTML 列表、表格、表单
1 列表标签 作用:布局内容排列整齐的区域 列表分类:无序列表、有序列表、定义列表。 例如: 1.1 无序列表 标签:ul 嵌套 li,ul是无序列表,li是列表条目。 注意事项: ul 标签里面只能包裹 li…...
Robots.txt 文件
什么是robots.txt? robots.txt 是一个位于网站根目录下的文本文件(如:https://example.com/robots.txt),它用于指导网络爬虫(如搜索引擎的蜘蛛程序)如何抓取该网站的内容。这个文件遵循 Robots…...
GitHub 趋势日报 (2025年06月08日)
📊 由 TrendForge 系统生成 | 🌐 https://trendforge.devlive.org/ 🌐 本日报中的项目描述已自动翻译为中文 📈 今日获星趋势图 今日获星趋势图 884 cognee 566 dify 414 HumanSystemOptimization 414 omni-tools 321 note-gen …...

零基础设计模式——行为型模式 - 责任链模式
第四部分:行为型模式 - 责任链模式 (Chain of Responsibility Pattern) 欢迎来到行为型模式的学习!行为型模式关注对象之间的职责分配、算法封装和对象间的交互。我们将学习的第一个行为型模式是责任链模式。 核心思想:使多个对象都有机会处…...
Webpack性能优化:构建速度与体积优化策略
一、构建速度优化 1、升级Webpack和Node.js 优化效果:Webpack 4比Webpack 3构建时间降低60%-98%。原因: V8引擎优化(for of替代forEach、Map/Set替代Object)。默认使用更快的md4哈希算法。AST直接从Loa…...

【MATLAB代码】基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),附源代码|订阅专栏后可直接查看
文章所述的代码实现了基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),针对传感器观测数据中存在的脉冲型异常噪声问题,通过非线性加权机制提升滤波器的抗干扰能力。代码通过对比传统KF与MCC-KF在含异常值场景下的表现,验证了后者在状态估计鲁棒性方面的显著优…...