• 文章
  • Question Answering as a Service with Cohere and Qdrant
返回实用示例

使用Cohere和Qdrant的问答服务

Kacper Łukawski

·

2022年11月29日

Question Answering as a Service with Cohere and Qdrant

双编码器可能是建立语义问答系统的最有效方法。 这种架构依赖于相同的神经模型,该模型为问题和答案创建向量嵌入。 假设是,问题和答案在潜在空间中应该有接近彼此的表示。 应该是这样的,因为它们应该都描述相同的语义概念。然而,这不适用于像“是”或“否”这样的答案,但标准的常见问题类问题稍微容易一些,因为这两种文本之间通常存在重叠。 不一定是用词方面,但在其语义上。

Bi-encoder structure. Both queries (questions) and documents (answers) are vectorized by the same neural encoder.
Output embeddings are then compared by a chosen distance function, typically cosine similarity.

是的,你需要自带嵌入,才能开始。获取它们的方法有很多,但使用 Cohere co.embed API 可能是最简单和最方便的方法。

为什么co.embed API和Qdrant非常契合?

维护一个大型语言模型可能很困难且成本高昂。当流量变化时,扩展和缩减需要更多的努力,并且变得不可预测。这可能绝对成为任何语义搜索系统的障碍。但如果您想立即开始,可以考虑使用SaaS模型,尤其是Cohere的co.embed API。它提供了作为高度可用HTTP服务的最先进的语言模型,不需要训练或维护自己的服务。由于所有通信都是通过JSON进行的,您可以简单地将co.embed的输出作为Qdrant的输入。

# Putting the co.embed API response directly as Qdrant method input
qdrant_client.upsert(
    collection_name="collection",
    points=rest.Batch(
        ids=[...],
        vectors=cohere_client.embed(...).embeddings,
        payloads=[...],
    ),
)

这两种工具易于结合,因此您可以在几分钟内开始使用语义搜索,而不是几天。

如果您的需求如此特殊,以至于您需要微调通用使用模型怎么办?Co.embed API 超越了预训练编码器,并允许提供一些自定义数据集来 使用您的数据自定义嵌入模型。结果是,您获得了特定领域模型的质量,但无需担心基础设施。

系统架构概述

在实际系统中,答案被向量化并存储在高效的向量搜索数据库中。我们通常甚至不需要提供具体的答案,只需使用句子或段落的文本并将其向量化即可。不过,如果一段稍长的文本包含特定问题的答案,那么它与问题嵌入的距离应该不会太远。并且肯定比所有其他不匹配的答案更接近。将答案嵌入存储在向量数据库中使搜索过程变得更加容易。

Building the database of possible answers. All the texts are converted into their vector embeddings and those
embeddings are stored in a vector database, i.e. Qdrant.

寻找正确的答案

一旦我们的数据库正常工作,所有的答案嵌入也都到位,我们就可以开始查询了。 我们基本上对给定的问题执行相同的向量化,并请求数据库提供一些近邻。 我们依赖于嵌入彼此之间的接近,因此我们期望在潜在空间中距离最小的点包含正确的答案。

While searching, a question gets vectorized by the same neural encoder. Vector database is a component that looks
for the closest answer vectors using i.e. cosine similarity. A proper system, like Qdrant, will make the lookup
process more efficient, as it won’t calculate the distance to all the answer embeddings. Thanks to HNSW, it will
be able to find the nearest neighbours with sublinear complexity.

使用SaaS工具实现QA搜索系统

我们不想为神经编码器维护自己的服务,也不想设置一个Qdrant实例。针对这两者都有SaaS解决方案 - Cohere的 co.embed APIQdrant Cloud,因此我们将使用它们,而不是本地工具。

生物医学数据问答

我们将为生物医学数据实施问答系统。这里有一个 pubmed_qa 数据集,其中 pqa_labeled 子集包含 1,000 个由领域专家标记的问题和答案示例。我们的系统将使用 co.embed API 生成的嵌入,并将其加载到 Qdrant。使用 Qdrant Cloud 与您自己的实例在这里并没有太大区别。连接到云实例的方式有细微差别,但所有其他操作都以相同方式执行。

from datasets import load_dataset

# Loading the dataset from HuggingFace hub. It consists of several columns: pubid, 
# question, context, long_answer and final_decision. For the purposes of our system, 
# we’ll use question and long_answer.
dataset = load_dataset("pubmed_qa", "pqa_labeled")
pubid问题上下文长答案最终决定
18802997钙保护素能否预测炎症性肠病复发风险…测量钙保护素可能有助于识别溃疡性结肠炎…可能
20538207应在肾脏…期间监测温度吗新的存储可以提供更稳定的温度…
25521278清盘是否是肥胖的危险因素?在进食时清空盘子的倾向 …
17595200子宫内对肥胖有影响吗?母子与父子比较..
15280782在HIV患者中不安全性行为是否在增加…没有证据表明不安全性行为的趋势…没有

