跳到主要内容
Open on GitHub

PremAI

PremAI 是一个一体化平台,可简化由生成式 AI 驱动的强大、可用于生产的应用程序的创建。通过简化开发流程,PremAI 使您能够专注于提升用户体验并推动应用程序的整体增长。您可以在此处快速开始使用我们的平台。

ChatPremAI

本示例介绍了如何使用 LangChain 与 `ChatPremAI` 交互不同的聊天模型。

安装和设置

我们首先安装 `langchain` 和 `premai-sdk`。您可以输入以下命令进行安装

pip install premai langchain

在进一步操作之前,请确保您已在 PremAI 上注册账户并已创建一个项目。如果尚未创建,请参阅快速入门指南以开始使用 PremAI 平台。创建您的第一个项目并获取您的 API 密钥。

from langchain_core.messages import HumanMessage, SystemMessage
from langchain_community.chat_models import ChatPremAI

在 LangChain 中设置 PremAI 客户端

导入所需的模块后,我们来设置客户端。目前我们假设 `project_id` 为 `8`。但请确保使用您自己的项目 ID,否则会抛出错误。

要将 LangChain 与 Prem 结合使用,您无需传递任何模型名称或为我们的聊天客户端设置任何参数。默认情况下,它将使用 LaunchPad 中使用的模型名称和参数。

注意:如果您在设置客户端时更改 `model` 或任何其他参数(如 `temperature` 或 `max_tokens`),它将覆盖 LaunchPad 中使用的现有默认配置。

import os
import getpass

if "PREMAI_API_KEY" not in os.environ:
os.environ["PREMAI_API_KEY"] = getpass.getpass("PremAI API Key:")

chat = ChatPremAI(project_id=1234, model_name="gpt-4o")

聊天补全

`ChatPremAI` 支持两种方法:`invoke`(与 `generate` 相同)和 `stream`。

第一种方法将提供静态结果。而第二种方法将逐个流式传输 token。以下是如何生成类似聊天的补全。

human_message = HumanMessage(content="Who are you?")

response = chat.invoke([human_message])
print(response.content)

您可以像这样提供系统提示:

system_message = SystemMessage(content="You are a friendly assistant.")
human_message = HumanMessage(content="Who are you?")

chat.invoke([system_message, human_message])

您也可以在调用模型时更改生成参数。具体操作如下:

chat.invoke(
[system_message, human_message],
temperature = 0.7, max_tokens = 20, top_p = 0.95
)

如果您在此处放置系统提示,它将覆盖您在从平台部署应用程序时固定的系统提示。

您可以在此处找到所有可选参数。除这些支持的参数外,任何其他参数都将在调用模型之前自动移除。

Prem 存储库的原生 RAG 支持

Prem 存储库允许用户上传文档(.txt、.pdf 等)并将这些存储库连接到 LLM。您可以将 Prem 存储库视为原生 RAG,其中每个存储库都可以被视为一个向量数据库。您可以连接多个存储库。您可以在此处了解更多关于存储库的信息。

LangChain PremAI 也支持存储库。操作方法如下。


query = "Which models are used for dense retrieval"
repository_ids = [1985,]
repositories = dict(
ids=repository_ids,
similarity_threshold=0.3,
limit=3
)

首先,我们通过一些存储库 ID 来定义我们的存储库。请确保这些 ID 是有效的存储库 ID。您可以在此处了解如何获取存储库 ID。

请注意:与 `model_name` 类似,当您调用参数 `repositories` 时,您可能会覆盖在 LaunchPad 中连接的存储库。

现在,我们将存储库与我们的聊天对象连接,以调用基于 RAG 的生成。

import json

response = chat.invoke(query, max_tokens=100, repositories=repositories)

print(response.content)
print(json.dumps(response.response_metadata, indent=4))

输出结果如下所示。

Dense retrieval models typically include:

1. **BERT-based Models**: Such as DPR (Dense Passage Retrieval) which uses BERT for encoding queries and passages.
2. **ColBERT**: A model that combines BERT with late interaction mechanisms.
3. **ANCE (Approximate Nearest Neighbor Negative Contrastive Estimation)**: Uses BERT and focuses on efficient retrieval.
4. **TCT-ColBERT**: A variant of ColBERT that uses a two-tower
{
"document_chunks": [
{
"repository_id": 1985,
"document_id": 1306,
"chunk_id": 173899,
"document_name": "[D] Difference between sparse and dense information\u2026",
"similarity_score": 0.3209080100059509,
"content": "with the difference or anywhere\nwhere I can read about it?\n\n\n 17 9\n\n\n u/ScotiabankCanada \u2022 Promoted\n\n\n Accelerate your study permit process\n with Scotiabank's Student GIC\n Program. We're here to help you tur\u2026\n\n\n startright.scotiabank.com Learn More\n\n\n Add a Comment\n\n\nSort by: Best\n\n\n DinosParkour \u2022 1y ago\n\n\n Dense Retrieval (DR) m"
}
]
}

