揭秘Skill测试3大方案Pytest精准断言、Agent自动化回归、LVMLLM多模态评测如果你正在做Agent开发大概率已经遇到过这种尴尬写一个Skill技能模块只需要半天但怎么证明它“真的能用”却要折腾一周。普通单元测试只能验证函数不报错却验证不了“大模型有没有按照Skill里的步骤执行”这件事。更麻烦的是一个Skill可能同时涉及工具调用、Prompt模板、上下文拼接和视觉输入任何一个环节微调都可能让输出从“看起来还行”变成“完全不可用”。很多团队的Skill测试还停留在“人工点几个样例看输出合理就上线”的阶段。这在Demo阶段没问题但一旦Skill数量超过10个、Agent开始对外服务缺乏自动化测试会让每次迭代都像走钢丝——你完全不知道这次改动破坏了哪个下游流程。这篇文章不聊虚的直接给出三条经过项目验证的Skill测试路径Pytest框架做确定性断言Agent编排做端到端回归LVMLLM做多模态语义评测。读完你会明白每套方案的适用边界、成本构成以及它们如何组合成一套完整的Skill质量保障体系。1. 这篇文章真正要解决的问题先说一个容易被忽视的事实Skill和普通代码模块有本质区别。普通函数有明确的输入输出签名你传入参数、拿到返回值、断言结果测试就结束了。但Skill是给大模型用的“能力封装”它的输入往往是一段自然语言任务描述输出是模型推理后的结果中间还可能穿插工具调用、外部API请求、多轮对话状态管理。这意味着Skill测试面临三个传统测试没有的挑战第一结果不确定性。同一个Skill相同的输入模型输出可能有细微差异。如果按“断言字符串完全相等”的思路写测试大概率会得到一堆必挂的用例。你需要的是“模糊断言”或“语义断言”。第二链路复杂性。一个Skill可能依赖其他Skill、系统提示词、知识库检索结果、Agent的全局记忆。单测很难把整条链路全部Mock但又不能只在集成环境验证因为排错成本太高。第三多模态输入输出。现在的Skill已经不只在处理纯文本了。不少Agent需要读取截图、解析表格、识别UI元素输出也可能包含图片或结构化数据。纯文本断言在这一层等于失效。这篇文章想解决的问题就是如何建立一套分层的Skill测试体系让“确定性逻辑”用Pytest锁死“复杂Agent流程”用自动化回归兜底“视觉与语义质量”用LVMLLM做机器评测。2. 核心概念与适用场景在进入实操之前先把标题里的几个关键词在“测试语境”下的定位理清楚。很多读者第一次看到“PytestAgentSkillsLVMLLM”这个组合会觉得乱实际上它们分别解决不同层级的问题。2.1 Skill被测对象Skill不是普通的Python函数而是“可复用能力的最小封装”。在大型语言模型应用中Skill通常包含技能描述和触发条件。Prompt模板或指令文本。可选的工具调用逻辑。输入输出格式定义。使用约束或校验规则。从工程角度看Skill是连接“模型能力”和“业务场景”的中间层。它的质量直接决定Agent执行任务的稳定程度。2.2 Pytest确定性测试框架Pytest是Python生态最成熟的测试框架它在Skill测试里的定位是守住确定性边界。所谓确定性边界指的是不依赖模型推理结果的部分比如Skill的Prompt模板是否正确渲染。参数校验是否生效。工具调用的参数是否拼接正确。返回的JSON结构是否符合契约。异常分支是否正确触发。这些部分虽然包裹在Skill里但本质上是确定的代码逻辑必须用Pytest锁定。它可以做到面对非确定性输出也能够验证方案适合测试“结构化输出契约”是否被遵守但Pytest不能轻易判断「回答得对不对」这就需要用大模型去判断。2.3 Agent端到端执行载体Agent是Skill的运行环境。在实际项目中Skill很少被单独调用而是由Agent根据用户任务自动选择和编排。因此测试Skill必须同时测试Agent的调度逻辑否则只能验证“Skill在孤立环境里正常”无法验证“Agent真的会在正确时机调用Skill”。这也是为什么很多团队最终会走上“Agent自动化回归”这条路把测试用例变成“用户会话”让Agent自主走完整个流程再检查最终效果。2.4 LLM语义评测器LLM在Skill测试中的作用有两种。第一种是被测对象——你的Skill本身就在调用大模型。第二种是评测工具——用一个大模型去检查另一个大模型或Skill的输出质量。这里有个非常重要的认知用LLM评测LLM不是银弹但它在语义判断上的稳定性远超关键词匹配。你可以让评测模型判断“输出是否包含必要信息”“语气是否符合要求”“是否偏离了用户原意”这是Pytest很难直接做到的。更关键的是LLM评测可以设计成结构化打分输出JSON格式的评分和理由方便纳入CI流程。2.5 LVM视觉能力评测器LVMLarge Vision Model大视觉模型解决的是“看图说话”类验证。如果被测Skill涉及截图识别、图像分类、UI自动化、图表理解就需要LVM来观察模型“看到了什么”。代码层如果出现“LVM”这个词读者在百度热搜词里会看到“不创建lvm能用吗”“lvm分区报老是报io错误”这类搜索容易误解。所以先说明本文的LVM指的是大视觉模型Large Vision Model而不是Linux的LVM逻辑卷管理Logical Volume Manager。如果你搜索LVM发现大量分区扩容教程说明你搜到了Linux方向——那个LVM也可以做测试但那是运维场景不在本文讨论范围。三者合在一起就形成一条完整的评测链路Pytest管“代码正确性”。Agent管“流程正确性”。LVMLLM管“语义和视觉质量”。工具/概念在Skill测试中的角色典型验证内容Skill被测对象能力模块、Prompt模板、工具调用Pytest确定性测试框架参数校验、输出结构、异常处理Agent端到端执行载体调度逻辑、多轮对话、工具调用顺序LLM语义评测器回答质量、指令遵循度、信息完整性LVM视觉能力评测器截图识别、图像理解、UI元素定位3. 方案一Pytest Skill 单元级测试先说方案一这是成本最低、见效最快的一层。虽然名字叫“单元级测试”但它并不是简单的函数测试而是把Skill里所有确定性的行为全部用TestCase钉死。3.1 前置条件Python 3.9建议3.10或以上。安装Pytestpip install pytest建议安装pytest-asyncio以支持异步Skill测试pip install pytest-asyncio如果你的Skill依赖了OpenAI SDK、LangChain或其他框架按实际项目安装即可。版本请以实际项目为准本文重点演示通用思路。3.2 被测Skill示例这里构造一个典型的“信息抽取Skill”它的作用是从用户输入中提取结构化信息并返回JSON。这个Skill本身可以调用LLM也可以走规则解析但对外暴露的接口是确定的。# 文件路径skills/info_extractor.py from typing import Dict, Optional class InfoExtractorSkill: 从用户输入中抽取结构化信息的Skill def __init__(self, name: str info_extractor): self.name name self.description 提取用户需求中的关键信息 def extract(self, user_input: str) - Dict[str, any]: if not user_input or not user_input.strip(): raise ValueError(user_input must not be empty) # 模拟真实Skill中的LLM调用或规则解析逻辑 result { name: None, amount: None, callback_time: None, raw_text: user_input, } if 额度 in user_input: start user_input.find(额度) result[amount] user_input[start 2:].strip() or None if 回调 in user_input: start user_input.find(回调) result[callback_time] user_input[start 2:].strip() or None return result这个示例刻意简化了内部逻辑以便聚焦测试方案本身。真实场景中这个extract方法里可能有大量Prompt模板、模型调用和工具交互。3.3 设计Pytest测试用例测试的重点不是“模型输出有多好”而是“Skill的确定性行为是否符合预期”。典型用例包括空输入校验是否正确。正常输入是否返回预期JSON结构。未找到关键词时返回的字段是None而不是抛异常。特殊字符是否会破坏输出。# 文件路径tests/test_info_extractor.py import pytest from skills.info_extractor import InfoExtractorSkill pytest.fixture def skill(): 统一的Skill实例避免测试方法之间相互污染 return InfoExtractorSkill(nametest_extractor) def test_extract_with_valid_input(skill): result skill.extract(我想申请5万额度明天下午3点回调) assert result[amount] 5万 assert result[callback_time] 明天下午3点 assert result[raw_text] 我想申请5万额度明天下午3点回调 def test_extract_without_keyword(skill): result skill.extract(我想咨询一下产品) assert result[amount] is None assert result[callback_time] is None def test_extract_with_empty_input(skill): with pytest.raises(ValueError, matchmust not be empty): skill.extract() pytest.mark.parametrize( input_text, expected_amount, [ (申请10万额度, 10万), (申请10万额度? 需要什么条件, 10万? 需要什么条件), ], ) def test_extract_amount_parametrized(skill, input_text, expected_amount): result skill.extract(input_text) assert result[amount] expected_amount这里需要提醒的是Pytest适合测试“Skill的确定性外壳”也就是那些不依赖大模型随机性的部分。如果extract方法内部调用LLM那传统断言需要Mock掉LLM返回值否则测试会不稳定。3.4 用Fixture隔离外部依赖真实场景中Skill很少是纯规则实现多半会调用LLM。这就需要在Pytest里把LLM依赖Mock掉让测试只关注Skill本身的逻辑。常用做法是“依赖注入 Monkeypatch”。# 文件路径tests/test_skill_with_mock.py from unittest.mock import MagicMock, patch from skills.info_extractor import InfoExtractorSkill class FakeLLMClient: def chat(self, messages, **kwargs): return { content: {name: 张三, amount: 5万}, usage: {total_tokens: 128}, } patch(skills.info_extractor.LLMClient) def test_extract_uses_llm_client(mock_llm_client_cls): mock_llm_client_cls.return_value FakeLLMClient() skill InfoExtractorSkill() result skill.extract(用户张三申请5万额度) assert result[name] 张三 assert result[amount] 5万通过这种方式Skill外部依赖被挡在测试之外用例可以在没有网络、没有真实API Key的CI环境里稳定运行。这也是Pytest方案最大的价值它是三层方案里唯一能大批量、低功耗、高频率运行的一层。pytest tests/ -v预期输出会显示所有用例通过给出PASSED标记。4. 方案二Agent端到端回归测试Pytest锁死了“代码层”但Skill最终要交给Agent在复杂对话中使用。这里就出现了一个新的测试盲区Agent到底会不会在正确时机调用这个Skill调用后是否把正确的上下文传给了Skill?这一层需要靠Agent自动化回归来覆盖。4.1 思路转变从“调函数”到“开一场会话”传统测试是“准备参数、调用函数、断言返回值”。Agent测试不能这么做原因是Agent行为具有多步推理和工具选择的不确定性。真正的做法是定义一批带预期效果的“测试任务”。用一个测试脚本启动Agent把任务作为用户消息输入。Agent自主执行任务期间可能触发Skill调用、工具请求、多轮对话。最终检查Agent产生的“轨迹”Trace是否符合预期。这种测试不求每一步完全一致但要求关键节点必定发生。比如当用户说“帮我查一下今天的天气”Agent必须在中间调用weather_skill最终返回的答案里必须包含城市和天气信息。4.2 用Agent执行测试任务假设你在用LangChain、LlamaIndex或自研Agent框架整体思路一致。下面用伪代码演示核心逻辑# 文件路径tests/agent_regression.py def run_agent_task(agent, task: str): 运行一次Agent任务返回完整轨迹和最终结果 response agent.chat(task) return response def assert_skill_called(response, skill_name: str): 检查Agent轨迹中是否包含了指定Skill调用 for step in response.steps: if step.type skill_call and step.skill_name skill_name: return True raise AssertionError(fSkill {skill_name} not called in agent trace) def test_weather_task_calls_weather_skill(): agent create_test_agent() response run_agent_task(agent, 今天上海天气怎么样) assert_skill_called(response, weather_skill) assert 上海 in response.content这里有个容易被忽略的点create_test_agent必须使用“测试专用配置”——关闭真实外部API、使用低成本模型如小模型或本地模型、超时时间设置短。否则一次回归测试跑下来既慢又费钱。4.3 给测试加“事件抹平”能力Agent多轮对话带来的问题远比普通函数复杂。比如Agent可能第1轮没有调用Skill而是反问用户“请问您指的是哪个城市”。只有用户补充信息后它才调用Skill。这种情况下单一任务脚本是跑不通的。你需要一个“多轮驱动测试”机制def simulate_conversation(agent, turns): 按预设会话进行多轮交互并在最后做断言 messages [] for user_msg in turns: messages.append({role: user, content: user_msg}) reply agent.chat(messages) messages.append({role: assistant, content: reply}) return messages def test_multi_turn_skill_trigger(): agent create_test_agent() messages simulate_conversation(agent, [ 帮我订一张机票, 明天早上9点从北京到上海, 经济舱选最便宜的一班, ]) assert booking_skill in [m.get(skill) for m in messages if m.get(skill)]4.4 把回归测试接入CIAgent回归测试的问题在于耗时和成本。建议做好三件事每天定时跑全量回归集而不是每次提交都跑。只对Skill改动相关的Agent任务跑快速回归。记录每次运行的模型版本、参数、上下文长度因为模型版本升级也可能导致回归用例失败。# 文件路径.github/workflows/agent-regression.yml name: Agent Regression on: schedule: - cron: 0 2 * * * jobs: regression: runs-on: ubuntu-latest steps: - uses: actions/checkoutv4 - name: Set up Python uses: actions/setup-pythonv5 with: python-version: 3.10 - run: pip install -r requirements.txt - run: pytest tests/agent_regression.py -v5. 方案三LVM LLM 多模态语义评测如果说前两层是“功能测试”那第三层就是“质量测试”。Pytest和Agent回归能证明Skill“运行成功”但无法回答一个更关键的问题Skill生成的结果真的满足用户需求吗比如Agent调用visual_analysis_skill分析一张产品照片返回“这是一个红色手机”。如果图片里实际是蓝色手机代码执行没有异常Agent也正常返回了Pytest和Agent回归都测不出问题。只有视觉大模型LVM能发现“颜色描述错误”只有语义大模型LLM能判断“这个回答和用户问题匹配度不够”。5.1 什么时候必须引入LVMLLM评测输出没有固定结构无法用JSON Schema断言。结果正确性依赖“理解”而不是“格式”。Skill会处理图片、表格、图表、UI截图等多模态输入。你需要对模型输出打分、排序、对比而不是只判断对错。一个典型的场景是Skill负责把网页截图转换成页面描述供Agent后续操作。你无法用字符串断言“描述正确”只能让LVM先“看”截图再让LLM比较Skill输出和LVM观察是否一致。5.2 构建评测流水线评测流水线分为四步。第一步准备评测数据集。第二步让被测Skill输出结果。第三步用LVM对输入图片生成标准描述。第四步用LLM根据预设规则给Skill输出打分。# 文件路径evaluator/skill_evaluator.py from typing import Dict import json class SkillEvaluator: def __init__(self, judge_llm, judge_lvm): self.judge_llm judge_llm self.judge_lvm judge_lvm def evaluate_visual_skill(self, skill_output: str, image_path: str) - Dict[str, any]: # LVM负责理解图像真实内容 visual_facts self.judge_lvm.describe(image_path) # LLM负责对比Skill输出和图像事实 prompt f 你是Skill质量评测专家请严格对比以下内容。 图像真实信息由LVM提取 {visual_facts} 被测Skill的输出 {skill_output} 请从以下维度打分1-5分 1. 信息准确性Skill输出是否与图像事实一致。 2. 信息完整性Skill输出是否遗漏了重要信息。 3. 表达清晰度文本是否容易理解。 只输出JSON格式如下 {{accuracy_score: 0, completeness_score: 0, clarity_score: 0, issues: [...], suggestion: ...}} result self.judge_llm.chat(prompt) return json.loads(result)5.3 组织评测样本集多模态评测不能只靠一两个样例下结论。建议维护一个“黄金样本集”每个样本包含原始输入文本、图片路径、表格。预期的关键信息点。允许的偏差范围。当前模型版本的评测结果快照。// 文件路径datasets/visual_skill_golden.json [ { id: case_001, input_image: datasets/images/product_red_phone.png, input_text: 分析这张产品图, expected_facts: [主体是手机, 颜色是红色, 背景是桌面], allow_missing: [], min_accuracy_score: 4 }, { id: case_002, input_image: datasets/images/ui_dashboard.png, input_text: 请描述这个页面布局, expected_facts: [包含侧边导航栏, 顶部是数据卡片, 主页有图表区域], allow_missing: [图表类型], min_accuracy_score: 3 } ]注意allow_missing是一个很有用的设计它允许某些评测样本存在合理的模糊地带避免评测器过于死板。5.4 运行评测并输出报告编写一个批量评测脚本遍历黄金样本集调用Skill生成输出再用LVMLLM打分最后汇总成报告。python evaluator/run_benchmark.py \ --skill visual_analysis_skill \ --dataset datasets/visual_skill_golden.json \ --output reports/visual_skill_report.json报告里的核心指标至少包含平均准确率得分。平均完整率得分。平均清晰度得分。每个用例的失败原因列表。建议改进的方向。有了这份报告Skill的每一次Prompt修改、每一个模型版本升级都有了可比对的“质量基线”。这比人工抽样看几个Case再拍脑袋决定改不改要可靠得多。6. 三大方案的对比与选型建议很多团队第一次搭建Skill测试时会陷入一个误区非要把三层全上了才算完整。实际上不同阶段的团队适合不同组合。维度方案一Pytest方案二Agent回归方案三LVMLLM评测核心目标锁死确定性逻辑验证Agent调度与流程评估输出质量与多模态理解测试速度秒级分钟级分钟到小时级运行成本极低中涉及模型调用较高需要额外调用评测模型对用例编写能力要求低中高稳定性高中中低受模型波动影响适合团队阶段所有阶段Skill数量多、流程复杂对外提供能力、需要质量基线6.1 三层方案的组合策略第一优先级Pytest。这是地基任何Skill都该有。即使Skill里全是LLM调用至少也要Mock掉模型把参数组装、异常处理、输出契约测清楚。第二优先级Agent回归。当Skill被Agent正式使用、业务流程开始变得复杂时加入。可以覆盖到“Skill被错误调用”这一类最危险的故障。第三优先级LVMLLM评测。当Skill作为正式产品能力上线或者需要定期评估Prompt调优效果时加入。这也是最接近“质量度量”的一层能够提供可量化指标。一个比较稳妥的落地路径是先花一天把Pytest用例铺起来跑通CI再花两三天建设Agent回归测试集至少覆盖核心业务链路评测方案可以在Skill数量变多、迭代变频繁之后再引入但数据集要提前开始积累——因为好的评测样本集本身就是稀缺资产。7. 常见问题与排查方法在搭建Skill测试体系时以下问题出现频率最高这里给出具体的排查思路。问题现象可能原因排查方式解决方案Pytest用例偶发失败Skill内部调用了真实LLM没有Mock查看失败用例是否涉及网络请求检查测试日志中的耗时在测试中Mock掉LLM客户端使用FakeClient返回固定结果Agent回归测试超时Agent多轮推理过长或者模型请求被限流查看Agent日志中的每步耗时检查是否在测试环境关闭了外部API设置单步超时和总超时阈值测试环境使用更低延迟的模型LLM评测打分不稳定评测模型温度过高随机性强把评测模型的temperature设为0并使用结构化Prompt使用JSON Schema约束输出多评测几次取平均LVM识别结果和人工判断不一致LVM模型本身有幻觉或者图像分辨率不足检查原始图片质量对比多款LVM的识别结果优先使用更高精度的LVM为关键样本增加人工审核环节回归测试里Agent没有调用预期SkillAgent的模型在测试环境无法正确识别任务意图查看Agent轨迹确认是否走入了错误分支检查Skill描述是否清晰优化Skill的描述文本检查测试用例的指令是否足够明确评测报告分数整体偏低Skill输出确实有问题或评测标准过于严格抽查失败用例人工复核调整评测Prompt中的评分标准或更新黄金样本集这里特别提醒Agent回归测试失败时不要只盯着“最终回答”看一定要分析Agent的中间轨迹。很多问题不是出在Skill本身而是Agent在调度环节把参数传错了。8. 最佳实践与工程建议下面几条经验来自多个Agent项目的沉淀能帮你少踩坑。8.1 把Skill测试分成“三层金字塔”不要所有Skill都同样对待。建议按“核心程度”和“复用程度”把Skill分层底层通用Skill如格式化、解析、检索必须100%覆盖Pytest测试。业务Skill如查询、下单、推荐必须覆盖Agent回归测试。对外能力Skill必须纳入LVMLLM评测体系。分层越清晰测试投入的ROI越高。不要试图给18个Skill都做三级测试。成本会失控。8.2 Prompt模板也要做版本管理Skill迭代中最危险的操作是“微调Prompt”后自认为没有影响行为实际上导致所有输出风格变化。所以哪怕只是改了一个字也应该触发Pytest冒烟测试和LLM评测样本集回归。8.3 建立“评测回归基线”把当前版本的评测报告保存为基线。下次任何改动后重新跑评测和基线对比得分。这是整个Skill测试体系中最有工程价值的数据资产。// 文件路径reports/baseline_20250101.json { skill: visual_analysis_skill, model: gpt-4o-mini, date: 2025-01-01, metrics: { accuracy_score: 4.2, completeness_score: 3.9, clarity_score: 4.5 } }8.4 安全性相关提醒Skill测试会涉及真实用户数据和外部API注意三点测试环境使用脱敏数据不使用生产环境真实用户信息。在CI中配置独立的API Key并限制其权限和配额。涉及删除、写入外部系统时优先使用Mock或沙箱环境。8.5 日志与可观测性Skill测试暴露的另一个问题是“黑盒”。一旦Agent多轮调用多个Skill出现问题很难定位。建议在Skill的入口和出口打印结构化日志{ event: skill_call, skill_name: info_extractor, input: ..., output: ..., latency_ms: 320, model: gpt-4o-mini, trace_id: abc123 }日志是排错的基础。没有日志的Skill测试体系在出现问题时基本只能靠猜。9. 总结与后续学习方向Skill测试的本质不是“更长的测试代码”而是“分层处理不确定性”。Pytest测试用确定性断言锁住代码逻辑Agent回归用任务级验证守住调用链路LVMLLM评测用机器评判补齐语义和视觉盲区。三者的关系不是替代而是互补。如果你所在的项目还完全没有Skill测试体系不要一上来就搭建大而全的平台。先在项目里加入Pytest把Skill的确定性部分覆盖住再挑1到2条核心业务链路做Agent端到端回归最后在Skill稳定迭代后再引入LVMLLM评测形成质量基线。下一步值得深入的方向有三个一是研究更稳定的LLM-as-a-Judge评测方法比如引入多裁判投票、对比评测样本二是把Agent轨迹与测试断言结合起来在回归测试中自动校验每个关键步骤三是关注多模态评测的基准数据集设计因为随着Agent能力扩展视觉类Skill会越来越多视频评测的需求也会逐步逼近。建议收藏本文在搭建Skill测试体系时直接对照使用。