📘 **TELUS Agriculture & Consumer Goods** 如何通过 **Haystack Agents** 转变促销交易

使用 Haystack 和 Cohere 进行多语言生成式问答

使用 Cohere 模型和 Haystack 为多语言酒店评论构建 RAG 管道

在当今互联互通的世界中,语言不应成为获取信息的障碍。这在旅行领域尤为重要,因为旅行者经常依靠评论来就住宿做出明智的决定(我知道我就是这样)。但是,如果您是一位说英语的旅行者,正在试图理解用多种语言写成的评论,并且只想知道:“这个地方是不是太吵了,睡不着?”

在这篇博文中,我们将深入探讨多语言检索和多语言生成的细节,并演示如何使用 Cohere 模型和 Haystack 构建一个 **检索增强生成 (RAG)** 管道,以从多语言酒店评论中生成答案。

本文附带一个 Colab 笔记本

多语言嵌入

通常,嵌入模型通过词语的语义相似性来创建词嵌入。这意味着“King”和“Queen”的嵌入在向量空间中应该比“King”和“Bread”更接近。然而,大多数这些嵌入模型是为单一语言设计的,无法捕捉不同语言单词之间的语义相似性。

Monolingual Embedding Models
单语嵌入模型

另一方面,多语言嵌入模型被训练用于捕捉跨语言单词之间的语义相似性。它们可以为“King”、“König”(德语中的“king”)和“Kral”(土耳其语中的“king”)创建相似的嵌入。多语言模型这种卓越的能力使得检索文档成为可能,而无需考虑文档或查询所用的语言。

Multilingual Embedding Models
多语言嵌入模型

Cohere 的多语言嵌入模型是尖端技术,旨在处理多种语言的文本。这些嵌入使模型能够理解西班牙语、法语、德语等语言的文本语义,同时为高效的跨语言分析提供一致的表示。

让我们使用 embed-multilingual-v2.0 模型来创建酒店评论的嵌入,看看这些模型是如何工作的。

存储多语言嵌入

要创建酒店评论的问答系统,我们需要的第一样东西是文档存储。我们将使用 InMemoryDocumentStore 来保存酒店评论及其嵌入。

from haystack.document_stores import InMemoryDocumentStore

document_store = InMemoryDocumentStore(embedding_dim=768, similarity= "dot_product")

创建索引管道

接下来,我们将设置一个包含 PreProcessorEmbeddingRetriever 的索引管道。PreProcessor 将长篇评论分解成更小的、有意义的块,而 EmbeddingRetriever 将为每个文档生成多语言嵌入。

我们将在 EmbeddingRetriever 中使用 Cohere 的 embed-multilingual-v2.0 模型。您需要此模型的 Cohere API 密钥,可以在 此处 获得。

from haystack.nodes import EmbeddingRetriever, PreProcessor
from haystack.pipelines import Pipeline

preprocessor = PreProcessor(
    clean_empty_lines=True,
    clean_whitespace=False,
    clean_header_footer=True,
    split_by="word",
    split_length=200,
    split_respect_sentence_boundary=True,
)
retriever = EmbeddingRetriever(
    embedding_model="embed-multilingual-v2.0", 
    document_store=document_store,
    api_key=COHERE_API_KEY
)

indexing_pipeline = Pipeline()
indexing_pipeline.add_node(component=preprocessor, name="preprocessor", inputs=["File"])
indexing_pipeline.add_node(component=retriever, name="retriever", inputs=["preprocessor"])
indexing_pipeline.add_node(component=document_store, name="document_store", inputs=['retriever'])

使用嵌入索引评论

我们的索引管道已准备就绪。我们将使用多种语言的酒店评论作为文档,包括葡萄牙语、波兰语、德语、西班牙语、法语、荷兰语和英语。所有这些评论都属于同一家住宿。让我们通过运行管道来索引这些评论。

