第 2 篇(03-04 章):代理设计原则与工具使用设计模式

第 2 篇(03-04 章):代理设计原则与工具使用设计模式

文章目录

  • [第 2 篇(03-04 章):代理设计原则与工具使用设计模式](#第 2 篇(03-04 章):代理设计原则与工具使用设计模式)
  • [一、第 03 章:AI 代理设计原则](#一、第 03 章:AI 代理设计原则)
    • [1. 代理设计原则](#1. 代理设计原则)
    • [2. 实施这些原则的指导方针](#2. 实施这些原则的指导方针)
    • [3. 如何使用这些原则与指导方针设计旅游代理](#3. 如何使用这些原则与指导方针设计旅游代理)
  • [二、第 04 章:工具使用设计模式](#二、第 04 章:工具使用设计模式)
    • [1. 什么是工具使用设计模式?](#1. 什么是工具使用设计模式?)
    • [2. 它适用于哪些用例?](#2. 它适用于哪些用例?)
    • [3. 实现工具使用设计模式所需的元素/构建块有哪些?](#3. 实现工具使用设计模式所需的元素/构建块有哪些?)
    • [4. 使用代理框架的工具使用示例](#4. 使用代理框架的工具使用示例)
    • [5. 使用工具使用设计模式构建可信 AI 代理的特别注意事项?](#5. 使用工具使用设计模式构建可信 AI 代理的特别注意事项?)
  • 三、代码示例讲解
  • 四、环境配置

本系列「微软《AI Agents for Beginners》实战解读」基于微软官方课程,逐章讲解并结合实践扩展。本篇覆盖第 03 章《AI 代理设计原则》第 04 章《工具使用设计模式》

文中子标题沿用官方课程原文;示例基于 Microsoft Agent Framework(MAF),模型后端为 DeepSeek(OpenAI 兼容协议)。


一、第 03 章:AI 代理设计原则

本章不以代码为中心,而是建立代理设计的人本原则。构建代理系统时,生成式 AI 的模糊性常使工程师难以确定起点;课程提供一套以人为中心的用户体验设计原则,作为团队定义与构建代理体验的起点,而非规范性架构。

代理设计的一般目标可归纳为四类:扩展和放大人的能力 (头脑风暴、解决问题、自动化)、弥补知识空白 (快速了解领域、翻译)、促进与他人协作让使用者成为更好的自己(如生活教练、任务管理)。

1. 代理设计原则

课程从空间、时间、核心三个维度组织原则。

代理(空间)。 该维度指导如何设计参与物理与数字世界的代理:

  • 连接,而非替代:代理帮助连接事件、知识与个人,使人们更加紧密;其定位不是替代或贬低人,而是促进协作与联结。
  • 易于访问且偶尔隐形:代理大部分时间在后台运行,仅在相关且适当时提醒。它对授权用户在任何设备上易于发现与访问,支持多模态输入输出,可在前台/后台、主动/被动之间切换;即便以隐形形式运行,其后台进程与协作路径对用户透明且可控。

代理(时间)。 该维度指导代理如何在过去、现在与未来之间运作:

  • 过去:基于历史数据分析提供更相关结果,从过去事件建立联系、反思记忆以应对当前情境。
  • 现在:推动"提醒"多于"通知"------代理可简化流程、动态生成提示,引导用户在恰当时刻关注重点;交互可在复杂度上渐进演变。
  • 未来:适应不同设备、平台与交互方式,随用户行为与无障碍需求演化,并可由用户定制。

代理(核心)。 构成代理设计基础的关键元素:

  • 拥抱不确定性但建立信任:预期代理存在不确定性;信任与透明是基础层。人类掌控代理的开关状态,代理运行状态始终清晰可见。

理论扩展:设计与工程的分界。 本章原则面向交互与体验层,而非系统实现。对应关系可映射为工程约束:透明 → 可观测性(第 10 章)与审计日志;控制 → 权限模型与人工审批(第 06 章);时间维度 → 记忆系统(第 13 章)。这些原则在后续章节以具体机制实现。

2. 实施这些原则的指导方针

将原则落到实现,需遵循三条指导方针:

  1. 透明度:告知用户 AI 的参与方式、系统如何运作(包括过去行为),以及如何反馈与修改系统。
  2. 控制:允许用户自定义、指定偏好、个性化,并能控制系统及其属性(包括"忘记"能力------删除数据与历史)。
  3. 一致性:追求跨设备与端点一致的多模态体验;使用熟悉的 UI 元素(如麦克风图标表示语音),并减轻用户认知负担(简洁回应、视觉辅助)。

3. 如何使用这些原则与指导方针设计旅游代理

以旅游代理为例,三原则的落地方式:

  1. 透明度:让用户明确知道这是 AI 驱动代理;提供使用说明与示例提示;展示用户历史提示列表;提供点赞/点踩等反馈入口;明确代理的主题限制。
  2. 控制:允许通过系统提示等机制修改代理;让用户选择回复详细程度、写作风格与禁忌话题;允许查看与删除文件、提示与历史对话。
  3. 一致性:统一"分享提示"、附件、图片等操作的图标规范(回形针表示文件、图片图标表示图像),降低学习成本。

理论扩展:认知负担与信任建立。 三原则共同指向降低认知负担(Cognitive Load)与建立可信交互(Trustworthy Interaction):透明度降低不确定感,控制权让渡提升掌控感,一致性减少学习成本------三者协同形成用户对代理的信任闭环。


二、第 04 章:工具使用设计模式

本章聚焦代理的"行动能力":通过工具,代理突破有限动作集合的限制,执行更广泛的操作。

1. 什么是工具使用设计模式?

工具使用设计模式 赋予 LLM 与外部工具交互以达成特定目标的能力。工具是代理可执行的代码,可以是简单函数(计算器),也可以是第三方服务 API(股票价格、天气预报)。在代理语境中,工具由代理响应模型生成的函数调用而执行。

理论扩展:工具的本质。 工具是对外部能力的可调用封装(Callable Abstraction)------它将"读取环境状态"或"施加副作用"统一表达为函数接口,使模型仅需声明"调用什么、传什么参数",而无需理解底层实现。

2. 它适用于哪些用例?

工具使用模式适用于需要与外部系统动态交互的场景,课程列举五类:

  • 动态信息检索:查询 API 或数据库获取最新数据(SQLite 数据分析、股票价格、天气)。
  • 代码执行与解释:执行代码或脚本解决数学问题、生成报告、进行模拟。
  • 工作流自动化:集成任务调度器、邮件服务、数据流水线,自动化重复或多步骤流程。
  • 客户支持:与 CRM 系统、票务平台、知识库交互解决用户查询。
  • 内容生成与编辑:借助语法检查、文本摘要、内容安全评估工具辅助内容创作。

3. 实现工具使用设计模式所需的元素/构建块有哪些?

实现该模式需要六类构建块:

  • 函数/工具 Schema:对可用工具的详细定义(函数名、用途、必需参数、预期输出),使 LLM 理解有哪些工具及如何构造请求。
  • 函数执行逻辑:管理基于用户意图与上下文"何时、如何"调用工具,可能包含规划模块、路由机制与条件流程。
  • 消息处理系统:管理用户输入、LLM 响应、工具调用及工具输出之间的对话流转。
  • 工具集成框架:连接代理与各类工具的基础设施(简单函数或复杂外部服务)。
  • 错误处理与验证:处理工具执行失败、验证参数、管理意外响应。
  • 状态管理:跟踪对话上下文、历史工具交互与持久数据,保证多轮一致性。

函数/工具调用。 函数调用是 LLM 与工具交互的主要方式。"函数"与"工具"常互换使用------可重用的代码块即代理执行任务的工具。调用过程为:将包含所有函数描述的 Schema 发送给 LLM → LLM 匹配用户请求与函数描述 → 返回函数名与参数 → 所选函数被执行 → 响应回传 LLM → LLM 基于结果回应用户。

理论扩展:提议-执行分离(第 01 章机制深化)。 该流程重申并深化了工具调用的核心机制:模型仅返回调用意图(提议),函数执行由代码完成(执行) 。此分离既是安全性基础,也意味着工具的质量取决于其描述质量------docstring 与参数 Schema 直接决定模型能否在正确时机调用正确工具。

4. 使用代理框架的工具使用示例

Microsoft 代理框架(MAF)。 MAF 通过 @tool 装饰器将 Python 函数定义为工具,框架自动处理模型与代码的双向通信(Schema 生成、调用执行、结果回传)。FoundryChatClient 还提供预构建工具,如文件搜索与代码解释器。

Microsoft Foundry 代理服务。 该托管服务将工具分两类:知识工具 (Bing 搜索、文件搜索、Azure AI 搜索)与操作工具 (函数调用、代码解释器、OpenAPI 定义工具、Azure Functions)。它支持将多个工具打包为工具集(ToolSet),并通过**线程(Thread)**跟踪对话消息历史。其优势是自动工具调用与安全管理数据,无需开发者手动解析工具调用。

5. 使用工具使用设计模式构建可信 AI 代理的特别注意事项?

工具使用引入安全风险,核心是模型动态生成的 SQL ------存在注入或恶意操作(删除、篡改)风险。缓解方式是最小权限配置数据库 :对 PostgreSQL、Azure SQL 等服务为应用分配只读(SELECT)角色;在安全环境中运行,将数据提取至只读数据库/数据仓库并采用友好 Schema,保证权限限于只读。

理论扩展:最小权限原则(Least Privilege)。 该注意事项是安全领域最小权限原则的实例化------代理所访问系统仅授予完成任务所需的最小权限,即使模型被诱导生成恶意指令,也无法越权执行破坏性操作。


三、代码示例讲解

以下代码取自课程 code_samples,已适配 DeepSeek 后端。按"逐段解释 → 完整代码"组织。

示例一:清晰指令(第 03 章落地)。

① 系统提示。 通过结构化指令定义代理的角色、步骤与边界:

python 复制代码
instructions = """
你是豪华旅游礼宾。你的职责是:
1. 先了解用户偏好(预算、气候、活动)
2. 推荐前确认目的地可用性
3. 给出个性化建议
4. 务必提及签证要求与最佳旅行季节
语气温暖、专业、热情。
"""

② 创建代理并运行。 as_agent 将系统提示并入代理;run 驱动一次交互:

python 复制代码
agent = make_client().as_agent(name="TravelConcierge", instructions=instructions)
response = await agent.run("预算2500美元,喜欢美食与历史,推荐一个目的地")

③ 完整代码(示例一)。

python 复制代码
import asyncio
from _deepseek import make_client

async def main():
    instructions = """
你是豪华旅游礼宾。你的职责是:
1. 先了解用户偏好(预算、气候、活动)
2. 推荐前确认目的地可用性
3. 给出个性化建议
4. 务必提及签证要求与最佳旅行季节
语气温暖、专业、热情。
"""
    agent = make_client().as_agent(
        name="TravelConcierge",
        instructions=instructions,
    )
    response = await agent.run(
        "预算2500美元,喜欢美食与历史,推荐一个目的地"
    )
    print(response)

if __name__ == "__main__":
    asyncio.run(main())

示例二:结构化输出(第 03 章落地)。

① Pydantic 定义输出结构。 用模型约束代理返回固定结构的 JSON:

python 复制代码
from pydantic import BaseModel

class DestinationRecommendation(BaseModel):
    destination: str
    available: bool
    best_season: str
    estimated_budget_usd: int

② 指令约束 + JSON 模式。 DeepSeek 不支持 response_format=Pydantic模型,改用 response_format={"type":"json_object"},并在指令中写明 JSON 结构,随后用 model_validate_json 解析:

python 复制代码
response = await agent.run(
    '推荐3个适合文化爱好者的目的地,预算2500美元。只输出 JSON:'
    '{"recommendations":[{"destination":"...","available":true,'
    '"best_season":"...","estimated_budget_usd":0}]}',
    options={"response_format": {"type": "json_object"}},
)
result = TravelPlan.model_validate_json(str(response))

③ 完整代码(示例二)。

python 复制代码
import asyncio
from pydantic import BaseModel
from _deepseek import make_client

class DestinationRecommendation(BaseModel):
    destination: str
    available: bool
    best_season: str
    estimated_budget_usd: int

class TravelPlan(BaseModel):
    recommendations: list[DestinationRecommendation]

async def main():
    agent = make_client().as_agent(
        name="结构化旅游专家",
        instructions="你是旅游专家,按指定 JSON 结构输出推荐结果。",
    )
    response = await agent.run(
        '推荐3个适合文化爱好者的目的地,预算2500美元。只输出 JSON:'
        '{"recommendations":[{"destination":"...","available":true,'
        '"best_season":"...","estimated_budget_usd":0}]}',
        options={"response_format": {"type": "json_object"}},
    )
    plan = TravelPlan.model_validate_json(str(response))
    for rec in plan.recommendations:
        print(rec.destination, rec.available, rec.estimated_budget_usd)

if __name__ == "__main__":
    asyncio.run(main())

示例三:工具调用与审批模式(第 04 章落地)。

① 定义工具。 @tool 将函数转化为工具;Annotated[type, "描述"] 为参数补充说明:

python 复制代码
from agent_framework import tool
from typing import Annotated

@tool(approval_mode="never_require")
def check_availability(destination: Annotated[str, "The destination to check"]) -> str:
    """Check booking availability for a destination."""
    availability = {"Barcelona": "Available", "Berlin": "Sold out"}
    return availability.get(destination, "Unknown destination")

② 审批模式。 对具有副作用的工具(如订票)使用 approval_mode="always_require",每次调用前需人工批准:

python 复制代码
@tool(approval_mode="always_require")
def book_flight(origin: Annotated[str, "Origin"], destination: Annotated[str, "Destination"]) -> str:
    """Book a flight. Requires approval before executing."""
    return f"Flight booked from {origin} to {destination}"

③ 完整代码(示例三)。

python 复制代码
import asyncio
from typing import Annotated
from agent_framework import tool
from _deepseek import make_client

@tool(approval_mode="never_require")
def check_availability(destination: Annotated[str, "The destination to check"]) -> str:
    """Check booking availability for a destination."""
    availability = {
        "Barcelona": "Available - 3 spots left",
        "Paris": "Available",
        "Berlin": "Sold out",
    }
    return availability.get(destination, "Unknown destination")

@tool(approval_mode="always_require")
def book_flight(
    origin: Annotated[str, "Origin airport code"],
    destination: Annotated[str, "Destination airport code"],
) -> str:
    """Book a flight for a passenger. Requires approval before executing."""
    return f"Flight booked from {origin} to {destination}"

async def main():
    agent = make_client().as_agent(
        name="TravelToolAgent",
        instructions="你是旅游代理,使用可用工具回答目的地、可用性与航班问题。",
        tools=[check_availability, book_flight],
    )
    response = await agent.run("哪些目的地还有空位?")
    print(response)
    print("book_flight 审批模式:", book_flight.approval_mode)

if __name__ == "__main__":
    asyncio.run(main())

运行前提:已按第 1 篇完成环境配置------创建 .envDEEPSEEK_API_KEY 填入开发者自有密钥 )与 _deepseek.py 共享客户端,并执行 pip install agent-framework python-dotenv openai pydantic


四、环境配置

环境配置与第 1 篇一致:创建 .env(含 DEEPSEEK_API_KEY=sk-<开发者自有密钥>DEEPSEEK_BASE_URLDEEPSEEK_MODEL)与共享客户端 _deepseek.py。本篇涉及结构化输出,额外安装 Pydantic。

相关推荐
啦啦啦啦啦zzzz1 天前
设计模式:桥接模式和组合模式
c++·设计模式·组合模式·桥接模式
莫得感情 o1 天前
设计模式 03 · 工厂方法模式
设计模式·工厂方法模式
cyforkk1 天前
高并发核心设计模式:Single-Flight 原理与实战
设计模式
饼干哥哥2 天前
字节Seedance2.5终于上线,这次在收割谁?
人工智能·设计模式·前端框架
董员外2 天前
RAG 系统进化论(六):GraphRAG(基于知识图谱的 RAG),从相似文本走向实体关系
人工智能·后端·设计模式
鬼鬼鬼2 天前
从 Prompt 到 Harness:企业级 Agent 工程的完整演进之路
设计模式·架构·ai编程
啦啦啦啦啦zzzz2 天前
设计模式:原型模式
c++·设计模式·原型模式
董员外2 天前
RAG 系统进化论(五):Corrective RAG 与 Self-RAG,让系统发现并纠正错误
人工智能·后端·设计模式
workflower2 天前
高质量数据集的类型
人工智能·机器学习·设计模式·自然语言处理·机器人