如何在 Python 中连接 Elasticsearch 并使用 Qwen3 来实现 RAG

今天的这篇文章是 “在本地电脑中部署阿里 Qwen3 大模型及连接到 Elasticsearch” 的续篇。我们接着上次的文章,继续探索如何使用 Qwen3 来实现 RAG。在本练习中,我们使用 Elastic Stack 9.0.1 版本。

创建 Elasticsearch API key

我们按照如下的步骤来活动 Elasticsearch API key:

点击上面的复制按钮,我们就可以得到访问  Elasticsearch 的 API key:dWFTcW5KY0JYZl9wQVhZMFdaVU86QjFzUXEtel8tTzdTUWI4M3huUk8yUQ==

用 Python 代码来实现 RAG

我们可以在上次的 Kibana 界面中点击 View code

我们点击上面的拷贝代码按钮,并把文件保存下来。我们把文件命名为 alice_qwen3.py:

alice_qwen3.py

## Install the required packages
## pip install -qU elasticsearch openai
import os
from elasticsearch import Elasticsearch
from openai import OpenAI
es_client = Elasticsearch(
    "<your-elasticsearch-url>",
    api_key=os.environ["ES_API_KEY"]
)
      
openai_client = OpenAI(
    api_key=os.environ["OPENAI_API_KEY"],
)
index_source_fields = {
    "book_alice": [
        "content"
    ]
}
def get_elasticsearch_results():
    es_query = {
        "retriever": {
            "standard": {
                "query": {
                    "semantic": {
                        "field": "content",
                        "query": query
                    }
                }
            }
        },
        "highlight": {
            "fields": {
                "content": {
                    "type": "semantic",
                    "number_of_fragments": 2,
                    "order": "score"
                }
            }
        },
        "size": 3
    }
    result = es_client.search(index="book_alice", body=es_query)
    return result["hits"]["hits"]
def create_openai_prompt(results):
    context = ""
    for hit in results:
        ## For semantic_text matches, we need to extract the text from the highlighted field
        if "highlight" in hit:
            highlighted_texts = []
            for values in hit["highlight"].values():
                highlighted_texts.extend(values)
            context += "\n --- \n".join(highlighted_texts)
        else:
            source_field = index_source_fields.get(hit["_index"])[0]
            hit_context = hit["_source"][source_field]
            context += f"{hit_context}\n"
    prompt = f"""
  Instructions:
  
  - You are an assistant for question-answering tasks using relevant text passages from the book Alice in wonderland
  - Answer questions truthfully and factually using only the context presented.
  - If you don't know the answer, just say that you don't know, don't make up an answer.
  - You must always cite the document where the answer was extracted using inline academic citation style [], using the position.
  - Use markdown format for code examples.
  - You are correct, factual, precise, and reliable.
  
  Context:
  {context}
  
  """
    return prompt
def generate_openai_completion(user_prompt, question):
    response = openai_client.chat.completions.create(
        model="gpt-3.5-turbo",
        messages=[
            {"role": "system", "content": user_prompt},
            {"role": "user", "content": question},
        ]
    )
    return response.choices[0].message.content
if __name__ == "__main__":
    question = "my question"
    elasticsearch_results = get_elasticsearch_results()
    context_prompt = create_openai_prompt(elasticsearch_results)
    openai_completion = generate_openai_completion(context_prompt, question)
    print(openai_completion)

为了能够使得这个代码能正常工作,我们需要做一些修改。在进行下面的修改之前,我们可以参考我之前的文章 “Elasticsearch:关于在 Python 中使用 Elasticsearch 你需要知道的一切 - 8.x”。我们在当前的目录下创建一个叫做 .env 的文件:

.env

$ pwd
/Users/liuxg/data/alice
$ code alice_qwen3.py
$ touch .env

它的内容如下:

ELASTICSEARCH_URL="https://localhost:9200"
OPENAI_API_KEY="Anything"
ES_API_KEY="dWFTcW5KY0JYZl9wQVhZMFdaVU86QjFzUXEtel8tTzdTUWI4M3huUk8yUQ=="
QWEN3_URL="http://localhost:1234/v1/"

