NVIDIA NIM平台利用AI的功能,AI驱动知识问答助手的实现

NVIDIA NIM API是一套行业标准 API,使开发者能够轻松地部署 AI 模型,只需几行代码即可。NIM API 作为无服务器推理端点提供,为迭代和构建生成式 AI 解决方案提供了一条安全、简化的路径。

1. 什么是NVIDIA NIM 平台:

NIM 代表 NVIDIA 推理微服务,这意味着它是一种用于对生成式 AI 模型进行推理的服务。在宣布推出时,NIM 仅作为一套面向开发者的 API提供。

在这里插入图片描述

NIM API 建立在强大的基础之上,包括Triton 推理服务器、TensorRT、TensorRT-LLM和PyTorch等推理引擎。这种架构促进了大规模的无缝 AI 推理,使开发者能够使用最先进的基础模型和微调模型,而无需担心基础设施。

NIM API 与 OpenAI 兼容,使开发者能够在其应用程序中利用 OpenAI 模型和工具的强大功能。开发者可以使用标准 HTTP REST 客户端或 OpenAI 客户端库来使用 NIM API。

多款的AI模型,覆盖各种行业:

在这里插入图片描述
NIM API 提供了多个 API 端点,使开发者能够与 AI 模型进行交互。NIM API 与流行的 LLM 编排工具(如 LangChain 和 LlamaIndex)紧密集成。开发者可以轻松地构建基本的聊天机器人、AI 助手、检索增强生成 (RAG) 应用程序和基于代理的更高级应用程序。


2. 简单的API集成即可实现功能:


ptyhon相关代码:

from openai import OpenAI

client = OpenAI(
  base_url = "https://integrate.api.nvidia.com/v1",
  api_key = "$API_KEY_REQUIRED_IF_EXECUTING_OUTSIDE_NGC"
)

completion = client.chat.completions.create(
  model="nvidia/llama-3.1-nemotron-70b-instruct",
  messages=[{"role":"user","content":"Write a limerick about the wonders of GPU computing."}],
  temperature=0.5,
  top_p=1,
  max_tokens=1024,
  stream=True
)

for chunk in completion:
  if chunk.choices[0].delta.content is not None:
    print(chunk.choices[0].delta.content, end="")

这段代码主要是使用了一个假设的 OpenAI 库(实际上,OpenAI 的官方库是 openai,但这里的 OpenAI 可能是一个自定义或者示例名称)来与 NVIDIA 的某个 API 服务进行交互,从而利用一个指定的模型(在这里是 nvidia/llama-3.1-nemotron-70b-instruct)来生成文本,以下是对代码的详细中文解释:

    1. 导入库:
    • 首先,代码从 openai 模块中导入了 OpenAI 类。
    • 但请注意,实际上 OpenAI 的官方 Python 库通常是小写的 openai。
    1. 创建客户端:
    • 接着,代码创建了一个 OpenAI 客户端实例,该实例需要两个参数:base_url 和 api_key。
    • base_url 是 NVIDIA API 的基础 URL,即服务的入口点。
    • api_key 是用于身份验证的 API 密钥。这里使用了一个占位符,表示如果在 NGC(NVIDIA GPU Cloud)外部执行此代码,则需要提供实际的 API 密钥。
    1. 请求文本生成:
    • 使用客户端的 chat.completions.create 方法向 API 发起请求,以生成文本。这个方法需要多个参数来定义生成文本的方式和条件。
    • model 指定了要使用的模型,这里是 NVIDIA 的一个大型语言模型。
    • messages 是一个列表,其中包含了用户输入的信息,即希望模型基于这些输入来生成文本。在这里,用户输入的内容是要求模型写一个关于 GPU 计算奇迹的打油诗(limerick)。
    • temperature、top_p 和 max_tokens 是控制文本生成质量和长度的参数。
    • stream=True 表示希望以流式方式接收生成的文本,这意味着文本会分块逐渐返回,而不是等待全部生成后再一次性返回。
    1. 处理和打印生成的文本: 最后,代码通过一个循环来处理流式返回的文本块。
    • 对于每个返回的文本块,它检查其中是否包含新生成的文本内容(delta.content),如果有,则将其打印出来。
    • 由于设置了 stream=True,所以这个过程可能是逐渐进行的,直到文本生成完成。

