从 OpenAI 到 Hugging Face 上的开放 LLM (集成 Messages API)

发布于 2024 年 2 月 8 日
在 GitHub 上更新

我们很高兴地宣布,为了提供与文本生成推理 (TGI) 和推理端点 (Inference Endpoints) 的 OpenAI 兼容性,我们正式引入了 Messages API。

从 1.4.0 版本开始,TGI 提供与 OpenAI Chat Completion API 兼容的 API。新的 Messages API 允许客户和用户无缝地从 OpenAI 模型过渡到开放的大语言模型 (LLM)。该 API 可以直接与 OpenAI 的客户端库或第三方工具 (如 LangChain 或 LlamaIndex) 一起使用。

“兼容 OpenAI 的新 Messages API 让 Ryght 的实时 GenAI 编排平台能够轻松地将 LLM 用例从 OpenAI 切换到开放模型。我们从 GPT4 迁移到推理端点上的 Mixtral/Llama2 的过程毫不费力,现在我们的工作流程得以简化,并且能更好地控制我们的 AI 解决方案。”- Johnny CrupiRyght 首席技术官

新的 Messages API 现在也已在推理端点中可用,支持专用和无服务器两种模式。为了让您快速上手,我们提供了详细的示例,教您如何

限制: Messages API 目前不支持函数调用 (function calling),并且仅适用于在其分词器配置 (tokenizer configuration) 中定义了 `chat_template` 的大语言模型,例如 Mixtral 8x7B Instruct

创建推理端点

推理端点 (Inference Endpoints) 提供了一个安全、生产级的解决方案,可轻松地在由 Hugging Face 管理的专用基础设施上部署 Hub 上的任何机器学习模型。

在本例中,我们将使用文本生成推理 (Text Generation Inference) 将一个经过微调的 Mixtral 模型 Nous-Hermes-2-Mixtral-8x7B-DPO 部署到推理端点。

我们只需在UI 界面上点击几下即可部署模型,或者利用 `huggingface_hub` Python 库以编程方式创建和管理推理端点。这里我们演示如何使用 Hub 库。

在下面的 API 调用中,我们需要指定端点名称和模型仓库,以及任务类型为 `text-generation`。本例中,我们使用 `protected` 类型,这样访问已部署的端点就需要一个有效的 Hugging Face 令牌。我们还需要配置硬件要求,如供应商、区域、加速器、实例类型和大小。您可以通过此 API 调用查看可用的资源选项,并在我们的目录这里查看部分模型的推荐配置。

注意:您可能需要发送邮件至 api-enterprise@huggingface.co 申请配额升级。

from huggingface_hub import create_inference_endpoint

endpoint = create_inference_endpoint(
    "nous-hermes-2-mixtral-8x7b-demo",
    repository="NousResearch/Nous-Hermes-2-Mixtral-8x7B-DPO",
    framework="pytorch",
    task="text-generation",
    accelerator="gpu",
    vendor="aws",
    region="us-east-1",
    type="protected",
    instance_type="nvidia-a100",
    instance_size="x2",
    custom_image={
        "health_route": "/health",
        "env": {
            "MAX_INPUT_LENGTH": "4096",
            "MAX_BATCH_PREFILL_TOKENS": "4096",
            "MAX_TOTAL_TOKENS": "32000",
            "MAX_BATCH_TOTAL_TOKENS": "1024000",
            "MODEL_ID": "/repository",
        },
        "url": "ghcr.io/huggingface/text-generation-inference:sha-1734540", # use this build or newer
    },
)

endpoint.wait()
print(endpoint.status)

我们的部署需要几分钟才能启动。我们可以使用 `.wait()` 方法来阻塞当前运行的线程,直到端点达到最终的“运行中 (running)”状态。一旦运行,我们就可以确认其状态,并通过 UI Playground 进行测试。

IE UI Overview

太棒了,我们现在有了一个可用的端点!

💡 使用 `huggingface_hub` 部署时,您的端点默认会在闲置 15 分钟后缩容至零,以在非活动期间优化成本。请查阅 Hub Python 库文档,了解所有可用于管理端点生命周期的功能。

