技术速递|智能体测试智能体:基于 Foundry Hosted Agents 构建云原生 Skill-Eval Harness
作者:卢建晖 - 微软高级云技术布道师
排版:Alan Wang
Skills 是智能体的必备能力,所以请对它进行测试。
Skill 是赋予智能体持久、可复用行为的最轻量方式:你只需编写一次 SKILL.md 文件,将其统一存储在 Foundry 支持版本管理的 Skills API 中,然后注入到 Hosted Agent 的上下文即可——无需修改代码,也无需重新部署。这正是 Skill 悄然成为生产级智能体标配能力的原因。
但一旦 Skill 承载了真正的业务行为,一个棘手的问题也随之而来:**你如何确认它仍然正常工作?**每次修改 Skill 时,你无法凭感觉判断它究竟是得到了优化,还是仅仅发生了变化。它可能不再被正确触发、遗漏某个必需的内容,或者在某个模型上的效果悄悄变差。解决办法,与我们对待任何 Prompt 的方式完全一致——对它进行评测:运行智能体、记录执行过程,并依据一组预定义的检查项进行评分。
azure_skill_eval 正是为一个具体 Skill——edu-video-script——解决这一问题。该 Skill 用于根据指定知识点生成教育类短视频脚本(示例中的 Smoke Test 要求它生成关于 “P vs NP 问题” 的短视频脚本)。整个评测过程完全采用云原生方式,并运行在 Foundry Hosted Agents 之上。
场景:一个 Skill、两个模型、四个托管智能体