总的来说,这段代码展示了如何使用一个假设的 OpenAI 库(或类似库)与 NVIDIA 的语言模型 API 进行交互的文本内容。

在这里插入图片描述


Node相关代码:

import OpenAI from 'openai';

const openai = new OpenAI({
  apiKey: '$API_KEY_REQUIRED_IF_EXECUTING_OUTSIDE_NGC',
  baseURL: 'https://integrate.api.nvidia.com/v1',
})

async function main() {
  const completion = await openai.chat.completions.create({
    model: "nvidia/llama-3.1-nemotron-70b-instruct",
    messages: [{"role":"user","content":"Write a limerick about the wonders of GPU computing."}],
    temperature: 0.5,
    top_p: 1,
    max_tokens: 1024,
    stream: true,
  })
   
  for await (const chunk of completion) {
    process.stdout.write(chunk.choices[0]?.delta?.content || '')
  }
  
}

main();

这段代码是使用 JavaScript(具体来说是 Node.js,因为它使用了 process.stdout.write)编写的,它利用了一个名为 OpenAI 的库(这个名称可能是为了示例,因为通常我们使用的库是 openai,代表 OpenAI 公司的官方库)来与 NVIDIA 的 API 进行通信,从而调用一个语言模型来生成文本。以下是对代码的详细中文解释:

    1. 导入库:
    • 首先,代码从 openai 包中导入了 OpenAI 类。这是进行后续操作的基础。
    1. 创建 OpenAI 客户端实例:
    • 接着,代码创建了一个 OpenAI 客户端的实例,命名为 openai。在创建这个实例时,传入了两个参数:apiKey 和 baseURL。
    • apiKey 是用于身份验证的 API 密钥,这里使用了一个占位符,表示实际使用时需要替换为有效的 API 密钥。
    • baseURL 是 NVIDIA API 的基础 URL,指定了服务的访问地址。
    1. 定义异步主函数:
    • 代码定义了一个名为 main 的异步函数,这个函数包含了与 API 交互并处理响应的主要逻辑。
    1. 请求文本生成:
    • 在 main 函数内,使用 await 关键字异步调用了 openai.chat.completions.create 方法,向 API 发送请求以生成文本。
    • 这个方法接收一个对象作为参数,该对象包含了多个用于控制文本生成的属性和值。
    • model 指定了要使用的模型名称,这里是 NVIDIA 提供的一个大型语言模型。
    • messages 是一个数组,包含了用户输入的信息,即要求模型基于这些输入来生成文本。
    • temperature、top_p 和 max_tokens 是用于控制文本生成质量和长度的参数。
    • stream 设置为 true,表示以流式方式接收生成的文本,即文本会分块逐渐返回而不是一次性返回全部内容。
    1. 处理和输出生成的文本:
    • 通过 for await…of 循环,代码逐块处理流式返回的文本。
    • 对于每个返回的文本块(chunk),它使用 process.stdout.write 方法将文本块中的内容(如果存在)输出到控制台。
    • 这里使用了可选链操作符(?.)来安全地访问可能不存在的属性,避免运行时错误。
    1. 执行主函数: 最后,代码调用了 main 函数,开始执行上述逻辑。

总的来说,这段代码展示了如何在 Node.js 环境中使用 OpenAI 库(或类似库)与 NVIDIA 的语言模型 API 进行交互。

在这里插入图片描述

shell相关代码:

curl https://integrate.api.nvidia.com/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $API_KEY_REQUIRED_IF_EXECUTING_OUTSIDE_NGC" \
  -d '{
    "model": "nvidia/llama-3.1-nemotron-70b-instruct",
    "messages": [{"role":"user","content":"Write a limerick about the wonders of GPU computing."}],
    "temperature": 0.5,   
    "top_p": 1,
    "max_tokens": 1024,
    "stream": true                
  }'