通过 OpenAI 客户端库使用推理端点

TGI 中对 Messages 的支持使得推理端点直接与 OpenAI Chat Completion API 兼容。这意味着任何现有通过 OpenAI 客户端库使用 OpenAI 模型的脚本都可以直接替换为使用任何在 TGI 端点上运行的开放大语言模型!

通过这种无缝过渡,您可以立即利用开放模型带来的众多优势:

  • 完全控制和透明的模型与数据
  • 不再担心速率限制
  • 能够根据您的特定需求完全自定义系统

让我们看看如何实现。

使用 Python 客户端

下面的例子展示了如何使用 OpenAI Python 库 进行这种转换。只需将 `` 替换为您的端点 URL (确保包含 `v1/` 后缀),并将 `` 字段填充为有效的 Hugging Face 用户令牌。`` 可以从推理端点 UI 中获取,也可以从我们上面创建的端点对象 `endpoint.url` 中获取。

然后,我们可以像平常一样使用客户端,向推理端点传递一个消息列表以流式获取响应。

from openai import OpenAI

# initialize the client but point it to TGI
client = OpenAI(
    base_url="<ENDPOINT_URL>" + "/v1/",  # replace with your endpoint url
    api_key="<HF_API_TOKEN>",  # replace with your token
)
chat_completion = client.chat.completions.create(
    model="tgi",
    messages=[
        {"role": "system", "content": "You are a helpful assistant."},
        {"role": "user", "content": "Why is open-source software important?"},
    ],
    stream=True,
    max_tokens=500
)

# iterate and print stream
for message in chat_completion:
    print(message.choices[0].delta.content, end="")

在后台,TGI 的 Messages API 会使用模型的聊天模板自动将消息列表转换为模型所需的指令格式。

💡 某些 OpenAI 功能,如函数调用,与 TGI 不兼容。目前,Messages API 支持以下聊天补全参数:`stream`、`max_tokens`、`frequency_penalty`、`logprobs`、`seed`、`temperature` 和 `top_p`。

使用 JavaScript 客户端

这是与上面相同的流式示例,但使用的是 OpenAI Javascript/Typescript 库

import OpenAI from "openai";

const openai = new OpenAI({
  baseURL: "<ENDPOINT_URL>" + "/v1/", // replace with your endpoint url
  apiKey: "<HF_API_TOKEN>", // replace with your token
});

async function main() {
  const stream = await openai.chat.completions.create({
    model: "tgi",
    messages: [
      { role: "system", content: "You are a helpful assistant." },
      { role: "user", content: "Why is open-source software important?" },
    ],
    stream: true,
    max_tokens: 500,
  });
  for await (const chunk of stream) {
    process.stdout.write(chunk.choices[0]?.delta?.content || "");
  }
}

main();

与 LangChain 和 LlamaIndex 集成

现在,让我们看看如何将这个新创建的端点与您喜欢的 RAG 框架一起使用。

如何与 LangChain 一起使用

要在 LangChain 中使用它,只需创建一个 `ChatOpenAI` 实例,并按如下方式传入您的 `` 和 ``:

from langchain_community.chat_models.openai import ChatOpenAI

llm = ChatOpenAI(
    model_name="tgi",
    openai_api_key="<HF_API_TOKEN>",
    openai_api_base="<ENDPOINT_URL>" + "/v1/",
)
llm.invoke("Why is open-source software important?")

我们能够直接利用与 OpenAI 模型相同的 `ChatOpenAI` 类。这使得所有以前的代码只需更改一行代码即可与我们的端点配合使用。现在让我们在一个简单的 RAG 管道中使用这样声明的 LLM,来回答一个关于 HF 博客文章内容的问题。

from langchain_core.runnables import RunnableParallel
from langchain_community.embeddings import HuggingFaceEmbeddings

# Load, chunk and index the contents of the blog
loader = WebBaseLoader(
    web_paths=("https://huggingface.co/blog/open-source-llms-as-agents",),
)
docs = loader.load()

# Declare an HF embedding model and vector store
hf_embeddings = HuggingFaceEmbeddings(model_name="BAAI/bge-large-en-v1.5")

