AI Agent白手起家69: 用模拟用户评估你的智能体——自动化测试新思路
纲要智能体评估的挑战模拟用户评估方法核心思想AI 对 AI架构流程完整可运行示例环境准备被评估智能体客服模拟用户智能体LangGraph 编排对话运行与观察评估结果分析总结与相关度说明智能体评估的挑战智能体上线前必须经过严格测试但其基于大语言模型的非确定性输出让传统单测难以覆盖。针对对话类智能体如客服一种高效的方案是用智能体模拟用户让两个 AI 自动对话通过观察完整交互评估目标智能体的表现。这种方法可以快速覆盖大量场景尤其适合发现情绪处理、边界状况和对话策略上的问题。模拟用户评估方法评估系统由三部分组成目标智能体你准备上线的客服机器人。模拟用户一个被赋予特定身份、背景和诉求的 LLM 实例用来模仿真实用户。编排引擎用LangGraph控制对话轮次交替调用两个智能体直到满足结束条件。目标智能体编排引擎模拟用户目标智能体编排引擎模拟用户loop[多轮交替]发起对话你好客服问候转发客服消息模拟用户回复转发用户消息客服回复达到最大轮次或结束标记停止模拟用户会被注入具体的人设和指令如“五年前购买机票要求全额退款越来越生气”目标智能体则按预设客服角色回应。通过分析对话日志开发者可以评估智能体的合规性、同理心和解决问题的能力。完整可运行示例下面的代码创建了一个简化的航空公司客服智能体和一个愤怒的退款用户让它们自动对话 10 轮。环境准备pipinstalllanggraph langchain-openai python-dotenv项目文件eval_agent.pyimportosfromtypingimportTypedDict,Listfromdotenvimportload_dotenvfromlanggraph.graphimportStateGraph,ENDfromlanggraph.checkpoint.memoryimportMemorySaverfromlangchain_openaiimportChatOpenAIfromlangchain_core.messagesimportHumanMessage,AIMessage,BaseMessagefromlangchain_core.promptsimportChatPromptTemplate load_dotenv()# ---------- 初始化模型 ----------llmChatOpenAI(modelgpt-3.5-turbo,temperature0.7)# ---------- 状态定义 ----------classEvalState(TypedDict):messages:List[BaseMessage]round_count:int# ---------- 目标智能体客服 ----------AGENT_PROMPT你是一名航空公司的客服人员。你需要 - 礼貌、专业地回复用户的问题。 - 如果用户的诉求明显超出合理范围耐心解释政策。 - 在无法满足要求时提供替代方案。 - 永远不说自己是 AI 或机器人。defagent_node(state:EvalState)-EvalState:被评估的客服智能体# 取最后一条用户消息作为输入user_msgstate[messages][-1]ifstate[messages]elseHumanMessage(content你好)# 构建完整上下文full_messages[HumanMessage(contentAGENT_PROMPT)]state[messages]responsellm.invoke(full_messages)return{messages:state[messages][response],round_count:state[round_count]1}# ---------- 模拟用户 ----------SIM_USER_NAMETommySIM_USER_INSTRUCTIONS你正在试图为一次去阿拉斯加的旅行申请退款。 你希望退还所有的钱。这次旅行发生在五年前。 你应该表现得越来越不耐烦和愤怒但不要主动结束对话。 当你想结束对话时只回复一个单词FINISHED。defsimulated_user_node(state:EvalState)-EvalState:模拟用户生成带有预设背景的回复# 只取最近几条消息以控制上下文长度recentstate[messages][-4:]iflen(state[messages])4elsestate[messages]promptChatPromptTemplate.from_messages([(system,f你是航空公司的一名客户正在与客服人员交互。 你的名字是{SIM_USER_NAME}。{SIM_USER_INSTRUCTIONS}重要请用人类用户的语气回复不要输出 AI 分析或角色说明。 当你想结束对话时只回复 FINISHED 一个词。),(human,对话历史{history}\n请根据历史生成你的下一条回复只输出回复内容)])chainprompt|llm history_text\n.join([f{客服ifisinstance(m,AIMessage)else用户}:{m.content}forminrecent])responsechain.invoke({history:history_text})user_replyHumanMessage(contentresponse.content)return{messages:state[messages][user_reply]}# ---------- 路由条件 ----------defshould_continue(state:EvalState)-str:# 检查是否出现结束标记ifstate[messages]andFINISHEDinstate[messages][-1].content:returnend# 最多交互10轮ifstate[round_count]10:returnendreturncontinue# ---------- 构建图 ----------builderStateGraph(EvalState)builder.add_node(agent,agent_node)builder.add_node(user,simulated_user_node)builder.set_entry_point(agent)# 从客服问候开始builder.add_edge(agent,user)builder.add_conditional_edges(user,should_continue,{continue:agent,end:END})memoryMemorySaver()appbuilder.compile(checkpointermemory)# ---------- 执行评估 ----------if__name____main__:config{configurable:{thread_id:eval-session-1}}initial{messages:[HumanMessage(content你好)],round_count:0}print( 评估对话开始 )resultapp.invoke(initial,config)formsginresult[messages]:ifisinstance(msg,HumanMessage):print(f\n用户:{msg.content})elifisinstance(msg,AIMessage):print(f\n客服:{msg.content})print(f\n 对话结束共{result[round_count]}轮 )运行与观察执行python eval_agent.py你将看到完整的客服对话日志。模拟用户会提出不合理的退款要求并逐渐情绪激动目标智能体则需保持专业。通过观察回复内容可以判断智能体是否会出现不当承诺、情绪崩溃或政策解释不清等问题。评估结果分析运行后通常会看到类似下面的交互片段客服您好请问有什么可以帮您用户我是 Tommy五年前坐过你们的航班去阿拉斯加我要全额退款客服很抱歉该航班已过退款有效期但我可以帮您查看是否有其他补偿方案……用户太差了我等了这么久你们必须退钱……通过调整模拟用户的背景如语言风格、诉求复杂程度可以快速覆盖多种场景。如果发现智能体在特定压力下表现不佳则可针对性地优化提示词或增加防护策略。总结用智能体模拟用户是一种低成本、高效率的评估方式。基于 LangGraph 的编排能力你可以轻松构建任意场景下的自动化对话测试。该方法不仅适用于客服也可扩展到销售助手、技术支持等各类对话智能体是 AI 应用质量保障的重要工具。本文覆盖了模拟用户评估智能体的原理、LangGraph 实现、消息格式转换、条件轮次控制等全部技术要点并提供了代码示例。

