前言

LLM 当前可以说渗透到了工作、生活中的方方面面,但是我一直都只用过在线提供的 LLM,钱包实在负荷不住了(说的就是你 Copilot),本文主要记录了一个纯小白如何摸索本地部署 LLM 并在编写代码的工作流中进行应用。

硬件环境,以下是我尝试比较「可用」模型尺寸与环境:
- 3B 模型:Ubuntu22.04 + GTX 1060 6G
- 13B 模型:Macos + M1 Max 32G

基本概念

文章编排其实与我实际摸索顺序是有区别的,我一向习惯是不求甚解先玩起来再说,而本节主要介绍一些在使用大模型过程中会遇到的特别概念,感觉太枯燥了可以跳过,后边遇到了回来再看也行。

LLM

大语言模型(英文:Large Language Model,缩写 LLM)是当前 AI 实际的“大脑🧠”。我们可以在本地运行并使用的模型主要是 Llama 2 (meta.com),其由 Meta 提供其是 Llama 的继任者,其他在网上可以看到的绝大多数模型都是基于 Llama v1/2 的 “微调”(Fine-Tune)或修改版本。

而由 Mistral AI | Frontier AI in your hands 发布的 Mistral 则是新晋的挑战者,当前在非代码微调领域也在快速发展,后续肯定能看到很多衍生版本。

Fine-Tune 微调

微调的目的是通过给模型增加更多某个领域数据使得其在某些事上做的更好,可以是对话、翻译、数学等等领域,有时看到很多不同名称的模型很多都是「微调」出来的版本,例如由 Meta 提供的 codellamaa models (github.com) 就是基于 Llama 2 微调的编码助手模型。

Context 语境

Context 我们可以理解为语境或者是上下文,由于 LLM 是无状态保留的它不会记得历史对话,因此你需要将历史对话都要输入给它才能使其理解并给出正确的回复。例如你在对话开始给 LLM 设定了一个角色「你是一个全栈工程师尤其对于 C++ 精通」,在后续对话中需要你讲这个角色信息都要发送给 LLM,否则它会忘记自己的角色。

LLMs Size

模型有大小之分,通常会看到最多的数字是 3B、7B、13B、20B、30B、33B、34B、65B、70B。「B」表示 billions of parameters 即十亿参数单位,通常认为参数越多模型的效果则会越好,例如 ChatGPT4 则宣称有 100 万亿。如下图 Llama2 提供了 7B、13B、70B 尺寸的模型:

Pasted image 20240405181707.png

Quantized 量化

以全尺寸模型是每个参数占用 2 个字节为例,这意味着 3B 模型的实际大小是 6GB。这对于我们本地部署来说负担太大了,你需要足够的显存或者内存来运行模型,以我的搭载 GTX1060 旧笔记本来说想要跑起来 3B 模型都很困难,并且由于参数量过小实际模型效果也很差。

这时「量化」则可以帮助我们获取「压缩」版本的模型,一般量化模型有 q2、q3、q4、q5、q6 和 q8。数字越小同样可以简单理解模型「越笨」,但是好处也是显而易见的 34B 模型经过 q3 量化只有 17GB!这与 68GB 的全尺寸相差甚远。

至于量化的原理有很多专业的文章讲解,简单来说一个模型的权重数据本来需要使用 float32 表示,量化后只需要使用 int8 来表示,仅仅这一个操作,本来需要 4 字节的权重数据缩小到 1 个字节。

经验法则:一般来说,运行一个大模型的小 q 比运行一个小模型的大 q 更好。总的来说,34B q3 将比 13B q8 更聪明、更好。

Pasted image 20240405200211.png

"K" Quantized

此外,除了量化 「q」,你可能还会看到 「K_M」或 「K_S」。这些是 K 量化,S 代表“小”,M 代表“中”,L 代表“大”。

所以 q4_K_S 小于 q4_K_L,两者都小于 q6。

LLM 文件格式

