mirror of
https://github.com/hwchase17/langchain.git
synced 2025-09-04 04:28:58 +00:00
docs, core: error messaging [wip] (#27397)
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
"""Custom **exceptions** for LangChain."""
|
||||
|
||||
from enum import Enum
|
||||
from typing import Any, Optional
|
||||
|
||||
|
||||
@@ -39,6 +40,10 @@ class OutputParserException(ValueError, LangChainException): # noqa: N818
|
||||
llm_output: Optional[str] = None,
|
||||
send_to_llm: bool = False,
|
||||
):
|
||||
if isinstance(error, str):
|
||||
error = create_message(
|
||||
message=error, error_code=ErrorCode.OUTPUT_PARSING_FAILURE
|
||||
)
|
||||
super().__init__(error)
|
||||
if send_to_llm and (observation is None or llm_output is None):
|
||||
msg = (
|
||||
@@ -49,3 +54,21 @@ class OutputParserException(ValueError, LangChainException): # noqa: N818
|
||||
self.observation = observation
|
||||
self.llm_output = llm_output
|
||||
self.send_to_llm = send_to_llm
|
||||
|
||||
|
||||
class ErrorCode(Enum):
|
||||
INVALID_PROMPT_INPUT = "INVALID_PROMPT_INPUT"
|
||||
INVALID_TOOL_RESULTS = "INVALID_TOOL_RESULTS"
|
||||
MESSAGE_COERCION_FAILURE = "MESSAGE_COERCION_FAILURE"
|
||||
MODEL_AUTHENTICATION = "MODEL_AUTHENTICATION"
|
||||
MODEL_NOT_FOUND = "MODEL_NOT_FOUND"
|
||||
MODEL_RATE_LIMIT = "MODEL_RATE_LIMIT"
|
||||
OUTPUT_PARSING_FAILURE = "OUTPUT_PARSING_FAILURE"
|
||||
|
||||
|
||||
def create_message(*, message: str, error_code: ErrorCode) -> str:
|
||||
return (
|
||||
f"{message}\n"
|
||||
"For troubleshooting, visit: https://python.langchain.com/docs/"
|
||||
f"troubleshooting/errors/{error_code.value}"
|
||||
)
|
||||
|
@@ -28,6 +28,7 @@ from typing import (
|
||||
|
||||
from pydantic import Discriminator, Field, Tag
|
||||
|
||||
from langchain_core.exceptions import ErrorCode, create_message
|
||||
from langchain_core.messages.ai import AIMessage, AIMessageChunk
|
||||
from langchain_core.messages.base import BaseMessage, BaseMessageChunk
|
||||
from langchain_core.messages.chat import ChatMessage, ChatMessageChunk
|
||||
@@ -274,6 +275,7 @@ def _create_message_from_message_type(
|
||||
f"Unexpected message type: '{message_type}'. Use one of 'human',"
|
||||
f" 'user', 'ai', 'assistant', 'function', 'tool', or 'system'."
|
||||
)
|
||||
msg = create_message(message=msg, error_code=ErrorCode.MESSAGE_COERCION_FAILURE)
|
||||
raise ValueError(msg)
|
||||
return message
|
||||
|
||||
@@ -318,12 +320,16 @@ def _convert_to_message(message: MessageLikeRepresentation) -> BaseMessage:
|
||||
msg_content = msg_kwargs.pop("content") or ""
|
||||
except KeyError as e:
|
||||
msg = f"Message dict must contain 'role' and 'content' keys, got {message}"
|
||||
msg = create_message(
|
||||
message=msg, error_code=ErrorCode.MESSAGE_COERCION_FAILURE
|
||||
)
|
||||
raise ValueError(msg) from e
|
||||
_message = _create_message_from_message_type(
|
||||
msg_type, msg_content, **msg_kwargs
|
||||
)
|
||||
else:
|
||||
msg = f"Unsupported message type: {type(message)}"
|
||||
msg = create_message(message=msg, error_code=ErrorCode.MESSAGE_COERCION_FAILURE)
|
||||
raise NotImplementedError(msg)
|
||||
|
||||
return _message
|
||||
@@ -1327,6 +1333,7 @@ def _msg_to_chunk(message: BaseMessage) -> BaseMessageChunk:
|
||||
f"Unrecognized message class {message.__class__}. Supported classes are "
|
||||
f"{list(_MSG_CHUNK_MAP.keys())}"
|
||||
)
|
||||
msg = create_message(message=msg, error_code=ErrorCode.MESSAGE_COERCION_FAILURE)
|
||||
raise ValueError(msg)
|
||||
|
||||
|
||||
@@ -1343,6 +1350,7 @@ def _chunk_to_msg(chunk: BaseMessageChunk) -> BaseMessage:
|
||||
f"Unrecognized message chunk class {chunk.__class__}. Supported classes are "
|
||||
f"{list(_CHUNK_MSG_MAP.keys())}"
|
||||
)
|
||||
msg = create_message(message=msg, error_code=ErrorCode.MESSAGE_COERCION_FAILURE)
|
||||
raise ValueError(msg)
|
||||
|
||||
|
||||
|
@@ -21,6 +21,7 @@ import yaml
|
||||
from pydantic import BaseModel, ConfigDict, Field, model_validator
|
||||
from typing_extensions import Self, override
|
||||
|
||||
from langchain_core.exceptions import ErrorCode, create_message
|
||||
from langchain_core.load import dumpd
|
||||
from langchain_core.output_parsers.base import BaseOutputParser
|
||||
from langchain_core.prompt_values import (
|
||||
@@ -74,18 +75,24 @@ class BasePromptTemplate(
|
||||
"Cannot have an input variable named 'stop', as it is used internally,"
|
||||
" please rename."
|
||||
)
|
||||
raise ValueError(msg)
|
||||
raise ValueError(
|
||||
create_message(message=msg, error_code=ErrorCode.INVALID_PROMPT_INPUT)
|
||||
)
|
||||
if "stop" in self.partial_variables:
|
||||
msg = (
|
||||
"Cannot have an partial variable named 'stop', as it is used "
|
||||
"internally, please rename."
|
||||
)
|
||||
raise ValueError(msg)
|
||||
raise ValueError(
|
||||
create_message(message=msg, error_code=ErrorCode.INVALID_PROMPT_INPUT)
|
||||
)
|
||||
|
||||
overall = set(self.input_variables).intersection(self.partial_variables)
|
||||
if overall:
|
||||
msg = f"Found overlapping input and partial variables: {overall}"
|
||||
raise ValueError(msg)
|
||||
raise ValueError(
|
||||
create_message(message=msg, error_code=ErrorCode.INVALID_PROMPT_INPUT)
|
||||
)
|
||||
return self
|
||||
|
||||
@classmethod
|
||||
@@ -148,7 +155,11 @@ class BasePromptTemplate(
|
||||
f"Expected mapping type as input to {self.__class__.__name__}. "
|
||||
f"Received {type(inner_input)}."
|
||||
)
|
||||
raise TypeError(msg)
|
||||
raise TypeError(
|
||||
create_message(
|
||||
message=msg, error_code=ErrorCode.INVALID_PROMPT_INPUT
|
||||
)
|
||||
)
|
||||
missing = set(self.input_variables).difference(inner_input)
|
||||
if missing:
|
||||
msg = (
|
||||
@@ -162,7 +173,9 @@ class BasePromptTemplate(
|
||||
" and not a variable, please escape it with double curly braces like: "
|
||||
f"'{{{{{example_key}}}}}'."
|
||||
)
|
||||
raise KeyError(msg)
|
||||
raise KeyError(
|
||||
create_message(message=msg, error_code=ErrorCode.INVALID_PROMPT_INPUT)
|
||||
)
|
||||
return inner_input
|
||||
|
||||
def _format_prompt_with_error_handling(self, inner_input: dict) -> PromptValue:
|
||||
@@ -381,7 +394,9 @@ def _get_document_info(doc: Document, prompt: BasePromptTemplate[str]) -> dict:
|
||||
f"{required_metadata}. Received document with missing metadata: "
|
||||
f"{list(missing_metadata)}."
|
||||
)
|
||||
raise ValueError(msg)
|
||||
raise ValueError(
|
||||
create_message(message=msg, error_code=ErrorCode.INVALID_PROMPT_INPUT)
|
||||
)
|
||||
return {k: base_info[k] for k in prompt.input_variables}
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user