Skip to content

Commit

Permalink
Merge branch 'master' into redis/langchain-redis-docs
Browse files Browse the repository at this point in the history
  • Loading branch information
efriis authored Aug 6, 2024
2 parents b9230d1 + 23c9aba commit c3efb5e
Show file tree
Hide file tree
Showing 11 changed files with 605 additions and 1,019 deletions.
148 changes: 129 additions & 19 deletions docs/docs/how_to/qa_sources.ipynb

Large diffs are not rendered by default.

66 changes: 50 additions & 16 deletions docs/docs/integrations/chat/openai.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -56,23 +56,16 @@
},
{
"cell_type": "code",
"execution_count": 2,
"execution_count": 1,
"id": "e817fe2e-4f1d-4533-b19e-2400b1cf6ce8",
"metadata": {},
"outputs": [
{
"name": "stdin",
"output_type": "stream",
"text": [
"Enter your OpenAI API key: ········\n"
]
}
],
"outputs": [],
"source": [
"import getpass\n",
"import os\n",
"\n",
"os.environ[\"OPENAI_API_KEY\"] = getpass.getpass(\"Enter your OpenAI API key: \")"
"if not os.environ.get(\"OPENAI_API_KEY\"):\n",
" os.environ[\"OPENAI_API_KEY\"] = getpass.getpass(\"Enter your OpenAI API key: \")"
]
},
{
Expand Down Expand Up @@ -126,7 +119,7 @@
},
{
"cell_type": "code",
"execution_count": 1,
"execution_count": 2,
"id": "522686de",
"metadata": {
"tags": []
Expand Down Expand Up @@ -281,12 +274,12 @@
},
{
"cell_type": "code",
"execution_count": 9,
"execution_count": 4,
"id": "b7ea7690-ec7a-4337-b392-e87d1f39a6ec",
"metadata": {},
"outputs": [],
"source": [
"from langchain_core.pydantic_v1 import BaseModel, Field\n",
"from pydantic import BaseModel, Field\n",
"\n",
"\n",
"class GetWeather(BaseModel):\n",
Expand Down Expand Up @@ -322,6 +315,47 @@
"ai_msg"
]
},
{
"cell_type": "markdown",
"id": "67b0f63d-15e6-45e0-9e86-2852ddcff54f",
"metadata": {},
"source": [
"### ``strict=True``\n",
"\n",
":::info Requires ``langchain-openai>=0.1.21rc1``\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": 5,
"id": "dc8ac4f1-4039-4392-90c1-2d8331cd6910",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_VYEfpPDh3npMQ95J9EWmWvSn', 'function': {'arguments': '{\"location\":\"San Francisco, CA\"}', 'name': 'GetWeather'}, 'type': 'function'}]}, 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-a4c6749b-adbb-45c7-8b17-8d6835d5c443-0', tool_calls=[{'name': 'GetWeather', 'args': {'location': 'San Francisco, CA'}, 'id': 'call_VYEfpPDh3npMQ95J9EWmWvSn', 'type': 'tool_call'}], usage_metadata={'input_tokens': 68, 'output_tokens': 17, 'total_tokens': 85})"
]
},
"execution_count": 5,
"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",
Expand Down Expand Up @@ -412,9 +446,9 @@
],
"metadata": {
"kernelspec": {
"display_name": "poetry-venv-2",
"display_name": "poetry-venv-311",
"language": "python",
"name": "poetry-venv-2"
"name": "poetry-venv-311"
},
"language_info": {
"codemirror_mode": {
Expand Down
36 changes: 28 additions & 8 deletions libs/core/langchain_core/utils/function_calling.py
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,8 @@ def format_tool_to_openai_tool(tool: BaseTool) -> ToolDescription:

def convert_to_openai_function(
function: Union[Dict[str, Any], Type, Callable, BaseTool],
*,
strict: Optional[bool] = None,
) -> Dict[str, Any]:
"""Convert a raw function/class to an OpenAI function.
Expand All @@ -330,6 +332,9 @@ def convert_to_openai_function(
Tool object, or a Python function. If a dictionary is passed in, it is
assumed to already be a valid OpenAI function or a JSON schema with
top-level 'title' and 'description' keys specified.
strict: If True, model output is guaranteed to exactly match the JSON Schema
provided in the function definition. If None, ``strict`` argument will not
be included in function definition.
Returns:
A dict version of the passed in function which is compatible with the OpenAI
Expand All @@ -344,25 +349,27 @@ def convert_to_openai_function(
if isinstance(function, dict) and all(
k in function for k in ("name", "description", "parameters")
):
return function
oai_function = function
# a JSON schema with title and description
elif isinstance(function, dict) and all(
k in function for k in ("title", "description", "properties")
):
function = function.copy()
return {
oai_function = {
"name": function.pop("title"),
"description": function.pop("description"),
"parameters": function,
}
elif isinstance(function, type) and is_basemodel_subclass(function):
return cast(Dict, convert_pydantic_to_openai_function(function))
oai_function = cast(Dict, convert_pydantic_to_openai_function(function))
elif is_typeddict(function):
return cast(Dict, _convert_typed_dict_to_openai_function(cast(Type, function)))
oai_function = cast(
Dict, _convert_typed_dict_to_openai_function(cast(Type, function))
)
elif isinstance(function, BaseTool):
return cast(Dict, format_tool_to_openai_function(function))
oai_function = cast(Dict, format_tool_to_openai_function(function))
elif callable(function):
return cast(Dict, convert_python_function_to_openai_function(function))
oai_function = cast(Dict, convert_python_function_to_openai_function(function))
else:
raise ValueError(
f"Unsupported function\n\n{function}\n\nFunctions must be passed in"
Expand All @@ -371,9 +378,18 @@ def convert_to_openai_function(
" 'title' and 'description' keys."
)

if strict is not None:
oai_function["strict"] = strict
# As of 08/06/24, OpenAI requires that additionalProperties be supplied and set
# to False if strict is True.
oai_function["parameters"]["additionalProperties"] = False
return oai_function


def convert_to_openai_tool(
tool: Union[Dict[str, Any], Type[BaseModel], Callable, BaseTool],
*,
strict: Optional[bool] = None,
) -> Dict[str, Any]:
"""Convert a raw function/class to an OpenAI tool.
Expand All @@ -382,15 +398,19 @@ def convert_to_openai_tool(
BaseTool. If a dictionary is passed in, it is assumed to already be a valid
OpenAI tool, OpenAI function, or a JSON schema with top-level 'title' and
'description' keys specified.
strict: If True, model output is guaranteed to exactly match the JSON Schema
provided in the function definition. If None, ``strict`` argument will not
be included in tool definition.
Returns:
A dict version of the passed in tool which is compatible with the
OpenAI tool-calling API.
"""
if isinstance(tool, dict) and tool.get("type") == "function" and "function" in tool:
return tool
function = convert_to_openai_function(tool)
return {"type": "function", "function": function}
oai_function = convert_to_openai_function(tool, strict=strict)
oai_tool: Dict[str, Any] = {"type": "function", "function": oai_function}
return oai_tool


def tool_example_to_messages(
Expand Down
2 changes: 1 addition & 1 deletion libs/core/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"

[tool.poetry]
name = "langchain-core"
version = "0.2.28"
version = "0.2.29rc1"
description = "Building applications with LLMs through composability"
authors = []
license = "MIT"
Expand Down
6 changes: 5 additions & 1 deletion libs/langchain/tests/unit_tests/chat_models/test_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,11 @@ def test_configurable() -> None:
"tools": [
{
"type": "function",
"function": {"name": "foo", "description": "foo", "parameters": {}},
"function": {
"name": "foo",
"description": "foo",
"parameters": {},
},
}
]
},
Expand Down
Loading

0 comments on commit c3efb5e

Please sign in to comment.