上面的配置你需要根据自己的安装进行响应的修改。注意:由于我们的 Qwen3 在本地部署,没有设置开发者 key,在上面的配置中,我们可以把 OPENAI_API_KEY 设置为任意值(除空值外,否则会有错误)。

我们接下来拷贝 Elasticsearch 的证书:

$ pwd
/Users/liuxg/python/alice
$ cp ~/elastic/elasticsearch-9.0.2/config/certs/http_ca.crt .
overwrite ./http_ca.crt? (y/n [n]) y
$ ls http_ca.crt 
http_ca.crt

接下来,我们需要安装我们所需要的 python 代码依赖包:

pip3 install elasticsearch python-dotenv openai

我们参考文章链接来先测试一下我们的 openai 相兼容的端点是工作正常的。我们创建如下的一个测试应用:

test_qwen_completion.py

from openai import OpenAI
 
client = OpenAI(api_key="qwen", base_url="http://localhost:1234/v1")
 
response = client.chat.completions.create(
    model="qwen/qwen3-32b",
    messages=[
        {"role": "system", "content": "You are a helpful assistant"},
        {"role": "user", "content": "What is Elastic"},
    ],
    stream=False
)
 
print(response.choices[0].message.content)

我们运行上面的代码:

$ pwd
/Users/liuxg/python/alice
$ python test_qwen_completion.py 
<think>
Okay, the user asked "What is Elastic?" Let me start by thinking about possible interpretations.

First possibility: Elasticsearch, a search engine developed by Elastic. That's pretty common usage of the term "Elastic" these days, especially since Elasticsearch became popular.

Second possibility: Elastic is also a company name itself. The company was originally called Elasticsearch BV before changing their legal entity structure in late 2019/early 2020更名为Elastic N.V., so maybe users are asking about the company itself.

Third possibility could be Elastic in general computing terms, meaning something scalable or adaptable. But given Elasticsearch/Elastic's popularity, the first two are more likely contexts.

Looking at recent trends in search queries about Elastic/Elasticsearch, Elasticsearch remains very popular among developers for full-text search capabilities and analytics purposes through the Elastic Stack/Elasticsearch ecosystem.

Considering best practices for helping users understand technologies, I'll provide comprehensive information covering both meanings:

1. Elastic 公司本身:成立年份、业务范围等基本信息。
2. Elasticsearch(Elasticsearch)作为主要产品:其功能特性、应用场景等。
3. Elastic Stack 的组成部分及整体解决方案。

Also need to consider potential follow-up questions users might have after explanation:
- How Elasticsearch works?
- What are typical use cases?
- What's relationship between Elastic company and Elasticsearch?

Need to keep explanations clear,organized, possibly include examples of use cases.

Also important note that while Elastic provides many other tools and services beyond Elasticsearch itself,Elasticsearch remains其核心产品.

Need check current facts:
- Elastic 公司成立年份是?
Elasticsearch 官方文档显示它最初由 Shay Banon 创建于约 2010 年,作为内部搜索工具。正式推出是在什么时候?

Yes, Shay Banon 开发了 Elasticsearch,并且 Elastic 公司(原名 Elasticsearch BV)成立于约 2012 年,正式推出 Elasticsearch 的时间大约是?

根据 Elastic 公司历史显示:
- 2012 年,Elasticsearch BV 成立(前身),以支持 Elasticsearch 的发展。
- 2014 年,Elasticsearch 放弃某些限制性许可条款。
- 在 2019 年后,公司更名为 Elastic N.V.

Also important distinction:Elasticsearch 是一个独立开源项目 (under Apache License),而 Elastic 公司不仅开发维护它,还提供商业产品(如企业版、云服务等)。

Need ensure terminology clarity:
- Open source version vs commercial offerings.
- Ecosystem components(Logstash,Kibana,Beats)all developed by Elastic team.

