Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Import of ChatVertexAI fails with "name 'SafetySetting' is not defined" #610

Closed
Luc2357 opened this issue Nov 21, 2024 · 14 comments
Closed

Comments

@Luc2357
Copy link

Luc2357 commented Nov 21, 2024

Upon creation of a new virtual environment, the import of the ChatVertexAI now fails with "'SafetySetting' is not defined"

Steps to reproduce:

python3 -m venv .venv
source .venv/bin/activate
pip install langchain-google-vertexai
python -c "from langchain_google_vertexai import ChatVertexAI"

Error reported:

NameError: name 'SafetySetting' is not defined. Did you mean: 'SafetySettingsType'?
Full stacktrace

Traceback (most recent call last):
  File "/Users/lucpons/.venv/lib/python3.12/site-packages/pydantic/_internal/_generate_schema.py", line 815, in _resolve_forward_ref
    obj = _typing_extra.eval_type_backport(obj, *self._types_namespace)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/lucpons/.venv/lib/python3.12/site-packages/pydantic/_internal/_typing_extra.py", line 534, in eval_type_backport
    return _eval_type_backport(value, globalns, localns, type_params)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/lucpons/.venv/lib/python3.12/site-packages/pydantic/_internal/_typing_extra.py", line 558, in _eval_type_backport
    return _eval_type(value, globalns, localns, type_params)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/lucpons/.venv/lib/python3.12/site-packages/pydantic/_internal/_typing_extra.py", line 592, in _eval_type
    return typing._eval_type(  # type: ignore
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/Cellar/[email protected]/3.12.3/Frameworks/Python.framework/Versions/3.12/lib/python3.12/typing.py", line 414, in _eval_type
    return t._evaluate(globalns, localns, recursive_guard)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/Cellar/[email protected]/3.12.3/Frameworks/Python.framework/Versions/3.12/lib/python3.12/typing.py", line 929, in _evaluate
    self.__forward_value__ = _eval_type(
                             ^^^^^^^^^^^
  File "/opt/homebrew/Cellar/[email protected]/3.12.3/Frameworks/Python.framework/Versions/3.12/lib/python3.12/typing.py", line 428, in _eval_type
    ev_args = tuple(_eval_type(a, globalns, localns, recursive_guard) for a in t.__args__)
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/Cellar/[email protected]/3.12.3/Frameworks/Python.framework/Versions/3.12/lib/python3.12/typing.py", line 428, in <genexpr>
    ev_args = tuple(_eval_type(a, globalns, localns, recursive_guard) for a in t.__args__)
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/Cellar/[email protected]/3.12.3/Frameworks/Python.framework/Versions/3.12/lib/python3.12/typing.py", line 414, in _eval_type
    return t._evaluate(globalns, localns, recursive_guard)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/Cellar/[email protected]/3.12.3/Frameworks/Python.framework/Versions/3.12/lib/python3.12/typing.py", line 929, in _evaluate
    self.__forward_value__ = _eval_type(
                             ^^^^^^^^^^^
  File "/opt/homebrew/Cellar/[email protected]/3.12.3/Frameworks/Python.framework/Versions/3.12/lib/python3.12/typing.py", line 428, in _eval_type
    ev_args = tuple(_eval_type(a, globalns, localns, recursive_guard) for a in t.__args__)
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/Cellar/[email protected]/3.12.3/Frameworks/Python.framework/Versions/3.12/lib/python3.12/typing.py", line 428, in <genexpr>
    ev_args = tuple(_eval_type(a, globalns, localns, recursive_guard) for a in t.__args__)
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/Cellar/[email protected]/3.12.3/Frameworks/Python.framework/Versions/3.12/lib/python3.12/typing.py", line 428, in _eval_type
    ev_args = tuple(_eval_type(a, globalns, localns, recursive_guard) for a in t.__args__)
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/Cellar/[email protected]/3.12.3/Frameworks/Python.framework/Versions/3.12/lib/python3.12/typing.py", line 428, in <genexpr>
    ev_args = tuple(_eval_type(a, globalns, localns, recursive_guard) for a in t.__args__)
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/Cellar/[email protected]/3.12.3/Frameworks/Python.framework/Versions/3.12/lib/python3.12/typing.py", line 414, in _eval_type
    return t._evaluate(globalns, localns, recursive_guard)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/homebrew/Cellar/[email protected]/3.12.3/Frameworks/Python.framework/Versions/3.12/lib/python3.12/typing.py", line 924, in _evaluate
    eval(self.__forward_code__, globalns, localns),
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "<string>", line 1, in <module>
NameError: name 'SafetySetting' is not defined. Did you mean: 'SafetySettingsType'?

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/Users/lucpons/.venv/lib/python3.12/site-packages/langchain_google_vertexai/__init__.py", line 16, in <module>
    from langchain_google_vertexai.embeddings import VertexAIEmbeddings
  File "/Users/lucpons/.venv/lib/python3.12/site-packages/langchain_google_vertexai/embeddings.py", line 544, in <module>
    VertexAIEmbeddings.model_rebuild()
  File "/Users/lucpons/.venv/lib/python3.12/site-packages/pydantic/main.py", line 589, in model_rebuild
    return _model_construction.complete_model_class(
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/lucpons/.venv/lib/python3.12/site-packages/pydantic/_internal/_model_construction.py", line 658, in complete_model_class
    schema = cls.__get_pydantic_core_schema__(cls, handler)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/lucpons/.venv/lib/python3.12/site-packages/pydantic/main.py", line 697, in __get_pydantic_core_schema__
    return handler(source)
           ^^^^^^^^^^^^^^^
  File "/Users/lucpons/.venv/lib/python3.12/site-packages/pydantic/_internal/_schema_generation_shared.py", line 84, in __call__
    schema = self._handler(source_type)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/lucpons/.venv/lib/python3.12/site-packages/pydantic/_internal/_generate_schema.py", line 612, in generate_schema
    schema = self._generate_schema_inner(obj)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/lucpons/.venv/lib/python3.12/site-packages/pydantic/_internal/_generate_schema.py", line 881, in _generate_schema_inner
    return self._model_schema(obj)
           ^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/lucpons/.venv/lib/python3.12/site-packages/pydantic/_internal/_generate_schema.py", line 693, in _model_schema
    {k: self._generate_md_field_schema(k, v, decorators) for k, v in fields.items()},
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/lucpons/.venv/lib/python3.12/site-packages/pydantic/_internal/_generate_schema.py", line 1073, in _generate_md_field_schema
    common_field = self._common_field_schema(name, field_info, decorators)
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/lucpons/.venv/lib/python3.12/site-packages/pydantic/_internal/_generate_schema.py", line 1261, in _common_field_schema
    schema = self._apply_annotations(
             ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/lucpons/.venv/lib/python3.12/site-packages/pydantic/_internal/_generate_schema.py", line 2051, in _apply_annotations
    schema = get_inner_schema(source_type)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/lucpons/.venv/lib/python3.12/site-packages/pydantic/_internal/_schema_generation_shared.py", line 84, in __call__
    schema = self._handler(source_type)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/lucpons/.venv/lib/python3.12/site-packages/pydantic/_internal/_generate_schema.py", line 2032, in inner_handler
    schema = self._generate_schema_inner(obj)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/lucpons/.venv/lib/python3.12/site-packages/pydantic/_internal/_generate_schema.py", line 875, in _generate_schema_inner
    return self.generate_schema(self._resolve_forward_ref(obj))
                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/lucpons/.venv/lib/python3.12/site-packages/pydantic/_internal/_generate_schema.py", line 817, in _resolve_forward_ref
    raise PydanticUndefinedAnnotation.from_name_error(e) from e
pydantic.errors.PydanticUndefinedAnnotation: name 'SafetySetting' is not defined

For further information visit https://errors.pydantic.dev/2.10/u/undefined-annotation
@langcarl langcarl bot added the investigate label Nov 21, 2024
@fazpu
Copy link

fazpu commented Nov 21, 2024

same here. Here is my stack trace when running unit tests on CI:

llms/fallback_llm_provider.py:14: in <module>
    from langchain_google_vertexai import ChatVertexAI
/home/runner/.local/share/hatch/env/virtual/code-bro-server/v7rDU5c8/test/lib/python3.11/site-packages/langchain_google_vertexai/__init__.py:16: in <module>
    from langchain_google_vertexai.embeddings import VertexAIEmbeddings
/home/runner/.local/share/hatch/env/virtual/code-bro-server/v7rDU5c8/test/lib/python3.11/site-packages/langchain_google_vertexai/embeddings.py:544: in <module>
    VertexAIEmbeddings.model_rebuild()
/home/runner/.local/share/hatch/env/virtual/code-bro-server/v7rDU5c8/test/lib/python3.11/site-packages/pydantic/main.py:589: in model_rebuild
    return _model_construction.complete_model_class(
/home/runner/.local/share/hatch/env/virtual/code-bro-server/v7rDU5c8/test/lib/python3.11/site-packages/pydantic/_internal/_model_construction.py:658: in complete_model_class
    schema = cls.__get_pydantic_core_schema__(cls, handler)
/home/runner/.local/share/hatch/env/virtual/code-bro-server/v7rDU5c8/test/lib/python3.11/site-packages/pydantic/main.py:[69](https://github.com/writeitai/writeit/actions/runs/11953818231/job/33323404662#step:10:70)7: in __get_pydantic_core_schema__
    return handler(source)
/home/runner/.local/share/hatch/env/virtual/code-bro-server/v7rDU5c8/test/lib/python3.11/site-packages/pydantic/_internal/_schema_generation_shared.py:84: in __call__
    schema = self._handler(source_type)
/home/runner/.local/share/hatch/env/virtual/code-bro-server/v7rDU5c8/test/lib/python3.11/site-packages/pydantic/_internal/_generate_schema.py:612: in generate_schema
    schema = self._generate_schema_inner(obj)
/home/runner/.local/share/hatch/env/virtual/code-bro-server/v7rDU5c8/test/lib/python3.11/site-packages/pydantic/_internal/_generate_schema.py:881: in _generate_schema_inner
    return self._model_schema(obj)
/home/runner/.local/share/hatch/env/virtual/code-bro-server/v7rDU5c8/test/lib/python3.11/site-packages/pydantic/_internal/_generate_schema.py:693: in _model_schema
    {k: self._generate_md_field_schema(k, v, decorators) for k, v in fields.items()},
/home/runner/.local/share/hatch/env/virtual/code-bro-server/v7rDU5c8/test/lib/python3.11/site-packages/pydantic/_internal/_generate_schema.py:693: in <dictcomp>
    {k: self._generate_md_field_schema(k, v, decorators) for k, v in fields.items()},
/home/runner/.local/share/hatch/env/virtual/code-bro-server/v7rDU5c8/test/lib/python3.11/site-packages/pydantic/_internal/_generate_schema.py:10[73](https://github.com/writeitai/writeit/actions/runs/11953818231/job/33323404662#step:10:74): in _generate_md_field_schema
    common_field = self._common_field_schema(name, field_info, decorators)
/home/runner/.local/share/hatch/env/virtual/code-bro-server/v7rDU5c8/test/lib/python3.11/site-packages/pydantic/_internal/_generate_schema.py:1261: in _common_field_schema
    schema = self._apply_annotations(
/home/runner/.local/share/hatch/env/virtual/code-bro-server/v7rDU5c8/test/lib/python3.11/site-packages/pydantic/_internal/_generate_schema.py:2051: in _apply_annotations
    schema = get_inner_schema(source_type)
/home/runner/.local/share/hatch/env/virtual/code-bro-server/v7rDU5c8/test/lib/python3.11/site-packages/pydantic/_internal/_schema_generation_shared.py:84: in __call__
    schema = self._handler(source_type)
/home/runner/.local/share/hatch/env/virtual/code-bro-server/v7rDU5c8/test/lib/python3.11/site-packages/pydantic/_internal/_generate_schema.py:2032: in inner_handler
    schema = self._generate_schema_inner(obj)
/home/runner/.local/share/hatch/env/virtual/code-bro-server/v7rDU5c8/test/lib/python3.11/site-packages/pydantic/_internal/_generate_schema.py:8[75](https://github.com/writeitai/writeit/actions/runs/11953818231/job/33323404662#step:10:76): in _generate_schema_inner
    return self.generate_schema(self._resolve_forward_ref(obj))
/home/runner/.local/share/hatch/env/virtual/code-bro-server/v7rDU5c8/test/lib/python3.11/site-packages/pydantic/_internal/_generate_schema.py:817: in _resolve_forward_ref
    raise PydanticUndefinedAnnotation.from_name_error(e) from e
E   pydantic.errors.PydanticUndefinedAnnotation: name 'SafetySetting' is not defined

@mkesicki
Copy link

Our docker:

boto3==1.34.22
google-api-python-client==2.114.0
google-auth==2.26.2
langchain==0.3.2
langchain-core==0.3.9
langchain-google-vertexai==2.0.3
langgraph==0.2.18
pdf2image==1.17.0
pillow==10.2.0```

Logs:
```For further information visit https://errors.pydantic.dev/2.10/u/undefined-annotation
Traceback (most recent call last):
  File "/var/lang/lib/python3.11/importlib/__init__.py", line 126, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 1204, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1176, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1147, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 690, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 940, in exec_module
  File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
  File "/var/task/datadog_lambda/handler.py", line 30, in <module>
    handler_module = import_module(modified_mod_name)
  File "/var/lang/lib/python3.11/importlib/__init__.py", line 126, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 1204, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1176, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1147, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 690, in _load_unlocked
  File "/var/task/ddtrace/internal/module.py", line 295, in _exec_module
    self.loader.exec_module(module)
  File "<frozen importlib._bootstrap_external>", line 940, in exec_module
  File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
  File "/var/task/lambda.py", line 3, in <module>
    import main
  File "<frozen importlib._bootstrap>", line 1176, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1147, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 690, in _load_unlocked
  File "/var/task/ddtrace/internal/module.py", line 295, in _exec_module
    self.loader.exec_module(module)
  File "/var/task/main.py", line 8, in <module>
    from langchain_google_vertexai import HarmBlockThreshold, HarmCategory, ChatVertexAI
  File "<frozen importlib._bootstrap>", line 1176, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1147, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 690, in _load_unlocked
  File "/var/task/ddtrace/internal/module.py", line 295, in _exec_module
    self.loader.exec_module(module)
  File "/var/task/langchain_google_vertexai/__init__.py", line 16, in <module>
    from langchain_google_vertexai.embeddings import VertexAIEmbeddings
  File "<frozen importlib._bootstrap>", line 1176, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1147, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 690, in _load_unlocked
  File "/var/task/ddtrace/internal/module.py", line 295, in _exec_module
    self.loader.exec_module(module)
  File "/var/task/langchain_google_vertexai/embeddings.py", line 544, in <module>
    VertexAIEmbeddings.model_rebuild()
  File "/var/task/pydantic/main.py", line 589, in model_rebuild
    return _model_construction.complete_model_class(
  File "/var/task/pydantic/_internal/_model_construction.py", line 658, in complete_model_class
    schema = cls.__get_pydantic_core_schema__(cls, handler)
  File "/var/task/pydantic/main.py", line 697, in __get_pydantic_core_schema__
    return handler(source)
  File "/var/task/pydantic/_internal/_schema_generation_shared.py", line 84, in __call__
    schema = self._handler(source_type)
  File "/var/task/pydantic/_internal/_generate_schema.py", line 612, in generate_schema
    schema = self._generate_schema_inner(obj)
  File "/var/task/pydantic/_internal/_generate_schema.py", line 881, in _generate_schema_inner
    return self._model_schema(obj)
  File "/var/task/pydantic/_internal/_generate_schema.py", line 693, in _model_schema
    {k: self._generate_md_field_schema(k, v, decorators) for k, v in fields.items()},
  File "/var/task/pydantic/_internal/_generate_schema.py", line 693, in <dictcomp>
    {k: self._generate_md_field_schema(k, v, decorators) for k, v in fields.items()},
  File "/var/task/pydantic/_internal/_generate_schema.py", line 1073, in _generate_md_field_schema
    common_field = self._common_field_schema(name, field_info, decorators)
  File "/var/task/pydantic/_internal/_generate_schema.py", line 1261, in _common_field_schema
    schema = self._apply_annotations(
  File "/var/task/pydantic/_internal/_generate_schema.py", line 2051, in _apply_annotations
    schema = get_inner_schema(source_type)
  File "/var/task/pydantic/_internal/_schema_generation_shared.py", line 84, in __call__
    schema = self._handler(source_type)
  File "/var/task/pydantic/_internal/_generate_schema.py", line 2032, in inner_handler
    schema = self._generate_schema_inner(obj)
  File "/var/task/pydantic/_internal/_generate_schema.py", line 875, in _generate_schema_inner
    return self.generate_schema(self._resolve_forward_ref(obj))
  File "/var/task/pydantic/_internal/_generate_schema.py", line 817, in _resolve_forward_ref
    raise PydanticUndefinedAnnotation.from_name_error(e) from e

@jzaldi
Copy link
Contributor

jzaldi commented Nov 21, 2024

As a workaround setting pydantic version to 2.9.0 seems to work. 2.10.0 seems to break backwards compatibility somehow. We have pydantic version bounded between 2 and 3 so new install might be pulling the new version. This works for me

virtualenv .venv
source .venv/bin/activate
pip install langchain-google-vertexai
pip install pydantic==2.9.1
python -c "from langchain_google_vertexai import ChatVertexAI"

@tiaan720
Copy link

We also received the same error. Weirdly enough not on our local tests but in the CI/CD pipelines tests.
I tried this:

virtualenv .venv
source .venv/bin/activate
pip install langchain-google-vertexai
pip install pydantic==2.9.1
python -c "from langchain_google_vertexai import ChatVertexAI"

But It still doesn't work.

@jzaldi
Copy link
Contributor

jzaldi commented Nov 21, 2024

We also received the same error. Weirdly enough not on our local tests but in the CI/CD pipelines tests. I tried this:

virtualenv .venv
source .venv/bin/activate
pip install langchain-google-vertexai
pip install pydantic==2.9.1
python -c "from langchain_google_vertexai import ChatVertexAI"

But It still doesn't work.

It fails with the same error?

@tiaan720
Copy link

We also received the same error. Weirdly enough not on our local tests but in the CI/CD pipelines tests. I tried this:

virtualenv .venv
source .venv/bin/activate
pip install langchain-google-vertexai
pip install pydantic==2.9.1
python -c "from langchain_google_vertexai import ChatVertexAI"

But It still doesn't work.

It fails with the same error?

Same error yes
E pydantic.errors.PydanticUndefinedAnnotation: name 'SafetySetting' is not defined
E
E For further information visit https://errors.pydantic.dev/2.10/u/undefined-annotation

@jzaldi
Copy link
Contributor

jzaldi commented Nov 21, 2024

Can you pip freeze the .venv that is created with that command?

@tiaan720
Copy link

[tool.poetry.dependencies]
python = "^3.11"
uvicorn = "^0.23.2"
langchain-openai = "^0.2.1"
langgraph = "^0.2.35"
kaleido = "0.2.1"
plotly = "^5.24.1"
numpy = "1.26.4"
python-dotenv = "^1.0.1"
httpx = "^0.27.2"
google-cloud-bigquery = "^3.26.0"
toml = "^0.10.2"
google-cloud-datastore = "^2.20.1"
langchain = "^0.3.7"
fastapi = "^0.115.4"
pandas = "^2.2.3"
langchain-google-community = "^2.0.2"
langchain-google-vertexai = "^2.0.7"
pydantic = "^2.9.1"

[tool.poetry.group.dev.dependencies]
isort = "^5.13.2"
black = "^24.10.0"

[tool.poetry.group.test.dependencies]
pytest = "^8.3.3"
pytest-cov = "^5.0.0"
pytest-asyncio = "^0.24.0"
pytest-mock = "^3.14.0"
flaky = "^3.8.1"

[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"

This is our toml files dependancies

@jzaldi
Copy link
Contributor

jzaldi commented Nov 21, 2024

[tool.poetry.dependencies] python = "^3.11" uvicorn = "^0.23.2" langchain-openai = "^0.2.1" langgraph = "^0.2.35" kaleido = "0.2.1" plotly = "^5.24.1" numpy = "1.26.4" python-dotenv = "^1.0.1" httpx = "^0.27.2" google-cloud-bigquery = "^3.26.0" toml = "^0.10.2" google-cloud-datastore = "^2.20.1" langchain = "^0.3.7" fastapi = "^0.115.4" pandas = "^2.2.3" langchain-google-community = "^2.0.2" langchain-google-vertexai = "^2.0.7" pydantic = "^2.9.1"

[tool.poetry.group.dev.dependencies] isort = "^5.13.2" black = "^24.10.0"

[tool.poetry.group.test.dependencies] pytest = "^8.3.3" pytest-cov = "^5.0.0" pytest-asyncio = "^0.24.0" pytest-mock = "^3.14.0" flaky = "^3.8.1"

[build-system] requires = ["poetry-core"] build-backend = "poetry.core.masonry.api"

This is our toml files dependancies

You have pydantic ^2.9.1, this can be installing 2.10.0 where the problem seems to be. Fix this version to 2.9.2 and try again

@mkesicki
Copy link

FYI: The workaround works in our case both on AWS lambda & locally

@Luc2357
Copy link
Author

Luc2357 commented Nov 21, 2024

Thank you @jzaldi, pinning the pydantic version works!

@Luc2357 Luc2357 closed this as completed Nov 21, 2024
@domsj-foodpairing
Copy link

I don't think this ticket should be closed already, please reopen

Of course everyone can pin their pydantic to <2.10, but some more things need to happen IMO.

  • temporarily restrict the pydantic version this package depends on
  • figure out if whether this is a regression in pydantic OR if it's a wrong usage of pydantic in langchain-google-vertexai
  • depending on the outcome: register pydantic bug or fix the usage here

@Viicos
Copy link

Viicos commented Nov 22, 2024

In Pydantic 2.10, we introduced a complete refactor of the forward annotations evaluation. As a reminder, a forward annotation is a type hint surrounded by quotes:

class Model(BaseModel):
    a: 'MyInt'

    # Or, if the `from __future__ import annotations` is included:
    b: MyInt  # the import will automatically surround the annotation with quotes


MyInt = int  # defined _after_ `Model`

Because Pydantic uses type hints to build the model schema, it needs to evaluate these annotations, which can be really challenging. Debugging issues related to forward annotations (like this one) is also complicated.


Explanation of what should happen

The 2.10 refactor revealed what seems to be a genuine bug in this library. The VertexAIEmbeddings class is a Pydantic model, using _VertexAICommon as a base class:

class VertexAIEmbeddings(_VertexAICommon, Embeddings):
"""Google Cloud VertexAI embedding models."""
# Instance context
instance: Dict[str, Any] = {} #: :meta private:
model_config = ConfigDict(
extra="forbid",
protected_namespaces=(),
)

_VertexAICommon has a field annotated as Optional["SafetySettingsType"] (L197):

class _VertexAICommon(_VertexAIBase):
client_preview: Any = Field(default=None, exclude=True) #: :meta private:
model_name: str = Field(default=None, alias="model")
"Underlying model name."
temperature: Optional[float] = None
"Sampling temperature, it controls the degree of randomness in token selection."
max_output_tokens: Optional[int] = Field(default=None, alias="max_tokens")
"Token limit determines the maximum amount of text output from one prompt."
top_p: Optional[float] = None
"Tokens are selected from most probable to least until the sum of their "
"probabilities equals the top-p value. Top-p is ignored for Codey models."
top_k: Optional[int] = None
"How the model selects tokens for output, the next token is selected from "
"among the top-k most probable tokens. Top-k is ignored for Codey models."
n: int = 1
"""How many completions to generate for each prompt."""
seed: Optional[int] = None
"""Random seed for the generation."""
streaming: bool = False
"""Whether to stream the results or not."""
model_family: Optional[GoogleModelFamily] = None #: :meta private:
safety_settings: Optional["SafetySettingsType"] = None

SafetySettingsType is being imported from the vertexai library. The definition can be found here:

vertexai/generative_models/_generative_models.py:

SafetySettingsType = Union[
    List["SafetySetting"],
    Dict[
        gapic_content_types.HarmCategory,
        gapic_content_types.SafetySetting.HarmBlockThreshold,
    ],
]

SafetySetting, also referenced as a forward annotation, is defined in the same file here:

class SafetySetting:
    """Parameters for the generation."""

    HarmCategory = gapic_content_types.HarmCategory
    HarmBlockMethod = gapic_content_types.SafetySetting.HarmBlockMethod
    HarmBlockThreshold = gapic_content_types.SafetySetting.HarmBlockThreshold

    ...

So if everything is working as expected, the safety_settings field annotation should resolve to something like:

class _VertexAICommon(_VertexAIBase):
    # other fields defined ...
    ...

    safety_settings: Optional[
        Union[
            List[vertexai.generative_models._generative_models.SafetySetting],
            Dict[
                gapic_content_types.HarmCategory,
                gapic_content_types.SafetySetting.HarmBlockThreshold,
            ],
        ]
    ]

What really happens in Pydantic 2.9

However, in Pydantic 2.9, 'SafetySetting' resolves to the wrong class. This can be seen by inspecting the model fields:

# pydantic==2.9.2

from langchain_google_vertexai.embeddings import VertexAIEmbeddings

VertexAIEmbeddings.model_fields['safety_settings'].annotation
>>> Optional[
>>>     Union[
>>>         List[google.cloud.aiplatform_v1beta1.types.content.SafetySetting],  # different type!
>>>         Dict[
>>>             gapic_content_types.HarmCategory,
>>>             gapic_content_types.SafetySetting.HarmBlockThreshold,
>>>         ],
>>>     ]
>>> ]

The reason we get a different type for 'SafetySetting' is quite obscure and is explained at the end of this comment.

Now two questions can be raised from this:

  • what is the expected type for 'SafetySetting', as referenced in SafetySettingsType? Following the Python type checking semantics, it should be vertexai.generative_models._generative_models.SafetySetting.
  • How can this be fixed? This isn't trivial. It seems like the vertexai library is defining a lot of aliases with forward references. This is usually hard if not impossible to support. Take the following example:
# module1.py

from typing import List

Alias = List['SomeType']

SomeType = int

# module2.py

from module1 import Alias
from pydantic import BaseModel

class Model(BaseModel):
    a: Alias

# Model failed to build (calling `model_rebuild()` will raise)

Here, a: Alias is strictly equivalent to a: List['SomeType'], and Pydantic has no way of knowing that Alias is actually defined in a separate module.

A workaround is to either avoid using forward references in such aliases (not always possible), or to use the new typing.TypeAliasType construct:

Alias = TypeAliasType('Alias', List['SomeType'])
# or, when 3.12 becomes the lowest supported version:
type Alias = List[SomeType]

Why the wrong type was used

This goes deeper in the runtime implementation of the typing constructs.

When defining such an alias:

Alias = List['SomeRef']

Any argument passed to the List constructor (or Dict, Set, etc) is implicitly converted to a ForwardRef instance.

This means that Alias is in reality List[ForwardRef('SomeRef')]. To evaluate forward annotations, we end up calling a the typing._eval_type function. This will call ForwardRef._evaluate, and if the evaluation is successful, the result is cached under the ForwardRef.__forward_value__ attribute. Any future call to _evaluate will return this cached value.

Coming back to our SafetySettingsType alias, it turns out that it is used in other models (before VertexAIEmbeddings was built), where a reference to google.cloud.aiplatform_v1beta1.types.content.SafetySetting was available 1. We end up calling _evaluate for the ForwardRef('SafetySetting') inside List["SafetySetting"], and the result is cached on the instance.

Later on, SafetySettingsType is referenced in the VertexAIEmbeddings model, and the cached value is used.

Footnotes

  1. To evaluate forward references, we use what we call a namespace: a dictionary mapping strings to actual objects. The 2.10 refactor is touching this namespace management. What must have happened is that google.cloud.aiplatform_v1beta1.types.content.SafetySetting was (wrongfully or not) included in a namespace in 2.9 while it isn't in 2.10.

@yeesian
Copy link

yeesian commented Nov 22, 2024

Thank you for the detailed explanation, created a new issue for it in #613

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

8 participants