Skip to main content
Open In ColabOpen on GitHub

NVIDIA NIMs

The langchain-nvidia-ai-endpoints 包含 LangChain 组件,用于在 NVIDIA NIM 推断微服务上构建基于模型的应用程序。NIM 支持来自社区以及 NVIDIA 的各个领域(如聊天、嵌入和重排序)的模型。这些模型由 NVIDIA 优化以在 NVIDIA 加速基础设施上提供最佳性能,并部署为一个 NIM,这是一种易于使用的预构建容器,可以在 NVIDIA 加速基础设施上通过单个命令部署到任何位置。

NVIDIA hosted deployments of NIMs are available to test on the NVIDIA API catalog. After testing, NIMs can be exported from NVIDIA’s API catalog using the NVIDIA AI Enterprise license and run on-premises or in the cloud, giving enterprises ownership and full control of their IP and AI application.

NIMs是以单个模型为基础打包为容器镜像,并通过NVIDIA NGC目录分发为NGC容器镜像。 在核心层面,NIMs提供了运行AI模型推理的简单、一致且熟悉的API接口。

该示例介绍了如何通过 NVIDIAEmbeddings 类使用 LangChain 与支持的 NVIDIA 检索式问答嵌入模型 进行交互,以实现检索增强生成

要了解通过此API访问聊天模型的更多信息,请参阅ChatNVIDIA文档。

安装

%pip install --upgrade --quiet  langchain-nvidia-ai-endpoints

设置

要开始使用:

  1. 创建一个免费账户,使用托管NVIDIA AI基础模型的NVIDIA

  2. 选择 Retrieval 标签,然后选择您首选的模型。

  3. Input 下选择 Python 选项卡,然后点击 Get API Key。接着点击 Generate Key

  4. 将生成的密钥复制并保存为NVIDIA_API_KEY。之后,您应该可以访问相关的端点。

import getpass
import os

# del os.environ['NVIDIA_API_KEY'] ## delete key and reset
if os.environ.get("NVIDIA_API_KEY", "").startswith("nvapi-"):
print("Valid NVIDIA_API_KEY already in environment. Delete to reset")
else:
nvapi_key = getpass.getpass("NVAPI Key (starts with nvapi-): ")
assert nvapi_key.startswith("nvapi-"), f"{nvapi_key[:5]}... is not a valid key"
os.environ["NVIDIA_API_KEY"] = nvapi_key

我们应该能够在该列表中看到一个嵌入模型,该模型可与大语言模型(LLM)结合使用,以实现高效的RAG解决方案。我们可以通过NVIDIAEmbeddings类来对接此模型以及NIM支持的其他嵌入模型。

在NVIDIA API目录中使用NIM

初始化嵌入模型时,可以通过传递参数来选择模型,例如下面的 NV-Embed-QA,或者不传递任何参数以使用默认模型。

from langchain_nvidia_ai_endpoints import NVIDIAEmbeddings

embedder = NVIDIAEmbeddings(model="NV-Embed-QA")
API 参考:NVIDIA嵌入

该模型是一个经过微调的 E5-large 模型,支持预期的 Embeddings 方法,包括:

  • embed_query:为查询样本生成查询嵌入。

  • embed_documents:为您想要搜索的一系列文档生成段落嵌入。

  • aembed_query/aembed_documents:以上方法的异步版本。

使用自托管的NVIDIA NIM

当准备部署时,您可以使用NVIDIA NIM自行托管模型——这包括在NVIDIA AI Enterprise软件许可中,并可以在任何地方运行它们,从而拥有您自定义的内容并完全控制您的知识产权(IP)和AI应用程序。

了解NIMs的更多信息

from langchain_nvidia_ai_endpoints import NVIDIAEmbeddings

# connect to an embedding NIM running at localhost:8080
embedder = NVIDIAEmbeddings(base_url="http://localhost:8080/v1")
API 参考:NVIDIA嵌入

相似度

以下是这些数据点相似性的快速测试:

查询:

  • 堪察加的天气怎么样?

  • 意大利以哪些种类的食物而闻名?

  • 我叫什么名字?我打赌你肯定不记得了...

  • 生命的意义到底是什么呢?

  • 生命的意义在于享受乐趣 :D

文档:

  • 堪察加的天气寒冷,冬季漫长而严酷。

  • 意大利以意大利面、披萨、冰淇淋和浓缩咖啡而闻名。

  • 我想不起个人姓名,只提供信息。

  • 生命的意义各不相同,通常被视为个人的实现。

  • 享受生活的每一刻确实是一种美好的生活方式。

嵌入式运行时

print("\nSequential Embedding: ")
q_embeddings = [
embedder.embed_query("What's the weather like in Komchatka?"),
embedder.embed_query("What kinds of food is Italy known for?"),
embedder.embed_query("What's my name? I bet you don't remember..."),
embedder.embed_query("What's the point of life anyways?"),
embedder.embed_query("The point of life is to have fun :D"),
]
print("Shape:", (len(q_embeddings), len(q_embeddings[0])))

文档嵌入

