大语言模型(LLM)是现代AI Agent的"大脑"。掌握API调用是构建Agent的第一步。本课深入探索OpenAI兼容API的调用方法与最佳实践。
| 提供商 | 模型 | 特点 | 适用场景 |
|---|---|---|---|
| OpenAI | GPT-4o | 综合能力强 | 通用Agent |
| Anthropic | Claude-4 | 长上下文、安全 | 文档分析Agent |
| Gemini 2.5 | 多模态 | 视觉Agent | |
| DeepSeek | DeepSeek-V3 | 性价比高 | 预算有限的Agent |
| 本地部署 | Llama 3 | 数据不出域 | 企业内网Agent |
┌──────────┐ ┌──────────────┐ ┌───────────┐
│ 你的代码 │────→│ API Gateway │────→│ LLM模型 │
│ │←────│ (认证/限流) │←────│ │
└──────────┘ └──────────────┘ └───────────┘
│ │
│ 请求: messages + params │
│ 响应: completion + usage │
↓ ↓
┌──────────┐ ┌───────────┐
│ 重试/缓存 │ │ Token计算 │
└──────────┘ └───────────┘
temperature = 0.0 → 确定性输出,适合代码生成、数据提取 temperature = 0.3 → 低随机性,适合分析、总结 temperature = 0.7 → 平衡模式,适合一般对话 temperature = 1.0 → 高创造性,适合创意写作 temperature = 1.5 → 非常随机,适合头脑风暴 Agent推荐: 0.0-0.3(需要确定性输出) 对话推荐: 0.5-0.8(需要自然感)
# LLM API客户端 - 支持OpenAI兼容接口
import os, time, json
from typing import List, Dict, Optional
from dataclasses import dataclass
@dataclass
class LLMConfig:
# LLM配置
api_key: str = os.getenv("OPENAI_API_KEY", "sk-demo")
base_url: str = os.getenv("OPENAI_BASE_URL", "https://api.openai.com/v1")
model: str = "gpt-4o-mini"
temperature: float = 0.7
max_tokens: int = 2048
timeout: int = 30
class MessageBuilder:
# 消息构建器
@staticmethod
def system(prompt):
return {"role": "system", "content": prompt}
@staticmethod
def user(content):
return {"role": "user", "content": content}
@staticmethod
def assistant(content):
return {"role": "assistant", "content": content}
@staticmethod
def tool_result(tool_call_id, content):
return {"role": "tool", "tool_call_id": tool_call_id, "content": content}
class MockLLMClient:
# 模拟LLM客户端(无需真实API Key)
def __init__(self, config=None):
self.config = config or LLMConfig()
self.usage = {"calls": 0, "tokens": 0}
self.responses = {
"你好": "你好!我是AI助手,有什么可以帮你的吗?",
"1+1": "1+1等于2。",
"写个函数": "好的,这是一个Python示例函数:\ndef hello():\n print('Hello!')"
}
def chat(self, messages, **kwargs):
self.usage["calls"] += 1
self.usage["tokens"] += len(str(messages)) // 4
user_msg = ""
for m in messages:
if m["role"] == "user":
user_msg = m["content"]
for key, resp in self.responses.items():
if key in user_msg:
return resp
return f"收到:{user_msg[:50]}..."
def chat_with_retry(self, messages, max_retries=3, **kwargs):
# 带指数退避的重试
for attempt in range(max_retries):
try:
return self.chat(messages, **kwargs)
except Exception as e:
if attempt == max_retries - 1:
raise
time.sleep(2 ** attempt)
def estimate_cost(self, input_tokens, output_tokens):
# GPT-4o-mini定价估算
return input_tokens * 0.15 / 1e6 + output_tokens * 0.60 / 1e6
# 使用示例
client = MockLLMClient()
messages = [MessageBuilder.system("你是友好的AI助手。"), MessageBuilder.user("你好!")]
result = client.chat(messages)
print(f"回复: {result}")
messages.append(MessageBuilder.assistant(result))
messages.append(MessageBuilder.user("1+1等于几?"))
result2 = client.chat(messages)
print(f"回复: {result2}")
print(f"统计: {client.usage}")
print(f"成本: ${client.estimate_cost(500, 200):.6f}")
| 提供商 | 模型 | 上下文窗口 | 特色功能 |
|---|---|---|---|
| OpenAI | GPT-4o / GPT-4o-mini | 128K | Function Calling, Structured Output |
| Anthropic | Claude 3.5 Sonnet | 200K | Tool Use, 长上下文理解 |
| Gemini 1.5 Pro | 1M | 超长上下文,多模态 | |
| DeepSeek | DeepSeek-V3 | 128K | 高性价比,代码能力强 |
| 智谱 | GLM-4 | 128K | 中文优化,国内合规 |
当你调用client.chat.completions.create()时,发生了什么?
客户端 -> API网关 -> 模型推理集群 | HTTP POST | 负载均衡 | GPU推理 | Auth: Bearer | 选节点 | Token流式返回 | Content:JSON | | | <- SSE/JSON - | <- Token流 -|
关键概念:Token(LLM最小文本单位)、Temperature(随机性控制)、Top-p(核采样)、Max tokens(生成长度限制)
一个健壮的LLM调用框架需要支持:多Provider切换、自动重试、Token统计、错误分类处理。
# UnifiedLLM - 统一LLM调用框架
import time
import json
from typing import List, Dict, Optional
from dataclasses import dataclass
from enum import Enum
class Provider(Enum):
OPENAI = "openai"
DEEPSEEK = "deepseek"
ZHIPU = "zhipu"
@dataclass
class TokenUsage:
prompt_tokens: int = 0
completion_tokens: int = 0
total_tokens: int = 0
@dataclass
class LLMResponse:
content: str
model: str
usage: TokenUsage
latency_ms: float
provider: str
class UnifiedLLM:
# 统一LLM调用框架
#
# 特性:
# 1. 统一接口切换不同Provider
# 2. 自动重试(网络错误/限流)
# 3. Token统计与成本估算
#
PRICING = {
"gpt-4o": {"input": 0.0025, "output": 0.01},
"gpt-4o-mini": {"input": 0.00015, "output": 0.0006},
"deepseek-chat": {"input": 0.00014, "output": 0.00028},
"glm-4": {"input": 0.001, "output": 0.001},
}
def __init__(self, provider: Provider = Provider.DEEPSEEK):
self.provider = provider
self.call_history: List[Dict] = []
self.total_usage = TokenUsage()
def _estimate_tokens(self, text: str) -> int:
cn = sum(1 for c in text if '\u4e00' <= c <= '\u9fff')
en = len(text) - cn
return int(cn / 1.5 + en / 4) + 1
def chat(self, messages: List[Dict], model: str = None,
temperature: float = 0.7, max_retries: int = 3) -> LLMResponse:
# 统一聊天接口 - 自动重试 + Token统计
config = {
Provider.OPENAI: {"model": "gpt-4o-mini"},
Provider.DEEPSEEK: {"model": "deepseek-chat"},
Provider.ZHIPU: {"model": "glm-4"},
}
if model is None:
model = config[self.provider]["model"]
for attempt in range(max_retries):
start = time.time()
try:
last_msg = messages[-1]["content"]
usage = TokenUsage(
prompt_tokens=self._estimate_tokens(
json.dumps(messages, ensure_ascii=False)),
completion_tokens=self._estimate_tokens(last_msg) * 2,
)
usage.total_tokens = usage.prompt_tokens + usage.completion_tokens
latency = (time.time() - start) * 1000
response = LLMResponse(
content=f"[模拟] 针对'{last_msg[:20]}'的回答,"
f"来自{self.provider.value}。",
model=model, usage=usage, latency_ms=latency,
provider=self.provider.value
)
self.total_usage.prompt_tokens += usage.prompt_tokens
self.total_usage.completion_tokens += usage.completion_tokens
self.total_usage.total_tokens += usage.total_tokens
self.call_history.append({
"model": model, "tokens": usage.total_tokens,
"latency_ms": round(latency, 1), "status": "success"
})
return response
except ConnectionError:
wait = 2 ** attempt
print(f" 连接失败(尝试{attempt+1}/{max_retries}),{wait}s后重试...")
time.sleep(min(wait, 0.5))
raise RuntimeError(f"API调用失败,已重试{max_retries}次")
def get_stats(self) -> Dict:
total = len(self.call_history)
success = sum(1 for h in self.call_history if h["status"] == "success")
cost = sum(h.get("tokens", 0) / 1000 *
self.PRICING.get(h.get("model", ""),
{"input": 0, "output": 0}).get("output", 0)
for h in self.call_history)
return {
"provider": self.provider.value,
"total_calls": total,
"success_rate": f"{success/total*100:.1f}%" if total else "N/A",
"total_tokens": self.total_usage.total_tokens,
"total_cost_usd": round(cost, 6)
}
# 测试
llm = UnifiedLLM(Provider.DEEPSEEK)
resp = llm.chat([{"role": "user", "content": "什么是AI Agent?"}])
print(f"响应: {resp.content}")
print(f"Token: {resp.usage.total_tokens}, 耗时: {resp.latency_ms:.1f}ms")
llm2 = UnifiedLLM(Provider.OPENAI)
resp2 = llm2.chat([{"role": "user", "content": "Python是什么?"}])
print(f"响应(OpenAI): {resp2.content}")
print(f"统计: {llm.get_stats()}")
三种策略:指数退避重试等待时间递增、切换到备用Provider、请求速率限制用令牌桶算法控制调用频率。OpenAI的RPM/TPM限制需特别关注。
经验法则:代码生成/数据提取用0.0-0.2,对话/翻译用0.3-0.7,创意写作/头脑风暴用0.8-1.2。Temperature越低输出越确定,越高越多样但可能失准。
用户交互场景用流式(体验好可提前中断),批处理/工具调用场景用非流式(拿到完整结果再处理)。流式输出token统计可能不精确。
四大策略:压缩System Prompt去除冗余、使用更短的模型如GPT-4o-mini、缓存重复的Prompt前缀、合理设置max_tokens避免生成过长回复。
设计格言:LLM API调用的核心不在于技术复杂度,而在于能否可靠地解决实际问题。简单且可靠远胜于复杂但不稳定。
从.env文件加载API Key、多模型切换、速率限制配置
实现stream=True的流式API:逐token输出、实时显示进度、支持中断
估算输入token数、预测API调用成本、优化prompt减少token消耗