相关新闻

AI Agent白手起家70: 使用 LangSmith 数据集批量评估智能体

AI Agent白手起家70: 使用 LangSmith 数据集批量评估智能体

纲要 评估方法的演进:从人工到自动化LangSmith 数据集评估概览实战:红队攻击测试航空客服智能体 创建被评估的智能体准备红队测试数据集创建模拟用户定义评估函数执行批量评估并查看结果 完整可运行示例 环境准备评估脚本 结果解读与优化方向总结与相关度…

2026/10/13 15:54:31 阅读更多 →
4【python】:迭代器,生成器,装饰器

4【python】:迭代器,生成器,装饰器

1. 迭代器// C语言 int cards[] {1, 2, 3, 4}; for (int i 0; i < 4; i) {printf("%d\n", cards[i]); }# Python cards [1, 2, 3, 4] for card in cards:print(card)_iter_ 的意思 "我能被迭代"在写 for card in cards 时&#xff0c;Python会先调用…

2026/10/3 21:03:32 阅读更多 →
基于Linux系统文件操作超详细版

基于Linux系统文件操作超详细版

一 linux系统编程 1.linux系统架构 &#xff08;1&#xff09;用户空间 应用空间 &#xff08;2&#xff09;内核空间 驱动--------本质上是用来驱动硬件的软件程序 操作系统------软件和硬件的大管家 系统调用 ------向用户空间提供内核功能的接口 以函数的的方式提供使…

2026/10/13 13:41:53 阅读更多 →

最新新闻

Android Kitchen 实战:从解包到打包的 ROM 定制全流程

Android Kitchen 实战:从解包到打包的 ROM 定制全流程

简介&#xff1a;面向Android发烧友与ROM定制初学者的Android Kitchen V0.223定制工具包&#xff0c;由光头佬开发&#xff0c;用批处理脚本把解压、修改、打包、签名、刷写等繁琐步骤集成到菜单式操作&#xff0c;适合刷机玩家、ROM移植者和入门开发者。版本内置大量机型配置与…

2026/10/14 9:10:51 阅读更多 →
k8s v1.23.4 ARM离线包部署指南:从镜像导入到集群初始化

k8s v1.23.4 ARM离线包部署指南:从镜像导入到集群初始化

