2.3 访问OpenAI实践
经过前面内容的学习,已经基本了解了LangChain的基本知识和用法。在本节的内容中,将通过具体例子的实现过程讲解访问OpenAI获得问题回馈的用法。
2.3.1 获得OpenAI回馈
要想我们的问题获得OpenAI回馈,需要调用方法client.completions.create()实现。这是OpenAI客户端对象中的一个方法,用于生成反馈文本。方法client.completions.create()的语法格式如下所示。
client.completions.create(
prompt: str,
max_tokens: int,
temperature: float,
top_p: Optional[float] = None,
stop: Optional[Union[str, List[str]]] = None,
n: int = 1,
logit_bias: Optional[Dict[str, float]] = None,
return_prompt: bool = False,
return_metadata: bool = False
) -> Union[Dict[str, Union[str, int, List[str]]], List[Dict[str, Union[str, int, List[str]]]]]:
通过设置create()方法的参数,可以控制生成文本的质量、多样性和其他方面的行为。各个参数的具体说明如下所示。
- prompt (str):提示文本,用于指导生成的文本内容。模型将根据此提示来生成接下来的文本。
- max_tokens (int):生成文本的最大长度(以标记数量计)。生成的文本长度可能会小于或等于此值。
- temperature (float):控制生成文本的多样性,较低的temperature会导致更加保守和确定性的输出,而较高的temperature会导致更加随机和多样化的输出。
- top_p (Optional[float]):对于下一个标记的概率分布的最高概率部分的累积分布,当总概率大于此阈值时停止生成。这是一种用于控制生成文本的方法,以确保生成的文本在语义上保持一致。
- stop (Optional[Union[str, List[str]]]):用于指定生成文本的停止标记。当生成的文本中包含任何停止标记时,生成过程将结束。
- n (int):要生成的候选文本数量,默认值为1。
- logit_bias (Optional[Dict[str, float]]):用于调整模型预测的偏置,可以通过指定不同标记的偏置来指导生成的文本内容。
- return_prompt (bool):设置是否在响应中包含生成文本时使用的提示,默认值为False。
- return_metadata (bool):设置是否在响应中包含生成文本时的元数据信息,默认值为False。
请看下面的例,展示了使用方法client.completions.create()获取OpenAI回馈的简单用法。
实例2-2:向OpenAI提问问题(源码路径:codes\2\practice\fan.py)
实例文件fan.py的功能是使用OpenAI生成了问题“CSDN是一个是个什么样的平台?”的回答信息。首先,它从dotenv库中导入load_dotenv函数,用于加载环境变量。然后,它创建了一个OpenAI客户端对象,并使用该对象调用了生成文本的方法。在生成文本的过程中,它提供了一个提示(prompt),要求为宠物狗起一个名字。最后,它打印输出CSDN是一个是个什么样的平台。
from dotenv import load_dotenv # 用于加载环境变量
load_dotenv() # 加载 .env 文件中的环境变量
# import os
# os.environ["OPENAI_API_KEY"] = '你的OpenAI API Key'
# import openai
# openai.api_key = '你的OpenAI API Key'
from openai import OpenAI
client = OpenAI()
prompt = 'CSDN是一个是个什么样的平台?'
response = client.completions.create(
max_tokens=1024,
n = 1,
stop=None,
model="gpt-3.5-turbo-instruct",
prompt= prompt,
temperature = 1
)
print(response)
对上述代码的具体说明如下所示:
(1)load_dotenv():这是dotenv库提供的一个函数,用于加载环境变量。在开发过程中,建议将敏感信息(如API密钥)存储在名为.env的文件中,然后使用load_dotenv()函数加载这些环境变量。
(2)openai.api_key:这是设置OpenAI API密钥的方法,将你的API密钥赋值给openai.api_key后,就可以在的代码中使用OpenAI的API服务。在注释掉的代码中,作者选择直接设置了API密钥,但是这种做法不够安全,因此更好的做法是将API密钥存储在环境变量中,并使用load_dotenv()函数进行加载。
(3)response:这是调用OpenAI API后得到的响应对象。在本例中,它包含了生成的文本内容。这个变量被赋值为调用生成文本方法的返回值。
(4)client.completions.create:用于生成反馈文本。在本实例中,client是通过OpenAI类创建的一个客户端对象,completions是这个对象的一个子模块,create是completions模块中的一个方法,用于向OpenAI API发送请求以生成反馈文本。执行后会输出:
Completion(id='cmpl-8NhLO1DdMjRmCVhK5ssyyaiqhD6Gi', choices=[CompletionChoice(finish_reason='stop', index=0, logprobs=None, text='\nCSDN(中国软件开发网)是中国领先的专业IT技术社区和开发者服务平台,成立于1999年。它为广大IT从业者提供了技术交流、学习、分享和求职招聘等服务。在CSDN上,用户可以浏览和发布技术文章、参与讨论、下载学习资料、观看技术视频教程等。CSDN覆盖了广泛的技术领域,包括软件开发、网络技术、人工智能、大数据、云计算等。同时,CSDN也是很多IT从业者学习和提升技能的重要平台之一。')], created=1700658850, model='gpt-3.5-turbo-instruct', object='text_completion', system_fingerprint=None, usage=CompletionUsage(completion_tokens=139, prompt_tokens=15, total_tokens=154))
2.3.2 设置模型
当我们调用OpenAI API获取问题的回馈信息时,可以设置要使用的模型,例如gpt-4、gpt-3、gpt-3.5。这一功能是通过参数model实现的。请看下面的例子,演示了使用参数model设置使用gpt-4模型的过程。
实例2-3:设置使用gpt-4模型回答我们的问题(源码路径:codes\2\practice\FanModel.py)
实例文件FanModel.py的功能是,使用gpt-4模型回答我们的问题“CSDN是一个是个什么样的平台?”。
from dotenv import load_dotenv # 用于加载环境变量
load_dotenv() # 加载 .env 文件中的环境变量
from openai import OpenAI
client = OpenAI()
# import os
# os.environ["OPENAI_API_KEY"] = '你的OpenAI API Key'
response = client.completions.create(model="gpt-4",
messages=[
{"role": "system", "content": "You are a creative AI."},
{"role": "user", "content": "CSDN是一个是个什么样的平台?"},
],
temperature=0.8,
max_tokens=60
)
print(response.choices[0].message.content)
在上述代码中,调用OpenAI API中的方法client.completions.create()生成了对话文本,在本例中传递了如下所示的参数。
- model:表示要使用的模型名称,在这里指定使用"gpt-4"模型。
- messages:包含了对话中的消息,其中每个消息都有一个角色("system"或"user")和内容。在本例中提供了两条消息:一个是系统消息,另一个是用户消息。
- temperature:控制生成文本的多样性。
- max_tokens:生成文本的最大长度(以标记数量计)。
本实例执行后不会显示完整的 Completion 对象,执行后会输出:
CSDN是一个技术交流、学习、分享和求职招聘等服务的IT技术社区和开发者服务平台。
这是因为 print(response.choices[0].message.content) 语句仅输出生成的对话系统回复文本内容,而不会包含其他信息,如 Completion 对象的 id、choices 等。因此,执行后只会显示生成的对话系统回复的文本内容,而不会包含完整的 Completion 对象。
另外,在本实例中还用到了messages参数。在OpenAI的对话模型中,messages 参数用于指定对话中的消息历史,包括用户消息和系统消息。它的作用是提供上下文信息,以便模型可以基于先前的消息生成合理的回复。具体来说,messages 参数是一个列表,其中每个元素都是一个字典,表示一条消息。每条消息包含如下所示的两个字段:
- role:指定消息的角色,可以是 "user" 表示用户的消息,也可以是 "system" 表示系统的消息。
- content:消息的内容,这是一个字符串,表示对话中的文本内容。
通过提供的消息历史,模型可以更好地理解对话的上下文,以便生成更加连贯和合理的回复。
当然除了使用传统的gpt-4、gpt-3、gpt-3.5等模型外,还可以使用其他模型例如text-davinci-003。"text-davinci-003"是OpenAI的语言模型之一,它属于Davinci系列模型。这些模型是由OpenAI开发的大型语言模型,具有强大的文本生成能力,可以用于各种自然语言处理任务,如文本生成、文本分类、对话生成等。
具体来说,"text-davinci-003" 模型是一个基于GPT-3架构的模型,它在大规模的文本数据上进行了训练,具有广泛的知识和语言理解能力。它可以根据给定的文本提示生成连贯、合理的文本内容,并且能够处理各种不同类型和长度的文本任务。通过使用 "text-davinci-003" 模型,可以实现多种自然语言处理应用,包括生成文本、问答系统、对话系统等。
实例2-4:设置使用text-davinci-003模型回答问题(源码路径:codes\2\practice\Qi.py)
实例文件Qi.py的功能是,使用text-davinci-003模型回答我们的问题“CSDN是一个是个什么样的平台?”。
import os
os.environ["OPENAI_API_KEY"] = '你的OpenAI API Key'
from langchain.llms import OpenAI
llm = OpenAI(
model="text-davinci-003",
temperature=0.8,
max_tokens=60,)
response = llm.predict("CSDN是一个是个什么样的平台?")
print(response.choices[0].text.strip())
在上述代码中,首先将OpenAI API密钥存储在环境变量中,确保了后续的OpenAI请求能够进行身份验证。然后,使用 langchain.llms 模块中的 OpenAI 类创建了一个实例 llm,并指定了使用的模型、temperature温度和最大生成标记数等参数。接着,调用 llm.predict()方法,向语言模型提供了一个文本提示 "CSDN是一个是个什么样的平台?",并请求生成对应的文本输出。最后,打印输出生成的文本结果。
CSDN是一个致力于为IT从业者提供技术交流、学习、分享和求职招聘等服务的专业平台,是中国领先的IT技术社区和开发者服务平台之一。
2.3.3 引入LangChain
到目前为止,本节中的实践还没有用到LangChain。在接下来的实例中,将使用 LangChain 框架中的 ChatOpenAI 类构建了一个聊天模型,然后向该聊天模型输入了一条系统消息和一条人类消息,并获取了聊天模型的响应。
实例2-5:使用LangChain实现OpenAI聊天系统(源码路径:codes\2\practice\ChatLongChain.py)
实例文件ChatLongChain.py的具体实现代码如下所示。
import os
os.environ["OPENAI_API_KEY"] = ''
from langchain.chat_models import ChatOpenAI
chat = ChatOpenAI(model="gpt-4",
temperature=0.8,
max_tokens=60)
from langchain.schema import (
HumanMessage,
SystemMessage
)
messages = [
SystemMessage(content="你是一个很棒的智能助手"),
HumanMessage(content="CSDN是一个是个什么样的平台?")
]
response = chat(messages)
print(response)
上述代码的实现流程如下所示:
- 导入必要的库:os、langchain.chat_models.ChatOpenAI、langchain.schema.HumanMessage和langchain.schema.SystemMessage。
- 创建一个 ChatOpenAI 类的实例 chat,设置使用指定的参数:模型为"gpt-4",temperature温度为0.8,最大令牌数为60。
- 定义了两条消息:一条是系统消息,内容为"你是一个很棒的智能助手";另一条是人类消息,内容为"CSDN是一个是个什么样的平台?"。
- 将这两条消息传递给聊天模型 chat,并获取模型的响应。
- 最后,打印输出聊天模型的响应内容。
这个例子和前面的例子相比,主要体现了 LangChain 框架的以下作用:
- 模块化构建:LangChain 提供了模块化的组件和工具,如 ChatOpenAI 类和 HumanMessage、SystemMessage 类,使得构建语言模型应用程序更加灵活和高效。
- 简化开发流程:LangChain 提供了一套工具、组件和接口,可以简化创建由大型语言模型 (LLM) 和聊天模型提供支持的应用程序的过程。开发者可以轻松地导入这些组件,快速搭建出端到端的语言模型应用。
- 高度抽象:LangChain 提供了高度抽象的方式来处理不同类型的消息和响应,如系统消息和人类消息,并提供了方便的方法来与聊天模型交互。
- 提供更多功能:LangChain 不仅提供了基本的聊天模型,还提供了其他功能模块,如内存、链等,使得开发者可以构建更加复杂和功能丰富的语言模型应用。
总的来说,LangChain 在构建语言模型应用程序时提供了更加方便、灵活和高效的开发方式,使得开发者能够更好地利用语言模型的能力,快速搭建出高质量的应用。
2.3.4 LangChain聊天模型
在LangChain中提供了一堆模块,我们可以使用它们来创建语言模型应用程序。可以将这些模块组合起来用于更复杂的应用程序,或者将它们单独用于更简单的应用程序。
在实际应用中,除了可以使用LLM外,还可以使用不同的聊天模型。聊天模型使用聊天消息作为输入和输出,而不是“文本输入、文本输出”API。要完成聊天,需要将一条或多条消息传递给聊天模型。
(1)LangChain 目前支持 AIMessage、HumanMessage、SystemMessage 和 ChatMessage 类型,在日常中将主要使用 HumanMessage、AIMessage 和 SystemMessage。例如下面是使用聊天模型的例子:
from langchain.chat_models import ChatOpenAI
from langchain.schema import (
AIMessage,
HumanMessage,
SystemMessage
)
chat = ChatOpenAI(temperature=0)
(2)也可以通过传递一条消息来完成,例如下面的代码。
chat([HumanMessage(content="Translate this sentence from English to French. I love programming.")])
# -> AIMessage(content="J'aime programmer.", additional_kwargs={})
或者传递多条消息给 OpenAI 的 gpt-3.5-turbo 和 gpt-4 models,例如下面的代码。
messages = [
SystemMessage(content="You are a helpful assistant that translates English to Chinese."),
HumanMessage(content="Translate this sentence from English to Chinese. I love programming.")
]
chat(messages)
# -> AIMessage(content="我喜欢编程。(Wǒ xǐhuān biānchéng.)", additional_kwargs={})
(3)也还可以使用 generate 为多组消息生成完成,这将返回一个带有附加消息参数的 LLMResult,例如下面的代码。
batch_messages = [
[
SystemMessage(content="You are a helpful assistant that translates English to Chinese."),
HumanMessage(content="Translate this sentence from English to Chinese. I love programming.")
],
[
SystemMessage(content="You are a helpful assistant that translates English to Chinese."),
HumanMessage(content="Translate this sentence from English to Chinese. I love artificial intelligence.")
],
]
result = chat.generate(batch_messages)
result
# -> LLMResult(generations=[[ChatGeneration(text="我喜欢编程。(Wǒ xǐhuān biānchéng.)", generation_info=None, message=AIMessage(content="我喜欢编程。(Wǒ xǐhuān biānchéng.)", additional_kwargs={}))], [ChatGeneration(text="我喜爱人工智能。(Wǒ xǐ'ài rén gōng zhì néng.)", generation_info=None, message=AIMessage(content="我喜爱人工智能。(Wǒ xǐ'ài rén gōng zhì néng.)", additional_kwargs={}))]], llm_output={'token_usage': {'prompt_tokens': 71, 'completion_tokens': 18, 'total_tokens': 89}})
还可以从 LLMResult 中提取 tokens 使用等信息,例如下面的代码。
result.llm_output['token_usage']
# -> {'prompt_tokens': 71, 'completion_tokens': 18, 'total_tokens': 89}
(4)对于聊天模型,还可以通过使用 MessagePromptTemplate 来使用模板。我们可以从一个或多个 MessagePromptTemplates 创建 ChatPromptTemplate。ChatPromptTemplate 的方法format_prompt会返回一个 PromptValue,我们可以将其转换为字符串或 Message 对象,这具体取决于是否要使用格式化值作为 LLM 或聊天模型的输入。例如下面是一个例子:
from langchain.chat_models import ChatOpenAI
from langchain.prompts.chat import (
ChatPromptTemplate,
SystemMessagePromptTemplate,
HumanMessagePromptTemplate,
)
chat = ChatOpenAI(temperature=0)
template="You are a helpful assistant that translates {input_language} to {output_language}."
system_message_prompt = SystemMessagePromptTemplate.from_template(template)
human_template="{text}"
human_message_prompt = HumanMessagePromptTemplate.from_template(human_template)
chat_prompt = ChatPromptTemplate.from_messages([system_message_prompt, human_message_prompt])
# get a chat completion from the formatted messages
chat(chat_prompt.format_prompt(input_language="English", output_language="Chinese", text="I love programming.").to_messages())
# -> AIMessage(content="我喜欢编程。(Wǒ xǐhuān biānchéng.)", additional_kwargs={})
(5)也可以将 LLMChain 与 Chat Model 一起使用,例如下面的代码。
from langchain.chat_models import ChatOpenAI
from langchain import LLMChain
from langchain.prompts.chat import (
ChatPromptTemplate,
SystemMessagePromptTemplate,
HumanMessagePromptTemplate,
)
chat = ChatOpenAI(temperature=0)
template="You are a helpful assistant that translates {input_language} to {output_language}."
system_message_prompt = SystemMessagePromptTemplate.from_template(template)
human_template="{text}"
human_message_prompt = HumanMessagePromptTemplate.from_template(human_template)
chat_prompt = ChatPromptTemplate.from_messages([system_message_prompt, human_message_prompt])
chain = LLMChain(llm=chat, prompt=chat_prompt)
chain.run(input_language="English", output_language="Chinese", text="I love programming.")
# -> "我喜欢编程。(Wǒ xǐhuān biānchéng.)"
(6)也可以将代理与聊天模型一起使用,使用 AgentType.CHAT_ZERO_SHOT_REACT_DESCRIPTION 作为代理类型初始化 Agent,例如下面的代码。
from langchain.agents import load_tools
from langchain.agents import initialize_agent
from langchain.agents import AgentType
from langchain.chat_models import ChatOpenAI
from langchain.llms import OpenAI
# First, let's load the language model we're going to use to control the agent.
chat = ChatOpenAI(temperature=0)
# Next, let's load some tools to use. Note that the `llm-math` tool uses an LLM, so we need to pass that in.
llm = OpenAI(temperature=0)
tools = load_tools(["serpapi", "llm-math"], llm=llm)
# Finally, let's initialize an agent with the tools, the language model, and the type of agent we want to use.
agent = initialize_agent(tools, chat, agent=AgentType.CHAT_ZERO_SHOT_REACT_DESCRIPTION, verbose=True)
# Now let's test it out!
agent.run("Who is Olivia Wilde's boyfriend? What is his current age raised to the 0.23 power?")
在上面的代码中,代理将以交互的方式执行搜索和计算以提供最终答案。
(7)也可以将内存与使用聊天模型初始化的链和代理一起使用,这与 Memory for LLMs 的主要区别在于我们可以将以前的消息保留为它们自己唯一的内存对象,而不是将它们压缩成一个字符串。例如在下面的实例中,使用ConversationChain来维护处理人类与AI之间的对话。
实例2-6:使用ConversationChain来维护对话(源码路径:codes\2\practice\Wei.py)
实例文件Wei.py的具体实现代码如下所示。
from langchain.prompts import (
ChatPromptTemplate,
MessagesPlaceholder,
SystemMessagePromptTemplate,
HumanMessagePromptTemplate
)
from langchain.chains import ConversationChain
from langchain.chat_models import ChatOpenAI
from langchain.memory import ConversationBufferMemory
prompt = ChatPromptTemplate.from_messages([
SystemMessagePromptTemplate.from_template("The following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know."),
MessagesPlaceholder(variable_name="history"),
HumanMessagePromptTemplate.from_template("{input}")
])
llm = ChatOpenAI(temperature=0)
memory = ConversationBufferMemory(return_messages=True)
conversation = ConversationChain(memory=memory, prompt=prompt, llm=llm)
conversation.predict(input="Hi there!")
# -> 'Hello! How can I assist you today?'
conversation.predict(input="I'm doing well! Just having a conversation with an AI.")
# -> "That sounds like fun! I'm happy to chat with you. Is there anything specific you'd like to talk about?"
conversation.predict(input="Tell me about yourself.")
# -> "Sure! I am an AI language model created by OpenAI. I was trained on a large dataset of text from the internet, which allows me to understand and generate human-like language. I can answer questions, provide information, and even have conversations like this one. Is there anything else you'd like to know about me?"
在上述在代码中创建了一个 ConversationChain 对象,用于处理人类与AI之间的对话。这个 ConversationChain 使用了一个 ChatPromptTemplate,其中包含了系统消息、历史消息占位符和人类消息模板。然后,通过 ChatOpenAI 类初始化了一个聊天模型 llm,并创建了一个 ConversationBufferMemory 对象作为内存,用于存储历史消息。最后,将这些组件传递给 ConversationChain 构造函数,创建了一个对话链,并使用 predict 方法进行对话预测。
由此可见,LangChain 是一个强大的框架,它通过提供模块化和灵活的方法简化了构建高级语言模型应用程序的过程。通过了解组件、链、提示模板、输出解析器、索引、检索器、聊天消息历史记录和代理等核心概念,您可以创建适合您特定需求的自定义解决方案。LangChain 的适应性和易用性使其成为开发人员的宝贵工具,使他们能够释放语言模型的全部潜力,并在广泛的用例中创建智能的、上下文感知的应用程序。