ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

MQTT-Explorer LLM 集成测试调试指南:CI 工作流步骤顺序修复与环境变量注入实践

MQTT-Explorer LLM 集成测试调试指南:CI 工作流步骤顺序修复与环境变量注入实践 开发工具物联网消息队列【免费下载链接】MQTT-ExplorerAn all-round MQTT client that provides a structured topic overview项目地址https://gitcode.com/gh_mirrors/mq/MQTT-Explorer点击查看免费下载LLM_TESTS_DEBUG.md 记录了 MQTT-Explorer 在接入 LLMAI Assistant集成测试时遇到的一个典型 CI 故障——GitHub Actions 工作流中.env.llm-tests环境文件因「先写文件、后 Checkout」的步骤顺序错误而被工作区覆盖丢失以及后续的环境变量注入、测试开关与 jsdom 网络限制的排查与修复过程。读完本文你将掌握该仓库 LLM 集成测试的完整调试思路、可复用的修复模式以及本地开发与 CI/CD 中运行「离线测试 在线 LLM 实测」两套测试体系的实操方法。一、问题背景LLM 集成测试的运行前提MQTT-Explorer 的 AI AssistantLLM 集成在 LLM_INTEGRATION.md 中已有完整设计前端通过 WebSocket RPC 与后端通信后端持有 API Key代理所有 LLM 请求。为了保证这个功能的质量仓库在 app/src/services/spec/ 目录下维护了三类测试单元测试llmService.spec.ts覆盖parseResponse()、getQuickSuggestions()、hasApiKey()等 LLM Service 方法提案校验测试llmProposals.spec.ts校验 Topic 格式、Payload 合法性、QoS 取值、Description 质量实时 LLM 集成测试llmIntegration.spec.ts真实调用 OpenAI/Gemini API验证系统识别zigbee2mqtt、Home Assistant、Tasmota、提案质量、边界情况与问题生成质量。其中第三类测试是**选择性opt-in**的需要同时满足两个条件才会真正执行见 app/src/services/spec/llmIntegration.spec.tsconst shouldRunLLMTests process.env.RUN_LLM_TESTS true const hasApiKey !!process.env.OPENAI_API_KEY || !!process.env.GEMINI_API_KEY || !!process.env.LLM_API_KEY也就是说必须有RUN_LLM_TESTStrue环境变量且至少注入一个 API Key。这看似简单却正是本次调试的核心战场——如何把 API Key 安全、可靠地注入到 CI 环境并让测试真正跑起来。二、核心问题GitHub Workflow 步骤顺序缺陷文档明确指出.github/workflows/copilot-setup-steps.yml存在一个致命步骤顺序问题。修复前的执行流程是创建.env.llm-tests文件写入 API Key 与测试开关Checkout 代码 ←这一步会用仓库内容覆盖工作目录导致刚创建的.env.llm-tests被整体清除运行测试GitHub Actions 的actions/checkout会重置工作目录任何在 checkout 之前写入的未跟踪文件都会丢失。于是测试运行时环境文件已不存在RUN_LLM_TESTS与 API Key 自然全部缺失LLM 集成测试被静默跳过而 CI 日志往往只会显示一个含糊的 skipped排查难度极高。修复后的正确顺序是先 Checkout 代码再创建.env.llm-tests此时文件才能在工作区中持久存在运行测试从当前仓库 .github/workflows/copilot-setup-steps.yml 可以看到修复后的实际形态——Checkout code步骤位于最前紧随其后的Persist Secrets to Agent Environment步骤负责写入环境文件steps: - name: Checkout code uses: actions/checkoutv6 - name: Persist Secrets to Agent Environment run: | echo export OPENAI_API_KEY${{ secrets.OPENAI_API_KEY }} .env.llm-tests echo export RUN_LLM_TESTStrue .env.llm-tests chmod 600 .env.llm-tests echo ✅ Created .env.llm-tests file ls -la .env.llm-tests修复中引入的四项关键改动文档总结的改动点逐一对应到上述 YAML每一项都有其明确目的改动目的实现位置将「Persist Secrets」步骤移到「Checkout code」之后避免 checkout 覆盖工作区、丢失环境文件.github/workflows/copilot-setup-steps.yml为环境变量添加export前缀使文件可通过source .env.llm-tests正确注入当前 shell而不是以普通赋值形式存在同上echo export OPENAI_API_KEY... .env.llm-tests追加RUN_LLM_TESTStrue显式启用 live 测试避免「有 Key 但测试仍跳过」的隐性失效同上echo export RUN_LLM_TESTStrue .env.llm-testschmod 600将文件权限收紧为仅属主可读写防止敏感 Key 被同环境其他用户读取同上chmod 600 .env.llm-tests验证日志ls -la echo确认文件确实创建成功为后续排障提供证据同上值得注意的是工作流环境块中还配置了TESTS_MQTT_BROKER_HOST: localhost、TESTS_MQTT_BROKER_PORT: 1883与OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}其中 secrets 通过环境变量传入再被第二步固化到.env.llm-tests中形成「GitHub Secrets → 环境变量 → 文件 → shell source」的注入链。三、环境变量注入机制验证从手动创建到一键脚本文档用一段最小化 bash 验证了.env.llm-tests的创建与 source 机制# 创建 .env 文件 echo export OPENAI_API_KEYsk-your-key .env.llm-tests echo export RUN_LLM_TESTStrue .env.llm-tests # Source 并验证 source .env.llm-tests echo $OPENAI_API_KEY # 输出 Key说明注入成功仓库在此基础上提供了两个一键脚本把上述流程产品化1. 环境搭建脚本 scripts/setup-llm-env.sh该脚本的核心逻辑是读取当前环境中的注入 secrets按优先级写入$REPO_ROOT/.env.llm-tests检测到OPENAI_API_KEY→ 写入export OPENAI_API_KEY...export RUN_LLM_TESTStrue检测到GEMINI_API_KEY→ 写入对应的 Gemini 配置 测试开关检测到通用LLM_API_KEY→ 额外写入export LLM_PROVIDER${LLM_PROVIDER:-openai}generic key 需要显式指定 provider三种 Key 都不存在 → 打印手工创建指引并以退出码 1 结束避免静默失败。写入完成后同样执行chmod 600 $ENV_FILE并在末尾提示永远不要把这个文件提交到版本控制已加入.gitignore。2. 测试运行脚本 scripts/run-llm-tests.sh该脚本负责完整的前置校验与执行set -e任何一步失败立即中断防止半失败状态被误判为成功校验OPENAI_API_KEY/GEMINI_API_KEY/LLM_API_KEY至少存在其一否则打印三种 Key 的用法并exit 1提供方自动识别检测到 OpenAI Key 时默认LLM_PROVIDERopenai检测到 Gemini Key 时默认LLM_PROVIDERgemini通用 Key 默认走openai强制export RUN_LLM_TESTStrue进入app/目录执行yarn test。这也解释了文档中「Provider auto-detection (OpenAI/Gemini)」这一已验证项的来源——两个脚本与测试入口 app/src/services/spec/llmIntegration.spec.ts 中的getProvider()逻辑相互印证const getProvider (): openai | gemini | null { if (process.env.OPENAI_API_KEY) return openai if (process.env.GEMINI_API_KEY) return gemini if (process.env.LLM_API_KEY process.env.LLM_PROVIDER) { return process.env.LLM_PROVIDER as openai | gemini } return null }三个层级shell 脚本、测试文件、服务层对提供方识别逻辑保持了一致这也是「Provider auto-detection 已验证」能被端到端确认的原因。四、测试检测与跳过行为的源码级验证文档描述的「测试能正确检测 API Key、启用 live 执行不跳过、输出 provider 识别日志」可以直接在测试代码中找到对应实现app/src/services/spec/llmIntegration.spec.tsbefore(function () { if (!shouldRunLLMTests) { console.log(Skipping LLM integration tests: RUN_LLM_TESTS not set to true) this.skip() } if (!hasApiKey) { console.warn(Skipping LLM integration tests: No API key found) this.skip() } if (!provider) { console.warn(Skipping LLM integration tests: Could not determine provider) this.skip() } console.log(Running LLM integration tests with provider: ${provider}) })可见跳过逻辑是分层守卫的RUN_LLM_TESTS未设置、无 API Key、无法识别 provider三种情况任一成立都会this.skip()并打印明确的原因日志。这解释了调试时的核心排查原则——先看测试是否在跑再看跑的是离线还是在线。若 CI 日志中出现 skip 提示第一反应应是检查RUN_LLM_TESTS与 Key 注入是否真正落到了执行测试的那个 shell 环境。在线测试的判定标准与耗时预期可见 docs/LLM_TEST_RESULTS.md离线测试 100 个用例全部通过、约 2 秒完成在线 LLM 集成测试 11 个用例、约 20-30 秒完成单用例耗时普遍在 1.5-2.3 秒区间真实 API 往返因此测试套件把this.timeout(60000)放宽到 60 秒以容纳 API 延迟。五、当前限制jsdom 环境中的网络错误文档记录了当前已知限制——在 jsdom 测试环境中调用真实 LLM API 会失败Error: Cross origin null forbidden Error: LLM API call failed: Network Error原因分析是明确的测试运行在 jsdom 模拟的 DOM 环境而非真实浏览器测试代码通过axios直接发起 HTTP 请求见 app/src/services/spec/llmIntegration.spec.tsjsdom 对跨域请求施加 CORS 限制导致Cross origin null forbidden因此实时 API 测试需要真正的 Node.js 环境或网络请求 mock。这一点值得特别注意生产架构中 LLM 请求是通过后端 WebSocket RPC 代理的见 app/src/services/llmService.ts 中backendRpc.call(RpcEvents.llmChat, ...)而测试为了独立于后端、直接验证 LLM 输出质量选择了直连 API 的方式所以在 jsdom 下必然受限。这是测试直连与生产代理两种路径的架构差异所致不是缺陷而是设计取舍。六、推荐的运行方案本地开发在 Node 环境中运行文档给出的本地运行方式与仓库脚本一致source .env.llm-tests cd app yarn test更推荐直接使用一键脚本脚本内部已处理 provider 识别与测试开关OPENAI_API_KEYsk-your-key ./scripts/run-llm-tests.sh手动方式的完整等价命令与 app/src/services/spec/README.md 中的说明一致export OPENAI_API_KEYsk-your-key export RUN_LLM_TESTStrue cd app yarn test执行后应能在控制台看到 provider 识别日志Running LLM integration tests with provider: openai随后是 zigbee2mqtt 系统识别、提案质量校验、边界情况、问题生成四组在线用例的逐个执行与通过结果。CI/CD 中的分层策略文档建议 CI 采用分层策略app/src/services/spec/README.md 给出了对应的 GitHub Actions 示例常规 CI默认只跑离线测试无需 API Key快速、确定性、零成本定时任务如 nightly通过secrets.OPENAI_API_KEY注入 Key 并设置RUN_LLM_TESTS: true运行在线实测网络与 mock 兜底若必须在 jsdom 环境跑在线逻辑考虑用 nock 或 msw mock HTTP 请求或在有真实网络访问权限的 Job 中执行。关键运维纪律同样适用于本仓库任何含 Key 的流程API Key 一律走 secrets 管理严禁硬编码或提交.env.llm-tests不纳入版本控制.gitignore已排除定期轮换 Key 并在供应商控制台监控用量与设置计费告警可参考 ENV_VARS_EXAMPLE.md 的 Security Recommendations。七、已验证工作项与调试结论文档末尾的 Verified Working 清单结合本次源码核对可以给出如下对应关系已验证项对应实现/证据✅ 工作流创建.env.llm-tests步骤顺序已修复.github/workflows/copilot-setup-steps.yml✅setup-llm-env.sh创建环境文件scripts/setup-llm-env.sh✅ 环境变量 source 机制export前缀 source .env.llm-tests✅ 测试检测 API Keyapp/src/services/spec/llmIntegration.spec.ts✅ Provider 自动识别OpenAI/Geminiapp/src/services/spec/llmIntegration.spec.ts 与 scripts/run-llm-tests.sh✅ 无 API Key 时的正确跳过行为app/src/services/spec/llmIntegration.spec.ts 三层守卫最终结论LLM 测试基础设施现已正常工作。核心修复只需把「Persist Secrets」步骤移到「Checkout code」之后配合export前缀、RUN_LLM_TESTStrue开关、chmod 600权限收紧与创建验证日志即可让 API Key 稳定穿越 checkout 阶段并到达测试进程。而 jsdom 网络限制属于环境能力边界不是基础设施故障——线上实测应放在 Node 环境或具备真实网络访问的 CI Job 中执行。八、调试思路沉淀三个可复用原则步骤顺序先于脚本内容GitHub Actions 中 checkout、缓存恢复、secrets 写入的先后顺序决定了文件能否存活到后续步骤。凡是在 checkout 之前写工作区文件的做法都应视为反模式。跳过不是通过测试静默 skip 时 CI 依然是绿色但功能质量无人把关。RUN_LLM_TESTStrue显式开关 skip 原因日志是让「该测没测」变得可见的关键设计。注入链每一环都要有证据从 Secrets 环境变量到.env文件再到 shell source每一环都应像工作流中的ls -la那样留有验证输出排障时才能快速定位断点。如需进一步了解 LLM 功能的完整配置LLM_PROVIDER、OPENAI_API_KEY、GEMINI_API_KEY、LLM_API_KEY、LLM_NEIGHBORING_TOPICS_TOKEN_LIMIT及其优先级、Token 上下文截断对提案质量的影响可继续阅读 LLM_INTEGRATION.md 与 ENV_VARS_EXAMPLE.md在线测试的完整示例输出与验收标准见 docs/LLM_TEST_RESULTS.md。赞分享开发工具物联网消息队列【免费下载链接】MQTT-ExplorerAn all-round MQTT client that provides a structured topic overview项目地址https://gitcode.com/gh_mirrors/mq/MQTT-Explorer点击查看免费下载相关推荐Tsuru环境变量注入工具集成CI/CD流程的终极指南Tsuru环境变量注入工具集成CI/CD流程的终极指南 在现代软件开发中持续集成和持续部署CI/CD已成为不可或缺的环节。Tsuru作为开源的可扩展平台后端云原生容器编排DevOpsWoodpecker CI 环境变量完全指南步骤级注入、内建 CI 变量与字符串替换Woodpecker CI 环境变量完全指南步骤级注入、内建 CI 变量与字符串替换 本篇技术指南以 Woodpecker一个简单而强大的 CI/CD 引擎CI/CDDevOpsAkka远程通信构建分布式系统的通信机制和网络配置Akka远程通信构建分布式系统的通信机制和网络配置 Akka远程通信是构建分布式系统的核心组件它允许不同JVM中的Actor通过网络进行高效通信。本文将详细示例工程后端软件架构上一篇使用 ag-ui Java Client 连接远程 AG-UI AgentHttpAgent、SSE 事件流与传输层定制实战下一篇electron-vue 静态资源使用指南理解 static/ 目录与 __static 全局变量创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表