深入浅出LangChain:从模型调用到Agents开发的全流程指南

news2024/9/22 19:46:31

2024最新LangChain全面解析:从基础组件到AI应用构建

LangChain、LangGraph、LangSmith:打造完整AI解决方案的利器

本文将对于LangChain的基本组件、用途、用法进行介绍。

LangChain、LangGraph以及LangSmith的组合,极大的简化了开发者构建AI应用、Agents、Tools的工作量,抹平了各个AI厂家间的调用差异,适配了大量了中间件及组件,形成了一个完整的解决方案。

通过本文的阅读,可以帮助大家加深对于AI产品、功能点下底层原理及实现的理解。

本文将从最基本的models调用开始介绍,涵盖memory、chain、RAG,最终以tools的定义及agents的调用结束。

注:LangChain发展很快,本文截止于2024年8月23日,基于此时最新版本V0.2编写。

一、Chat Models & Memory demo

Langchain的第一个优势是对于各大API供应商、开源模型进行了适配,将杂乱的调用,整合为一个统一的标准,最终的效果就是Just Invoke It。

0.2版本支持的models如下:

  • https://python.langchain.com/v0.2/docs/integrations/chat/

支持大厂:

也支持小厂:

如下是一个实例创建的代码,建立之后可供调用的方法是统一的,当然不同API支持的方法的数量不同,其中支持最全面的还是openai。

#最简单的方式,将API key放到环境变量``from langchain_openai import ChatOpenAI``from dotenv import load_dotenv``# Load environment variables from .env file``load_dotenv()``llm = ChatOpenAI(model="gpt-4o-mini")``   ``# 定义一个构建函数,然后再调用,Gemini的案例。``from dotenv import load_dotenv``from langchain_google_genai import ChatGoogleGenerativeAI``# Load environment variables from .env``load_dotenv()``# Create a Gemini model``def google_model_init(model):`    `model = ChatGoogleGenerativeAI(`        `model=model,`        `temperature=0,`        `max_tokens=None,`        `timeout=None,`        `max_retries=2,`        `# other params...`    `)`    `return model``   ``import model_init``model = model_init.google_model_init("gemini-1.5-flash")
同时还有一些本地部署的LLM不在支持的列表,只要将接口标准转化为openai的标准,也可以直接定义:  