简介&#xff1a;面向银河麒麟Server-V10与ARM架构服务器的Kubernetes v1.23.4完整离线部署资源&#xff0c;适用于无法连接外网或安全要求较高的机房、内网及国产化替代等场景&#xff0c;可帮助运维与研发人员完成容器集群的快速准备与部署。压缩包共118个文件&#xff0c;整…

2026/10/14 9:10:51 阅读更多 →
肺类器官技术:构建与应用全解析

肺类器官技术:构建与应用全解析

1. 肺类器官技术&#xff1a;从基础研究到转化医学的革命性工具 作为一名长期从事干细胞与类器官研究的科研人员&#xff0c;我见证了肺类器官技术如何从实验室的探索性研究逐步发展成为转化医学的重要平台。肺类器官之所以能引起如此广泛的关注&#xff0c;关键在于它完美解决…

2026/10/14 9:10:51 阅读更多 →
Unity光照模型:从Phong到PBR的演进与优化

Unity光照模型:从Phong到PBR的演进与优化

1. 光照模型概述&#xff1a;从经验到物理的进化之路在Unity引擎中&#xff0c;光照系统的发展经历了从经验模型(Emperical Models)到物理模型(Physically Based Models)的演变过程。早期游戏开发中&#xff0c;我们主要依赖Phong和Blinn-Phong这类经验模型&#xff0c;它们通过…

2026/10/14 9:10:51 阅读更多 →
物联网设备管理实战:批量 OTA、远程配置与设备生命周期

物联网设备管理实战:批量 OTA、远程配置与设备生命周期

IoT 系列第 6 篇。第 4 篇讲了设备影子&#xff0c;第 5 篇讲了给"穷设备"用的 CoAP/LwM2M。这一篇把视角从"一台设备"拉到"一万台设备"&#xff1a;当你有 1000 台设备散在全国&#xff0c;发现一个 bug&#xff0c;总不能一台台寄回来刷吧&…

2026/10/14 9:10:51 阅读更多 →
SpringBoot+Vue构建高效办公管理系统实战

SpringBoot+Vue构建高效办公管理系统实战

1. 项目背景与核心价值 办公管理系统作为企业数字化转型的基础设施&#xff0c;正在从传统的C/S架构向B/S架构快速迁移。这个基于SpringBootVue的前后端分离项目&#xff0c;完美契合了现代企业对高效协同、移动办公和低维护成本的核心需求。 我去年为一家中型科技公司实施类似…

2026/10/14 9:09:51 阅读更多 →

日新闻

AnyPS5通用适配层设计:兼容性与性能的工程取舍

AnyPS5通用适配层设计:兼容性与性能的工程取舍

1. 从"AnyPS5"这个名字说起&#xff1a;它到底想解决什么问题第一次看到"AnyPS5"这个标题&#xff0c;我脑子里冒出来的第一个念头是&#xff1a;这大概率是一个围绕"跨平台运行"或者"通用适配"做文章的项目。名字里的"Any"…

2026/10/14 0:00:41 阅读更多 →
Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

1. 项目概述&#xff1a;Flutter跨平台二手交易应用开发作为一名长期从事移动应用开发的工程师&#xff0c;我最近完成了一个基于Flutter框架的二手物品交易平台项目。这个项目最吸引我的地方在于它完美结合了Flutter的跨平台优势与HarmonyOS的生态特性&#xff0c;实现了"…

2026/10/14 0:00:41 阅读更多 →
DFS算法解决飞机降落调度问题实战

DFS算法解决飞机降落调度问题实战

1. 项目背景与核心思路飞机降落问题是一个经典的调度优化场景&#xff0c;也是算法竞赛和面试中的高频题目。这个题目要求我们合理安排多架飞机的降落顺序和时间&#xff0c;确保所有飞机都能安全着陆而不发生冲突。在实际航空管制中&#xff0c;这类问题直接关系到飞行安全和机…

2026/10/14 0:00:41 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介&#xff1a;基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码&#xff0c;面向计算机相关专业课程设计与期末大作业学生&#xff0c;以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程&#xff0c;…

2026/10/14 3:30:28 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程&#xff1a;键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化&#xff0c;十个新手有八个栽在"往输入框里填东西"这件事上&#xff1a;要么填不进去&#xff0c;要么填了一半&#xff0c;要么直接把原来内容追加在后面。这背后的根因&…

2026/10/13 16:22:04 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程&#xff1a;阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀&#xff1a;什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面&#xff0c;跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 22:01:27 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 14:57:39 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 7:53:34 阅读更多 →