估计阅读时长: 10 分钟

  https://github.com/xieguigang/LLMs

大语言模型从2023年开始,在最近几年非常的火爆。在最近的一段时间,有大语言模型自动化处理数据的需求,开发了一个基于Ollama服务的客户端来通过大语言模型执行自动化任务。在这里记录下这个开发过程。

Ollama介绍

Ollama 是一个开源的大型语言模型(LLM)服务工具,专注于简化本地环境中大模型的部署与管理。它通过类似 Docker 的框架设计,让用户能以极低门槛在个人电脑或服务器上运行各类开源模型(如 Llama 3、Mistral、DeepSeek 等),实现数据隐私与离线推理的平衡。

通过ollama在我们的本地电脑上(或者本地服务器上)部署一个大语言模型非常的简单,我们首先需要上到ollama的官网(https://ollama.com/)上,直接在主页上就可以看到Ollama的下载链接了。

就是页面正中间的那个大大的Download按钮,直接点击他,选择自己现在正在使用的操作系统平台的客户端,下载下来安装上就可以了。

安装DeepSeek

DeepSeek包含一系列不同的版本模型,我们在这里安装具有推理能力的deepseek-r1模型,deepseek-r1是DeepSeek的第一代推理模型,在数学、代码和推理任务上实现了与OpenAI-o1相媲美的性能。在ollama上,我们进入到deepseek-r1的模型页面上(https://ollama.com/library/deepseek-r1),可以看到不同参数尺寸规模的Deepseek-r1的模型列表。我们在这里选择一个大小和我们的显卡内存大小相近的模型,进行安装。

在这里我们以deepseek-r1:70b的模型为例来进行模型安装的讲解。假设我们现在已经安装好了ollama的客户端之后,打开系统的命令行界面,运行下面的命令即可执行模型的安装:

ollama run deepseek-r1:70b

整个模型的下载安装速度是挺快的,我的30MB/s的小水管大约可以半个小时内安装完毕。等待一段时间,完成模型下载之后,你就可以在你的本地电脑上成功安装上了deepseek大语言模型了,在这个整个过程中完全免费,不需要花费你一分钱。

从头开发一个基于Ollama的DeepSeek客户端

现在,通过上面的步骤,我们已经成功的在我们的本地电脑上安装好了DeepSeek大语言模型,现在就可以开始开发一个客户端用来和DeepSeek模型进行对话了。我们在前面所安装好的ollama就相当于一个网页服务器,我们需要通过一些工具向我们所安装好的ollama网页服务器发送请求,然后ollama服务上的大语言模型通过运算分析我们的请求后返回大语言模型的输出结果给我们,这样子的一个过程就是我们和大语言模型的一次对话过程了。上面的过程就是一次非常简单的网页请求过程,所以我们可以非常容易的通过任何支持http请求的编程语言开发出一个能够和大语言模型进行对话的程序。我们通过下面的流程图来描述上面的对话过程:

sequenceDiagram
participant Human
participant Ollama(DeepSeek)
Human->>Ollama(DeepSeek): Hello, how are you?
loop LLMs
Ollama(DeepSeek)->>Ollama(DeepSeek): LLMs thinking
end
Ollama(DeepSeek)-->>Human: Jolly good!

在上面的流程图中,Human就是用户使用我们所编写的http客户端向Ollama网页服务器发送对话请求。Ollama后台在收到信息后,会将信息交给大语言模型进行处理,处理完的结果会通过json的形式返回给我们的客户端。不断重复上面的过程我们就可以实现和大语言模型进行对话了。

开发一个基础的http请求客户端

在vb.net语言中,我们可以基于HttpClient对象来实现上面的和大语言对话的过程。下面是一个基础的http请求的代码:

' json_input为用户输入的信息
Dim content = New StringContent(json_input, Encoding.UTF8, "application/json")
Dim settings As New HttpClientHandler With {
    .Proxy = Nothing,
    .UseProxy = False
}

Using client As New HttpClient(settings) With {.Timeout = TimeSpan.FromHours(1)}
    Dim resp As String = RequestMessage(client, url, content).GetAwaiter.GetResult
    Dim jsonl As String() = resp.LineTokens

    ' 展示对话结果到网页上/客户端界面上
End Using

Private Shared Async Function RequestMessage(client As HttpClient, 
                                             url As String, 
                                             content As StringContent) As Task(Of String)

    Dim response As HttpResponseMessage = Await client.PostAsync(url, content)

    If response.IsSuccessStatusCode Then
        Return Await response.Content.ReadAsStringAsync()
    Else
        Dim msg As String = Await response.Content.ReadAsStringAsync()
        msg = $"{response.StatusCode.Description}{vbCrLf}{vbCrLf}{msg}"

        Throw New Exception(msg)
    End If
End Function

基于上面的简单的代码框架,我们就可以搭建出自己的聊天搭子。现在,如果我们想要上面的代码跑起来,还需要设置几个代码参数:

参数/变量 说明
url $"http://{_server}/api/chat" ollama提供的http请求的接口,假若ollama服务是部署在本地的,默认的url为http://127.0.0.1:11434/api/chat,这个链接也可以直接在你的浏览器中打开访问
json_input {"messages":
[{"content":"who are you?",
"metadata":null,"role":"user","tool_call_id":null,"tool_calls":null}],
"model":"deepseek-r1:32b",
"stream":true,
"temperature":0.1,
"tools":null}
进行大语言模型对话的请求信息,在里面的包含了模型的引用名称,模型的设置参数,以及我们从用户界面上获取得到的用户对话信息

将上面输入的json信息进行可视化,可以看得到它是长得这样子的:

  • messages, 是一个消息数组,包含有用户当前的输入信息,以及历史对话信息(大语言模型对和你对话的记忆能力来自于这个消息数组中所存储的历史记录,当你将这个消息数组清空之后,大语言模型和你相关的记忆也就没有了)。
  • model, 是一个字符串,即我们所调用的模型名称,例如,我们在这里调用的是deepseek-r1:32b这个大语言模型
  • stream, 是否采用流式模式从ollama后台服务返回消息给我们。非常推荐在这里将这个流式处理模型打开,否则当这个参数为False的时候,ollama只会在大语言模型完成了所有工作后一次性返回所有信息,处理复杂问题的时候非常容易出现超时的问题,非常容易导致程序不稳定状态。
  • temperature,0到1之间的一个参数值,越接近于1,大语言模型的思维越发散,越接近于零,大语言模型越严谨。
  • tools,模型可以进行调用的工具信息列表

下面展示的是在上面的json数据中的message消息信息的数据结构,可以直接通过针对下面的对象数组进行json序列化得到对应的json字符串:

Imports Ollama.JSON.FunctionCall

Namespace JSON

    Public Enum roles
        user
        assistant
        system
        tool
    End Enum

    Public Class History

        ''' <summary>
        ''' the role of the message, value of this property can be 
        ''' 
        ''' 1, user
        ''' 2, assistant or system
        ''' 3, tool
        ''' 
        ''' could be get the name tostring of <see cref="roles"/> enums value
        ''' </summary>
        ''' <returns></returns>
        Public Property role As String
        Public Property content As String
        Public Property metadata As String
        Public Property tool_calls As ToolCall()
        Public Property tool_call_id As String

        Sub New()
        End Sub

        Sub New(role As roles, content As String)
            Me.role = role.ToString
            Me.content = content
        End Sub

        Public Overrides Function ToString() As String
            Return $"{role}: {content.TrimNewLine("\n")}"
        End Function

    End Class
End Namespace

然后,我们就可以建立起针对大语言模型的请求的消息体的json模型:

Imports Ollama.JSON.FunctionCall

Namespace JSON

    Public Class RequestBody

        ''' <summary>
        ''' 每个batch文件只能包含对单个模型的请求,支持 glm-4、glm-3-turbo.
        ''' </summary>
        ''' <returns></returns>
        Public Property model As String
        Public Property temperature As Double?
        Public Property messages As History()
        ''' <summary>
        ''' json list response
        ''' </summary>
        ''' <returns></returns>
        Public Property stream As Boolean = False
        Public Property tools As FunctionTool()

        Sub New()
        End Sub

        Sub New(copy As RequestBody)
            model = copy.model
            temperature = copy.temperature
            messages = copy.messages.ToArray
            stream = copy.stream
            tools = copy.tools.ToArray
        End Sub

    End Class

End Namespace

现在,我们基于上面的数据结构来进行大语言模型的消息的创建,然后就可以发送请求进行聊天了:

Public Function Chat(message As String) As DeepSeekResponse
    Dim newUserMsg As New History With {.content = message, .role = "user"}
    ' 将当前的输入添加到历史信息中,建立大语言模型的记忆
    Call ai_memory.Add(newUserMsg)

    Dim req As New RequestBody With {
        .messages = ai_memory.ToArray,
        .model = model,
        .stream = True,
        .temperature = 0.1,
        .tools = If(tools.IsNullOrEmpty, Nothing, tools.ToArray)
    }

    Return Chat(req)
End Function

信息流式处理

当我们在创建发送给大语言模型的消息的时候,假若没有将stream参数设置为True,则Ollama后台会返回一个完整的json信息,但是这种情况在处理复杂问题的时候非常容易出现超时的错误问题。所以我们在这里强烈推荐将stream设置为True,进行返回消息的流式处理。当设置为流式处理模式之后,ollama后台会不断地向我们返回json信息,即后台运行的大语言模型每吐出一个字,ollama后台就会返回这个字给我们。这样子,我们在我们的程序中将接收到的信息拼接在一起之后,就可以得到大语言模型的完整输出信息了。

在实际情况中,大语言模型每吐出的一个字,都会通过一个完整的json消息返回给我们,这样子ollama后台在stream流式处理的模式下,实际上返回给我们的是一个jsonl文件。那现在我们可以通过下面的代码进行这个json列表的解析处理,拼接出完整的回答:

Dim resp As String = RequestMessage(client, url, content).GetAwaiter.GetResult
Dim jsonl As String() = resp.LineTokens
Dim msg As New StringBuilder

For Each stream As String In jsonl
    Dim result = stream.LoadJSON(Of ResponseBody)
    Dim deepseek_think = result.message.content

    Call ai_memory.Add(result.message)
    Call msg.Append(deepseek_think)
Next

Dim output As DeepSeekResponse = DeepSeekResponse.ParseResponse(msg.ToString)
Return output

至此,我们针对ollama后台所返回的json列表进行解析,取出消息文本,通过StringBuilder拼接在一起,就可以得到DeepSeek的完整输出信息了。将我们得到的output数据,返回给网页界面或者桌面程序的显示界面上,我们的程序用户就可以看见大语言模型对他们的输入的回答结果了

who are you?
Greetings! I'm DeepSeek-R1, an artificial intelligence assistant created by DeepSeek. I'm at your service and would be delighted to assist you with any inquiries or tasks you may have.

谢桂纲
Latest posts by 谢桂纲 (see all)

Attachments

No responses yet

Leave a Reply

Your email address will not be published. Required fields are marked *

博客文章
May 2025
S M T W T F S
 123
45678910
11121314151617
18192021222324
25262728293031
  1. 在mysql之中,针对24小时内的数据按照半个小时进行一次统计数量: ```sql SELECT DATE_FORMAT(FROM_UNIXTIME(FLOOR(UNIX_TIMESTAMP(add_time) / 1800) * 1800), '%Y-%m-%d %H:%i') AS half_hour, COUNT(*) AS count FROM user_track.page_view WHERE add_time >=…

  2. 针对图对象进行向量化表示嵌入: 首先,通过node2vec方法,将node表示为向量 第二步,针对node向量矩阵,进行umap降维计算,对node进行排序,生成node排序序列 第三步,针对node排序序列进行SGT序列图嵌入,实现将网络图对象嵌入为一维向量