这段命令是使用 curl 工具来发送一个 HTTP 请求到 NVIDIA 的 API 端点,以获取文本生成的结果。以下是对这段命令的详细解释:

    1. 请求地址:
    • 这是 NVIDIA 提供的 API 服务地址。
    1. 请求头:
    • -H “Content-Type: application/json”:这告诉服务器你发送的数据是 JSON 格式的。
    • -H “Authorization: Bearer $API_KEY_REQUIRED_IF_EXECUTING_OUTSIDE_NGC”:这是用于身份验证的请求头。
    • 其中 $API_KEY_REQUIRED_IF_EXECUTING_OUTSIDE_NGC 是一个占位符,表示你需要替换成实际的 API 密钥。
    • 如果你在 NVIDIA GPU Cloud (NGC) 外部执行这个命令,就需要提供这个密钥。Bearer 表示你使用的是 Bearer Token 认证方式。
    1. 请求体:
    • -d ‘{…}’ 部分是请求的主体内容,你向 API 传递的参数都包含在这里。这些参数告诉 API 如何生成你想要的文本。
    • “model”: “nvidia/llama-3.1-nemotron-70b-instruct”:指定了要使用的模型名称。
    • “messages”: 用户输入的信息,即你希望模型基于这个输入来生成文本。
    • “temperature”: 0.5、“top_p”: 1 和 “max_tokens”: 1024:这些是控制文本生成质量和长度的参数。
    • “stream”: true:这表示你希望以流式方式接收生成的文本。当设置为 true 时,API 会分块发送文本,而不是等待全部文本生成完毕后再一次性发送。
    1. 执行结果:
    • 执行这个 curl 命令后,如果一切设置正确,并且 API 服务正常响应,将在终端中看到流式返回的文本生成结果。
    • 由于设置了 stream: true,文本可能会逐段显示,直到生成完毕。

总的来说,这个 curl 命令展示了如何通过命令行与 NVIDIA 的文本生成 API 进行交互。

在这里插入图片描述
简单的不到20行代码即可实现一个AI的功能,NIM API 与流行的 LLM 编排工具(如 LangChain 和 LlamaIndex)紧密集成。开发者可以轻松地构建基本的聊天机器人、AI 助手、检索增强生成 (RAG) 应用程序和基于代理的更高级应用程序。


3. 如何快速的实践一个NIM平台 入门体验 亲手搭建“基于NVIDIA NIM 平台的知识问答系统:

把下面的代码复制粘贴到一开始创建的 Python 文件中,例如“nim_test.py”:

# -*- coding: utf-8 -*-

# 导入必要的库
from langchain_nvidia_ai_endpoints import NVIDIAEmbeddings, ChatNVIDIA
from langchain_community.document_loaders import WebBaseLoader
from langchain_community.vectorstores import FAISS
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import chain
import os
import gradio as gr
from datetime import datetime
# Even if you do not know the full answer, generate a one-paragraph hypothetical answer to the below question in Chinese
# 定义假设性回答模板
hyde_template = """Even if you do not know the full answer, generate a one-paragraph hypothetical answer to the below question:

{question}"""

# 定义最终回答模板
template = """Answer the question based only on the following context:
{context}

Question: {question}
"""

# 定义函数来处理问题
def process_question(url, api_key, model_name, question):
    # 初始化加载器并加载数据
    loader = WebBaseLoader(url)
    docs = loader.load()

    # 设置环境变量
    os.environ['NVIDIA_API_KEY'] = api_key

    # 初始化嵌入层
    embeddings = NVIDIAEmbeddings()
    text_splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=50)
    documents = text_splitter.split_documents(docs)
    vector = FAISS.from_documents(documents, embeddings)
    retriever = vector.as_retriever()

    # 初始化模型
    model = ChatNVIDIA(model=model_name)

    # 创建提示模板
    hyde_prompt = ChatPromptTemplate.from_template(hyde_template)
    hyde_query_transformer = hyde_prompt | model | StrOutputParser()

    # 定义检索函数
    @chain
    def hyde_retriever(question):
        hypothetical_document = hyde_query_transformer.invoke({"question": question})
        return retriever.invoke(hypothetical_document)

    # 定义最终回答链
    prompt = ChatPromptTemplate.from_template(template)
    answer_chain = prompt | model | StrOutputParser()

    @chain
    def final_chain(question):
        documents = hyde_retriever.invoke(question)
        response = ""
        for s in answer_chain.stream({"question": question, "context": documents}):
            response += s
        return response

    # 调用最终链获取答案
    return str(datetime.now())+final_chain.invoke(question)