因此,这也意味着在使用 Prem 平台时,您无需构建自己的 RAG 管道。Prem 使用其自己的 RAG 技术,为检索增强生成提供一流的性能。

理想情况下,您无需在此处连接存储库 ID 即可获得检索增强生成。如果您已在 Prem 平台中连接存储库,您仍然可以获得相同的结果。

流式传输

在本节中,我们来看看如何使用 LangChain 和 PremAI 流式传输 token。操作方法如下。

import sys

for chunk in chat.stream("hello how are you"):
sys.stdout.write(chunk.content)
sys.stdout.flush()

与上文类似,如果您想覆盖系统提示和生成参数,您需要添加以下内容:

import sys

for chunk in chat.stream(
"hello how are you",
system_prompt = "You are an helpful assistant", temperature = 0.7, max_tokens = 20
):
sys.stdout.write(chunk.content)
sys.stdout.flush()

这将逐个流式传输 token。

请注意:目前,尚不支持带流式传输的 RAG。但我们仍通过 API 提供支持。您可以在此处了解更多信息。

Prem 模板

编写提示模板可能非常混乱。提示模板冗长、难以管理,并且必须不断调整以改进并在整个应用程序中保持一致。

有了 Prem,编写和管理提示变得非常简单。LaunchPad 中的***模板***选项卡可帮助您编写所需数量的提示,并在 SDK 中使用它们,使您的应用程序能够使用这些提示运行。您可以在此处阅读更多关于提示模板的信息。

要将 Prem 模板与 LangChain 原生集成使用,您需要向 `HumanMessage` 传递一个 ID。此 ID 应为您的提示模板变量的名称。`HumanMessage` 中的 `content` 应为该变量的值。

例如,如果您的提示模板是这样:

Say hello to my name and say a feel-good quote
from my age. My name is: {name} and age is {age}

那么现在您的 `human_messages` 应该看起来像这样:

human_messages = [
HumanMessage(content="Shawn", id="name"),
HumanMessage(content="22", id="age")
]

将此 `human_messages` 传递给 ChatPremAI 客户端。请注意:不要忘记传递额外的 `template_id` 以使用 Prem 模板调用生成。如果您不了解 `template_id`,您可以在我们的文档中了解更多信息。以下是一个示例:

template_id = "78069ce8-xxxxx-xxxxx-xxxx-xxx"
response = chat.invoke([human_message], template_id=template_id)

Prem 模板也支持流式传输。

Prem 嵌入

在本节中,我们将介绍如何使用 LangChain 的 `PremEmbeddings` 访问不同的嵌入模型。我们首先导入模块并设置 API 密钥。

import os
import getpass
from langchain_community.embeddings import PremEmbeddings


if os.environ.get("PREMAI_API_KEY") is None:
os.environ["PREMAI_API_KEY"] = getpass.getpass("PremAI API Key:")

我们支持许多最先进的嵌入模型。您可以在此处查看我们支持的 LLM 和嵌入模型列表。目前,让我们在此示例中使用 `text-embedding-3-large` 模型。


model = "text-embedding-3-large"
embedder = PremEmbeddings(project_id=8, model=model)

query = "Hello, this is a test query"
query_result = embedder.embed_query(query)

# Let's print the first five elements of the query embedding vector

print(query_result[:5])
注意

与聊天不同,为 PremAIEmbeddings 设置 `model_name` 参数是强制性的。

最后,让我们嵌入一些示例文档。

documents = [
"This is document1",
"This is document2",
"This is document3"
]

doc_result = embedder.embed_documents(documents)

# Similar to the previous result, let's print the first five element
# of the first document vector

print(doc_result[0][:5])
print(f"Dimension of embeddings: {len(query_result)}")

嵌入维度:3072

doc_result[:5]

结果

[-0.02129288576543331, 0.0008162345038726926, -0.004556538071483374, 0.02918623760342598, -0.02547479420900345]

工具/函数调用