print("\nBatch Document Embedding: ")
d_embeddings = embedder.embed_documents(
[
"Komchatka's weather is cold, with long, severe winters.",
"Italy is famous for pasta, pizza, gelato, and espresso.",
"I can't recall personal names, only provide information.",
"Life's purpose varies, often seen as personal fulfillment.",
"Enjoying life's moments is indeed a wonderful approach.",
]
)
print("Shape:", (len(q_embeddings), len(q_embeddings[0])))

现在我们已经生成了嵌入向量,可以对结果进行简单的相似性检查,以查看在检索任务中哪些文档会被触发作为合理的答案:

%pip install --upgrade --quiet  matplotlib scikit-learn
import matplotlib.pyplot as plt
import numpy as np
from sklearn.metrics.pairwise import cosine_similarity

# Compute the similarity matrix between q_embeddings and d_embeddings
cross_similarity_matrix = cosine_similarity(
np.array(q_embeddings),
np.array(d_embeddings),
)

# Plotting the cross-similarity matrix
plt.figure(figsize=(8, 6))
plt.imshow(cross_similarity_matrix, cmap="Greens", interpolation="nearest")
plt.colorbar()
plt.title("Cross-Similarity Matrix")
plt.xlabel("Query Embeddings")
plt.ylabel("Document Embeddings")
plt.grid(True)
plt.show()

作为提醒,发送到我们系统的查询和文档是:

查询:

  • 堪察加的天气怎么样?

  • 意大利以哪些种类的食物而闻名?

  • 我叫什么名字?我打赌你肯定不记得了...

  • 生命的意义到底是什么呢?

  • 生命的意义在于享受乐趣 :D

文档:

  • 堪察加的天气寒冷,冬季漫长而严酷。

  • 意大利以意大利面、披萨、冰淇淋和浓缩咖啡而闻名。

  • 我想不起个人姓名,只提供信息。

  • 生命的意义各不相同,通常被视为个人的实现。

  • 享受生活的每一刻确实是一种美好的生活方式。

截断

嵌入模型通常具有固定的上下文窗口,用于确定可嵌入的最大输入令牌数量。此限制可能是一个硬性限制,等于模型的最大输入令牌长度,也可能是一个有效限制,超过该限制后嵌入的准确性会下降。

由于模型操作的是令牌(tokens),而应用程序通常处理的是文本,因此应用程序要确保其输入在模型的令牌限制范围内可能会具有挑战性。默认情况下,如果输入过大,则会抛出异常。

为协助实现这一点,NVIDIA 的 NIM(API 目录或本地)提供了一个 truncate 参数,当输入过大时可在服务器端将其截断。

truncate 参数有三个选项:

  • \"NONE\":默认选项。如果输入过大,则会抛出异常。
  • \"START\": 服务器从开头(左侧)截断输入,根据需要丢弃令牌。
  • \"END\":服务器从末尾(右侧)截断输入,必要时丢弃令牌。
long_text = "AI is amazing, amazing is " * 100
strict_embedder = NVIDIAEmbeddings()
try:
strict_embedder.embed_query(long_text)
except Exception as e:
print("Error:", e)
truncating_embedder = NVIDIAEmbeddings(truncate="END")
truncating_embedder.embed_query(long_text)[:5]

RAG 检索:

以下是对 LangChain 表达语言检索菜谱条目 中初始示例的重新应用,但使用 AI Foundation Models 在其 Playground 环境中提供的 Mixtral 8x7B InstructNVIDIA Retrieval QA Embedding 模型执行。菜谱中的后续示例同样可按预期运行,我们鼓励您使用这些选项进行探索。

提示:我们建议使用Mixtral进行内部推理(例如,用于数据提取、工具选择等的指令遵循),并使用Llama-Chat生成最终的单一“总结性回复”,即基于历史记录和上下文为用户生成简洁易懂的回复。

%pip install --upgrade --quiet  langchain faiss-cpu tiktoken langchain_community

from operator import itemgetter

from langchain_community.vectorstores import FAISS
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough
from langchain_nvidia_ai_endpoints import ChatNVIDIA
vectorstore = FAISS.from_texts(
["harrison worked at kensho"],
embedding=NVIDIAEmbeddings(model="NV-Embed-QA"),
)
retriever = vectorstore.as_retriever()

prompt = ChatPromptTemplate.from_messages(
[
(
"system",
"Answer solely based on the following context:\n<Documents>\n{context}\n</Documents>",
),
("user", "{question}"),
]
)

model = ChatNVIDIA(model="ai-mixtral-8x7b-instruct")

chain = (
{"context": retriever, "question": RunnablePassthrough()}
| prompt
| model
| StrOutputParser()
)

chain.invoke("where did harrison work?")
prompt = ChatPromptTemplate.from_messages(
[
(
"system",
"Answer using information solely based on the following context:\n<Documents>\n{context}\n</Documents>"
"\nSpeak only in the following language: {language}",
),
("user", "{question}"),
]
)

chain = (
{
"context": itemgetter("question") | retriever,
"question": itemgetter("question"),
"language": itemgetter("language"),
}
| prompt
| model
| StrOutputParser()
)

chain.invoke({"question": "where did harrison work", "language": "italian"})