当前 LLM 模型文件主要有以下几种格式:

  1. GGML(Georgi Gerganov Machine Learning):由 Georgi Gerganov 开发的一个张量库,为大型语言模型提供了基础设施,GGML 本身是一个 C 写的库,用它转换的大模型文件结果就是 GGML 格式的大模型文件,通常是原有的模型名 +GGML。它的目标是让大模型在消费级硬件上产生高性能的工具,其支持在 CPU/GPU 上运行。
  2. GGUF(GPT-Generated Unified Format):在 2023 年 8 月份,Georgi Gerganov 推出了 GGUF 作为 GGML 后续的替代者,用以作为 llama.cpp 的主要文件格式。GGUF 在二进制格式、数据结构、内存映射兼容性、数据压缩、索引与访问等方面均有优化,其同样支持在 CPU/GPU 上运行。
  3. GPTQ(Gradient-based Progressive Tensor Quantization):一种动态量化方法,它通过在训练过程中逐渐增加量化的严格程度来实现量化。与传统的静态量化方法不同,GPTQ 允许模型在量化过程中调整其权重,以最小化量化带来的性能损失。当前只能在 GPU 上运行,速度很快,可以使用 AutoGPTQ 或 ExLlama 运行。
  4. EXL2(exllamav2):用于在现代消费级 GPU 上本地运行 LLM 的快速推理库,其速度更快但是只能在 GPU 上运行。

以当前基础设施支持情况来看,GGUF 是最推荐使用的模型格式。

部署工具

前文我们已经了解了一些模型文件的基础知识,但是光有一个模型文件是没有用的,想要实际使用需要一个可以部署大模型的推理工具,本文主要以 GGUF 格式为主,因此这里介绍的更多是方便使用的部署工具,推理框架其大多基于 llama.cpp:

llama.cpp

ggerganov/llama.cpp: LLM inference in C/C++ (github.com)

可以在消费级硬件上部署模型所使用的推理框架 llama.cpp 是绕不过的,前文介绍大模型格式时也提过,作为当前大模型「基础设施」之一,其被很多工具使用作为推理框架。

llama.cpp 的特点在于其使用 C/C++ 重写了推理代码,既避免了 PyTorch 引入的复杂依赖,又提供了更为广泛的硬件支持,包括纯 CPU 推理、Apple Silicon 在内的各类底层计算架构都得以充分发挥对应的推理加速,并且由于当前很多模型均基于 Llama 架构因此其支持的模型非常多。

当然你也可以直接使用 llama.cpp 进行模型格式转换与推理使用,使用步骤太繁琐了可以参考其 github 主页教程。

ollama

ollama/ollama: Get up and running with Llama 2, Mistral, Gemma, and other large language models. (github.com)

ollama 作为一个开源大语言模型服务工具,提供了模型下载、管理、推理一体化的功能,并且其可以作为服务端提供 API 供其他程序调用,当前有着非常繁荣的生态。

如下为 Ubuntu22.04 环境安装并运行模型:

  1. 执行命令安装:curl -fsSL https://ollama.com/install.sh | sh
  2. 安装模型,支持的模型ollama run starcoder:3b
  3. 查看服务端运行状态,可以看到日志信息:systemctl status ollama.service
  4. 默认其监听端口:127.0.0.1:11434
  5. 测试 API 运行情况:curl http://127.0.0.1:11434

调整 ollama 监听端口,并开放监听局域网内请求:

  1. 修改 ollama.service:sudo vim /etc/systemd/system/ollama.service
Environment="OLLAMA_HOST=0.0.0.0:8080"
Environment="OLLAMA_ORIGINS='*'"
  1. 重启 ollama.server: sudo systemctl daemon-reload;sudo systemctl restart ollama.service
  2. 测试 API 运行情况:curl http://127.0.0.1:11434
  3. 为 ollama 客户端增加环境变量:export OLLAMA_HOST=0.0.0.0:8080

运行效果如下,可以看出基本代码是可以给出,但是 3B 模型对话来说效果就很差了:

Pasted image 20240406103755.png