LangChain PremAI 支持工具/函数调用。工具/函数调用允许模型通过生成与用户定义模式匹配的输出,来响应给定的提示。

  • 您可以在此处我们的文档中详细了解工具调用。
  • 您可以在文档的这一部分了解更多关于 LangChain 工具调用的信息。

注意

当前版本的 LangChain ChatPremAI 不支持带流式传输功能的函数/工具调用。流式传输支持与函数调用将很快推出。

向模型传递工具

为了传递工具并让 LLM 选择需要调用的工具,我们需要传递一个工具模式。工具模式是函数定义,以及关于函数功能、每个函数参数等的适当文档字符串。以下是一些简单的算术函数及其模式。

注意

定义函数/工具模式时,不要忘记添加有关函数参数的信息,否则会抛出错误。

from langchain_core.tools import tool
from pydantic import BaseModel, Field

# Define the schema for function arguments
class OperationInput(BaseModel):
a: int = Field(description="First number")
b: int = Field(description="Second number")


# Now define the function where schema for argument will be OperationInput
@tool("add", args_schema=OperationInput, return_direct=True)
def add(a: int, b: int) -> int:
"""Adds a and b.

Args:
a: first int
b: second int
"""
return a + b


@tool("multiply", args_schema=OperationInput, return_direct=True)
def multiply(a: int, b: int) -> int:
"""Multiplies a and b.

Args:
a: first int
b: second int
"""
return a * b
API 参考:tool

将工具模式与我们的 LLM 绑定

我们现在将使用 `bind_tools` 方法将上述函数转换为“工具”并将其与模型绑定。这意味着每次调用模型时,我们都将传递这些工具信息。

tools = [add, multiply]
llm_with_tools = chat.bind_tools(tools)

在此之后,我们将从模型中获得响应,该模型现在已与工具绑定。

query = "What is 3 * 12? Also, what is 11 + 49?"

messages = [HumanMessage(query)]
ai_msg = llm_with_tools.invoke(messages)

正如我们所见,当我们的聊天模型与工具绑定时,它会根据给定的提示,正确且顺序地调用工具集。

ai_msg.tool_calls

输出

[{'name': 'multiply',
'args': {'a': 3, 'b': 12},
'id': 'call_A9FL20u12lz6TpOLaiS6rFa8'},
{'name': 'add',
'args': {'a': 11, 'b': 49},
'id': 'call_MPKYGLHbf39csJIyb5BZ9xIk'}]

我们将上面显示的消息附加到 LLM,作为上下文,并使 LLM 了解它调用了哪些函数。

messages.append(ai_msg)

由于工具调用发生在两个阶段,其中:

  1. 在我们的第一次调用中,我们收集了 LLM 决定使用的所有工具,以便它可以将结果作为附加上下文,以提供更准确且无幻觉的结果。

  2. 在我们的第二次调用中,我们将解析 LLM 决定的那些工具集并运行它们(在我们的案例中,将是我们定义的函数,带有 LLM 提取的参数),并将此结果传递给 LLM。

from langchain_core.messages import ToolMessage

for tool_call in ai_msg.tool_calls:
selected_tool = {"add": add, "multiply": multiply}[tool_call["name"].lower()]
tool_output = selected_tool.invoke(tool_call["args"])
messages.append(ToolMessage(tool_output, tool_call_id=tool_call["id"]))
API 参考:ToolMessage

最后,我们调用 LLM(与工具绑定),并在其上下文中添加函数响应。

response = llm_with_tools.invoke(messages)
print(response.content)

输出

The final answers are:

- 3 * 12 = 36
- 11 + 49 = 60

定义工具模式:Pydantic 类 `Optional`

上面我们展示了如何使用 `tool` 装饰器定义模式,但我们也可以使用 Pydantic 等效地定义模式。当您的工具输入更复杂时,Pydantic 会很有用。

from langchain_core.output_parsers.openai_tools import PydanticToolsParser

class add(BaseModel):
"""Add two integers together."""

a: int = Field(..., description="First integer")
b: int = Field(..., description="Second integer")


class multiply(BaseModel):
"""Multiply two integers together."""

a: int = Field(..., description="First integer")
b: int = Field(..., description="Second integer")


tools = [add, multiply]
API 参考:PydanticToolsParser

现在,我们可以将它们绑定到聊天模型并直接获取结果。

chain = llm_with_tools | PydanticToolsParser(tools=[multiply, add])
chain.invoke(query)

输出

[multiply(a=3, b=12), add(a=11, b=49)]

现在,如上所述,我们解析并运行这些函数,再次调用 LLM 以获取结果。