LLM本地知识库问答系统(一):使用LangChain和LlamaIndex从零构建PDF聊天机器人指南

news2024/12/29 10:52:50

       随着大型语言模型(LLM)(如ChatGPT和GPT-4)的兴起,现在比以往任何时候都更容易构建比普通熊更智能的智能聊天机器人,并且可以浏览堆积如山的文档,为您的输入提供准确的响应。

       在本系列中,我们将探索如何使用pre-trained的LLM创建一个聊天机器人,该聊天机器人可以分析、总结PDF文档并回答问题,使其成为企业和个人都非常有用的工具。无论您是想构建个人助理、定制聊天机器人还是自动文档分析系统,本系列都将为您提供构建自己的LLM聊天机器人所需的知识。所以,让我们用LangChain和LlamaIndex深入LLM和聊天机器人的世界吧!

创建什么?

       使用ChatGPT作为助手来帮助用户基于多个文档进行问答系统搭建的想法是非常酷。起初,我们的想法是用特定的数据对模型进行微调,以实现这一目标,但这可能成本高昂,并且需要庞大的数据集。此外,对模型进行微调只能教会它一项新技能,而不能提供有关文档的完整信息。

      另一种方法是使用提示工程在(多)文档QA的提示中提供上下文。然而,GPT模型的注意力范围有限,将上下文传递给API也可能很昂贵,尤其是在处理大量客户反馈电子邮件和产品文档时。

那么如何创建呢?

