Skip to main content
Open In ColabOpen on GitHub

ChatPremAI

PremAI 是一个一站式平台,简化了由生成式 AI 驱动的稳健、生产级应用的创建过程。通过简化开发流程,PremAI 允许你专注于提升用户体验并推动应用程序的整体增长。你可以快速开始使用我们的平台 这里

这是如何使用LangChain与不同的聊天模型进行交互的一个示例,使用了ChatPremAI

安装与设置

我们首先安装 langchainpremai-sdk。您可以输入以下命令进行安装:

pip install premai langchain

在继续之前,请确保您已经在PremAI上创建了一个账户并且已经创建了一个项目。如果没有,请参阅快速入门指南以开始使用PremAI平台。创建您的第一个项目并获取您的API密钥。

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

Setup PremAI 客户端在 LangChain

一旦我们导入了所需的模块,接下来让我们设置客户端。暂时假设我们的project_id8。但请务必使用您的项目-id,否则会抛出错误。

要使用 LangChain 与 Prem,您无需传递任何模型名称或设置任何参数即可使用我们的 chat-client。默认情况下,它将使用在 LaunchPad 中使用的模型名称和参数。

Note: 如果您在设置客户端时更改了model或其他参数,如temperaturemax_tokens,这将覆盖LaunchPad中已有的默认配置。

import getpass
import os

# First step is to set up the env variable.
# you can also pass the API key while instantiating the model but this
# comes under a best practices to set it as env variable.

if os.environ.get("PREMAI_API_KEY") is None:
os.environ["PREMAI_API_KEY"] = getpass.getpass("PremAI API Key:")
# By default it will use the model which was deployed through the platform
# in my case it will is "gpt-4o"

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

聊天完成

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

The first one will give us a static result. Whereas the second one will stream tokens one by one. Here's how you can generate chat-like completions.

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

response = chat.invoke([human_message])
print(response.content)
I am an AI language model created by OpenAI, designed to assist with answering questions and providing information based on the context provided. How can I help you today?

上面的内容看起来很有趣吧?我将默认的lanchpad系统提示设置为:Always sound like a pirate 你也可以根据需要覆盖默认的系统提示。这是如何做到的方法。

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

chat.invoke([system_message, human_message])
AIMessage(content="I'm your friendly assistant! How can I help you today?", response_metadata={'document_chunks': [{'repository_id': 1985, 'document_id': 1306, 'chunk_id': 173899, 'document_name': '[D] Difference between sparse and dense informati…', '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        •  Promoted\n\n\n                       Accelerate your study permit process\n                       with Scotiabank's Student GIC\n                       Program. We're here to help you tur…\n\n\n                       startright.scotiabank.com         Learn More\n\n\n                            Add a Comment\n\n\nSort by:   Best\n\n\n      DinosParkour      • 1y ago\n\n\n     Dense Retrieval (DR) m"}]}, id='run-510bbd0e-3f8f-4095-9b1f-c2d29fd89719-0')

您可以在这里提供系统提示,例如这样:

chat.invoke([system_message, human_message], temperature=0.7, max_tokens=10, top_p=0.95)
/home/anindya/prem/langchain/libs/community/langchain_community/chat_models/premai.py:355: UserWarning: WARNING: Parameter top_p is not supported in kwargs.
warnings.warn(f"WARNING: Parameter {key} is not supported in kwargs.")
AIMessage(content="Hello! I'm your friendly assistant. How can I", response_metadata={'document_chunks': [{'repository_id': 1985, 'document_id': 1306, 'chunk_id': 173899, 'document_name': '[D] Difference between sparse and dense informati…', '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        •  Promoted\n\n\n                       Accelerate your study permit process\n                       with Scotiabank's Student GIC\n                       Program. We're here to help you tur…\n\n\n                       startright.scotiabank.com         Learn More\n\n\n                            Add a Comment\n\n\nSort by:   Best\n\n\n      DinosParkour      • 1y ago\n\n\n     Dense Retrieval (DR) m"}]}, id='run-c4b06b98-4161-4cca-8495-fd2fc98fa8f8-0')

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

Native RAG 支持,附带预装仓库

Prem Repositories,允许用户上传文档(.txt、.pdf等),并将这些仓库连接到LLM。您可以将Prem Repositories视为本地的RAG,其中每个仓库可以被视为一个向量数据库。您可以连接多个仓库。有关仓库的更多信息,请参阅这里

语义链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的更多信息,请参阅这里

请注意:类似地,当你调用参数repositories时,类似于model_name,你可能会覆盖启动垫上连接的仓库。

现在,我们将仓库与我们的聊天对象连接起来以调用基于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 informati\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"
}
]
}

理想情况下,您无需在此连接Repository ID即可获取检索增强生成。如果您已经在prem平台连接了仓库,则可以得到相同的结果。

Prem 模板

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

使用Prem,编写和管理提示可以非常简单。在启动台内部的模板标签页中帮助您编写所需的多个提示,并将其用于SDK以使您的应用程序使用这些提示运行。您可以在这里阅读更多关于提示模板的内容:这里

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

例如,假设你的提示模板是这样的:

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_messages], template_id=template_id)
print(response.content)

Prem Template 特性同样支持流式传输。

流式传输

在本节中,让我们看看如何使用 LangChain 和 PremAI 流式传输令牌。以下是具体做法。

import sys

for chunk in chat.stream("hello how are you"):
sys.stdout.write(chunk.content)
sys.stdout.flush()
It looks like your message got cut off. If you need information about Dense Retrieval (DR) or any other topic, please provide more details or clarify your question.

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

import sys

# For some experimental reasons if you want to override the system prompt then you
# can pass that here too. However it is not recommended to override system prompt
# of an already deployed model.

for chunk in chat.stream(
"hello how are you",
system_prompt="act like a dog",
temperature=0.7,
max_tokens=200,
):
sys.stdout.write(chunk.content)
sys.stdout.flush()
Woof! 🐾 How can I help you today? Want to play fetch or maybe go for a walk 🐶🦴

工具/函数调用

LangChain PremAI 支持工具/函数调用。工具/函数调用允许模型根据给定的提示生成符合用户定义模式的输出。

NOTE: 当前版本的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 参考:工具

将工具模式与我们的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 参考:工具消息

最终,我们调用带有功能响应的LLM(绑定工具)。

response = llm_with_tools.invoke(messages)
print(response.content)
The final answers are:

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

定义工具模式:Pydantic类

以上我们展示了如何使用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]

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

chain = llm_with_tools | PydanticToolsParser(tools=[multiply, add])
chain.invoke(query)
[multiply(a=3, b=12), add(a=11, b=49)]

现在,就像上面所做的那样,我们解析这些内容并运行这些函数,再次调用LLM以获取结果。