#1338·gorilla

[BFCL] Eager import of qwen_agent forces audio deps on Claude-only users

Author: hidingtonothingCreated May 28, 2026Updated Sep 4, 2026

Describe the issue

A fresh pip install bfcl-eval followed by bfcl --help crashes with ModuleNotFoundError: No module named 'soundfile', even when the user has no intention of running Qwen models. The cause is an eager import chain at CLI startup that loads every model handler — including Qwen's, which transitively requires soundfile, qwen_agent, and (further downstream) the libsndfile audio stack. Users running only Claude, GPT, Gemini, or open-weights models pay the cost of Qwen's audio dependencies just to see bfcl --help.

ID datapoint

  1. Datapoint / Model Handler permalink: https://github.com/ShishirPatil/gorilla/blob/main/berkeley-function-call-leaderboard/bfcl_eval/model_handler/api_inference/qwen.py (and the eager import in bfcl_eval/constants/model_config.py)
  2. Issue: Top-level import of the Qwen model handler forces every BFCL user — even those running only Claude/GPT/Gemini/open-weights models — to satisfy Qwen's transitive dependencies (qwen_agent, soundfile, libsndfile) at CLI startup. The CLI fails before printing --help.
  3. Gorilla repo commit #: reproduced against bfcl-eval 2026.3.23 from PyPI (latest at time of filing); not tied to a specific commit because the issue is a packaging design rather than a bug introduced by a particular change.

What is the issue

Environment

  • bfcl-eval 2026.3.23 (from PyPI)
  • Python 3.14.5 on macOS arm64
  • qwen_agent installed as a transitive dependency
  • No Qwen models being benchmarked — user is evaluating Claude Sonnet 4.6 only

Symptom

$ pip install bfcl-eval
[succeeds]

$ bfcl --help
Traceback (most recent call last):
  File ".../bin/bfcl", line 3, in <module>
    from bfcl_eval.__main__ import cli
  ...
  File ".../bfcl_eval/constants/model_config.py", line 27, in <module>
    from bfcl_eval.model_handler.api_inference.qwen import (
        ...
    )
  File ".../bfcl_eval/model_handler/api_inference/qwen.py", line 8, in <module>
    from qwen_agent.llm import get_chat_model
  File ".../qwen_agent/llm/__init__.py", line 18, in <module>
    from .azure import TextChatAtAzure
  File ".../qwen_agent/llm/azure.py", line 20, in <module>
    from qwen_agent.llm.base import register_llm
  File ".../qwen_agent/llm/base.py", line 29, in <module>
    from qwen_agent.utils.utils import (extract_text_from_message, ...)
  File ".../qwen_agent/utils/utils.py", line 34, in <module>
    import soundfile as sf
ModuleNotFoundError: No module named 'soundfile'

bfcl --help should work after pip install bfcl-eval with no further setup. It currently does not.

Reproduction

bash
# Fresh Python 3.14 venv (3.13 reproduces the same way)
python3.14 -m venv /tmp/repro
source /tmp/repro/bin/activate
pip install bfcl-eval
bfcl --help  # crashes with ModuleNotFoundError: No module named 'soundfile'

Root cause

In bfcl_eval/constants/model_config.py:27, the Qwen model handler is imported unconditionally at module load:

python
from bfcl_eval.model_handler.api_inference.qwen import (
    ...
)

bfcl_eval/__main__.py triggers this import chain via:

__main__ → _llm_response_generation → eval_runner_helper → model_config → qwen handler → qwen_agent → soundfile (missing)

So every entry into the BFCL CLI — including bfcl --help, bfcl models, bfcl version — has to satisfy Qwen's full transitive dependency closure before doing anything else.

Proposed Changes

Two options, in increasing order of restructure:

Option 1 — Lazy import of model handlers in model_config.py. Move the handler imports inside a factory function or use a registry pattern that loads handlers on demand:

python
# Instead of top-level imports, register lazily:
def get_handler(model_name: str):
    if model_name.startswith("qwen"):
        from bfcl_eval.model_handler.api_inference.qwen import QwenAPIHandler
        return QwenAPIHandler
    if model_name.startswith("claude"):
        from bfcl_eval.model_handler.api_inference.anthropic import AnthropicAPIHandler
        return AnthropicAPIHandler
    # ...

This keeps bfcl --help fast and dependency-light, and only loads each handler's transitive deps when that handler is actually requested.

Option 2 — Make Qwen (and similar) handlers optional extras. Move qwen_agent to an extras_require group in setup.py / pyproject.toml:

toml
[project.optional-dependencies]
qwen = ["qwen_agent>=X.Y", "soundfile", ...]

Then pip install 'bfcl-eval[qwen]' opts in. The default install only pulls dependencies for handlers the user actually needs.

Option 1 alone fixes the CLI startup issue. Option 2 additionally reduces install footprint and the risk of unrelated dep-conflicts (e.g., numba/scipy versions pulled in by librosa if Qwen ever needs it).

(Note: the issue template's {'previous_datapoint': ..., 'updated_datapoint': ...} JSON skeleton is for dataset corrections rather than packaging bugs, so it's omitted here — this issue is about the model-handler import structure, not a datapoint.)

Additional context

Impact

  • Every user running BFCL today on a fresh install hits this on bfcl --help if they don't happen to already have soundfile in their environment.
  • The downstream Qwen audio stack (soundfile → libsndfile, optionally librosa → numba → scipy) introduces a significant transitive dependency surface that's irrelevant to most users.
  • This bites particularly on Python versions where qwen_agent or its transitive deps don't have wheels available — every install becomes a build-from-source exercise.

Workaround

For now, after pip install bfcl-eval:

bash
pip install soundfile
# If a later import chain step also fails on a different missing module, install that one too

This unblocks the CLI for Claude/GPT/Gemini-only use cases, at the cost of carrying audio deps the user doesn't need.

Discovery context

Found while installing the BFCL stack for Claude Sonnet 4.6 evaluation as part of an Anthropic-recommended hallucination-evaluation toolchain. The benchmark itself is excellent and the V4 Hallucination subscore is exactly the kind of metric Claude-focused users want. The dependency packaging is the only friction.