ollama 基本使用也都是在终端中进行,但是得益于其提供 API 与繁荣的生态,当前有很多 WEB UI 类工具可供使用,具体安装方法这里就不再展开:
open-webui/open-webui: User-friendly WebUI for LLMs (Formerly Ollama WebUI) (github.com)
ollama-interface/Ollama-Gui: A GUI interface for Ollama (github.com)

LM Studio

LM Studio - Discover, download, and run local LLMs

ollama 很不错但是对于普通用户来说使用起来还是太麻烦,而 LM Studio 工具是一个自带 UI,开箱即用的工具,但是注意其并不开源,当前免费使用

LM Studio 支持查找模型、下载、管理、推理运行一体的工具,不仅仅支持 Chat,还提供多模型会话以及 Local LLM Server,主要支持的模型格式同样为 GGUF:

Pasted image 20240406104827.png

工具下载安装都是 UI 界面这里就不详细介绍,非常好上手。

代码补全

作为程序员在使用大模型不仅仅想要 Chat,更想要在写代码过程中提供自动生成代码功能,类似 github copilot,这一节是介绍如何将本地大模型用在编写代码相关领域:

模型选择

其实前文都没有介绍过模型选择相关,因为我认为当前本地部署模型没有通杀的,你应该选择 " 尺寸 + 领域(聊天、通用、编码、数学等)" 多尝试选择适合自己的模型。

到了编写代码领域也是同理,对于代码进行微调过的模型往往要表现的比通用模型要好,例如 codellama 与 llama2 的关系。并且在代码补全时速度也是要考虑的,否则它生成的时间比我们自己写还要久也太鸡肋了。

因此模型选择上建议,代码 Chat 相关使用特化的模型参数量可以大一些,例如 codellama 7B/13B,保证对话质量,速度慢一些也可以接受。但是代码生成补全上建议 starcode 3B 保证速度(如果性能实在不够还可以选择 deepseek-coder:1.3b-base)。

Prompt

对于编码领域 Prompt 也是有些特别,尤其是对于代码补全需要支持 FIM(Fill-in-the-middle),这块易用性比较好的是 ollama,很多插件工具都支持 ollama 协议进行代码 chat 与补全。

至于详细关于 Prompt 相关信息参考如下文章:
How to prompt Code Llama · Ollama Blog

Vscode

虽说我用 Vscode 不多,但是生态好啊,啥插件都有,先介绍下 Vscode 如何使用本地大模型,这里我主要使用的插件是 Continue

Pasted image 20240406111828.png

他支持 ollama、LM Studio 服务端 API,这里我演示如何 LM Studio 部署 codellama13B,ollama 部署 starcode:3b 分别提供 chat 与 代码补全功能:

LM Studio 加载 codellama 模型并 Start Server:

Pasted image 20240406112026.png

ollama 则是加载 starcode:3b 模型,详见前文这里就不复述了;

continue 插件在 vscode 中的设置很少,其主要配置都是在 ~/.continue/config.json 配置文件中,主要关注如下配置项,models 中配置 Chat 的模型信息,tabAutocomplete* 中则是代码补全相关配置:

{
  "models": [
    {
      "model": "AUTODETECT",
      "title": "LM Studio",
      "apiBase": "http://localhost:1234/v1/",
      "completionOptions": {},
      "provider": "lmstudio"
    }
  ],
  "tabAutocompleteModel": {
    "title": "Tab Autocomplete Model",
    "provider": "ollama",
    "model": "starcoder:3b",
    "apiBase": "http://ubuntu.lan:8080"
  },
  "tabAutocompleteOptions": {
    "useCopyBuffer": false,
    "maxPromptTokens": 400,
    "prefixPercentage": 0.5
  },
  "allowAnonymousTelemetry": true
}

最终效果如下:

对话:使用 @ 还可以添加某个文件,非常好用😂:
 

Pasted image 20240406113537.png

补全:实在不好截图用个插件主页的例图,个人使用效果差不多:
 

Pasted image 20240406113838.png

其他:还支持选择代码进行描述修改,例如增加个注释等等:
 

Pasted image 20240406114022.png

Neovim

作为 nvimer 主要工作流都是使用 Neovim,这里介绍下可以使用本地大模型进行代码 Chat 与补全的插件:

Pasted image 20240406114449.png

jackMort/ChatGPT.nvim (github.com):看名字就知道主要使用 ChatGPT 的插件,但是很巧我们 LM Studio 提供的同样是 openai 格式的 API 可以直接接入,配置如下:

tool["jackMort/ChatGPT.nvim"] = {
    event = "BufReadPost",
    lazy = true,
    config = function()
        require("chatgpt").setup({
            api_host_cmd = "echo http://localhost:1234",  -- 主要是这里配置为 LM Studio
            api_key_cmd = "echo 'lm-studio'",
            edit_with_instructions = {
                diff = false,
                keymaps = {
                    close = "<C-q>",
                    accept = "<C-y>",
                    toggle_diff = "<C-d>",
                    toggle_settings = "<C-o>",
                    toggle_help = "<C-h>",
                    cycle_windows = "<Tab>",
                    use_output_as_input = "<C-i>",
                },
            },
            chat = {
                keymaps = {
                    close = "<C-q>",
                },
            },
        })
    end,
    dependencies = {
        "MunifTanjim/nui.nvim",
        "nvim-lua/plenary.nvim",
        "folke/trouble.nvim",
        "nvim-telescope/telescope.nvim",
    },
}
  • 使用效果:
     
Pasted image 20240406115137.png

huggingface/llm.nvim (github.com):由 huggingface 提供的插件,专注于代码补全,配置如下(注意你要知道使用的模型 fim 该如何配置,否则效果会非常差):

    tool["huggingface/llm.nvim"] = {
    event = "BufReadPost",
    lazy = true,
    config = function()
        local llm = require("llm")
        llm.setup({
            api_token = nil, -- cf Install paragraph
            model = "starcoder:3b", -- the model ID, behavior depends on backend
            backend = "ollama", -- backend ID, "huggingface" | "ollama" | "openai" | "tgi"
            url = "http://ubuntu.lan:8080/api/generate", -- the http url of the backend
            tokens_to_clear = { "<|endoftext|>" }, -- tokens to remove from the model's output
            request_body = {
                parameters = {
                    max_new_tokens = 60,
                    temperature = 0.2,
                    top_p = 0.95,
                },
            },
            -- set this if the model supports fill in the middle
            fim = {
                enabled = true,
                prefix = "<fim_prefix>",
                middle = "<fim_middle>",
                suffix = "<fim_suffix>",
            },
            debounce_ms = 150,
            accept_keymap = "<C-l>",
            dismiss_keymap = "<C-\\>",
            tls_skip_verify_insecure = false,
            -- llm-ls configuration, cf llm-ls section
            lsp = {
                bin_path = nil,
                host = nil,
                port = nil,
                version = "0.5.2",
            },
            tokenizer = nil, -- cf Tokenizer paragraph
            context_window = 8192, -- max number of tokens for the context window
            enable_suggestions_on_startup = true,
            enable_suggestions_on_files = "*", 
        })
    end,
}

总结

这篇文章主要是记录了最近几天假期再折腾如何学习大模型本地部署,并如何在常用的工具中使用。

作为非专业人士,感觉能够部署使用也就差不多了,更多还是要考虑如何利用好 LLM 提升工作流,后续会继续探索如何利用 LLM 更快、更好的执行 TDD,感兴趣的同学留言交流哦~

相关资料

AI 时代,重识羊驼 - 少数派 (sspai.com)
用 Ollama 轻松玩转本地大模型 - 少数派 (sspai.com)
深入浅出:大模型量化技术GPTQ详解 | 数据学习者官方网站(Datalearner)
GGUF格式的大模型文件是什么意思?gguf是什么格式?如何使用?为什么有GGUF格式的大模型文件?GGUF大模型文件与GGML的差异是啥? | 数据学习者官方网站(Datalearner)
大模型领域的GGML是什么?GGML格式的大模型文件与原有文件有什么不同?它是谁提出的?如何使用? | 数据学习者官方网站(Datalearner)
(2) A Starter Guide for Playing with Your Own Local AI! : LocalLLaMA (reddit.com)