Elasticsearch:使用 Ollama 和 Go 开发 RAG 应用程序

作者:来自 Elastic Gustavo Llermaly

使用 Ollama 通过 Go 创建 RAG 应用程序来利用本地模型。

关于各种开放模型,有很多话要说。其中一些被称为 Mixtral 系列,各种规模都有,而一种可能不太为人所知的是 openbiollm,这是 Llama 3 针对医疗领域的改编版。通过实现它们的 API 来测试所有这些模型需要大量工作。但是,Ollama 允许我们使用友好的界面和简单的命令行来测试它们。

在本文中,我们将在 Golang 中构建一个 RAG 应用程序,使用 Ollama 作为 LLM 服务器,使用 Elasticsearch 作为向量数据库。

步骤

  • 安装 Ollama
  • 提取数据
  • Go 中的 RAG 应用程序

安装 Ollama

什么是 Ollama?

Ollama 是一个框架,允许你使用 CLI 在本地下载和访问模型。使用简单的命令,我们可以下载、聊天和设置一个服务器,其中包含我们想要从我们的应用程序中使用的模型。

在此处下载 Ollama 安装程序:

https://ollama.com/

包含可用模型的库在此处:

https://ollama.com/library

安装 Ollama 后,我们可以通过运行其中一个可用模型来测试一切是否正常。让我们使用 3B 参数安装 llama3.2。该库包含下载和运行模型所需的命令:

我们将运行 3B 版本的命令:

ollama run llama3.2:latest

第一次,它会下载模型,然后在终端中打开聊天:

现在我们可以输入 /exit 退出并使用在此位置设置的服务器:http://localhost:11434。让我们测试端点以确保一切按预期运行。

Ollama 提供两种答案模式:generate 以提供单一答案,chat 以与模型进行对话:

生成 - generate

当我们只希望对单个问题得到单个答案而不需要其他答案时,我们会使用生成。

curl http://localhost:11434/api/chat -d '{"model": "llama3.2","stream": false,"messages": [{ "role": "user", "content": "Why Elastic is so cool?" }]
}' 

默认情况下,答案以 stream: true 的形式生成,但我们将使用 stream: false,这样答案就只在一条消息中生成,并且更易于阅读。stream: true 在 UI 应用程序中很有用,因为 tokens 在生成时就会发送,而不是阻塞直到整个响应完成。

让我们继续讨论数据。

提取数据

让我们将一些医学文档作为文本和向量在 Elasticsearch 中编入索引。我们将使用这些来测试面向医学的模型(如 openbiollm)与一般模型相比的答案质量。

在开始之前,请确保我们已经创建了推理端点以使用 ELSER 作为我们的嵌入模型:

PUT _inference/sparse_embedding/my-elser-model 
{"service": "elser", "service_settings": {"num_allocations": 1,"num_threads": 1}
}

现在,让我们继续使用 semantic_text 字段类型创建索引,该类型允许我们控制分块大小以及向量配置。这使我们的索引能够支持全文、语义和混合搜索。

PUT rag-ollama 
{"mappings": {"properties": {"semantic_field": {"type": "semantic_text","inference_id": "my-elser-model"},"content": {"type": "text","copy_to": "semantic_field"}}}
}

现在,让我们索引这些文档:

POST _bulk
{"index":{"_index":"rag-ollama"}}
{"title":"JAK Inhibitors vs. Monoclonal Antibodies in Rheumatoid Arthritis Treatment","content":"This article compares the mechanisms of action, efficacy, and safety profiles of JAK inhibitors and monoclonal antibodies in rheumatoid arthritis treatment, including recent clinical trial data and real-world evidence. It discusses the intracellular signaling pathways targeted by JAK inhibitors, their rapid onset of action, and oral administration advantages. The article also covers the specific targets of various monoclonal antibodies, their long-term safety profiles, and the criteria for choosing between these two classes of drugs based on patient characteristics and disease severity."}
{"index":{"_index":"rag-ollama"}}
{"title":"Diagnostic Approach to Resistant Hypertension: Focus on Primary Aldosteronism","content":"This guide outlines the step-by-step diagnostic process for resistant hypertension, with a particular emphasis on screening and confirming primary aldosteronism. It details the use of aldosterone-renin ratio (ARR) testing as an initial screening tool, explaining proper patient preparation and interpretation of results. The guide also covers confirmatory tests such as the saline infusion test and captopril challenge test, their protocols, and diagnostic criteria. Additionally, it discusses the role of imaging studies in localizing aldosterone-producing adenomas and the importance of adrenal vein sampling in subtype classification of primary aldosteronism."}
{"index":{"_index":"rag-ollama"}}
{"title":"Gut Microbiota Diversity and Inflammatory Cytokine Production in IBD","content":"This study examines the relationship between gut microbiota diversity and the production of pro-inflammatory cytokines in inflammatory bowel diseases (IBD). It explores how reduced microbial diversity correlates with increased levels of cytokines such as TNF-α, IL-1β, and IL-6 in both Crohn's disease and ulcerative colitis. The research discusses specific bacterial species associated with anti-inflammatory effects and their mechanisms of action. Furthermore, it delves into potential therapeutic implications, including the use of prebiotics, probiotics, and fecal microbiota transplantation to modulate the gut microbiome and influence cytokine production. The study also touches on emerging microbiome-based interventions and their potential to complement existing IBD treatments."}
{"index":{"_index":"rag-ollama"}}
{"title":"Biological Therapy Selection in Rheumatoid Arthritis After csDMARD Failure","content":"This article provides a comprehensive framework for selecting appropriate biological therapy in rheumatoid arthritis patients who have not responded adequately to conventional synthetic Disease-Modifying Antirheumatic Drugs (csDMARDs). It discusses the various classes of biologics available, including TNF inhibitors, IL-6 inhibitors, B-cell depleting agents, and T-cell costimulation modulators. The article outlines key factors to consider in the decision-making process, such as disease activity scores, extra-articular manifestations, comorbidities, and patient preferences. It also addresses the importance of biomarkers and predictors of treatment response in guiding therapy selection. The piece concludes with a discussion on cycling versus switching mechanisms of action when faced with inadequate response to an initial biologic agent."}
{"index":{"_index":"rag-ollama"}}
{"title":"Hypertension Management in Chronic Kidney Disease: Special Considerations","content":"This review discusses the unique challenges in managing hypertension in patients with chronic kidney disease (CKD). It outlines the current recommendations for blood pressure targets in CKD patients, explaining how these differ based on the presence and degree of albuminuria. The article explores the preferred classes of antihypertensive medications in CKD, with a focus on renin-angiotensin system blockers and their renoprotective effects. It addresses the complexities of managing volume status in CKD and the role of diuretics. The review also covers the impact of proteinuria on treatment decisions and the need for more aggressive blood pressure control in heavily proteinuric patients. Finally, it discusses considerations for patients on dialysis and the phenomenon of reverse epidemiology in end-stage renal disease."}

完成了!现在我们已经准备好了模型和数据,我们可以将所有内容与我们的 Go 应用程序整合在一起。

Go 中的 RAG 应用程序

对于我们的 Go 应用程序,我们可以直接调用 Ollama 服务器,但我决定改用 parakeet。Parakeet 是一个基于 Go 文本创建 GenAI 应用程序的库。它提供了 Go 接口来抽象 HTTP 通信,此外还提供了用于嵌入、分块和内存等的帮助程序,因此创建应用程序变得非常容易。

我们将首先创建工作文件夹并设置依赖项:

mkdir ollama-rag
cd ollama-rag
go mod init ollama-rag
go get github.com/parakeet-nest/parakeet
go get github.com/elastic/go-elasticsearch/v8@latest

现在,创建一个 main.go 文件,其中包含测试一切是否配置正确的最少内容:

main.go

package mainimport ("github.com/parakeet-nest/parakeet/completion""github.com/parakeet-nest/parakeet/enums/option""github.com/parakeet-nest/parakeet/llm""fmt"
)func main() {ollamaUrl := "http://localhost:11434"model := "llama3.2:latest"options := llm.SetOptions(map[string]interface{}{option.Temperature: 0.5,})question := llm.GenQuery{Model:   model,Prompt:  "Why Elastic is so cool?, answer in one sentence",Options: options,}// We use generate because we are going to run this script to ask a single questionanswer, err := completion.Generate(ollamaUrl, question)if err != nil {log.Fatal("😡:", err)}fmt.Println(answer.Response)
}