Also consider possible confusion:用户可能将公司名称和产品名称混淆,需要清楚区分。

Now, organize comprehensive response covering:
- What Elastic 公司是?
- What Elasticsearch 是?
- How Elasticsearch works at high level.
- Common use cases/scenarios(search,analytics)
- Other products in Elastic Stack。
- Brief mention of commercial vs open-source offerings.

Should also consider providing brief explanation on technical aspects(e.g., distributed nature,full-text search capabilities)without getting too technical,just enough context to understand significance.

Maybe include some real-world examples of companies using Elasticsearch/Elastic Stack,to illustrate practical applications。

Also check spelling and terminology accuracy:
- "Elasticsearch" 正确拼写。
- Elastic N.V./Elastic 公司名称正确。

Need avoid assumptions beyond basic facts,unless necessary(e.g., specific implementation details unless user asks)。

Now,组织答案:
1. 引言:Elastic 公司和 Elasticsearch 的关系。
2. 分别介绍 Elastic 公司本身:
   - 成立时间、地点、愿景。
3. Elasticsearch 的本质:
   - 类型(全文搜索引擎)
   - 开源状态(Apache License)。
4. 功能特点:
   - 分布式、实时搜索、分析能力等。
5. 应用场景的例子:
   - 日志分析(ELK Stack/Kibana)
   - 商业搜索引擎(如电商产品搜索)
6. Elastic Stack 组成:
   - Logstash,Kibana,Beats 等。
7. 商业产品与开源产品的区别:
   - 企业版功能扩展,云服务等。
8. 总结:两者之间的关系。

Need ensure clarity between company and product distinction,as users might confuse them initially。

Also important note that while Elastic 公司开发维护 Elasticsearch 等工具,这些工具本身是开放源代码的,即使有商业版本。

Also remember user might want brief intro without too much technical depth initially.

I think comprehensive response covering both aspects would best meet user needs,since ambiguous question。
</think>

**Elastic 公司与 Elasticsearch 的关系及简介**

以下是关于 **"Elastic 是什么?"** 的详细解释:

---

### 一、【Elastic 公司】  
**成立与定位:**
- Elastic 是一家总部位于荷兰的科技公司,原名为 Elasticsearch BV(成立于约 **2012 年**),后来在 **2019 年更名为 Elastic N.V.**。
- 公司愿景是通过开发工具帮助开发者和企业构建可扩展的搜索、分析与安全解决方案。

**核心业务:**
- 开发并维护多个开源项目(如 Elasticsearch、Kibana、Logstash 等)。
- 提供基于这些技术的企业级产品和服务(包括云服务、企业版授权等)。

---

### 二、【Elasticsearch】—— 核心产品  
**定义:**
- **Elasticsearch** 是一个开源的分布式搜索与分析引擎,主要用于:实时全文搜索、日志分析(Logging)、商业智能等场景。
- 它是 Elastic 公司开发的最知名的产品之一,基于 Apache License 2.0 协议开源。

**主要特点:**
- **分布式架构**:数据自动分片并跨多节点存储,支持水平扩展。
- **实时搜索与分析**:支持复杂查询(如全文检索、聚合统计),响应速度快。
- **JSON 支持**:天然支持 JSON 数据格式,便于与现代应用集成。
- **多语言 SDK**:提供 Java、Python、JavaScript 等多种语言的客户端库。

---

### 三、【Elasticsearch 的工作原理】(简要)  
- 数据写入后会被索引化,并分布存储在集群的多个节点中。
- 支持分片和副本机制,确保高可用性和容错性。
- 查询时,Elasticsearch 使用倒排索引技术快速匹配结果,并返回聚合后的分析数据。

---

### 四、【典型应用场景】  
#### 1. 搜索引擎:  
- 示例:电商网站的商品搜索、维基百科的词条检索。
#### 2. 日志与分析(ELK Stack):
- **Elasticsearch(搜索)** + **Logstash(数据处理)** + **Kibana(可视化工具)** 组合用于日志集中化分析。
- 示例:监控服务器日志、分析用户行为数据。
#### 3. 安全与威胁检测:
- 结合 Elastic 的安全产品(如 Elastic Security),实时分析日志以检测潜在攻击。
#### 4. 商业智能(BI):
- 使用 Kibana 创建数据仪表盘,支持实时业务决策。

