所有文章
非专业人士的AI课6:LLM大模型的典型应用级别
本系列文章的目标是从非AI从业者的角度出发,去尝试理解AI及其大模型在应用中的基本概念,争取通过对这些概念的深入理解和澄清,建立对大模型的工作机制流程以及应用框架方面的知识结构,从而在我们的生活和工作中更好的使用AI。 LLM大语言模型在特定行业领域中的应用,大致可以分为下图所示的几种级别。其中,从头开始设计和构建大模型当然是难度和门槛最高的,而最简单的应用就是我们所谓的提示词工程(Prompt Engineering),即在向LLM大语言模型提问的时候,对提问问题的语言组织结构(提示词,Prompt)进行精心安排,使大模型的输出更符合自己的提问需求。 !image.png 从头开始构建模型 对于从头开始构建大模型的应用而言,整个流程就如[[3. LLM大语言模型项目的典型开发流程详解]]所述,从项目需求分析和定义开始进行规划,选择合适的技术路线或者基于开源的大模型框架进行优化,针对模型和应用开发需求,提前准备训练数据,使用数据对模型的参数分别进行预训练和微调,最终部署到服务器上并推广给目标用户使用。 以上的全过程,对于团队能力、算力资源、数据、开发周期的要求都是非常高的。因此,这种开发模式也是大模型应用中门槛最高的类型。 私有化部署开源LLM后微调 这种方式相比从头进行大模型的开发而言,简单了一些,基本上是把已经完成预训练的开源LLM模型(这种已经完成预训练的模型也称为基础模型,Base Model)进行私有化部署,然后按照应用领域的微调需求,使用与该应用领域相对应的微调标注数据进行微调。微调之后的工作量与从头开始构建模型的模式差异不大。 这种开发模式,省去了大语言模型本身的设计开发,以及已经基于海量通用语义数据对模型进行了预训练,只需要进行微调即可,对于团队能力、算力资源的要求大大降低,因此这种开发模式对中小型团队和个人开发者而言比较友好。 指令微调LLM 首先解释一下基础大语言模型(Base LLM)和指令微调大语言模型(Instruction-Tuned LLM)。 - Base LLM 是一种通过大规模自监督学习(self-supervised learning)预训练的语言模型,主要依赖海量文本数据来学习语言结构和模式。这类模型虽然具备强大的文本生成能力,但在执行具体任务时往往缺乏明确的指令理解能力。也就是说,在[[3. LLM大语言模型项目的典型开发流程详解]]中完成了预训练,但是尚未进行微调的模型就是Base LLM,相当于这类模型具有对语言的语义规律和基础知识有充分的理解,但是缺乏对于用户输入指令的理解能力。 - 相比之下,Instruction-Tuned LLM 是在 Base LLM 的基础上进行了额外的指令微调,目的是使其更善于处理人类提供的任务指令,提高了实用性和交互体验。相比Base LLM Model,经过指令训练集进行指令微调以后,模型就具备了更强的任务执行能力,能够更准确地按照用户的需求生成符合用户预期的、有价值的内容。 基于Base LLM,对该模型进行指令数据集的微调之后,Base LLM就可以进化成为Instruction-Tuned LLM。指令数据集一般包含指令-上下文-响应的完整序列,因此指令微调对于数据的要求很高,一般包含人类标注员针对指令微调任务所编写的大量任务示例,用以训练模型理解任务指令并生成符合预期的响应。 下面是指令微调数据集的比较典型的例子: !image.png - 用于指令微调的数据集对于数据的内容和格式有比较高的要求,databricks-dolly-15k是一个开源的指令微调数据集,其中包含由数千名 Databricks 员工生成的遵循指令的记录。可以从HuggingFace上下载该数据集。 经过以上的指令数据集对Base LLM的微调之后,模型就可以对用户所输入的指令进行识别、执行并输出更符合用户预期需求的答复。而为了进一步约束模型输出的答案,部分模型还会采用人类反馈强化学习(RLHF)的模式让模型生成的答案更加符合人类的价值观和伦理道德偏好。 - 这个过程在[[3. LLM大语言模型项目的典型开发流程详解]]中已经有详细的描述。 其实,微调的含义往往超过了此处重点介绍的指令微调,实际的应用中,我们也会针对具体行业领域和应用场景所需要的专业知识,整理出来针对性的微调训练数据,在Base LLM的基础上针对这些具体的行业领域场景进行微调,使之更适合应用于该领域。这部分微调的过程基本上与指令微调类似,都是在Base LLM的基础上进一步使用额外的训练数据进行训练,使之更加符合应用的要求和预期。 > 在此之上的部分,都可以称之为AI模型开发(AI Model Development);而在此之下的则可以称之为AI应用开发(AI Application Development)。 RAG/AI Agent RAG和AI Agent是当前AI应用开发领域中最为火热的方向。 有关RAG部分的信息,在[[4. 一文说清楚RAG的工作流程以及与微调的区别]]一文中已经有非常详细的解释和描述,在此不再赘述。 有关AI Agent部分的信息,在[[5. AI Agent的框架与工作流程解析]]一文中已经有非常详细的解释和描述,在此不再赘述。 Prompt Engineering 下面的少样本提示和零样本提示都可以归纳入提示词工程(prompt engineering)的范畴。提示词工程就是我们精心设计、优化输入信息,从而引导AI生成高质量、准确、有针对性的回答的语言艺术。如果你写提示词的能力不够,那么AI给出的往往就像是用一堆正确的废话堆砌而成的文字垃圾;反之,它的回答会非常令人惊艳。所以,使用同样的大模型去查询相同的问题,大模型的输出质量与输入的提示词有非常强的关联。 提示词如何书写,并没有一个明确的答案,但是考虑到大语言模型进行输出信息推理的工作原理和流程,一个较好的提示词应该至少包含角色定义、提供上下文以及确定目标/提出问题这三部分信息。以下是参考资料三种提到的一种写好提示词的框架结构,按照这个框架对自己向LLM提出的问题和要求的描述进行精心组织,可以很有效的解决我们在工作和生活中的大量问题。 !image.png 少样本提示 所谓的少样本提示(Few Shot Prompting),就是针对一些稍微复杂的问题,我们使用语言很难轻易的把需求清楚的表达出来的时候,我们就可以在向大模型提问的时候,给大模型提供一些样本,让模型自己去分析样本的结构、逻辑、语气表达形式等,并根据自己学到的东西,给我们生成类似的内容。 下面是一个少样本提示的很经典的例子。用户向大模型输入的提示词是: !image.png 以上提示词从模型返回的结果是: !image.png 零样本提示 零样本提示(Zero Shot Prompting),是指不需要在提示词中包含任何示例,大模型就能够完成用户所指示的任务。这种提示词一般是用于面向比较简单、目标和过程清晰的任务,而且也要求用户的提示词十分明确,大模型具有相当强的能力理解用户的需求。 总之,针对相对比较简单和目标清晰的任务,可以使用零样本提示词尽可能明确、清晰、详尽的定义自己要模型执行的任务,以方便模型理解。 参考资料 - 《大模型应用开发:动手做AI Agent》 - 《大模型RAG实战:RAG原理、应用和系统构建》 - 《AI效率手册:从ChatGPT开启高效能》 - 一文说清楚什么是基础模型(Base LLM)、指令微调模型(Instruction-Tuned LLM)
非专业人士的AI课5:AI Agent的框架与工作流程解析
本系列文章的目标是从非AI从业者的角度出发,去尝试理解AI及其大模型在应用中的基本概念,争取通过对这些概念的深入理解和澄清,建立对大模型的工作机制流程以及应用框架方面的知识结构,从而在我们的生活和工作中更好的使用AI。 AI Agent是什么? 在AI的应用方面,目前最成熟和最广泛的仍然是以类似ChatGPT一样的对话应用,系统提供一个可支持文本输入或者语音输入的界面,用户在其中按照提示词工程的要求输入问题,AI系统对其进行学习研究、推理决策、生成答案,最后再通过文本框或者语音的形式把生成的答案展现给用户。 而AI Agent,也称为AI智能体或者AI智能代理,是一个具有一定程度自主性的人工系统。更具体地说,AI Agent是一个能够自动感知环境、做出决策并付诸行动的智能系统。 因此,相比于ChatGPT类型的对话方面的应用(重心在于能够回答用户所提出的问题),AI Agent系统所具备的自主性和适应性是其最大的特色。Agent能够自动通过对输入的分析感知环境、参数变量的变化,针对变化自主思考下一步的行动计划,并自行执行经过深思熟虑的思考后的行动,最终给出结果。 - ChatGPT类应用:会对话 - AI Agent:会做事 AI Agent的架构 下图是参考资料1第二章所提出的一个AI Agent的框架图。从图中可以看到,一个典型的AI Agent包括四大元素:规划,记忆,工具,执行。 !image.png 规划 AI Agent需要具备思考和规划的能力,而LLM所具备的推理能力很好的解决了这个问题,这也是LLM在推理方面逐渐成熟一下,AI Agent也随之爆发的原因所在。 对完整的复杂任务所进行的规划和思考,主要包含对子目标和任务的分解(Subgoal Decomposition)、连续的思考(即思维链)、自我反思和批评(Self-critics),以及对过去行动的反思(Reflection)等。 记忆 AI Agent的记忆包含两个方面,短期记忆和长期记忆。 短期记忆与任务执行的上下文相关,属于提示工程的一部分,一般在AI Agent运行过程中整理在对话的上下文中传递给大模型服务器。 长期记忆,则用于对AI Agent要用的信息长时间保存并能够实现高效率的检索,最典型的就是能够支持外部知识库,把Agent运行任务需要的外部知识以向量化的方式保存在外部数据库中,并且能够支持高效的检索。 工具 由于大模型一旦完成预训练,其内部能力和知识边界就基本固定下来,而且难以拓展。此外作为基于文本和自然语言的处理和生成工具,大语言模型不太适合一些工作(例如复杂浮点数字的计算),因此就需要一些外部工具来扩展Agent的能力,使其能够执行这些它很难胜任的任务。 AI Agent系统可调用的外部工具,典型的包括网络搜索、日历时间、计算器、本地代码执行能力(Function Calling)等。 执行 AI Agent需要具备调用工具执行任务的能力,与外界互动,通过调用工具的方式来完成一个动作或者子任务。 从上图可以看到,AI Agent如何规划和决策制定过程,如何调用工具来执行行动的完整工作流程是其应用的核心所在,这部分工作逻辑就称为AI Agent的推理引擎或者认知框架。推理引擎决定了Agent如何从感知的环境中抽取信息,如何规划未来的任务,如何利用过去的经验,以及如何调用工具。 研究人员提出了多种智能Agent的推理逻辑,如CoT、ToT、LLM+P等。其中,ReAct框架脱颖而出。 AI Agent的React框架 本质上讲,AI Agent的React框架就是一个思考-行动-观察这个完整序列所组成的循环。 - Thought:基于用户任务的总体目标、当前的状态以及可用的工具集,思考下一步的行动计划,确定下来行动方案。 - Action:基于思考的结果,决定具体要采取的行动并执行。 - Observation:收集并观察前一步的执行结果,对结果进行评估,决定下一轮次的思考方向。 !image.png 以上的流程从概念上理解非常简单,但是应该如何与现实中的AI应用的具体实现来相关联呢?以下通过一个基于LangChain开发框架的示例代码进行说明。 在下面的例子中,使用LangChain框架开发一个简单的Agent。这个Agent的工作流程非常简单,大模型首先对用户输入的问题进行分析,如果需要执行浮点数加减乘除的运算时,就调用本地实现的浮点数运算的代码,然后把结果返回给大模型,由大模型来组织语言输出结果。 其实这个功能完全可以基于大模型的API来使用function calling的方式来实现。但是,通过这个例子的打印信息,可以看到大模型进行思考、决策、调用工具并返回结果的过程,其他更复杂的Agent应用实际上也是类似的工作流程和逻辑。 以下例子自测通过,使用月之暗面的Kimi作为LLM服务器,关于LLM模型的API Key设置以及通过API调用可参考[[基于Python快速实现与Kimi的AI对话]]。 以上程序运行的结果是: 以上通过终端打印的信息很值得研究: - 首先就是,在用户问题提出的连续计算的需求,被明确的分成了两步,首先计算加法,然后再计算乘法。每一步的计算逻辑都是:模型给出这一步的计算式,本地代码运行这个计算式,把结果以字符串形式返回模型,模型基于中间结果再执行下一个计算式,直到最终计算完成后输出结果。 - 大模型竟然把每一步的计算式都已经用字符串的形式整理好了,本地代码拿到这个计算式以后只需要使用eval进行计算就可以了,这确实太方便了。 参考资料 - 《大模型应用开发:动手做AI Agent》
非专业人士的AI课4:一文说清楚RAG的工作流程以及与微调的区别
本系列文章的目标是从非AI从业者的角度出发,去尝试理解AI及其大模型在应用中的基本概念,争取通过对这些概念的深入理解和澄清,建立对大模型的工作机制流程以及应用框架方面的知识结构,从而在我们的生活和工作中更好的使用AI。 RAG RAG(Retrieval Augmented Generation,检索增强生成),是一种结合了大型预训练语言模型与知识检索技术的新型生成模型,为应对大模型应用开发中的诸多挑战提供了新的思路。 生成式大模型存在的问题 大模型并不具备在环境不断变化的场景中回答特定问题所需的全面知识。例如,早期的ChatGPT 3.5版本的预训练语料库时间截至2021年,这意味着模型无法准确输出2021年以后的事实性问题,这正是现代大模型所面临的知识更新困境。 实际上,对于一个大模型来说,更新基础模型知识库是非常困难的一件事情。首先,需要保证预训练数据的质量;其次,更新知识库后的模型通常都需要重新训练,至少要将新数据与旧数据按照一定的比例进行混合训练,而不能仅仅使用新数据,否则会出现灾难性遗忘的问题。总之,大模型的知识更新问题将成为模型的一个重要痛点,并且是一个值得研究的课题。 RAG则可以很好地解决以上问题。该框架可以使模型访问超出其训练数据范围之外的信息,使得模 型在每次生成时可以利用检索提供的外部更专业、更准确的知识,从而更好地回答用户问题。 RAG的工作流程 RAG的完整工作流程主要涉及3个阶段:数据准备、数据召回和答案生成。输出质量的高低主要取决于数据质量和检索策略。 - 数据准备阶段包括识别数据源、从数据源提取数据、清洗数据并将其存储在数据库中。 - 数据召回阶段包括根据用户输入的查询条件从数据库中检索相关数据。 - 答案生成阶段则是利用检索到的数据和用户输入的查询条件生成输出结果。 下图是一个使用LLM大语言模型和本地知识库数据库(问题相关的知识和信息已经保存在本地知识库中)配合来实现的RAG系统的工作流程。 !image.png - 1.用户通过提示词输入查询RAG系统的问题。 - 2.系统对用户提出的问题进行分解,首先调用搜索引擎从本地知识库数据库中检索与查询问题相关的知识片段。 - 3-4,把查询到的知识片段作为查询的上下文放到用户输入提示词中。 - 最后,LLM对用户输入的查询问题以及上下文信息进行解析,生成文本答案。 > 相比于大模型的直接推理输出,RAG系统还有一个非常突出的优势,就是其输出信息的可溯源性。众所周知,在大模型领域中,模型基本都基于Transformer的解码器结构,因此大模型的生成结果存在不可解释性的问题。而RAG系统配合大语言模型的输出结果,不仅给出了答案,还提供了信息溯源的引用链接。因此,相较于纯粹的大模型生成,RAG具有更强的可解释性。 实际上现在我们使用的大模型普遍都提供了联网搜索的功能,而这个联网搜索的功能本质上就是RAG的实现。在回答问题之前首先配合搜索引擎查询有参考价值的网页,对网页内容进行检索处理,然后把检索到的相关内容放在大模型对话的上下文中,最终由大模型返回结果。 以下是使用deepseek不打开联网搜索功能的情况下,查询2024年美国大选的结果,因此deepseek的当前模型训练数据中只包含2023年10月份之前的信息,所以无法给出准确的答案。 !image.png 以下开启了联网搜索(相当于打开RAG功能),可以通过联网查到最新的信息,并且还给出了信息溯源的链接。 !image.png RAG与微调的对比 模型微调是指在一个特定任务上用一定量的数据来训练模型的过程,通过在特定数据集上微调可以提高模型在特定数据集上的性能。如果有足够大的监督数据集,且数据集不会发生改变,那么微调是一个很不错的方法。然而,如果数据集是动态的,就需要不断地重新训练模型以跟上数据的变化,这种情况下使用微调的方案,成本就会很高,而且系统的灵活性很差。 !image.png 总的来说,RAG位于大模型应用难易链条的中部,它既不像重新训练或从头构建模型或者微调模型那么难,也不像通过简单提示工程直接向大模型提问那么容易。它克服了直接微调模型的3个缺点——成本高、信息更新困难以及缺乏可观察性。相较而言,由于RAG无须训练,因此成本较低;由于数据是实时获取的,因此始终是最新的;由于可以显示检索到的文档,因此结果更加可信。
非专业人士的AI课3:LLM大语言模型项目的典型开发流程详解
本系列文章的目标是从非AI从业者的角度出发,去尝试理解AI及其大模型在应用中的基本概念,争取通过对这些概念的深入理解和澄清,建立对大模型的工作机制流程以及应用框架方面的知识结构,从而在我们的生活和工作中更好的使用AI。 本文通过对参考资料的学习,对LLM大语言模型开发流程中的各个环节进行总结和详细的解释,建立对LLM大语言模型开发的初步知识结构。 总体而言,在商业领域中进行的大模型开发而言,其主要的开发流程包括以下几个方面: - 项目需求分析,确定项目的目标 - 基于项目目标进行前期的数据准备 - 基于项目目标进行模型的设计和选型 - 使用数据对模型进行训练 - 部署模型到应用环境中,提供项目需求预定义的服务 - 模型在实际应用中的运维 1. 确定项目目标 在每个与大模型相关的项目立项开发初期,首先要做的事情就是要明确项目的目标,并构建项目的系统框架。因为这涉及到后续工作流程中,针对性的进行模型架构、算法以及训练数据集等的选型。 项目的需求分析和目标制定,是大模型项目开发的起点,为后续的数据准备、模型设计\选型、模型训练提供了明确的方向和约束条件。因此在大模型项目立项之前,应该首先明确该项目需要面对的知识领域和具体要解决的问题,只有项目目标明确确定的情况下,才能选择出来合适的模型和训练数据,进而设计出高效并且成本、效益符合项目需求最大化的系统框架。 下图就是参考资料1中提供的一个财务分析模型的系统设计: !image.png - 针对该系统的功能和性能需求,从开源模型中选择规模和成本合适的模型作为系统设计的基础。 - 以网上收集的公开财报等相关数据为基础,将大模型作为数据集构造器,通过让其学习这些少量标注数据的内容,来自动扩充数据集,为该项目后续的训练阶段提供更多的训练样本。 2. 模型训练数据准备 该阶段的工作实际上包含两个方面,数据收集和数据预处理。 按照项目系统设计的训练所需,开发者可以从网络、公开数据集、用户生成数据、公司内部数据等途径获取训练数据。对于LLM大语言模型的训练而言,数据类型涵盖图片、文字、音频等。开发者可重点考虑开源的数据集,以及针对当前模型要解决的垂直领域问题相关的网络公开数据集。 数据预处理的环节,则需要针对文本、图像等不同的数据进行分别处理,其目的都是构建高质量数据集: - 针对文本数据,常用的数据处理方法一般包含低质过滤(判断和识别低质量的数据并去除)、冗余去除(从不同粒度的角度出发去掉数据中的冗余元素)、隐私消除(识别和去除数据中包含的个人/组织隐私和敏感信息)等。 - 针对图像数据,一般采用图像去噪(降噪)、图像重采样(分辨率缩放)和图像增强(提升对比度、亮度等)等技术,以提升图像数据质量。 分词与嵌入 数据处理完成后,下一步就是要进行分词,也就是Tokenization。所谓的分词就是把文本分割成离散的、有意义的最小语言单元的过程,而这个最小的语言单元就是Token,从训练的文本变成Token的过程使用Tokenizer完成。 - 在平时我们使用LLM大语言模型的过程中,可以清楚的看到模型的输出以一个字或者一个词的节奏按顺序吐出来,这个字或者词就是一个Token。而当我们调用API对LLM大模型进行访问的时候,费用也是基于与大模型交互的Token数量(包括用户向模型提问问题的上行Token数量和模型输出答案的下行Token数量)来进行收费的。 - 为了方便开发者对文本进行分词处理,许多主流的开发框架将分词功能封装成Tokenizer组件或者类,供开发者调用。Tokenizer可以简化开发流程,提高代码复用性,并且确保整个过程中的一致性。因此可以从HuggingFace上下载开源的分词器进行定制化的修改。 !image.png 经过以上的分词器对训练文本所执行的分词操作后,文本语句就会被分割为一个个最小的语言单元。但是这个语言单元仍然无法被大模型识别,此时还需要对每个语言单元执行一个向量化的嵌入操作(Embedding)。而嵌入操作,就是把词汇映射成数值形式的向量的过程。如此一来,模型就能够理解和处理这些向量,并基于这些数值化的特征进行计算和分析,从而实现对自然语言的深入处理和理解。 - 分词和嵌入的这两个概念在基于大模型的RAG应用中,也需要用到,同样是把外部文件或者网络上搜索到的文本文件的内容,执行分词操作(Tokenization)以及嵌入操作(Embedding)后送入大模型进行后续处理。 !image.png 3. 模型的设计和选型 基本上,所有LLM大语言模型的基础都是Transformer架构,而多模态模型中针对图像模块的处理一般则采用Visual Transformer架构。总的来说,大模型的开发、设计和优化调试是整个系统设计与实现过程中技术难度最高的部分。因此: - 从现实的角度来讲,小型开发团队或个人开发者在完成大多数的人工智能业务实现时,已经无须从头构建模型,而是可以根据任务所需选择开源大模型,如Deepseek、Qwen、LLaMA、ChatGLM、Alpaca等。 这种方式可以节省大量的模型设计时间,提升开发效率。 - 而对于有较多资源和能力的团队而言,考虑自行从头开发模型,在模型构建之前,一般需要首先选择合适的深度学习框架,目前主流的深度学习框架有TensorFlow、PyTorch等。其中TensorFlow是由谷歌团队研发的开源架构,PyTorch是Meta团队研发的开源框架,而国内主流的开源框架有百度的飞桨PaddlePaddle等。然后定义模型结构,包括层次结构、参数初始化、定义损失函数、选择优化算法等。 4. 模型的训练 大模型的训练过程一般包含分词器训练、预训练和微调3个基本步骤。 预训练Pre Training: - 基于大型语料库对模型进行训练,目的是让大模型能够掌握基本的自然语言理解和生成能力,以及掌握丰富、广泛的知识,为后续的任务执行打好基础。 - 在预训练阶段,从低成本渠道中获取大量无标注数据,并且把这些数据送入模型,由模型对这些数据的共性知识进行学习,形成一种对于语言的通用理解能力。 微调Fine Tuning: - 微调是一种在预训练语言模型的基础上使用目标任务数据进行训练的模型训练技术。 - 在微调阶段,则是针对模型应用的知识领域和方向,使用少量相关领域的标注数据(一般成本比较高)在预训练阶段的Base Model基础上进行进一步的训练,使其适应目标领域和特定任务的应用需求。 > 当前,无论是在计算机视觉还是NLP领域,广泛采用了“预训练+微调”的开发范式。而一般情况下,尤其是对于中小团队而言,开发者不需要自行对模型进行完整的预训练,而是可以选择合适的开源预训练模型,然后根据具体任务的需求进行微调即可。 !image.png 此外,如果需要对模型的输出进行无害化处理(使大模型输出的内容不会包含有害、不当或者不符合伦理道德的内容),还需要借助RLHF、RLAIF等技术使模型与人类的价值观对齐。 - RLHF,Reinforcement Learning from Human Feedback,基于人类反馈的强化学习。具体工作步骤是,从prompt数据库中采样一部分数据,让模型同时生成多个答案;然后由人类标注员对生成的多个答案进行打分或者排序,然后再使用强化学习算法对模型进行微调。整个过程相当于使用模型生成多个答案的打分或者排序信息,使模型能够更好的与人类的价值观和意图对齐,生成更自然、更符合人类期望的输出。 - RLAIF,Reinforcement Learning from AI Feedback,即基于AI反馈的强化学习。RLAIF是RLHF的一种替代方法,目标是使用AI模型所生产的反馈来代替人类标注员所给出的反馈,从而降低在模型训练中对人工标注的依赖。其工作流程主要是借助于另外一个更为强大的LLM模型,对当前正在训练的模型的输出答案进行评估和打分(在这个环节替代了RLHF的人力工作),然后通过强化学习算法对目标模型进行微调。 5. 模型的部署 模型部署是指将大模型部署到实际应用场景的过程。但是,模型部署并非只是简单的把已经训练好的模型部署在服务器上就好。 在模型部署中,一般需要基于前期训练好的模型进行模型量化、知识蒸馏、模型剪枝等操作,以实现模型压缩,最大限度地减少模型依赖的硬件资源。 6. 模型的应用和运维 最后一步,就是把训练好的大模型服务向目标用户开启。那么针对大模型的使用和大模型服务的运维,就需要提供易用、美观的前端工具。此外,还可以利用LangChain这类大模型开发框架,基于已训练和部署的大模型,开发更加多样化的大模型应用程序以及以训练和部署好的LLM大模型为中枢决策和推理模块,构建更为灵活和强大的AI Agent应用。 参考资料 - 《大模型导论》,张成文 - 一文说清楚什么是预训练(Pre-Training)、微调(Fine-Tuning)
非专业人士的AI课2:对大模型多模态以及开源闭源概念的总结
本系列文章的目标是从非AI从业者的角度出发,去尝试理解AI及其大模型在应用中的基本概念,争取通过对这些概念的深入理解和澄清,建立对大模型的工作机制流程以及应用框架方面的知识结构,从而在我们的生活和工作中更好的使用AI。 究竟什么是大语言模型LLM? 目前我们所说的大模型,全称是大语言模型LLM(Large Language Model)。所谓的”大”是指这个模型所包含的参数量非常大,目前市场上主流的LLM模型的参数量都达到了千亿以上的级别。而所谓的“语言”是指自然语言(Natural Language),也就是这个模型可以直接使用自然语言(而不是只有计算机和程序员才懂的程序代码)与人进行交互,用户对这个模型的使用需求,以自然语言的方式输入模型,而模型也以自然语言的方式给出响应和答复。 用户输入自然语言文本信息到模型中,模型根据用户的问题生成用户能够理解的自然语言文本的内容,这种模型就是大语言模型的单模态模型。 最典型的LLM单模态大语言模型就是引爆OpenAI的GPT-3.5模型,参数量高达1750亿。如此大的参数量,意味着可以提供卓越的性能、强大的学习能力,但是同时也意味着对计算和存储资源提出更高的要求,训练和推理的成本也更高。 单模态与多模态 目前大模型的发展趋势,基本上比较流行的大模型都是多模态模型。所谓的多模态,就是模型的输入输出,不仅能够支持GPT3.5这样的单模态模型所能够支持的自然语言文本信息,也能够支持图像、音频甚至视频方面的内容,例如以文生图、视频,以及根据图像生成描述性文本等。 !image.png OpenAI目前的多款在市场上广受欢迎的多模态大模型,包括可识别图像的多模态LLM大模型GPT-4及其以上的版本,文生图模型DALLE3,文生视频大模型Sora,语言转文字模型Whisper等。而国内阿里的通义千问,腾讯的混元,百度的文心一言,字节跳动的豆包等大模型基本也都支持了对图像、音频等的多模态支持。 Yolo 实际上除了LLM大语言模型以外,还有一些专业性更强、专注于解决某一方向问题的其他AI模型。例如用于在视频图像中进行目标检测(人,车辆,宠物等)的Yolo模型,这类模型大概有上千万参数,注重轻量化和实时性,适合边缘计算场景,可以对输入图像进行检测生成目标框和类别预测,当前约78%的自动驾驶企业和65%的智能摄像头厂商选择YOLO作为主力检测框架,但其具体版本需根据硬件性能调整。例如车载系统多采用YOLOv8m(平衡精度与速度),而门禁摄像头则倾向YOLOv5s(更低功耗)。 大模型的开源和闭源 大模型选择开源或者闭源的商业经营模式,决定了这个模型的代码、模型权重、训练数据、训练过程等核心资源是否完全公开,允许任何人查看、修改和分发(如Apache 2.0等传统开源许可证)。 例如,DeepSeek-R1模型采用Apache 2.0协议,开发者可基于其代码自由开发商业应用。这种开放性促进了全球开发者的协作创新,形成“社区驱动”的生态模式。 下表是目前主流大模型的开源和闭源状态列表: !image.png 可以看到,Meta的Llama,阿里的Qwen,还有最近爆火的deepseek都选择了开源的商业模式。而实际上,自从deepseek爆火,国内的腾讯、Kimi等一种大模型厂商也选择了对其开发的大模型进行开源。那么为什么这些厂商选择了开源的商业模式呢? 大模型开源模式的优势 - 大模型开源之后带来的最大好处就是可以快速的建立自己的技术生态,吸引更多中小型的开发者和企业快速的参与到开源模型的改进和优化中。例如,Meta的Llama系列开源后,迅速衍生出多个垂直领域的模型,加速了技术的迭代。 - 开源生态的成熟也可以快速推动上下游厂商之间的合作与适配,例如DeepSeek开源后,迅速得到了云厂商、社区和芯片厂商的跟进。 - 开源模式能够吸引更多用户和开发者,从而提升品牌知名度和行业影响力。例如,DeepSeek的开源举措不仅推动了技术的普及,还重塑了大模型市场的竞争格局。对比技术竞争力相差不大但是采用闭源模式的Kimi而言,尽管Kimi 2024年在市场推广中投入了超过9亿的营销费用,但是推销效果远远比不上deepseek开源模式推广的影响力。 - 开源模式的商业盈利方式更加多元化。开源并不意味着完全免费,厂商可以通过提供增值服务(如企业级解决方案、定制化服务、API接口等)来盈利,还能够通过数据和流量变现,例如通过广告、用户数据分析等方式实现商业化。 - 当然,大模型开源的同时,也会采用专利等方式对自己的核心技术进行保护。例如,DeepSeek在多个关键领域提交了专利申请,涵盖大模型训练优化、系统稳定性优化、网络与硬件优化等。这种“开源+专利”的双轨策略,既保护了核心技术,又避免了被竞争对手抢注或侵权。 大模型以开源的方式发布以后: - 竞争对手和有大模型开发能力的团队,可以研究大模型的相关代码,参与到对这个模型的改进和优化,以及针对某些垂直领域进行定制化的开发和训练。 - 云服务厂商可以把训练好的大模型部署在自己的云服务器中,通过API等方式为用户提供服务来谋求商业利益。 - 中小型团队和个人开发者可以基于开源大模型进行私有部署,并针对当前行业和机构的需求进行定制化训练和微调。 Hugging Face 对于开源大模型,就必须要提到在AI大模型开发领域大名鼎鼎的Hugging Face网站(www.huggingface.co)。Hugging Face类似于AI模型领域的Github,该网站上维护了全世界几乎所有的开源大模型的代码,以及开源的模型训练数据。截至2025年3月份为止,在Hugging Face上已经上传了接近150万个大模型,超过30万个开源的训练数据集。所以,这就为小型团队和个人开发者自行部署和训练开源大模型提供了极大的便利。 !image.png 实际上对于绝大多数小型开发团队或个人开发者而言,如果要参与大模型开发的话,在完成大多数的人工智能业务时无须从头构建模型,比较现实的做法,是根据自己要解决的任务类型,按需选择开源大模型,如Deepseek、通义QWen、LLaMA、ChatGLM、Alpaca等。从Hugging Face这样的网站上下载对应的开源大模型、训练数据集以及其他训练和部署的工作,基于这个基础进行定制化行业应用方面的开发和训练。这种方式可以节省大量的模型设计时间,提升开发效率。
非专业人士的AI课1:深度神经网络学习入门
本系列文章的目标是从非AI从业者的角度出发,去尝试理解AI及其大模型在应用中的基本概念,争取通过对这些概念的深入理解和澄清,建立对大模型的工作机制流程以及应用框架方面的知识结构,从而能够帮助我们在生活和工作中更好的使用AI。 深度神经网络是一切AI模型的基础 目前几乎所有比较流行的AI应用及其模型,都是基于深度神经网络拓扑结构的。如下图所示,深度神经网络网络在层次上可以分为三层:输入层,非常多的中间隐藏层(这就是称之为深度网络的原因),以及最后的输出层。 !image.png 神经网络中的每一个节点都是一个神经元。对于各个神经元的计算而言,大体上可以分为以下两个步骤: - Step 1:从前一层的所有节点按照不同的加权权重(Weight,如下图中的多个w参数)进行乘加运算,再把乘加计算的结果加上不同的偏移量(bias,如下图中的b参数),得到第一步的计算结果。 - Step 2:以第一步的计算结果作为输入,进行激活函数(即下图的f函数)的运算。目前的神经网络多种比较常用的激活函数,其输出范围取决于具体使用的激活函数类型。不同的激活函数有不同的输出范围,大部分激活函数的输出范围是(-1,1)或者(0,1)之间的连续浮点数据。 !image.png 深度神经网络的参数量 在深度神经网络中,我们所说的参数量通常指的是神经元之间连接的权重(Weights)和偏置(Biases)的总数量,而不是神经元的个数(也就是上图中的w参数和b参数)。 以下给出一个参数量计算量的简单例子。假设有一个简单的全连接神经网络,其结构为:输入层有 n 个神经元,隐藏层(单层)有 m 个神经元,输出层有 k 个神经元。 输入层到隐藏层: - 权重数量:n×m(每个输入神经元连接到每个隐藏神经元) - 偏置数量:m(每个隐藏神经元有一个偏置) - 总参数量:n×m+m 隐藏层到输出层: - 权重数量:m×k(每个隐藏神经元连接到每个输出神经元) - 偏置数量:k(每个输出神经元有一个偏置) - 总参数量:m×k+k 因此,整个网络的总参数量为: 总参数量=(n×m+m)+(m×k+k)。 !image.png 无论是ChatGPT这类大语言模型,还是Yolo这样的对图像中的目标进行检测和分类的模型,其实现从本质上讲都是以上所描述的深度神经网络的结构。而从以上深度神经网络的架构来讲,无论是开发中的训练还是部署后的推理,都是从input层输入数据,在中间的隐藏层进行计算和传递,最终在output层输出,其中主要涉及到的运算就是在各层的神经元之间进行的海量乘加运算,因此模型越大,层次越多,参数越多,那么要进行一次计算的计算量都成指数增加,这就是大多数大模型的训练以及推理对于算力要求很高的原因所在。 - 可以认为,LLM大语言模型所学习到的海量知识就保存在各层神经元的参数之中。
以代码案例来详细介绍Function Calling
什么是Function Calling? 众所周知,大语言模型本身只是一个文本生成的工具,虽然有很强的文本生成能力和逻辑推理能力,但是LLM并不具备直接去执行外部功能操作的能力。因此,如果我们要把大模型用于实际产品的应用场景之中,只能利用大模型来生成文本信息的话,那么整个系统真正能够解决问题的能力就会大打折扣。 如果能够将大语言模型所具备的自然语言处理能力,与外部工具/API调用功能相结合的话,就能够显著增强大模型在实际应用场景中解决问题的能力。大模型所具备的function calling就提供了这样一种机制,能够把大模型处理文本的能力,与本地通过function调用的能力相结合,从而为大模型的实际运用提供了极大的拓展空间。 > 大语言模型function calling的工作逻辑,就是在以大语言模型为中心的人工智能系统中,利用大语言模型所具备的推理能力,在系统的运行过程中根据大模型的响应信息,自动调用本地/外部工具或API,从而达到扩展人工智能系统能力的目的。 Function Calling的工作流程解析 以下借助于参考资料1中的一个流程图来对大模型的function calling的执行流程进行说明。 在该流程案例中,当用户向大模型查询”北京今日气温“相关的信息时,因为涉及到对实时信息的查询,因此LLM本身是不可能直接输出正确结果的。此时就需要借助于类似function calling这样的外部工具。 在这种情况下,function calling机制要能够工作,在用户查询这个实时天气信息相关的问题时,大模型需要先知道当遇到这类问题的时候,应该调用的外部函数名称和参数列表是什么。这个信息(也就是给大模型提供的外部工具集Tools参数)与问题一起传递给大模型。 大模型对用户问题(及Tools中包含的外部函数列表中包含的外部函数描述信息)解析时,判断该问题是否需要调用Tools参数中所传递的外部函数。当判断该问题需要调用外部函数时,大模型会在返回的文本信息中包含该外部函数的调用参数列表。如下图的第二步所示。 用户应用程序收到大模型给出的答复后,在本地按照大模型返回的参数列表调用指定的外部函数,得到执行结果,并把执行结果包含在Json结构中,重新返回给大模型。如下图的第三步和第四步所示。 大模型收到外部函数的执行结果后,对其进行数据格式转换,并按照用户问题的语义信息,结合外部函数返回的执行结果信息,重新生成最终的文本答复给用户。如下图的第五步和第六步所示。 !image.png Function Calling的核心工作机制总结 以上所描述的Function Calling完整流程的正常运行,依赖于外部函数能力描述、大模型语义解析以及外部函数调用流程三个方面的支持。 外部函数能力描述 如果需要大模型在应用中能够针对特定的问题,自动生成对外部函数的调用信息,就需要首先向大模型传递外部函数的描述信息。因此,开发者需要预先定义好可供大模型应用在执行过程中可调用的函数清单,其中包含每个函数的API描述、参数规范(类型/格式说明)和返回结构等信息。这样,在大模型遇到相关问题的时候,才能够应该调用哪个外部函数,以及调用这个外部函数应该使用的参数列表。 以下是一个外部函数的描述信息,在向大模型发出问题请求时,在上下文中同时提供给大模型。该外部函数可以用于计算两个浮点数的乘积,调用时应该以字符串的形式提供两个浮点数参数。 大模型语义解析 在这个环节,大模型应该对用户输入的问题及其上下文中包含的外部工具函数集的信息进行解析: - 针对该问题,是直接按照传统LLM的流程来进行处理,还是需要调用问题上下文中中包含的外部函数来辅助? - 针对该问题,如果需要调用外部函数,对用户问题和外部函数集中的函数描述信息进行解析,找到对应于该问题的外部函数。 - 针对该问题,如果需要并且找到解决该问题的外部函数,需要进一步分析语义,并且按照该外部函数描述中的参数信息,整理出来调用该函数的参数列表。 以上信息完整获取后,大模型在其应答信息中把该信息返回给应用程序,下一步要由用户应用程序在本地来执行大模型所指定的外部函数。 外部函数调用流程 这部分就是大模型与本地应用程序配合,能够支持本地应用程序在收到大模型给出的答复信息后,从答复信息中得到要执行的外部函数及其参数列表信息,在本地/通过API执行这个外部功能函数,并把执行结果以及前一步骤完整过程的上下文(再强调一下,LLM没有记忆和状态,每次访问LLM都需要把完整的过程上下文一起上传,方便LLM对该过程有清楚完整的理解)发给大模型,由大模型生成最终的答案并返回。 Function Calling的例子 > Talk is stupid, show me the CODE。 以下以一个Python的代码例子来对大语言模型调用function calling的功能进行说明。该例子的大致运行流程如下。即对于传统LLM可支持的问题仍然通过传统的LLM工作流程来进行处理,但是对于LLM不支持且在function call tools已声明的应用中(此处的例子为查询当日天气、计算复杂浮点数相乘)调用function call功能在本地进行处理并把结果返回大模型,最终统一由大模型来输出答案。 - 蓝色部分模块由应用程序执行,红色部分模块由大模型执行。LLM-function-call-workflow.png 以上代码执行的打印信息为: 可以看到,从该程序的运行流程来看完全符合设计预期: - 当用户输入的问题是“陕西省的省会是哪个城市?”,这个问题是在大语言模型的知识范围和能力之内,因此大语言模型直接给出答案,不需要调用function calling功能。 - 当用户输入的问题是“北京今天天气怎么样?”,这个对于实时问题的查询明显超出了大模型的能力范围,再加上我们在大模型调用时提供了get_weather接口的描述信息,要求大模型在查询天气时,在响应的文本消息中返回调用该函数的参数列表。应用程序收到以后,自动调用get_weather函数并传递该参数列表,得到当前的天气状态,并提供给大语言模型生成最终的答案。 - 同样的道理,当当用户输入的问题是“3.567乘以25.345等于多少“这样的复杂浮点数乘法的计算,这也是明显超出大模型能力的应用,此时按照相同的逻辑,由大模型返回要调用的本次函数名称get_multiply_result和计算参数列表,自动调用本地的get_multiply_result函数得到计算结果以后,再返回给大语言模型生成最终的答案。 参考资料 - 不再混淆了!一文揭秘MCP Server、Function Call与Agent的核心区别
大模型的MCP到底是什么
MCP简介及其核心作用 MCP:Model Context Protocol,即模型上下文协议,是由Anthropic公司(也就是Claude大模型的开发商)在2024年11月份所开源的标准通信协议,其目的是为大语言模型(LLM)与外部服务之间的通信提供一个标准化的接口协议,实现与外部数据源、工具等的无缝连接,从而扩展大模型的能力。 从本质上讲,MCP是一种在智能体Agent和大模型应用程序开发过程中大家共同约定的一种技术规范和协议。它所解决的最大痛点问题,就是AI Agent及其应用开发中调用外部工具的技术门槛过高、碎片化严重的问题。 !image.png MCP通信协议的核心作用可以概括为: - 统一大模型与外部服务之间的通信接口和交互标准。通过这种类似于通用插座的协议设计模式,解决了大模型与不同外部服务(如 GitHub、Slack、本地数据库等)通信数据格式和交互规则不统一的问题。 - 有效的提升了开发效率。对于外部服务的开发者而言,只需要按照MCP规范开发一次MCP Server,所有兼容 MCP 的模型或者其他类型的客户端均可直接调用,无需重复适配。 - 可以优化大模型的工作性能。通过在交互流程中动态加载上下文数据,可以为模型提供更精准的上下文信息输入,从而提升回答的准确性和实用性。 MCP的客户端-服务器架构 MCP协议的实现是基于客户端-服务器架构的。 MCP Client MCP Client一般集成在用户交互英语程序(如基于大模型的应用程序、AI Agent、Chatbox等)之中,负责与MCP Server通信来整合Server所提供的能力和服务,驱动整个应用程序任务的执行。 MCP Client所包含的核心功能如下: - Client在初始化时,要向所有配置的MCP-Server发送能力查询请求,通过其响应消息收集可用的工具列表信息(包括工具名称、描述、参数等)。 - Client根据要执行的任务需求,动态调用合适的工具,并协调多工具之间的协作(例如调用天气查询服务API后结合其结果生成回复)。 - Client可以通过MCP通信协议支持对接本地以及远程的多种Server类型,无需修改代码即可扩展能力。 总之,MCP Client是MCP服务的主动消费方,根据整体应用程序的设计需求以及用户输入的数据信息,有效的对其注册的MCP服务组合进行调用,达成应用的设计目标。 MCP Server MCP Server则是被调用方,负责向外提供具体的能力服务或者数据接口。典型的MCP服务可以包括大模型服务(例如文本、图像生成等)、工具(本地文件、数据读取、爬虫、数据库查询)以及第三方的API(例如天气查询)访问。 MCP Server所包含的核心功能包括: - MCP Server应按照MCP协议所定义的标准化接口来实现,并向Client注册自身所具备的能力(如tool_name、description、参数规范)。MCP Client根据这些标准信息可以了解到MCP Server所能提供的服务,以及应该如何调用这个服务。 - 在运行过程中,MCP Server对外提供服务,处理来自Client的请求并返回结果(如执行Linux命令、查询数据库、调用大模型生成内容等)。 - 此外,作为服务的提供方而言,MCP Server还需要支持资源控制(如限制敏感数据访问)和安全性管理(如身份验证)。 总之,MCP Server是MCP服务的被动提供方,按照MCP协议标准的要求对外其他服务,Client既可以通过标准接口查询MCP Server所提供的服务,也同样可以通过标准接口来调用这些服务。 MCP的通信机制 为适应本地调用和远程调用MCP Server两者方式,MCP协议定义了两种通信机制:针对本地的stdio以及针对远程访问的HTTP/SSE通信。如下图所示: !image.png 针对远程访问的HTTP/SSE方式 SSE(Server Send Events)本身是针对HTTP协议支持长连接通信的一种扩展协议。使能SSE的情况下,HTTP客户端通过发送一个特殊的HTTP GET请求到服务器,请求中包含Accept: text/event-stream头,表明客户端期望接收SSE数据流。服务器响应后会保持连接打开,并可以持续向客户端推送数据。需要注意,SSE连接的情况下,只能由服务器向客户端单向推送数据,客户端不能使用这个链接向服务器发送数据。 当客户端通过HTTP SSE建立持久连接后,服务器就可在有新的数据的情况下,通过该连接向客户端持续推送数据流,实现从服务器到客户端的实时单向通信。而当客户端有新的请求时,仍然需要通过独立的HTTP Post消息向服务器发出请求,服务器则通过之前建立的HTTP SSE长连接向客户端持续返回流式响应。 客户端和服务器之间的所有请求和响应数据均采用JSON-RPC 2.0规范,以确保结构化数据传输。 针对本地访问的stdio方式 针对MCP Sever和Client之间的本地访问需求,MCP则定义了一种stdio(标准输入输出)的本地进程间通信的传输方式。 在这种模式下,MCP客户端在启动的过程中,直接在本地启动MCP服务器应用程序作为其子进程,此后两者之间使用操作系统的标准输入(stdin)和输出(stdout)管道来进行通信。通信流程采用同步交互的请求-响应机制,每条请求需等待对应响应后才返回,客户端通过stdin发送JSON-RPC 2.0格式请求,服务器端则通过stdout返回JSON-RPC 2.0格式的响应。 MCP的典型工作流程解释 对于标准的MCP Client和Server之间的交互流程而言,一般包含两个阶段:初始化及Server能力协商,服务请求与响应。 !image.png 初始化与Server能力协商 在MCP Client应用程序启动时,需要首先向其配置的所有MCP Server发送discover请求,获取其所具备的能力服务列表、描述信息、调用参数详情等。 MCP Server在收到Client的discovery请求后,返回结构化的工具描述信息,例如以下是一个天气查询服务的描述信息:{tool_name: "weather_query", description: "查询实时天气", parameters: {city: str}}。 MCP Client在收到以上信息以后,就能够在后续应用程序的运行过程中需要进行天气查询的时候,按照参数格式的要求调用这个MCP Server所提供的服务。 MCP服务请求与响应 MCP Client在应用程序的执行过程中,根据任务的执行需求来选择合适的工具(可选择的工具列表已经在前面的初始化阶段查询到),然后向MCP Server发送包含访问参数的JSON-RPC请求。例如{"method": "weather_query", "params": {"city": "Beijing"}}。 MCP Server收到Client的请求后,执行与调用参数对应的操作(例如调用OpenWeather API)并向Client返回结果(如温度、湿度数据)。 MCP Client收到Server的响应以后,将多个Server的返回结果整合,最后再传递给大模型以生成最终的响应文本消息(如生成包含天气建议的自然语言回复)。 MCP与function calling的区别 首先明确一点,MCP只是一个通信协议和流程的框架,在MCP应用中并不一定必须要存在AI大模型,用户完全可以开发一个独立的MCP客户端和MCP服务器端,然后在客户端和服务器端基于MCP协议进行通信交互,实现特定的功能。只不过,在AI大模型能够支持MCP协议的情况下,在MCP应用中引入大模型的参与,可以显著提升应用的智能化水平和用户体验。 其次,在MCP应用中,大模型通常扮演MCP Client的角色。具体来说: - MCP Client:大模型作为客户端,可直接通过MCP协议向预先定义MCP Server发起请求,调用外部工具或数据源。这个过程中,大模型负责解析用户的需求,决定需要调用哪些工具,并通过MCP协议与提供MCP服务的服务器进行交互。 - MCP Server:基于MCP协议对外提供外部工具和数据源访问的服务器应用,它将各种资源和服务封装成标准化的接口,供大模型(MCP Client)调用。 从MCP实现的功能上讲,它与function calling非常类似,但是两者有着本质上的区别: - 外部任务的执行主体不同:对于MCP应用而言,外部任务的执行由大模型服务器自行基于MCP协议访问对应的MCP Server,得到答案以后以自然语言返回给用户,而function calling是用户以自然语言提出的问题,大模型解析以后结构化数据的形式返回给用户的应用程序,由用户应用程序在本地执行function功能,因此用户应用程序需要自己处理外部函数的执行和结果的返回。 - 协议和交互的规范性:MCP定义了一个标准化的通信协议和工作流程,规范了MCP Client(大模型)和MCP Server(外部工具和服务)之间的交互逻辑,这使得不同模型和工具之间的交互更加统一和高效;而function calling的具体实现通常依赖于用户应用程序的自行定义,不同的应用程序可能会有不同的调用方式和接口设计,很难在不同的应用之间复用。 参考资料 - 实操干货!MCP全解析,一步步教你借助第三方MCP Server开发Agent - 从0手撕代码搭建MCP Client与Server!详解DeepSeek、ollama、vLLM接入MCP实战!_java_赋范大模型技术社区-DeepSeek技术社区
SD卡插入检测后的完整初始化流程解析
本文对SD卡插入后,在SD主控和卡之间的完整初始化流程进行完整的分析和解释:对于一个支持SD卡的消费类电子产品而言,当SD卡插入该产品的SD卡插槽以后,SD主控与SD卡之间的完整初始化通信流程,如何通过这个初始化的设置流程做好进一步读写SD卡的准备。 - 本文仅关注SD卡的SD模式,不考虑SPI模式。 从SD卡插入卡槽,到最后主控对SD卡进行数据内容的读写之间,主要存在以下五个阶段。后续部分对这五个阶段进行详细的解释说明。 - 物理检测与上电阶段 - 卡识别初始化阶段(识别模式) - 卡识别配置阶段 - 数据传输模式准备 - 数据通信阶段 对于本文的理解,需要首先建立SD卡与其主控之间通过CMD引脚在两者之间进行的CMD及其响应消息通信数据的理解,这方面可以参考另外一篇笔记:[[SD卡的CMD命令及其响应消息数据结构]]。 下图是从SD协议文档中对于UHS-I类型的SD卡进行初始化设置的整体流程图,本文的叙述框架就是对这个流程图的具体执行过程进行详细的总结和说明。 !image.png 1. 物理检测与上电阶段 初始未插卡的状态下,由SD主控进行控制,SD引脚上的电源引脚未使能,CLK无时钟输出。在使用CD/DAT3引脚检测卡插入状态的设计中,此时CD引脚上拉为High电平。 当SD卡插入以后,CD引脚拉低触发SD卡的检测中断。 - 此时主控检测到SD卡插入后,控制SD引脚的电源引脚使能,给SD卡供电(默认给SD卡提供3.3V电源供应)。 - 同时,SD引脚开始输出慢速时钟用于对卡访问进行初始化,SD协议要求初始时钟
SD通信命令协议解析之CMD6
在SD协议中,SD主控与SD卡之间交互流程中的CMD6是一个相对比较复杂的命令。其复杂性体现在: - 同一个命令既可以实现对SD卡支持特性的读取,也可以对其进行设置。 - CMD6命令的执行及其从SD卡上读取的响应消息,双方不仅在SD的CMD pin上通信,也涉及到了在DAT引脚上传输部分数据,而其他CMD命令的交互执行基本上都只涉及到CMD pin。 - CMD6命令中所支持的功能比较多,包含多个function group,每个function group又包含多个function mode。 所以,本篇比较在较为深入的学习SD物理层协议规范文件(V6.00版本)的基础上,详细的整理出来CMD6命令交互的流程。 CMD6执行的前提就是,先要通过CMD7指令选中SD卡,让SD卡进入传输状态Transfer Mode。 CMD6命令的交互数据结构 CMD6命令的整体数据结构仍然遵守[[SD卡的CMD命令及其响应消息数据结构]]中对于CMD命令数据结构的定义,CMD Command Index为0x06,Argument的32bit则如下图所示。 - 最高的31bit用于表示该命令是要验证请求设置的数据对于SD卡是否合法,还是要把参数指定的function mode设置进去。 - bit30-bit24为预留位,全部为0。 - bit23-bit0的24个bit,以4个bit为一组,分为6个function group,对应于各个function group的设置参数,其中实际上只用到了前面4个group,group 5和6预留给未来的新group。 !image.png 而Group 1-4这四个Group中,每个function可设置的function mode的值对应于下表所示。 !image.png - 4个function group的设置参数各自独立,分别占用其中的4个bit,所以可以在一条CMD6指令中同时设置或者检查多个function group的设置,例如可同时设置总线速度和驱动强度。 - 对于每个function group而言,同一时间只能选择一个function mode。function mode设置为0表示使用默认值,设置为0xF表示继续使用当前值。 - 每个function group的function 0是其上电后默认的配置,例如默认的SD卡读写总线时钟速度(Access Mode)为SDR12,也就是25MHz。 当处于Transfer Mode的SD卡收到以上CMD6消息时,SD卡会在CMD Pin上返回一个R1消息用于表示自己当前的内部工作状态,以及在DAT数据总线上返回一个512bit的状态消息(对于SD卡而言,就是一个标准的块读操作)。 CMD6命令的执行流程 如上所述,CMD6命令的执行可以分为Check(Mode 0)和Switch(Mode 1)两种操作模式。 - 其中Check模式用于检查SD卡是否可以支持CMD6 Argument中所指定的function mode。 - Switch模式则用于把CMD6 Argument中所指定的function mode设置到SD卡中。 CMD6 Check Operation 对于SD主控而言,在CMD6的Argument设置中,bit31设置为0表示该命令是一个check操作,并且在各个function group中设置要查询的function mode,通过这个命令查询SD卡是否支持指定的function mode。 当SD卡收到以上CMD6命令以后,从CMD pin上返回一个R1响应消息答复自己的当前工作状态,然后在DAT总线上发出一个512bit的信息结构,其中包含有SD卡是否支持指定function mode的信息(在512bit信息结构的bit399到bit376之间),如果支持就返回这个function mode的index,如果不支持就返回0xF。 !image.png CMD6 Switch Operation 对于SD主控的Switch操作而言,与上面的Check操作类似。在CMD6的Argument设置中,bit31设置为1表示该命令是一个switch操作,然后在各个function group中设置要查询的function mode,通过这个命令来向SD卡设置指定的function mode。 当SD卡收到以上CMD6命令以后,从CMD pin上返回一个R1响应消息答复自己的当前工作状态,然后在DAT总线上发出一个512bit的信息结构,其中包含有SD卡是否支持指定function mode的信息(在512bit信息结构的bit399到bit376之间),如果支持就返回这个function mode的index,如果不支持就返回0xF。此外,在这个512bit的信息结构发出的8个clk以后,CLK以及DAT的总线工作时序就切换为function mode所设置的工作模式。 !image.png
SD卡与SDIO接口、eMMC之间的联系与区别
工作中接触到的主控芯片中,在其支持的SD主控及其接口的支持上,大概率都会提到该SD主控可以支持SD协议、SDIO协议以及eMMC协议规范的不同版本。例如下图是君正T41的SD主控对于这些不同协议规范版本的支持情况: !image.png 那么SD主控所支持的SD卡、SDIO以及eMMC等接口和规范协议之间的连续和区别是什么呢? SD卡与SDIO接口的联系与区别 SDIO(Secure Digital Input Output)和SD卡(Secure Digital Memory Card)同属于SD(Secure Digital)的标准体系,但二者的设计目标与功能实现有明显差异:SD卡是存储类的专用设备,而SDIO则为泛用型外设利用相同的SD接口以及类似的SD协议框架提供了高速扩展接口。简单的说,SDIO和SD卡两者在硬件物理层上完全兼容,但是具体的通信协议上各自发展出来自己的体系。 硬件物理层的相互兼容包括: - 相同的引脚定义:SDIO设备与SD卡使用相同的物理接口(也就是9引脚 micro/SD接口)。 - 电气规范一致:SDIO设备和接口均遵循SD协会定义的电压范围(3.3V或1.8V UHS模式)与信号电平标准。 双方在协议层方面的差异: - SD命令集分支:SD卡仅实现SD存储协议(侧重于块读写指令),而SDIO则扩展了SDIO协议用于支持通用设备的控制。 - 初始化流程:SD主控制器通过发送CMD5命令检测来插入设备是存储卡还是SDIO外设。 因此SD卡(存储)与SDIO(扩展外设)规范协议栈两者共享物理层,但核心功能与技术规范的演进方向相互独立发展,因此SD卡与SDIO的标准规范是独立的。这就是为什么大多数主控SOC在SD控制器的规格中都分别给出了SD和SDIO的规范支持版本。以下是SDIO协议规范的演进以及各个版本的重点支持特性: !image.png SD卡与eMMC之间的联系与区别 SD卡和eMMC都是利用SD接口来解决存储存储的问题,不同的只是SD卡针对的应用场合是可移动、可插拔的使用场景,而eMMC针对的则是嵌入式焊接的方式固定到产品中的应用场景。 - 也就是说,SD卡是可以在产品的SD卡槽中可插拔使用,可以更换;而eMMC是直接焊接在产品的电路板上的,不可更换。但是两者都是通过SD接口连接到主控芯片上。 两者的技术根源类似(均衍生自MMC协议),所以大多数主控的SD控制都能够同时兼容SD卡、SDIO以及eMMC,但是SD卡和eMMC在使用方式上的差异还是会导致两者在物理层和驱动命令集方面的差异: - 在物理层的电气信号上,SD卡要求更高的ESD防护(因为支持可插拔),而eMMC则依赖PCB信号的完整性设计。 - 两者支持的SD总线的时钟和规范也有差异,例如eMMC 5.1规范的HS400可支持200MHz DDR双边沿采样数据。 - SD协议通信的命令集方面,两者也有差异,并且包含一些各自独有的命令集。 最重要的是,SD卡和eMMC协议背后的组织不同。SD卡以及SDIO的相关协议规范的组织是SD协会(SD Association),而eMMC的协议规范则是由JEDEC来制定和维护。SD协会重点兼容历史设备(向后兼容SDHC插槽),而JEDEC则推动eMMC与UFS接轨(为UFS铺路),因此随着规范的演进,两者之间的差异会越来越大。
SD卡的CMD命令及其响应消息数据结构
众所周知,在SD卡与其控制器之间的SD接口上,有一个专门的CMD引脚。CMD与CLK引脚配合,在SD卡和其主控之间进行控制和配置命令的传输。每次命令模式的通信,SD主控向卡在CMD引脚上发出一个CMD命令结构,根据CMD命令的不同由SD卡给出该命令的答复消息Rx。 - 当然对于CMD6和CMD16等少数命令而言,除了在CMD引脚上,SD卡会给出响应消息以外,在DAT总线上也会有一些通信活动。 CMD命令结构 所有Native模式(即非SPI模式)的SD卡命令都采用相同的48位(6字节)固定长度的传输结构: !image.png - 起始位(Start Bit):固定为0(低电平),占1个CLK周期。 - CMD命令索引(Command Index):占据6个bit的二进制值,用于定义命令类型(如CMD0=0x00, CMD8=0x08),其编码范围为0-63之间。 - 参数(Argument):固定占据32位的CMD参数,在进行传输时MSB(bit31)优先传输,不同命令之间的参数结构差异极大。 - CRC7校验:7位循环冗余校验码,CRC运算覆盖命令索引和参数字段 - 结束位(End Bit):固定为1(高电平),占1个CLK周期 响应消息Rx 而当SD卡接收到以上的CMD指令后,通过同样CMD引脚配合CLK的跳变,根据之前CMD的不同向SD主控发出不同的响应消息。 - 所有从SD卡到主控的命令响应均通过CMD引脚传输,单向串行通信。 - 所有响应均以Start Bit (0)开头,以End Bit (1)结束。这一点与CMD命令的结构类似。 - 时序方面,响应数据的传输由主控控制的CLK信号同步,采样点在CLK下降沿。 - SD卡与主控之间的通信中,针对各种CMD命令,SD卡所发回的响应消息主要有R1,R1b,R2,R3,R6,R7这几种。后续在初始化流程中对各个响应消息的数据结构进行说明。 R1:普通应答消息 下图是R1响应消息的数据结构。整个响应消息长度为48bit,其中Command Index需要与这个响应消息前面的CMD命令的CMD Index相同,Card Index部分则包含一个32位的SD卡内部状态,这个SD卡状态在SD卡内部维护。 !image.png R1b:带busy bit的普通应答消息 R1b的消息结构与R1完全相同。只不过部分CMD命令要求SD卡响应R1消息的时候,同时在DAT0引脚上提供一个busy位,例如CMD12,在SD卡接收到这个命令以后,执行操作处于busy状态时,就会把DAT0拉低来提供这个busy状态信息给Host。 R2:CID,CSD寄存器 当SD卡收到CMD2和CMD10的时候,通过这个响应消息发回CID寄存器;当SD卡收到CMD9的时候,通过这个响应消息发回CSD寄存器。下图是R2消息的数据结构: !image.png - 注意,R2的总长度是136bit,只有CID和CSD的bit127到bit1会包含在R2消息中,最后的bit0会被最后的end bit 1替代。 R3:OCR寄存器 R3响应消息的长度为固定的48bit,用于响应ACMD41命令,向SD主控返回SD卡OCR寄存器的值。 !image.png R6:响应RCA地址 R6响应消息固定长度48bit,用于响应CMD3。其中Argument的高16位为SD卡自己生成的RCA地址,低16bit则是SD卡当前的部分状态位。 !image.png R7:卡接口状态 R7实际上就是当卡收到CMD8的时候,向SD主控返回卡支持的电压范围。R7响应消息的长度固定为48bit,其中最主要的就是bit19到bit16之间的Voltage Accepted的四个bit。 !image.png ACMD SD卡与SD主控之间的命令通信,除了以上的CMD命令及其响应消息以外,还有一个ACMD命令。所谓的ACMD命令,就是Appilication CMD即应用模式CMD。SD协议中增加ACMD的原因主要是: - CMD结构中的CMD Index总共只有6bit,能够支持的命令有限,通过这个ACMD模式可以在当前命令数据结构的条件下扩展命令的功能。 - 对SD命令进行分层,CMD负责处理硬件方面的操作,ACMD负责处理应用层面的功能。 在具体的ACMD通信流程上,ACMD的每次通信,需要先发出一个CMD55指令,要求SD卡进入应用模式,SD卡返回一个R1响应消息,在这个响应消息中用APP_CMD状态表示自己处于等待接收ACMD命令的状态中;SD主控接着发送ACMD命令,SD卡收到后,再按照ACMD命令要求返回与之对应的响应消息。每个ACMD命令的通信流程都如下所示: 主控发出ACMD命令后,从SD卡读到的响应消息也是以上所总结出来的R1-R7的这几个消息。
基于多模态大模型的HTTP API实现图像识别的功能(Python+C)
在之前的笔记中,通过在Python中利用OpenAI SDK访问月之暗面MoonShot的Kimi API,实现了一个单词对话和多轮对话的功能:[[基于Python快速实现与Kimi的AI对话]]。 本篇笔记在以上笔记的基础上,仍然利用OpenAI的API,访问Kimi多模态模型实现图片中对象识别的功能,同时使用Python和C代码实现并提供案例解析。能够利用C语言来访问多模态大模型开放出来的HTTP API接口,也就能够在低成本的MCU处理器上,基于合理的提示词设计,实现需要大模型服务支持才能提供出来的功能, 该例子的功能需求很简单,就是给大语言模型上传一张照片,请大模型给出照片中检测到的对象的描述。本案例使用在网上搜索到的一张小鸟的照片。 !image.png > 相比于与大模型之间进行的简单文本对话,要使用多模态大模型来实现图像识别的功能,最大的不同,在于客户端发给多模态大模型的HTTP请求,需要把图片文件进行base64编码后作为附件,与文本对话的提示词一起上传上去。 多模态大模型进行图像识别的Python实现 以下是基于Kimi多模态大模型进行图像识别的Python实现。需要注意的是: - 代码运行需要先在环境变量中设置MOONSHOT_API_KEY,把自己的API Key设置进去,具体可以参考[[基于Python快速实现与Kimi的AI对话]]。 - 要能够对上传的照片附件中所包含的对象进行识别,需要选择能够支持多模态的大模型,否则会提示模型不支持图像识别的报错信息。对于Kimi而言,此时应该设置的多模态大模型节点应该是moonshot-v1-8k-vision-preview。 可参考代码中的注释对于其运行流程进行详细的理解: 执行以上代码后,大模型返回的信息如下: 多模态大模型进行图像识别的C实现 以上利用Python和Kimi多模态大模型,基于HTTP API的方式可以很方便的实现图像识别的功能。但是大多数低成本的MCU和SOC上是无法运行Python的,所以如果要想在这类处理器上利用大模型来扩展自己的能力,就需要用C语言来实现相同的功能逻辑,这就是这里需要用C语言来重新实现以上功能的原因所在。 以下是使用Kimi多模态大模型进行图像识别功能的C语言代码实现: 可以看到,C语言的实现相对就要复杂很多,以上代码中自行实现了json的解析和base64编码,同时依赖libcurl来实现与Kimi Web API服务器之间的HTTP通信。因此,在编译时应该要链接libcurl库: 同样的,编译后生成的image-recognition要能够正常运行,也需要在Linux系统中设置MOONSHOT_API_KEY环境变量:
基于Python快速实现与Kimi的AI对话
准备工作 对于基于大语言模型的AI应用程序开发而言,用户的应用程序与Kimi或者OpenAI这类大语言模型之间基本上都是使用标准的HTTP接口进行请求,Kimi和OpenAI服务器针对用户应用程序提出的问题进行答复,答复的结果同样封装在HTTP的reponse message中传回给用户应用程序,用户应用程序对结果进行解析后呈现给用户,或者调用其他更加智能化的功能处理(例如AI Agent)。 在此选择国内大语言模型开发商月之暗面Moonshot(也就是Kimi)为例进行与LLM Server之间的AI应用程序交互逻辑的学习和总结。使用Kimi的原因在于: - 在deepseek之前,Kimi一直是我本人稳定使用的AI工具,其稳定性和输出结果的质量,相比于国内的其他大模型而言一直是名列前茅的。 - Moonshot为每个注册用户提供了15元的预充值费用,这个费用对于通过API进行测试开发而言,基本上是够用了。 对于开发基于Moonshot的AI应用程序而言,提前要做的准备工作主要包括两个部分: - 按照Moonshot的要求安装python及其Openai library。 - 申请访问Moonshot服务器的API Key,并且为安全起见以环境变量的方式配置到自己的开发机中。 安装Python及其openai library 在进行以下的调试和开发之前,首先要在本地开发环境中安装python和基于python的openai library: - Moonshot API的使用直接兼容了OpenAI的API和library,所以可以使用openai的python library,修改对接的LLM节点,与Moonshot的server进行通信交互。这样对于AI应用程序开发而言,就可以在很大程度上减少对接不同LLM Server的工作量,算是一个很取巧的设计。 - 与Moonshot Server的对接,要求python版本在3.7.1版本以上,openai library的版本在1.0.0以上。 访问python的官网下载自己系统对应的python:Download Python | Python.org,当前的最新版本是3.13.2。 Python安装以后,直接在系统的终端中输入以下命令安装openai library:pip install openai 以上完成后在终端中查询当前的python环境以及openai library版本是否符合以上要求: !image.png Moonshot API Key的申请与配置 访问Moonshot的用户中心进行API Key的申请:Moonshot AI - 开放平台。点击新建按钮申请API Key,API Key的名称按照自己的使用情况随意填写即可,项目选择默认的default即可,确认后即可生成API Key。 - 需要注意的是,因为API Key涉及到对Moonshot Server和API的访问所产生的费用,一旦泄露出去被滥用后会产生费用。所以为了保密和安全起见,生成的API Key只有在这个时候才能拷贝保存下来,所以务必在此时把API Key拷贝出来并保存在一个安全的地方。 ![[基于Python快速实现与Kimi的AI对话-Moonshot-Key.png]] 为了后续更加方便并且安全的使用,建议把以上API Key以环境变量的方式保存在一个名称为MOONSHOT_API_KEY的环境变量中。 单轮对话通信功能的实现 从通信和代码实现的逻辑上讲,对于单轮对话通信而言,AI应用程序客户端与Moonshot Server之间的通信流程非常简单,就是应用程序把需要向Moonshot Server查询的问题封装在一个HTTP Request消息中,Server收到后会把答复包含在一个HTTP Response消息中,回复给应用程序客户端。应用程序客户端对其消息进行解析后显示出来。无论是Request还是Response消息,都是封装在Json结构的文本内容。 代码具体的实现流程: - 基于OpenAI library创建一个连接Moonshot Server的client,在其中要指定正确的API Key和Server URL; - 把要向Server查询的问题文本字符串按照role+content的格式整理在json结构中; - 基于前面的client和整理好的查询问题json结构体,调用client.chat.completions.create发起与Moonshot Server之间的通信; - 应用程序对Moonshot Server的答复进行解析,正确的情况下显示出来。 以下代码的功能就是实现与Moonshot Server之间的一轮对话,查询当前日期以及截至当前日期中国的人口数量,同时在收到Moonshot Server答复以后,把这个答复信息保存在一个json文本文件中: 值得一提的是以上代码中用messages所包含的请求消息,在与Moonshot Server通信所发出的问题咨询中,默认包含了三种以下角色(role)。如果对prompt engineering有一点了解的话,可以更容易理解各个角色的含义。 - system role:这部分通过文本字符串描述信息定义清楚对于Server角色的定义,如果Server有一个清楚的身份和角色定义,就有可能给出更加准确、帮助性更强的答复。当然这部分是可选的。 - user role:这部分就是用户通过文本字符串形式提交给Server的问题。 - assistant role:这部分是Server针对用户所提出问题给出的答复,同样是文本字符串形式。 执行以上代码以后,在json中所保存的Server响应消息如下: 可以看到,现在测试使用的Moonshot server返回的时间信息是错误的,而且多次调用返回的时间还不一样,可见在应用代码中不能依赖于该服务返回对时间日期要求较高的响应信息。 多轮交互式对话通信功能的实现 以上实现了应用程序与Server之间进行单轮对话的功能。那么如果要实现多轮对话呢?众所周知,HTTP协议是无状态、无记忆的协议,所以服务器端既不会维护通信的连接状态,也不会缓存多轮对话的上下文,因此多轮对话与单轮对话最大的不同,就是要在客户端中自行管理和维护好通话的上下文信息,把问题背景相关的上下文信息全部汇总后发给Server进行问题查询。Server收到后对于多轮通话的内容进行学习和推理,从而给出针对最新问题的答复。 以下代码简单的演示了在多轮会话通信中,客户端如何汇总和整理多轮对话的信息,并且发送给Server进行最新问题的查询。 结语 - 本质上,基于大语言模型的AI应用程序的开发,就是使用HTTP协议与LLM Server之间进行的交互。因为HTTP协议本身是无状态无记忆的,所以每一轮HTTP通信,客户端也就是AI应用程序端都需要把历史会话信息完整的发送给LLM Server进行解析、理解并得到答案。所以,对于AI应用程序的开发而言,既可以采用以上基于Python的OpenAI SDK与LLM Server进行交互,也可以采用任意的HTTP library和框架(例如Kimi的开放平台网站上同样提供了基于Curl的HTTP通信交互的流程参考代码)来实现与LLM Server的通信和交互。 - 总的来说,因为大语言模型服务器使用HTTP协议对外释放API,那么对通过该协议来访问LLM Server的流程开发就非常简单,接下来就是要发挥想象力,根据自己产品面对的应用场景和问题,设计合理的提示词(Prompt Engineering),然后就可以利用LLM Server的强大文本推理和生成能力,实现可以解决问题的人工智能应用。 参考资料 - 基本信息 - Moonshot AI 开放平台
SD卡的分类及其各种规格参数总结
SD卡的基本规格总结 尺寸类型 - SD:32×24×2.1mm(全尺寸),基本上以及很少使用了 - microSD:11×15×1.0mm,目前应用的主流 引脚触点差异: - UHS-I及其之前:9个触点(VCC,两个VSS,CLK,CMD,DAT3-DAT0),仍然是目前应用的主流 - UHS-II/UHS-III:17个触点(新增差分对) - SD Express:保留传统触点+隐式PCIe通道设计 电压兼容性 - 普通SD卡:仅支持3.3V - UHS卡:可支持3.3V/1.8V双电压(需主控匹配,双方协商电压切换) !image.png - 可以看到,SD卡除了标准的SD模式以外,还能够支持SPI Mode,在这种情况下,数据线从SD模式的四根(DAT3-DAT0)变成了一根。 SD卡的分类 当前SD卡的标准体系较为复杂,涉及到存储容量、总线协议、速度等级等多个维度的定义。因此也就有多个不同维度的SD卡分类规则。 基于容量进行分类 从SD卡的存储容量角度上,可以分为以下四类,分别在不同的SD规范中定义。需要注意的是因为FAT3文件系统支持的文件系统大小以及单个文件大小的限制均比较小,所以SDXC卡默认采用exFAT文件系统。 !image.png - 目前应用的主流是SDHC和SDXC,SDSC因为容量太小,已经被淘汰了。 - 其实无论是对于开发者还是用户而言,都只需要关注自己产品应用的存储容量就好,不需要关注究竟属于哪个容量分类。 基于总线接口及总线速度进行分类 从SD卡所连接的系统总线接口以及总线读写速度的角度,SD卡可以分为以下分类。对于开发者而言,需要关注主控芯片的SD接口规范,这一点限定了SDIO接口的时钟、电压、引脚分布等。 !image.png 关于SD卡的引脚结构,UHS-I及其之前的SD卡规范使用传统的9个引脚:CLK,CMD,DAT3-DAT0(其中DAT3也用于卡检测的CD引脚),VCC,两个VSS。从UHS-II开始,在传统的SD卡接口规范的基础上增加了两组LVDS差分对,共8个引脚,因此新的UHS-II/III接口和卡共包含17个接口。但是,新的UHS-II/III卡插入旧的SD卡插槽时,新增的差分引脚无电气连接,对于SD卡的读写访问会自动回退至UHS-I模式或更低,这一点有点像USB TypeC接口对之前USB2.0接口的兼容一样。下图是UHS-II/III卡的引脚结构示意图: !image.png 关于SD卡所支持的电压,在SD2.0及其之前的规范,SD接口的主机和SD卡只支持3.3V单电压模式,不支持电压的动态切换;但是从SD3.0也就是UHS-I开始,SD主机接口以及SD卡均应支持3.3V和1.8V双电压模式,否则无法通过UHS认证。在支持双电压的情况下,主机在给SD卡初始上电后首先提供3.3V电压,然后通过CMD8+ACMD41+CMD11的协议序列在双方之间交换双电压的支持能力,根据交互信息决定是否切换电压到1.8V。 关于通信的单端SDR和双端DDR模式。在UHS-I之前的规范中,SD卡只能支持单端的SDR通信,UHS-I规范则引入了可选的DDR模式,可以支持在一个时钟周期发送两次数据,这样相同的时钟周期下传输数据可以翻倍。对于UHS-I而言,该规范可以支持SDR12、SDR25、SDR50、SDR104以及DDR50这几种模式,其中前四种是单端SDR模式,只不过是在之前SD规范的基础上进一步提升了时钟频率,时钟最高可以达到208MHz,因此最高可以提供104MB/s理论带宽;而DDR50则是双边沿触发发送数据,DDR模式下最高时钟50MHz,可以提供最高50MB/s的理论带宽。当然,能否支持UHS-I的高规格时钟速度以及DDR模式,需要主控SD控制器与SD卡之间进行协商,只有双方都支持的情况下才能使用。 > SD 2.0 High Speed以及UHS-I的单端SDR是目前多数消费类产品应用中的主流。 除了以上基于传统SD接口的总线接口以外,目前还出现了基于PCIe总线通信规范的SD Express总线接口,不过这种接口的SD卡以及主控目前在产品开发中还比较少见: !image.png 基于SD卡的读写速度进行分类 相比于前面的SD接口的速度而言,SD读的读写速度的分类和等级就更加复杂了。首先是按照C开头进行的基本速度等级: !image.png 接下来是UHS速度等级,跟C开头的速度等级一样,主要关注的仍然是大块数据的写入速度,既然是同样的评估标准,为什么不继续用C? !image.png 还有专门针对视频文件写入应用的V速度等级。跟C/U开头的速度等级有啥区别? !image.png 最后还有一个针对手机APP应用随机访问速度的A速度等级: !image.png 无论如何,对于包含SD卡产品的开发者而言,重点只需要关注自己的主控SD控制器的规范版本,按照规范版本来实现具体的电路和驱动程序/功能即可,不太需要关注这些不同的SD卡速度等级。而对于普通用户而言,则需要根据自己的产品应用需求,选择符合产品应用的SD卡速度等级,当然选择的SD卡速度等级需要与其主控能够支持的SD卡规范相匹配才能发挥出来最佳的性能。 容量、接口和速度等级分类的例子 下图是参考文档1中所提供的一个真实SD卡标注信息的说明,结合以上的理论知识应该是可以很好的理解了: !image.png SD卡标准规范版本的演进 以下是SD卡各个主要版本的协议规范的发布时间,以及各版本新增加的主要特性。结合以上对于SD卡进行不同分类标准的说明可以更容易理解。 !image.png 参考资料 - 存储印象:浅谈存储卡UHS-I、UHS-II、UHS-III总线标准