基于pytest的Ollama大模型API自动化测试框架设计与实践
1. 项目概述:为什么我们需要一个集成Ollama的API自动化测试框架?
最近在折腾大模型应用的后端开发,发现一个挺头疼的问题:每次迭代模型或者调整提示词(Prompt),都得手动去调用接口、检查返回结果,不仅效率低,还容易遗漏一些边界情况。特别是当我们把像Ollama这样的本地大模型服务集成到业务流里,测试就变得更复杂了。它不像传统的REST API返回固定的JSON结构,大模型的输出是开放式的文本,充满了不确定性。一个标点符号的改变、一个词语的替换,都可能影响下游业务逻辑的正确性。
这就是“Ollama集成测试框架”这个项目要解决的核心痛点。它不是一个从零造轮子的宏大工程,而是基于成熟的Python测试生态(主要是 pytest ),构建一套专门用于验证与大模型API交互的自动化测试方案。简单说,就是写一段脚本,能自动调用Ollama的API,然后智能地判断返回的文本是否符合我们的预期,比如是否包含了关键信息、是否遵循了指定的格式、情感倾向是否正确等等。
对于开发者、测试工程师或者任何需要确保AI应用输出稳定可靠的人来说,这套框架能带来几个实实在在的好处: 提升回归测试效率 ,每次代码或模型更新,一键运行所有测试用例; 保障输出质量 ,通过预设的断言规则,确保模型输出不会“跑偏”; 实现持续集成 ,可以轻松接入Jenkins、GitHub Actions等CI/CD流程,让测试成为开发环节中自然的一环。
2. 框架整体设计与核心思路拆解
2.1 核心需求与挑战分析
在动手搭建之前,我们先得想清楚要测什么,以及难点在哪。集成Ollama的API测试,主要关注以下几个层面:
- 基础连通性测试 :Ollama服务是否正常启动?API端点(通常是
http://localhost:11434/api/generate)能否访问?这是所有测试的基石。 - 功能正确性测试 :给定一个输入(Prompt),模型返回的文本内容是否满足业务要求?例如,让模型总结一段话,它是否真的给出了摘要,而不是复述原文?
- 性能与稳定性测试 :API的响应时间是否在可接受范围内?长时间、高并发调用下,服务是否会崩溃或产生严重延迟?
- 输出格式与结构测试 :对于需要结构化输出的场景(比如让模型生成JSON),返回的内容是否能被正确解析?字段是否齐全?
- 非确定性输出的验证 :这是最大的挑战。大模型的输出每次可能略有不同。我们不能简单地断言返回字符串完全等于某个值,而是需要更灵活的验证策略,如关键词匹配、正则表达式、语义相似度判断等。
基于这些需求,我们的框架设计思路就很明确了: 以 pytest 为骨架,以 requests 或 httpx 为HTTP客户端,封装针对Ollama API的调用,并设计一套丰富的“断言器”来应对非确定性输出。
2.2 技术栈选型与理由
为什么选这些工具?这里有个人的一些考量:
- 测试框架:pytest 。这是Python社区的事实标准。它比
unittest更简洁灵活,夹具(fixture)机制非常适合管理测试资源(如Ollama客户端连接),丰富的插件生态(如pytest-html生成报告,pytest-xdist并行测试)能极大提升测试体验。 - HTTP客户端:httpx 。虽然
requests足够经典,但我更倾向于httpx。它兼容requests的API,上手无门槛,同时原生支持异步HTTP请求。在跑大量测试用例或性能测试时,异步能力能显著缩短总耗时。对于同步需求,它的用法和requests几乎一样。 - 断言与验证库:综合使用 。
pytest内置的assert语句,用于基础判断。- 正则表达式 (
re) :用于验证输出是否匹配某种模式,例如日期格式、电话号码等。 - 第三方库:
deepdiff:用于复杂JSON结构的对比,可以忽略一些无关紧要的差异(如空格、字段顺序)。 - 语义相似度:
sentence-transformers或openai的Embedding API :这是应对非确定性输出的“大招”。通过计算生成文本与预期文本在向量空间中的余弦相似度,来判断它们的意思是否相近。虽然会引入额外依赖和计算开销,但对于关键场景的验证非常有效。
- 配置管理:pydantic + dotenv 。用
pydantic的BaseSettings来定义和管理测试配置(如Ollama服务地址、默认模型、超时时间),通过.env文件区分不同环境(开发、测试、生产),保证测试的灵活性和安全性。 - 测试数据管理:JSON/YAML文件 。将测试用例(输入Prompt、预期输出关键词、断言规则等)与测试脚本分离,存储在外部文件中。这样非技术人员也能参与维护测试用例,且便于进行数据驱动的测试。
注意 :选择
sentence-transformers进行本地语义相似度计算时,需要下载模型文件(如all-MiniLM-L6-v2),首次使用可能较慢。如果网络环境允许,使用OpenAI等在线API可能更方便,但会带来成本和网络依赖。
3. 核心细节解析与实操要点
3.1 Ollama API调用封装
直接在每个测试用例里写 requests.post(...) 会很冗余,且不利于维护。我们需要一个统一的客户端封装。
# core/ollama_client.py
import httpx
from pydantic import BaseModel, Field
from typing import Optional, Dict, Any
import logging
logger = logging.getLogger(__name__)
class OllamaGenerateRequest(BaseModel):
"""匹配Ollama /api/generate 接口的请求体"""
model: str
prompt: str
stream: bool = False
options: Optional[Dict[str, Any]] = None
class OllamaClient:
def __init__(self, base_url: str = "http://localhost:11434", timeout: float = 30.0):
self.base_url = base_url.rstrip('/')
self.timeout = timeout
self.client = httpx.AsyncClient(timeout=timeout) # 使用异步客户端
async def generate(self, request: OllamaGenerateRequest) -> str:
"""调用生成接口,返回完整的响应文本"""
url = f"{self.base_url}/api/generate"
try:
# 注意:Ollama API 期望的是JSON body
response = await self.client.post(url, json=request.dict())
response.raise_for_status() # 状态码非2xx会抛出异常
result = response.json()
# 响应结构:{"model":"xx","response":"...","done":true}
return result.get("response", "").strip()
except httpx.HTTPStatusError as e:
logger.error(f"API请求失败,状态码:{e.response.status_code}, 响应:{e.response.text}")
raise
except httpx.RequestError as e:
logger.error(f"网络请求错误:{e}")
raise
except KeyError:
logger.error("API响应格式异常,未找到'response'字段")
raise
async def close(self):
"""关闭客户端连接"""
await self.client.aclose()
# 同步版本的简化封装(如果不需要异步)
class SyncOllamaClient:
def __init__(self, base_url: str = "http://localhost:11434"):
self.base_url = base_url
def generate_sync(self, model: str, prompt: str) -> str:
import requests
url = f"{self.base_url}/api/generate"
resp = requests.post(url, json={"model": model, "prompt": prompt, "stream": False})
resp.raise_for_status()
return resp.json().get("response", "").strip()
封装要点解析 :
- 使用Pydantic模型定义请求体 :这提供了类型提示和自动验证,确保我们发送的数据结构是正确的。
OllamaGenerateRequest类清晰地定义了必填和可选字段。 - 统一错误处理 :通过
raise_for_status()和try-except块,将HTTP错误、网络错误和响应格式错误统一捕获并记录日志,便于测试失败时排查。 - 支持异步 :主客户端使用了
httpx.AsyncClient,为后续性能测试或批量测试留出空间。同时提供了一个同步版本备用。 - 提取核心响应 :方法最终返回清洗过的
response文本,方便测试断言直接使用。
3.2 灵活断言器的设计与实现
这是框架的“大脑”。我们需要设计多种断言方式,来应对不同的验证场景。
# core/assertions.py
import re
import json
from typing import List, Union, Pattern
from deepdiff import DeepDiff
class OllamaResponseAssertor:
"""Ollama API响应断言器"""
@staticmethod
def assert_contains(response_text: str, keywords: Union[str, List[str]]):
"""断言响应中包含特定关键词或短语"""
if isinstance(keywords, str):
keywords = [keywords]
for kw in keywords:
assert kw in response_text, f"响应中未找到关键词:'{kw}'。实际响应:{response_text[:200]}..."
@staticmethod
def assert_not_contains(response_text: str, forbidden_words: Union[str, List[str]]):
"""断言响应中不包含禁忌词"""
if isinstance(forbidden_words, str):
forbidden_words = [forbidden_words]
for word in forbidden_words:
assert word not in response_text, f"响应中包含禁忌词:'{word}'。"
@staticmethod
def assert_matches_pattern(response_text: str, pattern: Union[str, Pattern]):
"""使用正则表达式断言响应格式"""
if isinstance(pattern, str):
pattern = re.compile(pattern)
assert pattern.search(response_text) is not None, f"响应不匹配模式:{pattern.pattern}"
@staticmethod
def assert_valid_json(response_text: str):
"""断言响应是可解析的JSON字符串"""
try:
json.loads(response_text)
except json.JSONDecodeError as e:
raise AssertionError(f"响应不是有效的JSON:{e}")
@staticmethod
def assert_json_schema(response_text: str, expected_schema: dict, ignore_order: bool = True):
"""断言JSON响应与预期结构匹配(使用deepdiff进行深度比较)"""
try:
actual_json = json.loads(response_text)
except json.JSONDecodeError:
raise AssertionError("响应不是有效的JSON,无法进行结构比较")
diff = DeepDiff(actual_json, expected_schema, ignore_order=ignore_order)
assert not diff, f"JSON结构不匹配,差异:{diff}"
@staticmethod
def assert_semantic_similarity(response_text: str, expected_text: str, threshold: float = 0.8):
"""断言响应与预期文本的语义相似度高于阈值(需要额外依赖)"""
# 这里以sentence-transformers为例
try:
from sentence_transformers import SentenceTransformer, util
# 建议将模型加载移到类外部或使用缓存,避免每次断言都加载
model = SentenceTransformer('all-MiniLM-L6-v2')
emb1 = model.encode(response_text, convert_to_tensor=True)
emb2 = model.encode(expected_text, convert_to_tensor=True)
cosine_score = util.cos_sim(emb1, emb2).item()
assert cosine_score >= threshold, f"语义相似度{cosine_score:.3f}低于阈值{threshold}"
except ImportError:
raise RuntimeError("语义相似度断言需要安装 `sentence-transformers` 库。")
断言器设计心得 :
- 静态方法 :设计成静态方法,无需实例化即可使用,非常方便。例如
OllamaResponseAssertor.assert_contains(response, “答案”)。 - 渐进式复杂度 :从简单的字符串包含(
assert_contains)到复杂的语义相似度(assert_semantic_similarity),提供不同粒度的验证工具。测试用例可以根据需要组合使用。 - 语义相似度断言慎用 :这是一个“重武器”。虽然强大,但计算开销大,且相似度阈值
threshold需要根据具体任务反复调试确定(例如,摘要任务可能要求0.85,而创意写作0.7可能就够了)。建议只在关键用例中使用,并考虑缓存模型。 - 清晰的错误信息 :每个断言失败时,都输出包含上下文的具体错误信息,而不是简单的
AssertionError,这能极大加速调试过程。
4. 实操过程:构建并运行你的第一个测试套件
4.1 项目结构与配置
让我们从一个完整的项目示例开始。假设项目目录结构如下:
ollama_api_test_framework/
├── .env # 环境变量配置
├── conftest.py # pytest全局配置和fixture
├── requirements.txt # 项目依赖
├── config/
│ └── settings.py # 配置管理
├── core/
│ ├── __init__.py
│ ├── ollama_client.py # 封装的客户端
│ └── assertions.py # 断言器
├── test_data/
│ └── test_cases.yaml # 数据驱动的测试用例
└── tests/
├── __init__.py
├── test_connectivity.py # 基础连通性测试
└── test_functional.py # 功能测试
首先,配置环境变量和设置。
# config/settings.py
from pydantic_settings import BaseSettings
class TestSettings(BaseSettings):
ollama_base_url: str = "http://localhost:11434"
default_model: str = "llama3.2:latest" # 根据你本地部署的模型调整
request_timeout: int = 60
semantic_similarity_threshold: float = 0.75
class Config:
env_file = ".env"
settings = TestSettings()
# .env 文件(可根据环境覆盖默认值)
OLLAMA_BASE_URL=http://localhost:11434
DEFAULT_MODEL=qwen2.5:7b
REQUEST_TIMEOUT=120
4.2 编写pytest Fixture管理资源
conftest.py 是 pytest 的魔力所在,这里定义的fixture可以被所有测试文件使用。
# conftest.py
import pytest
import asyncio
from core.ollama_client import OllamaClient
from config.settings import settings
@pytest.fixture(scope="session")
def event_loop():
"""为异步测试创建事件循环"""
loop = asyncio.get_event_loop_policy().new_event_loop()
yield loop
loop.close()
@pytest.fixture(scope="session")
async def ollama_client():
"""创建并返回一个Ollama客户端实例,测试结束后自动关闭"""
client = OllamaClient(base_url=settings.ollama_base_url, timeout=settings.request_timeout)
yield client
await client.close()
@pytest.fixture(scope="session")
def default_model():
"""返回默认测试模型"""
return settings.default_model
Fixture使用技巧 :
scope="session"表示这个fixture在整个测试会话中只创建一次,并被所有测试用例共享。对于HTTP客户端这种重量级资源,这能避免重复创建连接的开销。- 异步fixture需要配合
pytest-asyncio插件使用(需pip install pytest-asyncio)。event_loopfixture是pytest-asyncio的常见写法,确保每个测试用例有独立的事件循环。
4.3 编写基础连通性测试
这是我们的第一个测试,确保测试环境是就绪的。
# tests/test_connectivity.py
import pytest
class TestOllamaConnectivity:
"""Ollama服务基础连通性测试"""
@pytest.mark.asyncio
async def test_service_is_up(self, ollama_client):
"""测试Ollama服务是否可访问"""
# 这里可以调用一个简单的API,如 /api/tags 来验证
# 但为了简单,我们尝试生成一个极短的文本来测试
from core.ollama_client import OllamaGenerateRequest
request = OllamaGenerateRequest(model="dummy-model-check", prompt="Hello", stream=False)
# 我们预期这个请求会因为模型不存在而返回一个特定的错误,但这证明了服务是活的
# 更稳健的做法是调用 /api/tags
try:
# 使用httpx直接调用tags接口更合适
async with ollama_client.client as client:
resp = await client.get(f"{ollama_client.base_url}/api/tags")
assert resp.status_code == 200
# 确保响应中有模型列表
data = resp.json()
assert "models" in data
print(f"可用模型: {[m['name'] for m in data['models']]}")
except Exception as e:
pytest.fail(f"无法连接到Ollama服务: {e}")
@pytest.mark.asyncio
async def test_default_model_available(self, ollama_client, default_model):
"""测试默认配置的模型是否在本地可用"""
async with ollama_client.client as client:
resp = await client.get(f"{ollama_client.base_url}/api/tags")
models = [m["name"] for m in resp.json().get("models", [])]
assert default_model in models, f"默认模型 '{default_model}' 未在本地找到。可用模型: {models}"
4.4 编写数据驱动的功能测试
这是框架的核心应用。我们将测试用例数据放在YAML文件中。
# test_data/test_cases.yaml
test_cases:
- name: "测试模型能正确回答简单事实问题"
model: "llama3.2:latest" # 可覆盖默认模型
prompt: "中国的首都是哪里?"
assertions:
- type: "contains"
value: ["北京"]
- type: "not_contains"
value: ["东京", "华盛顿"]
- name: "测试模型能按要求生成JSON格式"
prompt: |
请生成一个包含书名、作者和出版年份的JSON对象,内容关于一本经典的科幻小说。
assertions:
- type: "valid_json"
- type: "json_schema"
value:
type: "object"
required: ["书名", "作者", "出版年份"]
properties:
书名:
type: "string"
作者:
type: "string"
出版年份:
type: "integer"
- name: "测试模型总结能力(语义相似度)"
prompt: |
请用一句话总结以下段落:
“自动化测试是软件开发中的重要环节,它能通过自动执行测试用例,替代部分手动测试工作,提高测试效率,保障软件质量,并支持持续集成和持续交付。”
expected_summary: "自动化测试通过自动执行用例提升软件测试效率和质量。"
assertions:
- type: "semantic_similarity"
threshold: 0.8 # 可覆盖全局阈值
然后,编写一个测试文件来读取这些数据并执行测试。
# tests/test_functional.py
import pytest
import yaml
import asyncio
from core.ollama_client import OllamaGenerateRequest
from core.assertions import OllamaResponseAssertor
from config.settings import settings
def load_test_cases():
with open("test_data/test_cases.yaml", 'r', encoding='utf-8') as f:
data = yaml.safe_load(f)
return data.get('test_cases', [])
@pytest.mark.parametrize("test_case", load_test_cases())
@pytest.mark.asyncio
async def test_ollama_with_data(test_case, ollama_client):
"""数据驱动的Ollama功能测试"""
tc_name = test_case['name']
print(f"\n执行测试用例: {tc_name}")
# 准备请求
model = test_case.get('model', settings.default_model)
prompt = test_case['prompt']
request = OllamaGenerateRequest(model=model, prompt=prompt, stream=False)
# 执行请求
response_text = await ollama_client.generate(request)
print(f"Prompt: {prompt[:50]}...")
print(f"Response: {response_text[:200]}...")
# 执行所有断言
for assertion in test_case.get('assertions', []):
a_type = assertion['type']
a_value = assertion.get('value')
if a_type == 'contains':
OllamaResponseAssertor.assert_contains(response_text, a_value)
elif a_type == 'not_contains':
OllamaResponseAssertor.assert_not_contains(response_text, a_value)
elif a_type == 'matches_pattern':
OllamaResponseAssertor.assert_matches_pattern(response_text, a_value)
elif a_type == 'valid_json':
OllamaResponseAssertor.assert_valid_json(response_text)
elif a_type == 'json_schema':
OllamaResponseAssertor.assert_json_schema(response_text, a_value)
elif a_type == 'semantic_similarity':
expected = test_case.get('expected_summary')
if not expected:
pytest.skip(f"测试用例 '{tc_name}' 缺少 `expected_summary`,跳过语义相似度断言。")
threshold = assertion.get('threshold', settings.semantic_similarity_threshold)
OllamaResponseAssertor.assert_semantic_similarity(response_text, expected, threshold)
else:
raise ValueError(f"不支持的断言类型: {a_type}")
数据驱动测试的优势 :
- 关注点分离 :测试逻辑(Python代码)和测试数据(YAML)分离,结构清晰。
- 易于维护 :新增测试用例只需在YAML文件中添加一条记录,无需修改代码。
- 非技术人员可参与 :产品经理或业务专家可以直接编写或审查YAML中的Prompt和预期结果。
- 参数化测试 :
@pytest.mark.parametrize让一个测试函数可以运行多条用例,并清晰展示每条用例的结果。
4.5 运行测试并生成报告
安装依赖后,就可以运行测试了。
# 安装依赖
pip install pytest httpx pydantic pydantic-settings pyyaml deepdiff sentence-transformers pytest-asyncio pytest-html
# 运行所有测试
pytest -v
# 运行特定测试文件
pytest tests/test_functional.py -v
# 运行测试并生成HTML报告
pytest --html=report.html --self-contained-html
# 遇到网络慢,模型加载慢?可以设置更长的超时时间
OLLAMA_REQUEST_TIMEOUT=300 pytest -v
5. 常见问题与排查技巧实录
在实际搭建和运行过程中,你肯定会遇到各种问题。下面是我踩过的一些坑和解决方案。
5.1 连接与超时问题
| 问题现象 | 可能原因 | 排查步骤与解决方案 |
|---|---|---|
httpx.ConnectError 连接被拒绝 |
1. Ollama服务未启动。 2. 端口号错误(默认是11434)。 3. 防火墙或网络策略阻止。 |
1. 终端运行 ollama serve 确保服务已启动。 2. 检查 OLLAMA_BASE_URL 配置,确认端口正确。 3. 使用 curl http://localhost:11434/api/tags 手动测试连通性。 |
httpx.ReadTimeout 读取超时 |
1. Prompt复杂或模型较大,生成时间过长。 2. 服务器资源(CPU/内存)不足。 3. 网络延迟高。 |
1. 增加超时设置 :在 OllamaClient 初始化或请求时设置更大的 timeout 值(如300秒)。 2. 优化Prompt :尝试简化Prompt,或使用更小的模型进行测试。 3. 监控资源 :运行测试时,观察系统资源使用情况。 |
httpx.HTTPStatusError: 404 Not Found |
API路径错误。 | 确认Ollama API路径。生成接口是 /api/generate ,列表模型是 /api/tags ,确保URL拼接正确。 |
实操心得 : 超时时间一定要根据模型大小和Prompt长度合理设置。 对于7B参数模型,简单问答可能只需几秒,但复杂推理或长文本生成可能需要几分钟。我通常会在配置中设置一个较大的默认值(如120秒),并为特定的长文本测试用例在代码中临时覆盖这个值。
5.2 模型与响应相关问题
| 问题现象 | 可能原因 | 排查步骤与解决方案 |
|---|---|---|
| 测试失败,提示模型不存在 | 1. 配置的模型名称错误。 2. 模型未拉取到本地。 |
1. 运行 ollama list 查看本地已有模型。 2. 使用 /api/tags 接口在测试初始化时验证模型是否存在。 3. 拉取模型: ollama pull <model-name> 。 |
| 断言失败,但肉眼观察输出“似乎”正确 | 1. 断言过于严格(如完全字符串匹配)。 2. 模型输出存在随机性。 3. 关键词有同义词或不同表述。 |
1. 改用更灵活的断言 :用 assert_contains 替代 == ,用 assert_semantic_similarity 。 2. 调整Prompt :在Prompt中明确要求“用‘北京’一词回答”,减少随机性。 3. 增加断言容错 :提供多个可能的关键词列表。 |
| 响应内容为空或非常短 | 1. Prompt不清晰,模型无法理解。 2. 模型“害怕”生成内容(在安全策略下)。 3. 生成参数(如 temperature )设置过低。 |
1. 优化Prompt工程 :让指令更清晰具体。例如,将“写点东西”改为“写一段关于春天的50字短文”。 2. 检查请求参数 :在 OllamaGenerateRequest 的 options 中尝试调整 temperature (提高创造性)或 seed (固定随机性)。 3. 查看完整日志 :Ollama服务端日志可能有更多线索。 |
避坑技巧 : 对于关键的业务流测试,建议在Prompt中设置 seed 参数。 这能确保模型在相同输入下产生完全相同的输出,极大提高测试的确定性和可重复性。例如: "options": {"seed": 42} 。但要注意,这牺牲了输出的多样性,只适用于需要稳定输出的场景。
5.3 性能与稳定性测试进阶
基础功能测试通过后,你可能需要关注性能。
# tests/test_performance.py
import pytest
import asyncio
import time
from core.ollama_client import OllamaGenerateRequest
@pytest.mark.asyncio
async def test_single_request_latency(ollama_client, default_model):
"""测试单次请求的延迟是否在预期范围内"""
prompt = "请用一句话介绍你自己。"
request = OllamaGenerateRequest(model=default_model, prompt=prompt)
start_time = time.perf_counter()
response = await ollama_client.generate(request)
end_time = time.perf_counter()
latency = end_time - start_time
print(f"单次请求延迟: {latency:.2f} 秒, 生成长度: {len(response)} 字符")
# 断言延迟小于5秒(这个阈值需要你根据模型和硬件调整)
assert latency < 5.0, f"请求延迟{latency:.2f}秒超过阈值"
@pytest.mark.asyncio
async def test_concurrent_requests(ollama_client, default_model):
"""测试并发处理能力(模拟轻度并发)"""
async def make_one_request():
req = OllamaGenerateRequest(model=default_model, prompt="说你好。")
return await ollama_client.generate(req)
num_requests = 5
start_time = time.perf_counter()
tasks = [make_one_request() for _ in range(num_requests)]
responses = await asyncio.gather(*tasks)
end_time = time.perf_counter()
total_time = end_time - start_time
print(f"并发 {num_requests} 个请求,总耗时: {total_time:.2f} 秒")
# 简单检查是否所有请求都成功完成
assert len(responses) == num_requests
assert all(len(r) > 0 for r in responses)
性能测试注意 :对本地部署的Ollama进行压测要格外小心,很容易把电脑跑崩。建议从低并发数开始,逐步增加,并密切监控CPU和内存使用情况。性能基准(如延迟阈值)需要在你的特定硬件和模型上多次运行后确定。
5.4 框架扩展与集成建议
这个基础框架可以随着项目需求不断扩展:
- 测试报告增强 :集成
pytest-html生成美观的HTML报告,或使用pytest-allure生成更专业的Allure报告,展示每个Prompt和对应的模型输出,便于回溯。 - CI/CD集成 :在
GitHub Actions或GitLab CI的配置文件中,添加一个测试步骤。确保在代码合并或发布前,自动运行Ollama API测试。# .github/workflows/test.yml 示例片段 - name: Run Ollama API Tests run: | # 启动Ollama服务(假设已安装) ollama serve & sleep 10 # 等待服务启动 # 运行测试 pytest -v --html=report.html - 多模型/多配置测试 :使用
@pytest.mark.parametrize同时对多个模型(如llama3.2,qwen2.5)或不同生成参数(temperature=0.1vs0.8)进行测试,对比输出质量和性能。 - Mock测试 :对于单元测试,你可能不希望每次都调用真实的Ollama服务。可以使用
pytest-mock或unittest.mock来模拟OllamaClient.generate方法,返回预定义的响应,从而测试你的业务逻辑代码。
搭建这样一个框架的初期会花点时间,但一旦成型,它就会成为你AI应用开发流程中一个强大的安全网和效率工具。它能让你在模型迭代、Prompt调整时充满信心,因为你知道任何回归问题都会被自动化测试第一时间捕捉到。
更多推荐

所有评论(0)