运行它:

go run main.go

在终端中,你应该看到类似这样的答案:

Elastic, a company known for its innovative and user-friendly software solutions, has disrupted the traditional IT industry by empowering businesses to create, deploy, and manage applications quickly and reliably.

这个答案是基于 LLM 的训练数据,这不是我们可以提供或控制的,并且存在一些缺点:

  • 信息可能是错误的
  • 信息可能已过时
  • 无法获取来源的引用

现在,让我们创建一个名为 elasticsearch/elasticsearch.go 的文件,使用 Go 的官方客户端连接 Elasticsearch,并能够使用我们文档中的信息根据我们的数据生成有根据的答案。

:更多有关如何连接到 Elasticsearch,摄取数据,并进行搜索,请参阅文章 “Elasticsearch:运用 Go 语言实现 Elasticsearch 搜索 - 8.x”。

elasticsearch/elasticsearch.go 

package elasticsearchimport ("context""encoding/json""fmt""strings""github.com/elastic/go-elasticsearch/v8""github.com/elastic/go-elasticsearch/v8/typedapi/types"
)// Initializing elasticsearch clientfunc EsClient() (*elasticsearch.TypedClient, error) {var cloudID = "" // your Elastic Cloud ID Herevar apiKey = "" // your Elastic ApiKey Herees, err := elasticsearch.NewTypedClient(elasticsearch.Config{CloudID: cloudID,APIKey:  apiKey,})if err != nil {return nil, fmt.Errorf("unable to connect: %w", err)}return es, nil
}// Searching for documents and building the context
func SemanticRetriever(client *elasticsearch.TypedClient, query string, size int) (string, error) {// Perform the semantic searchres, err := client.Search().Index("rag-ollama").Query(&types.Query{Semantic: &types.SemanticQuery{Field: "semantic_field",Query: query,},}).Size(size).Do(context.Background())if err != nil {return "", fmt.Errorf("semantic search failed: %w", err)}// Prepare to format the resultsvar output strings.Builderoutput.WriteString("Documents found\n\n")// Iterate through the search hitsfor i, hit := range res.Hits.Hits {// Define a struct to unmarshal each documentvar doc struct {Title   string `json:"title"`Content string `json:"content"`}// Unmarshal the document source into our structif err := json.Unmarshal(hit.Source_, &doc); err != nil {return "", fmt.Errorf("failed to unmarshal document %d: %w", i, err)}// Append the formatted document to our outputoutput.WriteString(fmt.Sprintf("Title\n%s\n\nContent\n%s\n", doc.Title, doc.Content))// Add a separator between documents, except for the last oneif i < len(res.Hits.Hits)-1 {output.WriteString("\n-----\n\n")}}// Return the formatted output as a stringreturn output.String(), nil
}

EsClient 函数使用提供的云凭据初始化 Elasticsearch 客户端,SemanticRetriever 执行语义查询以构建 LLM 回答问题所需的上下文。

要查找你的云 ID 和 API 密钥,请转到此链接。

让我们回到我们的 main.go 文件并使用上述功能进行更新以调用 Elasticsearch 并运行语义查询:这将构建 LLM 上下文:

main.go

package mainimport ("fmt""log""ollama-rag/elasticsearch""github.com/parakeet-nest/parakeet/completion""github.com/parakeet-nest/parakeet/enums/option""github.com/parakeet-nest/parakeet/llm"
)func main() {ollamaUrl := "http://localhost:11434"chatModel := "llama3.2:latest"question := `Summarize document: JAK Inhibitors vs. Monoclonal Antibodies in Rheumatoid Arthritis Treatment`size := 3esClient, err := elasticsearch.EsClient()if err != nil {log.Fatalln("😡:", err)}// Retrieve documents from semantic query to build contextdocumentsContent, nil := elasticsearch.SemanticRetriever(esClient, question, size)systemContent := `You are a helpful medical assistant. Only answer the questions based on found documents.Add references to the base document titles and be succint in your answers.`options := llm.SetOptions(map[string]interface{}{option.Temperature: 0.0,})queryChat := llm.Query{Model: chatModel,Messages: []llm.Message{{Role: "system", Content: systemContent},{Role: "system", Content: documentsContent},{Role: "user", Content: question},},Options: options,}fmt.Println()fmt.Println("🤖 answer:")// Answer the question_, err = completion.ChatStream(ollamaUrl, queryChat,func(answer llm.Answer) error {fmt.Print(answer.Message.Content)return nil})if err != nil {log.Fatal("😡:", err)}fmt.Println()
}

