PEAS模型与Agent设计框架
*PEAS 模型——Performance(性能度量)、Environment(环境)、Actuators(执行器)、Sensors(传感器)*
PEAS 模型与 Agent 设计框架
1.1 为什么需要设计框架:凭直觉的代价
PEAS 模型——Performance(性能度量)、Environment(环境)、Actuators(执行器)、Sensors(传感器)
工程师在设计 Agent 时,最常见的路径是:想到什么功能加什么,遇到问题再修补。这种方式在简单场景下还凑合,但在稍复杂的真实场景里会导致系统性的设计缺陷。
凭直觉设计的典型问题:
- 加了很多工具,但没想清楚每个工具的边界,导致 Agent 在相似工具之间选择错误
- 没有定义"什么叫成功",上线后不知道 Agent 表现好不好,优化方向模糊
- 忽略了环境的动态性,用缓存数据回答了实时查询,给出过期信息
- 传感器设计不完整,Agent 无法获取做决策所需的关键信息
这些问题不是因为工程师能力差,而是因为在没有系统化框架的情况下,很容易只关注"Agent 能做什么",而忽略"Agent 在什么环境下做"和"怎么衡量做得好不好"。
PEAS 框架的四个维度及其设计价值
PEAS 框架来自经典 AI 教材《Artificial Intelligence: A Modern Approach》(Russell & Norvig),是在开始编码之前,系统性分析 Agent 设计需求的工具。四个字母分别代表:
P(Performance,性能指标) 解决的问题:怎么衡量 Agent 好不好?这个问题比想象中难——"回答得好"是主观感受,不是可测量的指标。Performance 迫使设计者把模糊的"好"转化为可量化的数字,比如"用户问题解决率 > 80%"。这是后续优化的基础,没有明确的指标,优化就无从入手。
E(Environment,环境) 解决的问题:Agent 在什么条件下工作?环境的特性直接决定 Agent 需要什么能力。动态环境要求实时数据,不能用缓存;部分可观测的环境要求 Agent 能主动澄清歧义;多轮环境要求对话历史记忆。忽略环境分析,就会在错误的假设下设计系统。
A(Actuators,执行器) 解决的问题:Agent 能影响哪些东西?执行器就是工具。这个维度迫使设计者把"Agent 能做什么"完整列出,而不是随意添加——每个工具都应该对应 Environment 里的一个需求。多余的工具增加决策复杂度,缺少的工具会导致 Agent 无法完成任务。
S(Sensors,传感器) 解决的问题:Agent 能感知哪些信息?传感器就是输入。这个维度检验 Agent 是否有足够的信息做出正确决策。如果某个决策需要某类信息,但传感器里没有获取这类信息的渠道,Agent 就会在信息不足的情况下猜测,导致错误。
第 01 篇在文末提到了 PEAS 框架,用它简单分析了天气查询 Agent。本篇做完整展开:PEAS 是什么、怎么用、用它分析一个真实的复杂 Agent(电商客服)会发现哪些设计盲点。
在设计一个 AI Agent 之前,往往面临这样的问题:应该给它配哪些工具?记忆需要持久化吗?失败了怎么处理?这些决策如果凭直觉拍板,等上线之后很可能发现遗漏了关键能力,或者设计了一堆用不上的功能。
PEAS 框架提供了一套系统化的分析方法,在动手实现之前,先把 Agent 所处的环境和需要具备的能力理清楚。
1.2 PEAS 框架
PEAS 来自经典 AI 教材《Artificial Intelligence: A Modern Approach》(Russell & Norvig),是设计理性 Agent 的基础分析工具。四个字母分别代表:
Performance(性能指标):怎么衡量 Agent 表现得好不好?这个问题比想象中难回答。性能指标必须是可测量的,不能停留在"回答得好"这种模糊描述。
Environment(环境):Agent 在什么环境下运行?环境的特性直接决定 Agent 需要什么能力。
Actuators(执行器):Agent 能做什么动作?执行器是 Agent 影响外部世界的手段,对应 AI Agent 中的"工具"概念。
Sensors(传感器):Agent 能感知什么信息?传感器是 Agent 获取外部信息的渠道,对应 AI Agent 中的"输入"概念。
1.3 用 PEAS 分析客服 Agent
以一个电商客服 Agent 为例,逐项填写 PEAS 分析表。
Performance(性能指标)
- 问题解决率:用户问题在本次对话中被解决的比例(目标 > 80%)
- 首次解决率(FCR):不需要人工介入就解决的比例
- 平均对话轮次:解决问题平均需要几轮对话(越少越好)
- 用户满意度评分:对话结束后的评分(1-5 分)
- 误触发人工:Agent 不该转人工但转了的比例(越低越好)
Environment(环境)
- 用户通过微信、APP、网页多渠道发起对话
- 对话是多轮的,用户的问题可能跨越多条消息
- 用户情绪多样,包含抱怨、催促、质疑等负面情绪
- 订单状态实时变化,同一问题在不同时间答案可能不同
- 有些问题没有标准答案(例如商品质量纠纷的处理)
Actuators(执行器/工具)
- 查询订单状态 API
- 查询物流信息 API
- 发起退款/退货流程
- 查询商品信息数据库
- 发送优惠券
- 转接人工客服
- 记录工单
Sensors(传感器/输入)
- 用户的文字消息
- 用户的历史订单(通过用户 ID 关联)
- 当前对话的完整历史
- 知识库(FAQ、退换货政策、产品手册)
- 用户账户信息(会员等级、历史投诉记录)
1.4 环境类型的分类
理解环境特性是设计 Agent 的关键。不同类型的环境需要不同的设计策略。
| 维度 | 类型A | 类型B | 客服 Agent 是哪种 |
|---|---|---|---|
| 可观测性 | 完全可观测 | 部分可观测 | 部分可观测(不知道用户真实意图) |
| 确定性 | 确定性 | 随机性 | 随机性(用户行为不可预测) |
| 时间性 | 静态 | 动态 | 动态(订单状态实时变化) |
| 连续性 | 离散 | 连续 | 离散(每条消息是独立事件) |
| 主体数量 | 单 Agent | 多 Agent | 单 Agent(加人工客服则是多 Agent) |
部分可观测性意味着 Agent 不能假设自己知道全部信息。客服 Agent 无法直接读取用户心理——用户说"这个不对",到底是商品有问题、物流延误、还是价格显示错误?需要通过提问来消除歧义。
随机性意味着 Agent 需要为意外情况准备回退策略。工具调用失败了怎么办?用户突然问了一个完全不相关的问题怎么处理?
动态环境意味着 Agent 不能缓存数据太久。查询订单状态时必须调用实时 API,不能用对话开头查到的状态一直用。
1.5 从 PEAS 到设计决策
PEAS 分析完成后,每个组成部分都应该对应具体的设计决策。
从 Performance 推导评估指标:性能指标要转化为可自动测量的数据。"问题解决率"可以用"用户是否在对话结束后给出正面反馈,或者没有再次发起同类问题"来衡量。
从 Environment 推导记忆设计:
- 动态环境 → 不能依赖缓存,关键数据必须实时获取
- 多轮对话 → 需要对话历史作为短期记忆
- 用户历史 → 需要用户级别的持久化记忆(历史订单、投诉记录)
从 Actuators 推导工具集:列出的每个工具都要问:这个工具是否有明确的成功/失败判断标准?失败时应该怎么处理?
从 Sensors 推导输入处理:传感器对应 Agent 的输入来源,每种输入来源都需要考虑:数据格式是什么?如何集成到上下文中?
1.6 从 PEAS 到代码
以下代码将 PEAS 分析结果直接转化为 Agent 实现框架。
验证目的:展示 PEAS 分析如何直接驱动代码设计——工具函数对应 Actuators,输入参数对应 Sensors,最大轮次保护对应 Performance,实时查询而非缓存对应 Environment 的动态性。
from openai import OpenAI
from typing import Optional
import json
client = OpenAI()
# ============================================================
# Actuators(执行器):工具函数
# 每个工具的设计对应 PEAS 分析中的一个执行动作
# ============================================================
def query_order(order_id: str, user_id: str) -> dict:
"""
查询订单状态。
设计说明:动态环境要求实时查询,不能缓存。
返回结构化数据而非字符串,方便 Agent 提取关键字段。
"""
# 实际项目中调用订单服务 API
# 这里用模拟数据演示
mock_orders = {
"ORD-001": {
"status": "已发货",
"logistics": "顺丰 SF1234567890",
"estimated_delivery": "2024-01-15",
"amount": 299.00,
}
}
if order_id in mock_orders:
return {"success": True, "data": mock_orders[order_id]}
return {"success": False, "error": f"订单 {order_id} 不存在或不属于该用户"}
def initiate_refund(order_id: str, reason: str, user_id: str) -> dict:
"""
发起退款申请。
设计说明:写操作必须校验权限(用户只能操作自己的订单),
返回申请编号方便后续跟进。
"""
# 实际场景需要校验订单归属、退款期限等业务规则
refund_id = f"RF-{order_id}-001"
return {
"success": True,
"refund_id": refund_id,
"message": f"退款申请已提交,预计 3-5 个工作日到账。申请编号:{refund_id}",
}
def search_knowledge_base(query: str) -> str:
"""
搜索知识库。
设计说明:对应 Sensors 中的知识库输入。
知识库检索失败应该有 fallback,不能让 Agent 无从作答。
"""
knowledge = {
"退换货": "支持 7 天无理由退换货,商品需保持原包装。发起退换后 24 小时内上门取件。",
"发票": "支持个人和企业抬头开票,订单完成后 15 天内可申请。",
"运费": "订单满 99 元免运费,不满 99 元收取 6 元运费。",
}
for key, value in knowledge.items():
if key in query:
return value
return "未找到相关信息,请联系人工客服获取帮助。"
def transfer_to_human(reason: str, user_id: str) -> dict:
"""
转接人工客服。
设计说明:必须记录转接原因,用于后续分析哪些场景 Agent 无法处理。
这是 Agent 能力边界的重要数据来源。
"""
return {
"success": True,
"queue_number": "A-0042",
"wait_time": "约 3 分钟",
"message": "正在为您转接人工客服,排队号:A-0042,预计等待 3 分钟。",
}
# ============================================================
# PEAS 驱动的 Agent 设计
# ============================================================
class CustomerServiceAgent:
"""
基于 PEAS 分析设计的客服 Agent。
Environment: 多轮对话、动态数据、部分可观测
→ 维护对话历史(短期记忆)
→ 所有数据实时查询,不缓存
Actuators: 查询/退款/知识库/转人工
→ 四个工具函数
Sensors: 用户消息 + 用户 ID(关联历史数据)
→ 每次调用传入 user_id
Performance: 问题解决率、对话轮次
→ 设置 max_turns 控制效率,到上限转人工
"""
SYSTEM_PROMPT = """你是一个专业的电商客服助手。
你的职责:
1. 帮助用户查询订单、物流状态
2. 协助处理退款、退换货申请
3. 回答产品和政策相关问题
4. 遇到无法处理的问题,转接人工客服
处理原则:
- 每次回答前先确认用户的具体问题
- 查询数据时务必使用工具获取实时数据,不能凭记忆作答
- 退款等写操作前,先向用户确认
- 超过 2 次无法解决用户问题,主动提出转人工"""
TOOLS = [
{
"type": "function",
"function": {
"name": "query_order",
"description": "查询订单状态、物流信息和金额",
"parameters": {
"type": "object",
"properties": {
"order_id": {"type": "string", "description": "订单号,格式如 ORD-001"},
"user_id": {"type": "string", "description": "用户 ID"},
},
"required": ["order_id", "user_id"],
},
},
},
{
"type": "function",
"function": {
"name": "initiate_refund",
"description": "为用户发起退款申请",
"parameters": {
"type": "object",
"properties": {
"order_id": {"type": "string"},
"reason": {"type": "string", "description": "退款原因"},
"user_id": {"type": "string"},
},
"required": ["order_id", "reason", "user_id"],
},
},
},
{
"type": "function",
"function": {
"name": "search_knowledge_base",
"description": "搜索知识库,获取退换货政策、发票、运费等信息",
"parameters": {
"type": "object",
"properties": {
"query": {"type": "string", "description": "搜索关键词"},
},
"required": ["query"],
},
},
},
{
"type": "function",
"function": {
"name": "transfer_to_human",
"description": "将用户转接到人工客服,当问题超出处理能力时使用",
"parameters": {
"type": "object",
"properties": {
"reason": {"type": "string", "description": "转人工的原因"},
"user_id": {"type": "string"},
},
"required": ["reason", "user_id"],
},
},
},
]
def __init__(self, user_id: str, max_turns: int = 10):
self.user_id = user_id
self.max_turns = max_turns
# 短期记忆:当前对话历史(对应 Sensors 中的"对话历史")
self.messages = [{"role": "system", "content": self.SYSTEM_PROMPT}]
self.turn_count = 0
self.tool_map = {
"query_order": query_order,
"initiate_refund": initiate_refund,
"search_knowledge_base": search_knowledge_base,
"transfer_to_human": transfer_to_human,
}
def chat(self, user_message: str) -> str:
"""处理一条用户消息,返回 Agent 的最终回复。"""
self.turn_count += 1
self.messages.append({"role": "user", "content": user_message})
# 保护机制:达到最大轮次,强制转人工
if self.turn_count >= self.max_turns:
return "本次对话已超过最大轮次,为您转接人工客服处理。"
while True:
response = client.chat.completions.create(
model="gpt-4o",
messages=self.messages,
tools=self.TOOLS,
tool_choice="auto",
temperature=0,
)
msg = response.choices[0].message
self.messages.append(msg)
# 没有工具调用,直接返回文本回复
if not msg.tool_calls:
return msg.content
# 执行工具调用
for tool_call in msg.tool_calls:
func_name = tool_call.function.name
func_args = json.loads(tool_call.function.arguments)
# 注入 user_id(安全设计:user_id 由系统注入,不依赖 LLM 传入)
if "user_id" in self.tool_map[func_name].__code__.co_varnames:
func_args["user_id"] = self.user_id
result = self.tool_map[func_name](**func_args)
self.messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"content": json.dumps(result, ensure_ascii=False),
})
# 使用示例
if __name__ == "__main__":
agent = CustomerServiceAgent(user_id="USER-12345")
conversations = [
"我的订单 ORD-001 发货了吗?",
"什么时候能到?",
"我想申请退款",
"退款政策是什么?",
]
for user_input in conversations:
print(f"\n用户:{user_input}")
reply = agent.chat(user_input)
print(f"客服:{reply}")
1.7 PEAS 分析的价值
PEAS 框架的核心价值不在于填表,而在于在动手写代码之前就发现设计遗漏。
以下是几个常见的、不经过 PEAS 分析就容易漏掉的设计点:
- 环境是动态的,忘了设计实时查询,用缓存数据回答——订单状态早变了,Agent 还在说"您的订单在途中"
- 传感器里有用户历史,没有设计长期记忆——同一用户第二次来,Agent 又从头问一遍
- 执行器里有退款工具,没有设计权限校验——用户可以退别人的单
- Performance 没定义,开发完不知道怎么算"好"——上线了靠主观感受评估
小结: PEAS 框架把 Agent 设计从"凭直觉加功能"变成"系统化分析需求"。四个维度分别回答"好的标准是什么、在什么环境下工作、能做什么、能感知什么",每个答案都直接对应代码层面的设计决策。