documents = [Document("O ar condicionado de um dos quartos deu problema, mas levaram um ventilador para ser utilizado. Também por ser em uma área bem movimentada, o barulho da rua pode ser ouvido. Porém, eles deixam protetores auriculares para o uso. Também senti falta de um espelho de corpo inteiro no apartamento. Só havia o do banheiro que mostra apenas a parte superior do corpo."),
             Document("Durchgängig Lärm, weil direkt an der Partymeile; schmutziges Geschirr; unvollständige Küchenausstattung; Abzugshaube über Herd ging für zwei Stunden automatisch an und lies sich nicht abstellen; Reaktionen auf Anfragen entweder gar nicht oder unfreundlich"),
             Document("Das Personal ist sehr zuvorkommend! Über WhatsApp war man im guten Kontakt und konnte alles erfragen. Auch das Angebot des Shuttleservices war super und würde ich empfehlen - sehr unkompliziert! Unser Flug hatte Verspätung und der Shuttle hat auf uns gewartet. Die Lage zur Innenstadt ist sehr gut,jedoch ist die Fensterfront direkt zur Club-Straße deshalb war es nachts bis drei/vier Uhr immer recht laut. Die Kaffeemaschine oder auch die Couch hätten sauberer sein können. Ansonsten war das Appartement aber völlig ok."),
             Document("Super appartement. Juste au dessus de plusieurs bars qui ferment très tard. A savoir à l'avance. (Bouchons d'oreilles fournis !)"),
             Document("Zapach moczu przy wejściu do budynku, może warto zainstalować tam mocne światło na czujnik ruchu, dla gości to korzystne a dla kogoś kto chciałby zrobić tam coś innego niekorzystne :-). Świetne lokalizacje w centrum niestety są na to narażane."),
             Document("El apartamento estaba genial y muy céntrico, todo a mano. Al lado de la librería Lello y De la Torre de los clérigos. Está situado en una zona de marcha, así que si vais en fin de semana , habrá ruido, aunque a nosotros no nos molestaba para dormir"),
             Document("The keypad with a code is convenient and the location is convenient. Basically everything else, very noisy, wi-fi didn't work, check-in person didn't explain anything about facilities, shower head was broken, there's no cleaning and everything else one may need is charged."),
             Document("It is very central and appartement has a nice appearance (even though a lot IKEA stuff), *W A R N I N G** the appartement presents itself as a elegant and as a place to relax, very wrong place to relax - you cannot sleep in this appartement, even the beds are vibrating from the bass of the clubs in the same building - you get ear plugs from the hotel -> now I understand why -> I missed a trip as it was so loud and I could not hear the alarm next day due to the ear plugs.- there is a green light indicating 'emergency exit' just above the bed, which shines very bright at night - during the arrival process, you felt the urge of the agent to leave as soon as possible. - try to go to 'RVA clerigos appartements' -> same price, super quiet, beautiful, city center and very nice staff (not an agency)- you are basically sleeping next to the fridge, which makes a lot of noise, when the compressor is running -> had to switch it off - but then had no cool food and drinks. - the bed was somehow broken down - the wooden part behind the bed was almost falling appart and some hooks were broken before- when the neighbour room is cooking you hear the fan very loud. I initially thought that I somehow activated the kitchen fan"),
             Document("Un peu salé surtout le sol. Manque de service et de souplesse"),
             Document("De comfort zo centraal voor die prijs."),
             Document("Die Lage war sehr Zentral und man konnte alles sehenswertes zu Fuß erreichen. Wer am Wochenende nachts schlafen möchte, sollte diese Unterkunft auf keinen Fall nehmen. Party direkt vor der Tür so das man denkt, man schläft mitten drin. Sehr Sehr laut also und das bis früh 5 Uhr. Ab 7 kommt dann die Straßenreinigung die keineswegs leiser ist."),
             Document("Ótima escolha! Apartamento confortável e limpo! O RoofTop é otimo para beber um vinho! O apartamento é localizado entre duas ruas de movimento noturno. Porem as janelas, blindam 90% do barulho. Não nos incomodou"),
             Document("Nous avons passé un séjour formidable. Merci aux personnes , le bonjours à Ricardo notre taxi man, très sympathique. Je pense refaire un séjour parmi vous, après le confinement, tout était parfait, surtout leur gentillesse, aucune chaude négative. Je n'ai rien à redire de négative, Ils étaient a notre écoute, un gentil message tout les matins, pour nous demander si nous avions besoins de renseignement et savoir si tout allait bien pendant notre séjour."),
             Document("Boa localização. Bom pequeno almoço. A tv não se encontrava funcional."),
             Document("Céntrico. Muy cómodo para moverse y ver Oporto. Edificio con terraza propia en la última planta. Todo reformado y nuevo. Te traen un estupendo desayuno todas las mañanas al apartamento. Solo que se puede escuchar algo de ruido de la calle a primeras horas de la noche. Es un zona de ocio nocturno. Pero respetan los horarios.")
]

indexing_pipeline.run(documents=documents)

检索增强生成 (RAG)

现在,我们已经在文档存储中索引了多语言嵌入,让我们来创建用户互动最多的部分:检索增强生成 (RAG) 管道。

RAG 管道由两部分组成:文档检索和答案生成。

多语言文档检索

在 RAG 管道的文档检索步骤中,检索器会在多语言向量空间中为查询创建一个嵌入,并从文档存储中检索与查询最相似的 top_k 个文档。在我们的例子中,检索到的文档将是酒店评论。

我们将使用与索引管道中相同的 EmbeddingRetriever 实例。

Retrieval Mechanism with Document Store
带文档存储的检索机制

多语言答案生成

在 RAG 管道的生成步骤中,我们将使用 LLM(一个生成模型)根据检索到的文档生成答案。

让我们为酒店评论创建一个提示模板。在这个模板中,我们将有两个提示变量:{join(documents)}{query}。这些变量稍后将用用户的问题和从检索器输出的酒店评论填充。

from haystack.nodes import AnswerParser, PromptTemplate

prompt="""
You will be provided with reviews in various languages for an accommodation. 
Create a concise and informative answer for a given question based solely on the given reviews.
\nReviews: {join(documents)}
\nQuestion: {query};
\nAnswer:
"""
template = PromptTemplate(
    prompt=prompt,
    output_parser=AnswerParser())

定义 PromptTemplate 后,我们需要定义 PromptNode。对于这个生成场景,我们将使用 Cohere 的 command 模型,并使用 API 密钥、模型名称以及我们之前定义的 PromptTemplate 来初始化 PromptNode。然后,我们将 EmbeddingRetriever 连接到 PromptNode,以完成我们的 RAG 管道。

prompt_node = PromptNode(model_name_or_path="command", api_key=COHERE_API_KEY, default_prompt_template=template)

rag_pipeline = Pipeline()
rag_pipeline.add_node(component=retriever, name="Retriever", inputs=["Query"])
rag_pipeline.add_node(component=prompt_node, name="PromptNode", inputs=["Retriever"])  

现在我们可以使用各种问题运行管道,并了解这家住宿是否适合入住!🏡

results = rag_pipeline.run("Is this place too noisy to sleep?", params={"Retriever": {"top_k": 3}})
print(results["answers"][0].answer)

>> "Based on the information provided in the reviews, it seems that the accommodation can be very noisy, especially at night. Multiple reviewers mentioned..."

要了解更多关于如何在 Haystack 管道中使用 Cohere 模型的信息,请查看我们的 Cohere 集成页面🩵