![]()
在本课程到目前为止,您已经构建了运行在笔记本内、由 az login 和少量环境变量驱动的代理,这些代理运行在您的笔记本电脑上。这完全是学习的正确方式。但这并不是让数千客户在凌晨三点依赖的代理的正确运行方式。
本课讲述的是“在我的机器上运行正常”和“在生产环境中可靠且经济地运行正常”之间的差距。我们通过使用 Microsoft Foundry 和 Microsoft Foundry Agent Service 来弥合这一差距,并通过构建一个具有工具调用、检索、记忆、评估和监控功能的真实客户支持代理来实现。
本课将涵盖:
完成本课后,您将学会:
本课假设您已经完成前面的课程并熟悉:
您还需要:
az login)。requirements.txt 所列的包。原型代理和生产代理共享相同的核心循环——推理、调用工具、响应。改变的是包裹在该循环周围的一切。模型大约占生产代理的 20%;其余 80% 是运营框架。
| 关注点 | 原型 | 生产 |
|---|---|---|
| 托管 | 在笔记本中运行 | 作为托管服务运行,具备版本管理和推送功能 |
| 身份 | 使用您的 az login 令牌 |
使用具有限定 RBAC 的托管身份 |
| 状态 | 内存中,重启后丢失 | 外部持久化(线程存储、内存服务) |
| 失败处理 | 查看堆栈跟踪 | 重试、回退、死信队列和警报 |
| 成本 | “几分钱” | 按请求追踪,路由和缓存,预算控制 |
| 质量 | 手动检查输出 | 在每次发布前自动评估 |
| 信任 | 您批准每个动作 | 策略+人机交互审批高风险操作 |
记住这张表。下面的每个章节都对应表中的一行。
有三种部署模式,通常会组合使用。
代理对象存在于您的应用进程内。您的代码直接调用模型提供者;推理循环在您的服务中运行。所有前面的课程都是这样操作的。
代理作为资源注册在 Microsoft Foundry 中。Foundry 托管推理循环,存储线程,执行内容安全和 RBAC,并在 Foundry 门户中展示代理。您的应用成为一个瘦客户端,创建线程并读取响应。
多个代理(和工具)组成有明确控制流的图——顺序步骤、分支、人类审批节点和可暂停恢复的持久检查点。这是 Microsoft Agent Framework 工作流 功能在部署规模上的应用。
flowchart TB
subgraph P1[客户端托管]
A1[你的应用进程] --> M1[模型提供者]
end
subgraph P2[托管代理]
A2[精简客户端] --> F2[Foundry 代理服务]
F2 --> M2[模型 + 工具 + 线程存储]
end
subgraph P3[代理工作流]
A3[协调器] --> S1[分诊代理]
S1 --> S2[解决者代理]
S2 --> H[人工审批节点]
H --> S3[行动代理]
end
部署代理不是一次性的 push 操作,而是一个循环,很像软件发布生命周期,因为它就是。
flowchart LR
Create[创建 / 作者] --> Version[版本]
Version --> Evaluate[离线评估]
Evaluate -->|通过门控| Deploy[部署托管]
Evaluate -->|未通过门控| Create
Deploy --> Observe[在线观察]
Observe --> Improve[收集失败]
Improve --> Create
Deploy --> Retire[退役旧版本]
这一核心理念继承自 第10课:离线评估是门槛,而非事后考虑。 新版本代理必须通过评估门槛后才能发布。上线可观测性将真实失败反馈入离线测试集。整个流程如是。
扩展代理不同于扩展无状态的 web API,因为每个请求可能触发多次高成本的模型和工具调用。核心的四种方法:
无状态请求处理。 不在进程内存中保存任何用户状态。将对话线程持久化存储在 Foundry 线程存储或内存服务中,任何实例都能处理任意请求。这让您能水平扩展——增加实例,无需粘性会话。
模型路由。 并非每个请求都需要最强大(最昂贵)的模型。将简单请求——意图分类、简短事实回答——路由到小型快速模型,复杂推理请求才用大模型。Foundry 的 模型路由器 可以帮您做,或您也可以自己做轻量分类器。实验课会实现自定义版本。
响应缓存。 很多支持查询是近似重复的(“如何重置密码?”)。缓存常见问题的答案,直接返回,避免触发模型调用。即使是适度的缓存命中率,成本和延迟都能大幅降低。
并发与背压。 模型服务有速率限制。限制并发量,使用指数退避重试,优雅失败(排队回复“我们正在处理”要胜过 500 错误)。
flowchart LR
Q[用户查询] --> C{缓存命中?}
C -->|是| R[返回缓存答案]
C -->|否| Router{复杂度?}
Router -->|简单| SLM[小模型]
Router -->|复杂| LLM[大模型]
SLM --> Out[响应]
LLM --> Out
Out --> Store[缓存 + 跟踪]
不可见则不可操作。正如第10课所述,Microsoft Agent Framework 原生发出 OpenTelemetry 跟踪——每次模型调用、工具调用和编排步骤变成一个跨度。生产环境中将这些跨度导出到 Microsoft Foundry(或任何支持 OTel 的后端),以实现:
from agent_framework.observability import get_tracer
tracer = get_tracer()
with tracer.start_as_current_span("support_request") as span:
span.set_attribute("customer.tier", "enterprise")
span.set_attribute("routed.model", "gpt-5-nano")
# 代理执行会在此跨度内自动跟踪
属性如 customer.tier 和 routed.model 将大量追踪转化成可回答的问题(“企业客户是否过度地路由到小模型?”)。
生产代理中成本主要由令牌费用决定。影响最大的三个杠杆:
评估门和成本控制是同一学科的两面:评估告诉您质量下限,路由和缓存让您尽可能接近该下限的成本。
治理。 托管代理继承 Foundry 的 RBAC、内容安全和审计日志。为每个代理分配权限最小的托管身份——只读知识库,限定访问工单 API,不多不少。
人机交互。 某些操作影响重大,无法完全自动化——退款、删除账户、提交法律团队等。Microsoft Agent Framework 支持 需审批的工具:代理提出操作,执行暂停,人批准或拒绝,之后工作流继续。第6课已介绍该原语;这里是具体部署。
生产环境中的 MCP。 MCP 允许代理通过标准接口调用外部工具。生产中应将每个 MCP 服务器视为不可信边界:锁定服务器版本,使用限定身份运行,验证输出,绝不暴露秘密。MCP 服务是依赖项,需要补丁、审计和速率限制。
flowchart TB
subgraph Dev[开发架构]
D1[笔记本] --> D2[代理框架]
D2 --> D3[模型提供者]
D2 --> D4[本地工具]
end
subgraph Deploy[部署架构]
E1[CI 流水线] --> E2[评估关卡]
E2 -->|通过| E3[Foundry 代理服务]
E3 --> E4[版本托管代理]
end
subgraph Run[运行时架构]
F1[客户端应用] --> F2[托管代理]
F2 --> F3[模型路由器]
F2 --> F4[Azure AI 搜索 RAG]
F2 --> F5[内存服务]
F2 --> F6[MCP 工具]
F2 --> F7[OTel -> Foundry 跟踪]
F2 --> F8[人工审批]
end
这三张图——开发、部署、运行时——展示了同一代理生命的不同时期。接下来的实验引导您一步步构建。
打开 code_samples/16-python-agent-framework.ipynb,从头到尾完成。您将组装一个具有所有生产关切点的 Contoso 客户支持代理:
笔记本组织成每个生产关切点是独立、可运行的部分。其核心是路由加缓存的请求处理程序:
async def handle_support_request(query: str, customer_id: str) -> str:
# 1. 尽可能从缓存提供服务。
cached = response_cache.get(normalize(query))
if cached:
return cached
# 2. 按复杂度路由以控制成本。
model = "gpt-5-nano" if is_simple(query) else "gpt-5-mini"
# 3. 在跟踪跨度内运行代理以便观察。
with tracer.start_as_current_span("support_request") as span:
span.set_attribute("routed.model", model)
span.set_attribute("customer.id", customer_id)
response = await support_agent.run(query, model=model)
# 4. 缓存并返回。
response_cache.set(normalize(query), response.text)
return response.text
评估门看起来是这样:
async def evaluation_gate(agent, test_cases, threshold: float = 0.8) -> bool:
passed = 0
for case in test_cases:
result = await agent.run(case["input"])
if score_response(result.text, case["expected"]) >= 0.8:
passed += 1
pass_rate = passed / len(test_cases)
print(f"Evaluation pass rate: {pass_rate:.0%} (gate: {threshold:.0%})")
return pass_rate >= threshold # 只有在门控通过时才部署
逐行仔细阅读——笔记本将原语保持非常小巧,没有任何隐藏在框架调用后面。
上述评估门在离线评估您的代理对象。代理一旦作为托管代理部署,您需要另一个更便宜的检查:已部署的端点是否真的响应?
“成功部署”只证明控制平面接受了定义——但不能证明代理真的响应。缺少依赖、错误的模型路由或连接过期都可能导致部署成功但无响应。冒烟测试可在几秒内捕捉这些问题,每次部署时运行,成本远低于完整评估。
本仓库自带基于 AI Smoke Test GitHub Action 的现成冒烟测试方案:
tests/lesson-16-smoke-tests.json 包含 Contoso 支持代理的提示和断言(基于政策的答案、订单查询、保持主题和多轮对话连贯)。其他课程代理的目录文件与其共存—见 tests/README.md。.github/workflows/smoke-test.yml 使用 Azure OIDC 登录,将每个提示 POST 到代理的 Responses 端点,任何断言失败时任务失败。- name: Smoke-test hosted agent
uses: JFolberth/ai-smoketest@v1
with:
project_endpoint: $
agent_name: ContosoSupportAgent
tests_file: tests/lesson-16-smoke-tests.json
部署代理后,从 Actions 选项卡运行它,提供你的 Foundry 项目端点和代理名称。联邦身份需要在 Foundry 项目范围内拥有 Azure AI User 角色。将这些层级想象成金字塔:冒烟测试(是否可达且响应?)在每次部署时运行,离线评估(够好可以发布吗?)在晋级前运行,在线评估(在实际环境中表现如何?)持续运行。
在进入作业之前测试你的理解。
1. 生产代理中“大致有多少比例是‘模型’,剩下的是什么?
2. 在什么情况下你会选择托管代理而不是客户机托管的代理?
3. 为什么可扩展代理在其自身进程内存中必须是无状态的?
4. 模型路由解决什么问题,它和评估有什么关系?
5. 什么是“评估门”,它在生命周期中处于什么位置?
6. 为什么 MCP 服务器在生产中应被视为不可信边界?
7. 通常哪个单一改变对生产代理成本影响最大,为什么?
8. 像 customer.tier 和 routed.model 这样的跨度属性在可观察性中扮演什么角色?
采用实验中的客户支持代理并强化它以适应特定场景:一个 SaaS 公司的订阅计费支持代理。
你的提交应包括:
get_subscription_status、get_invoice 和 issue_credit(超过 50 美元的信用需人工审批)。写一小段文字(Markdown 单元格中),解释你选择了哪条模型路由规则以及如何用真实流量验证它。没有唯一正确答案——评估重点是你是否将生产关注点合理连接起来。
本课中,你用 Microsoft Foundry 将代理从原型推向生产:
下一课走相反的路线:你将把代理缩小到单个开发者机器并完全本地运行。
免责声明: 本文件由 AI 翻译服务 Co-op Translator 翻译完成。尽管我们力求准确,但请注意,自动翻译可能包含错误或不准确之处。原始语言版文件应视为权威来源。对于重要信息,建议使用专业人工翻译。我们对因使用本翻译而产生的任何误解或误释不承担责任。