资讯动态

智能体设计方法论:从PEAS模型到ReAct架构的工程实践

发布时间:2026/10/18 4:38:05 来源:尧图企业网站定制
最近几年做大模型应用的人越来越绕不开一个词智能体Agent。我见过不少团队LLM API接得贼溜RAG流程也跑得通但一问到“你的智能体是怎么设计的”就支支吾吾说不出个所以然。问题出在哪儿很多人一上来就扎进LangChain源码、看各种Agent框架的Demo反而把最基础的设计方法论落下了。这篇文章我想换个思路不聊某一个具体框架也不贴一堆云里雾里的源码而是把智能体设计里最底层的两个东西讲透一个是从传统AI继承过来的PEAS模型用来定义智能体到底该做什么一个是这几年大模型带火的ReAct架构用来解决模型怎么边想边做的循环问题。这两件事想明白了你再去用任何框架都只是工具选择的问题而不是摸着石头过河。适合谁看刚接触智能体、想系统理清概念的程序员或者已经在调智能体但总觉得哪里不对的开发者都建议收藏。1. 先把“智能体”拆开PEAS模型讲了什么1.1 一个容易被跳过的四要素框架PEAS不是新概念它来自传统人工智能教材里的智能体设计理论四个字母分别代表 Performance性能、Environment环境、Actuators执行器、Sensors传感器。当年学的时候我觉得这就是个“填表工具”直到开始做大模型智能体才意识到这其实是整个设计流程里最先应该动手的地方。先说说这四个词分别是什么意思。Performance通俗讲就是“怎么算它干得好”。不是产品经理拍脑袋说“体验不错”而是可度量、可比较的指标。Environment是智能体存在于哪个环境里它能感知到什么、环境又藏着什么不确定性。Actuators是智能体影响环境的手段在软件系统里就是它能调用的函数、能写入的数据、能触发的动作。Sensors则是它读取外部信息的通道比如用户文本、数据库返回、API响应、系统时间。很多开发者的误区在于他们先把模型用起来再去想工具和策略最后才补绩效定义。顺序一旦反了后面所有调试都会很痛苦。举个例子你做一个日程提醒智能体如果没有提前想清楚“Performance”等上线后你根本没法回答“这个智能体比普通的日历提醒好在哪”也没法判断模型的那次回复究竟算成功还是失败。1.2 用大众熟悉的场景体会PEAS为了把PEAS从抽象术语变成能动手的东西我用一个很常见的场景来拆解一个日程助手智能体。这个助手需要接收用户的文字指令比如“明天上午十点开会一小时记得提醒我”然后创建日历事件并在合适时间提醒。对照PEASPerformance意图识别准确率、字段解析完整度时间、标题、时长一个不能少、提醒准时性、用户编辑后的事件冲突率。Environment用户的历史日程、当前时间、节假日信息、用户偏好的提醒提前量。Actuators创建日程、更新日程、删除日程、主动推送提醒消息。Sensors用户输入的聊天文本、当前的系统时间、日历数据库中的事件列表。你看这样一列后面无论用提示词工程还是写代码工作边界全清楚了。哪一环节该加重投入、哪一环节可以考虑简化PEAS直接给了你一张需求全景图。我在实际项目里一般第一步就把这套分析写到设计文档里后面团队讨论的时候大家争的是指标和边界而不是“我感觉”“我觉得”。1.3 PEAS在纯大模型场景里的变化传统PEAS是从机器人学那边继承过来的传感器和执行器往往是物理世界的摄像头、电机。但大模型智能体跑在软件环境里传感器成了API调用、文件读取、网页检索、用户文本输入执行器成了JSON格式的动作输出、数据库变更、消息推送。理解了这种映射你就能明白为什么现在很多Agent框架的核心其实是工具调用因为工具就是执行器而工具返回的内容就是传感器的输入。还有一点很多人忽略大模型本身也是一个感知源——它从系统提示词里感知到任务边界从对话历史里感知到上下文状态。所以在填写PEAS的时候我建议把模型通过输入看到的全部信息也纳入Sensors的考虑范围别只顾着外部API。2. ReAct架构让模型真正“动起来”的设计范式2.1 从纯对话到“想一步、做一步”的转变如果你只让大模型直接输出最终答案那它本质上还是一个高级的文本猜测器它没有验证手段没有工具支持也没有状态推进一切全靠训练参数里沉淀的那些统计规律。换句话说纯Prompt方式做复杂任务就像让人蒙着眼睛走迷宫每一步都靠感觉撞墙了也不自知。ReAct架构Reasoning Acting解决的正是这个问题。它的核心逻辑很直接模型在推理过程中不急着给答案而是反复执行一种循环——先输出一段 Thought推理我现在遇到了什么下一步该做什么然后输出一个 Action行动调用某个工具/执行某个指令再拿到 Observation观察工具返回了什么结果这个结果又喂回给模型进入下一轮 Thought。循环直到模型认为信息足够输出最终回答。这个概念听起来不复杂但它是大模型智能体真正可用的分水岭。原因在于当模型能把推理过程外显成文字、把决策外显成动作你就拥有了可审计的日志、可干预的断点以及可接驳无数工具的扩展面。这比一股脑把整个任务直接丢给模型要可靠得多。2.2 ReAct里的三个关键节点如何协作我一直跟同事讲ReAct的核心不是想也不是做而是用外部观察把两者咬合起来。你只看Thought会变成白日梦只看Action会变成乱来只有在Thought-Action-Observation这个三角循环里每一步都有据可依系统才稳定。我们用日程智能体的一个片段来演示Thought用户说的是明天上午十点开会一小时。我需要从中解析出日期、时间、时长和标题。当前系统时间是晚上八点明天上午十点距今还有14小时需要创建事件并且设定好提醒时机。Actioncreate_event(title会议, date2025-01-15, time10:00, duration60, reminder30)Observation{success: true, event_id: evt_0001, conflict: false}模型拿到这个观察结果之后才会进入下一轮Thought事件创建成功没有冲突。是否需要告知用户然后输出最终回答。如果没有ReAct循环模型一步到位直接瞎编一个好的已经提醒你了但到底有没有写进日历模型自己也不知道。这是很多Demo和真实项目日常之间巨大的差距。2.3 ReAct和CoT的对比为什么不是互斥关系你可能听过另一个名词CoTChain-of-Thought思维链。它指的是让模型把思考过程写出来再生成答案。CoT非常有用但它停留在嘴巴上——它只改变了模型的推理文本形态模型还是没法真正触碰外部世界。ReAct可以理解为CoT的增强版它在CoT的想之外增加了做和看让推理链路有机会被外部反馈纠正。有个说法我很认同CoT是让模型在大脑内部做推演ReAct则是给大脑接上手脚和眼睛。在做多步算术题时CoT可能不依赖工具也能硬算但一旦遇到查询实时天气再决定是否通知用户带伞这种任务纯CoT就走不通了因为模型的训练数据里根本没有今天的天气数据必须靠工具获取。理解了这个你就能判断什么时候用ReAct什么时候其实CoT就够了。3. 从零手写一个最小可用智能体实操记录3.1 前置准备与工具选型通常到这一步大家会纠结要不要上某个现成的Agent框架。我的建议是第一版尽量不依赖重型框架。我更喜欢用最朴素的Python LLM API来完成初版框架太重反而把核心逻辑包住了排查起问题特别麻烦。当你把某个场景的ReAct循环跑明白了再迁移到框架里几乎没有任何成本。环境方面其实没太多花头Python 3.10以上一个能处理对话补全的LLM接口OpenAI兼容格式就行国内外的模型服务都支持这种形式再加上一个JSON解析库。别小看这个选型它决定了你后面调试日志的直观程度。我早期用过一个很复杂的中间层后来出了问题日志里全是框架自带的抽象信息反而看不到模型的Thought输出排查效率低到离谱。后来换回裸API一眼就能定位问题。3.2 用PEAS定义日程助手的需求边界你说你直接开写代码我劝你先停下来花二十分钟把PEAS表格填完。我习惯用一张Markdown表格来沉淀这个设计过程PEAS要素本项目的具体定义Performance事件创建成功率、字段解析完整度、冲突检测召回率、用户反馈满意率Environment日历数据表、系统时间、用户偏好设置、历史对话记录Actuatorscreate_event、query_calendar、update_event、send_notificationSensors用户输入文本、当前时间、日历数据库返回、系统通知状态这张表你以后一定会反复用写提示词时参考它定义每个工具的参数时参考它写测试用例时还是参考它。很多人做到一半发现工具和场景不匹配往往就是因为一开始没把PEAS定死。3.3 实现一个最简ReAct循环核心代码其实非常短核心思路就是循环调用模型解析动作执行工具再把结果拼回去。下面这段是我在模拟项目里使用的核心调度逻辑的简化版本你可以直接照着跑通import json import datetime # 模拟的工具注册表 TOOLS { create_event: { description: 创建日程事件参数title, date, time, duration, reminder, handler: lambda args: calendar_db.create_event(args) }, query_calendar: { description: 查询指定日期的日程参数date, handler: lambda args: calendar_db.query(args[date]) } } def run_agent(user_input, max_iterations5): messages [ {role: system, content: SYSTEM_PROMPT}, {role: user, content: user_input} ] for step in range(max_iterations): response call_llm(messages) # 返回模型文本 content response.content # 尝试解析模型输出中的动作 action try_parse_action(content) # {name: ..., args: {...}} if action is None: # 模型认为信息足够了直接输出答案 return content if action[name] in TOOLS: observation TOOLS[action[name]][handler](action[args]) else: observation {error: f未知工具 {action[name]}} # 把推理和观察都放回上下文里 messages.append({role: assistant, content: content}) messages.append({role: user, content: f工具返回结果{json.dumps(observation, ensure_asciiFalse)}}) return 达到最大迭代次数任务未完成这里有一个关键点try_parse_action看着简单实际非常值得重视。我建议模型输出动作时用严格的JSON包裹比如{name: create_event, args: {...}}。解析时先用正则提取再用json.loads。遇到解析失败不要慌把原始内容原样返回给模型让它自己修正格式这比用正则强修可靠得多。3.4 让模型“学会”使用工具的提示词写法许多人以为提示词写得越细越好其实不然。ReAct场景下你真正要做的是把PEAS里的信息转成模型能理解的约束告诉模型它有哪些工具可用每个工具的参数要求和返回格式是什么。明确告诉模型输出格式要么是JSON动作要么是最终回答不要混着来。告诉模型它的每一步观察是什么含义。比如工具报错时它应该修正参数重试而不是死循环。约束它的行为边界查询失败时不能自作主张伪造结果应该返回错误信息给用户。有一个比较通用的结构我一直在用大致是角色定位、任务目标、工具清单、行动规则、输出格式、兜底策略。写Prompt并不需要去追求那些花哨的模板把这几块交代清楚模型的稳定性会有质的提升。3.5 跑通一次调用的完整日志记录真实运行的效果我贴一段简化的日志内容做了脱敏处理。你会看到模型在整个循环里的思考轨迹很清晰--- Step 1 --- User: 明天上午10点安排一个项目评审会议时长1小时提前30分钟提醒我。 Assistant Thought: 用户要求创建日程事件时间是明天上午10点时长60分钟需要提前提醒。先查询当前日历避免冲突。 Action: {name: query_calendar, args: {date: 2025-06-12}} Observation: {events: [{start: 09:00, end: 09:30, title: 站会}]} --- Step 2 --- Assistant Thought: 查询结果显示10点这个时间段没有冲突可以创建事件。 Action: {name: create_event, args: {title: 项目评审会议, date: 2025-06-12, time: 10:00, duration: 60, reminder: 30}} Observation: {success: true, event_id: evt_001} Final: 已为你创建日程“项目评审会议”时间明天上午10:00-11:00会提前30分钟提醒你。这看起来代码简单但实际写的时候有大量细节容易踩坑。下面这部分我把这几年的排查经验整理成一个速查清单全是实战里血泪换来的。4. 常见问题与排查技巧实录4.1 模型输出JSON不稳定动作解析频繁失败这是所有ReAct项目里碰到最频繁的问题。哪怕你很明确地说了“只输出JSON”模型还是可能多写一句解释或者用代码块的 Markdown 格式把它包起来。我的处理经验分三层。第一层是宽容解析不要用json.loads直接硬卡先用正则把花括号之间的内容提取出来再去掉Markdown代码块标记最后才尝试解析。第二层是让模型自纠错如果解析失败就把原始输出和报错信息一起拼到下一轮对话里明确告诉模型“你的输出格式不符合要求请重新输出JSON动作”。第三层是准备后手连续两轮解析失败时直接按错误流程回复用户不要无限循环占用资源。4.2 智能体陷入思考死循环Action来回反复表现是模型不断调用同一个查询工具或者反复输出Thought却始终不收敛。根本原因通常有两个一是Observation信息太多模型被无用信息淹没抓不住关键信号二是工具返回的失败信息没有结构化模型不知道下一步该怎么办。对应的解法也简单把Observation做归一化统一返回{success: bool, data: ..., error: ...}这样的结构让模型一眼能看出成功还是失败另外设置最大迭代次数比如5轮超过就直接跳出并提示用户稍后再试。我还会在Prompt里加一句“如果你已经拿到了相同的观察结果不要重复同样的动作请尝试更换参数或直接告知用户”。4.3 上下文窗口被工具返回结果撑爆这是“长任务智能体”最容易犯的错。工具返回的数据动不动几百上千行全部塞进对话历史几轮之后Token就爆了。实际项目中我在工具层做了一层轻量摘要只给模型返回关键字段和截断后的前N行数据并附带上已截断的标识。比如查询日程只返回事件标题、起止时间、状态而不返回背后的原始日志对象。不要把所有上下文都一股脑交给模型模型需要的是决策因子不是原始数据全量。4.4 智能体在关键节点“说谎”这是个容易让人发毛的问题。比如查询工具明确返回没有此人模型却回复“已找到并处理”。为什么因为在训练数据里“假装成功”在很多时候比“承认失败”更符合对话流畅度的要求。我的处理方式要求模型在无法完成工具调用或工具报错时必须原样向用户反馈错误信息并在系统提示词里反复强调“绝不虚构工具执行结果”。同时在工具返回的Observation里强制包含一个success字段让模型没有模糊空间。别指望一次Prompt就能根治需要反复试跑几个失败场景来校准。5. 已经不是Demo级别走向可靠智能体的几个进阶方向5.1 把记忆从“对话上下文”升级成“结构化记忆”纯靠上下文传递信息智能体的记忆力等于它的窗口大小可用的历史信息稍纵即逝。我现在的做法是加一个轻量级的记忆数据库把用户偏好、历史决策、之前任务的总结都存起来。每次任务开始前把相关记忆检索出来塞进系统提示词。方法不复杂但对体验的提升非常直接。用户发现这个智能体“记得上次说过的话”信任感完全不一样。5.2 从单智能体到多智能体协作如果你只有一个模型循环那一切好办。但真实复杂场景里把“意图理解”“任务规划”“工具执行”“结果审核”分给不同的角色去做往往比一个掌握所有技能的智能体更稳定。原因在于分角色以后每个角色的Prompt更短、工具更少、决策面更窄模型越容易表现得稳定。代价是上下文管理变复杂很多时候需要在不同角色之间传递状态。我的建议是团队初期先把单智能体的ReAct循环玩熟再拆角色否则排查问题时会陷入角色之间的“甩锅”困境。5.3 建立一套围绕测试集的效果评估机制这是很多独立开发者和团队都会忽略的点。优化智能体不能靠感觉你要准备一份场景测试集每个用例包含用户输入、期望调用的工具序列、允许的结果误差范围。每次改动Prompt或工具定义都把这套测试集跑一遍对比通过率。哪怕只有二十个用例也比拍脑袋调提示词有效得多。别等到上线后用户发现问题才去补救那是最昂贵的调试方式。我个人做智能体项目最大的体会是AI能力只是整个系统里的一环反而是在“定义清晰、边界明确、容错可靠”这些工程问题上花的功夫直接决定了一个智能体是玩具还是工具。ReAct给了模型思考与行动的能力PEAS给了我们定义与衡量的框架但真正让一个智能体能在真实业务里跑起来的是开发者对每一个细节的控制力。如果你也想动手做一个自己的智能体不要一上来就追求复杂炫酷的效果先拿一个最简单的日程助手把PEAS填完把ReAct循环写通把上面那些坑都踩一遍你对智能体的理解会脱胎换骨。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