-- 知识铺
将自然语言理解添加到任何应用程序
[
](https://.com/@davidmezzetti?source=post_page—–c721f4ff91ad——————————–)[
](https://.com/neuml?source=post_page—–c721f4ff91ad——————————–)
搜索是许多应用程序的基础。一旦数据开始堆积,用户希望能够找到它。这是互联网的基础,也是一个从未解决或完成的日益增长的挑战。
自然语言处理(NLP)领域正在迅速发展,出现了许多新的发展。大规模通用语言模型是一种令人兴奋的新功能,允许我们添加令人惊叹的功能。
创新继续与新的模式和进步来在什么似乎每周的基础。
本文介绍了txtai,这是一个一体化的嵌入式数据库,可以在任何应用程序中实现基于自然语言理解(NLU)的搜索。
关于txtai
txtai是一个用于语义搜索,LLM编排和语言模型工作流的一体化嵌入数据库。
嵌入式数据库是向量索引(稀疏和密集)、图网络和关系数据库的结合。这使得向量搜索与SQL,主题建模,检索增强生成和更多。
嵌入式数据库可以独立存在和/或作为大型语言模型(LLM)提示的强大知识源。
以下是主要功能的摘要:
- 🔎使用SQL的向量搜索、对象存储、主题建模、图分析和多模式索引
- 📄为文本、文档、音频、图像和视频创建嵌入
- 💡由语言模型驱动的管道,运行LLM提示,问答,标记,转录,翻译,摘要等
- ️️将管道连接在一起并聚合业务逻辑的工作流程。txtai流程可以是简单的微服务或多模型工作流。
- 使用Python或YAML编译。️API绑定可用于JavaScript、Java、Rust和Go。
- ️使用容器编排运行本地或横向扩展
txtai使用Python 3.9+、Hugging Face Transformers、Sentence Transformers和FastAPI构建。txtai是根据Apache 2.0许可证开源的。
安装并运行txtai
txtai可以通过pip或Docker安装。下面介绍如何通过pip安装。
<span id="2b16" data-selectable-paragraph="">pip install txtai
语义搜索
嵌入式数据库是提供语义搜索的引擎。数据被转换为嵌入向量,其中相似的概念将产生相似的向量。大的和小的索引都是用这些向量构建的。
索引用于查找具有相同含义的结果,而不一定是相同的关键字。
嵌入式数据库的基本用例是构建用于语义搜索的近似最近邻(ANN)索引。下面的示例对少量文本条目进行索引,以演示语义搜索的价值。
<span id="b370" data-selectable-paragraph="">from txtai import Embeddings
data = [
"US tops 5 million confirmed virus cases",
"Canada's last fully intact ice shelf has suddenly collapsed, forming a Manhattan-sized iceberg",
"Beijing mobilises invasion craft along coast as Taiwan tensions escalate",
"The National Park Service warns against sacrificing slower friends in a bear attack",
"Maine man wins $1M from $25 lottery ticket",
"Make huge profits without work, earn up to $100,000 a day"
]
embeddings = Embeddings(path="sentence-transformers/nli-mpnet-base-v2")
embeddings.index(data)
print("%-20s %s" % ("Query", "Best Match"))
print("-" * 50)
for query in ("feel good story", "climate change",
"public health story", "war", "wildlife", "asia",
"lucky", "dishonest junk"):
uid = embeddings.search(query, 1)[0][0]
print("%-20s %s" % (query, data[uid]))
上面的例子表明,对于所有查询,查询文本都不在数据中。这是transformers模型在基于令牌的搜索上的真正力量。你从盒子里拿出来的是什么?🔥🔥🔥
更新和删除
嵌入支持更新和删除。upsert操作将插入新数据并更新现有数据
下一节运行一个查询,然后更新一个值,更改顶部结果,最后删除更新后的值以恢复到原始查询结果。
<span id="6691" data-selectable-paragraph="">
uid = embeddings.search("feel good story", 1)[0][0]
print("Initial: ", data[uid])
udata = data.copy()
udata[0] = "See it: baby panda born"
embeddings.upsert([(0, udata[0], None)])
uid = embeddings.search("feel good story", 1)[0][0]
print("After update: ", udata[uid])
embeddings.delete([0])
uid = embeddings.search("feel good story", 1)[0][0]
print("After delete: ", udata[uid])
<span id="c9e4" data-selectable-paragraph="">Initial: Maine man wins $1M from $25 lottery ticket
After update: See it: baby panda born
After delete: Maine man wins $1M from $25 lottery ticket
持久性
嵌入可以保存到存储中并重新加载。
<span id="cb1e" data-selectable-paragraph="">embeddings.save("index")
embeddings = Embeddings()
embeddings.load("index")
uid = embeddings.search("climate change", 1)[0][0]
print(data[uid])
<span id="c76e" data-selectable-paragraph="">Canada's last fully intact ice shelf has suddenly collapsed, forming a
Manhattan-sized iceberg
混合搜索
虽然密集向量索引是语义搜索系统的最佳选择,但稀疏关键字索引仍然可以增加价值。在某些情况下,找到精确的匹配很重要。
混合搜索结合了稀疏和密集向量索引的结果,以达到两全其美。
<span id="ac46" data-selectable-paragraph="">
embeddings = Embeddings(
hybrid=True,
path="sentence-transformers/nli-mpnet-base-v2"
)
embeddings.index(data)
print("%-20s %s" % ("Query", "Best Match"))
print("-" * 50)
for query in ("feel good story", "climate change",
"public health story", "war", "wildlife", "asia",
"lucky", "dishonest junk"):
uid = embeddings.search(query, 1)[0][0]
print("%-20s %s" % (query, data[uid]))
结果与语义搜索相同。让我们运行相同的示例,只使用关键字索引来查看这些结果。
<span id="4864" data-selectable-paragraph="">
embeddings = Embeddings(keyword=True)
embeddings.index(data)
print(embeddings.search("feel good story"))
print(embeddings.search("lottery"))
<span id="c1f1" data-selectable-paragraph="">[]
[(4, 0.5234998733628726)]
请注意,当嵌入实例只使用关键字索引时,它无法找到语义匹配,只能找到关键字匹配。
内容存储
到目前为止,所有示例都引用原始数据数组来检索输入文本。这对于演示来说很好,但如果你有数百万个文档呢?在这种情况下,需要使用id从外部数据库检索文本。
内容存储添加了一个关联的数据库(即SQLite,DuckDB),该数据库存储与矢量索引相关联的元数据。文档文本、附加元数据和附加对象可以与索引向量一起存储和检索。
<span id="00f0" data-selectable-paragraph="">
embeddings = Embeddings(
path="sentence-transformers/nli-mpnet-base-v2",
content=True,
objects=True
)
embeddings.index(data)
print(embeddings.search("feel good story", 1)[0]["text"])
<span id="1c0a" data-selectable-paragraph="">Maine man wins $1M from $25 lottery ticket
上面唯一的变化是将_内容_标志设置为True。这样就可以在索引旁边存储文本和元数据内容(如果提供)。注意文本是如何从查询结果中直接提取出来的!
让我们添加一些元数据。
使用SQL查询
启用内容后,整个词典将被存储并可以查询。除了向量查询,txtai还接受SQL查询。这使得可以使用矢量索引和存储在数据库后端的内容进行组合查询。
<span id="6e49" data-selectable-paragraph="">
embeddings.index([{"text": text, "length": len(text)} for text in data])
print(embeddings.search("select text, score from txtai where similar('hiking danger') and score >= 0.15"))
print(embeddings.search("select text, length, score from txtai where similar('feel good story') and score >= 0.05 and length >= 40"))
print(embeddings.search("select count(*), min(length), max(length), sum(length) from txtai"))
<span id="647c" data-selectable-paragraph="">[{'text': 'The National Park Service warns against sacrificing slower friends in a bear attack', 'score': 0.3151373863220215}]
[{'text': 'Maine man wins $1M from $25 lottery ticket', 'length': 42, 'score': 0.08329027891159058}]
[{'count(*)': 6, 'min(length)': 39, 'max(length)': 94, 'sum(length)': 387}]
上面的这个例子添加了一个简单的附加字段,文本长度。
请注意,第二个查询是根据元数据字段长度进行过滤的,沿着带有一个类似的
查询子句。这提供了矢量搜索与传统过滤的完美结合,以帮助识别最佳结果。
对象存储
除了元数据之外,二进制内容也可以与文档相关联。下面的例子下载了一个图像,并将其与相关的文本一起沿着到嵌入索引中。
<span id="5021" data-selectable-paragraph="">import urllib
from IPython.display import Image
request = urllib.request.urlopen("https://raw.githubusercontent.com/neuml/txtai/master/demo.gif")
embeddings.upsert([("txtai", {"text": "txtai executes machine-learning workflows to transform data and build AI-powered semantic search applications.", "object": request.read()}, None)])
result = embeddings.search("select object from txtai where similar('machine learning') limit 1")[0]["object"]
Image(result.getvalue(), width=600)
主题建模
通过语义图启用主题建模。语义图,也称为知识图或语义网络,构建具有连接节点的语义关系的图网络。
在txtai中,它们可以利用嵌入索引中固有的关系。
<span id="b31b" data-selectable-paragraph="">
embeddings = Embeddings(
path="sentence-transformers/nli-mpnet-base-v2",
content=True,
functions=[
{"name": "graph", "function": "graph.attribute"},
],
expressions=[
{"name": "category", "expression": "graph(indexid, 'category')"},
{"name": "topic", "expression": "graph(indexid, 'topic')"},
],
graph={
"topics": {
"categories": ["health", "climate", "finance", "world politics"]
}
}
)
embeddings.index(data)
embeddings.search("select topic, category, text from txtai")
<span id="d0fb" data-selectable-paragraph="">[{'topic': 'confirmed_cases_us_5',
'category': 'health',
'text': 'US tops 5 million confirmed virus cases'},
{'topic': 'collapsed_iceberg_ice_intact',
'category': 'climate',
'text': "Canada's last fully intact ice shelf has suddenly collapsed, forming a Manhattan-sized iceberg"},
{'topic': 'beijing_along_craft_tensions',
'category': 'world politics',
'text': 'Beijing mobilises invasion craft along coast as Taiwan tensions escalate'}]
当启用图形索引时,将为嵌入实例中的每个条目分配主题。主题是动态创建的,使用稀疏索引在社区检测算法分组的图节点上。
主题类别也可以如上所示导出。
子索引
可以为嵌入配置子索引。一个嵌入实例可以有多个子索引,每个子索引都有不同的配置。
我们将构建一个同时包含关键字和密集索引的嵌入索引来演示。
<span id="20bf" data-selectable-paragraph="">
embeddings = Embeddings(
content=True,
defaults=False,
indexes={
"keyword": {
"keyword": True
},
"dense": {
"path": "sentence-transformers/nli-mpnet-base-v2"
}
}
)
embeddings.index(data)
<span id="04dc" data-selectable-paragraph="">embeddings.search("feel good story", limit=1, index="keyword")
<span id="aa57" data-selectable-paragraph="">[]
<span id="7015" data-selectable-paragraph="">embeddings.search("feel good story", limit=1, index="dense")
<span id="63a1" data-selectable-paragraph="">[{'id': '4',
'text': 'Maine man wins $1M from $25 lottery ticket',
'score': 0.08329027891159058}]
这个例子再次展示了关键字搜索和语义搜索的区别。第一个搜索调用使用定义的关键字索引,第二个使用密集向量索引。
LLMorchestration
txtai是一个多合一的嵌入式数据库。它是唯一一个还支持稀疏索引、图网络和具有内联SQL支持的关系数据库的矢量数据库。除此之外,txtai还支持LLM编排。
RAG管道是txtai的检索增强生成(RAG)。该管道通过将提示、上下文数据存储和生成模型结合在一起来从内容中提取知识。
下面的示例展示了大型语言模型(LLM)如何使用嵌入数据库作为上下文。
<span id="899f" data-selectable-paragraph="">import torch
from txtai import RAG
def prompt(question):
return [{
"query": question,
"question": f"""
Answer the following question using the context below.
Question: {question}
Context:
"""
}]
embeddings = Embeddings(
path="sentence-transformers/nli-mpnet-base-v2",
content=True,
autoid="uuid5"
)
embeddings.index(data)
rag = RAG(
embeddings,
"google/flan-t5-large",
torch_dtype=torch.bfloat16,
output="reference"
)
rag(prompt("What country is having issues with climate change?"))[0]
<span id="124c" data-selectable-paragraph="">{'answer': 'Canada', 'reference': 'da633124-33ff-58d6-8ecb-14f7a44c042a'}
上面的逻辑首先构建一个嵌入索引。然后加载LLM并使用嵌入索引驱动LLM提示符。
RAG流水线可以选择性地返回对与答案最匹配的记录的id的引用。该id可用于解析完整的答案引用。请注意,上面的嵌入使用了uuid自动序列。
<span id="6af4" data-selectable-paragraph="">uid = rag(prompt("What country is having issues with climate change?"))[0]["reference"]
embeddings.search(f"select id, text from txtai where id = '{uid}'")
<span id="6c50" data-selectable-paragraph="">[{'id': 'da633124-33ff-58d6-8ecb-14f7a44c042a',
'text': "Canada's last fully intact ice shelf has suddenly collapsed, forming a Manhattan-sized iceberg"}]
LLM推理也可以独立运行。
<span id="780e" data-selectable-paragraph="">from txtai import LLM
llm = LLM("google/flan-t5-large", torch_dtype=torch.bfloat16)
llm("Where is one place you'd go in Washington, DC?")
<span id="e49a" data-selectable-paragraph="">national museum of american history
语言模型工作流
语言模型工作流,也称为语义工作流,将语言模型连接在一起以构建智能应用程序。
工作流可以与嵌入实例一起运行,类似于关系数据库中的存储过程。工作流程可以用Python或YAML编写。我们将演示如何使用YAML编写工作流。
<span id="e323" data-selectable-paragraph="">
writable: true
embeddings:
path: sentence-transformers/nli-mpnet-base-v2
content: true
functions:
- {name: translation, argcount: 2, function: translation}
translation:
workflow:
search:
tasks:
- search
- action: translation
args:
target: fr
task: template
template: "{text}"
上面的工作流加载嵌入索引并定义搜索工作流。搜索工作流运行搜索,然后将结果传递到翻译管道。翻译管道将结果翻译为法语。
<span id="bf54" data-selectable-paragraph="">from txtai import Application
app = Application("embeddings.yml")
app.add(data)
app.index()
list(app.workflow(
"search",
["select text from txtai where similar('feel good story') limit 1"]
))
<span id="d91c" data-selectable-paragraph="">['Maine homme gagne $1M à partir de $25 billet de loterie']
在某些情况下,SQL函数可以完成与工作流相同的任务。下面的函数将翻译管道作为一个函数运行。
<span id="a27a" data-selectable-paragraph="">app.search("select translation(text, 'fr') text from txtai where similar('feel good story') limit 1")
<span id="7692" data-selectable-paragraph="">[{'text': 'Maine homme gagne $1M à partir de $25 billet de loterie'}]
带有模板LLM链也可以使用工作流。工作流是自包含的,它们可以在有或没有相关嵌入实例的情况下运行。以下工作流程使用LLM条件地将文本翻译为法语,然后检测文本的语言。
<span id="7980" data-selectable-paragraph="">sequences:
path: google/flan-t5-large
torch_dtype: torch.bfloat16
workflow:
chain:
tasks:
- task: template
template: Translate '{statement}' to {language} if it's English
action: sequences
- task: template
template: What language is the following text? {text}
action: sequences
<span id="0a8b" data-selectable-paragraph="">inputs = [
{"statement": "Hello, how are you", "language": "French"},
{"statement": "Hallo, wie geht's dir", "language": "French"}
]
app = Application("workflow.yml")
list(app.workflow("chain", inputs))
<span id="2459" data-selectable-paragraph="">['French', 'German']
结束了
NLP正在快速发展。一年前不可能的事情,现在已经成为可能。本文介绍了txtai,一个一体化的嵌入式数据库。可能性是无限的,我们很高兴看到什么可以建立在txtai之上!
请访问下面的链接了解更多信息。
- 原文作者:知识铺
- 原文链接:https://index.zshipu.com/geek002/post/202410/%E4%BB%8B%E7%BB%8Dtxtai%E4%B8%80%E4%BD%93%E5%8C%96%E5%B5%8C%E5%85%A5%E5%BC%8F%E6%95%B0%E6%8D%AE%E5%BA%93%E7%94%B1%E5%A4%A7%E5%8D%ABMezzetti-NeuML%E4%BB%8B%E8%B4%A8---Introducing-txtai-the-all-in-one-embeddings-database-by-David-Mezzetti-NeuML-Medium.md--%E7%9F%A5%E8%AF%86%E9%93%BA/
- 版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可,非商业转载请注明出处(作者,原文链接),商业转载请联系作者获得授权。
- 免责声明:本页面内容均来源于站内编辑发布,部分信息来源互联网,并不意味着本站赞同其观点或者证实其内容的真实性,如涉及版权等问题,请立即联系客服进行更改或删除,保证您的合法权益。转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。也可以邮件至 sblig@126.com