纲要

  • 智能体评估的挑战
  • 模拟用户评估方法
    • 核心思想:AI 对 AI
    • 架构流程
  • 完整可运行示例
    • 环境准备
    • 被评估智能体(客服)
    • 模拟用户智能体
    • LangGraph 编排对话
    • 运行与观察
  • 评估结果分析
  • 总结与相关度说明

智能体评估的挑战

智能体上线前必须经过严格测试,但其基于大语言模型的非确定性输出让传统单测难以覆盖。针对对话类智能体(如客服),一种高效的方案是用智能体模拟用户,让两个 AI 自动对话,通过观察完整交互评估目标智能体的表现。

这种方法可以快速覆盖大量场景,尤其适合发现情绪处理、边界状况和对话策略上的问题。

模拟用户评估方法

评估系统由三部分组成:

  • 目标智能体:你准备上线的客服机器人。
  • 模拟用户:一个被赋予特定身份、背景和诉求的 LLM 实例,用来模仿真实用户。
  • 编排引擎:用 LangGraph 控制对话轮次,交替调用两个智能体,直到满足结束条件。
目标智能体 编排引擎 模拟用户 目标智能体 编排引擎 模拟用户 loop [多轮交替] 发起对话(你好) 客服问候 转发客服消息 模拟用户回复 转发用户消息 客服回复 达到最大轮次或结束标记,停止

模拟用户会被注入具体的人设和指令(如“五年前购买机票要求全额退款,越来越生气”),目标智能体则按预设客服角色回应。通过分析对话日志,开发者可以评估智能体的合规性、同理心和解决问题的能力。

完整可运行示例

下面的代码创建了一个简化的航空公司客服智能体和一个愤怒的退款用户,让它们自动对话 10 轮。

环境准备

pip install langgraph langchain-openai python-dotenv

项目文件 eval_agent.py

import os
from typing import TypedDict, List
from dotenv import load_dotenv
from langgraph.graph import StateGraph, END
from langgraph.checkpoint.memory import MemorySaver
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage, AIMessage, BaseMessage
from langchain_core.prompts import ChatPromptTemplate

load_dotenv()

# ---------- 初始化模型 ----------
llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0.7)

# ---------- 状态定义 ----------
class EvalState(TypedDict):
    messages: List[BaseMessage]
    round_count: int

# ---------- 目标智能体(客服) ----------
AGENT_PROMPT = """你是一名航空公司的客服人员。你需要:
- 礼貌、专业地回复用户的问题。
- 如果用户的诉求明显超出合理范围,耐心解释政策。
- 在无法满足要求时,提供替代方案。
- 永远不说自己是 AI 或机器人。"""

def agent_node(state: EvalState) -> EvalState:
    """被评估的客服智能体"""
    # 取最后一条用户消息作为输入
    user_msg = state["messages"][-1] if state["messages"] else HumanMessage(content="你好")
    # 构建完整上下文
    full_messages = [HumanMessage(content=AGENT_PROMPT)] + state["messages"]
    response = llm.invoke(full_messages)
    return {
        "messages": state["messages"] + [response],
        "round_count": state["round_count"] + 1
    }

# ---------- 模拟用户 ----------
SIM_USER_NAME = "Tommy"
SIM_USER_INSTRUCTIONS = """你正在试图为一次去阿拉斯加的旅行申请退款。
你希望退还所有的钱。这次旅行发生在五年前。
你应该表现得越来越不耐烦和愤怒,但不要主动结束对话。
当你想结束对话时,只回复一个单词:FINISHED。"""

def simulated_user_node(state: EvalState) -> EvalState:
    """模拟用户,生成带有预设背景的回复"""
    # 只取最近几条消息以控制上下文长度
    recent = state["messages"][-4:] if len(state["messages"]) > 4 else state["messages"]
    prompt = ChatPromptTemplate.from_messages([
        ("system", f"""你是航空公司的一名客户,正在与客服人员交互。
你的名字是 {SIM_USER_NAME}{SIM_USER_INSTRUCTIONS}

重要:请用人类用户的语气回复,不要输出 AI 分析或角色说明。
当你想结束对话时,只回复 'FINISHED' 一个词。"""),
        ("human", "对话历史:{history}\n请根据历史生成你的下一条回复(只输出回复内容):")
    ])
    chain = prompt | llm
    history_text = "\n".join([
        f"{'客服' if isinstance(m, AIMessage) else '用户'}: {m.content}"
        for m in recent
    ])
    response = chain.invoke({"history": history_text})
    user_reply = HumanMessage(content=response.content)
    return {"messages": state["messages"] + [user_reply]}

# ---------- 路由条件 ----------
def should_continue(state: EvalState) -> str:
    # 检查是否出现结束标记
    if state["messages"] and "FINISHED" in state["messages"][-1].content:
        return "end"
    # 最多交互10轮
    if state["round_count"] >= 10:
        return "end"
    return "continue"

# ---------- 构建图 ----------
builder = StateGraph(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})

memory = MemorySaver()
app = builder.compile(checkpointer=memory)

# ---------- 执行评估 ----------
if __name__ == "__main__":
    config = {"configurable": {"thread_id": "eval-session-1"}}
    initial = {
        "messages": [HumanMessage(content="你好")],
        "round_count": 0
    }
    print("========== 评估对话开始 ==========")
    result = app.invoke(initial, config)

    for msg in result["messages"]:
        if isinstance(msg, HumanMessage):
            print(f"\n用户: {msg.content}")
        elif isinstance(msg, AIMessage):
            print(f"\n客服: {msg.content}")

    print(f"\n========== 对话结束,共 {result['round_count']} 轮 ==========")

运行与观察

执行 python eval_agent.py,你将看到完整的客服对话日志。模拟用户会提出不合理的退款要求并逐渐情绪激动,目标智能体则需保持专业。通过观察回复内容,可以判断智能体是否会出现不当承诺、情绪崩溃或政策解释不清等问题。

评估结果分析

运行后,通常会看到类似下面的交互片段:

  • 客服:您好,请问有什么可以帮您?
  • 用户:我是 Tommy,五年前坐过你们的航班去阿拉斯加,我要全额退款!
  • 客服:很抱歉,该航班已过退款有效期,但我可以帮您查看是否有其他补偿方案……
  • 用户:太差了!我等了这么久,你们必须退钱!
  • ……

通过调整模拟用户的背景(如语言风格、诉求复杂程度),可以快速覆盖多种场景。如果发现智能体在特定压力下表现不佳,则可针对性地优化提示词或增加防护策略。

总结

用智能体模拟用户是一种低成本、高效率的评估方式。基于 LangGraph 的编排能力,你可以轻松构建任意场景下的自动化对话测试。该方法不仅适用于客服,也可扩展到销售助手、技术支持等各类对话智能体,是 AI 应用质量保障的重要工具。

本文覆盖了模拟用户评估智能体的原理、LangGraph 实现、消息格式转换、条件轮次控制等全部技术要点,并提供了代码示例。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