{"record":{"id":"e385f6a7cfbb977a","repo":"datawhalechina/hello-agents","slug":"id-api-env","errorCode":null,"errorMessage":"模型ID、API密钥和服务地址必须被提供或在.env文件中定义。","messagePattern":"模型ID、API密钥和服务地址必须被提供或在\\.env文件中定义。","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"code/chapter4/llm_client.py","lineNumber":24,"sourceCode":"# 加载 .env 文件中的环境变量\nload_dotenv()\n\nclass HelloAgentsLLM:\n    \"\"\"\n    为本书 \"Hello Agents\" 定制的LLM客户端。\n    它用于调用任何兼容OpenAI接口的服务，并默认使用流式响应。\n    \"\"\"\n    def __init__(self, model: str = None, apiKey: str = None, baseUrl: str = None, timeout: int = None):\n        \"\"\"\n        初始化客户端。优先使用传入参数，如果未提供，则从环境变量加载。\n        \"\"\"\n        self.model = model or os.getenv(\"LLM_MODEL_ID\")\n        apiKey = apiKey or os.getenv(\"LLM_API_KEY\")\n        baseUrl = baseUrl or os.getenv(\"LLM_BASE_URL\")\n        timeout = timeout or int(os.getenv(\"LLM_TIMEOUT\", 60))\n        \n        if not all([self.model, apiKey, baseUrl]):\n            raise ValueError(\"模型ID、API密钥和服务地址必须被提供或在.env文件中定义。\")\n\n        self.client = OpenAI(api_key=apiKey, base_url=baseUrl, timeout=timeout)\n\n    def think(self, messages: List[Dict[str, str]], temperature: float = 0) -> str:\n        \"\"\"\n        调用大语言模型进行思考，并返回其响应。\n        \"\"\"\n        print(f\"🧠 正在调用 {self.model} 模型...\")\n        try:\n            response = self.client.chat.completions.create(\n                model=self.model,\n                messages=messages,\n                temperature=temperature,\n                stream=True,\n            )\n            \n            # 处理流式响应\n            print(\"✅ 大语言模型响应成功:\")","sourceCodeStart":6,"sourceCodeEnd":42,"githubUrl":"https://github.com/datawhalechina/hello-agents/blob/606a07d341a47be773fab7f4b71177f53f96b2c3/code/chapter4/llm_client.py#L6-L42","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["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).","Or pass all three explicitly: LLMClient(model='...', apiKey='...', baseUrl='...').","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.","In containers/CI, map the platform's secret names to these three variables explicitly."],"exampleFix":"# before\nclient = LLMClient()  # ValueError if env not loaded\n\n# after\nfrom dotenv import load_dotenv\nload_dotenv()  # or load_dotenv(\"path/to/.env\")\nclient = LLMClient()\n# or fully explicit:\nclient = LLMClient(model=\"qwen-max\", apiKey=\"sk-...\", baseUrl=\"https://dashscope.aliyuncs.com/compatible-mode/v1\")","handlingStrategy":"validation","validationCode":"from dotenv import load_dotenv; load_dotenv()\nimport os\nmissing = [k for k in (\"LLM_MODEL_ID\", \"LLM_API_KEY\", \"LLM_BASE_URL\") if not os.getenv(k)]\nif missing: raise EnvironmentError(f\"missing env: {missing}\")","typeGuard":"null","tryCatchPattern":"try:\n    client = LLMClient()\nexcept ValueError as e:\n    raise EnvironmentError(f\"LLM config incomplete: {e}\") from e","preventionTips":["Load .env (load_dotenv) before constructing LLMClient.","Provide a .env.example in the repo listing the three required variables.","Fail fast at startup with a clear preflight check instead of at first LLM call."],"tags":["configuration","env-vars","openai-sdk","valueerror"],"backgroundTag":null,"analyzedSha":"606a07d341a47be773fab7f4b71177f53f96b2c3","analyzedAt":"2026-08-14T22:57:27.446Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}