如你所见,我们将用户的问题连同与之相关的所有文档一起发送。这就是我们如何根据 Elasticsearch 中的文档获得答案。

我们可以通过运行代码进行测试:

go run .

你应该看到类似这样的内容:

According to the article "JAK Inhibitors vs. Monoclonal Antibodies in Rheumatoid Arthritis Treatment", JAK inhibitors and monoclonal antibodies are two classes of drugs used to treat rheumatoid arthritis (RA). The main difference between them lies in their mechanisms of action:

        JAK inhibitors target intracellular signaling pathways, specifically the Janus kinase (JAK) pathway, which is involved in inflammation and immune response. They have a rapid onset of action and are administered orally.

  • Monoclonal antibodies target specific proteins involved in the inflammatory process, such as tumor necrosis factor-alpha (TNF-α), interleukin-6 (IL-6), and interleukin-17 (IL-17).

The article highlights that JAK inhibitors have a more favorable safety profile compared to monoclonal antibodies, with fewer gastrointestinal side effects. However, the choice between these two classes of drugs depends on patient characteristics and disease severity.

"References:"

        "JAK Inhibitors vs. Monoclonal Antibodies in Rheumatoid Arthritis Treatment" (document title)

Parakeet 将为我们处理 Ollama 交互,包括 token 流!从现在开始,我们可以非常轻松地测试不同的模型,而无需更改代码。

除了主库中的模型外,我们还可以访问社区成员上传的模型。

要使用其中一个,我们只需确保先下载到 Ollama 中。例如,让我们测试 openbiollm:

ollama run taozhiyuai/openbiollm-llama-3:8b_q8_0

安装后,我们可以将它与我们的 Go 代码一起使用:

chatModel := "taozhiyuai/openbiollm-llama-3:8b_q8_0"

让我们用同样的问题再运行一次。你注意到有什么不同吗?

In rheumatoid arthritis treatment, JAK inhibitors and monoclonal antibodies are commonly used. This article discusses the benefits and drawbacks of both therapies. JAK inhibitors work by targeting intracellular signaling pathways involved in the immune response. They have a rapid onset of action and can be administered orally, making them convenient for patients. Recent clinical trial data has shown that JAK inhibitors are effective at reducing inflammation and slowing joint damage progression in rheumatoid arthritis. However, there is still ongoing research to fully understand their long-term safety profile. Monoclonal antibodies, on the other hand, specifically target molecules involved in the immune system. These drugs have been found to be highly effective in managing symptoms of rheumatoid arthritis and improving joint function. They can provide prolonged symptom control and are often used as first-line treatment options. However, due to their complexity and unique administration requirements, monoclonal antibodies may not be suitable for all patients. In conclusion, both J AK inhibitors and monoclonal antibodies have their own advantages and disadvantages in treating rheumatoid arthritis. The choice of therapy depends on individual patient characteristics and disease severity. Ongoing research will contribute to a deeper understanding of the efficacy and safety profiles of these treatments, ultimately leading to improved care for patients with rheumatoid arthritis.

openbiollm 模型似乎提供了更多有关技术术语的细节,但它没有遵循有关引用上下文中提供的文档和给出简短答案的说明。相比之下,Llama3.2 更好地遵循了说明。

你可以在此处找到完整的工作示例

结论

Ollama 提供了一种非常直接和简单的方法来下载和测试不同的开放模型,从知名的模型到社区成员微调的模型。将它与 Parakeet 和官方 Elasticsearch Go 客户端配对,可以非常轻松地创建 RAG 应用程序。此外,通过使用 semantic_text 字段类型,你可以创建一个使用 ELSER(Elastic Sparse 嵌入模型)的语义查询就绪索引,而无需任何其他配置,从而简化了分块、索引和向量查询过程。

Elasticsearch 与行业领先的 Gen AI 工具和提供商进行了原生集成。查看我们的网络研讨会,了解如何超越 RAG 基础知识,或构建可用于生产的应用程序 Elastic Vector Database。

