datawhalechina/hello-agents · error · ValueError

模型ID、API密钥和服务地址必须被提供或在.env文件中定义。

Error message

模型ID、API密钥和服务地址必须被提供或在.env文件中定义。

What it means

A ValueError raised by LLMClient.__init__ when any of model, apiKey, or baseUrl is missing after merging constructor arguments with environment variables (LLM_MODEL_ID, LLM_API_KEY, LLM_BASE_URL). It is a fail-fast configuration check: the all([...]) guard requires all three to be non-empty before constructing the OpenAI client, so the SDK never receives incomplete credentials.

Source

Thrown at code/chapter4/llm_client.py:24

# 加载 .env 文件中的环境变量
load_dotenv()

class HelloAgentsLLM:
    """
    为本书 "Hello Agents" 定制的LLM客户端。
    它用于调用任何兼容OpenAI接口的服务,并默认使用流式响应。
    """
    def __init__(self, model: str = None, apiKey: str = None, baseUrl: str = None, timeout: int = None):
        """
        初始化客户端。优先使用传入参数,如果未提供,则从环境变量加载。
        """
        self.model = model or os.getenv("LLM_MODEL_ID")
        apiKey = apiKey or os.getenv("LLM_API_KEY")
        baseUrl = baseUrl or os.getenv("LLM_BASE_URL")
        timeout = timeout or int(os.getenv("LLM_TIMEOUT", 60))
        
        if not all([self.model, apiKey, baseUrl]):
            raise ValueError("模型ID、API密钥和服务地址必须被提供或在.env文件中定义。")

        self.client = OpenAI(api_key=apiKey, base_url=baseUrl, timeout=timeout)

    def think(self, messages: List[Dict[str, str]], temperature: float = 0) -> str:
        """
        调用大语言模型进行思考,并返回其响应。
        """
        print(f"🧠 正在调用 {self.model} 模型...")
        try:
            response = self.client.chat.completions.create(
                model=self.model,
                messages=messages,
                temperature=temperature,
                stream=True,
            )
            
            # 处理流式响应
            print("✅ 大语言模型响应成功:")

View on GitHub (pinned to 606a07d341)

Solutions

  1. Create/fix .env in the working directory with LLM_MODEL_ID, LLM_API_KEY, LLM_BASE_URL, and ensure dotenv is loaded before constructing LLMClient (or export them in the shell).
  2. Or pass all three explicitly: LLMClient(model='...', apiKey='...', baseUrl='...').
  3. Verify with a one-liner: python -c "import os; print(os.getenv('LLM_MODEL_ID'), os.getenv('LLM_API_KEY'), os.getenv('LLM_BASE_URL'))" — whichever prints None is the culprit.
  4. In containers/CI, map the platform's secret names to these three variables explicitly.

Example fix

# before
client = LLMClient()  # ValueError if env not loaded

# after
from dotenv import load_dotenv
load_dotenv()  # or load_dotenv("path/to/.env")
client = LLMClient()
# or fully explicit:
client = LLMClient(model="qwen-max", apiKey="sk-...", baseUrl="https://dashscope.aliyuncs.com/compatible-mode/v1")
Defensive patterns

Strategy: validation

Validate before calling

from dotenv import load_dotenv; load_dotenv()
import os
missing = [k for k in ("LLM_MODEL_ID", "LLM_API_KEY", "LLM_BASE_URL") if not os.getenv(k)]
if missing: raise EnvironmentError(f"missing env: {missing}")

Type guard

null

Try / catch

try:
    client = LLMClient()
except ValueError as e:
    raise EnvironmentError(f"LLM config incomplete: {e}") from e

Prevention

When it happens

Trigger: Instantiating LLMClient() with no arguments when any of the three env vars is unset/empty; passing only some arguments (e.g. LLMClient(model='qwen-max')) while the key or base URL is missing; running in a shell where .env was never loaded (this constructor does not call load_dotenv itself unless done elsewhere); typos in env var names like LLM_APIKEY.

Common situations: New clone without .env created; .env present but the process started from a different working directory so it was not picked up; CI/containers where secrets are injected under different variable names; renaming between OPENAI_API_KEY-style and this project's LLM_* names.

Related errors


AI-assisted analysis of datawhalechina/hello-agents@606a07d341 (2026-08-14). Data as JSON: /api/errors/e385f6a7cfbb977a. Report an issue: GitHub.