---

### 五、【Elastic Stack】—— 完整生态系统  
除了 Elasticsearch,公司还提供以下工具:
- **Kibana**:数据可视化与仪表板平台。
- **Logstash**:日志收集、处理与转发工具。
- **Beats(如 Filebeat)**:轻量级数据收集器。
- **Apaches Nifi / Fluentd 等集成工具**支持。

---

### 六、【开源 vs 商业产品】  
- **开源版本(Open Distro)**:免费使用,适合大多数开发者和中小企业。
- **企业版产品(如 Elastic Stack Enterprise)**:提供高级功能、技术支持与云服务选项。

---

### 总结:
- **Elastic 是公司名称**,而 Elasticsearch 是其核心开源搜索引擎。
- 使用场景广泛:从电商搜索到日志分析,再到安全监控与 BI。
- 社区活跃度高,生态丰富(如 ELK Stack),是当前搜索与日志分析领域的主流解决方案之一。

如果您有具体问题(如安装、使用场景等),欢迎进一步提问!

很显然,我们的 Qwen 给我们的推理是正确的。

我们接下来修改从 Playground 拷贝过来的代码:

alice_qwen3.py

## Install the required packages
## pip install -qU elasticsearch openai
import os
from dotenv import load_dotenv
from elasticsearch import Elasticsearch
from openai import OpenAI

load_dotenv()

ELASTICSEARCH_URL = os.getenv('ELASTICSEARCH_URL')
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
ES_API_KEY = os.getenv("ES_API_KEY")
QWEN3_URL = os.getenv("QWEN3_URL")

es_client = Elasticsearch(
    ELASTICSEARCH_URL,
    ca_certs="./http_ca.crt",
    api_key=ES_API_KEY,
    verify_certs = True
)

# resp = es_client.info()
# print(resp)

try:
    openai_client = OpenAI(
    api_key=OPENAI_API_KEY,
    base_url=QWEN3_URL
    )
except:
    print("Something is wrong")

index_source_fields = {
    "book_alice": [
        "content"
    ]
}

def get_elasticsearch_results(query):
    es_query = {
        "retriever": {
            "standard": {
                "query": {
                    "nested": {
                        "path": "content.inference.chunks",
                        "query": {
                            "knn": {
                                "field": "content.inference.chunks.embeddings",
                                "query_vector_builder": {
                                    "text_embedding": {
                                        "model_id": ".multilingual-e5-small-elasticsearch",
                                        "model_text": query
                                    }
                                }
                            }
                        },
                        "inner_hits": {
                            "size": 2,
                            "name": "book_alice.content",
                            "_source": [
                                "content.inference.chunks.text"
                            ]
                        }
                    }
                }
            }
        },
        "size": 3
    }
    result = es_client.search(index="book_alice", body=es_query)
    return result["hits"]["hits"]

def create_openai_prompt(results):
    context = ""
    for hit in results:
        inner_hit_path = f"{hit['_index']}.{index_source_fields.get(hit['_index'])[0]}"
        ## For semantic_text matches, we need to extract the text from the inner_hits
        if 'inner_hits' in hit and inner_hit_path in hit['inner_hits']:
            context += '\n --- \n'.join(inner_hit['_source']['text'] for inner_hit in hit['inner_hits'][inner_hit_path]['hits']['hits'])
        else:
            source_field = index_source_fields.get(hit["_index"])[0]
            hit_context = hit["_source"][source_field]
            context += f"{hit_context}\n"
    prompt = f"""
  Instructions:
  
  - You are an assistant for question-answering tasks using relevant text passages from the book Alice in wonderland
  - Answer questions truthfully and factually using only the context presented.
  - If you don't know the answer, just say that you don't know, don't make up an answer.
  - You must always cite the document where the answer was extracted using inline academic citation style [], using the position.
  - Use markdown format for code examples.
  - You are correct, factual, precise, and reliable.
  
  Context:
  {context}
  
  """
    return prompt

