OGX 集成测试指南:基于记录-回放机制的跨 Provider 端到端测试体系
2026/9/16 23:29:37 网站建设 项目流程

OGX 集成测试指南:基于记录-回放机制的跨 Provider 端到端测试体系

【免费下载链接】ogxOpen GenAI Stack项目地址: https://gitcode.com/GitHub_Trending/ll/ogx

OGX(Open GenAI Stack)提供了一套完整的集成测试体系,覆盖从 Chat Completions、Embeddings、Vision 到 Agents、Responses API、Vector IO、Telemetry 等全部 API 表面,并基于自研的「记录-回放」(record-replay)机制,让测试无需真实调用付费 API 也能稳定、可重复地在本地与 CI 中运行。本文以 tests/integration/README.md 为骨架,结合仓库内conftest.pysuites.pyapi_recorder.pyintegration-tests.sh等源码,系统讲解集成测试的启动方式、配置项、录制模式、录音管理与测试编写方法,帮助你在一小时内上手并扩展 OGX 的端到端测试。

集成测试验证的是「跨多个 Provider 的完整工作流」,例如:本地 Ollama 上的推理 → 服务器响应 → 客户端消费回放数据。与单元测试不同,集成测试需要真实的模型后端(本地推理引擎或云端 API),OGX 用「录制一次、处处回放」的方式解耦了这种依赖。各 Provider 的目标模型清单与 CI 车道(CI lanes)见 TARGET_MODELS.md,该文件由scripts/generate_target_models_docs.py自动生成。

快速开始

在仓库根目录执行以下命令即可运行全部集成测试(默认使用已有录音回放,不产生任何真实 API 调用):

# Run all integration tests with existing recordings uv run --group dev \ pytest -sv tests/integration/ --stack-config=starter

这里--stack-config=starter表示以库内联(library client)方式构建 Stack:测试进程内部直接组装starter配置对应的各 Provider,无需启动独立服务器。-sv用于输出每个测试的进度详情。

Provider 依赖检查

不同 Stack 配置依赖不同的 Provider 包(例如 Ollama Provider 需要ollama包,vLLM Provider 需要vllm相关依赖)。scripts/integration-tests.sh会在运行测试前做一次「Provider 依赖预检」:执行与 CI 完全相同的依赖安装命令ogx stack list-deps <config> | xargs -L1 uv pip install,并解析uv pip list中已安装的包名做比对。若缺少依赖,脚本会提前失败并给出精确的安装命令;追加--install-deps参数则会自动安装缺失依赖后再运行测试。

从 scripts/integration-tests.sh 的实现可以看到,check_provider_dependencies函数会跳过--*标志及其取值、剥离[...]extras、版本号与环境标记后提取包名,与已安装列表做大小写归一化比对。对docker:*http://*配置会跳过预检(依赖已打入镜像或由远端提供)。

配置选项

集成测试基于 pytest 的addoption机制扩展了大量自定义命令行参数,完整清单可通过以下命令查看(关注输出中Custom options:一节):

cd tests/integration # this will show a long list of options, look for "Custom options:" pytest --help

--stack-config:以五种方式指向一个 Stack

--stack-config是集成测试的核心参数,它的取值决定测试连接「哪种形态」的 OGX Stack。根据 conftest.py 中的定义,共有以下形式:

取值形式说明
server:<config>自动启动一个使用给定配置的服务器(如server:starter)。若端口空闲则自动拉起服务,若已有服务在运行则直接复用,实现「一步到位」的测试
server:<config>:<port>同上,但指定自定义端口(如server:starter:8322
一个 URL指向一个已运行的 OGX 发行版(distribution)服务器
发行版名称或config.yaml路径starter,或以库内联方式加载指定配置文件
api=provider逗号分隔列表动态组合 API 与 Provider(如inference=ollama,responses=builtin),最适合只测单一 API 表面

在 conftest 的pytest_sessionstart钩子中,系统会根据--stack-config是否以server:docker:http开头,设置OGX_TEST_STACK_CONFIG_TYPE环境变量为serverlibrary_client——这个标记直接影响录制系统在服务器模式下通过 HTTP 头传递测试上下文的行为(见下文「Recording System Internals」)。

--env:注入 Provider 所需环境变量

pytest ... --env KEY=value

这是一个通用工具选项,用于设置各 Provider 所需的环境变量(如OLLAMA_URLOPENAI_API_KEY)。在pytest_configure钩子中,所有--env值都会被split("=", 1)解析后写入os.environ

模型相关参数

以下参数控制测试使用的模型,每个参数都支持逗号分隔的列表,系统会自动生成多个参数组合(笛卡尔积)来展开测试:

  • --text-model:文本模型列表
  • --vision-model:视觉模型列表
  • --embedding-model:嵌入模型列表
  • --judge-model:评测(judge)模型列表
  • --embedding-dimension:嵌入模型输出维度,默认768
  • --rerank-model:重排模型列表(conftest 中新增,rerank_model_idfixture)

这些选项在 conftest.py 中注册,并在pytest_generate_tests中通过itertools.product生成所有组合,测试 ID 采用txt=3B:emb=Nomic-v1.5这类简短格式(由get_short_id将模型名映射为短标识)。注意:如果没有指定任何模型,测试会被跳过——这是 fixture 在参数为None时的预期行为。

Suites 与 Setups:按需收窄测试范围

--suite:单套命名测试集

--suite用于收窄测试收集范围,避免每次全量运行。套件定义集中在 suites.py,可用套件包括:

  • base:收集大多数测试(排除 responses 目录),默认 setup 为ollama
  • responses:仅收集tests/integration/responses下的测试(需要强工具调用能力的模型)
  • vision:仅收集tests/integration/inference/test_vision_inference.py
  • messages/messages-openai/v1/messages翻译路径测试(后者使用 gpt 强制走 Anthropic→OpenAI 翻译代码路径而非原生透传)
  • interactions:Google Gemini 交互测试
  • bedrock/bedrock-responses:基于预录制响应的 AWS Bedrock 测试(CI 中不进行实时 API 调用)
  • gpt-reasoning/ollama-reasoning/vllm-reasoning:推理(reasoning)能力专项,roots 精确到文件::测试函数
  • base-vllm-subset:仅 inference 目录 + vllm

从实现上看,pytest_ignore_collect会跳过所选套件 roots 之外的路径以加速收集;对于 roots 含::test_function的套件,pytest_collection_modifyitems会进一步精确过滤到指定测试函数。base套件的 roots 通过目录 glob 动态生成(排除__pycache__fixturestest_casesrecordingsresponsesmessagesinteractions)。

--setup:全局配置预设

--setup是与任何套件都可搭配的「全局配置」,用于预填模型与环境变量默认值;显式 CLI 参数始终优先于 setup 默认值。在pytest_configure中,setup 的env先写入环境变量(不覆盖已存在的值),随后defaults只填充尚未显式给定的 CLI 选项。核心 setup 包括:

Setup用途默认文本模型
ollama本地 Ollama,轻量模型(设OLLAMA_URLollama/llama3.2:3b-instruct-fp16
ollama-vision本地 Ollama 视觉模型ollama/llama3.2-vision:11b
ollama-postgres服务器模式 + Postgres 持久化(POSTGRES_HOST/PORT/DB/USER/PASSWORDollama/llama3.2:3b-instruct-fp16
ollama-reasoningdeepseek-r1 推理模型ollama/deepseek-r1:1.5b
vllmvLLM 高效本地推理(设VLLM_URLvllm/Qwen/Qwen3-0.6B
vllm-gpu-gpt-ossGPU vLLM + gpt-oss:20b 推理模型vllm/gpt-oss:20b
gptOpenAI GPT 高质量响应(gpt-4o)openai/gpt-4o
gpt-reasoningOpenAI o4-mini 推理openai/o4-mini
claudeAnthropic Claudeanthropic/claude-3-5-haiku-20241022
azureAzure 托管的 GPTazure/gpt-4o
bedrockAWS Bedrock 的 GPT-OSSbedrock/openai.gpt-oss-20b-1:0
watsonxIBM watsonxwatsonx/meta-llama/llama-3-3-70b-instruct
vertexaiGoogle Vertex AI Geminivertexai/publishers/google/models/gemini-2.0-flash

此外还有tgitogethercerebrasdatabricksfireworksanthropicllama-apigeminigroqllama-cpp-servervllm-qwen3next等更多命名 setup,完整定义见 suites.py。各 setup 对应的模型矩阵(含视觉/嵌入模型)可在 TARGET_MODELS.md 查阅。

组合示例

# Run conversations tests with GPT for high-quality responses pytest -s -v tests/integration/conversations --stack-config=server:starter --setup=gpt # Fast responses run with a strong tool-calling model pytest -s -v tests/integration --stack-config=server:starter --suite=responses --setup=gpt # Fast single-file vision run with Ollama defaults pytest -s -v tests/integration --stack-config=server:starter --suite=vision --setup=ollama # Base suite with VLLM for performance pytest -s -v tests/integration --stack-config=server:starter --suite=base --setup=vllm # Override a default from setup pytest -s -v tests/integration --stack-config=server:starter \ --suite=responses --setup=gpt --embedding-model=text-embedding-3-small

注意--suite=vision --setup=ollama示例中,setup 显式指定时不会自动应用套件的默认 setup(vision 的默认 setup 实为ollama-vision),因此需要自行给出含视觉模型的配置。

常见运行场景

场景一:针对服务器测试(server 模式)

自动拉起starter配置的服务器并运行全部推理测试:

OLLAMA_URL=http://localhost:11434 \ pytest -s -v tests/integration/inference \ --stack-config=server:starter \ --text-model=ollama/llama3.2:3b-instruct-fp16 \ --embedding-model=nomic-embed-text-v1.5

指定自定义端口(服务器将被启动在 8322):

OLLAMA_URL=http://localhost:11434 \ pytest -s -v tests/integration/inference/ \ --stack-config=server:starter:8322 \ --text-model=ollama/llama3.2:3b-instruct-fp16 \ --embedding-model=nomic-embed-text-v1.5

从 scripts/integration-tests.sh 可以看到,server:模式下脚本会从 8321 起寻找空闲端口、以nohup ogx stack run <config> --insecure后台启动服务器,轮询/v1/health与 IPv6 回环健康检查确认就绪,并通过trap stop_server EXIT ERR INT TERM保证测试结束后清理进程。

场景二:库内联客户端(library client)

库内联模式在进程内构造 Stack,而不是连接服务器。对于迭代开发非常有用——无需反复启停服务器。只需把server:starter换成starter

pytest -s -v tests/integration/inference --stack-config=starter --text-model=... --embedding-model=...

conftest 中对该模式的说明是:服务器模式下运行的测试集是库内联模式的超集(部分用例依赖服务器端行为),因此重新录制录音时必须使用服务器模式(见下文)。

场景三:ad-hoc 动态发行版

有时你想「现场拼一个」发行版,用来测试单个 Provider、单个 API 或少量 Provider 组合。此时用逗号分隔的api=provider列表即可,例如inference=remote::ollama,responses=inline::builtin

pytest -s -v tests/integration/inference/ \ --stack-config=inference=remote::ollama,responses=inline::builtin \ --text-model=$TEXT_MODELS \ --vision-model=$VISION_MODELS \ --embedding-model=$EMBEDDING_MODELS

再如:单独运行 Vector IO 嵌入测试,动态组合sentence-transformers推理与sqlite-vec向量库:

pytest -s -v tests/integration/vector_io/ \ --stack-config=inference=inline::sentence-transformers,vector_io=inline::sqlite-vec \ --embedding-model=nomic-embed-text-v1.5

这类动态配置在 conftest 中通过run_config_from_dynamic_config_spec解析,并支持自动推断默认嵌入模型(例如检测到 sentence-transformers 时自动填入sentence-transformers/nomic-ai/nomic-embed-text-v1.5)。

录制模式:四种运行方式

OGX 集成测试支持四种由环境变量/CLI 控制的录制模式,枚举定义于 api_recorder.py,CLI 选项为--inference-mode

REPLAY 模式(默认)

使用缓存的响应回放,不发起任何 API 调用。录制缺失时测试直接失败,这是 CI 中确定性最高的模式:

pytest tests/integration/

RECORD-IF-MISSING 模式(新增测试时推荐)

仅在不存在录音时才发起真实调用并记录,已有录音则回放。这是迭代开发的推荐模式,兼顾速度与补录能力:

pytest tests/integration/inference/test_new_feature.py --inference-mode=record-if-missing

RECORD 模式

强制录制所有 API 交互并覆盖已有录音。会重录一切,谨慎使用:

pytest tests/integration/inference/test_new_feature.py --inference-mode=record

LIVE 模式

所有测试走真实 API 调用(不记录):

pytest tests/integration/ --inference-mode=live

--inference-mode的取值限定为record/replay/live/record-if-missing(conftest 的choices校验),最终写入OGX_TEST_INFERENCE_MODE环境变量。默认录制目录为tests/integration/recordings,可用OGX_TEST_RECORDING_DIR覆盖。从源码看,实际的录制存储位于各测试目录下的recordings/子目录(见ResponseStorage._get_test_dir的路径解析逻辑),同时保留tests/integration/common/recordings作为会话级(session-level)录音的回退目录。

录音管理

查看录音

录音以 JSON 文件 + SQLite 索引的形式存储:

# See what's recorded sqlite3 recordings/index.sqlite "SELECT endpoint, model, timestamp FROM recordings;" # Inspect specific response cat recordings/responses/abc123.json | jq '.'

自动化重录(推荐)

当你提交包含新增或修改测试的 PR 时,录音工作流会自动完成以下步骤:

  1. 检测缺失的测试录音
  2. 使用 ollama 录制(无需任何 API Key)
  3. 将录音提交回你的 PR

出于安全考虑,该工作流分两步执行:

  • Step 1:以只读权限运行测试,将录音作为 CI 产物(artifacts)上传
  • Step 2:仅以写权限运行可信的基础仓库代码,将产物中的录音提交回 PR

对 PR 作者而言:直接开 PR 即可,无需其他操作;同仓库与 fork PR 均支持(fork 需开启 "Allow edits from maintainers")。录音提交后会自动以回放模式再次触发测试,验证新录音可正常回放。

对维护者而言——需要 API Key 的 Provider(gpt、azure、bedrock)的录制方式:

通过 GitHub UI:

  1. 进入ActionsIntegration Tests (Record)
  2. 点击Run workflow
  3. 输入 PR 编号与 Provider:gpt,azure

通过 GitHub CLI:

# Record for a specific PR with multiple providers gh workflow run record-integration-tests.yml \ -f pr_number=1234 \ -f providers="gpt,azure" # Just gpt gh workflow run record-integration-tests.yml \ -f pr_number=1234 \ -f providers="gpt" # Record specific subdirectories or patterns gh workflow run record-integration-tests.yml \ -f pr_number=1234 \ -f subdirs="agents,inference" gh workflow run record-integration-tests.yml \ -f pr_number=1234 \ -f pattern="test_streaming"

可用 Provider 及其凭据要求:

Provider凭据要求
ollama无需 API Key(PR 上自动运行)
gptOpenAI(需要OPENAI_API_KEYsecret)
azureAzure OpenAI(需要AZURE_API_KEYAZURE_API_BASEsecrets)
bedrockAWS Bedrock(需要AWS_BEARER_TOKEN_BEDROCKsecret)
watsonxIBM watsonx(需要WATSONX_API_KEYWATSONX_BASE_URLWATSONX_PROJECT_IDsecrets)

注意:vllm目前尚未加入该录制工作流(不在 Provider 矩阵中)。

新增 Provider 到录制工作流的步骤:

  1. .github/workflows/record-integration-tests.ymlprovider矩阵中添加新条目:

    - setup: your-provider suite: responses
  2. Run and record tests步骤中添加该 Provider 的 API Key 环境变量:

    YOUR_PROVIDER_API_KEY: ${{ matrix.provider.setup == 'your-provider' && secrets.YOUR_PROVIDER_API_KEY || '' }}
  3. 在仓库设置中添加对应的 GitHub secret

本地重录

# Re-record specific tests pytest -s -v --stack-config=server:starter tests/integration/inference/test_modified.py --inference-mode=record

重要:重录时必须使用指向服务器的 Stack(即server:starter)。原因在于服务器模式下运行的测试集合是库内联模式的超集——若用库内联模式重录,部分仅在服务器端出现的请求将无法被覆盖。

编写集成测试

基本测试模式

集成测试的 fixtures(ogx_clienttext_model_id等)由 conftest 注入,测试只需关注结构而非 AI 输出质量:

def test_basic_chat_completion(ogx_client, text_model_id): response = ogx_client.chat.completions.create( model=text_model_id, messages=[{"role": "user", "content": "Hello"}], ) # Test structure, not AI output quality assert response.choices[0].message is not None assert isinstance(response.choices[0].message.content, str) assert len(response.choices[0].message.content) > 0

Provider 特定测试

对于某些模型才支持的能力(如带task_type的非对称嵌入),应显式跳过不支持的模型:

def test_asymmetric_embeddings(ogx_client, embedding_model_id): if embedding_model_id not in MODELS_SUPPORTING_TASK_TYPE: pytest.skip(f"Model {embedding_model_id} doesn't support task types") query_response = ogx_client.inference.embeddings( model_id=embedding_model_id, contents=["What is machine learning?"], task_type="query", ) assert query_response.embeddings is not None

可参考的实际用例遍布各子目录,例如 test_openai_completion.py、test_vision_inference.py、test_basic_responses.py 等。

TypeScript 客户端回放

Python 测试通过后,TypeScript SDK 测试可与 Python 测试并行运行(仅限server:<config>模式)。通过TS_CLIENT_PATH指向ogx-client-typescript的版本或路径来启用:

# Use published npm package (responses suite) TS_CLIENT_PATH=^0.3.2 scripts/integration-tests.sh --stack-config server:ci-tests --suite responses --setup gpt # Use local checkout from ~/.cache (recommended for development) git clone https://github.com/ogx-ai/ogx-client-typescript.git ~/.cache/ogx-client-typescript TS_CLIENT_PATH=~/.cache/ogx-client-typescript scripts/integration-tests.sh --stack-config server:ci-tests --suite responses --setup gpt # Run base suite with TypeScript tests TS_CLIENT_PATH=~/.cache/ogx-client-typescript scripts/integration-tests.sh --stack-config server:ci-tests --suite base --setup ollama

TypeScript 测试在 Python 测试全部通过后立即执行,复用同一套回放 fixtures。Python 套件/setup 与 TypeScript 测试文件之间的映射定义在 tests/integration/client-typescript/suites.json。若未设置TS_CLIENT_PATH,TypeScript 测试会被整体跳过。从 scripts/integration-tests.sh 可以看到,脚本会区分目录路径与 npm 版本号:目录路径会先执行npm install+npm run build构建本地客户端,npm 版本则直接安装ogx-client@<version>

目录结构

integration/ admin/ # Admin API tests agents/ # Agent orchestration tests batches/ # Batch processing tests client-typescript/ # TypeScript SDK replay tests common/ # Shared test utilities and recording storage conversations/ # Conversation persistence tests datasets/ # Dataset management tests eval/ # Evaluation tests files/ # File management tests fixtures/ # Test fixtures and data inference/ # Inference API tests (chat completion, embeddings, vision) inspect/ # Inspect API tests post_training/ # Post-training tests providers/ # Provider-specific tests recordings/ # Cached API responses for replay mode responses/ # OpenAI Responses API tests scoring/ # Scoring tests telemetry/ # Telemetry tests test_cases/ # Shared test case definitions tool_runtime/ # Tool runtime tests tools/ # Tool integration tests vector_io/ # Vector I/O tests conftest.py # Main conftest (client setup, recording mode, fixtures) suites.py # Suite/setup definitions ci_matrix.json # CI test matrix configuration

实际仓库中除上述目录外,还包含interactions/messages/models/openresponses/等目录(README 列举的datasets/eval/post_training/scoring/tools/在演进中已归并入其他目录或迁移)。conftest.py承担客户端初始化、录制模式读取与 fixture 生成三大职责;suites.py是套件/setup 的单一事实来源;ci_matrix.json 定义 CI 车道矩阵——默认车道共 16 条(含base+ollamaresponses+gptresponses+azure等),另有gpu-vllm车道与每周日(cron1 0 * * 0)的定时车道。

Recording System Internals:记录-回放系统的实现细节

记录/回放系统的核心实现位于 src/ogx/testing/api_recorder.py,关键设计如下:

  • 请求哈希(Request hashing):每个 API 调用通过哈希其参数(方法名、模型、消息等)匹配录音,即使测试执行顺序发生变化也能正确回放。哈希计算见normalize_inference_request:对请求体做递归归一化(浮点四舍五入到 5 位、字符串内长小数四舍五入、规范化 file_search 元数据中的 score/document_id/attributes 等易变字段、剔除 Bedrock 端点的stream_options与根层的project_id),并将当前测试 ID 混入哈希以保证测试间隔离——相同请求在不同测试中哈希不同。例外是模型列表端点(/v1/models/api/tags),它们属于会话级共享基础设施,哈希不包含 test_id。
  • 确定性 ID(Deterministic IDs):回放期间,资源 ID(文件、向量存储等)通过计数器确定性地生成(前缀见_ID_KIND_PREFIXESfile-vs_batch_call_),每个测试基于其 nodeid 的 SHA256 派生一个初始计数器,保证同一测试每次运行产生完全相同的 ID,从而让测试结果可复现。
  • 存储格式(Storage format):录音以 JSON 文件形式存储在 Provider 相关目录中;同时使用 SQLite 索引将请求哈希映射到响应文件。录音文件包含test_idrequestresponseid_normalization_mapping元数据;响应体通过__type__/__data__携带 Pydantic 类型信息,回放时用model_validate/model_construct反序列化还原对象。
  • 流式响应(Streaming):流式响应被录制成完整的 chunk 序列,回放时逐 chunk 重新输出,忠实还原流式行为。此外,_normalize_response会把响应 ID 替换为rec-<hash前12位>、时间戳归零、Ollama 时长字段归零,从而显著减少录音文件在 git diff 中的噪音。
  • 工具调用与重排请求:工具调用(如 Tavily 搜索)通过normalize_tool_request哈希并走同样的录制逻辑;HTTP 层重排(rerank)请求则通过 patchaiohttp.ClientSession.postaiohttp层捕获(仅拦截含/rerank的 URL),保证客户端后处理(如max_num_results应用)在回放时仍能正常执行。
  • 服务器模式下的测试上下文传递:在服务器模式下,测试 ID 通过X-OGX-Provider-DataHTTP 头从客户端注入到服务器端(patch_httpx_for_test_id利用 Stainless 客户端与 OpenAI 客户端的_prepare_request钩子实现),使录制系统在跨进程场景下依然能按测试隔离录音。

conftest 中还包含若干对测试行为有影响的细节:pytest_sessionstart会为未设置SQLITE_STORE_DIR的会话创建临时目录作为存储根;pytest_runtest_teardown支持通过OGX_TEST_INTERVAL_SECONDS为 inference/agents/responses 测试间插入间隔(用于压测或节流场景);autouse fixture_track_test_context将每个测试的 nodeid 写入 contextvar,供录制系统定位录音子目录。

CI 矩阵与 Responses 覆盖率

ci_matrix.json 中的默认车道包含responses+gpt(覆盖率 100%)、responses+azure(82%)、responses+watsonx(45%)、responses+vertexai(51%)、bedrock-responses+bedrock(20%)等组合。Responses 功能点总计 137 个,各 Provider 的实测覆盖情况汇总于 TARGET_MODELS.md:OpenAI 137/137(100%)、Azure 112/137(82%)、Vertex AI 70/137(51%)、WatsonX 62/137(45%)、Bedrock 27/137(20%)、Ollama 与 vLLM 各 3/137(2%)。这些数据源自回放录音,与docs/docs/api-openai/provider_matrix.md同源,是衡量各 Provider Responses API 对齐程度的重要参考。

结语

OGX 的集成测试体系以「录制-回放」为核心,将昂贵的、不稳定的真实模型调用转化为廉价、确定性的本地回放,同时通过--stack-config的五种形态、Suites/Setups 的组合编排、TypeScript 客户端的并行回放,以及 CI 自动补录工作流,覆盖了从本地迭代到多 Provider 云端矩阵的完整测试生命周期。无论你是为新增 Provider 编写测试、在本地复现 CI 失败,还是维护多 Provider 的 Responses 兼容性,这套体系都能让你以最小的外部依赖获得最大化的端到端信心。

【免费下载链接】ogxOpen GenAI Stack项目地址: https://gitcode.com/GitHub_Trending/ll/ogx

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询