Skip to main content
Open In Colab在 GitHub 上打开

NVIDIA NIM

langchain-nvidia-ai-endpointspackage 包含 LangChain 集成,使用 model 构建应用程序 NVIDIA NIM 推理微服务。NIM 支持跨域的模型,例如聊天、嵌入和重新排名模型 来自社区和 NVIDIA。这些模型由 NVIDIA 优化,可在 NVIDIA 上提供最佳性能 加速基础设施并部署为 NIM,NIM 是一种易于使用的预构建容器,可使用单个 命令。

NVIDIA 托管的 NIM 部署可在 NVIDIA API 目录中进行测试。测试后, 可以使用 NVIDIA AI Enterprise 许可证从 NVIDIA 的 API 目录中导出 NIM,并在本地或云中运行。 让企业拥有并完全控制其 IP 和 AI 应用程序。

NIM 按模型打包为容器映像,并通过 NVIDIA NGC 目录作为 NGC 容器映像分发。 NIM 的核心是提供简单、一致且熟悉的 API,用于在 AI 模型上运行推理。

此示例介绍了如何使用 LangChain 与支持的 NVIDIA 检索 QA 嵌入模型进行交互,以便通过NVIDIAEmbeddings类。

有关通过此 API 访问聊天模型的更多信息,请查看 ChatNVIDIA 文档。

安装

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

设置

要开始使用,请执行以下作:

  1. 在托管 NVIDIA AI Foundation 模型的 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类。

在 NVIDIA API Catalog 上使用 NIM

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

from langchain_nvidia_ai_endpoints import NVIDIAEmbeddings

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

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

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

  • embed_documents:为要搜索的文档列表生成段落嵌入。

  • aembed_query/aembed_documents:上述的异步版本。

使用自托管的 NVIDIA NIM

准备好部署后,您可以使用 NVIDIA NIM(包含在 NVIDIA AI Enterprise 软件许可证中)自托管模型,并在任何地方运行它们,从而获得自定义的所有权,并完全控制您的知识产权 (IP) 和 AI 应用程序。

了解有关 NIM 的更多信息

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 参考:NVIDIAEmbeddings

相似

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

查询:

  • 堪察加半岛的天气状况如何?

  • 意大利以哪些美食而闻名?

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

  • 无论如何,生活的意义何在?

  • 生活的意义在于享受: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

文件:

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

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

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

  • 人生的目的各不相同,通常被视为个人的成就。

  • 享受生活中的时刻确实是一种美妙的方法。

截断

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

由于模型对令牌进行作,而应用程序通常使用文本,因此应用程序很难确保其输入保持在模型的令牌限制范围内。默认情况下,如果输入太大,则会引发异常。

为了帮助实现这一点,NVIDIA 的 NIM (API Catalog 或本地) 提供了一个truncate参数,如果输入太大,则会截断服务器端的输入。

truncateparameter 有三个选项:

  • “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 的 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"})