# def generate_openai_completion(user_prompt, question):
#     response = openai_client.chat.completions.create(
#         model="gpt-3.5-turbo",
#         messages=[
#             {"role": "system", "content": user_prompt},
#             {"role": "user", "content": question},
#         ]
#     )
#     return response.choices[0].message.content

def generate_openai_completion(user_prompt, question):
    response = openai_client.chat.completions.create(
        model='qwen/qwen3-32b',
        messages=[
            {"role": "system", "content": user_prompt},
            {"role": "user", "content": question},
        ],
        stream=False
    )
    return response.choices[0].message.content

if __name__ == "__main__":
    # question = "Who was at the tea party?"
    question = "哪些人在茶会?"
    print("Question is: ", question, "\n")

    elasticsearch_results = get_elasticsearch_results(question)
    context_prompt = create_openai_prompt(elasticsearch_results)
    openai_completion = generate_openai_completion(context_prompt, question)
    print(openai_completion)

注意:根据使用的版本不同,get_elasticsearch_results 的实现可能会有不同。这个是由于最新的版本中 semantic_text 被分片的部分不再在 _source 中显示。

我们运行上面的代码:

python alice_qwen3.py
$ pwd
/Users/liuxg/python/alice
$ python alice_qwen3.py 
Question is:  哪些人在茶会? 

<think>
好的,我现在需要回答用户的问题:“哪些人在茶会?”根据提供的上下文文本,我得先仔细看看里面提到了哪些角色。

首先,在对话中出现了“Hatter”(帽匠)、“March Hare”(三月兔)和“Alice”(爱丽丝)。他们正在举行一个茶会。用户的问题是问哪些人参加了这个茶会,所以我需要确认这三个角色是否都在场。

接下来,在文本中帽匠和三月兔正在与爱丽丝对话。例如,帽匠说:“Is that the reason so many tea-things are put out here?” 而三月兔则邀请爱丽丝喝葡萄酒(虽然实际上没有酒),并和她争执。此外,还有提到“Dormouse”(睡鼠)在背景中打鼾,并且当帽匠讲述故事时,它摇晃自己并开始睡觉唱歌。虽然睡鼠可能没有直接参与对话很多,但它确实在茶会的场景中出现过。

例如,在文本中有这样一句话:“Here the Dormouse shook itself, and began singing in its sleep”,这说明睡鼠也在现场。所以茶会上至少有帽匠、三月兔、爱丽丝和睡鼠这四个角色。

需要注意的是,有没有其他角色?比如女王或者其他动物?根据提供的上下文,并没有提到其他人或动物参与茶会,所以应该只有这四个角色。因此,答案应该是帽匠、三月兔、爱丽丝和睡鼠。
</think>

在茶会中出现的人物包括:帽匠(the Hatter)、三月兔(March Hare)、爱丽丝(Alice)以及睡鼠(Dormouse)。具体场景中,帽匠与三月兔正在与爱丽丝对话,并围绕“茶会”展开互动。例如,帽匠提到“总是下午六点”,并解释他们为何无法清理茶具;三月兔则邀请爱丽丝喝酒(尽管实际上并未提供酒)[]。同时,睡鼠在背景中沉睡,并因唱“Twinkle, twinkle”而被提到[]。

此外,虽然未直接参与对话,但通过帽匠的叙述可知女王的心(Queen of Hearts)亦与茶会事件相关,因其曾在“音乐会”中因不满表演而怒吼“砍头”[]。不过女王本人并未实际出现在茶会现场的对话中,因此主要角色仍为上述四人

很显然, Qwen3 给出了我们想要的答案!

祝大家使用 Qwen3 愉快!

更多阅读:Elasticsearch:在 Elastic 中玩转 DeepSeek R1 来实现 RAG 应用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值