要为你的用例构建最佳搜索解决方案,请立即开始免费云试用或在你的本地机器上试用 Elastic。

原文:Using Ollama and Go for RAG applications - Elasticsearch Labs

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

实战案例——ZooKeeper集群部署(新手教程超详细)

案例目标 了解ZooKeeper分布式应用程序协调服务使用3台机器搭建ZooKeeper集群使用ZooKeeper集群 案例分析 规划节点 ZooKeeper集群节点规划 Ip 主机名 节点 192.168.110.10 zookeeper1 集群节点 192.168.110.20 zookeeper2 集群节点 192.168.110.30 zookeeper3 …

上手教程:使用Terraform打造弹性VPC架构

最近Akamai发布的虚拟专用云&#xff08;VPC&#xff09;功能提供了一种隔离的网络&#xff0c;让云资源可以用私密的方式进行通信。 关于Akamai VPC功能&#xff0c;最棒的地方在于它有着极高的灵活性。用户可以通过Cloud Manager、开发人员工具&#xff08;如CLI&#xff09…

基于python的扫雷游戏

游戏 游戏目标&#xff1a; 揭开所有非地雷的格子。 如果揭开地雷&#xff0c;游戏失败。 使用标记功能&#xff08;&#x1f6a9;&#xff09;来标记可能的地雷位置。 格子类型&#xff1a; 空白格子&#xff1a;表示周围没有地雷。 数字格子&#xff1a;显示周围 8 个格子…

利用Java爬虫速卖通按关键字搜索AliExpress商品

在这个信息爆炸的时代&#xff0c;数据的价值日益凸显。对于电商领域的从业者来说&#xff0c;能够快速获取商品信息成为了一项重要的技能。速卖通&#xff08;AliExpress&#xff09;作为全球领先的跨境电商平台&#xff0c;拥有海量的商品数据。本文将介绍如何使用Java语言编…

Java中三大构建工具的发展历程(Ant、Maven和Gradle)

&#x1f438; 背景 我们要写一个Java程序&#xff0c;一般的步骤是编译&#xff0c;测试&#xff0c;打包。 这个构建的过程&#xff0c;如果文件比较少&#xff0c;我们可以手动使用java, javac,jar命令去做这些事情。但当工程越来越大&#xff0c;文件越来越多&#xff0c…

ubuntu快速入门

