Hi all. When trying to switch to using `AzureChat...
# marvin-ai
d
Hi all. When trying to switch to using
AzureChatOpenAI
I get an
AttributeError: 'AzureChatOpenAI' object has no attribute 'get'
when the agent's running. The model's assigned to the default as in the docs here
Copy code
cf.defaults.model = AzureChatOpenAI(
            api_version=AZURE_OPENAI_LLM_API_VERSION,
            temperature=0,
            streaming=True,
            model_name=AZURE_OPENAI_LLM_DEPLOYMENT,
            api_key=AZURE_OPENAI_LLM_API_KEY,
            azure_endpoint=azure_endpoint)
I'll put the stack trace in a comment on the thread. Anyone have any ideas? Presumably it's a mismatch in langchain models - controlflow's requirements.txt.lock say 0.1.23, the pyproject.toml says >= 0.2 while we're using 0.2.2 (we've been using langchain in this project for a while, currently integrating some controlflow elements in). Using the default model - which from the docs I believe is just a ChatOpenAI? - works fine, so AzureChatOpenAI should, right?
Copy code
cf.run(
                 ^^^^^^^
  File "/Users/dangodbold/src/github.com/expectai/acp-llm/.venv/lib/python3.12/site-packages/controlflow/run.py", line 128, in run
    results = run_tasks(
              ^^^^^^^^^^
  File "/Users/dangodbold/src/github.com/expectai/acp-llm/.venv/lib/python3.12/site-packages/prefect/tasks.py", line 997, in __call__
    return run_task(
           ^^^^^^^^^
  File "/Users/dangodbold/src/github.com/expectai/acp-llm/.venv/lib/python3.12/site-packages/prefect/task_engine.py", line 1512, in run_task
    return run_task_sync(**kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/dangodbold/src/github.com/expectai/acp-llm/.venv/lib/python3.12/site-packages/prefect/task_engine.py", line 1325, in run_task_sync
    return engine.state if return_type == "state" else engine.result()
                                                       ^^^^^^^^^^^^^^^
  File "/Users/dangodbold/src/github.com/expectai/acp-llm/.venv/lib/python3.12/site-packages/prefect/task_engine.py", line 457, in result
    raise self._raised
  File "/Users/dangodbold/src/github.com/expectai/acp-llm/.venv/lib/python3.12/site-packages/prefect/task_engine.py", line 763, in run_context
    yield self
  File "/Users/dangodbold/src/github.com/expectai/acp-llm/.venv/lib/python3.12/site-packages/prefect/task_engine.py", line 1323, in run_task_sync
    engine.call_task_fn(txn)
  File "/Users/dangodbold/src/github.com/expectai/acp-llm/.venv/lib/python3.12/site-packages/prefect/task_engine.py", line 786, in call_task_fn
    result = call_with_parameters(self.task.fn, parameters)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/dangodbold/src/github.com/expectai/acp-llm/.venv/lib/python3.12/site-packages/prefect/utilities/callables.py", line 206, in call_with_parameters
    return fn(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^
  File "/Users/dangodbold/src/github.com/expectai/acp-llm/.venv/lib/python3.12/site-packages/controlflow/run.py", line 52, in run_tasks
    orchestrator.run(
  File "/Users/dangodbold/src/github.com/expectai/acp-llm/.venv/lib/python3.12/site-packages/prefect/tasks.py", line 997, in __call__
    return run_task(
           ^^^^^^^^^
  File "/Users/dangodbold/src/github.com/expectai/acp-llm/.venv/lib/python3.12/site-packages/prefect/task_engine.py", line 1512, in run_task
    return run_task_sync(**kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/dangodbold/src/github.com/expectai/acp-llm/.venv/lib/python3.12/site-packages/prefect/task_engine.py", line 1325, in run_task_sync
    return engine.state if return_type == "state" else engine.result()
                                                       ^^^^^^^^^^^^^^^
  File "/Users/dangodbold/src/github.com/expectai/acp-llm/.venv/lib/python3.12/site-packages/prefect/task_engine.py", line 457, in result
    raise self._raised
  File "/Users/dangodbold/src/github.com/expectai/acp-llm/.venv/lib/python3.12/site-packages/prefect/task_engine.py", line 763, in run_context
    yield self
  File "/Users/dangodbold/src/github.com/expectai/acp-llm/.venv/lib/python3.12/site-packages/prefect/task_engine.py", line 1323, in run_task_sync
    engine.call_task_fn(txn)
  File "/Users/dangodbold/src/github.com/expectai/acp-llm/.venv/lib/python3.12/site-packages/prefect/task_engine.py", line 786, in call_task_fn
    result = call_with_parameters(self.task.fn, parameters)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/dangodbold/src/github.com/expectai/acp-llm/.venv/lib/python3.12/site-packages/prefect/utilities/callables.py", line 206, in call_with_parameters
    return fn(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^
  File "/Users/dangodbold/src/github.com/expectai/acp-llm/.venv/lib/python3.12/site-packages/controlflow/orchestration/orchestrator.py", line 217, in run
    self.run_agent_turn(
  File "/Users/dangodbold/src/github.com/expectai/acp-llm/.venv/lib/python3.12/site-packages/prefect/tasks.py", line 997, in __call__
    return run_task(
           ^^^^^^^^^
  File "/Users/dangodbold/src/github.com/expectai/acp-llm/.venv/lib/python3.12/site-packages/prefect/task_engine.py", line 1512, in run_task
    return run_task_sync(**kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/dangodbold/src/github.com/expectai/acp-llm/.venv/lib/python3.12/site-packages/prefect/task_engine.py", line 1325, in run_task_sync
    return engine.state if return_type == "state" else engine.result()
                                                       ^^^^^^^^^^^^^^^
  File "/Users/dangodbold/src/github.com/expectai/acp-llm/.venv/lib/python3.12/site-packages/prefect/task_engine.py", line 457, in result
    raise self._raised
  File "/Users/dangodbold/src/github.com/expectai/acp-llm/.venv/lib/python3.12/site-packages/prefect/task_engine.py", line 763, in run_context
    yield self
  File "/Users/dangodbold/src/github.com/expectai/acp-llm/.venv/lib/python3.12/site-packages/prefect/task_engine.py", line 1323, in run_task_sync
    engine.call_task_fn(txn)
  File "/Users/dangodbold/src/github.com/expectai/acp-llm/.venv/lib/python3.12/site-packages/prefect/task_engine.py", line 786, in call_task_fn
    result = call_with_parameters(self.task.fn, parameters)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/dangodbold/src/github.com/expectai/acp-llm/.venv/lib/python3.12/site-packages/prefect/utilities/callables.py", line 206, in call_with_parameters
    return fn(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^
  File "/Users/dangodbold/src/github.com/expectai/acp-llm/.venv/lib/python3.12/site-packages/controlflow/orchestration/orchestrator.py", line 372, in run_agent_turn
    messages = self.compile_messages()
               ^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/dangodbold/src/github.com/expectai/acp-llm/.venv/lib/python3.12/site-packages/controlflow/orchestration/orchestrator.py", line 492, in compile_messages
    llm_rules=self.agent.get_llm_rules(),
              ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/dangodbold/src/github.com/expectai/acp-llm/.venv/lib/python3.12/site-packages/controlflow/agents/agent.py", line 187, in get_llm_rules
    return controlflow.llm.rules.rules_for_model(self.get_model())
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/dangodbold/src/github.com/expectai/acp-llm/.venv/lib/python3.12/site-packages/controlflow/llm/rules.py", line 74, in rules_for_model
    return OpenAIRules(model=model)
           ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/dangodbold/src/github.com/expectai/acp-llm/.venv/lib/python3.12/site-packages/pydantic/main.py", line 212, in __init__
    validated_self = self.__pydantic_validator__.validate_python(data, self_instance=self)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/dangodbold/src/github.com/expectai/acp-llm/.venv/lib/python3.12/site-packages/langchain_openai/chat_models/base.py", line 480, in build_extra
    values = _build_model_kwargs(values, all_required_field_names)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/dangodbold/src/github.com/expectai/acp-llm/.venv/lib/python3.12/site-packages/langchain_core/utils/utils.py", line 236, in _build_model_kwargs
    extra_kwargs = values.get("model_kwargs", {})
                   ^^^^^^^^^^
  File "/Users/dangodbold/src/github.com/expectai/acp-llm/.venv/lib/python3.12/site-packages/pydantic/main.py", line 856, in __getattr__
    raise AttributeError(f'{type(self).__name__!r} object has no attribute {item!r}')
AttributeError: 'AzureChatOpenAI' object has no attribute 'get'
j
That is definitely unexpected - it looks like the error is coming from langchain but its being prompted by pydantic validation, and langchain's pydantic integration is very weird so i'll look to see if we can prevent it in CF
d
Yeah, I couldn't work it out. When debugging the agent's model is always None if it's just using the default one, so I couldn't confirm 100% it's always
ChatOpenAI
, but I think it's somewhere there in the model inheritance, somethings re-implemented for Azure in a way that breaks this (or not implemented in the first place).
j
@Dan Godbold this went a little deeper than I thought - I've lost the trail somewhere in Pydantic. This fix will resolve it on the CF side https://github.com/PrefectHQ/ControlFlow/pull/376
I've released this fix in 0.11.3
d
Fantastic, thanks!
As a curiosity (I've not had enough time with python to get into the depths enough to know if this is a useful or stupid question) do you see the same behaviour when the types are declared with
ChatOpenAI | AzureChatOpenAI
rather than
Union[ChatOpenAI, AzureChatOpenAI]
? Is there a difference under the covers?