使用Cohere和Qdrant构建答案数据库

为了开始生成嵌入,您需要创建一个Cohere帐户。这将开始您的试用期,因此您将能够免费将文本向量化。登录后,您的默认API密钥将在设置中提供。我们将需要它来调用co.embed API,使用官方的python包。

import cohere

cohere_client = cohere.Client(COHERE_API_KEY)

# Generating the embeddings with Cohere client library
embeddings = cohere_client.embed(
    texts=["A test sentence"],
    model="large",
)
vector_size = len(embeddings.embeddings[0])
print(vector_size) # output: 4096

首先让我们连接到 Qdrant 实例,并创建一个具有适当配置的集合,以便我们稍后可以将一些嵌入放入其中。

# Connecting to Qdrant Cloud with qdrant-client requires providing the api_key.
# If you use an on-premise instance, it has to be skipped.
qdrant_client = QdrantClient(
    host="xyz-example.eu-central.aws.cloud.qdrant.io", 
    prefer_grpc=True,
    api_key=QDRANT_API_KEY,
)

现在我们能够将所有的答案向量化。它们将形成我们的集合,因此我们也可以将它们与有效负载和标识符一起放入Qdrant。这将使我们的数据集易于搜索。

answer_response = cohere_client.embed(
    texts=dataset["train"]["long_answer"],
    model="large",
)
vectors = [
    # Conversion to float is required for Qdrant
    list(map(float, vector)) 
    for vector in answer_response.embeddings
]
ids = [entry["pubid"] for entry in dataset["train"]]

# Filling up Qdrant collection with the embeddings generated by Cohere co.embed API
qdrant_client.upsert(
    collection_name="pubmed_qa", 
    points=rest.Batch(
        ids=ids,
        vectors=vectors,
        payloads=list(dataset["train"]),
    )
)

就这样。在我们自己的服务器上甚至没有设置一个,我们创建了一个系统,可以轻松地被问到问题。我不想称之为无服务器,因为这个术语已经被使用,但 co.embed API 与 Qdrant Cloud 使一切更易于维护。

通过语义搜索回答问题——质量

现在是时候用一些问题查询我们的数据库了。以某种方式衡量系统的整体质量可能是有趣的。 在这类问题中,我们通常使用 top-k 准确率。我们假设如果正确答案 出现在前 k 个结果中,则系统的预测是正确的。

# Finding the position at which Qdrant provided the expected answer for each question. 
# That allows to calculate accuracy@k for different values of k.
k_max = 10
answer_positions = []
for embedding, pubid in tqdm(zip(question_response.embeddings, ids)):
    response = qdrant_client.search(
        collection_name="pubmed_qa",
        query_vector=embedding,
        limit=k_max,
    )

    answer_ids = [record.id for record in response]
    if pubid in answer_ids:
        answer_positions.append(answer_ids.index(pubid))
    else:
        answer_positions.append(-1)

保存的答案位置使我们能够计算不同k值的指标。

# Prepared answer positions are being used to calculate different values of accuracy@k
for k in range(1, k_max + 1):
    correct_answers = len(
        list(
            filter(lambda x: 0 <= x < k, answer_positions)
        )
    )
    print(f"accuracy@{k} =", correct_answers / len(dataset["train"]))

以下是不同 k 值的 top-k 准确率:

指标
准确率@10.877
准确率@20.921
准确率@30.942
准确率@40.950
准确率@50.956
准确率@60.960
准确率@70.964
准确率@80.971
精确度@90.976
准确率@100.977

即使我们仅考虑第一个结果,系统似乎也表现得相当不错,距离是最小的。我们大约在 12% 的问题上失败了。但随着 k 值的提高,数字变得更好。检查我们的系统未能回答的问题、它们的完美匹配和我们的猜测也可能很有价值。

我们成功地在仅仅几行代码内实现了一个有效的问答系统。如果您对所取得的结果满意,那么您可以立即开始使用它。不过,如果您觉得还需要稍微改进,那么微调模型是一个不错的选择。如果您想查看完整的源代码,它可以在谷歌Colab上找到。

这个页面有用吗?

感谢您的反馈!🙏

我们很遗憾听到这个消息。 😔 你可以 编辑 这个页面在 GitHub上,或者 create 一个 GitHub 问题。