from langchain_openai import ChatOpenAI``   ``llm = ChatOpenAI(`    `model_name="your-model-name",  # 根据你的模型名称进行修改`    `openai_api_key="your-api-key",  # 你的API密钥`    `openai_api_base="https://your-custom-openai-api.com/v1",  # 你的自定义API基础URL`    `temperature=0.7,`    `max_tokens=100``)

memory部分

LangChain帮助大家完成了很多事项的开发,例如聊天记录的持久化,你无需花时间去进行各个不同中间件的适配,LangChain已经全部做过了。

支持的中间件非常多:

  • https://python.langchain.com/v0.2/docs/integrations/memory/

本文以mangodb为例,写了个demo:

  • https://python.langchain.com/v0.2/docs/integrations/memory/mongodb_chat_message_history/

使用docker快速拉起一个mangodb:

docker run -d --name mongodb -p 27017:27017 -e MONGO_INITDB_ROOT_USERNAME=langchain -e MONGO_INITDB_ROOT_PASSWORD=langchain mongo
**利用LangChain将聊天记录持久化至mangodb:**
model = model_init.google_model_init("gemini-1.5-flash")``   ``DATABASE_NAME = "langchain"``SESSION_ID = "user_session_new"  # 用户ID,此处写死``COLLECTION_NAME = "chat_history"``   ``# Initialize MongoDB Chat Message History``print("Initializing MongoDB Chat Message History...")``   ``chat_history = MongoDBChatMessageHistory(`    `session_id=SESSION_ID,`    `connection_string="mongodb://langchain:langchain@192.168.137.3:27017", #上边本地部署的连接,结合实际修改。`    `database_name=DATABASE_NAME,`    `collection_name=COLLECTION_NAME,``)``   ``print("Chat History Initialized.")``print("Current Chat History:", chat_history.messages)``   ``print("Start chatting with the AI. Type 'exit' to quit.")``   ``while True:`    `human_input = input("User: ")`    `if human_input.lower() == "exit":`        `break``   `    `chat_history.add_user_message(human_input)`    `ai_response = model.invoke(chat_history.messages)`    `chat_history.add_ai_message(ai_response.content)``   `    `print(f"AI: {ai_response.content}")

chat过程的记录按照LangChain的标准存放于mongodb,相当的省心。

二、Prompt Templates

Prompt 的质量直接影响到 LLM 反馈结果的优劣。因此,将关键的 Prompt 进行结构化处理,并将可变部分留给程序填充,是确保 Prompt 质量的有效方法。

目前(以及未来),LLM 对英语的支持,将领先于所有其他语言。观察一些国内的项目,可以发现其核心 Prompt 也是以英语编写。因此,建议大家在未来逐步习惯使用英语的 Prompt。

Prompt Templates的定义很简单,此处将几种常见的情况列出,熟悉使用即可。

#单个替换``template = "Tell me a joke about {topic}."``prompt_template = ChatPromptTemplate.from_template(template)``prompt = prompt_template.invoke({"topic": "cats"})``   ``#多个替换``template_multiple = """You are a helpful assistant.``Human: Tell me a {adjective} short story about a {animal}.``Assistant:"""``prompt_multiple = ChatPromptTemplate.from_template(template_multiple)``prompt = prompt_multiple.invoke({"adjective": "funny", "animal": "panda"})``   ``#多行下Tuple的替换``messages = [`    `("system", "You are a comedian who tells jokes about {topic}."),`    `("human", "Tell me {joke_count} jokes."),``]``prompt_template = ChatPromptTemplate.from_messages(messages)``prompt = prompt_template.invoke({"topic": "lawyers", "joke_count": 3})``三、How to use Chains``LangChain定义了一种LangChain Expression Language(LCEL),来简化书写,完成多个LLM的任务的执行,简洁 且 优雅。``3.1 LCEL``chain = prompt | model``result = chain.invoke({"key":"value"})``# Define prompt templates (no need for separate Runnable chains)``prompt_template = ChatPromptTemplate.from_messages(`    `[`        `("system", "You are a comedian who tells jokes about {topic}."),`        `("human", "Tell me {joke_count} jokes."),`    `]``)``   ``# Create the combined chain using LangChain Expression Language (LCEL)``chain = prompt_template | model | StrOutputParser()``# chain = prompt_template | model``   ``# Run the chain``result = chain.invoke({"topic": "cars", "joke_count": 3})``   
3.2 how chains work,under the hood

对于chain而言,我们大致了解其底层实现,3 main things:

  • runnables:Runnables是LangChain中的基本构建块。它们是可以执行某些操作的对象,通常接受输入并产生输出。Runnables可以是简单的函数、复杂的模型或其他任何可以处理数据的组件。它们的关键特征是可以被"运行",即给定输入后能够产生输出。

  • runnable lambdas:Runnable Lambdas是一种特殊类型的Runnable,它们通常是简单的、匿名的函数。在LangChain中,你可以使用lambda函数来快速定义简单的操作,这些操作可以轻松地集成到更大的处理流程中。Runnable Lambdas提供了一种灵活且简洁的方式来定义自定义的数据处理步骤。

  • runnable sequences:Runnable Sequences是将多个Runnables组合在一起的方式。它允许你创建一个处理流水线,其中一个Runnable的输出可以作为下一个Runnable的输入。这种序列化的方法使得创建复杂的处理链变得简单,每个步骤都可以独立定义和测试,然后组合成一个完整的工作流程。

如下是一个事例,实际我们使用中,直接使用LCEL就可以了。如下的代码仅仅用于参考,理解背后的原理:

# Create individual runnables (steps in the chain)``# **x是Python中的解包操作符,用于字典。它的作用是将字典x中的所有键值对作为单独的关键字参数传递给函数。``format_prompt = RunnableLambda(lambda x: prompt_template.format_prompt(**x))``invoke_model = RunnableLambda(lambda x: model.invoke(x.to_messages()))``parse_output = RunnableLambda(lambda x: x.content)``# Create the RunnableSequence (equivalent to the LCEL chain)``chain = RunnableSequence(first=format_prompt, middle=[invoke_model], last=parse_output)``   
3.2 Chain的三种运行模式:
  • Extended:串连执行

  • Parallel:并行执行

  • Branching:判断执行

chain module/extended

我们可以自己利用lambda函数,写一些runnable lambda,随后可以按照LCEL加入到chain中进行串联运行。这个的好处在于,你可以把你任何想做的事情,嵌入到一个lambda函数中,例如,嵌入一个API call。

# Define prompt templates``prompt_template = ChatPromptTemplate.from_messages(`    `[`        `("system", "You are a comedian who tells jokes about {topic}."),`        `("human", "Tell me {joke_count} jokes."),`    `]``)``   ``# Define additional processing steps using RunnableLambda``uppercase_output = RunnableLambda(lambda x: x.upper())``count_words = RunnableLambda(lambda x: f"Word count: {len(x.split())}\n{x}")``   ``# Create the combined chain using LangChain Expression Language (LCEL)``chain = prompt_template | model | StrOutputParser() | uppercase_output | count_words``   ``# Run the chain``result = chain.invoke({"topic": "lawyers", "joke_count": 3})
chain module/parallel  

Langchian提供了并行运行的功能,可以在LCEL进行调用。之所以需要并行,我的理解是,LLM本身就存在token生成的过程,相比传统的数据库查询,慢了不是一个数量级。因此,当多个任务进行串行时,等待的时间势必会进一步拉长,因此在这种场景下,parallel就是很刚需的了。

以下是一个调用方法的简单的示例:

# Simplify branches with LCEL``pros_branch_chain = (`    `RunnableLambda(lambda x: analyze_pros(x)) | model | StrOutputParser()``)``   ``cons_branch_chain = (`    `RunnableLambda(lambda x: analyze_cons(x)) | model | StrOutputParser()``)``   ``# Create the combined chain using LangChain Expression Language (LCEL)``chain = (`    `prompt_template`    `| model`    `| StrOutputParser()`    `| RunnableParallel(branches={"pros": pros_branch_chain, "cons": cons_branch_chain})`    `| RunnableLambda(lambda x: combine_pros_cons(x["branches"]["pros"], x["branches"]["cons"]))``)

chain module/branching

这个就是Langchian的if语句,按照不同的结果,执行不同的branch。

最常见的案例就是,对于客户的评价进行分类,按照不同的分类使用不同的prompt进行处理。

案例:

# Define the feedback classification template``classification_template = ChatPromptTemplate.from_messages(`    `[`        `("system", "You are a helpful assistant."),`        `("human","Classify the sentiment of this feedback as positive, negative, neutral, or escalate: {feedback}."),`    `]``)``   ``# Define the runnable branches for handling feedback``branches = RunnableBranch(`    `(`        `lambda x: "positive" in x,`        `positive_feedback_template | model | StrOutputParser()  # 正面反馈chain`    `),`    `(`        `lambda x: "negative" in x,`        `negative_feedback_template | model | StrOutputParser()  # 负面反馈chain`    `),`    `(`        `lambda x: "neutral" in x,`        `neutral_feedback_template | model | StrOutputParser()  # 普通反馈chain`    `),`    `escalate_feedback_template | model | StrOutputParser()     # 搞不定的chain``)``   ``# Create the classification chain``classification_chain = classification_template | model | StrOutputParser()``   ``# Combine classification and response generation into one chain``chain = classification_chain | branches

四、RAG (Retrieval-Augmented Generation)

4.1 What’s RAG

RAG(检索增强生成)技术目前使用范围非常广泛,一般的介绍强调RAG为LLM增加了获取数据的能力,实现了LLM与现实世界(如Web和API)的连接,并增强了LLM获取私有知识库的能力。我倒是觉得,RAG更像是一种高级的检索方式,实现了基于语义理解的搜索。

传统搜索引擎主要基于关键词匹配,而RAG利用LLM的语义理解能力,将检索从单纯的词语匹配提升到了语义层面的相似性搜索。这种转变使得检索结果更加精确和相关。并且有了多模态的加持之后,可以进一步实现图片、语音、视频的检索。

4.2 文字RAG的原理

当我们使用RAG时,本质其实是在原有问题的基础上,进一步的加上我们根据语义所检索回来的信息,最终拼凑出来一个完整的prompt给LLM。因此对于一个知识库而言,是必须提前做切分的,做成小块的chunks,再对于chunks做embedding,最终再存放至向量数据库。

不同的模型,最大的上下文窗口的大小差异较大,我们最常用的GPT-4,实际上只有8000左右的token数。实际的chunk切分过程中,可以切分成1000-2000 tokens的chunks,最终3个chunk加原始的问题,基本上就足够了。对于其他的模型而言,可以结合实际情况测试验证。

  • 文本分块:将长文本切分成较小的chunk(通常约1000-2000tokens),以适应LLM的输入窗口限制(如ChatGPT约8000 tokens)。

  • 文本嵌入:使用嵌入模型将文本转换为向量表示。语义相近的词汇在向量空间中距离较近,这使得基于相似性的搜索成为可能。

  • 问题嵌入:用户的问题也会被转换为向量表示。

  • 相似度检索:通过比较问题向量和文本chunk向量的相似度,找出最相关的内容。

  • 向量存储:使用如Chroma等向量数据库存储和检索这些向量。

常见厂家模型的窗口大小:

公司

模型名称

最大上下文窗口大小 (tokens)

OpenAI

GPT-3 (davinci)

4,096

OpenAI

GPT-3.5-turbo

4,096

OpenAI

GPT-4 (8K context)

8,192

Google

Gemini Pro

32,768

Google

Gemini Ultra

1,048,576

Anthropic

Claude

9,000

Anthropic

Claude Instant

9,000

4.3 Embedding models

各个厂家都有自己的embedding models,并且是收费的。对于历史数据或者知识库的embedding,只需要做一次就可以了。原始的数据使用哪个模型进行embedding,在进行语义检索的时候,也必须同样使用哪个embedding model。他们是强相关,必须搭配使用的。

openai的embedding models的价格:https://openai.com/api/pricing/

那么,如何系统的去学习大模型LLM?

我在一线互联网企业工作十余年里,指导过不少同行后辈。帮助很多人得到了学习和成长。

作为一名热心肠的互联网老兵,我意识到有很多经验和知识值得分享给大家,也可以通过我们的能力和经验解答大家在人工智能学习中的很多困惑,所以在工作繁忙的情况下还是坚持各种整理和分享。

但苦于知识传播途径有限,很多互联网行业朋友无法获得正确的资料得到学习提升,故此将并将重要的AI大模型资料包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来。

所有资料 ⚡️ ,朋友们如果有需要全套 《LLM大模型入门+进阶学习资源包》,扫码获取~

篇幅有限,部分资料如下:

👉LLM大模型学习指南+路线汇总👈

💥大模型入门要点,扫盲必看!
在这里插入图片描述
💥既然要系统的学习大模型,那么学习路线是必不可少的,这份路线能帮助你快速梳理知识,形成自己的体系。

路线图很大就不一一展示了 (文末领取)
在这里插入图片描述

👉大模型入门实战训练👈

💥光学理论是没用的,要学会跟着一起做,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。
在这里插入图片描述

👉国内企业大模型落地应用案例👈

💥两本《中国大模型落地应用案例集》 收录了近两年151个优秀的大模型落地应用案例,这些案例覆盖了金融、医疗、教育、交通、制造等众多领域,无论是对于大模型技术的研究者,还是对于希望了解大模型技术在实际业务中如何应用的业内人士,都具有很高的参考价值。 (文末领取)
在这里插入图片描述

👉GitHub海量高星开源项目👈

💥收集整理了海量的开源项目,地址、代码、文档等等全都下载共享给大家一起学习!
在这里插入图片描述

👉LLM大模型学习视频👈

💥观看零基础学习书籍和视频,看书籍和视频学习是最快捷也是最有效果的方式,跟着视频中老师的思路,从基础到深入,还是很容易入门的。 (文末领取)
在这里插入图片描述

👉640份大模型行业报告(持续更新)👈

💥包含640份报告的合集,涵盖了AI大模型的理论研究、技术实现、行业应用等多个方面。无论您是科研人员、工程师,还是对AI大模型感兴趣的爱好者,这套报告合集都将为您提供宝贵的信息和启示。
在这里插入图片描述

👉获取方式:

这份完整版的大模型 LLM 学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费

😝有需要的小伙伴,可以Vx扫描下方二维码免费领取🆓

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

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

相关文章

看新闻知补贴不用专门薅羊毛!让工作变舒服的5个黄金法则——早读(逆天打工人爬取热门微信文章解读)

你们都不看新闻吗? 引言Python 代码第一篇 洞见 让工作变舒服的5个黄金法则第二篇 故事之散户结尾 (发了3000亿以旧换新补贴,大家没有感觉到力度吗? 时间到今年年底,9月-12月是消费区,中间夹杂个双十一,现在…

[易聊]软件项目测试报告

一、项目背景 随着互联网发展,各种各样的软件,比如游戏、短视频、购物软件中都有好友聊天功能,这是一个可在浏览器中与好友进行实时聊天的网页程序。“ 易聊 ”相对于一般的聊天软件,可以让用户免安装、随时随地的通过浏览器网页…

页面内容---复制粘贴【收藏版】【H5 web端亲测有效】

js中的复制粘贴 . 页面内容—复制粘贴【收藏版】【H5 web端亲测有效】 navigator.clipboard.writeText(copyText) 是 Web API 中的一个方法,用于将指定的文本内容复制到用户的剪贴板。这个方法属于 Clipboard API,它使得网页能够读取和写入剪贴板的内容…

【笔记】数据结构笔记02

toc 前话 算法学习网站&#xff1a; itcharge 代码随想录 labuladong 参考严蔚敏数据结构 树与等价问题 typedef PTree MFSet;//查找算法int find_mfset(MFSet S,int i){if(i<1||i>S.n) return -1;//i不属于任一集合for(ji;S.nodes[j].parent>0;jnodes[j].paren…

用宝塔部署项目到阿里云服务器访问不到的问题

今天用宝塔部署项目到阿里云&#xff0c;开始前端部署到了80端口&#xff0c;能正常访问&#xff0c;后端部署到了8081&#xff0c;但是后端接口一直无响应&#xff0c;最后超时。 但是java正常运行 系统防火墙的状态正常&#xff0c;策略也是放行 阿里云安全组也已经配置了 …

【性能优化】:从理论中来到实践中去(三)

本文主要介绍真实代码实现 序言 根据前面两篇文章的梳理 【性能优化】&#xff1a;探索系统瓶颈的根源&#xff08;一&#xff09; 【性能优化】&#xff1a;设计模式与技术方案解析&#xff08;二&#xff09; 我们已经知道了自动化跑批系统的核心功能&#xff0c;今天就来真…

如何使用混合搜索实现更好的 LLM RAG 检索

通过结合密集嵌入和BM25构建高级本地LLM RAG管道 基本的检索增强生成&#xff08;RAG&#xff09;管道使用编码器模型在给定查询时搜索相似文档。 这也被称为语义搜索&#xff0c;因为编码器将文本转换为高维向量表示&#xff08;称为嵌入&#xff09;&#xff0c;在该表示中&…

【计算机组成原理】汇总五、中央处理器

五、中央处理器 文章目录 五、中央处理器1.CPU的功能与结构1.1CPU功能1.2运算器1.2.1基本结构1.2.2 ALU和寄存器的数据通路 1.3控制器1.3.1基本结构1.3.2控制器功能 1.4CPU的基本结构 2.指令执行过程2.1指令周期2.2指令周期流程2.3数据流2.4指令执行方案&#xff1a;如何安排多…

Type-C接口诱骗取电快充方案

Type-C XSP08Q 快充协议芯片是一种新型电源管理芯片&#xff0c;主要负责控制充电电流和电压等相关参数&#xff0c;从而实现快速充电功能。Type-C XSP08Q快充协议是在Type-C接口基础上&#xff0c;加入了XSP08Q协议芯片的支持&#xff0c;很大程度上提升了充电速度。 正常情况…

ConcurrentHashMap扩容原理 | 存储流程 | 源码探究

新人写手&#xff0c;代码菜鸡&#xff1b;笔下生涩&#xff0c;诚惶诚恐。 初试锋芒&#xff0c;尚显青涩&#xff1b;望君指点&#xff0c;愿受教诲。 本篇文章将从源码的层面&#xff0c;探讨ConcurrentHashMap的存储流程以及扩容原理 Java版本为JDK17&#xff0c;源代码可…

Ollama 本地部署

文章目录 前言一、Ollama是什么&#xff1f;二、使用步骤1.安装 OllamaWindows检验是否安装成功 2.运行ollama 模型库运行模型提问修改配置&#xff08;可选&#xff09;如果有个性化需求&#xff0c;需要修改默认配置&#xff1a; 参考 前言 Ollama是一个易于使用的本地大模型…

LivePortraitV3,支持图像驱动和区域控制,更精确的人像控制(WIN,MAC)

LivePortrait又又又又更新了&#xff01;这速度真是&#x1f44d;&#x1f3fb;&#x1f44d;&#x1f3fb; 【LivePortraitV3&#xff0c;支持图像驱动和区域控制&#xff0c;更精确的人像控制&#xff08;WIN&#xff0c;MAC&#xff09;】 https://www.bilibili.com/video/…

别暑气 迎秋意

今年长达40天的“三伏”结束啦&#xff01; 伏天过后&#xff0c;暑热逐渐消退&#xff0c;天气开始转凉&#xff0c;秋季逐渐来临。我们也该调整好生活节奏&#xff0c;去迎接收获季节的开始。 1、注意防寒保暖 天气逐渐转凉&#xff0c;昼夜温差不断增大&#xff0c;所以要…

Pytest自动化测试框架关联/参数化实战

关联 利用Python提供的fixture可以实现关联 实现步骤&#xff1a; 在case目录下&#xff0c;新建conftest.py文件&#xff0c;比如我们需要token&#xff0c;就在这个文件下定义一个公共的方法&#xff0c;调用登录接口并返回需要的token值&#xff08;注&#xff1a;公共的方…

【乐企】有关乐企能力测试接口对接-货物运输服务(详细)

1、前置条件&#xff0c;参考【乐企】有关乐企能力测试接口对接-基础版&#xff08;详细&#xff09; 2、接口文档 和基础版区别&#xff1a; 1、传参的时候添加了 用例编码&#xff1a;ylbm 2、发票上传接口的服务编码变化了&#xff1a;fwbm:HWYSFPSC 3、能力编码和用例编码…

Linux——安装软件(mysql)

一、应用部署&#xff1a; 安装软件 运行某个程序或者服务 安装软件包 dnf/yum 包安装工具官方网站提供的集成软件包源码编译安装 // 源码编译的步骤 只应用于编译型语言 对于解释性语言编写的程序 采用不用的方式打包 编译型语言编写的程序&#xff1a; nginx解释性语言…

Verilog刷题笔记63

找BUG 1、&#xff1a;Bug mux2 挑错&#xff1a; module top_module (input sel,input [7:0] a,input [7:0] b,output [7:0]out );assign out sel?a:b;endmodule结果正确&#xff1a; 原因: 1、输出out也应为8位 2、逻辑错误&#xff0c;&按位操作&#xff0c;需要将…

【可兼容的】protobuf、streamlit、transformers、icetk、cpm_kernels版本号

搞大模型训练的工作不可避免地需要很多库&#xff0c;但是非常讨厌的事情是这些库动不动就不兼容。最近在做文本分类训练的时候又遇到了这个问题&#xff0c;为了避免后面再安装包的时候把我之前的环境破坏了&#xff0c;所以特地来记录一下&#xff1a;protobuf、streamlit、t…

GD32F4xx---RTC初始化设置及闹钟方式实现秒中断讲解

GD32F4xx—RTC初始化设置及闹钟方式实现秒中断讲解 1、下载链接:源码工程 一、概述 GD32F4x的RTC例程网上资源较少,详细阅读用户手册后做出如下配置。RTC模块提供了一个包含日期(年/月/日)和时间(时/分/秒/亚秒)的日历功能。除亚秒用二进制码显示外,时间和日期都以BC…

欧科云链: Web3浪潮下合规是“必选项”, 技术创新成发展重点

如果说2023年将是Web3的监管与合规之年。那么2024年就是Web3发展里程碑之年。 自2023年&#xff0c;包括美国、日本、新加坡、迪拜、中国香港等全球多个国家和地区金融中心都先后宣布要成为Web3中心、虚拟资产中心&#xff0c;并努力在监管框架下推动Web3生态的技术创新。 放…