mirror of
https://github.com/hwchase17/langchain.git
synced 2026-06-09 18:50:33 +00:00
multiple: structured output tracing standard metadata (#29421)
Co-authored-by: Chester Curme <chester.curme@gmail.com>
This commit is contained in:
@@ -1111,9 +1111,13 @@ class ChatAnthropic(BaseChatModel):
|
||||
Added support for TypedDict class as `schema`.
|
||||
|
||||
""" # noqa: E501
|
||||
|
||||
tool_name = convert_to_anthropic_tool(schema)["name"]
|
||||
llm = self.bind_tools([schema], tool_choice=tool_name)
|
||||
formatted_tool = convert_to_anthropic_tool(schema)
|
||||
tool_name = formatted_tool["name"]
|
||||
llm = self.bind_tools(
|
||||
[schema],
|
||||
tool_choice=tool_name,
|
||||
structured_output_format={"kwargs": {}, "schema": formatted_tool},
|
||||
)
|
||||
if isinstance(schema, type) and is_basemodel_subclass(schema):
|
||||
output_parser: OutputParserLike = PydanticToolsParser(
|
||||
tools=[schema], first_tool_only=True
|
||||
|
||||
@@ -965,8 +965,16 @@ class ChatFireworks(BaseChatModel):
|
||||
"schema must be specified when method is 'function_calling'. "
|
||||
"Received None."
|
||||
)
|
||||
tool_name = convert_to_openai_tool(schema)["function"]["name"]
|
||||
llm = self.bind_tools([schema], tool_choice=tool_name)
|
||||
formatted_tool = convert_to_openai_tool(schema)
|
||||
tool_name = formatted_tool["function"]["name"]
|
||||
llm = self.bind_tools(
|
||||
[schema],
|
||||
tool_choice=tool_name,
|
||||
structured_output_format={
|
||||
"kwargs": {"method": "function_calling"},
|
||||
"schema": formatted_tool,
|
||||
},
|
||||
)
|
||||
if is_pydantic_schema:
|
||||
output_parser: OutputParserLike = PydanticToolsParser(
|
||||
tools=[schema], # type: ignore[list-item]
|
||||
@@ -977,7 +985,13 @@ class ChatFireworks(BaseChatModel):
|
||||
key_name=tool_name, first_tool_only=True
|
||||
)
|
||||
elif method == "json_mode":
|
||||
llm = self.bind(response_format={"type": "json_object"})
|
||||
llm = self.bind(
|
||||
response_format={"type": "json_object"},
|
||||
structured_output_format={
|
||||
"kwargs": {"method": "json_mode"},
|
||||
"schema": schema,
|
||||
},
|
||||
)
|
||||
output_parser = (
|
||||
PydanticOutputParser(pydantic_object=schema) # type: ignore[type-var, arg-type]
|
||||
if is_pydantic_schema
|
||||
|
||||
@@ -996,8 +996,16 @@ class ChatGroq(BaseChatModel):
|
||||
"schema must be specified when method is 'function_calling'. "
|
||||
"Received None."
|
||||
)
|
||||
tool_name = convert_to_openai_tool(schema)["function"]["name"]
|
||||
llm = self.bind_tools([schema], tool_choice=tool_name)
|
||||
formatted_tool = convert_to_openai_tool(schema)
|
||||
tool_name = formatted_tool["function"]["name"]
|
||||
llm = self.bind_tools(
|
||||
[schema],
|
||||
tool_choice=tool_name,
|
||||
structured_output_format={
|
||||
"kwargs": {"method": "function_calling"},
|
||||
"schema": formatted_tool,
|
||||
},
|
||||
)
|
||||
if is_pydantic_schema:
|
||||
output_parser: OutputParserLike = PydanticToolsParser(
|
||||
tools=[schema], # type: ignore[list-item]
|
||||
@@ -1008,7 +1016,13 @@ class ChatGroq(BaseChatModel):
|
||||
key_name=tool_name, first_tool_only=True
|
||||
)
|
||||
elif method == "json_mode":
|
||||
llm = self.bind(response_format={"type": "json_object"})
|
||||
llm = self.bind(
|
||||
response_format={"type": "json_object"},
|
||||
structured_output_format={
|
||||
"kwargs": {"method": "json_mode"},
|
||||
"schema": schema,
|
||||
},
|
||||
)
|
||||
output_parser = (
|
||||
PydanticOutputParser(pydantic_object=schema) # type: ignore[type-var, arg-type]
|
||||
if is_pydantic_schema
|
||||
|
||||
@@ -931,7 +931,14 @@ class ChatMistralAI(BaseChatModel):
|
||||
)
|
||||
# TODO: Update to pass in tool name as tool_choice if/when Mistral supports
|
||||
# specifying a tool.
|
||||
llm = self.bind_tools([schema], tool_choice="any")
|
||||
llm = self.bind_tools(
|
||||
[schema],
|
||||
tool_choice="any",
|
||||
structured_output_format={
|
||||
"kwargs": {"method": "function_calling"},
|
||||
"schema": schema,
|
||||
},
|
||||
)
|
||||
if is_pydantic_schema:
|
||||
output_parser: OutputParserLike = PydanticToolsParser(
|
||||
tools=[schema], # type: ignore[list-item]
|
||||
@@ -943,7 +950,16 @@ class ChatMistralAI(BaseChatModel):
|
||||
key_name=key_name, first_tool_only=True
|
||||
)
|
||||
elif method == "json_mode":
|
||||
llm = self.bind(response_format={"type": "json_object"})
|
||||
llm = self.bind(
|
||||
response_format={"type": "json_object"},
|
||||
structured_output_format={
|
||||
"kwargs": {
|
||||
# this is correct - name difference with mistral api
|
||||
"method": "json_mode"
|
||||
},
|
||||
"schema": schema,
|
||||
},
|
||||
)
|
||||
output_parser = (
|
||||
PydanticOutputParser(pydantic_object=schema) # type: ignore[type-var, arg-type]
|
||||
if is_pydantic_schema
|
||||
@@ -956,7 +972,13 @@ class ChatMistralAI(BaseChatModel):
|
||||
"Received None."
|
||||
)
|
||||
response_format = _convert_to_openai_response_format(schema, strict=True)
|
||||
llm = self.bind(response_format=response_format)
|
||||
llm = self.bind(
|
||||
response_format=response_format,
|
||||
structured_output_format={
|
||||
"kwargs": {"method": "json_schema"},
|
||||
"schema": schema,
|
||||
},
|
||||
)
|
||||
|
||||
output_parser = (
|
||||
PydanticOutputParser(pydantic_object=schema) # type: ignore[arg-type]
|
||||
|
||||
@@ -1085,8 +1085,16 @@ class ChatOllama(BaseChatModel):
|
||||
"schema must be specified when method is not 'json_mode'. "
|
||||
"Received None."
|
||||
)
|
||||
tool_name = convert_to_openai_tool(schema)["function"]["name"]
|
||||
llm = self.bind_tools([schema], tool_choice=tool_name)
|
||||
formatted_tool = convert_to_openai_tool(schema)
|
||||
tool_name = formatted_tool["function"]["name"]
|
||||
llm = self.bind_tools(
|
||||
[schema],
|
||||
tool_choice=tool_name,
|
||||
structured_output_format={
|
||||
"kwargs": {"method": method},
|
||||
"schema": formatted_tool,
|
||||
},
|
||||
)
|
||||
if is_pydantic_schema:
|
||||
output_parser: Runnable = PydanticToolsParser(
|
||||
tools=[schema], # type: ignore[list-item]
|
||||
@@ -1097,7 +1105,13 @@ class ChatOllama(BaseChatModel):
|
||||
key_name=tool_name, first_tool_only=True
|
||||
)
|
||||
elif method == "json_mode":
|
||||
llm = self.bind(format="json")
|
||||
llm = self.bind(
|
||||
format="json",
|
||||
structured_output_format={
|
||||
"kwargs": {"method": method},
|
||||
"schema": schema,
|
||||
},
|
||||
)
|
||||
output_parser = (
|
||||
PydanticOutputParser(pydantic_object=schema) # type: ignore[arg-type]
|
||||
if is_pydantic_schema
|
||||
@@ -1111,7 +1125,13 @@ class ChatOllama(BaseChatModel):
|
||||
)
|
||||
if is_pydantic_schema:
|
||||
schema = cast(TypeBaseModel, schema)
|
||||
llm = self.bind(format=schema.model_json_schema())
|
||||
llm = self.bind(
|
||||
format=schema.model_json_schema(),
|
||||
structured_output_format={
|
||||
"kwargs": {"method": method},
|
||||
"schema": schema,
|
||||
},
|
||||
)
|
||||
output_parser = PydanticOutputParser(pydantic_object=schema)
|
||||
else:
|
||||
if is_typeddict(schema):
|
||||
@@ -1126,7 +1146,13 @@ class ChatOllama(BaseChatModel):
|
||||
else:
|
||||
# is JSON schema
|
||||
response_format = schema
|
||||
llm = self.bind(format=response_format)
|
||||
llm = self.bind(
|
||||
format=response_format,
|
||||
structured_output_format={
|
||||
"kwargs": {"method": method},
|
||||
"schema": response_format,
|
||||
},
|
||||
)
|
||||
output_parser = JsonOutputParser()
|
||||
else:
|
||||
raise ValueError(
|
||||
|
||||
@@ -31,8 +31,8 @@ class TestChatOllama(ChatModelIntegrationTests):
|
||||
"Fails with 'AssertionError'. Ollama does not support 'tool_choice' yet."
|
||||
)
|
||||
)
|
||||
def test_structured_output(self, model: BaseChatModel) -> None:
|
||||
super().test_structured_output(model)
|
||||
def test_structured_output(self, model: BaseChatModel, schema_type: str) -> None:
|
||||
super().test_structured_output(model, schema_type)
|
||||
|
||||
@pytest.mark.xfail(
|
||||
reason=(
|
||||
|
||||
@@ -1390,7 +1390,13 @@ class BaseChatOpenAI(BaseChatModel):
|
||||
)
|
||||
tool_name = convert_to_openai_tool(schema)["function"]["name"]
|
||||
bind_kwargs = self._filter_disabled_params(
|
||||
tool_choice=tool_name, parallel_tool_calls=False, strict=strict
|
||||
tool_choice=tool_name,
|
||||
parallel_tool_calls=False,
|
||||
strict=strict,
|
||||
structured_output_format={
|
||||
"kwargs": {"method": method},
|
||||
"schema": schema,
|
||||
},
|
||||
)
|
||||
|
||||
llm = self.bind_tools([schema], **bind_kwargs)
|
||||
@@ -1404,7 +1410,13 @@ class BaseChatOpenAI(BaseChatModel):
|
||||
key_name=tool_name, first_tool_only=True
|
||||
)
|
||||
elif method == "json_mode":
|
||||
llm = self.bind(response_format={"type": "json_object"})
|
||||
llm = self.bind(
|
||||
response_format={"type": "json_object"},
|
||||
structured_output_format={
|
||||
"kwargs": {"method": method},
|
||||
"schema": schema,
|
||||
},
|
||||
)
|
||||
output_parser = (
|
||||
PydanticOutputParser(pydantic_object=schema) # type: ignore[arg-type]
|
||||
if is_pydantic_schema
|
||||
@@ -1417,7 +1429,13 @@ class BaseChatOpenAI(BaseChatModel):
|
||||
"Received None."
|
||||
)
|
||||
response_format = _convert_to_openai_response_format(schema, strict=strict)
|
||||
llm = self.bind(response_format=response_format)
|
||||
llm = self.bind(
|
||||
response_format=response_format,
|
||||
structured_output_format={
|
||||
"kwargs": {"method": method},
|
||||
"schema": convert_to_openai_tool(schema),
|
||||
},
|
||||
)
|
||||
if is_pydantic_schema:
|
||||
output_parser = _oai_structured_outputs_parser.with_types(
|
||||
output_type=cast(type, schema)
|
||||
|
||||
Reference in New Issue
Block a user