# 定义可用的模型列表
models = ["mistralai/mistral-7b-instruct-v0.2","meta/llama-3.1-405b-instruct"]

# 启动Gradio应用
iface = gr.Interface(
    fn=process_question,
    inputs=[
        gr.Textbox(label="输入需要学习的网址"),
        gr.Textbox(label="NVIDIA API Key"),
        gr.Dropdown(models, label="选择语言模型"),
        gr.Textbox(label="输入问题")
    ],
    outputs="text",
    title="网页知识问答系统"
)

# 启动Gradio界面
iface.launch()

因为这是一个python的脚本,所以,需要保证环境中有python环境:

python -V

如果没有就需要安装一个python的环境,可以网上尝试搜索一下。

如果有python环境就可以安装一下项目所需要使用的包:

pip install langchain_nvidia_ai_endpoints langchain-community langchain-text-splitters faiss-cpu gradio==3.50.0 setuptools beautifulsoup4

接下来进行NIM平台的注册功能:

在这里插入图片描述
输入用户名即可完成NIM平台的注册:

在这里插入图片描述
如何get API key呢?点击任意一个模型,可以看到如下,点击python,再点击“Get API Key”:

在这里插入图片描述
点击下面的copy即可复制生成的好的key,注意一下这里的key有失效时间:
在这里插入图片描述
再在环境中使用pyhton命令启动脚本:

python nimtest.py

在这里插入图片描述
在网址上输入127.0.0.0:7860即可打开一个AI交互页面:
在这里插入图片描述
因为最新也是在学习java,所以,找了一篇****的文章:

在这里插入图片描述
所以,看一下,发现Error了,估计是因为有人工授权的原因,所以,我换了一个网站。

在这里插入图片描述
可以看到可以搜索到我们想要的信息,代码也是提供了2个语言模型:

在这里插入图片描述

更换另外一个模型,可以看到回答的全是英文:
在这里插入图片描述
可以看到回答的是英文,试一下,在输入问题,再加一个“使用中文回答”:

在这里插入图片描述


4. 上面是使用web提供的界面,如何将NIM平台以API的方式来集成呢?

NIM平台覆盖了很多的场景:

  • 大语言模型 Phi-3 LLMs
  • 生成代码 Granite Code
  • 生成文本向量 Generate Embeddings for Text Retrieval (agent-blueprints)
  • 视觉语义分割ChangeNet
  • 光学字符检测OCDRNet
  • 统计图表理解deplot(agent-blueprints)

上面已经尝试过大语言模型的场景,我们来看看其它的场景吧:

# 导入OpenAI库
from openai import OpenAI

# 初始化OpenAI客户端,配置基础URLAPI密钥
# 基础URL指向NVIDIAAPI服务
# API密钥在NGC外部执行时需要,以验证身份
client = OpenAI(
  base_url = "https://integrate.api.nvidia.com/v1",
  api_key = "$API_KEY_REQUIRED_IF_EXECUTING_OUTSIDE_NGC"
)

# 创建聊天完成对象,使用特定的模型来生成Python函数代码
# 模型选择:ibm/granite-34b-code-instruct
# 请求模型编写一个计算阶乘的Python函数
# 参数说明:
# model: 使用的预训练模型名称
# messages: 用户输入的角色和内容
# temperature: 控制输出随机性的参数,值越小输出越确定,值越大输出越随机
# top_p: 控制输出质量的参数,值越小输出越高质量,但速度会变慢
# max_tokens: 模型生成的最多token数,防止输出过长
# stream: 是否以流式方式获取结果
completion = client.chat.completions.create(
  model="ibm/granite-34b-code-instruct",
  messages=[{"role":"user","content":"xxxx"}],
  temperature=0.5,
  top_p=1,
  max_tokens=1024,
  stream=True
)

# 以流式处理生成的结果
# 遍历每个返回的代码块,即时打印出生成的函数代码
for chunk in completion:
  if chunk.choices[0].delta.content is not None:
    print(chunk.choices[0].delta.content, end="")

在上面的content字段中,我们输入“如何写一个java spring boot的代码”,即可以给我生成一个简单的代码,非常的方便:
在这里插入图片描述

上一篇:【C++篇】类与对象的秘密(上)


下一篇:Android 设置控件为圆形