docs: tool-use use case (#15783)

Co-authored-by: Harrison Chase <hw.chase.17@gmail.com>
This commit is contained in:
Bagatur
2024-01-16 10:41:14 -08:00
committed by GitHub
parent 3d34347a85
commit 8840a8cc95
12 changed files with 2791 additions and 29 deletions

View File

@@ -9,6 +9,7 @@ from typing import (
Union,
)
from langchain_core._api import deprecated
from langchain_core.output_parsers import (
BaseGenerationOutputParser,
BaseLLMOutputParser,
@@ -106,7 +107,7 @@ def create_openai_fn_runnable(
from typing import Optional
from langchain.chains.openai_functions import create_openai_fn_chain
from langchain.chains.openai_functions import create_openai_fn_runnable
from langchain_community.chat_models import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.pydantic_v1 import BaseModel, Field
@@ -180,7 +181,7 @@ def create_structured_output_runnable(
from typing import Optional
from langchain.chains.openai_functions import create_structured_output_chain
from langchain.chains.openai_functions import create_structured_output_runnable
from langchain_community.chat_models import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.pydantic_v1 import BaseModel, Field
@@ -200,7 +201,7 @@ def create_structured_output_runnable(
("human", "Tip: Make sure to answer in the correct format"),
]
)
chain = create_structured_output_chain(Dog, llm, prompt)
chain = create_structured_output_runnable(Dog, llm, prompt)
chain.invoke({"input": "Harry was a chubby brown beagle who loved chicken"})
# -> Dog(name="Harry", color="brown", fav_food="chicken")
""" # noqa: E501
@@ -236,6 +237,7 @@ def create_structured_output_runnable(
""" --- Legacy --- """
@deprecated(since="0.1.1", removal="0.2.0", alternative="create_openai_fn_runnable")
def create_openai_fn_chain(
functions: Sequence[Union[Dict[str, Any], Type[BaseModel], Callable]],
llm: BaseLanguageModel,
@@ -336,6 +338,9 @@ def create_openai_fn_chain(
return llm_chain
@deprecated(
since="0.1.1", removal="0.2.0", alternative="create_structured_output_runnable"
)
def create_structured_output_chain(
output_schema: Union[Dict[str, Any], Type[BaseModel]],
llm: BaseLanguageModel,

View File

@@ -1,5 +1,6 @@
import copy
import json
from json import JSONDecodeError
from typing import Any, List, Type
from langchain_core.exceptions import OutputParserException
@@ -13,6 +14,16 @@ from langchain_core.pydantic_v1 import BaseModel
class JsonOutputToolsParser(BaseGenerationOutputParser[Any]):
"""Parse tools from OpenAI response."""
strict: bool = False
"""Whether to allow non-JSON-compliant strings.
See: https://docs.python.org/3/library/json.html#encoders-and-decoders
Useful when the parsed output may include unicode characters or new lines.
"""
return_id: bool = False
"""Whether to return the tool call id."""
def parse_result(self, result: List[Generation], *, partial: bool = False) -> Any:
generation = result[0]
if not isinstance(generation, ChatGeneration):
@@ -26,16 +37,30 @@ class JsonOutputToolsParser(BaseGenerationOutputParser[Any]):
return []
final_tools = []
exceptions = []
for tool_call in tool_calls:
if "function" not in tool_call:
pass
function_args = tool_call["function"]["arguments"]
final_tools.append(
{
"type": tool_call["function"]["name"],
"args": json.loads(function_args),
}
)
continue
try:
function_args = json.loads(
tool_call["function"]["arguments"], strict=self.strict
)
except JSONDecodeError as e:
exceptions.append(
f"Function {tool_call['function']['name']} arguments:\n\n"
f"{tool_call['function']['arguments']}\n\nare not valid JSON. "
f"Received JSONDecodeError {e}"
)
continue
parsed = {
"type": tool_call["function"]["name"],
"args": function_args,
}
if self.return_id:
parsed["id"] = tool_call["id"]
final_tools.append(parsed)
if exceptions:
raise OutputParserException("\n\n".join(exceptions))
return final_tools
@@ -44,10 +69,17 @@ class JsonOutputKeyToolsParser(JsonOutputToolsParser):
key_name: str
"""The type of tools to return."""
return_single: bool = False
"""Whether to return only the first tool call."""
def parse_result(self, result: List[Generation], *, partial: bool = False) -> Any:
results = super().parse_result(result)
return [res["args"] for res in results if results["type"] == self.key_name]
results = [res for res in results if res["type"] == self.key_name]
if not self.return_id:
results = [res["args"] for res in results]
if self.return_single:
return results[0] if results else None
return results
class PydanticToolsParser(JsonOutputToolsParser):