1.进入某个文件夹 cd workspace/2.tab自动补全 3.列出当前文件夹所有文件 ls列出所有文件包括隐藏文件 ls -a 4.创建文件夹 mkdir linuxLearn 5.创建文件 gedit command.sh在commmand.sh键入 echo hello echo hi? echo how are you? PS:touch hello.txt(也可以创建新…

meshy的文本到3d的使用

Meshy官方网站&#xff1a; 中文官网&#xff1a; Meshy官网中文站 ​编辑 Opens in a new window ​编辑www.meshycn.com Meshy AI 中文官网首页 英文官网&#xff1a; Meshy目前似乎还没有单独的英文官网&#xff0c;但您可以在中文官网上找到英文界面或相关英文资料。 链…

嵌入式入门Day34

网络编程 Day1 为什么要学习网络编程&#xff1f;网络发展历史APRAnet阶段TCP/IP两个协议阶段网络体系结构及OSI开放系统系统互联模型网络体系结构概念OSI开放系统互联模型 TCP和UDP异同网络基础相关的概念字节序IP地址的转换IP地址子网掩码端口号 为什么要学习网络编程&#x…

代码解析:安卓VHAL的AIDL参考实现

以下内容基于安卓14的VHAL代码。 总体架构 参考实现采用双层架构。上层是 DefaultVehicleHal&#xff0c;实现了 VHAL AIDL 接口&#xff0c;并提供适用于所有硬件设备的通用 VHAL 逻辑。下层是 FakeVehicleHardware&#xff0c;实现了 IVehicleHardware 接口。此类可模拟与实…

【视觉惯性SLAM:四、相机成像模型】

相机成像模型介绍 相机成像模型是计算机视觉和图像处理中的核心内容&#xff0c;它描述了真实三维世界如何通过相机映射到二维图像平面。相机成像模型通常包括针孔相机的基本成像原理、数学模型&#xff0c;以及在实际应用中如何处理相机的各种畸变现象。 一、针孔相机成像原…

【前端,TypeScript】TypeScript速成(二):逻辑控制与循环

TypeScript 当中的逻辑控制 if-else if-else 的使用和其它语言非常相似&#xff1a; let answer: yes|no|maybe|undefined undefinedlet httpStatus: 200 | 404 | 500 | 200 | 404 | 500 200function processHttpStatus(s: 200 | 404 | 500 | 200 | 404 | 500) {// 一律使…

JSON 系列之1:将 JSON 数据存储在 Oracle 数据库中

本文为Oracle数据库JSON学习系列的第一篇&#xff0c;讲述如何将JSON文档存储到数据库中&#xff0c;包括了版本为19c和23ai的情形。 19c中的JSON 先来看一下数据库版本为19c时的情形。 创建表colortab&#xff0c;其中color列的长度设为4000。若color的长度需要设为32767&a…

TOGAF之架构标准规范-业务架构

TOGAF标准规范中&#xff0c;业务架构阶段的主要工作是开发支持架构愿景的业务架构。 如上所示&#xff0c;业务架构&#xff08;Business Architecture&#xff09;在TOGAF标准规范中处于B阶段&#xff0c;该阶段的主要内容包括阶段目标、阶段输入、流程步骤、架构方法。 阶段…

科技创新 数智未来|清科·沙丘投研院走进竹云

12月20日&#xff0c;清科沙丘投研院带领企投家团队走进竹云交流分享&#xff0c;聚焦技术创新、企业数字化管理、行业前沿应用案例等热点议题&#xff0c;深入探讨数字技术如何点燃企业高质量发展的澎湃动力&#xff0c;共话企业数字化、智能化发展之道。 达晨财智股权管理部…

【免费分享】mysql笔记,涵盖查询、缓存、存储过程、索引,优化。

概括 本篇笔记涵盖基础查询、视图、存储过程、函数、索引、优化、分库分表。适合在学完mysql后进行时常观看。下面展示部分内容。如果需要可以在文章底部的链接进行下载查看。 简介 数据库 数据库&#xff1a;DataBase&#xff0c;简称 DB&#xff0c;存储和管理数据的仓库…

Docker 安装全攻略:从入门到上手

Docker 安装全攻略&#xff1a;从入门到上手 在当今的软件开发与部署领域&#xff0c;Docker 已经成为了一项不可或缺的关键技术。它能够将应用程序及其依赖项打包成轻量级、可移植的容器&#xff0c;极大地简化了开发、测试和部署的流程。本文将详细讲解在不同操作系统下 Doc…

mysql建立主从集群

mysql建立主从集群需要多个mysql服务器&#xff0c;主从数据库是通过log日志来进行同步的&#xff0c;所以需开启log-bin。本地安装多个mysql参考底部 主数据库配置 打开主数据库my.ini配置文件&#xff0c;给其配置server_id1 [mysqld] port3306 basedirD:/phpstudy_pro/1/…

curl+openssl 踩坑笔记

curl编译&#xff1a;点击跳转 踩坑一 * SSL certificate problem: unable to get local issuer certificate * closing connection #0 curl: (60) SSL certificate problem: unable to get local issuer certificate More details here: https://curl.se/docs/sslcerts.html …

【开源免费】基于SpringBoot+Vue.JS租房管理系统(JAVA毕业设计)

本文项目编号 T 102 &#xff0c;文末自助获取源码 \color{red}{T102&#xff0c;文末自助获取源码} T102&#xff0c;文末自助获取源码 目录 一、系统介绍二、数据库设计三、配套教程3.1 启动教程3.2 讲解视频3.3 二次开发教程 四、功能截图五、文案资料5.1 选题背景5.2 国内…

小程序配置文件 —— 13 全局配置 - window配置

全局配置 - window配置 这里讲解根目录 app.json 中的 window 字段&#xff0c;window 字段用于设置小程序的状态栏、导航条、标题、窗口背景色&#xff1b; 状态栏&#xff1a;顶部位置&#xff0c;有网络信号、时间信息、电池信息等&#xff1b;导航条&#xff1a;有一个当…