text_splitter = RecursiveCharacterTextSplitter(chunk_size=512, chunk_overlap=200)
splits = text_splitter.split_documents(docs)
vectorstore = Chroma.from_documents(documents=splits, embedding=hf_embeddings)

# Retrieve and generate using the relevant pieces of context
retriever = vectorstore.as_retriever()
prompt = hub.pull("rlm/rag-prompt")

def format_docs(docs):
    return "\n\n".join(doc.page_content for doc in docs)

rag_chain_from_docs = (
    RunnablePassthrough.assign(context=(lambda x: format_docs(x["context"])))
    | prompt
    | llm
    | StrOutputParser()
)

rag_chain_with_source = RunnableParallel(
    {"context": retriever, "question": RunnablePassthrough()}
).assign(answer=rag_chain_from_docs)

rag_chain_with_source.invoke("According to this article which open-source model is the best for an agent behaviour?")
{
    "context": [...],
    "question": "According to this article which open-source model is the best for an agent behaviour?",
    "answer": " According to the article, Mixtral-8x7B is the best open-source model for agent behavior, as it performs well and even beats GPT-3.5. The authors recommend fine-tuning Mixtral for agents to potentially surpass the next challenger, GPT-4.",
}

如何与 LlamaIndex 一起使用

同样,您也可以在 LlamaIndex 中使用 TGI 端点。我们将使用 `OpenAILike` 类,并通过配置一些额外的参数 (即 `is_local`、`is_function_calling_model`、`is_chat_model`、`context_window`) 来实例化它。请注意,上下文窗口参数应与您端点先前设置的 `MAX_TOTAL_TOKENS` 的值相匹配。

from llama_index.llms import OpenAILike

# Instantiate an OpenAILike model
llm = OpenAILike(
    model="tgi",
    api_key="<HF_API_TOKEN>",
    api_base="<ENDPOINT_URL>" + "/v1/",
    is_chat_model=True,
    is_local=False,
    is_function_calling_model=False,
    context_window=32000,
)

# Then call it
llm.complete("Why is open-source software important?")

我们现在可以在类似的 RAG 管道中使用它。请记住,您在推理端点中先前选择的 `MAX_INPUT_LENGTH` 将直接影响模型可以处理的检索到的块 (chunk) 的数量 (`similarity_top_k`)。

from llama_index import (
    ServiceContext,
    VectorStoreIndex,
)
from llama_index import download_loader
from llama_index.embeddings import HuggingFaceEmbedding
from llama_index.query_engine import CitationQueryEngine

SimpleWebPageReader = download_loader("SimpleWebPageReader")

documents = SimpleWebPageReader(html_to_text=True).load_data(
    ["https://huggingface.co/blog/open-source-llms-as-agents"]
)

# Load embedding model
embed_model = HuggingFaceEmbedding(model_name="BAAI/bge-large-en-v1.5")

# Pass LLM to pipeline
service_context = ServiceContext.from_defaults(embed_model=embed_model, llm=llm)
index = VectorStoreIndex.from_documents(
    documents, service_context=service_context, show_progress=True
)

# Query the index
query_engine = CitationQueryEngine.from_args(
    index,
    similarity_top_k=2,
)
response = query_engine.query(
    "According to this article which open-source model is the best for an agent behaviour?"
)
According to the article, Mixtral-8x7B is the best performing open-source model for an agent behavior [5]. It even beats GPT-3.5 in this task. However, it's worth noting that Mixtral's performance could be further improved with proper fine-tuning for function calling and task planning skills [5].

清理

在您使用完端点后,您可以暂停或删除它。这一步可以通过 UI 完成,也可以像下面这样以编程方式完成。

# pause our running endpoint
endpoint.pause()

# optionally delete
endpoint.delete()

总结

文本生成推理 (TGI) 中的新 Messages API 为从 OpenAI 模型到开放大语言模型的平滑过渡提供了一条路径。我们迫不及待地想看到您将利用在 TGI 上运行的开放大语言模型来驱动哪些用例!

请参阅此 notebook,获取本文中代码的可运行版本。

社区

注册登录 发表评论