mirror of
https://github.com/hwchase17/langchain.git
synced 2025-06-28 17:38:36 +00:00
mistralai[patch]: Added Json Mode for ChatMistralAI (#22213)
- **Description:** Powered
[ChatMistralAI.with_structured_output](fbfed65fb1/libs/partners/mistralai/langchain_mistralai/chat_models.py (L609)
)
via json mode
- **Issue:** #22081
---------
Co-authored-by: Bagatur <baskaryan@gmail.com>
This commit is contained in:
parent
25c270b5a5
commit
577ed68b59
@ -24,6 +24,7 @@ CHAT_MODEL_FEAT_TABLE = {
|
|||||||
"ChatMistralAI": {
|
"ChatMistralAI": {
|
||||||
"tool_calling": True,
|
"tool_calling": True,
|
||||||
"structured_output": True,
|
"structured_output": True,
|
||||||
|
"json_model": True,
|
||||||
"package": "langchain-mistralai",
|
"package": "langchain-mistralai",
|
||||||
"link": "/docs/integrations/chat/mistralai/",
|
"link": "/docs/integrations/chat/mistralai/",
|
||||||
},
|
},
|
||||||
|
@ -12,6 +12,7 @@ from typing import (
|
|||||||
Dict,
|
Dict,
|
||||||
Iterator,
|
Iterator,
|
||||||
List,
|
List,
|
||||||
|
Literal,
|
||||||
Optional,
|
Optional,
|
||||||
Sequence,
|
Sequence,
|
||||||
Tuple,
|
Tuple,
|
||||||
@ -49,6 +50,10 @@ from langchain_core.messages import (
|
|||||||
ToolCall,
|
ToolCall,
|
||||||
ToolMessage,
|
ToolMessage,
|
||||||
)
|
)
|
||||||
|
from langchain_core.output_parsers import (
|
||||||
|
JsonOutputParser,
|
||||||
|
PydanticOutputParser,
|
||||||
|
)
|
||||||
from langchain_core.output_parsers.base import OutputParserLike
|
from langchain_core.output_parsers.base import OutputParserLike
|
||||||
from langchain_core.output_parsers.openai_tools import (
|
from langchain_core.output_parsers.openai_tools import (
|
||||||
JsonOutputKeyToolsParser,
|
JsonOutputKeyToolsParser,
|
||||||
@ -608,8 +613,9 @@ class ChatMistralAI(BaseChatModel):
|
|||||||
|
|
||||||
def with_structured_output(
|
def with_structured_output(
|
||||||
self,
|
self,
|
||||||
schema: Union[Dict, Type[BaseModel]],
|
schema: Optional[Union[Dict, Type[BaseModel]]] = None,
|
||||||
*,
|
*,
|
||||||
|
method: Literal["function_calling", "json_mode"] = "function_calling",
|
||||||
include_raw: bool = False,
|
include_raw: bool = False,
|
||||||
**kwargs: Any,
|
**kwargs: Any,
|
||||||
) -> Runnable[LanguageModelInput, Union[Dict, BaseModel]]:
|
) -> Runnable[LanguageModelInput, Union[Dict, BaseModel]]:
|
||||||
@ -622,6 +628,12 @@ class ChatMistralAI(BaseChatModel):
|
|||||||
attributes will be validated, whereas with a dict they will not be. If
|
attributes will be validated, whereas with a dict they will not be. If
|
||||||
`method` is "function_calling" and `schema` is a dict, then the dict
|
`method` is "function_calling" and `schema` is a dict, then the dict
|
||||||
must match the OpenAI function-calling spec.
|
must match the OpenAI function-calling spec.
|
||||||
|
method: The method for steering model generation, either "function_calling"
|
||||||
|
or "json_mode". If "function_calling" then the schema will be converted
|
||||||
|
to an OpenAI function and the returned model will make use of the
|
||||||
|
function-calling API. If "json_mode" then OpenAI's JSON mode will be
|
||||||
|
used. Note that if using "json_mode" then you must include instructions
|
||||||
|
for formatting the output into the desired schema into the model call.
|
||||||
include_raw: If False then only the parsed structured output is returned. If
|
include_raw: If False then only the parsed structured output is returned. If
|
||||||
an error occurs during model output parsing it will be raised. If True
|
an error occurs during model output parsing it will be raised. If True
|
||||||
then both the raw model response (a BaseMessage) and the parsed model
|
then both the raw model response (a BaseMessage) and the parsed model
|
||||||
@ -709,21 +721,81 @@ class ChatMistralAI(BaseChatModel):
|
|||||||
# 'justification': 'Both a pound of bricks and a pound of feathers weigh one pound. The weight is the same, but the volume and density of the two substances differ.'
|
# 'justification': 'Both a pound of bricks and a pound of feathers weigh one pound. The weight is the same, but the volume and density of the two substances differ.'
|
||||||
# }
|
# }
|
||||||
|
|
||||||
|
Example: JSON mode, Pydantic schema (method="json_mode", include_raw=True):
|
||||||
|
.. code-block::
|
||||||
|
|
||||||
|
from langchain_mistralai import ChatMistralAI
|
||||||
|
from langchain_core.pydantic_v1 import BaseModel
|
||||||
|
|
||||||
|
class AnswerWithJustification(BaseModel):
|
||||||
|
answer: str
|
||||||
|
justification: str
|
||||||
|
|
||||||
|
llm = ChatMistralAI(model="mistral-large-latest", temperature=0)
|
||||||
|
structured_llm = llm.with_structured_output(
|
||||||
|
AnswerWithJustification,
|
||||||
|
method="json_mode",
|
||||||
|
include_raw=True
|
||||||
|
)
|
||||||
|
|
||||||
|
structured_llm.invoke(
|
||||||
|
"Answer the following question. "
|
||||||
|
"Make sure to return a JSON blob with keys 'answer' and 'justification'.\n\n"
|
||||||
|
"What's heavier a pound of bricks or a pound of feathers?"
|
||||||
|
)
|
||||||
|
# -> {
|
||||||
|
# 'raw': AIMessage(content='{\n "answer": "They are both the same weight.",\n "justification": "Both a pound of bricks and a pound of feathers weigh one pound. The difference lies in the volume and density of the materials, not the weight." \n}'),
|
||||||
|
# 'parsed': AnswerWithJustification(answer='They are both the same weight.', justification='Both a pound of bricks and a pound of feathers weigh one pound. The difference lies in the volume and density of the materials, not the weight.'),
|
||||||
|
# 'parsing_error': None
|
||||||
|
# }
|
||||||
|
|
||||||
|
Example: JSON mode, no schema (schema=None, method="json_mode", include_raw=True):
|
||||||
|
.. code-block::
|
||||||
|
|
||||||
|
from langchain_mistralai import ChatMistralAI
|
||||||
|
|
||||||
|
structured_llm = llm.with_structured_output(method="json_mode", include_raw=True)
|
||||||
|
|
||||||
|
structured_llm.invoke(
|
||||||
|
"Answer the following question. "
|
||||||
|
"Make sure to return a JSON blob with keys 'answer' and 'justification'.\n\n"
|
||||||
|
"What's heavier a pound of bricks or a pound of feathers?"
|
||||||
|
)
|
||||||
|
# -> {
|
||||||
|
# 'raw': AIMessage(content='{\n "answer": "They are both the same weight.",\n "justification": "Both a pound of bricks and a pound of feathers weigh one pound. The difference lies in the volume and density of the materials, not the weight." \n}'),
|
||||||
|
# 'parsed': {
|
||||||
|
# 'answer': 'They are both the same weight.',
|
||||||
|
# 'justification': 'Both a pound of bricks and a pound of feathers weigh one pound. The difference lies in the volume and density of the materials, not the weight.'
|
||||||
|
# },
|
||||||
|
# 'parsing_error': None
|
||||||
|
# }
|
||||||
""" # noqa: E501
|
""" # noqa: E501
|
||||||
if kwargs:
|
if kwargs:
|
||||||
raise ValueError(f"Received unsupported arguments {kwargs}")
|
raise ValueError(f"Received unsupported arguments {kwargs}")
|
||||||
is_pydantic_schema = isinstance(schema, type) and issubclass(schema, BaseModel)
|
is_pydantic_schema = isinstance(schema, type) and issubclass(schema, BaseModel)
|
||||||
llm = self.bind_tools([schema], tool_choice="any")
|
if method == "function_calling":
|
||||||
if is_pydantic_schema:
|
if schema is None:
|
||||||
output_parser: OutputParserLike = PydanticToolsParser(
|
raise ValueError(
|
||||||
tools=[schema], first_tool_only=True
|
"schema must be specified when method is 'function_calling'. "
|
||||||
|
"Received None."
|
||||||
|
)
|
||||||
|
llm = self.bind_tools([schema], tool_choice="any")
|
||||||
|
if is_pydantic_schema:
|
||||||
|
output_parser: OutputParserLike = PydanticToolsParser(
|
||||||
|
tools=[schema], first_tool_only=True
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
key_name = convert_to_openai_tool(schema)["function"]["name"]
|
||||||
|
output_parser = JsonOutputKeyToolsParser(
|
||||||
|
key_name=key_name, first_tool_only=True
|
||||||
|
)
|
||||||
|
elif method == "json_mode":
|
||||||
|
llm = self.bind(response_format={"type": "json_object"})
|
||||||
|
output_parser = (
|
||||||
|
PydanticOutputParser(pydantic_object=schema)
|
||||||
|
if is_pydantic_schema
|
||||||
|
else JsonOutputParser()
|
||||||
)
|
)
|
||||||
else:
|
|
||||||
key_name = convert_to_openai_tool(schema)["function"]["name"]
|
|
||||||
output_parser = JsonOutputKeyToolsParser(
|
|
||||||
key_name=key_name, first_tool_only=True
|
|
||||||
)
|
|
||||||
|
|
||||||
if include_raw:
|
if include_raw:
|
||||||
parser_assign = RunnablePassthrough.assign(
|
parser_assign = RunnablePassthrough.assign(
|
||||||
parsed=itemgetter("raw") | output_parser, parsing_error=lambda _: None
|
parsed=itemgetter("raw") | output_parser, parsing_error=lambda _: None
|
||||||
|
Loading…
Reference in New Issue
Block a user