Skip to main content
PremAI 是一个一站式平台,简化了基于生成式 AI 构建健壮、生产就绪应用程序的流程。通过简化开发过程,PremAI 让您专注于提升用户体验并推动应用程序的整体增长。您可以在此快速开始使用我们的平台。 本示例介绍如何使用 LangChain 通过 ChatPremAI 与不同的聊天模型进行交互。

安装与配置

首先安装 langchainpremai-sdk,可以输入以下命令进行安装:
pip install premai langchain
在继续之前,请确保您已在 PremAI 上创建账户并创建了项目。如果还没有,请参阅快速入门指南,开始使用 PremAI 平台。创建您的第一个项目并获取 API 密钥。
from langchain_community.chat_models import ChatPremAI
from langchain.messages import HumanMessage, SystemMessage

在 LangChain 中配置 PremAI 客户端

导入所需模块后,让我们配置客户端。目前假设我们的 project_id8,请确保使用您自己的项目 ID,否则会报错。 使用 langchain 与 prem 时,无需传入任何模型名称或为聊天客户端设置参数。默认情况下,它将使用在 LaunchPad 中配置的模型名称和参数。
注意:如果在设置客户端时修改了 model 或其他参数(如 temperaturemax_tokens),将会覆盖在 LaunchPad 中使用的现有默认配置。
import getpass
import os

# 第一步是设置环境变量。
# 也可以在实例化模型时直接传入 API 密钥,但最佳实践是将其设为环境变量。

if os.environ.get("PREMAI_API_KEY") is None:
    os.environ["PREMAI_API_KEY"] = getpass.getpass("PremAI API Key:")
# 默认情况下,它将使用通过平台部署的模型
# 在本例中为 "gpt-4.1"

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

聊天补全

ChatPremAI 支持两种方法:invoke(与 generate 相同)和 stream 前者返回静态结果,后者逐 token 流式返回。以下是生成聊天补全的方式:
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?
上面的效果很有趣吧?我将默认的 LaunchPad 系统提示设置为: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\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"}]}, 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\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"}]}, id='run-c4b06b98-4161-4cca-8495-fd2fc98fa8f8-0')
如果在此处传入系统提示,它将覆盖在平台上部署应用程序时固定的系统提示。

通过 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 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"
        }
    ]
}
理想情况下,您无需在此处连接仓库 ID 即可获得检索增强生成。如果您已在 Prem 平台上连接了仓库,仍然可以获得相同的结果。

Prem 模板

编写提示模板可能非常繁琐。提示模板通常很长、难以管理,并且需要不断调整以提升效果,同时还要在整个应用程序中保持一致。 借助 Prem,编写和管理提示可以变得非常简单。LaunchPad 中的 Templates 选项卡可帮助您编写所需数量的提示,并在 SDK 中使用这些提示运行您的应用程序。更多关于提示模板的信息请参阅这里 要在 LangChain 中原生使用 Prem 模板,您需要在 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_messages], template_id=template_id)
print(response.content)
流式输出中也支持 Prem 模板功能。

流式输出

本节介绍如何使用 LangChain 和 PremAI 进行 token 流式输出:
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 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 支持工具/函数调用。工具/函数调用允许模型根据给定的提示生成符合用户自定义 schema 的输出。 注意: 当前版本的 LangChain ChatPremAI 不支持带流式输出的函数/工具调用,相关支持即将推出。

向模型传入工具

为了传入工具并让 LLM 选择需要调用的工具,我们需要传入工具 schema。工具 schema 是函数定义,包含关于函数功能、函数各参数含义等的详细说明。以下是一些简单的算术函数及其 schema。 注意: 在定义函数/工具 schema 时,务必添加关于函数参数的说明,否则会报错。
from langchain.tools import tool
from pydantic import BaseModel, Field


# 定义函数参数的 schema
class OperationInput(BaseModel):
    a: int = Field(description="First number")
    b: int = Field(description="Second number")


# 现在定义函数,参数 schema 为 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

将工具 schema 绑定到 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.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"]))
最后,我们使用函数响应加入上下文后再次调用 LLM(已绑定工具)。
response = llm_with_tools.invoke(messages)
print(response.content)
The final answers are:

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

定义工具 schema:Pydantic 类

上面我们展示了如何使用 tool 装饰器定义 schema,但同样可以使用 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]
现在,可以将它们绑定到聊天模型并直接获取结果:
chain = llm_with_tools | PydanticToolsParser(tools=[multiply, add])
chain.invoke(query)
[multiply(a=3, b=12), add(a=11, b=49)]
现在,如上所述,我们解析并运行这些函数,再次调用 LLM 以获取最终结果。