待测试的 Skill 是 edu-video-script。整个 Harness 最巧妙的地方在于,它并不会只检查一次运行结果,而是通过由 Agent Framework FoundryAgent 串联起来的四个 Foundry Hosted Agents,从三个不同维度对该 Skill 进行压力测试。
| 托管智能体 | 角色 |
|---|---|
| skill-eval-business-agent-gpt | 被测系统(SUT),在 gpt-5.5 上运行 edu-video-script |
| skill-eval-business-agent-deepseek | 相同的 Skill,运行于 DeepSeek-V4-Pro |
| skill-eval-attacker-agent | 多轮对抗式 Prompt 生成器 |
| skill-eval-judge-agent | 充当 LLM Judge,以 JSON 形式返回评分结果 |
两个业务智能体在不同模型上运行同一个 Skill,因此每一个测试用例都形成了一次公平的横向对比:究竟哪个模型能够更好地执行这项 Skill?攻击者与评测者则分别负责生成测试与完成评分。
我们衡量什么(先定义“完成标准”)
优秀的评测始于一个可验证的“完成”定义——包括结果、过程、风格以及效率。
对于一个教育短视频脚本来说,这意味着:
-
是否生成了一份有效的脚本(结果)?
-
是否真正遵循了
edu-video-script模板(过程 / 风格)? -
当用户在多轮对话中不断施压时,它是否仍能保持稳定?
整个 Harness 通过三个评分层次回答这些问题。
- 首先进行确定性检查(validator.py)
这是成本最低、可解释性最强的一层信号:输出结果是否符合 Skill 所规定的脚本模板?validator.py 会执行一系列固定、确定性的模板检查——完全不依赖模型。这些检查能够立即发现明显的回归问题,而且不会消耗任何 Token。
- LLM Judge(skill-eval-judge-agent)
模板检查只能回答“是否完成了基本要求?”,却无法回答“这份脚本是否足够优秀?”——例如节奏是否合理、表达是否清晰、是否真正讲清楚了知识点。因此,系统引入了一个专门负责评分的托管智能体,对结果进行评估,并返回结构化 JSON,使不同运行结果、不同模型之间的评分能够直接比较:
{ "overall_pass": true, "score": 100, "checks": [] }
结构化输出正是关键所在:固定字段(overall_pass、score、checks)可以方便地比较 GPT 与 DeepSeek 的差异,也能够对比今天的 Skill 版本与上周版本之间的变化。
- 多轮攻击智能体(test_agent.py + skill-eval-attacker-agent)
一个在理想 Prompt 下表现优秀的 Skill,仍然可能在用户持续施压后迅速失效。攻击智能体会针对指定知识点,根据选定的攻击策略(例如:超长输入)生成对抗式 Prompt,并在多轮对话中持续发起攻击(max_turns,默认值为 3)。这里真正验证的是:edu-video-script 是否能够在压力环境下依然遵循模板,而不仅仅是在理想场景中表现良好。
# the attacker takes a knowledge point + a strategy, emits one user prompt
azd ai agent invoke skill-eval-attacker-agent \
"Topic: P vs. NP problem Recommended attack strategy: Extreme length Please output the unique user prompt text."
完整的评测流程
runner.py 实现了一套类似 ghcsdk 风格的评测流水线,可按“测试用例 × 模型”运行,并支持灵活切换不同配置:可以选择全部模型、仅 GPT、仅 DeepSeek;可以只运行单个测试用例(例如 edge-03);也可以开启或关闭对抗模式、单轮 / 多轮测试以及 Judge 评分。这些配置同样对应于 POST /api/run 的查询参数:
model、only_case、use_attack、single_turn、use_judge、max_turns。
测试集定义于 shared/test_cases.py,其中内置了 10 个边界测试用例(edge-01 … edge-10),并导出到 evals/evals.json。你并不需要一个庞大的基准测试集;一组数量不多但设计精准的测试用例,就足以发现大部分回归问题。而当真实故障出现时,只需持续将新的案例加入测试集即可。
python -m evals.export_evals # regenerate evals/evals.json from shared/test_cases.py
每一次 SUT 调用都会经过 runtime.py,其实现遵循 Agent Framework 官方 Hosted Agent 示例:每一轮都会创建新的托管会话,通过 Responses API 发起调用,并在完成后销毁该会话。
# shared/runtime.py — the documented Foundry hosted-agent pattern
project = AIProjectClient(endpoint=FOUNDRY_PROJECT_ENDPOINT,
credential=cred, allow_preview=True)
agent = FoundryAgent(project_client=project,
name=agent_name, # e.g. skill-eval-business-agent-gpt
allow_preview=True)
session = project.beta.agents.create_session(agent_name=agent_name)
# ... send the (possibly adversarial) prompt, collect the Responses output ...
因此,一个完整测试用例的执行流程如下:runner → business agent(运行 Skill)→ validator → judge
如果启用了攻击模式,则会先由攻击方发起多轮对抗测试。
云原生设计——以及它为何对评测如此重要
这一部分,正是整个 Harness 从一个本地脚本成长为生产级评测系统的关键。评测 Harness 中最复杂的工作——例如部署智能体、记录每一次运行、扩展测试规模以及权限治理——全部由 Azure 平台负责,而不是由开发者自行实现。
-
Foundry Hosted Agents 是整个运行时。SUT、攻击方和评测方全部作为受管控托管智能体运行于你的 Foundry 项目中。你只需提供 Skill 与测试用例;Foundry 负责托管智能体、模型以及会话。业务智能体使用
host: azure.ai.agent与docker.remoteBuild: true进行部署,因此执行azd deploy时,会直接在 Azure Container Registry 中完成镜像构建——本地甚至无需启动 Docker。 -
UI 采用无服务器架构。部署在 Azure Container Apps 上的 FastAPI 应用支持上传
evals.json、实时查看评测进度以及浏览数据看板;当无人使用时,还能够自动缩容至零实例。 -
每一次运行都会被永久保存。所有结果都会写入 Azure Blob Storage(
skill-eval-runs),每次运行对应一个yymmdd-XXXXXX/文件夹,并维护一个按时间倒序排列的runs.json索引。评测结果不会只停留在终端输出中。 -
访问控制基于身份认证完成。在云端,用户分配的 Managed Identity 仅拥有两个角色:Storage Blob Data Contributor 与 Azure AI User;本地环境则使用
AzureCliCredential。整个过程中无需在环境变量中存放任何访问密钥。 -
基础设施具备可重复部署能力。执行
azd up时,会自动运行infra/main.bicep,一次性完成 Storage、容器、Log Analytics、Container Apps 环境、Managed Identity 以及角色权限分配等全部资源的部署。
最终带来的价值是:你看到的每一个评测分数,都来自与你最终生产环境完全一致的托管运行时,而不是本地模拟环境;同时,生成这些分数的每一次运行记录,都已经保存在 Blob Storage 中,可以与历史所有运行结果进行对比。
运行
本地运行(无需部署):
conda activate agentdev
cd Skill_eval/azure_skill_eval
pip install -r requirements.txt
cp .env.example .env # FOUNDRY_PROJECT_ENDPOINT + AZURE_STORAGE_*
uvicorn webapp.app:app --reload --port 8000
打开 http://localhost:8000,上传 evals/evals.json,选择模型和评测模式,然后点击运行。
云端运行(azd):
azd auth login
azd env new skill-eval-dev
azd env set FOUNDRY_PROJECT_ENDPOINT https://<project>.services.ai.azure.com/api/projects/<project>
azd env set MODEL_GPT gpt-5.5
azd env set MODEL_DEEPSEEK DeepSeek-V4-Pro
azd up
先完成一次 Skill 的注册,部署四个托管智能体,然后执行 Smoke Test:
python -m hosted_agent.provision_skills # upload edu-video-script to Foundry Skills
azd deploy skill-eval-business-agent-gpt
azd deploy skill-eval-business-agent-deepseek
azd deploy skill-eval-attacker-agent
azd deploy skill-eval-judge-agent
azd ai agent invoke skill-eval-business-agent-gpt "Here is a script for an educational short video on the P vs. NP problem."
查看结果
每一次运行都会作为一个独立目录保存在 Blob Storage 中:
summary.json 提供整体结果摘要——包括通过率和评判平均得分;而每个 per-{case}__{model}.json 文件则对应单个测试结果,你可以查看 Skill 的具体输出,以及它为何通过或失败。数据看板会通过 /api/runs/{run_id}/files/{filename} 直接从 Blob Storage 实时读取这些结果。由于 GPT 与 DeepSeek 针对同一组测试用例完成评测,因此它们的对比结果都会保存在同一个运行目录中,便于直接比较。
经验
-
无法评测的 Skill,也就无法被信任。edu-video-script 被当作代码一样管理——在 Foundry 中进行版本管理、运行以及评分。
-
按照由低成本到高成本的顺序组织评测器。首先执行确定性的模板检查(validator.py),然后使用 LLM Judge 评估内容质量,最后通过多轮攻击智能体验证稳健型。
-
让评测器返回结构化 JSON。overall_pass、score 和 checks 等字段,可以方便地比较不同模型以及不同 Skill 版本之间的结果。
-
在同一项 Skill 上比较不同模型。让 GPT-5.5 与 DeepSeek-V4-Pro 同时运行相同的测试用例,可以把“该选哪个模型?”从经验判断变成可量化的数据结论。
-
把 Harness 交给平台负责。Foundry Hosted Agents 提供运行时;Azure Container Apps、Blob Storage、Managed Identity,以及 azd/Bicep,共同保证整个评测流程具备可重复部署和持久化能力。
编写 Skill,然后构建用于验证它的 Harness。在 Foundry 中,第二步主要是配置工作,而最终得到的是一个真正可以放心投入生产环境的 Skill。
总结
Skill 将智能体的行为从代码迁移到了支持版本管理的 Markdown,这极大提升了复用能力。但只有能够证明每一次修改之后 Skill 仍然正常工作,这种优势才能真正发挥出来。azure_skill_eval 正是通过将评测作为独立、可重复执行的工程环节,而不是依赖开发者的主观判断,为 edu-video-script 提供了这样的保障。
整个方案结构简单,也非常值得迁移到自己的 Skill 项目中:
-
定义一套可验证的“完成”标准,然后设计一组精炼而有针对性的测试用例(本文示例为 10 个边界测试用例)。
-
采用分层评分机制,并按照从低成本到高成本的顺序执行——先进行确定性的模板检查,再使用结构化的 LLM Judge 评分,最后执行多轮对抗测试。
-
针对相同测试用例,在不同模型之间进行对比(GPT-5.5 与 DeepSeek-V4-Pro),让模型选型建立在数据之上,而不是凭经验判断。
-
将评测平台交给云端负责——以 Foundry Hosted Agents 作为运行时,以 Azure Container Apps 承载 FastAPI UI,以 Blob Storage 持久化评测结果,以 Managed Identity 管理访问权限,并通过 azd/Bicep 保证整个环境能够重复部署。
最终形成的是一个持续反馈闭环:每一次 Skill 修改都会得到验证,每一次回归问题都会被及时发现,每一个评分结果都可以追溯到与你生产环境一致的托管运行时。这正是“能够构建 Skill”与“能够信任 Skill”之间的区别。而在 Foundry 上,弥补这段差距所需要做的,大多数只是合理的配置工作。

示例代码:
更多推荐



所有评论(0)