langchain-ai / langchain

šŸ¦œšŸ”— Build context-aware reasoning applications
https://python.langchain.com
MIT License
93.88k stars 15.13k forks source link

"NameError: name 'FilePath' is not defined" in calling create_schema_from_function #27226

Open MRYingLEE opened 2 weeks ago

MRYingLEE commented 2 weeks ago

Checked other resources

Example Code

The following code:

from langchain_core.tools.base import (
    create_schema_from_function as create_schema_from_function,
)

import pandas
func=pandas.read_csv
print(type(func))
print(func.__name__)
print(func.__qualname__)

model = create_schema_from_function(
    func_name,
    func,
    filter_args=(),
    parse_docstring=True,
    error_on_invalid_docstring=False,
    include_injected=False,
)

Error Message and Stack Trace (if applicable)

<class 'function'> read_csv read_csv

NameError Traceback (most recent call last) Cell In[27], line 11 8 print(func.name) 9 print(func.qualname) ---> 11 model = create_schema_from_function( 12 func_name, 13 func, 14 filter_args=(), 15 parse_docstring=True, 16 error_on_invalid_docstring=False, 17 include_injected=False, 18 )

File /lib/python3.12/site-packages/langchain_core/tools/base.py:249, in create_schema_from_function(model_name, func, filter_args, parse_docstring, error_on_invalid_docstring, include_injected) 244 with warnings.catch_warnings(): 245 # We are using deprecated functionality here. 246 # This code should be re-written to simply construct a pydantic model 247 # using inspect.signature and create_model. 248 warnings.simplefilter("ignore", category=PydanticDeprecationWarning) --> 249 validated = validate_arguments(func, config=_SchemaConfig) # type: ignore 251 # Let's ignore self and cls arguments for class and instance methods 252 # If qualified name has a ".", then it likely belongs in a class namespace 253 in_class = bool(func.qualname and "." in func.qualname)

File /lib/python3.12/site-packages/pydantic/deprecated/decorator.py:64, in validate_arguments(func, config) 61 return wrapper_function 63 if func: ---> 64 return validate(func) 65 else: 66 return validate

File /lib/python3.12/site-packages/pydantic/deprecated/decorator.py:51, in validate_arguments..validate(_func) 50 def validate(_func: 'AnyCallable') -> 'AnyCallable': ---> 51 vd = ValidatedFunction(_func, config) 53 @wraps(_func) 54 def wrapper_function(*args: Any, *kwargs: Any) -> Any: 55 return vd.call(args, **kwargs)

File /lib/python3.12/site-packages/pydantic/deprecated/decorator.py:94, in ValidatedFunction.init(self, function, config) 91 self.v_args_name = 'args' 92 self.v_kwargs_name = 'kwargs' ---> 94 type_hints = _typing_extra.get_type_hints(function, include_extras=True) 95 takes_args = False 96 takes_kwargs = False

File /lib/python312.zip/typing.py:2246, in get_type_hints(obj, globalns, localns, include_extras) 2238 if isinstance(value, str): 2239 # class-level forward refs were handled above, this must be either 2240 # a module-level annotation or a function argument annotation 2241 value = ForwardRef( 2242 value, 2243 is_argument=not isinstance(obj, types.ModuleType), 2244 is_class=False, 2245 ) -> 2246 hints[name] = _eval_type(value, globalns, localns) 2247 return hints if include_extras else {k: _strip_annotations(t) for k, t in hints.items()}

File /lib/python312.zip/typing.py:400, in _eval_type(t, globalns, localns, recursive_guard) 393 """Evaluate all forward references in the given type t. 394 395 For use of globalns and localns see the docstring for get_type_hints(). 396 recursive_guard is used to prevent infinite recursion with a recursive 397 ForwardRef. 398 """ 399 if isinstance(t, ForwardRef): --> 400 return t._evaluate(globalns, localns, recursive_guard) 401 if isinstance(t, (_GenericAlias, GenericAlias, types.UnionType)): 402 if isinstance(t, GenericAlias):

File /lib/python312.zip/typing.py:907, in ForwardRef._evaluate(self, globalns, localns, recursive_guard) 902 if self.forward_module is not None: 903 globalns = getattr( 904 sys.modules.get(self.forward_module, None), 'dict', globalns 905 ) 906 type_ = _type_check( --> 907 eval(self.forward_code__, globalns, localns), 908 "Forward references must evaluate to types.", 909 is_argument=self.forward_is_argument, 910 allow_special_forms=self.forward_is_class, 911 ) 912 self.forward_value = _evaltype( 913 type, globalns, localns, recursive_guard | {self.forward_arg} 914 ) 915 self.forward_evaluated__ = True

File :1

NameError: name 'FilePath' is not defined

NameError Traceback (most recent call last) Cell In[27], line 11 8 print(func.name) 9 print(func.qualname) ---> 11 model = create_schema_from_function( 12 func_name, 13 func, 14 filter_args=(), 15 parse_docstring=True, 16 error_on_invalid_docstring=False, 17 include_injected=False, 18 )