以下是实现这些目标的具体步骤:

  1. 首先加载文档(PDF、HTML、文本、数据库等);
  2. 然后将数据分割成块,并对这些块建立embedding索引,这样方便使用向量检索工具进行语义搜索;
  3. 对于每个问题,通过搜索索引和embedding数据来获取与问题相关的信息;
  4. 将问题和相关数据输入到LLM模型中。在这个系列中使用OpenAI的LLM;

       实现上述过程主要的两个框架,分别是:Langchain(https://python.langchain.com/en/latest/)和LLamaIndex(https://gpt-index.readthedocs.io/en/latest/)

我们如何开始

下面是使用Langchain和ChatGPT实现PDF问答系统的大致框架:

      在本文,不会详细介绍Langchain或LLamaIndex具体原理和实现细节,后面会专门介绍。本文主要介绍如下内容:

  • 基于Langchain的生成式问答
  • LLamaIndex生成式问答
  • 奖金部分。

准备工作

     首先我们需要在OPenAI官网获取API秘钥,具体步骤是:转到https://platform.openai.com,登录或注册新帐户→ 点击您的个人资料→ 查看API密钥并创建新的密钥,如下图所示:

Note:实际上,我们可以使用其他LLM模型。

       下面准备安装相关的python包,需要保证Python>=3.7来进行操作,然后创建一个虚拟环境并安装以下Python库:

## to create virtual environment$ python3 -m venv llm_app_env## on MacOS or Linux$ source llm_app_env/bin/activate## on Window$ llm_app_env\Scripts\activate.bat## then install the following libraries.openai[embeddings]==0.27.6langchain==0.0.155pypdf==3.8.1tiktoken==0.3.3faiss-cpu==1.7.4unstructured==0.6.2chromadb==0.3.21llama-index==0.6.1jupyterlab

Langchain介绍

       LangChain是一个强大的开源工具,可以轻松地与大型语言模型交互并构建应用程序。将其视为一个中间人,将您的应用程序连接到广泛的LLM提供商,如OpenAI、Cohere、Huggingface、Azure OpenAI等。

       然而,LangChain不仅仅是一个访问预训练语言模型的工具,它还提供了许多有用的特性和功能,允许您构建自定义应用程序和工具。例如:

  • 使用自己的文档进行问答和文本摘要
  • 处理内存和具有有限令牌问题的长文档。
  • 与OpenAI ChatGPT Retriever插件的出色集成
  • 多个链来处理您定义的问题,或者使用Agent将其提升。
  • 还有更多。

       Langchain是一个伟大的框架,它使人工智能应用程序的创建能力现在掌握在您手中。更令人惊讶的是,它是开源的,所以你知道它掌握在优秀社区的手中。

下面使用Langchain来搭建一个问答系统:

设置OpenAI API密钥

import loggingimport sysimport osos.environ["OPENAI_API_KEY"] = "<YOUR_OPENAI_API_KEY>"

加载并拆分数据

## load the PDF using pypdffrom langchain.document_loaders import PyPDFLoaderfrom langchain.text_splitter import RecursiveCharacterTextSplitter# load the dataloader = PyPDFLoader('../notebooks/documents/Apple-Financial-Report-Q1-2022.pdf')# the 10k financial report are huge, we will need to split the doc into multiple chunk.# This text splitter is the recommended one for generic text. It is parameterized by a list of characters. # It tries to split on them in order until the chunks are small enough.text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=0)data = loader.load()texts = text_splitter.split_documents(data)# view the first chunktexts[0]

简单问答

       我们将使用OpenAI作为LLM提供者,因此使用OpenAI Embedding,但请注意,OpenAI Embedding API使用的是“text-davinci-003”模型(定价参考:https://openai.com/pricing)

       接下来,我们将导入Chroma,Chroma是嵌入数据库,不像传统的SQL数据库,也不像你通常使用的NoSQL数据库。它嵌入了数据库,使构建LLM应用程序变得容易。

通过Chroma官方网站

       我们的文档以文本的形式表示,因此很难根据问题找到相关信息。假设你需要在1000页中找到苹果上一季度的收入,并将收入与前几年进行比较。这可能需要多大的挑战性和耗时?因此,为了让我们的搜索更容易,我们首先需要以数字格式转换或表示单词或短语,这些单词或短语可以用作机器学习模型的输入。换句话说,帮助机器理解文本。embeddings将每个单词或短语映射到实数向量,通常具有数百个维度,使得相似的单词或短语被映射到嵌入空间中的相似向量。

       使用embeddings的主要优点之一是,它们可以捕捉单词或短语之间的语义和句法关系。例如,在嵌入空间中,“国王”和“王后”的向量比“苹果”的向量更接近,因为它们在语义上与王室头衔相关。

       因此,嵌入数据库正是这样做的。它将把所有embeddings数据存储在数据库中,然后给我们提供非常多的索引,使我们能够执行类似数据检索的操作,并以可扩展的风格进行操作。如果你需要得到之前关于寻找苹果上季度收入的问题的答案,我们首先需要在嵌入Chroma等数据库的基础上进行相似性搜索或语义搜索,以提取相关信息,并将这些信息提供给LLM模型来获得答案。

       听起来太复杂了!这就是Langchain拯救我们的地方,所有的艰苦工作都将在后台完成。Just do it!

# import Chroma and OpenAIEmbeddingsfrom langchain.vectorstores import Chromafrom langchain.embeddings.openai import OpenAIEmbeddings# initialize OpenAIEmbeddingembeddings = OpenAIEmbeddings(model='text-embedding-ada-002')# use Chroma to create in-memory embedding database from the docdocsearch = Chroma.from_documents(texts, embeddings,  metadatas=[{"source": str(i)} for i in range(len(texts))])## perform search based on the questionquery = "What is the operating income?"docs = docsearch.similarity_search(query)

       您可以看到,我们能够执行相似性搜索,从嵌入数据库中获取相关信息。

       现在,我们将使用Langchain的主要组件之一Chain将LLM提供程序合并到我们的代码中。请记住,本文的目的是建立问答机器人。因此,只需按照步骤进行操作,如果你很好奇,迫不及待地想了解更多细节,请随时访问Langchain的官方网站。瓦尔哈拉在等着你!!!!

Langchain提供了四种预先构建的问答Chain,具体如下:

  • 问答:load_qa_chain
  • 有来源问答:load_qa_with_sources_chain
  • 检索问题答案:RetrievalQA
  • 资源检索问答:RetrievalQAWithSourcesChain

      它们非常相似,RetrievalQA和RetrievalQAWithSourcesChain分别使用load_qa_chain和load_qa_with_sources_chain,唯一的区别是前两者将把所有嵌入都馈送到LLM中,而后两者只向LLM提供相关信息。我们可以使用前两个来首先提取相关信息,并仅将该信息提供给LLM。此外,前两个比后两个给了我们更多的灵活性。

下面的代码将演示我们是如何做到这一点的。

## importing necessary frameworkfrom langchain.chains.question_answering import load_qa_chainfrom langchain.chains.qa_with_sources import load_qa_with_sources_chainfrom langchain.chains import RetrievalQAfrom langchain.chains import RetrievalQAWithSourcesChainfrom langchain.chat_models import ChatOpenAI

现在我们将尝试4种不同的问答链

1.load_qa_chain

## use LLM to get answeringchain = load_qa_chain(ChatOpenAI(temperature=0.2,model_name='gpt-3.5-turbo'),                       chain_type="stuff")query = "What is the operating income?"chain.run(input_documents=docs, question=query)

2.load_qa_with_sources_chain

chain = load_qa_with_sources_chain(ChatOpenAI(temperature=0.2,model_name='gpt-3.5-turbo'),                                    chain_type="stuff")query = "What is the operating income?"chain({"input_documents": docs, "question": query}, return_only_outputs=True)

3.RetrievalQA

qa=RetrievalQA.from_chain_type(llm=ChatOpenAI(temperature=0.2,model_name='gpt-3.5-turbo'), chain_type="stuff",                                                 retriever=docsearch.as_retriever())query = "What is the operating income?"qa.run(query)

4.RetrievalQAWithSourcesChain

chain=RetrievalQAWithSourcesChain.from_chain_type(ChatOpenAI(temperature=0.2,model_name='gpt-3.5-turbo'), chain_type="stuff",                                                     retriever=docsearch.as_retriever())chain({"question": "What is the operating income?"}, return_only_outputs=True)

       上面的大部分代码都是非常基本的。我们只想在深入研究框架能提供什么之前完成这项工作。在此之前,让我们转到另一个可以与Langchain结合使用的框架,它将为您提供更多的能力来创建更好的LLM应用程序。

LLamaIndex介绍

       我首先介绍了Langchain,如果你花一些时间浏览它的官方文件,你可能会想“哇,没有什么好的东西可以超越这一点”。

       好吧,我的朋友们,有一个完整的SaaS行业建立在AWS之上,只是为了让您更好、更容易地使用AWS服务。其他LLM框架或LLM模型之间的竞争也是如此。我们生活在一个今天好的东西明天可能会过时的世界里。我个人认为Langchain将有一个非常光明的未来,并将成为用于构建LLM应用程序的核心技术。LLamIndex甚至让我们的工作变得更容易,它还通过处理一些痛苦的众所周知的问题和现有方法的局限性引入了自己的优势,这些问题和局限性将花费您的时间和手动操作,例如:

  • 文本块缺少全局上下文。通常,这个问题需要特定区块中索引之外的上下文。
  • 仔细调整前k/相似性得分阈值。如果值太小,就会错过上下文。让价值变得太大,成本/延迟可能会随着不相关的上下文而增加。
  • Embeddings并不总是为问题选择最相关的上下文。Embeddings本质上是在文本和上下文之间分别确定的。

       LLamaIndex(GPT索引)有自己的机制来处理这些限制。同样,这个博客的目的是完成这项工作。我不会详细介绍LLamaIndex是如何工作的(可以在官方文件上找到)。

那么LLM是什么

       一张由Jerry Liu抄写的羊皮纸,他在羊皮纸上公布了LlamaIndex,这是一个利用GPT的力量,利用询问者提供的知识,形成对询问的回复的门户网站。

       简而言之,LlamaIndex是通过以下步骤将LLM连接到用户来响应查询的另一种方式(类似于Langchain的方式):

  1. 加载文档(手动或通过数据加载程序)

  2. 将文档解析为节点

  3. 构造索引(从节点或文档)

  4. [可选,高级]在其他指数之上构建指数

  5. 查询索引

        简单来说,LlamaIndex将数据加载到文档对象中,并将其转换为索引。当您输入查询时,索引会将其发送到GPT提示符以生成响应,默认情况下使用OpenAI的text-davinci-003模型。尽管这个过程看起来很复杂,但只要几行代码就可以执行,您很快就会了解到这一点。

       您很快就会看到LLamaIndex是多么容易使用,因为它已经完成了所有的艰苦工作。你的工作只是阅读它的官方文件,学习不同类型的索引,然后分析你的应用程序需求,看看什么最适合你。当然,你的应用程序中可能需要越来越多复杂的东西,LLamaIndex的高级API可能不足以处理此类情况。这就是LLamaIndex可以与Langchain等其他工具集成以加快开发过程的便利之处。

让我们从设置简单索引和加载文档开始。

import loggingimport sys## setup your OpenAI Keyimport osos.environ["OPENAI_API_KEY"] = "<YOUR_OPENAI_API_KEY>"# enable logs to see what happen underneathlogging.basicConfig(stream=sys.stdout, level=logging.DEBUG)logging.getLogger().addHandler(logging.StreamHandler(stream=sys.stdout))

LlamaIndex的核心是指数,有多种类型的指数。

  • 列表索引
  • 矢量存储索引
  • 树索引
  • 关键字表索引
  • 图形索引
  • SQL索引。

       每个索引都有其独特的用途,具有不同的用途。好处是,您可以将索引堆叠在其他索引之上,这样做将使您的应用程序更强大,能够理解您的文档上下文和应用程序需求。

第一步是加载文档

from llama_index import GPTVectorStoreIndexfrom llama_index import download_loader# we will use this UnstructuredReader to read PDF fileUnstructuredReader = download_loader('UnstructuredReader', refresh_cache=True)loader = UnstructuredReader()# load the datadata = loader.load_data(f'../notebooks/documents/_10-Q-Q1-2022-(As-Filed).pdf', split_documents=False)

Document表示数据源的轻量级容器。可以选择下面两步骤之一:

  1. 将Document对象直接输入索引

  2. 首先,将文档转换为Node对象

       同样,本系列的目的是帮助您尽快构建第一个应用程序,因此我将直接讨论索引构建。我将在未来的一篇文章中介绍LLamaIndex的所有方面。

索引构建与查询

       我们现在可以在这些Document对象上建立一个索引。最简单的高级抽象是在索引初始化期间加载Document对象。

index = GPTVectorStoreIndex.from_documents(data)query_engine = index.as_query_engine()response = query_engine.query("What is the operating income?")print(response)

      根据您使用的索引,LlamaIndex可能会进行LLM调用以构建索引。GPTVvectorStoreIndex不会调用LLM,但GPTTreeStoreIndex会调用。

自定义LLM

      默认情况下,LlamaIndex使用OpenAI的text-davinci-003模型。在构造索引时,您可以选择使用另一个LLM。

from llama_index import LLMPredictor, PromptHelper, ServiceContextfrom langchain.chat_models import ChatOpenAI# define LLMllm_predictor = LLMPredictor(llm=ChatOpenAI(temperature=0.2,model_name='gpt-3.5-turbo'))# define prompt helper# set maximum input sizemax_input_size = 4096# set number of output tokensnum_output = 256# set maximum chunk overlapmax_chunk_overlap = 20prompt_helper = PromptHelper(max_input_size, num_output, max_chunk_overlap)service_context = ServiceContext.from_defaults(llm_predictor=llm_predictor, prompt_helper=prompt_helper)index = GPTVectorStoreIndex.from_documents(    documents,     service_context=service_context)query_engine = index.as_query_engine()response = query_engine.query("What is the operating income?")print(response)

       在短短几行代码中,我们就能够构建一个LLM应用程序,可以进行基本的问答。

       对于具有机器学习工程师或数据科学背景的人来说,这是相当简单明了的,但我相信对于一些新手来说,有时会觉得很困惑。我理解这一点,但很难在一篇帖子中解释所有内容。这篇文章的目的只是让你体验一下现在构建这样一个令人惊叹的LLM应用程序是多么容易。你现在可能有很多问题,甚至可能几行代码都不懂,但这没关系。

       您将很快收集组件的所有知识和方面,以构建自己的LLM应用程序。你可以等到我的下一篇文章,因为我将在下一篇中介绍LlamaIndex,或者如果你足够好奇,请通过阅读官方文件来做好准备。

       在此之前,我希望这篇文章能够帮助您扩展编码知识,并为LLM提供有价值的见解。记得保持好奇心,继续探索人工智能的广阔世界。

       祝贺你走到这一步!作为对您努力的奖励,这里有一段代码,您可以使用它与文档聊天

# do importsfrom langchain.agents import Toolfrom langchain.chains.conversation.memory import ConversationBufferMemoryfrom langchain.chat_models import ChatOpenAIfrom langchain.agents import initialize_agentfrom llama_index.langchain_helpers.agents import LlamaToolkit, create_llama_chat_agent, IndexToolConfigquery_engine = index.as_query_engine()tool_config = IndexToolConfig(    query_engine=query_engine,     name=f"Financial Report",    description=f"useful for when you want to answer queries about the Apple financial report",    tool_kwargs={"return_direct": True})toolkit = LlamaToolkit(    index_configs=[tool_config])memory = ConversationBufferMemory(memory_key="chat_history")llm=ChatOpenAI(temperature=0.2,model_name='gpt-3.5-turbo')agent_chain = create_llama_chat_agent(    toolkit,    llm,    memory=memory,    verbose=True)while True:    text_input = input("User: ")    response = agent_chain.run(input=text_input)    print(f'Agent: {response}')

YouTube视频结果展示地址:https://youtu.be/FuKFjNNbSVM

参考文献:

[1] https://langchain.readthedocs.io/en/latest/index.html(LangChain docs)

[2] https://langchain.readthedocs.io/en/latest/modules/memory.html#memory(LangChain Prompt Memory module)

[3] https://github.com/hwchase17/langchain(LangChain Repo)

[4] https://gpt-index.readthedocs.io/en/latest/index.html(LlamaIndex docs)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/937680.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于微信小程序的汽车租赁系统的设计与实现ljx7y

汽车租赁系统&#xff0c;主要包括管理员、用户二个权限角色&#xff0c;对于用户角色不同&#xff0c;所使用的功能模块相应不同。本文从管理员、用户的功能要求出发&#xff0c;汽车租赁系统系统中的功能模块主要是实现管理员后端&#xff1b;首页、个人中心、汽车品牌管理、…

LAMP介绍与配置

一.LAMP 1.1.LAMP架构的组成 CGI&#xff08;通用网关接口&#xff09;和FastCGI&#xff08;快速公共网关接口&#xff09;都是用于将Web服务器与后端应用程序&#xff08;如PHP、Python等&#xff09;进行交互的协议/接口。 特点 CGI FastCGI 运行方式 每个请求启动…

【C语言】2023.8.27C语言入学考试复盘总结

前言 本篇文章记录的是对于2023年8月27日的 C语言 的入学考试的整理总结 成绩&#xff1a;220/240 题目&#xff1a;9/12 错题整理 首先先对于我没做出来的三道题做一个整理 错题1&#xff1a;7-4 分段函数PLUS 题干 以下是一个二元分段函数&#xff0c;请你根据所给的函…

列式存储引擎-内核机制-Parquet格式

列式存储引擎-内核机制-Parquet格式 Parquet是一种开源的列式存储结构&#xff0c;广泛应用于大数据领域。 1、数据模型和schema Parquet继承了Protocol Buffer的数据模型。每个记录由一个或多个字段组成。每个字段可以是atomic字段或者group字段。Group字段包含嵌套的字段&…

软件工程(九) UML顺序-活动-状态-通信图

顺序图和后面的一些图,要求没有用例图和类图那么高,但仍然是比较重要的,我们也需要按程度去了解。 1、顺序图 顺序图(sequence diagram, 顺序图),顺序图是一种交互图(interaction diagram),它强调的是对象之间消息发送的顺序,同时显示对象之间的交互。 下面以一个简…

Python WEB框架之FastAPI

Python WEB框架之FastAPI 今天想记录一下最近项目上一直在用的Python框架——FastAPI。 个人认为&#xff0c;FastAPI是我目前接触到的Python最好用的WEB框架&#xff0c;没有之一。 之前也使用过像Django、Flask等框架&#xff0c;但是Django就用起来太重了&#xff0c;各种…

remove elements in c++

https://www.youtube.com/watch?vq5OfB6ZXT6E&listPL5jc9xFGsL8E_BJAbOw_DH6nWDxKtzBPA&index4

AUTOSAR规范与ECU软件开发(实践篇)6.7 服务软件组件与应用层软件组件端口连接

在生成了BSW模块的代码后, 切换到ISOLAR-A系统级设计界面,会发现产生一些基础软件模块的服务软件组件: BswM、 ComM、 Det和EcuM等, 如图6.60所示。 图6.60 生成了BSW后的服务软件组件 此时, 如果涉及服务软件组件与应用层软件组件的交互, 就需要为应用层软件组…

PowerDesigner学习笔记

备注&#xff1a;文章主要对概念数据模型进行深入分析 1.对各种模型图初步认识 1.1.概念数据模型 (CDM) (Conceptual Data Model) 对数据和信息进行建模&#xff0c;利用实体-关系图&#xff08;E-R图&#xff09;的形式组织数据&#xff0c;检验数据设计的有效性和合理性。 …

【leetcode 力扣刷题】字符串翻转合集(全部反转///部分反转)

字符串翻转合集 344. 反转字符串541. 反转字符串Ⅱ151. 反转字符串中的单词剑指 Offer 58 - II. 左旋转字符串反转单词思路循环挪动子串和子串的拼接 344. 反转字符串 题目链接&#xff1a;344. 反转字符串 题目内容&#xff1a; 题目中重点强调了必须原地修改输入数组&#…

Java --- 异常处理

目录 一、什么是异常 二、异常抛出机制 三、如何对待异常 四、 Java异常体系 4.1、Throwable 4.2、Error 4.2、Exception 4.2.1、编译时异常 4.2.2、运行时期异常 五、异常处理 5.1、捕获异常&#xff08;try-catch&#xff09; 5.1.2、catch中异常处理方式 …

顺序表链表OJ题(1)——【LeetCode】

W...Y的主页 &#x1f60a; 代码仓库分享 &#x1f495; 前言&#xff1a; 今天我们来回顾一下顺序表与链表&#xff0c;针对这一块我们也有许多OJ题目供大家参考。当我们学习完顺序表链表后避免不了一些习题的练习&#xff0c;这样才能巩固我们学习的内容。 话不多说&#xf…

C++:常成员变量、常成员函数、常对象

常成员变量: 1.用const修饰&#xff0c;可位于类型前后&#xff0c;若是成员变量类型为指针则只可位于类型后。 即&#xff1a;int *const p&#xff1b; 2.只能通过构造函数的初始化表对常成员变量进行初始化。 3.常成员所在类中的所有构造函数都必须对常成员变量初始化…

06.sqlite3学习——DQL(数据查询)(全)

目录 SQLite——DQL&#xff08;数据查询&#xff09; 数据集 select语句 条件查询 比较 确定范围 确定集合 like 查询记录 查询不重复的记录 排序和限制 排序 限制 聚合 聚合函数 语法 SQLite Group By详解 语法 实例 SQLite Having 子句 语法 实例 多…

浪潮云海护航省联社金融上云,“一云多芯”赋能数字农业

农村金融是现代金融体系的重要组成部分&#xff0c;是农业农村发展的重要支撑力量&#xff0c;而统管全省农商行及农信社的省级农村信用社联合社&#xff08;以下简称&#xff1a;省联社&#xff09;在我国金融系统中占据着举足轻重的地位。省联社通常采用“大平台小法人”的发…

Leetcode 2651.计算列车到站时间

给你一个正整数 arrivalTime 表示列车正点到站的时间&#xff08;单位&#xff1a;小时&#xff09;&#xff0c;另给你一个正整数 delayedTime 表示列车延误的小时数。 返回列车实际到站的时间。 注意&#xff0c;该问题中的时间采用 24 小时制。 示例 1&#xff1a; 输入&…

计算机系统真题

计算机系统真题 考点计算机系统存储体系磁盘调度算法 考点 计算机系统 PC找到指令&#xff0c;存储到IR中 根据ID分析指令的操作&#xff0c;并执行指令,AR访问操作数 A pc存指令的地址 内存按照字节编址&#xff1a; 在统一单位&#xff0c;转换一下&#xff1a; 3x2的平方 …

飞腾E2000 UEFI使用设备树方式启动linux系统

以往我们使用uboot引导系统启动,是采用uboot引导设备树+内核+文件系统的方式。 那么使用UEFI如何通过设备树+内核+文件系统的方式进行引导呢?这篇文章主要就介绍了这种操作方法。 一、使用Buildroot交叉编译生成E2000 Linux系统 详细请参考嵌入式软件部提供的 E2000 Linux…

服务器部署前后端项目-SQL Father为例

hello~大家好哇&#xff0c;好久没更新博客了。现在来更新一波hhh 现在更新一下部署上的一些东西&#xff0c;因为其实有很多小伙伴跟我之前一样&#xff0c;很多时候只是开发了&#xff0c;本地前后端都能调通&#xff0c;也能用&#xff0c;但是没有部署到服务器试过&#x…

【FPGA零基础学习之旅#11】数码管动态扫描

&#x1f389;欢迎来到FPGA专栏~数码管动态扫描 ☆* o(≧▽≦)o *☆嗨~我是小夏与酒&#x1f379; ✨博客主页&#xff1a;小夏与酒的博客 &#x1f388;该系列文章专栏&#xff1a;FPGA学习之旅 文章作者技术和水平有限&#xff0c;如果文中出现错误&#xff0c;希望大家能指正…