mirror of
https://github.com/hwchase17/langchain.git
synced 2025-04-29 20:35:43 +00:00
1466 lines
49 KiB
Plaintext
1466 lines
49 KiB
Plaintext
{
|
||
"cells": [
|
||
{
|
||
"cell_type": "raw",
|
||
"id": "afaf8039",
|
||
"metadata": {},
|
||
"source": [
|
||
"---\n",
|
||
"sidebar_label: OpenAI\n",
|
||
"---"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "cb4dd00a-8893-4a45-96f7-9a9fc341cd61",
|
||
"metadata": {},
|
||
"source": [
|
||
"# ChatOpenAI\n",
|
||
"\n",
|
||
"This notebook provides a quick overview for getting started with OpenAI [chat models](/docs/concepts/chat_models). For detailed documentation of all ChatOpenAI features and configurations head to the [API reference](https://python.langchain.com/api_reference/openai/chat_models/langchain_openai.chat_models.base.ChatOpenAI.html).\n",
|
||
"\n",
|
||
"OpenAI has several chat models. You can find information about their latest models and their costs, context windows, and supported input types in the [OpenAI docs](https://platform.openai.com/docs/models).\n",
|
||
"\n",
|
||
":::info Azure OpenAI\n",
|
||
"\n",
|
||
"Note that certain OpenAI models can also be accessed via the [Microsoft Azure platform](https://azure.microsoft.com/en-us/products/ai-services/openai-service). To use the Azure OpenAI service use the [AzureChatOpenAI integration](/docs/integrations/chat/azure_chat_openai/).\n",
|
||
"\n",
|
||
":::"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "e49f1e0d",
|
||
"metadata": {},
|
||
"source": [
|
||
"## Overview\n",
|
||
"\n",
|
||
"### Integration details\n",
|
||
"| Class | Package | Local | Serializable | [JS support](https://js.langchain.com/docs/integrations/chat/openai) | Package downloads | Package latest |\n",
|
||
"| :--- | :--- | :---: | :---: | :---: | :---: | :---: |\n",
|
||
"| [ChatOpenAI](https://python.langchain.com/api_reference/openai/chat_models/langchain_openai.chat_models.base.ChatOpenAI.html) | [langchain-openai](https://python.langchain.com/api_reference/openai/index.html) | ❌ | beta | ✅ |  |  |\n",
|
||
"\n",
|
||
"### Model features\n",
|
||
"| [Tool calling](/docs/how_to/tool_calling) | [Structured output](/docs/how_to/structured_output/) | JSON mode | Image input | Audio input | Video input | [Token-level streaming](/docs/how_to/chat_streaming/) | Native async | [Token usage](/docs/how_to/chat_token_usage_tracking/) | [Logprobs](/docs/how_to/logprobs/) |\n",
|
||
"| :---: | :---: | :---: | :---: | :---: | :---: | :---: | :---: | :---: | :---: |\n",
|
||
"| ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | \n",
|
||
"\n",
|
||
"## Setup\n",
|
||
"\n",
|
||
"To access OpenAI models you'll need to create an OpenAI account, get an API key, and install the `langchain-openai` integration package.\n",
|
||
"\n",
|
||
"### Credentials\n",
|
||
"\n",
|
||
"Head to https://platform.openai.com to sign up to OpenAI and generate an API key. Once you've done this set the OPENAI_API_KEY environment variable:"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 1,
|
||
"id": "e817fe2e-4f1d-4533-b19e-2400b1cf6ce8",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"import getpass\n",
|
||
"import os\n",
|
||
"\n",
|
||
"if not os.environ.get(\"OPENAI_API_KEY\"):\n",
|
||
" os.environ[\"OPENAI_API_KEY\"] = getpass.getpass(\"Enter your OpenAI API key: \")"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "c2a3ce99-a44a-4ea6-8d23-8a88e332f0f9",
|
||
"metadata": {},
|
||
"source": [
|
||
"If you want to get automated tracing of your model calls you can also set your [LangSmith](https://docs.smith.langchain.com/) API key by uncommenting below:"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "85255d53-ac8a-44e1-aa26-8e567bb77ae7",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"# os.environ[\"LANGSMITH_API_KEY\"] = getpass.getpass(\"Enter your LangSmith API key: \")\n",
|
||
"# os.environ[\"LANGSMITH_TRACING\"] = \"true\""
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "c59722a9-6dbb-45f7-ae59-5be50ca5733d",
|
||
"metadata": {},
|
||
"source": [
|
||
"### Installation\n",
|
||
"\n",
|
||
"The LangChain OpenAI integration lives in the `langchain-openai` package:"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"id": "2113471c-75d7-45df-b784-d78da4ef7aba",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"%pip install -qU langchain-openai"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "1098bc9d-ce83-462b-8c19-f85bf3a159dc",
|
||
"metadata": {},
|
||
"source": [
|
||
"## Instantiation\n",
|
||
"\n",
|
||
"Now we can instantiate our model object and generate chat completions:"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 2,
|
||
"id": "522686de",
|
||
"metadata": {
|
||
"tags": []
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"from langchain_openai import ChatOpenAI\n",
|
||
"\n",
|
||
"llm = ChatOpenAI(\n",
|
||
" model=\"gpt-4o\",\n",
|
||
" temperature=0,\n",
|
||
" max_tokens=None,\n",
|
||
" timeout=None,\n",
|
||
" max_retries=2,\n",
|
||
" # api_key=\"...\", # if you prefer to pass api key in directly instaed of using env vars\n",
|
||
" # base_url=\"...\",\n",
|
||
" # organization=\"...\",\n",
|
||
" # other params...\n",
|
||
")"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "6511982a-734a-4193-a47d-254f8dcaff5e",
|
||
"metadata": {},
|
||
"source": [
|
||
"## Invocation"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 3,
|
||
"id": "ce16ad78-8e6f-48cd-954e-98be75eb5836",
|
||
"metadata": {
|
||
"tags": []
|
||
},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"AIMessage(content=\"J'adore la programmation.\", additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 5, 'prompt_tokens': 31, 'total_tokens': 36}, 'model_name': 'gpt-4o-2024-05-13', 'system_fingerprint': 'fp_3aa7262c27', 'finish_reason': 'stop', 'logprobs': None}, id='run-63219b22-03e3-4561-8cc4-78b7c7c3a3ca-0', usage_metadata={'input_tokens': 31, 'output_tokens': 5, 'total_tokens': 36})"
|
||
]
|
||
},
|
||
"execution_count": 3,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"messages = [\n",
|
||
" (\n",
|
||
" \"system\",\n",
|
||
" \"You are a helpful assistant that translates English to French. Translate the user sentence.\",\n",
|
||
" ),\n",
|
||
" (\"human\", \"I love programming.\"),\n",
|
||
"]\n",
|
||
"ai_msg = llm.invoke(messages)\n",
|
||
"ai_msg"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 4,
|
||
"id": "2cd224b8-4499-41fb-a604-d53a7ff17b2e",
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"J'adore la programmation.\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"print(ai_msg.content)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "778f912a-66ea-4a5d-b3de-6c7db4baba26",
|
||
"metadata": {},
|
||
"source": [
|
||
"## Chaining\n",
|
||
"\n",
|
||
"We can [chain](/docs/how_to/sequence/) our model with a prompt template like so:"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 5,
|
||
"id": "fbb043e6",
|
||
"metadata": {
|
||
"tags": []
|
||
},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"AIMessage(content='Ich liebe das Programmieren.', additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 6, 'prompt_tokens': 26, 'total_tokens': 32}, 'model_name': 'gpt-4o-2024-05-13', 'system_fingerprint': 'fp_3aa7262c27', 'finish_reason': 'stop', 'logprobs': None}, id='run-350585e1-16ca-4dad-9460-3d9e7e49aaf1-0', usage_metadata={'input_tokens': 26, 'output_tokens': 6, 'total_tokens': 32})"
|
||
]
|
||
},
|
||
"execution_count": 5,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"from langchain_core.prompts import ChatPromptTemplate\n",
|
||
"\n",
|
||
"prompt = ChatPromptTemplate.from_messages(\n",
|
||
" [\n",
|
||
" (\n",
|
||
" \"system\",\n",
|
||
" \"You are a helpful assistant that translates {input_language} to {output_language}.\",\n",
|
||
" ),\n",
|
||
" (\"human\", \"{input}\"),\n",
|
||
" ]\n",
|
||
")\n",
|
||
"\n",
|
||
"chain = prompt | llm\n",
|
||
"chain.invoke(\n",
|
||
" {\n",
|
||
" \"input_language\": \"English\",\n",
|
||
" \"output_language\": \"German\",\n",
|
||
" \"input\": \"I love programming.\",\n",
|
||
" }\n",
|
||
")"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "0b1b52a5-b58d-40c9-bcdd-88eb8fb351e2",
|
||
"metadata": {},
|
||
"source": [
|
||
"## Tool calling\n",
|
||
"\n",
|
||
"OpenAI has a [tool calling](https://platform.openai.com/docs/guides/function-calling) (we use \"tool calling\" and \"function calling\" interchangeably here) API that lets you describe tools and their arguments, and have the model return a JSON object with a tool to invoke and the inputs to that tool. tool-calling is extremely useful for building tool-using chains and agents, and for getting structured outputs from models more generally.\n",
|
||
"\n",
|
||
"### ChatOpenAI.bind_tools()\n",
|
||
"\n",
|
||
"With `ChatOpenAI.bind_tools`, we can easily pass in Pydantic classes, dict schemas, LangChain tools, or even functions as tools to the model. Under the hood these are converted to an OpenAI tool schemas, which looks like:\n",
|
||
"```\n",
|
||
"{\n",
|
||
" \"name\": \"...\",\n",
|
||
" \"description\": \"...\",\n",
|
||
" \"parameters\": {...} # JSONSchema\n",
|
||
"}\n",
|
||
"```\n",
|
||
"and passed in every model invocation."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 6,
|
||
"id": "b7ea7690-ec7a-4337-b392-e87d1f39a6ec",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"from pydantic import BaseModel, Field\n",
|
||
"\n",
|
||
"\n",
|
||
"class GetWeather(BaseModel):\n",
|
||
" \"\"\"Get the current weather in a given location\"\"\"\n",
|
||
"\n",
|
||
" location: str = Field(..., description=\"The city and state, e.g. San Francisco, CA\")\n",
|
||
"\n",
|
||
"\n",
|
||
"llm_with_tools = llm.bind_tools([GetWeather])"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 7,
|
||
"id": "1d1ab955-6a68-42f8-bb5d-86eb1111478a",
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_o9udf3EVOWiV4Iupktpbpofk', 'function': {'arguments': '{\"location\":\"San Francisco, CA\"}', 'name': 'GetWeather'}, 'type': 'function'}], 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 17, 'prompt_tokens': 68, 'total_tokens': 85}, 'model_name': 'gpt-4o-2024-05-13', 'system_fingerprint': 'fp_3aa7262c27', 'finish_reason': 'tool_calls', 'logprobs': None}, id='run-1617c9b2-dda5-4120-996b-0333ed5992e2-0', tool_calls=[{'name': 'GetWeather', 'args': {'location': 'San Francisco, CA'}, 'id': 'call_o9udf3EVOWiV4Iupktpbpofk', 'type': 'tool_call'}], usage_metadata={'input_tokens': 68, 'output_tokens': 17, 'total_tokens': 85})"
|
||
]
|
||
},
|
||
"execution_count": 7,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"ai_msg = llm_with_tools.invoke(\n",
|
||
" \"what is the weather like in San Francisco\",\n",
|
||
")\n",
|
||
"ai_msg"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "67b0f63d-15e6-45e0-9e86-2852ddcff54f",
|
||
"metadata": {},
|
||
"source": [
|
||
"### ``strict=True``\n",
|
||
"\n",
|
||
":::info Requires ``langchain-openai>=0.1.21``\n",
|
||
"\n",
|
||
":::\n",
|
||
"\n",
|
||
"As of Aug 6, 2024, OpenAI supports a `strict` argument when calling tools that will enforce that the tool argument schema is respected by the model. See more here: https://platform.openai.com/docs/guides/function-calling\n",
|
||
"\n",
|
||
"**Note**: If ``strict=True`` the tool definition will also be validated, and a subset of JSON schema are accepted. Crucially, schema cannot have optional args (those with default values). Read the full docs on what types of schema are supported here: https://platform.openai.com/docs/guides/structured-outputs/supported-schemas. "
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 8,
|
||
"id": "dc8ac4f1-4039-4392-90c1-2d8331cd6910",
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_jUqhd8wzAIzInTJl72Rla8ht', 'function': {'arguments': '{\"location\":\"San Francisco, CA\"}', 'name': 'GetWeather'}, 'type': 'function'}], 'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 17, 'prompt_tokens': 68, 'total_tokens': 85}, 'model_name': 'gpt-4o-2024-05-13', 'system_fingerprint': 'fp_3aa7262c27', 'finish_reason': 'tool_calls', 'logprobs': None}, id='run-5e3356a9-132d-4623-8e73-dd5a898cf4a6-0', tool_calls=[{'name': 'GetWeather', 'args': {'location': 'San Francisco, CA'}, 'id': 'call_jUqhd8wzAIzInTJl72Rla8ht', 'type': 'tool_call'}], usage_metadata={'input_tokens': 68, 'output_tokens': 17, 'total_tokens': 85})"
|
||
]
|
||
},
|
||
"execution_count": 8,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"llm_with_tools = llm.bind_tools([GetWeather], strict=True)\n",
|
||
"ai_msg = llm_with_tools.invoke(\n",
|
||
" \"what is the weather like in San Francisco\",\n",
|
||
")\n",
|
||
"ai_msg"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "768d1ae4-4b1a-48eb-a329-c8d5051067a3",
|
||
"metadata": {},
|
||
"source": [
|
||
"### AIMessage.tool_calls\n",
|
||
"Notice that the AIMessage has a `tool_calls` attribute. This contains in a standardized ToolCall format that is model-provider agnostic."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 9,
|
||
"id": "166cb7ce-831d-4a7c-9721-abc107f11084",
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"[{'name': 'GetWeather',\n",
|
||
" 'args': {'location': 'San Francisco, CA'},\n",
|
||
" 'id': 'call_jUqhd8wzAIzInTJl72Rla8ht',\n",
|
||
" 'type': 'tool_call'}]"
|
||
]
|
||
},
|
||
"execution_count": 9,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"ai_msg.tool_calls"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "e082c9ac-c7c7-4aff-a8ec-8e220262a59c",
|
||
"metadata": {},
|
||
"source": [
|
||
"For more on binding tools and tool call outputs, head to the [tool calling](/docs/how_to/function_calling) docs."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "84833dd0-17e9-4269-82ed-550639d65751",
|
||
"metadata": {},
|
||
"source": [
|
||
"## Responses API\n",
|
||
"\n",
|
||
":::info Requires ``langchain-openai>=0.3.9``\n",
|
||
"\n",
|
||
":::\n",
|
||
"\n",
|
||
"OpenAI supports a [Responses](https://platform.openai.com/docs/guides/responses-vs-chat-completions) API that is oriented toward building [agentic](/docs/concepts/agents/) applications. It includes a suite of [built-in tools](https://platform.openai.com/docs/guides/tools?api-mode=responses), including web and file search. It also supports management of [conversation state](https://platform.openai.com/docs/guides/conversation-state?api-mode=responses), allowing you to continue a conversational thread without explicitly passing in previous messages, as well as the output from [reasoning processes](https://platform.openai.com/docs/guides/reasoning?api-mode=responses).\n",
|
||
"\n",
|
||
"`ChatOpenAI` will route to the Responses API if one of these features is used. You can also specify `use_responses_api=True` when instantiating `ChatOpenAI`.\n",
|
||
"\n",
|
||
"### Built-in tools\n",
|
||
"\n",
|
||
"Equipping `ChatOpenAI` with built-in tools will ground its responses with outside information, such as via context in files or the web. The [AIMessage](/docs/concepts/messages/#aimessage) generated from the model will include information about the built-in tool invocation.\n",
|
||
"\n",
|
||
"#### Web search\n",
|
||
"\n",
|
||
"To trigger a web search, pass `{\"type\": \"web_search_preview\"}` to the model as you would another tool.\n",
|
||
"\n",
|
||
":::tip\n",
|
||
"\n",
|
||
"You can also pass built-in tools as invocation params:\n",
|
||
"```python\n",
|
||
"llm.invoke(\"...\", tools=[{\"type\": \"web_search_preview\"}])\n",
|
||
"```\n",
|
||
"\n",
|
||
":::"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 1,
|
||
"id": "0d8bfe89-948b-42d4-beac-85ef2a72491d",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"from langchain_openai import ChatOpenAI\n",
|
||
"\n",
|
||
"llm = ChatOpenAI(model=\"gpt-4o-mini\")\n",
|
||
"\n",
|
||
"tool = {\"type\": \"web_search_preview\"}\n",
|
||
"llm_with_tools = llm.bind_tools([tool])\n",
|
||
"\n",
|
||
"response = llm_with_tools.invoke(\"What was a positive news story from today?\")"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "c9fe67c6-38ff-40a5-93b3-a4b7fca76372",
|
||
"metadata": {},
|
||
"source": [
|
||
"Note that the response includes structured [content blocks](/docs/concepts/messages/#content-1) that include both the text of the response and OpenAI [annotations](https://platform.openai.com/docs/guides/tools-web-search?api-mode=responses#output-and-citations) citing its sources:"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 7,
|
||
"id": "3ea5a4b1-f57a-4c8a-97f4-60ab8330a804",
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"[{'type': 'text',\n",
|
||
" 'text': 'Today, a heartwarming story emerged from Minnesota, where a group of high school robotics students built a custom motorized wheelchair for a 2-year-old boy named Cillian Jackson. Born with a genetic condition that limited his mobility, Cillian\\'s family couldn\\'t afford the $20,000 wheelchair he needed. The students at Farmington High School\\'s Rogue Robotics team took it upon themselves to modify a Power Wheels toy car into a functional motorized wheelchair for Cillian, complete with a joystick, safety bumpers, and a harness. One team member remarked, \"I think we won here more than we do in our competitions. Instead of completing a task, we\\'re helping change someone\\'s life.\" ([boredpanda.com](https://www.boredpanda.com/wholesome-global-positive-news/?utm_source=openai))\\n\\nThis act of kindness highlights the profound impact that community support and innovation can have on individuals facing challenges. ',\n",
|
||
" 'annotations': [{'end_index': 778,\n",
|
||
" 'start_index': 682,\n",
|
||
" 'title': '“Global Positive News”: 40 Posts To Remind Us There’s Good In The World',\n",
|
||
" 'type': 'url_citation',\n",
|
||
" 'url': 'https://www.boredpanda.com/wholesome-global-positive-news/?utm_source=openai'}]}]"
|
||
]
|
||
},
|
||
"execution_count": 7,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"response.content"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "95fbc34c-2f12-4d51-92c5-bf62a2f8900c",
|
||
"metadata": {},
|
||
"source": [
|
||
":::tip\n",
|
||
"\n",
|
||
"You can recover just the text content of the response as a string by using `response.text()`. For example, to stream response text:\n",
|
||
"\n",
|
||
"```python\n",
|
||
"for token in llm_with_tools.stream(\"...\"):\n",
|
||
" print(token.text(), end=\"|\")\n",
|
||
"```\n",
|
||
"\n",
|
||
"See the [streaming guide](/docs/how_to/chat_streaming/) for more detail.\n",
|
||
"\n",
|
||
":::"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "2a332940-d409-41ee-ac36-2e9bee900e83",
|
||
"metadata": {},
|
||
"source": [
|
||
"The output message will also contain information from any tool invocations:"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 14,
|
||
"id": "a8011049-6c90-4fcb-82d4-850c72b46941",
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"{'tool_outputs': [{'id': 'ws_67d192aeb6cc81918e736ad4a57937570d6f8507990d9d71',\n",
|
||
" 'status': 'completed',\n",
|
||
" 'type': 'web_search_call'}]}"
|
||
]
|
||
},
|
||
"execution_count": 14,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"response.additional_kwargs"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "288d47bb-3ccb-412f-a3d3-9f6cee0e6214",
|
||
"metadata": {},
|
||
"source": [
|
||
"#### File search\n",
|
||
"\n",
|
||
"To trigger a file search, pass a [file search tool](https://platform.openai.com/docs/guides/tools-file-search) to the model as you would another tool. You will need to populate an OpenAI-managed vector store and include the vector store ID in the tool definition. See [OpenAI documentation](https://platform.openai.com/docs/guides/tools-file-search) for more detail."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 24,
|
||
"id": "1f758726-33ef-4c04-8a54-49adb783bbb3",
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"Deep Research by OpenAI is a new capability integrated into ChatGPT that allows for the execution of multi-step research tasks independently. It can synthesize extensive amounts of online information and produce comprehensive reports similar to what a research analyst would do, significantly speeding up processes that would typically take hours for a human.\n",
|
||
"\n",
|
||
"### Key Features:\n",
|
||
"- **Independent Research**: Users simply provide a prompt, and the model can find, analyze, and synthesize information from hundreds of online sources.\n",
|
||
"- **Multi-Modal Capabilities**: The model is also able to browse user-uploaded files, plot graphs using Python, and embed visualizations in its outputs.\n",
|
||
"- **Training**: Deep Research has been trained using reinforcement learning on real-world tasks that require extensive browsing and reasoning.\n",
|
||
"\n",
|
||
"### Applications:\n",
|
||
"- Useful for professionals in sectors like finance, science, policy, and engineering, enabling them to obtain accurate and thorough research quickly.\n",
|
||
"- It can also be beneficial for consumers seeking personalized recommendations on complex purchases.\n",
|
||
"\n",
|
||
"### Limitations:\n",
|
||
"Although Deep Research presents significant advancements, it has some limitations, such as the potential to hallucinate facts or struggle with authoritative information. \n",
|
||
"\n",
|
||
"Deep Research aims to facilitate access to thorough and documented information, marking a significant step toward the broader goal of developing artificial general intelligence (AGI).\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"llm = ChatOpenAI(model=\"gpt-4o-mini\")\n",
|
||
"\n",
|
||
"openai_vector_store_ids = [\n",
|
||
" \"vs_...\", # your IDs here\n",
|
||
"]\n",
|
||
"\n",
|
||
"tool = {\n",
|
||
" \"type\": \"file_search\",\n",
|
||
" \"vector_store_ids\": openai_vector_store_ids,\n",
|
||
"}\n",
|
||
"llm_with_tools = llm.bind_tools([tool])\n",
|
||
"\n",
|
||
"response = llm_with_tools.invoke(\"What is deep research by OpenAI?\")\n",
|
||
"print(response.text())"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "f88bbd71-83b0-45a6-9141-46ec9da93df6",
|
||
"metadata": {},
|
||
"source": [
|
||
"As with [web search](#web-search), the response will include content blocks with citations:"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 22,
|
||
"id": "865bc14e-1599-438e-be44-857891004979",
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"[{'file_id': 'file-3UzgX7jcC8Dt9ZAFzywg5k',\n",
|
||
" 'index': 346,\n",
|
||
" 'type': 'file_citation',\n",
|
||
" 'filename': 'deep_research_blog.pdf'},\n",
|
||
" {'file_id': 'file-3UzgX7jcC8Dt9ZAFzywg5k',\n",
|
||
" 'index': 575,\n",
|
||
" 'type': 'file_citation',\n",
|
||
" 'filename': 'deep_research_blog.pdf'}]"
|
||
]
|
||
},
|
||
"execution_count": 22,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"response.content[0][\"annotations\"][:2]"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "dd00f6be-2862-4634-a0c3-14ee39915c90",
|
||
"metadata": {},
|
||
"source": [
|
||
"It will also include information from the built-in tool invocations:"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 20,
|
||
"id": "e16a7110-d2d8-45fa-b372-5109f330540b",
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"{'tool_outputs': [{'id': 'fs_67d196fbb83c8191ba20586175331687089228ce932eceb1',\n",
|
||
" 'queries': ['What is deep research by OpenAI?'],\n",
|
||
" 'status': 'completed',\n",
|
||
" 'type': 'file_search_call'}]}"
|
||
]
|
||
},
|
||
"execution_count": 20,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"response.additional_kwargs"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "82b2cfbe-a019-4c6b-a323-a5d7c158cb0d",
|
||
"metadata": {},
|
||
"source": [
|
||
"#### Computer use\n",
|
||
"\n",
|
||
"`ChatOpenAI` supports the `\"computer-use-preview\"` model, which is a specialized model for the built-in computer use tool. To enable, pass a [computer use tool](https://platform.openai.com/docs/guides/tools-computer-use) as you would pass another tool.\n",
|
||
"\n",
|
||
"Currently, tool outputs for computer use are present in `AIMessage.additional_kwargs[\"tool_outputs\"]`. To reply to the computer use tool call, construct a `ToolMessage` with `{\"type\": \"computer_call_output\"}` in its `additional_kwargs`. The content of the message will be a screenshot. Below, we demonstrate a simple example.\n",
|
||
"\n",
|
||
"First, load two screenshots:"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 2,
|
||
"id": "0fab26a6-f041-4d40-8d7c-51ae8a1ad698",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"import base64\n",
|
||
"\n",
|
||
"\n",
|
||
"def load_png_as_base64(file_path):\n",
|
||
" with open(file_path, \"rb\") as image_file:\n",
|
||
" encoded_string = base64.b64encode(image_file.read())\n",
|
||
" return encoded_string.decode(\"utf-8\")\n",
|
||
"\n",
|
||
"\n",
|
||
"screenshot_1_base64 = load_png_as_base64(\n",
|
||
" \"/path/to/screenshot_1.png\"\n",
|
||
") # perhaps a screenshot of an application\n",
|
||
"screenshot_2_base64 = load_png_as_base64(\n",
|
||
" \"/path/to/screenshot_2.png\"\n",
|
||
") # perhaps a screenshot of the Desktop"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 3,
|
||
"id": "ff26e977-1bf2-467d-a853-719c1132bb43",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"from langchain_openai import ChatOpenAI\n",
|
||
"\n",
|
||
"# Initialize model\n",
|
||
"llm = ChatOpenAI(\n",
|
||
" model=\"computer-use-preview\",\n",
|
||
" model_kwargs={\"truncation\": \"auto\"},\n",
|
||
")\n",
|
||
"\n",
|
||
"# Bind computer-use tool\n",
|
||
"tool = {\n",
|
||
" \"type\": \"computer_use_preview\",\n",
|
||
" \"display_width\": 1024,\n",
|
||
" \"display_height\": 768,\n",
|
||
" \"environment\": \"browser\",\n",
|
||
"}\n",
|
||
"llm_with_tools = llm.bind_tools([tool])\n",
|
||
"\n",
|
||
"# Construct input message\n",
|
||
"input_message = {\n",
|
||
" \"role\": \"user\",\n",
|
||
" \"content\": [\n",
|
||
" {\n",
|
||
" \"type\": \"text\",\n",
|
||
" \"text\": (\n",
|
||
" \"Click the red X to close and reveal my Desktop. \"\n",
|
||
" \"Proceed, no confirmation needed.\"\n",
|
||
" ),\n",
|
||
" },\n",
|
||
" {\n",
|
||
" \"type\": \"input_image\",\n",
|
||
" \"image_url\": f\"data:image/png;base64,{screenshot_1_base64}\",\n",
|
||
" },\n",
|
||
" ],\n",
|
||
"}\n",
|
||
"\n",
|
||
"# Invoke model\n",
|
||
"response = llm_with_tools.invoke(\n",
|
||
" [input_message],\n",
|
||
" reasoning={\n",
|
||
" \"generate_summary\": \"concise\",\n",
|
||
" },\n",
|
||
")"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "714bce19-6360-4c09-ba44-59034050527f",
|
||
"metadata": {},
|
||
"source": [
|
||
"The response will include a call to the computer-use tool in its `additional_kwargs`:"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 4,
|
||
"id": "e4a12d04-d1ab-4bd5-b93d-7028f9c818fb",
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"{'reasoning': {'id': 'rs_67ddb381c85081919c46e3e544a161e8051ff325ba1bad35',\n",
|
||
" 'summary': [{'text': 'Closing Visual Studio Code application',\n",
|
||
" 'type': 'summary_text'}],\n",
|
||
" 'type': 'reasoning'},\n",
|
||
" 'tool_outputs': [{'id': 'cu_67ddb385358c8191bf1a127b71bcf1ea051ff325ba1bad35',\n",
|
||
" 'action': {'button': 'left', 'type': 'click', 'x': 17, 'y': 38},\n",
|
||
" 'call_id': 'call_Ae3Ghz8xdqZQ01mosYhXXMho',\n",
|
||
" 'pending_safety_checks': [],\n",
|
||
" 'status': 'completed',\n",
|
||
" 'type': 'computer_call'}]}"
|
||
]
|
||
},
|
||
"execution_count": 4,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"response.additional_kwargs"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "f54e95aa-715e-4ebe-acbd-681ea832abb0",
|
||
"metadata": {},
|
||
"source": [
|
||
"We next construct a ToolMessage with these properties:\n",
|
||
"\n",
|
||
"1. It has a `tool_call_id` matching the `call_id` from the computer-call.\n",
|
||
"2. It has `{\"type\": \"computer_call_output\"}` in its `additional_kwargs`.\n",
|
||
"3. Its content is either an `image_url` or an `input_image` output block (see [OpenAI docs](https://platform.openai.com/docs/guides/tools-computer-use#5-repeat) for formatting)."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 5,
|
||
"id": "003626d2-82d9-41c2-995e-e9f8c1520d30",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"from langchain_core.messages import ToolMessage\n",
|
||
"\n",
|
||
"tool_call_id = response.additional_kwargs[\"tool_outputs\"][0][\"call_id\"]\n",
|
||
"\n",
|
||
"tool_message = ToolMessage(\n",
|
||
" content=[\n",
|
||
" {\n",
|
||
" \"type\": \"input_image\",\n",
|
||
" \"image_url\": f\"data:image/png;base64,{screenshot_2_base64}\",\n",
|
||
" }\n",
|
||
" ],\n",
|
||
" # content=f\"data:image/png;base64,{screenshot_2_base64}\", # <-- also acceptable\n",
|
||
" tool_call_id=tool_call_id,\n",
|
||
" additional_kwargs={\"type\": \"computer_call_output\"},\n",
|
||
")"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "ffa2bc27-389d-4c3a-b646-a9c7eedc2cb7",
|
||
"metadata": {},
|
||
"source": [
|
||
"We can now invoke the model again using the message history:"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 6,
|
||
"id": "ad10a31a-9b81-4dde-8a37-1a656543345a",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"messages = [\n",
|
||
" input_message,\n",
|
||
" response,\n",
|
||
" tool_message,\n",
|
||
"]\n",
|
||
"\n",
|
||
"response_2 = llm_with_tools.invoke(\n",
|
||
" messages,\n",
|
||
" reasoning={\n",
|
||
" \"generate_summary\": \"concise\",\n",
|
||
" },\n",
|
||
")"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 7,
|
||
"id": "fb3a7251-890a-467c-ab59-ae0331221964",
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"'Done! The Desktop is now visible.'"
|
||
]
|
||
},
|
||
"execution_count": 7,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"response_2.text()"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "a2759df1-317c-4dd9-823a-4aab65e41939",
|
||
"metadata": {},
|
||
"source": [
|
||
"Instead of passing back the entire sequence, we can also use the [previous_response_id](#passing-previous_response_id):"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 14,
|
||
"id": "6a40d11b-2426-48ec-bb5e-19e0b36fd74c",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"previous_response_id = response.response_metadata[\"id\"]\n",
|
||
"\n",
|
||
"response_2 = llm_with_tools.invoke(\n",
|
||
" [tool_message],\n",
|
||
" previous_response_id=previous_response_id,\n",
|
||
" reasoning={\n",
|
||
" \"generate_summary\": \"concise\",\n",
|
||
" },\n",
|
||
")"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 15,
|
||
"id": "687d2f05-38b7-42a5-b640-bfd6b4753719",
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"'The Visual Studio Code terminal has been closed and your desktop is now visible.'"
|
||
]
|
||
},
|
||
"execution_count": 15,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"response_2.text()"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "6fda05f0-4b81-4709-9407-f316d760ad50",
|
||
"metadata": {},
|
||
"source": [
|
||
"### Managing conversation state\n",
|
||
"\n",
|
||
"The Responses API supports management of [conversation state](https://platform.openai.com/docs/guides/conversation-state?api-mode=responses).\n",
|
||
"\n",
|
||
"#### Manually manage state\n",
|
||
"\n",
|
||
"You can manage the state manually or using [LangGraph](/docs/tutorials/chatbot/), as with other chat models:"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 4,
|
||
"id": "51d3e4d3-ea78-426c-9205-aecb0937fca7",
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"As of March 12, 2025, here are some positive news stories that highlight recent uplifting events:\n",
|
||
"\n",
|
||
"*... exemplify positive developments in health, environmental sustainability, and community well-being. \n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"from langchain_openai import ChatOpenAI\n",
|
||
"\n",
|
||
"llm = ChatOpenAI(model=\"gpt-4o-mini\")\n",
|
||
"\n",
|
||
"tool = {\"type\": \"web_search_preview\"}\n",
|
||
"llm_with_tools = llm.bind_tools([tool])\n",
|
||
"\n",
|
||
"first_query = \"What was a positive news story from today?\"\n",
|
||
"messages = [{\"role\": \"user\", \"content\": first_query}]\n",
|
||
"\n",
|
||
"response = llm_with_tools.invoke(messages)\n",
|
||
"response_text = response.text()\n",
|
||
"print(f\"{response_text[:100]}... {response_text[-100:]}\")"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 5,
|
||
"id": "5da9d20f-9712-46f4-a395-5be5a7c1bc62",
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"Your question was: \"What was a positive news story from today?\"\n",
|
||
"\n",
|
||
"The last sentence of my answer was: \"These stories exemplify positive developments in health, environmental sustainability, and community well-being.\"\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"second_query = (\n",
|
||
" \"Repeat my question back to me, as well as the last sentence of your answer.\"\n",
|
||
")\n",
|
||
"\n",
|
||
"messages.extend(\n",
|
||
" [\n",
|
||
" response,\n",
|
||
" {\"role\": \"user\", \"content\": second_query},\n",
|
||
" ]\n",
|
||
")\n",
|
||
"second_response = llm_with_tools.invoke(messages)\n",
|
||
"print(second_response.text())"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "5fd8ca21-8a5e-4294-af32-11f26a040171",
|
||
"metadata": {},
|
||
"source": [
|
||
":::tip\n",
|
||
"\n",
|
||
"You can use [LangGraph](https://langchain-ai.github.io/langgraph/) to manage conversational threads for you in a variety of backends, including in-memory and Postgres. See [this tutorial](/docs/tutorials/chatbot/) to get started.\n",
|
||
"\n",
|
||
":::\n",
|
||
"\n",
|
||
"\n",
|
||
"#### Passing `previous_response_id`\n",
|
||
"\n",
|
||
"When using the Responses API, LangChain messages will include an `\"id\"` field in its metadata. Passing this ID to subsequent invocations will continue the conversation. Note that this is [equivalent](https://platform.openai.com/docs/guides/conversation-state?api-mode=responses#openai-apis-for-conversation-state) to manually passing in messages from a billing perspective."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 6,
|
||
"id": "009e541a-b372-410e-b9dd-608a8052ce09",
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"Hi Bob! How can I assist you today?\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"from langchain_openai import ChatOpenAI\n",
|
||
"\n",
|
||
"llm = ChatOpenAI(\n",
|
||
" model=\"gpt-4o-mini\",\n",
|
||
" use_responses_api=True,\n",
|
||
")\n",
|
||
"response = llm.invoke(\"Hi, I'm Bob.\")\n",
|
||
"print(response.text())"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 7,
|
||
"id": "393a443a-4c5f-4a07-bc0e-c76e529b35e3",
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"Your name is Bob. How can I help you today, Bob?\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"second_response = llm.invoke(\n",
|
||
" \"What is my name?\",\n",
|
||
" previous_response_id=response.response_metadata[\"id\"],\n",
|
||
")\n",
|
||
"print(second_response.text())"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "67bf5bd2-0935-40a0-b1cd-c6662b681d4b",
|
||
"metadata": {},
|
||
"source": [
|
||
"### Reasoning output\n",
|
||
"\n",
|
||
"Some OpenAI models will generate separate text content illustrating their reasoning process. See OpenAI's [reasoning documentation](https://platform.openai.com/docs/guides/reasoning?api-mode=responses) for details.\n",
|
||
"\n",
|
||
"OpenAI can return a summary of the model's reasoning (although it doesn't expose the raw reasoning tokens). To configure `ChatOpenAI` to return this summary, specify the `reasoning` parameter:"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 2,
|
||
"id": "8d322f3a-0732-45ab-ac95-dfd4596e0d85",
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"'3^3 = 3 × 3 × 3 = 27.'"
|
||
]
|
||
},
|
||
"execution_count": 2,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"from langchain_openai import ChatOpenAI\n",
|
||
"\n",
|
||
"reasoning = {\n",
|
||
" \"effort\": \"medium\", # 'low', 'medium', or 'high'\n",
|
||
" \"summary\": \"auto\", # 'detailed', 'auto', or None\n",
|
||
"}\n",
|
||
"\n",
|
||
"llm = ChatOpenAI(\n",
|
||
" model=\"o4-mini\",\n",
|
||
" use_responses_api=True,\n",
|
||
" model_kwargs={\"reasoning\": reasoning},\n",
|
||
")\n",
|
||
"response = llm.invoke(\"What is 3^3?\")\n",
|
||
"\n",
|
||
"# Output\n",
|
||
"response.text()"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 3,
|
||
"id": "d7dcc082-b7c8-41b7-a5e2-441b9679e41b",
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"**Calculating power of three**\n",
|
||
"\n",
|
||
"The user is asking for the result of 3 to the power of 3, which I know is 27. It's a straightforward question, so I’ll keep my answer concise: 27. I could explain that this is the same as multiplying 3 by itself twice: 3 × 3 × 3 equals 27. However, since the user likely just needs the answer, I’ll simply respond with 27.\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"# Reasoning\n",
|
||
"reasoning = response.additional_kwargs[\"reasoning\"]\n",
|
||
"for block in reasoning[\"summary\"]:\n",
|
||
" print(block[\"text\"])"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "57e27714",
|
||
"metadata": {},
|
||
"source": [
|
||
"## Fine-tuning\n",
|
||
"\n",
|
||
"You can call fine-tuned OpenAI models by passing in your corresponding `modelName` parameter.\n",
|
||
"\n",
|
||
"This generally takes the form of `ft:{OPENAI_MODEL_NAME}:{ORG_NAME}::{MODEL_ID}`. For example:"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 11,
|
||
"id": "33c4a8b0",
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"AIMessage(content=\"J'adore la programmation.\", additional_kwargs={'refusal': None}, response_metadata={'token_usage': {'completion_tokens': 8, 'prompt_tokens': 31, 'total_tokens': 39}, 'model_name': 'ft:gpt-3.5-turbo-0613:langchain::7qTVM5AR', 'system_fingerprint': None, 'finish_reason': 'stop', 'logprobs': None}, id='run-0f39b30e-c56e-4f3b-af99-5c948c984146-0', usage_metadata={'input_tokens': 31, 'output_tokens': 8, 'total_tokens': 39})"
|
||
]
|
||
},
|
||
"execution_count": 11,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"fine_tuned_model = ChatOpenAI(\n",
|
||
" temperature=0, model_name=\"ft:gpt-3.5-turbo-0613:langchain::7qTVM5AR\"\n",
|
||
")\n",
|
||
"\n",
|
||
"fine_tuned_model.invoke(messages)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "5d5d9793",
|
||
"metadata": {},
|
||
"source": [
|
||
"## Multimodal Inputs\n",
|
||
"\n",
|
||
"OpenAI has models that support multimodal inputs. You can pass in images or audio to these models. For more information on how to do this in LangChain, head to the [multimodal inputs](/docs/how_to/multimodal_inputs) docs.\n",
|
||
"\n",
|
||
"You can see the list of models that support different modalities in [OpenAI's documentation](https://platform.openai.com/docs/models).\n",
|
||
"\n",
|
||
"At the time of this doc's writing, the main OpenAI models you would use would be:\n",
|
||
"\n",
|
||
"- Image inputs: `gpt-4o`, `gpt-4o-mini`\n",
|
||
"- Audio inputs: `gpt-4o-audio-preview`\n",
|
||
"\n",
|
||
"For an example of passing in image inputs, see the [multimodal inputs how-to guide](/docs/how_to/multimodal_inputs).\n",
|
||
"\n",
|
||
"Below is an example of passing audio inputs to `gpt-4o-audio-preview`:"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 8,
|
||
"id": "39d08780",
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"\"I'm sorry, but I can't create audio content that involves yelling. Is there anything else I can help you with?\""
|
||
]
|
||
},
|
||
"execution_count": 8,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"import base64\n",
|
||
"\n",
|
||
"from langchain_openai import ChatOpenAI\n",
|
||
"\n",
|
||
"llm = ChatOpenAI(\n",
|
||
" model=\"gpt-4o-audio-preview\",\n",
|
||
" temperature=0,\n",
|
||
")\n",
|
||
"\n",
|
||
"with open(\n",
|
||
" \"../../../../libs/partners/openai/tests/integration_tests/chat_models/audio_input.wav\",\n",
|
||
" \"rb\",\n",
|
||
") as f:\n",
|
||
" # b64 encode it\n",
|
||
" audio = f.read()\n",
|
||
" audio_b64 = base64.b64encode(audio).decode()\n",
|
||
"\n",
|
||
"\n",
|
||
"output_message = llm.invoke(\n",
|
||
" [\n",
|
||
" (\n",
|
||
" \"human\",\n",
|
||
" [\n",
|
||
" {\"type\": \"text\", \"text\": \"Transcribe the following:\"},\n",
|
||
" # the audio clip says \"I'm sorry, but I can't create...\"\n",
|
||
" {\n",
|
||
" \"type\": \"input_audio\",\n",
|
||
" \"input_audio\": {\"data\": audio_b64, \"format\": \"wav\"},\n",
|
||
" },\n",
|
||
" ],\n",
|
||
" ),\n",
|
||
" ]\n",
|
||
")\n",
|
||
"output_message.content"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "5c35d0a4-a6b8-4d35-a02b-a37a8bda5692",
|
||
"metadata": {},
|
||
"source": [
|
||
"## Predicted output\n",
|
||
"\n",
|
||
":::info\n",
|
||
"Requires `langchain-openai>=0.2.6`\n",
|
||
":::\n",
|
||
"\n",
|
||
"Some OpenAI models (such as their `gpt-4o` and `gpt-4o-mini` series) support [Predicted Outputs](https://platform.openai.com/docs/guides/latency-optimization#use-predicted-outputs), which allow you to pass in a known portion of the LLM's expected output ahead of time to reduce latency. This is useful for cases such as editing text or code, where only a small part of the model's output will change.\n",
|
||
"\n",
|
||
"Here's an example:"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 3,
|
||
"id": "88fee1e9-58c1-42ad-ae23-24b882e175e7",
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"/// <summary>\n",
|
||
"/// Represents a user with a first name, last name, and email.\n",
|
||
"/// </summary>\n",
|
||
"public class User\n",
|
||
"{\n",
|
||
" /// <summary>\n",
|
||
" /// Gets or sets the user's first name.\n",
|
||
" /// </summary>\n",
|
||
" public string FirstName { get; set; }\n",
|
||
"\n",
|
||
" /// <summary>\n",
|
||
" /// Gets or sets the user's last name.\n",
|
||
" /// </summary>\n",
|
||
" public string LastName { get; set; }\n",
|
||
"\n",
|
||
" /// <summary>\n",
|
||
" /// Gets or sets the user's email.\n",
|
||
" /// </summary>\n",
|
||
" public string Email { get; set; }\n",
|
||
"}\n",
|
||
"{'token_usage': {'completion_tokens': 226, 'prompt_tokens': 166, 'total_tokens': 392, 'completion_tokens_details': {'accepted_prediction_tokens': 49, 'audio_tokens': None, 'reasoning_tokens': 0, 'rejected_prediction_tokens': 107}, 'prompt_tokens_details': {'audio_tokens': None, 'cached_tokens': 0}}, 'model_name': 'gpt-4o-2024-08-06', 'system_fingerprint': 'fp_45cf54deae', 'finish_reason': 'stop', 'logprobs': None}\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"code = \"\"\"\n",
|
||
"/// <summary>\n",
|
||
"/// Represents a user with a first name, last name, and username.\n",
|
||
"/// </summary>\n",
|
||
"public class User\n",
|
||
"{\n",
|
||
" /// <summary>\n",
|
||
" /// Gets or sets the user's first name.\n",
|
||
" /// </summary>\n",
|
||
" public string FirstName { get; set; }\n",
|
||
"\n",
|
||
" /// <summary>\n",
|
||
" /// Gets or sets the user's last name.\n",
|
||
" /// </summary>\n",
|
||
" public string LastName { get; set; }\n",
|
||
"\n",
|
||
" /// <summary>\n",
|
||
" /// Gets or sets the user's username.\n",
|
||
" /// </summary>\n",
|
||
" public string Username { get; set; }\n",
|
||
"}\n",
|
||
"\"\"\"\n",
|
||
"\n",
|
||
"llm = ChatOpenAI(model=\"gpt-4o\")\n",
|
||
"query = (\n",
|
||
" \"Replace the Username property with an Email property. \"\n",
|
||
" \"Respond only with code, and with no markdown formatting.\"\n",
|
||
")\n",
|
||
"response = llm.invoke(\n",
|
||
" [{\"role\": \"user\", \"content\": query}, {\"role\": \"user\", \"content\": code}],\n",
|
||
" prediction={\"type\": \"content\", \"content\": code},\n",
|
||
")\n",
|
||
"print(response.content)\n",
|
||
"print(response.response_metadata)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "2ee1b26d-a388-4e7c-9f40-bfd1388ecc03",
|
||
"metadata": {},
|
||
"source": [
|
||
"Note that currently predictions are billed as additional tokens and may increase your usage and costs in exchange for this reduced latency."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "feb4a499",
|
||
"metadata": {},
|
||
"source": [
|
||
"## Audio Generation (Preview)\n",
|
||
"\n",
|
||
":::info\n",
|
||
"Requires `langchain-openai>=0.2.3`\n",
|
||
":::\n",
|
||
"\n",
|
||
"OpenAI has a new [audio generation feature](https://platform.openai.com/docs/guides/audio?audio-generation-quickstart-example=audio-out) that allows you to use audio inputs and outputs with the `gpt-4o-audio-preview` model."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 1,
|
||
"id": "f67a2cac",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"from langchain_openai import ChatOpenAI\n",
|
||
"\n",
|
||
"llm = ChatOpenAI(\n",
|
||
" model=\"gpt-4o-audio-preview\",\n",
|
||
" temperature=0,\n",
|
||
" model_kwargs={\n",
|
||
" \"modalities\": [\"text\", \"audio\"],\n",
|
||
" \"audio\": {\"voice\": \"alloy\", \"format\": \"wav\"},\n",
|
||
" },\n",
|
||
")\n",
|
||
"\n",
|
||
"output_message = llm.invoke(\n",
|
||
" [\n",
|
||
" (\"human\", \"Are you made by OpenAI? Just answer yes or no\"),\n",
|
||
" ]\n",
|
||
")"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "b7dd4e8b",
|
||
"metadata": {},
|
||
"source": [
|
||
"`output_message.additional_kwargs['audio']` will contain a dictionary like\n",
|
||
"```python\n",
|
||
"{\n",
|
||
" 'data': '<audio data b64-encoded',\n",
|
||
" 'expires_at': 1729268602,\n",
|
||
" 'id': 'audio_67127d6a44348190af62c1530ef0955a',\n",
|
||
" 'transcript': 'Yes.'\n",
|
||
"}\n",
|
||
"```\n",
|
||
"and the format will be what was passed in `model_kwargs['audio']['format']`.\n",
|
||
"\n",
|
||
"We can also pass this message with audio data back to the model as part of a message history before openai `expires_at` is reached.\n",
|
||
"\n",
|
||
":::note\n",
|
||
"Output audio is stored under the `audio` key in `AIMessage.additional_kwargs`, but input content blocks are typed with an `input_audio` type and key in `HumanMessage.content` lists. \n",
|
||
"\n",
|
||
"For more information, see OpenAI's [audio docs](https://platform.openai.com/docs/guides/audio).\n",
|
||
":::"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 8,
|
||
"id": "f5ae473d",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"history = [\n",
|
||
" (\"human\", \"Are you made by OpenAI? Just answer yes or no\"),\n",
|
||
" output_message,\n",
|
||
" (\"human\", \"And what is your name? Just give your name.\"),\n",
|
||
"]\n",
|
||
"second_output_message = llm.invoke(history)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "90c18d18-b25c-4509-a639-bd652b92f518",
|
||
"metadata": {},
|
||
"source": [
|
||
"## Flex processing\n",
|
||
"\n",
|
||
"OpenAI offers a variety of [service tiers](https://platform.openai.com/docs/guides/flex-processing). The \"flex\" tier offers cheaper pricing for requests, with the trade-off that responses may take longer and resources might not always be available. This approach is best suited for non-critical tasks, including model testing, data enhancement, or jobs that can be run asynchronously.\n",
|
||
"\n",
|
||
"To use it, initialize the model with `service_tier=\"flex\"`:\n",
|
||
"```python\n",
|
||
"llm = ChatOpenAI(model=\"o4-mini\", service_tier=\"flex\")\n",
|
||
"```\n",
|
||
"\n",
|
||
"Note that this is a beta feature that is only available for a subset of models. See OpenAI [docs](https://platform.openai.com/docs/guides/flex-processing) for more detail."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "a796d728-971b-408b-88d5-440015bbb941",
|
||
"metadata": {},
|
||
"source": [
|
||
"## API reference\n",
|
||
"\n",
|
||
"For detailed documentation of all ChatOpenAI features and configurations head to the [API reference](https://python.langchain.com/api_reference/openai/chat_models/langchain_openai.chat_models.base.ChatOpenAI.html)."
|
||
]
|
||
}
|
||
],
|
||
"metadata": {
|
||
"kernelspec": {
|
||
"display_name": "Python 3 (ipykernel)",
|
||
"language": "python",
|
||
"name": "python3"
|
||
},
|
||
"language_info": {
|
||
"codemirror_mode": {
|
||
"name": "ipython",
|
||
"version": 3
|
||
},
|
||
"file_extension": ".py",
|
||
"mimetype": "text/x-python",
|
||
"name": "python",
|
||
"nbconvert_exporter": "python",
|
||
"pygments_lexer": "ipython3",
|
||
"version": "3.10.4"
|
||
}
|
||
},
|
||
"nbformat": 4,
|
||
"nbformat_minor": 5
|
||
}
|