ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

LLM从原理到落地:本地部署、微调评测与Agent容错全路线

LLM从原理到落地:本地部署、微调评测与Agent容错全路线 我现在刷信息流的时候满屏都是“LLM是什么”“大模型框架”“本地跑 GGUF”“LLM as Judge”“Agent 出错怎么排查”这类热搜词。看下来最大的感受是想学 LLM 的人很多但真正能一条线走通的人很少。大部分人卡在同一个路口——概念看了不少真到自己动手做一个能用、能评、能稳定上线的应用又不知道从哪里下手。这个系列我就打算按一条完整的路线来写《深入学习 LLM(一)》先解决“地基”问题——模型到底是什么、工具链怎么选、本地怎么跑、数据怎么微调、效果怎么评测、Agent 怎么做可靠。后面再逐步展开更深的内容。内容偏工程实践适合三类人刚入门的开发者、准备在业务里落地大模型应用的工程师、以及想搞明白“大模型项目为什么总在最后一步翻车”的产品和技术负责人。这一篇的信息量会比较大我会尽量少讲空话多放可以直接抄走的判断标准、参数和踩坑记录。1. 先把基础打对LLM 到底是什么1.1 从“预测下一个词”到“能力涌现”很多人对 LLM 的第一印象是“特别聪明、什么都会”。但如果只保留一句准确的话来描述它应当是LLM 是一个做“下一个词预测”的概率模型。给定一段上文它计算下一个最可能出现的词严格来说是 token是什么然后不断重复这个过程生成整段内容。这个本质决定了它的很多脾气。比如它会一本正经地编造不存在的引用因为对它来说“编一个像样的引用”和“说出真实引用”在概率上都是合法的延续它也不擅长算术因为把数字拆成 token 之后计算路径并不稳定。理解这一点能避免你对模型产生不切实际的期待。支撑这一能力的基础架构是 Transformer。它最关键的设计是自注意力机制Self-Attention简单理解就是模型在处理某个词的时候会动态计算它和序列中其他词的相关程度从而决定“该重点参考哪些上下文”。这也是为什么 LLM 能做“根据前文理解后文”而不是像老式 n-gram 模型那样只看紧邻的几个词。在训练流程上主流模型基本都走“三段式”预训练在海量文本上做自监督学习目标是预测下一个词。这一步让模型获得语言能力和世界知识。指令微调SFT用大量“用户问题 标准回答”对模型做监督训练让它学会服从指令、用对话形式回答。对齐RLHF / DPO 等让模型输出更符合人类偏好比如更有帮助、更安全、更简洁。到了指令微调之后模型才表现出大家熟知的指令跟随Instruction Following、**上下文学习In-Context Learning和一定程度的思维链Chain-of-Thought**能力。这些能力被统称为“涌现能力”听起来很玄但从工程视角看你可以把它们理解为“模型在语料中见过足够多类似模式后产生的一种复杂模式匹配”。不需要把它当成魔法只需要知道这是一把双刃剑——模式匹配既让它灵活也让它容易“幻觉”。1.2 为什么大模型这么“听话”指令对齐与提示工程“听话”这个词很形象。一个 Base 模型只有预训练阶段的模型你问它问题它大概率会续写一段百科式文本而不是正经回答你。真正让它“变成对话助手”的是对齐阶段的数据和训练方式。所以你在写 Prompt 时本质上是在和“对齐后的默认行为”打交道。常用 Prompt 结构包括三部分System 指令定义模型角色、任务目标、输出格式。User 输入具体请求。Assistant 输出模型回答。实操中我强烈建议你对任何生产级 Prompt 都显式写 System 指令哪怕很简单。这能明显减少模型“自由发挥”的概率。举个最简单的例子你让它“总结会议纪要”如果只给一句原文它可能输出一个带小标题的长篇总结如果 System 里写明“只输出 5 条结论每条不超过 20 字不要解释”输出就会稳定得多。几个经常被忽略但很重要的参数意识Temperature控制随机性。做抽取、分类、代码生成时建议调到 0~0.2做创意写作、头脑风暴可以 0.7~1.0。上下文窗口窗口越大不等于效果越好。模型对中间内容的关注度往往弱于开头和结尾这在技术上称为“lost in the middle”。需要长上下文时把关键指令放在 System 或末尾比堆在中间更有效。输出长度限制 max_tokens 能显著避免模型啰嗦也可以降低成本。提示入门阶段做一个“温度对比实验”特别有帮助。用同一个高质量 Prompttemperature 分别设为 0.2 和 0.9各生成 10 次观察输出的稳定程度。你会发现不少业务场景里低 temperature 的稳定性远比你想象的重要。2. 学习路线与工具链选型框架不是万能的2.1 先跑通 API再碰本地模型我发现很多新人一上来就想本地部署大模型理由通常是“不想花钱”“有隐私需求”或“听起来很酷”。这些理由可以理解但从学习效率看第一条路径应该是调用 API。原因很简单API 让你把精力集中在 Prompt、逻辑、评估这些真正重要的工程问题上而不是被 CUDA 版本、内存不足、量化效果这些环境问题劝退。等你用 API 跑通一个完整小应用比如“文档问答”或“角色扮演机器人”之后再回到本地部署你会更明白本地模型该调什么、不该调什么。否则你会在模型下载和依赖安装上花掉一周却连“这个模型的效果到底好不好”都判断不了。什么时候需要用 LangChain 这类框架我认为有清晰判断标准需要串联多个模型调用或工具调用时比如“先判断意图 → 再查数据库 → 再生成回答”的工作流框架的 Chain / Graph 能力确实省事。需要多种模型切换时LiteLLM 这类工具能统一 API 格式切换到不同供应商不修代码。需要成熟组件时比如文档切分、向量检索的封装LlamaIndex 比你自己写更稳。什么时候不适合用框架当你的逻辑只有“一个 Prompt 进去一个输出出来”时别用框架。直接调用 SDK 更简单、更好排查、依赖更少。框架的优势在抽象和编排但代价是隐藏细节。一旦输出不符合预期你得先判断是模型的问题、Prompt 的问题、还是框架内部做了你不知道的变换。这会浪费大量时间。我自己的项目里大概 70% 的调用是直接写 SDK 完成的只有 30% 涉及多步编排才引入框架。这个比例供你参考。2.2 主流框架和个人“LLM Wiki”给还没接触过框架的读者列一个快速对比工具/框架定位适合场景注意点LangChain通用编排框架多步骤 Agent、工具调用、复杂工作流版本升级快API 变动频繁锁定版本LlamaIndex数据检索与知识库文档问答、RAG 场景对结构化数据的索引能力较强LiteLLM统一 API 网关多模型切换、成本管理简单场景没必要引入LM Studio本地 GUI 推理工具本地快速体验模型效果适合调试不适合生产服务Ollama本地推理服务一键跑 GGUF 模型部署极简单但精细控制偏弱这里多提一句热词里的“LLM Wiki”。我认识不少高质量从业者几乎每个人都有自己的“LLM 笔记库”内容不是概念抄录而是项目记录模型名字和版本、Prompt 版本、参数配置、评测结果、失败样例、成本记录。这种做法非常重要因为 LLM 应用的调试是高度实验性的没有记录你等于没有积累。我建议你也建一个个人 LLM Wiki核心字段至少包括任务目标、数据来源、模型与参数、Prompt 全文、评测指标、失败案例。每次实验都记录一个月后回看你会发现自己避开了大量重复的坑。3. 本地部署实战GGUF 量化和安卓手机运行3.1 为什么选 GGUF 格式本地部署绕不开一件事怎么把动辄几十 GB 的模型塞进你的显卡或者内存里。这时候 GGUF 格式就派上用场了。GGUF 是 llama.cpp 项目推出的模型格式核心特点是把所有东西打包成一个文件模型的权重、tokenizer 配置、特殊 token、元信息都包含在内。相比传统的 safetensors 格式GGUF 更适合 CPU 推理和边缘设备因为它对权重的编码方式做了量化优化。量化这个词如果你第一次见可以用图片来类比一张 4K 照片原图很大压成 JPEG 后变很小肉眼看差别不大。模型的量化也类似把原本用 16 位浮点数表示的权重转成 4 位或 8 位表示模型体积大幅缩小推理时占用的内存或显存也降低很多质量略有损失但通常可接受。常见的量化等级和取舍我放在表里量化等级位数模型体积7B 模型参照质量损耗适用场景Q4_K_M4bit约 4.1G低消费级显卡/内存的均衡选择Q5_K_M5bit约 4.8G较低内存稍充足时优先Q6_K6bit约 5.7G很低质量敏感场景Q8_08bit约 7.2G接近无损显存足够时的首选选型口诀显存/内存决定上限质量敏感度决定档位。8GB 显存跑 7B 模型选 Q4_K_M 是最稳的如果你确定模型质量下降明显再考虑降低模型规模比如换成 3B 或 1.5B而不是硬上高量化。3.2 在电脑上快速跑起来本地推理我建议从 Ollama 开始它是我试过对新手最友好的工具。安装后拉模型即可# 拉取一个量化好的 7B 模型 ollama pull qwen2.5:7b-instruct-q4_K_M # 运行并进入交互式对话 ollama run qwen2.5:7b-instruct-q4_K_MOllama 支持通过 Modelfile 自定义参数例如设置 temperatureFROM qwen2.5:7b-instruct-q4_K_M PARAMETER temperature 0.2如果你更愿意用底层一点的 llama.cpp流程也简单从 GitHub 克隆源码编译后直接用命令行推理。编译前确认架构N 卡用 CUDA 加速纯 CPU 则用原生版本git clone https://github.com/ggerganov/llama.cpp cd llama.cpp cmake -B build -DGGML_CUDAON cmake --build build --config Release -j 4实测下来影响推理速度的最大因素是内存带宽而不只是 CPU 算力。笔记本在纯 CPU 情况下跑 7B Q4大约能到 5~8 token/秒能接受但不算流畅桌面高性能 CPU 能到 10 token/秒。如果你的预期是“像 ChatGPT 一样秒回”本地小模型目前很难满足这一点务必提前想清楚。提示跑本地模型时一定要确认你使用的是量化版模型文件。很多人下载了一个 14GB 的原版 7B 模型还在抱怨内存爆掉——量化和非量化的差别跑之前先看清楚。3.3 安卓本地运行支持 Android 8 的方案热词里有“安卓本地运行 GGUF 格式 LLM支持安卓 8”这个我专门验证过答案是可行但需要管理预期。最稳的方案是 Termux。Termux 是安卓上的终端模拟器可以把它理解成手机上的一台 Linux 小机器。在 Termux 里编译 llama.cpp 的 Android 版本然后加载你下载好的 GGUF 模型文件。步骤大致如下# 在 Termux 中 pkg update pkg install git cmake build-essential git clone https://github.com/ggerganov/llama.cpp cd llama.cpp # 在安卓上编译 CPU 版本即可不需要 CUDA cmake -B build cmake --build build --config Release -j 4之后把 GGUF 文件放到手机存储中运行./build/bin/llama-cli -m /sdcard/Download/your-model.Q4_K_M.gguf -p 你好介绍一下你自己针对 Android 8 的兼容性有几点实测经验尽量选择aarch64 体系的手机也就是近几年的主流 arm64 机型不要用老旧的 32 位系统。模型体积控制在2GB 以内推荐 1.5B~3B 的 Q4 量化版本。7B 在手机上体验很差每生成一个 token 都要等很久。手机内存至少4GB 起步低于这个值建议放弃本地运行的念头。使用过程中手机会明显发热这是 CPU 满载导致的正常现象长时间运行注意散热。这类方案适合你“在通勤时研究一下 prompt 逻辑”但把手机当成正经推理服务器目前还不太现实。4. 用聊天记录精调 LLM从数据到 LoRA 的一条线4.1 为什么聊天记录是好数据如果你想做一个特定风格的对话机器人比如客服助手、特定人设的聊天机器人拿真实聊天记录做微调是性价比很高的方案。理由很直接聊天记录就是用户和助手互动的真实样本里面包含你想要的语气、问题类型、回答风格比人工编造的数据要自然得多。但聊天记录不能直接用原因有三隐私风险大聊天记录可能包含姓名、手机号、地址等敏感信息必须先脱敏。噪声多大量消息是“嗯”“好的”“收到”这类无效内容需要过滤。格式不统一不同来源的记录字段都不一样要整理成模型训练需要的结构。一个简单的数据转换思路是把原始记录格式化成统一的 JSONL。假设原始聊天日志长这样[ {from: user, text: 你们发货用哪家快递}, {from: assistant, text: 默认用顺丰您下单后我会把单号发给您。} ]转换成训练格式后每行是一条完整对话样本符合 System/User/Assistant 结构{messages: [{role: system, content: 你是某店铺的售后客服回答简短友好。}, {role: user, content: 你们发货用哪家快递}, {role: assistant, content: 默认用顺丰您下单后我会把单号发给您。}]}做数据清洗时我建议按这四步走去重同一条消息反复出现会放大模型对该内容的过拟合。过滤删除过短的、无意义的、纯表情的对话。脱敏用规则或正则把手机号、邮箱、地址替换为占位符。重组把多轮对话切成不超过目标上下文长度的独立样本。注意任何来源的聊天记录只要不是你自己生产的都要确认数据合规性。清洗完数据再拿给模型训练是个人和团队都应该养成的习惯。4.2 LoRA 微调实操注意点全量微调一个大模型对于个人开发者来说不现实显存不够是一个方面另一个方面是你也不需要。用LoRALow-Rank Adaptation是目前的主流做法。它的思路是冻结原有模型参数只额外训练一小部分“旁路”参数。你可以把它想象成给模型加了一个“可拆卸的适配器”效果只影响你训练过的领域还会保留原有模型的通用能力。实际操作中我会优先用这两个训练方案LLaMA-Factory界面友好内置了大量数据集格式支持适合快速实验。HuggingFace PEFT TRL更底层适合需要定制训练逻辑的团队。LoRA 的几个关键参数直接给结论rank秩通常 8~32 之间。rank 越大可学习的参数越多但也更容易过拟合。对话风格类任务8~16 够用。alpha一般为 rank 的 2 倍是 LoRA 输出的缩放因子。学习率1e-4 到 2e-4 是常见区间不要太大否则容易崩。epochs对话数据量几千到几万条时2~3 轮即可更多的轮次很容易过拟合。另外一个特别容易被忽略的细节是训练数据的对话格式必须与模型自带的 chat template 完全一致。很多模型微调后出现“回答前言不搭后语”的诡异现象原因不是模型没学会而是训练时用的格式和模型原本的格式不一致导致模型在推理时不知道该按什么规则生成。训练前先确认对应模型的 chat template 长什么样再把你的数据传成同样的格式。验证阶段我强烈建议单独留出一批“模型在训练时没见过的聊天记录”做测试。微调前后的同一个问题各跑一遍对比回答风格、信息准确性、是否产生“记忆错乱”。如果在测试集上回答质量明显提升、但常识能力下降说明过拟合了这时候可以混入 20%~30% 的通用指令数据一起训练能有效缓解。5. 评测、LLM as Judge 和基于 LLM 的自动化单元测试5.1 怎么客观评估一个 LLM 应用大多数团队在大模型项目上翻车不是模型选错了而是没有一套评测方法。大家往往靠“肉眼看看回答怎么样”来判断效果这种感性判断在 Demo 阶段可以但一旦要上线会变得非常不可靠——因为同一个 Prompt 换一次输入输出质量波动可能非常大。我建议哪怕是小项目也先建一个基础评测集包含三类样本标准正确样本输入明确了预期答案可以用字符串匹配或模型判断对错。边界样本比如空输入、超长输入、包含错误信息的输入。对抗样本故意诱导模型输出不安全内容、幻觉内容。评测指标可以分成四类指标类型例子说明准确性抽取结果的 F1、分类准确率有标准答案时使用内容质量完整性、相关性、可读性需要人评或 LLM 评稳定性同一输入多次输出的方差越低越稳生产环境重点看成本性能延迟、tokens 数、失败率直接决定可持续性其中“稳定性”我特别想强调很多项目的 Prompt 在评测集上效果不错但日志显示用户反馈时好时坏。原因通常就是 temperature 偏高且没有做多轮抽样测试。稳定性测试方法很简单固定输入和参数重复调用 10 次计算输出的差异程度。5.2 LLM as Judge 的正确用法人工评测样本量一大就吃不消于是“用强模型评价弱模型输出”的思路被广泛应用这就是 LLM as Judge。它在主观任务上很有用比如摘要质量、文案吸引度、代码风格这类没有唯一正确答案的场景人工打分又贵又慢LLM 反而能给出相对一致的评分。但 LLM as Judge 有三个已知偏差使用前务必了解自偏好偏差它对“和自己风格相似的输出”打分会偏高。长度偏差更长的回答往往得到更高分哪怕内容啰嗦。位置偏差两个回答放在前还是放后会影响裁判的判断。缓解手段也很明确用Rubric 评分细则在 Prompt 里写清楚每个分数档位对应的标准。多次交换候选回答顺序取平均分。使用多个不同模型交叉打分消除单一模型偏好。引入少量人类标注做校准发现 Judge 偏移时及时调整 Prompt。实际用的时候比如评价一个摘要模型Judge 的 Prompt 可以长这样请根据以下评分标准为摘要打分1-5分 - 5分信息完整、语言流畅、没有冗余 - 3分核心信息保留但有明显冗余或遗漏 - 1分关键信息丢失或内容错误 【原文】 {original_text} 【候选摘要】 {candidate_summary} 只输出分数和一句简短理由。注意Judge 本身也会受到温度影响建议 temperature 设为 0并且同一对输出跑多次取均值。5.3 用 LLM 生成单元测试编程方向的读者应该对“基于 LLM 的单元测试”这个热搜词很感兴趣。思路是用 LLM 自动生成测试用例辅助工程师提升覆盖率。比如你写了一个函数自己懒得枚举边界条件可以让模型先看代码再生成测试计划和用例。我的实践是先让模型做两步输出而不是直接让它写完整测试文件第一步生成测试计划下面是函数代码请列出 5 个最有价值的测试场景包含正常输入、空输入、边界值、异常输入并说明每个场景的预期行为。 {code}第二步再根据测试计划生成测试代码。这样生成出来的代码可理解性远高于一步到位生成。如果你用的是 Python pytest生成的测试大致长这样import pytest def test_normal_input(): assert my_function(10) 20 def test_empty_input(): with pytest.raises(ValueError): my_function() def test_boundary_value(): assert my_function(0) 0但 LLM 生成单测有几个绕不开的坑我踩过之后总结如下幻觉断言模型会生成“看起来很有道理但实际是编的”预期值。这种用例跑起来可能因为断言错误而失败反而误导你去改正确的代码。边界遗漏模型更习惯生成常见输入对极端类型比如超大整数、None、嵌套结构经常漏掉。代码与测试不匹配如果函数签名或行为发生变化旧测试不会自动更新容易累积成问题。排查这类问题的方法就是先审测试计划再生成测试代码最后跑测试看失败原因。不要让 LLM 生成的测试用例直接进入 CI一旦出现“红了一片”先判断是测试错了还是代码错了。另外一个很常见的工程报错是LLM request failed: provider rejected the request schema or tool payload.这个报错通常出现在给函数传入工具定义时。原因是工具调用function calling的 JSON Schema 不符合模型 API 的要求比如缺少 required 字段、参数类型写错、或者附加了 API 不支持的字段。排查思路很简单把发送给 API 的完整工具定义打出来用 JSON Schema 的校验器查一圈再对照 API 文档逐一核对字段名。大多数情况下问题出在“你以为的字段名”和“API 真正要求的字段名”不一致。6. LLM 智能体、容错控制与安全红线6.1 从“聊”到“做”Agent 的基本骨架LLM 本身只能“说”不能“做”。Agent 的出现本质上是把 LLM 放到一个循环里让它能调用外部工具、观察结果、再决定下一步动作。目前业界最常见的一种骨架是 ReAct 模式流程如下思考Thought模型分析当前状态决定该做什么。行动Action模型输出一个工具调用请求比如“查询天气 API参数 city北京”。观察Observation系统执行工具把结果返回给模型。循环模型根据观察结果继续思考直到达到终止条件。工程实现时你需要维护一个“工具集”和一个“循环控制器”。工具集是 JSON Schema 描述的函数列表循环控制器负责调用模型、解析输出、执行工具、拼接历史。这个看似简单的循环实际在生产环境里会遇到大量问题。最常见的几类包括模型输出了格式错误的工具参数导致解析失败。模型陷入了循环反复调用同一个工具而不推进任务。工具执行超时但模型还在等待结果。模型给出的下一步动作明显不合理但系统没有拦截机制。6.2 构建可靠的容错控制系统要构建真正可用的 Agent关键是容错控制。我看热词里那篇论文标题讲的就是“LLM 智能体自主容错控制构建可靠 AI 系统的工程实践”这一类问题在真实业务里非常值得重视。我的建议是给 Agent 加上五道防护超时与重试每次工具调用设置超时时间建议根据工具平均耗时动态调整超时后重试一次再失败则让模型换路径。最大步数限制防止模型失控地无限循环。一般任务不要超过 10 步。循环检测记录最近的工具调用序列如果同一工具、同一参数重复出现多次直接终止或切入人工提示。格式校验在模型输出传给工具之前用 JSON Schema 做一次校验格式不对就返回错误信息让模型自己修正。输出护栏对模型最终输出做敏感词过滤或规则校验避免错误信息直接给用户。这里特别想提一下“记忆与知识库投毒”的安全风险。业界已经出现类似 AgentPoison 的研究攻击者通过在 Agent 的记忆库或知识库中注入恶意内容诱导 Agent 在后续决策时输出攻击者想要的结果。通俗来说Agent 会“读什么信什么”如果你直接让它检索外部知识库或长期记忆而没做来源可信度校验它很可能把注入的假信息当成事实用于决策。防御思路不是不用知识库而是做几件事检索结果白名单只允许 Agent 读取可信来源的内容。来源标注让检索结果带上来源 IDAgent 输出时标注引用。最小权限Agent 调用的工具只给完成任务所需的最小权限不要把数据库写权限也交付给模型。输入输出过滤对写入记忆库的内容先做一遍敏感词和格式审查。注意安全不是上线前才考虑的事。只要你的 Agent 涉及外部数据或用户数据就应该在架构设计阶段把这些防护加进去。后期补防护成本会高很多。最后再分享一个我的经验这个系列的第一篇我从模型原理写到了工具链、本地部署、微调、评测和 Agent 容错内容跨度很大。但我最想让你带走的一句话是大模型项目真正的难点从来不是模型本身而是模型之外的数据、评测和工程边界。我自己早期做项目时把大量时间花在“换更强的模型”上结果效果不稳定问题根本不是模型不够强而是评测集太随意、Prompt 没版本管理、Agent 没有容错设计。后来一点点把“LLM Wiki”建起来每一个实验都记录、每一次失败都归因项目的进展反而变快了。建议你从今天开始做一件很小的事建一个文档把你下一个 LLM 实验的任务目标、数据、模型、参数、测评结果和失败案例记录下来。等这个系列写到后面几篇你再回头看这份记录会发现它比任何教程都有价值。
返回列表