- LLM 网关
- 大模型
- 后端
- AI 应用
【免费下载链接】free-claude-code
Use Claude Code, Codex, VSCode, Pi, and OpenCode (and 6 other harnesses) for free (1.3B+ free tokens) from your terminal, app, IDE, or phone, and now from the browser with native browser sessions (multi-harness + multi-model) like OpenClaw (voice supported + ToS friendly)
smoke/是 free-claude-code 仓库中一套独立于常规 CI(tests/与e2e/)的本地产品级 E2E 冒烟测试套件。它允许在开发者本机启动子进程、真实调用 Provider、连接本地模型服务(LM Studio / llama.cpp / Ollama),并可选地发送/删除真实机器人消息。本文基于 smoke/README.md 完整讲解其分层结构(installers / prereq / product)、全部 Target 与所需环境、运行命令、失败分类体系,并结合仓库源码(smoke/conftest.py、smoke/lib/config.py、smoke/lib/outcomes.py 等)深入解析其实现原理。读完本文,你将能够独立运行、裁剪、并行化并解读这套 smoke 套件的任意场景。
一、smoke/ 是什么:本地专用的产品 E2E 套件
smoke/目录的定位与常规测试有本质区别,smoke/README.md 开篇即声明:
smoke/is local-only. It can launch subprocesses, call real providers, touch local model servers, and optionally send/delete bot messages. Installer checks also live here as an opt-in suite. Regular CI collects onlytests/ande2e/.
含义拆解如下:
- 仅限本地运行:它会启动真实子进程、连接真实 Provider、访问本地模型服务器,甚至可能向 Telegram/Discord 发送并删除机器人消息,因此绝不进入常规 CI;CI 只收集
tests/与e2e/。 - 安装器检查是可选套件:
smoke/installers/作为 opt-in 子套件存在,且 smoke/installers/AGENTS.md 明确要求:测试必须通过真实脚本函数进行,下载与外部安装器一律 stub,绝不安装真实工具、绝不使用 live Provider、绝不修改用户已安装的工具与配置;每个场景都必须使用私有文件、配置、PATH 与缓存存储。 - 结果落盘:无论是否真正执行,只要运行
pytest smoke,skip 条目都会写入.smoke-results/目录。
二、套件分层:installers / prereq / product
smoke/README.md 定义了三级分类(Taxonomy),每一层的目的与验收标准都不同:
| 目录 | 定位 | 关键约束 |
|---|---|---|
smoke/installers/ | 安装器、卸载器、harness 生命周期检查 | 隔离文件与模拟下载,不安装真实工具(详见 smoke/installers/AGENTS.md) |
smoke/prereq/ | 存活探针:server、routes、auth、CLI 脚本、Provider ping、本地/models、机器人权限 | 仅作为前置条件(prerequisites),不算产品覆盖 |
smoke/product/ | 端到端产品场景 | 功能 smoke 覆盖的唯一来源 |
smoke/features.py 的开头模块注释把这一分层逻辑讲得很清楚:
Public product behavior must have deterministic pytest contract coverage plus a product E2E scenario when that behavior is a user-facing product path. Liveness and route probes live in
smoke/prereqand do not count as product coverage.
即:公共产品行为 = 确定性 pytest 契约测试(tests/与e2e/)+ 产品级 E2E 场景(smoke/product/),而smoke/prereq/的存活与路由探针不计入产品覆盖。这一"契约 + 产品 E2E"双层思想贯穿整个套件:
- 契约层:
tests/中的确定性测试(如 tests/api/test_auth.py、tests/application/test_routing.py)保护协议形状与内部边界; - 产品层:
smoke/product/中的 live 测试验证真实用户路径(多轮对话、自适应思考、工具调用、断开恢复等)。
smoke/features.py中的FeatureCoverage数据类正是这一思想的载体,每条记录同时携带pytest_contract_tests、live_prereq_tests、product_e2e_tests、smoke_targets、required_env与skip_policy字段,将"特性 → 子特性 → 场景 → 环境 → 预期行为 → 失败类别"的映射固化为唯一事实源。
2.1 与之配套的能力契约图:smoke/capabilities.py
与smoke/features.py配套的是 smoke/capabilities.py,模块注释称其为 "architectural companion"。其中CapabilityContract记录了每条子特性契约的拥有模块边界(owner,如free_claude_code.application.code_sessions.service.CodeService)、输入输出与失败语义,以及对应的契约测试与 smoke 测试。例如provider_routing能力的claude_model_resolution子特性由free_claude_code.application.routing.ModelRouter拥有,由 tests/application/test_routing.py 与test_model_mapping_configuration_is_consistent探针共同保护。这套能力图的价值在于:当内部实现被重构时,契约层(tests)与产品层(smoke)仍然可以各自独立验证,能力归属不因重构而丢失。
三、必会本地命令:三步走
3.1 收集用例与首次试跑
smoke/README.md 给出的两条基础命令(PowerShell 语法):
uv run pytest smoke --collect-only -q uv run pytest smoke -n 0 -s --tb=short--collect-only -q:只收集用例、不执行,用于快速预览将要运行哪些场景(例如确认目标 Provider 模型已按预期被参数化展开)。- 第二条命令在未设置
FCC_LIVE_SMOKE=1时会跳过一切用例,但仍会把 skip 条目写入.smoke-results/——这正是 smoke/conftest.py 中pytest_collection_modifyitems的实现:SmokeConfig.load().live为假时,为每个 item 追加pytest.mark.skip(reason="set FCC_LIVE_SMOKE=1 to run local smoke tests")。 -n 0关闭 pytest-xdist 并行(pyproject 默认-n auto --dist=worksteal,见 pyproject.toml 的[tool.pytest.ini_options]),-s保留子进程输出,--tb=short压缩回溯信息。
3.2 只运行安装器检查
$env:FCC_LIVE_SMOKE = "1" uv run pytest smoke/installers该子套件不依赖任何真实工具或 Provider 凭据,且按 smoke/installers/AGENTS.md 的规则模拟下载、隔离环境,因此 CI 之外可以随时在本机运行,用于回归安装/卸载/升级与跨 harness 交互流程。
3.3 完整产品 smoke 运行
$env:FCC_LIVE_SMOKE = "1" uv run pytest smoke -n 0 -s --tb=short这是最常用的完整跑法:FCC_LIVE_SMOKE=1放行所有 live 用例,-n 0保证顺序执行(消息平台、CLI 子进程等场景需要确定性的执行顺序)。
四、并行化与 Provider 矩阵
Provider smoke 场景可以跨 Provider 并行、同一 Provider 内顺序执行:
$env:FCC_LIVE_SMOKE = "1" $env:FCC_SMOKE_TARGETS = "providers" uv run pytest smoke -n auto --dist=loadgroup -s --tb=short实现要点(可验证于 smoke/conftest.py):
pytest_generate_tests钩子读取SmokeConfig,把每个已配置 Provider 的 smoke 模型展开为一个参数化用例,id为 Provider 名;- 每个参数化用例被打上
pytest.mark.xdist_group(f"provider:{provider}"),配合--dist=loadgroup实现"Provider 间并行、Provider 内串行"; provider_model_params在未配置任何 Provider smoke 模型时返回一个带 skip 标记的smoke_disabled占位参数,保证收集阶段不会报错。
4.1 Provider smoke 模型来源:默认值、覆盖与归一化
Provider product E2E每个已配置 Provider 各跑一次,与MODEL、MODEL_FABLE、MODEL_OPUS、MODEL_SONNET、MODEL_HAIKU无关。默认模型来自 smoke/lib/config.py 的PROVIDER_SMOKE_DEFAULT_MODELS字典(例如deepseek/deepseek-v4-pro、nvidia_nim/nvidia/nemotron-3-super-120b-a12b、open_router/nvidia/nemotron-3-super-120b-a12b:free),可被FCC_SMOKE_MODEL_<PROVIDER>覆盖:
$env:FCC_SMOKE_MODEL_DEEPSEEK = "deepseek-v4-pro" # 或 "deepseek-v4-flash"_normalize_provider_model(smoke/lib/config.py)的规则是:值中若已包含 Provider 前缀(parse_provider_type(model) == provider)则原样使用,否则自动拼接为{provider}/{model}。如果没有任何 Provider smoke 模型被配置,live 产品 smoke 会以missing_env失败,除非显式设置FCC_ALLOW_NO_PROVIDER_SMOKE=1(专供 harness 开发场景)。这一"选中的 Provider 缺失即失败"的策略同样体现在 smoke/features.py 的provider_matrix特性 skip_policy 中。
五、Target 矩阵:默认与 opt-in
5.1 默认 Target(不发送真实机器人消息、不加载语音后端)
默认集合由 smoke/lib/config.py 的DEFAULT_TARGETS定义(api、auth、cli、clients、config、extensibility、llamacpp、lmstudio、messaging、ollama、providers、rate_limit、tools):
| Target | Product 场景 | 所需环境 |
|---|---|---|
api | messages、count_tokens 完整 payload、errors、/stop、优化 | 仅流式 messages 需要已配置 Provider |
auth | 规范 bearer 认证、冲突的 legacy headers、无效/缺失认证 | 无(测试会设置隔离 token) |
cli | server 入口、Claude CLI 自适应思考、自动 WebSearch、Auto-mode 分类器、会话清理 | Claude CLI 二进制 + 真实 CLI 用 Provider;Auto mode 需要已连接的 OpenAI 账号;WebSearch 需要FCC_SMOKE_RUN_WEB_TOOLS=1 |
clients | VS Code 与 JetBrains 协议载荷;Pi、OpenCode、Aider、Cline、Hermes、DeepSeek Harness、Grok Build、Muse Code CLI 提示 | 已配置 Provider;已安装 Pi/OpenCode/Aider/Cline 二进制;Hermes、DSH、Grok、Muse 使用本地 fake upstream |
config | env 优先级、removed-env 迁移、proxy/timeouts | 无 |
extensibility | Provider runtime 与平台工厂构造 | 无 |
messaging | fake Discord/Telegram 全流程、literal clear scopes、trees、持久化、语音取消 | 无 |
providers | 多轮文本、自适应思考历史、工具、断开、错误 | 已配置 Provider,可选FCC_SMOKE_MODEL_* |
tools | 强制 tool_use 与 tool_result 延续 | 支持工具且已配置的 Provider |
rate_limit | 断开清理与后续请求 | 已配置 Provider |
lmstudio | 本地/models+ 经代理的 OpenAI-chat 版 Messages | 运行中的 LM Studio 服务器 |
llamacpp | 本地/models+ 经代理的 OpenAI-chat 版 Messages | 运行中的 llama-server |
ollama | 本地/v1/models+ 经代理的 OpenAI-chat 版 Messages | 运行中的 Ollama 服务器 |
5.2 opt-in / 副作用 Target
这些 Target 会真实消耗配额或触碰外部 API,必须显式开启(对应 smoke/lib/config.py 的SIDE_EFFECT_TARGETS与OPT_IN_TARGETS):
| Target | Product 场景 | 所需环境 |
|---|---|---|
nvidia_nim_cli | Claude Code CLI 在 NIM 模型矩阵上的特性矩阵 | NVIDIA_NIM_API_KEY、Claude CLI |
nvidia_nim_vision | Claude 风格图像 tool result 以像素形式到达 NIM 视觉模型 | NVIDIA_NIM_API_KEY、FCC_SMOKE_MODEL_NVIDIA_NIM_VISION |
openrouter_free_cli | Claude Code CLI 在 OpenRouter 免费模型矩阵上的特性矩阵 | OPENROUTER_API_KEY、Claude CLI |
telegram | getMe、send、edit、delete、可选手动 inbound | token 与 chat/user ID |
discord | channel 访问、send、edit、delete、可选手动 inbound | token 与 channel ID |
voice | 本地 Whisper 或 NVIDIA NIM 转录生成的 WAV | VOICE_NOTE_ENABLED=true、FCC_SMOKE_RUN_VOICE=1 |
值得注意的是,smoke/lib/config.py 还维护了一张TARGET_ALIASES别名表(如contract→api、thinking→providers、vscode→clients、nim_cli→nvidia_nim_cli),_parse_targets在解析FCC_SMOKE_TARGETS时会把别名归一化到正式 Target 名;当值包含all时则展开为全部 Target(DEFAULT_TARGETS | SIDE_EFFECT_TARGETS | OPT_IN_TARGETS)。
5.3 Target 如何路由用例
在 smoke/conftest.py 的pytest_runtest_setup钩子中,pytest 读取用例上的smoke_targetmarker(例如smoke/product/test_api_product_live.py顶部pytestmark = [pytest.mark.live, pytest.mark.smoke_target("api")]),若该 Target 不在FCC_SMOKE_TARGETS解析结果中,则直接pytest.skip("smoke target disabled: ...")——这就是"Target 裁剪"机制的实现入口,也是失败分类中target_disabled的来源。
六、实战示例:八组典型运行
smoke/README.md 提供了覆盖多 Provider 矩阵、本地服务器、消息平台、NIM/OpenRouter CLI 矩阵与单用例回归的完整示例,全部继承如下(并补充必要注释):
1)多 Provider 矩阵(本地 + 云端混合)
$env:FCC_LIVE_SMOKE = "1" $env:FCC_SMOKE_PROVIDER_MATRIX = "open_router,nvidia_nim,deepseek,lmstudio,llamacpp,ollama" uv run pytest smoke/product -n 0 -s --tb=shortFCC_SMOKE_PROVIDER_MATRIX以逗号分隔 Provider 前缀,限定只有这些 Provider 参与场景;此例把云端(open_router / nvidia_nim / deepseek)与本地(lmstudio / llamacpp / ollama)六类后端一并验证。
2)仅针对 Ollama 的 prereq + product 组合
$env:FCC_LIVE_SMOKE = "1" $env:FCC_SMOKE_TARGETS = "ollama" $env:OLLAMA_BASE_URL = "http://localhost:11434" uv run pytest smoke/prereq smoke/product -n 0 -s --tb=short先跑smoke/prereq中的存活探针(本地/v1/models可达性),再跑smoke/product中的 Ollama OpenAI-chat 代理 Messages 场景,二者共用同一OLLAMA_BASE_URL。
3)消息平台 + 语音后端
$env:FCC_LIVE_SMOKE = "1" $env:FCC_SMOKE_TARGETS = "telegram,discord,voice" $env:FCC_SMOKE_RUN_VOICE = "1" uv run pytest smoke/product -n 0 -s --tb=short注意语音需要显式FCC_SMOKE_RUN_VOICE=1,否则语音后端不会加载(见 smoke/lib/config.py 的TARGET_REQUIRED_ENV)。
4)NVIDIA NIM CLI 矩阵
$env:FCC_LIVE_SMOKE = "1" $env:FCC_SMOKE_TARGETS = "nvidia_nim_cli" $env:FCC_SMOKE_NIM_MODELS = "nvidia/nemotron-3.5-lightning-30b-a3b,moonshotai/kimi-k3,minimaxai/minimax-m3,nvidia/nemotron-3-super-120b-a12b" uv run pytest smoke/product -n 0 -s --tb=shortFCC_SMOKE_NIM_MODELS替换默认特征化模型集(默认集定义于 smoke/lib/config.py 的NVIDIA_NIM_CLI_DEFAULT_MODELS);若只传FCC_SMOKE_NIM_EXTRA_MODELS,则会在默认集之后追加模型(nvidia_nim_cli_model_refs中的去重与顺序保证见 smoke/lib/config.py)。
5)OpenRouter 免费 CLI 矩阵
$env:FCC_LIVE_SMOKE = "1" $env:FCC_SMOKE_TARGETS = "openrouter_free_cli" $env:FCC_SMOKE_OPENROUTER_FREE_MODELS = "nvidia/nemotron-3-super-120b-a12b:free,poolside/laguna-s-2.1:free,poolside/laguna-xs-2.1:free" uv run pytest smoke/product -n 0 -s --tb=short与 NIM 矩阵同理,FCC_SMOKE_OPENROUTER_FREE_MODELS替换默认集(默认集见OPENROUTER_FREE_CLI_DEFAULT_MODELS),_EXTRA_MODELS变体追加。
6)Claude Auto mode + OpenAI 已连接账号的单用例回归
$env:FCC_LIVE_SMOKE = "1" $env:FCC_SMOKE_TARGETS = "cli" $env:FCC_SMOKE_PROVIDER_MATRIX = "openai" $env:FCC_SMOKE_MODEL_OPENAI = "gpt-5.6-luna" uv run pytest smoke/product/test_client_product_live.py -n 0 -s --tb=short -k claude_auto_mode_openai_connected通过-k关键字精确筛选claude_auto_mode_openai_connected用例;FCC_SMOKE_MODEL_OPENAI为该 Provider 指定 smoke 模型(connected-account 类 Provider 的配置判定依赖该变量,见 smoke/lib/config.py)。
7)无副作用 Target 的快速回归
$env:FCC_LIVE_SMOKE = "1" $env:FCC_SMOKE_TARGETS = "messaging,config,extensibility" uv run pytest smoke/product -n 0 -s --tb=short这三类 Target 都不需要外部凭据:messaging 走 fake 平台,config/extensibility 使用隔离 env 文件,可随时安全回归。
8)NVIDIA NIM 视觉回归(PowerShell 与 POSIX 双版本)
$env:FCC_LIVE_SMOKE = "1" $env:FCC_SMOKE_TARGETS = "nvidia_nim_vision" $env:FCC_SMOKE_MODEL_NVIDIA_NIM_VISION = "meta/llama-3.2-11b-vision-instruct" uv run pytest smoke/product/test_nvidia_nim_vision_product_live.py -n 0 -s --tb=shortFCC_LIVE_SMOKE=1 \ FCC_SMOKE_TARGETS=nvidia_nim_vision \ FCC_SMOKE_MODEL_NVIDIA_NIM_VISION=meta/llama-3.2-11b-vision-instruct \ uv run pytest smoke/product/test_nvidia_nim_vision_product_live.py -n 0 -s --tb=shortFCC_SMOKE_MODEL_NVIDIA_NIM_VISION是必填显式视觉模型(见 smoke/lib/config.py 的nvidia_nim_vision_model:只有设置了该变量才返回模型,且绝不会回退到文本模型),这正是 smoke/features.py 中vision_protocol_matrix特性 "skip unless the dedicated vision target and explicit model are configured" 策略的实现基础。
七、Codex Code session 模式专项
7.1 本地模拟 Provider 下的四种模式
smoke/README.md 为 Codex 提供专项运行:用本地模拟 Provider驱动已安装的 Codex,使用一次性 session 与文件夹,验证Ask、Auto-review、Full access、返回 Use config四种权限模式,并检查"子代理 review 在父回复之后完成"及后续消息的延续行为,全程不消耗 Provider 配额:
$env:FCC_LIVE_SMOKE = "1" $env:FCC_SMOKE_TARGETS = "clients" uv run pytest smoke/product/test_codex_modes_product_live.py -n 0 -s -k local_e2e对应用例(test_codex_modes_local_e2e、test_codex_child_review_local_e2e)在 smoke/features.py 的code_session_modes特性中登记,契约层由 tests/application/test_code_sessions.py、tests/runtime/test_codex_app_server.py 等共同保护。
7.2 真实模型 smoke(严格零成本路由)
若要做真实推理验证,设置FCC_SMOKE_CODEX_FREE_MODEL为显式选择的open_router/<model>引用,并以-k free_provider_e2e运行同一文件。该用例会检查 OpenRouter 当前 prompt 与 completion 价格均为零,且只使用该路由,绝不回退到付费模型。本地用例不需要该设置与任何 Provider 凭据。两次运行都会打印已安装的 Codex 版本;受限模式要求原生 sandbox 支持,且绝不会替你设置 sandbox 或改动你的 Codex 配置。
八、完整环境变量参考
smoke/README.md 的 Environment 一节定义了全部运行时变量;结合 smoke/lib/config.py 的SmokeConfig.load()可看到每个变量的默认值与解析逻辑:
| 变量 | 作用 | 默认值 / 说明 |
|---|---|---|
FCC_LIVE_SMOKE=1 | 开启 live smoke 执行 | 未设置时全部用例被conftest.py跳过 |
FCC_ALLOW_NO_PROVIDER_SMOKE=1 | 允许无 Provider 的 live smoke(harness 开发用) | 默认无 Provider 时 product smoke 以missing_env失败 |
FCC_SMOKE_TARGETS | 逗号分隔 Target 列表或all | 默认DEFAULT_TARGETS;支持别名归一化 |
FCC_SMOKE_PROVIDER_MATRIX | 逗号分隔的 Provider 前缀白名单 | 为空表示不限制 |
FCC_SMOKE_MODEL_<PROVIDER> | 单个 Provider 的 smoke 模型覆盖 | 使用大写 Provider ID,如FCC_SMOKE_MODEL_KILO;值可含 Provider 前缀或仅为模型名 |
FCC_SMOKE_MODEL_NVIDIA_NIM_VISION | NIM 视觉模型(opt-innvidia_nim_vision必填) | 绝不回退文本模型 |
FCC_SMOKE_MODEL_MISTRAL_REASONING | Mistral 原生 reasoning smoke 模型覆盖 | 默认mistral/mistral-medium-3-5 |
FCC_SMOKE_NIM_MODELS | NIM CLI 矩阵模型(替换默认集) | 默认见NVIDIA_NIM_CLI_DEFAULT_MODELS;置空会报错 |
FCC_SMOKE_NIM_EXTRA_MODELS | NIM CLI 矩阵追加模型 | 在默认/替换集之后追加并去重 |
FCC_SMOKE_OPENROUTER_FREE_MODELS | OpenRouter 免费 CLI 矩阵模型(替换默认集) | 默认见OPENROUTER_FREE_CLI_DEFAULT_MODELS |
FCC_SMOKE_OPENROUTER_FREE_EXTRA_MODELS | OpenRouter 免费 CLI 矩阵追加模型 | 追加语义同上 |
FCC_SMOKE_TIMEOUT_S | 每次请求/子进程超时 | 默认45秒 |
FCC_SMOKE_CLAUDE_BIN | Claude CLI 可执行文件名 | 默认claude |
FCC_SMOKE_RUN_WEB_TOOLS=1 | 启用真实 Provider 自动 WebSearch + 已安装 Claude Code WebSearch 场景(含一次公开 DuckDuckGo 请求) | 默认关闭 |
FCC_SMOKE_TELEGRAM_CHAT_ID | Telegram chat/user ID(send/edit/delete) | 配合TELEGRAM_BOT_TOKEN |
FCC_SMOKE_DISCORD_CHANNEL_ID | Discord channel ID(send/edit/delete) | 配合DISCORD_BOT_TOKEN |
FCC_SMOKE_INTERACTIVE=1 | 启用 Telegram/Discord 手动 inbound 检查 | 默认关闭 |
FCC_SMOKE_RUN_VOICE=1 | 允许语音转录后端加载/运行 | 默认关闭 |
此外两点运行时细节值得注意:
- 运行设置使用隔离的受管
~/.fcc/.env;FCC_ENV_FILE只在一次性 legacy 迁移 smoke 中被使用(对应removed_env_migration特性)。 - 测试内的默认提示词为
FCC_SMOKE_PROMPT(默认Reply with exactly: FCC_SMOKE_PONG),用于校验真实 Provider 的确定性回复。
九、Windows 与嵌套uv run的坑
smoke/README.md 明确提示:子进程使用与测试运行器相同的 Python 解释器,而不是嵌套uv run。原因在 smoke/lib/child_process.py 的模块注释中讲得很透彻:
Nested
uv runcan try to refresh console scripts while they are locked (fcc-server.exein use), causing flaky smoke.
即嵌套uv run可能在fcc-server.exe被占用时尝试刷新 console scripts,导致 Windows 上锁冲突与 smoke 抖动。因此cmd_fcc_server()与cmd_fcc_version()都直接以sys.executable -c "from free_claude_code.cli.entrypoints import serve; serve()"启动(见 smoke/lib/child_process.py)。同样地,smoke/lib/server.py 的start_server在启动本地 smoke 服务器时,会通过find_free_port()寻找空闲端口,设置HOST=127.0.0.1、MESSAGING_PLATFORM=none、FCC_OPEN_BROWSER=0等隔离环境,然后轮询/health(超时即probe_timeout语义),并把进程日志写入.smoke-results/。
十、失败分类体系:triaging 的核心语言
所有 smoke 产物写入.smoke-results/,且会对名称包含KEY、TOKEN、SECRET、WEBHOOK或AUTH的环境变量值做脱敏(SECRET_KEY_PARTS,实现见 smoke/lib/config.py 的redacted函数)。
10.1 六类分类
| 类别 | 含义 | 是否失败 |
|---|---|---|
missing_env | 缺少必需凭据、二进制、Provider 配置、本地 Provider 服务器/模型或 opt-in 标志 | 默认 skip;显式选中时失败 |
upstream_unavailable | 真实 Provider 或 bot API 不可达 | 默认 skip;显式选中时失败 |
probe_timeout | smoke 驱动到达目标,但 CLI/探针未在超时内完成 | 默认 skip;显式选中时失败 |
product_failure | 应用接受场景但返回错误形状、崩溃、泄漏状态或违反产品契约 | 失败 |
harness_bug | smoke 测试或驱动自身做了无效假设 | 失败 |
target_disabled | 因FCC_SMOKE_TARGETS有意选择了其他 Target 而跳过 | skip |
10.2 分类规则的三条主线
product_failure与harness_bug是真正失败;missing_env、upstream_unavailable、probe_timeout默认是 skip。- 例外:当用户通过
FCC_SMOKE_PROVIDER_MATRIX显式选中了某个 Provider 时,选中但缺失的 Provider 会升级为失败(对应 smoke/features.py 中provider_matrix的 skip_policy:"selected providers missing credentials are failing missing_env")。 - 分类不是靠猜:
upstream_unavailable由 smoke/lib/outcomes.py 的is_upstream_unavailable_text依据具体信号判定——包括connection refused、connect timeout、read timeout、service unavailable、rate limit exceeded、overloaded、at capacity等文本标记,以及匹配429/5xx的 HTTP 状态正则;target_disabled则由conftest.py的 skip reason "smoke target disabled" 识别。
10.3 报告产物
pytest_sessionfinish 钩子在会话结束时调用SmokeReport.write()(实现见 smoke/lib/report.py),把每条用例的 nodeid、outcome、classification、duration、markers 与脱敏后的 detail 写入report-<worker>-<timestamp>.json。由于文件名携带worker_id(来自PYTEST_XDIST_WORKER,默认main),并行运行时每个 worker 各写一份报告,方便按 worker 归并分析。
十一、源码中的特性清单速览
smoke/features.py 的FEATURE_INVENTORY是套件的"唯一事实源":任何公共产品行为都必须在此登记契约测试与产品 E2E 场景。按业务域归纳:
- 接入兼容层:
drop_in_claude_code_replacement、drop_in_codex_replacement、anthropic_api_routes、claude_auto_mode_classifier、vscode_extension、intellij_extension; - CLI/harness 层:
pi_cli_integration、opencode_cli_integration、aider_cli_integration、cline_cli_integration、hermes_cli_integration、dsh_cli_integration、grok_cli_integration、muse_cli_integration、package_cli_entrypoints、claude_cli_drop_in; - Provider 与路由层:
provider_matrix、zero_cost_provider_access、per_model_mapping、mixed_provider_mapping、model_fallback、provider_hot_swap、smart_rate_limiting; - 协议转换层:
thinking_token_support、native_tool_assembly、vision_protocol_matrix、streaming_error_mapping、count_tokens_contract; - 本地端点层:
lmstudio_endpoint、llamacpp_endpoint、ollama_endpoint; - 消息平台层:
discord_telegram_bot、messaging_commands、tree_threading、restart_restore、session_persistence、subagent_control、voice_notes; - 配置与扩展层:
config_env_precedence、removed_env_migration、extensible_provider_platform_abcs、provider_proxy_timeout_config、request_optimization、optional_authentication、probe_routes、code_session_modes。
每个特性条目都给出skip_policy(何时跳过、何时必须失败)与required_env(所需环境),例如code_session_modes的策略是"本地行为在 Codex 与原生 sandbox 前提可用时必须通过;免费推理需显式选择并校验价格",voice_notes的策略是"fake 取消流程必跑,后端转录为 opt-in"。这份清单既是对照表,也是排查"某个功能为何被跳过"的权威依据。
十二、总结:如何把 smoke/ 用起来
把整套体系收敛为一张可操作清单:
- 先收集:
uv run pytest smoke --collect-only -q预览用例;未设FCC_LIVE_SMOKE=1时一切都会被跳过,但这本身就能验证收集与参数化是否正确。 - 按 Target 裁剪:用
FCC_SMOKE_TARGETS指定要验证的模块(api/providers/clients/messaging/ollama等),conftest.py会跳过未选中的 Target。 - 控制 Provider 范围:
FCC_SMOKE_PROVIDER_MATRIX限定参与 Provider;FCC_SMOKE_MODEL_<PROVIDER>覆盖单 Provider 模型;显式选中的 Provider 缺失时升级为失败。 - 并行与顺序:无状态 Target 用
-n auto --dist=loadgroup跨 Provider 并行;涉及 CLI 子进程、消息平台、语音的场景用-n 0保序。 - 解读结果:打开
.smoke-results/report-*.json,按六类分类 triage——product_failure与harness_bug必须修复;missing_env/upstream_unavailable/probe_timeout在未显式选中时属于环境性 skip;target_disabled表示未选中该 Target。 - Windows 注意:子进程复用同一解释器,不要嵌套
uv run,避免fcc-server.exe锁冲突。
这套"契约测试(tests)+ 存活探针(prereq)+ 产品 E2E(product)+ 失败分类(outcomes)"的四层体系,把 free-claude-code 的复杂能力矩阵(多协议转换、多 harness 接入、多 Provider 路由、消息平台与语音)变成了可裁剪、可并行、可 triage 的本地验证流程,是任何想为该项目贡献或深度集成前必备的验证手段。
- LLM 网关
- 大模型
- 后端
- AI 应用
【免费下载链接】free-claude-code
Use Claude Code, Codex, VSCode, Pi, and OpenCode (and 6 other harnesses) for free (1.3B+ free tokens) from your terminal, app, IDE, or phone, and now from the browser with native browser sessions (multi-harness + multi-model) like OpenClaw (voice supported + ToS friendly)
相关推荐
Sunshine 自托管游戏串流入门:三步跑通 4K60 串流
Sunshine 自托管游戏串流入门:三步跑通 4K60 串流 Sunshine 是一个自托管的游戏串流主机:装在你的 PC 上,画面实时编码后推送给 Moon
音视频后端gitsigns.nvim 测试指南:命令体系、版本矩阵与确定性测试实践
gitsigns.nvim 测试指南:命令体系、版本矩阵与确定性测试实践 本篇技术指南围绕 gitsigns.nvim 仓库的 etc/testing.md h
开发工具DeepChat E2E Smoke 冒烟测试体系详解:从 Playwright 配置到本地流式渲染验证
DeepChat E2E Smoke 冒烟测试体系详解:从 Playwright 配置到本地流式渲染验证 本指南围绕 DeepChat 仓库中的端到端冒烟测试套
AI Agent人工智能AI 应用桌面应用MCP Clients
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考