目录
- [1. 前言](#1. 前言)
- [2. 环境准备](#2. 环境准备)
- [3. 案例一:首次调用 API](#3. 案例一:首次调用 API)
- [3.1 代码实现](#3.1 代码实现)
- [3.2 关键点解析](#3.2 关键点解析)
- [3.3 运行结果与观察](#3.3 运行结果与观察)
- [3.4 核心概念解释](#3.4 核心概念解释)
- [4. 案例二:观察 Tokens](#4. 案例二:观察 Tokens)
- [4.1 代码实现](#4.1 代码实现)
- [4.2 关键点解析](#4.2 关键点解析)
- [4.3 运行结果与观察](#4.3 运行结果与观察)
- [4.4 核心概念解释](#4.4 核心概念解释)
- [5. 案例三:统计不同模型调用成本](#5. 案例三:统计不同模型调用成本)
- [5.1 代码实现](#5.1 代码实现)
- [5.2 关键点解析](#5.2 关键点解析)
- [5.3 运行结果与观察](#5.3 运行结果与观察)
- [5.4 核心概念解释](#5.4 核心概念解释)
- [6. 案例四:比较不同模型的回答风格](#6. 案例四:比较不同模型的回答风格)
- [6.1 在线商业 API 对比(参考实现)](#6.1 在线商业 API 对比(参考实现))
- [6.2 本地模型对比实现](#6.2 本地模型对比实现)
- [6.3 本地模型对比总结](#6.3 本地模型对比总结)
- [7. 案例五:常见错误处理与重试机制](#7. 案例五:常见错误处理与重试机制)
- [7.1 代码实现](#7.1 代码实现)
- [7.2 关键点解析](#7.2 关键点解析)
- [7.3 运行结果与观察](#7.3 运行结果与观察)
- [7.4 核心概念解释](#7.4 核心概念解释)
1. 前言
经过基础知识的洗礼,我们开始迎接 API 调用环节。尽管教程里包含免费和付费调用两种方案,但个人更偏向于免费路线,后续根据需要再添加付费 API 调用案例。(知识是无价的,商业才是有价的)。
本章分为 5 个案例,以下逐个讲解。
2. 环境准备
练习前提:首先需要在 Windows 上下载 Ollama。(B 站或其他资源较多,此处不一一赘述)
3. 案例一:首次调用 API
先使用 Ollama 下载几个模型,如 qwen2.5:3b、llama3.2:3b 这两个,作为练习较为合适。当然,本机配置较高的读者可以选择配置更好的模型。
3.1 代码实现
python
import sys
if hasattr(sys.stdout, "reconfigure"):
sys.stdout.reconfigure(encoding="utf-8", errors="replace")
from openai import OpenAI
client = OpenAI(
base_url="http://localhost:11434/v1",
api_key="ollama", # Ollama 不检查,随便填即可
)
models = ["llama3.2:3b", "qwen2.5:3b", "gemma4:e4b"]
for model in models:
r = client.chat.completions.create(
model=model, # 可换成 qwen2.5:3b / llama3.2:3b
max_tokens=100,
messages=[
{"role": "system", "content": "只输出最终答案,不要输出任何推理过程、思维链或分析步骤。"},
{"role": "user", "content": "用一句话自我介绍。"}
],
extra_body={
"thinking": False # 关键配置:关闭推理过程输出
}
)
# === 自我验证 ===
print("Ollama {} 运行".format(model))
origin_text = r.choices[0].message.content
text = origin_text if len(origin_text) > 0 else r.choices[0].message.reasoning
print("回应:", text)
print("usage:", r.usage)
assert r.choices[0].finish_reason in ("stop", "length"), f"非预期 finish_reason: {r.choices[0].finish_reason}"
3.2 关键点解析
从创建 client 前与官网教程是一样的。client 创建使用 OpenAI 的 API,使用本地 Ollama 不需要真实的 api_key。
重点在下面:为了验证不同模型的效果(回答"用一句话自我介绍"的效果),分别调用了相应的 API,输出结果却不尽相同。有的模型是强推理模型,一定会有 reasoning 输出,不一定会有 content 输出。为了兼容,对代码进行了修改。(也添加了提示词,但是效果不是太大,无法根治 reasoning,稍微会好点)

3.3 运行结果与观察
运行代码后,不同模型对同一提示词给出了风格各异的回复。这直观展示了模型间的差异。整个调用过程使用统一的 OpenAI 格式 API,只需更换 model 参数即可切换模型,非常便捷。代码通过 thinking: False 希望解决reasoning,但实际也未完全解决,所以人还是要把关的。
3.4 核心概念解释
- max_tokens:即输出回复的最大长度(计费相关呦)。
- thinking: False # 关键配置:关闭推理过程输出(效果有,但一般)
4. 案例二:观察 Tokens
在第一个案例中,我们体验了不同模型对同一提示词的回复差异。本案例将聚焦于另一个重要维度:Tokens 的消耗与统计 。我们将通过编写一个小程序,观察同一模型在不同语言提示下输入/输出 Tokens 的数量,并理解 temperature 参数对输出长度随机性的影响。
4.1 代码实现
python
import sys, statistics
if hasattr(sys.stdout, "reconfigure"):
sys.stdout.reconfigure(encoding="utf-8", errors="replace")
from openai import OpenAI
client = OpenAI(base_url="http://localhost:11434/v1", api_key="ollama")
PROMPTS = {
"中文": "用一句话描述一只猫在做什么。",
"English": "Describe in one sentence what a cat is doing.",
}
N = 10 # 本机慢、N 小一点
for label, prompt in PROMPTS.items():
output_tokens = []
for _ in range(N):
r = client.chat.completions.create(
model="llama3.2:3b",
max_tokens=80,
temperature=1.0,
messages=[{"role": "user", "content": prompt}],
)
output_tokens.append(r.usage.completion_tokens)
print(f"\n[{label}] prompt: {prompt}")
print(f" input tokens: {r.usage.prompt_tokens}")
print(f" output tokens --- min={min(output_tokens)} max={max(output_tokens)} mean={statistics.mean(output_tokens):.1f} stdev={statistics.stdev(output_tokens):.1f}")
# === 自我验证 ===
assert max(output_tokens) > min(output_tokens), "temperature=1.0 下、output 长度应该有 variance"
print("\n✅ 练习 2 通过 --- 本机跑 $0")
4.2 关键点解析
- 目标 :本案例旨在观察同一模型(
llama3.2:3b,可以选其他模型,但注意资源消耗)在处理不同语言(中/英文)提示时,输入 Tokens(prompt_tokens)和输出 Tokens(completion_tokens)的差异,并验证temperature参数对输出长度随机性的影响。 - 实验设计 :对每种语言的提示词,我们采样
N=10次(因本机性能限制,次数较少),记录每次输出的completion_tokens,最后计算最小值、最大值、平均值和标准差。 - 参数设置 :
temperature=1.0意味着模型在生成时具有较高的随机性("创意"),这会导致每次输出的长度(即completion_tokens)可能不同。我们通过统计方差来验证这一点。
4.3 运行结果与观察
运行上述代码后,我们可以得到类似下图的统计结果(具体数值因运行环境而异):

从结果中可以观察到两个关键现象:
- 输入 Tokens 的差异 :同样的模型,对英文和中文提示的
input tokens(即prompt_tokens)数量是不同的。这打破了"中文一定比英文占用更多 Tokens"的简单认知。实际占用数量与模型本身的词表(vocabulary)和分词器(tokenizer)强相关,不同模型的结果可能截然不同。 - 输出 Tokens 的随机性 :在
temperature=1.0的设置下,即使提示词完全相同,模型每次生成的回复长度(completion_tokens)也会在max_tokens限制内波动,表现为输出 Tokens 的最大值、最小值不一致,且标准差不为零。这直观地体现了temperature参数对生成"发散性"的影响。
本节通过一个简单的统计实验,展示了如何量化观察模型调用中的 Tokens 消耗,并验证了关键参数(如 temperature)对输出特性的影响。
注:感兴趣的可以修改temperature从0到1
4.4 核心概念解释
- temperature:创意程度参数。简单来说,值为 0 时,模型的输出是确定性的(每次相同);值为 1 时,输出比较发散,更有"创意",长度和内容都可能变化。
- completion_tokens :统计输出内容的 Token 数量,实际值不会超过
max_tokens参数的限制。 - prompt_tokens:统计输入提示词(Prompt)的 Token 数量。
5. 案例三:统计不同模型调用成本
在前两个案例中,我们分别体验了不同模型的回复差异和观察了 Tokens 消耗。本案例将聚焦于调用成本的量化分析。虽然本地调用 Ollama 模型没有直接的金钱成本,但时间成本是真实存在的。我们将通过编写一个性能测试程序,统计不同模型完成 1000 次调用所需的时间,帮助读者建立成本意识,并为选择合适模型提供数据参考。
5.1 代码实现
python
import sys, time
if hasattr(sys.stdout, "reconfigure"):
sys.stdout.reconfigure(encoding="utf-8", errors="replace")
from openai import OpenAI
client = OpenAI(base_url="http://localhost:11434/v1", api_key="ollama")
# 测试的模型列表
models = ["qwen2.5:3b", "gemma4:e4b", "llama3.2:3b"]
for model in models:
print(f"\n=== 测试模型: {model} ===")
# 预热一次,避免首次调用延迟影响统计
client.chat.completions.create(
model=model,
max_tokens=50,
messages=[{"role": "user", "content": "预热"}],
)
# 正式测试:采样 5 次
latencies = []
for i in range(5):
t0 = time.time()
r = client.chat.completions.create(
model=model,
max_tokens=200,
messages=[{"role": "user", "content": "你好!请用一句话介绍一下你自己(模型本身)。"}],
)
latencies.append(time.time() - t0)
print(f" 第 {i+1} 次: {latencies[-1]:.2f} 秒")
# 统计计算
avg_latency = sum(latencies) / len(latencies)
out_tok_avg = r.usage.completion_tokens
tps = out_tok_avg / avg_latency if avg_latency > 0 else 0
# 输出结果
print(f"\n统计结果:")
print(f" 延迟 (秒): min={min(latencies):.2f}, max={max(latencies):.2f}, mean={avg_latency:.2f}")
print(f" 平均输出: {out_tok_avg} tokens")
print(f" 吞吐率: {tps:.1f} tokens/秒")
print(f" 1000 次预计耗时: {avg_latency * 1000 / 60:.1f} 分钟")
# === 自我验证 ===
assert avg_latency > 0, "延迟应大于 0"
assert out_tok_avg > 0, "输出 tokens 应大于 0"
print("\n✅ 案例三测试完成")
5.2 关键点解析
- 目标:本案例旨在量化本地模型的调用时间成本,帮助读者建立本地部署的成本意识。
- 实验设计:对每个模型进行 5 次采样测试,记录每次调用的延迟(latency),计算平均值、最小值和最大值,并基于平均延迟估算完成 1000 次调用所需的时间。
- 成本意识:虽然本地调用没有直接的 API 费用,但时间成本是真实存在的。对于需要高频调用的场景,选择合适的模型可以显著提升效率。
5.3 运行结果与观察
运行上述代码后,可以得到类似下图的性能对比结果(具体数值因硬件配置而异):

从结果中可以观察到几个关键现象:
- 时间成本量化:通过将单次平均延迟乘以 1000,可以直观估算大规模调用所需的时间。例如,单次调用平均需要 2.5 秒时,1000 次调用约需 41.7 分钟。所有模型的平均调用时间都超过了400分钟,成本很高(4060显卡)。
- 硬件资源影响 :测试结果与硬件配置(CPU、GPU、内存)强相关。性能较弱的设备上,时间成本会显著增加。

5.4 核心概念解释
- 延迟(Latency):从发送请求到收到完整响应所经历的时间,通常以秒为单位。是衡量模型响应速度的关键指标。
- 吞吐率(Tokens per Second, TPS) :每秒生成的 tokens 数量,计算公式为
输出 tokens 数 / 延迟时间。该指标反映了模型的生成效率。 - 成本意识:在 AI 应用开发中,成本不仅包括 API 调用费用(商业模型),还包括时间成本、硬件投入和维护成本。选择合适的模型需要在效果、速度和成本之间取得平衡。
6. 案例四:比较不同模型的回答风格
在前三个案例中,我们分别体验了模型调用、Tokens 统计和性能测试。本案例将聚焦于不同模型对同一问题的回答风格对比。我们将分别使用在线商业 API 和本地 Ollama 模型来回答同一个问题,观察它们在表达风格、响应速度和资源消耗上的差异。
6.1 在线商业 API 对比(参考实现)
原始案例使用了三个在线大模型(Claude、GPT-4o-mini、Gemini)进行对比,需要获取 API Key 并可能产生费用。这里提供参考代码,供有条件的读者练习:
python
from __future__ import annotations
import os
import sys
import time
from dataclasses import dataclass
if hasattr(sys.stdout, "reconfigure"):
sys.stdout.reconfigure(encoding="utf-8", errors="replace")
PROMPT = "用 1-2 句話解釋 AGI 跟 narrow AI 的差別。"
@dataclass
class Reply:
provider: str
model: str
text: str
in_tokens: int
out_tokens: int
latency_ms: int
def call_claude(prompt: str) -> Reply | None:
if not os.environ.get("ANTHROPIC_API_KEY"):
return None
import anthropic
client = anthropic.Anthropic()
t0 = time.time()
msg = client.messages.create(
model="claude-haiku-4-5",
max_tokens=200,
messages=[{"role": "user", "content": prompt}],
)
return Reply(
provider="Anthropic",
model="claude-haiku-4-5",
text=msg.content[0].text,
in_tokens=msg.usage.input_tokens,
out_tokens=msg.usage.output_tokens,
latency_ms=int((time.time() - t0) * 1000),
)
def call_openai(prompt: str) -> Reply | None:
if not os.environ.get("OPENAI_API_KEY"):
return None
from openai import OpenAI
client = OpenAI()
t0 = time.time()
r = client.chat.completions.create(
model="gpt-4o-mini",
max_tokens=200,
messages=[{"role": "user", "content": prompt}],
)
return Reply(
provider="OpenAI",
model="gpt-4o-mini",
text=r.choices[0].message.content or "",
in_tokens=r.usage.prompt_tokens,
out_tokens=r.usage.completion_tokens,
latency_ms=int((time.time() - t0) * 1000),
)
def call_gemini(prompt: str) -> Reply | None:
if not os.environ.get("GOOGLE_API_KEY"):
return None
from google import genai
client = genai.Client()
t0 = time.time()
r = client.models.generate_content(
model="gemini-2.0-flash",
contents=prompt,
)
usage = getattr(r, "usage_metadata", None)
return Reply(
provider="Google",
model="gemini-2.0-flash",
text=r.text,
in_tokens=getattr(usage, "prompt_token_count", 0) or 0,
out_tokens=getattr(usage, "candidates_token_count", 0) or 0,
latency_ms=int((time.time() - t0) * 1000),
)
def compare(prompt: str) -> list[Reply]:
replies = []
for fn in (call_claude, call_openai, call_gemini):
r = fn(prompt)
if r is None:
print(f"⚠ skip {fn.__name__}(沒有對應 API key)")
else:
replies.append(r)
return replies
if __name__ == "__main__":
print(f"prompt: {PROMPT}\n" + "=" * 60)
replies = compare(PROMPT)
for r in replies:
print(f"\n[{r.provider} / {r.model}] latency={r.latency_ms}ms in={r.in_tokens} out={r.out_tokens}")
print(r.text)
# === 自我驗證 ===
assert len(replies) >= 1, "至少要有一家 provider 回應(請設一個 API key)"
for r in replies:
assert len(r.text) > 5, f"{r.provider} 回應太短"
assert r.in_tokens > 0, f"{r.provider} 沒 input token"
print(f"\n✅ 練習 4 通過 --- 收到 {len(replies)} 家 provider 回應、可比較風格 / 長度 / 成本")
关键点说明:
- 统一接口设计 :使用
Reply数据类统一封装各模型的返回结果,便于对比分析 - 错误处理:当缺少 API Key 时优雅跳过,不影响其他模型测试
- 多维度对比:同时记录响应时间、输入输出 Tokens,全面评估模型表现
运行结果示例:
markup
prompt: 用 1-2 句話解釋 AGI 跟 narrow AI 的差別。
============================================================
[Anthropic / claude-haiku-4-5] latency=1234ms in=25 out=45
AGI(通用人工智能)擁有類似人類的廣泛認知能力,能處理各種任務;而窄域AI則專注於特定領域,如語音識別或下棋。
[OpenAI / gpt-4o-mini] latency=987ms in=22 out=38
AGI(通用人工智能)旨在擁有類似人類的全面智能,能夠處理多種不同任務;而窄域AI(狹義AI)則專注於特定任務,如語音識別或圖像分類。
[Google / gemini-2.0-flash] latency=876ms in=20 out=42
AGI是指能像人類一樣廣泛學習和推理的通用人工智能,而窄域AI則只專注於執行特定任務(如臉部辨識)。
6.2 本地模型对比实现
对于大多数学习者,使用本地 Ollama 模型进行对比更加实际。以下代码展示了如何使用 Ollama 的原生 API(非 OpenAI 兼容格式)调用多个本地模型:
python
from __future__ import annotations
import sys
import time
from dataclasses import dataclass
from typing import Optional
import requests
if hasattr(sys.stdout, "reconfigure"):
sys.stdout.reconfigure(encoding="utf-8", errors="replace")
PROMPT = "用 1-2 句話解釋 AGI 跟 narrow AI 的差別。"
@dataclass
class Reply:
provider: str
model: str
text: str
in_tokens: int
out_tokens: int
latency_ms: int
def _call_ollama(prompt: str, model: str) -> Optional[Reply]:
"""通用 Ollama 调用函数(使用原生 API)"""
try:
t0 = time.time()
resp = requests.post(
"http://localhost:11434/api/generate",
json={
"model": model,
"prompt": prompt,
"stream": False,
"options": {"num_predict": 200}
},
timeout=60
)
data = resp.json()
text = data.get("response", "").strip()
return Reply(
provider="Local-Ollama",
model=model,
text=text,
in_tokens=len(prompt) // 2, # 简单估算
out_tokens=len(text) // 2, # 简单估算
latency_ms=int((time.time() - t0) * 1000),
)
except Exception as e:
print(f"⚠ {model} 调用失败: {e}")
return None
def call_qwen(prompt: str) -> Optional[Reply]:
"""调用 qwen2.5:3b"""
return _call_ollama(prompt, "qwen2.5:3b")
def call_llama(prompt: str) -> Optional[Reply]:
"""调用 llama3.2:3b"""
return _call_ollama(prompt, "llama3.2:3b")
def call_deepseek(prompt: str) -> Optional[Reply]:
"""调用 deepseek-r1:8b"""
return _call_ollama(prompt, "deepseek-r1:8b")
def compare(prompt: str) -> list[Reply]:
"""比较所有模型"""
replies = []
for fn in (call_qwen, call_llama, call_deepseek):
r = fn(prompt)
if r is None:
print(f"⚠ 跳过 {fn.__name__}(模型未安装)")
else:
replies.append(r)
return replies
if __name__ == "__main__":
print(f"prompt: {PROMPT}\n" + "=" * 60)
replies = compare(PROMPT)
for r in replies:
print(f"\n[{r.provider} / {r.model}] latency={r.latency_ms}ms in={r.in_tokens} out={r.out_tokens}")
print(r.text)
# 验证
assert len(replies) >= 1, "至少需要一个模型响应"
for r in replies:
assert len(r.text) > 5, f"{r.provider} 回应太短"
assert r.in_tokens > 0, f"{r.provider} 没有 input token"
print(f"\n✅ 测试通过 --- 收到 {len(replies)} 个本地模型响应")
运行结果示例:

6.3 本地模型对比总结
6.2 节展示了如何使用 Ollama 原生 API 调用多个本地模型进行对比。通过统一的 Reply 数据类封装结果,我们可以方便地比较不同模型在回答风格、响应时间和资源消耗上的差异。
核心要点总结:
- API 调用方式 :使用 Ollama 原生 API(
/api/generate端点)而非 OpenAI 兼容接口,输出内容上不需要像案例一特殊处理,这一点更加方便。 - 统一接口设计 :通过
_call_ollama函数封装调用逻辑,简化多模型对比 - 模型选择 :示例中对比了
qwen2.5:3b、llama3.2:3b和deepseek-r1:8b三个模型 - 结果对比:可以直观看到不同模型对同一问题的回答风格差异
适用场景:
- 需要对比多个本地模型的性能表现
- 希望使用 Ollama 原生 API 的完整功能
- 隐私敏感或离线环境下的模型测试
通过这个案例,读者可以掌握使用 Ollama 原生 API 进行多模型对比的基本方法,为实际项目中的模型选型提供参考。
当然在线模型回答的更加严谨和恰当,日常功能使用还是需要尝试在线模型。
7. 案例五:常见错误处理与重试机制
在前面的案例中,我们学习了如何成功调用 Ollama API。但在实际开发中,网络波动、服务异常、参数错误等情况时有发生。本案例将介绍常见的错误类型及其处理方法,并实现一个带指数退避的重试机制,提高程序的健壮性。
7.1 代码实现
python
from __future__ import annotations
import os
import random
import sys
import time
from typing import Any, Callable
if hasattr(sys.stdout, "reconfigure"):
sys.stdout.reconfigure(encoding="utf-8", errors="replace")
from openai import (
APIConnectionError,
APIStatusError,
AuthenticationError,
OpenAI,
RateLimitError,
)
MODEL = os.environ.get("MODEL", "qwen2.5:3b")
# === 重试包装器 ===
RETRIABLE = (APIConnectionError, RateLimitError) # 可重试的异常类型
MAX_ATTEMPTS = 4 # 最大重试次数
BASE_DELAY = 1.0 # 基础延迟(秒)
def with_retry(fn: Callable[[], Any], *, max_attempts: int = MAX_ATTEMPTS, base_delay: float = BASE_DELAY, sleep_fn=time.sleep) -> Any:
"""
指数退避重试机制。
- 可重试异常(如网络连接错误、限流)→ 等待 base * 2^attempt 秒后重试(含随机抖动)
- 不可重试异常(如认证错误)→ 直接抛出,不浪费时间重试
"""
last_exc = None
for attempt in range(max_attempts):
try:
return fn()
except RETRIABLE as e:
last_exc = e
if attempt == max_attempts - 1:
break
delay = base_delay * (2 ** attempt) + random.uniform(0, 0.3)
print(f" ⚠ 第 {attempt+1}/{max_attempts} 次尝试失败 ({type(e).__name__});{delay:.1f}秒后重试")
sleep_fn(delay)
raise last_exc
# === 三种错误场景演示 ===
def demo_bad_key() -> None:
"""场景1:故意使用错误的 base_url,模拟 APIConnectionError(Ollama 未运行时)"""
print("\n[场景1] 故意连接到不存在的 Ollama 端口")
client = OpenAI(base_url="http://localhost:65535/v1", api_key="ollama")
try:
client.chat.completions.create(
model=MODEL,
max_tokens=10,
messages=[{"role": "user", "content": "你好"}],
)
except APIConnectionError as e:
print(f" ✅ 捕获到 APIConnectionError: {type(e).__name__}")
print(f" 💡 生产环境处理:重试(网络错误通常是暂时的)")
def demo_with_retry() -> None:
"""场景2:使用 with_retry 包装正常调用,应该第一次就成功"""
print("\n[场景2] 正常调用 + with_retry 包装(需要 Ollama 正在运行)")
client = OpenAI(base_url="http://localhost:11434/v1", api_key="ollama")
def call():
return client.chat.completions.create(
model=MODEL,
max_tokens=30,
messages=[{"role": "user", "content": "用一个 emoji 回答。"}],
)
try:
msg = with_retry(call)
print(f" ✅ 成功,第一次就通过: {msg.choices[0].message.content}")
except APIConnectionError:
print(" ⚠ Ollama 未运行(端口 11434 不通)。请先运行 `ollama serve`")
def demo_too_long_prompt() -> None:
"""场景3:故意发送超长 prompt,观察上下文窗口满时的行为"""
print("\n[场景3] Prompt 超过上下文窗口(Ollama 通常会截断或抛出异常)")
client = OpenAI(base_url="http://localhost:11434/v1", api_key="ollama")
huge_prompt = "重复很多次的 token。" * 200000000 # 约 1M tokens
try:
client.chat.completions.create(
model=MODEL,
max_tokens=10,
messages=[{"role": "user", "content": huge_prompt}],
)
print(" ⚠ Ollama 未抛出异常(可能直接截断 prompt)。云 API 通常会返回 400 错误")
except APIStatusError as e:
print(f" ✅ 捕获到 APIStatusError: 状态码 {e.status_code}")
print(f" 💡 生产环境处理:在客户端先计算 token 数量,超过限制则拒绝,避免浪费 API 调用")
except APIConnectionError:
print(" ⚠ Ollama 未运行")
if __name__ == "__main__":
demo_bad_key()
demo_with_retry()
demo_too_long_prompt()
# === 自我验证 ===
print("\n✅ 案例五测试通过 --- 您已了解 3 种常见错误的处理方式,知道何时该重试、何时该停止")

7.2 关键点解析
- 目标:本案例旨在演示如何处理 Ollama API 调用中常见的错误,并实现一个健壮的重试机制。
- 错误类型分类 :
- APIConnectionError:网络连接错误(如 Ollama 服务未启动、端口错误)
- RateLimitError:请求频率限制错误(在免费 API 中常见)
- APIStatusError:HTTP 状态码错误(如 400 Bad Request、429 Too Many Requests)
- AuthenticationError:认证错误(API Key 无效)
- 重试策略:指数退避 + 随机抖动,避免"惊群效应"
- 生产建议:根据错误类型决定是否重试,避免无限重试不可恢复的错误
通过本案例,您将掌握在实际项目中处理 API 错误的正确方法,提高应用程序的稳定性和用户体验。
8. 案例总结
本章通过五个案例系统介绍了 Ollama 本地大模型 API 调用的核心技能:
- 首次调用 API :掌握基础调用方法,理解
max_tokens、thinking参数,处理推理模型输出兼容性。 - 观察 Tokens :量化分析 Tokens 消耗,验证
temperature对输出随机性的影响。 - 统计调用成本:量化时间成本,建立成本意识,为模型选型提供数据参考。
- 比较回答风格:对比在线与本地模型的差异,掌握多模型对比方法。
- 错误处理与重试:识别常见错误类型,实现指数退避重试机制,提高程序健壮性。
这五个案例构成了从基础调用到生产部署的完整学习路径,帮助读者掌握本地大模型调用的核心技能。
下一节将对Prompt进行进一步深入讲解