File /lib/python3.12/site-packages/langchain_core/tools/base.py:249, in create_schema_from_function(model_name, func, filter_args, parse_docstring, error_on_invalid_docstring, include_injected) 244 with warnings.catch_warnings(): 245 # We are using deprecated functionality here. 246 # This code should be re-written to simply construct a pydantic model 247 # using inspect.signature and create_model. 248 warnings.simplefilter("ignore", category=PydanticDeprecationWarning) --> 249 validated = validate_arguments(func, config=_SchemaConfig) # type: ignore 251 # Let's ignore self and cls arguments for class and instance methods 252 # If qualified name has a ".", then it likely belongs in a class namespace 253 in_class = bool(func.qualname and "." in func.qualname)

File /lib/python3.12/site-packages/pydantic/deprecated/decorator.py:64, in validate_arguments(func, config) 61 return wrapper_function 63 if func: ---> 64 return validate(func) 65 else: 66 return validate

File /lib/python3.12/site-packages/pydantic/deprecated/decorator.py:51, in validate_arguments..validate(_func) 50 def validate(_func: 'AnyCallable') -> 'AnyCallable': ---> 51 vd = ValidatedFunction(_func, config) 53 @wraps(_func) 54 def wrapper_function(*args: Any, *kwargs: Any) -> Any: 55 return vd.call(args, **kwargs)

File /lib/python3.12/site-packages/pydantic/deprecated/decorator.py:94, in ValidatedFunction.init(self, function, config) 91 self.v_args_name = 'args' 92 self.v_kwargs_name = 'kwargs' ---> 94 type_hints = _typing_extra.get_type_hints(function, include_extras=True) 95 takes_args = False 96 takes_kwargs = False

File /lib/python312.zip/typing.py:2246, in get_type_hints(obj, globalns, localns, include_extras) 2238 if isinstance(value, str): 2239 # class-level forward refs were handled above, this must be either 2240 # a module-level annotation or a function argument annotation 2241 value = ForwardRef( 2242 value, 2243 is_argument=not isinstance(obj, types.ModuleType), 2244 is_class=False, 2245 ) -> 2246 hints[name] = _eval_type(value, globalns, localns) 2247 return hints if include_extras else {k: _strip_annotations(t) for k, t in hints.items()}

File /lib/python312.zip/typing.py:400, in _eval_type(t, globalns, localns, recursive_guard) 393 """Evaluate all forward references in the given type t. 394 395 For use of globalns and localns see the docstring for get_type_hints(). 396 recursive_guard is used to prevent infinite recursion with a recursive 397 ForwardRef. 398 """ 399 if isinstance(t, ForwardRef): --> 400 return t._evaluate(globalns, localns, recursive_guard) 401 if isinstance(t, (_GenericAlias, GenericAlias, types.UnionType)): 402 if isinstance(t, GenericAlias):

File /lib/python312.zip/typing.py:907, in ForwardRef._evaluate(self, globalns, localns, recursive_guard) 902 if self.forward_module is not None: 903 globalns = getattr( 904 sys.modules.get(self.forward_module, None), 'dict', globalns 905 ) 906 type_ = _type_check( --> 907 eval(self.forward_code__, globalns, localns), 908 "Forward references must evaluate to types.", 909 is_argument=self.forward_is_argument, 910 allow_special_forms=self.forward_is_class, 911 ) 912 self.forward_value = _evaltype( 913 type, globalns, localns, recursive_guard | {self.forward_arg} 914 ) 915 self.forward_evaluated__ = True

File :1

NameError: name 'FilePath' is not defined

Description

I tried to call create_schema_from_function on some popular functions, such as pandas.read_csv, to generate schema for OpenAI structured outputs.

System Info

System Information

OS: Emscripten OS Version: #1 Python Version: 3.12.1 (main, Jul 26 2024, 14:03:47) [Clang 19.0.0git (https:/github.com/llvm/llvm-project 0a8cd1ed1f4f35905df318015b

Package Information

langchain_core: 0.3.10 langsmith: 0.1.132

Optional packages not installed

langgraph langserve

Other Dependencies

httpx: 0.27.2 jsonpatch: 1.33 orjson: 3.10.1 packaging: 23.2 pydantic: 2.7.0 PyYAML: 6.0.1 requests: 2.31.0 requests-toolbelt: 1.0.0 tenacity: 8.5.0 typing-extensions: 4.11.0

eyurtsev commented 2 weeks ago

There's some issue with resolving forward references. We could take a look, but i don't recommend doing this.

read_csv has a very large function signature. feeding all of this into a chat model is probably going to result in pretty bad performance and expensive calls due to higher token usage.

Instead I'd recommend being much more selective of the surface area of the tool that you're exposing.

from langchain_core.tools import tool

@tool
def read_csv(my_argument: str):
   """Carefully document what the tool does."""
   df =  pd.DataFrame(my_argument)
   # what do you want to do with df here -- chat models expect a string.

   return df

you could return an arficat, but i'd recommend reading the relevant how to guide: https://python.langchain.com/docs/how_to/tool_artifacts/#defining-the-tool