Agent 开发实战 · 第 2 篇

完成第一次模型 API 请求

正确处理密钥、模型、超时、错误分类和最小运行日志。

30 分钟开发入门

学完能做什么

你会用 Python 完成一次可运行的模型请求,并正确处理密钥、模型 ID、超时、空响应和常见错误。这个请求会成为后续工具调用 Agent 的模型适配层。

请求前先确认四件事

  1. 已创建 API 密钥,并只保存到安全位置;
  2. 已在模型列表确认可用的模型 ID;
  3. 当前账户有可用额度;
  4. Python 版本和依赖安装正常。

不要从网页标题或教程截图猜模型 ID。模型可用性会变化,应以控制台和接口返回为准。

准备独立环境

bash
mkdir first-model-request
cd first-model-request
python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade openai

Windows PowerShell 激活命令通常是:

powershell
.venv\Scripts\Activate.ps1

将密钥和模型 ID 放入当前终端环境变量:

bash
export BIGAO_API_KEY="你的密钥"
export BIGAO_MODEL_ID="控制台中的模型ID"

不要把真实值写进源码、提交记录、聊天截图或错误日志。

最小但完整的请求代码

创建 first_request.py

python
import os
import sys

from openai import APIConnectionError, APIStatusError, OpenAI


api_key = os.environ.get("BIGAO_API_KEY")
model_id = os.environ.get("BIGAO_MODEL_ID")

if not api_key or not model_id:
    raise RuntimeError("缺少 BIGAO_API_KEY 或 BIGAO_MODEL_ID")

client = OpenAI(
    api_key=api_key,
    base_url="https://api.bigao.ai/v1",
    timeout=30.0,
    max_retries=2,
)


def main() -> None:
    try:
        response = client.chat.completions.create(
            model=model_id,
            messages=[
                {
                    "role": "system",
                    "content": "你是简洁的中文助手。不确定时明确说明。",
                },
                {
                    "role": "user",
                    "content": "用三点解释为什么 API 请求要设置超时。",
                },
            ],
            temperature=0.2,
        )
    except APIConnectionError as error:
        print(f"连接失败:{error.__class__.__name__}", file=sys.stderr)
        raise SystemExit(2)
    except APIStatusError as error:
        print(
            f"接口返回错误:status={error.status_code}",
            file=sys.stderr,
        )
        raise SystemExit(3)

    content = response.choices[0].message.content
    if not content:
        raise RuntimeError("模型返回了空内容")

    print(content)
    print(f"request_id={getattr(response, '_request_id', None)}")


if __name__ == "__main__":
    main()

运行:

bash
python first_request.py

每个参数为什么存在

参数作用第一版建议
base_url指向兼容接口地址集中配置,不散落在代码里
timeout限制等待时间依据业务延迟设定,不要无限等待
max_retries处理少量临时故障保持较小,写操作另做幂等
model指定模型来自配置,不硬编码多个副本
messages提供指令与任务系统规则短而明确
temperature调整输出随机性稳定任务使用较低值

超时不代表服务端一定没有执行。有副作用的请求以后必须配合业务幂等键,而不是盲目重试。

不要只打印答案

进入正式开发后,至少记录这些非敏感字段:

  • 自己生成的任务 ID;
  • 请求开始时间和耗时;
  • 请求模型 ID、实际模型 ID 与提示词版本;
  • HTTP 状态与请求 ID;
  • 输入、输出的长度或用量;
  • 成功、失败和错误分类。

不要记录 API 密钥、完整授权头、未经处理的个人信息和模型隐藏推理。

常见错误如何判断

401

表示密钥缺失、不完整、已撤销或无效。检查服务地址和密钥,但不要在终端回显完整值。

403

表示已认证账户当前无权完成请求。检查账户状态并保留响应中的请求 ID;这不是“模型不匹配”的信号。

请求的模型不可用

开发者 Key 按供应商授权。请求未知模型或其他供应商模型时,网关可能使用该供应商的默认模型,并按实际模型计费。不要假定请求一定使用了提交的模型 ID,应读取 X-Bigao-Requested-ModelX-Bigao-Effective-ModelX-Bigao-Model-Fallback 响应头。

429

可能是请求频率、并发或余额限制。读取响应信息,降低并发并使用带随机抖动的退避;不要无限重试。

连接或超时错误

先分别检查 DNS、TLS、系统时间、防火墙与目标地址是否可达,再确认是不是短时故障。网络不可用时重跑代码不会改变结果。

返回成功但内容为空

先检查响应类型、结束原因和模型是否返回了工具调用。不要把空字符串当成有效答案。

把调用封装成边界

后续 Agent 不应在各处直接创建客户端。定义稳定接口:

python
from dataclasses import dataclass


@dataclass
class ModelReply:
    text: str | None
    tool_calls: list
    request_id: str | None


def ask_model(messages, tools=None) -> ModelReply:
    # 在这里统一设置模型、超时、重试、日志和错误映射
    ...

这样更换模型或测试模拟响应时,不需要改业务循环。

运行练习

  1. 正常运行一次并保存任务 ID、耗时和请求 ID;
  2. 临时填写未知模型 ID,观察模型回退响应头;
  3. 将超时设得很短,验证连接错误不会泄露密钥;
  4. 把用户问题移到命令行参数,限制最大长度;
  5. ask_model 写一个不访问网络的假实现。

完成检查清单

  • 密钥来自环境变量或密钥服务,没有进入代码库。
  • 模型 ID 和接口地址来自集中配置。
  • 请求设置了超时和有限重试。
  • 401、403、429、模型回退、连接失败和空响应能被区分。
  • 日志保留请求证据,但不包含敏感信息。

下一步

下一篇会在这个模型边界上加入一个只读工具,完成第一次真正的工具调用闭环。