Agent角色扮演实战:我做了个7x24小时的客服Agent

说实话,之前我一直觉得让Agent"扮演"某个角色是个锦上添花的功能——不就是改个system prompt吗?

直到上周我接手了一个客服系统的需求,才发现角色扮演远不止改prompt那么简单。

为什么需要角色扮演

先说说场景。

我们有个电商SaaS平台,商家想要一个7x24小时的AI客服。这不是普通的问答——每个商家有自己的产品目录、售后政策、促销规则,而且语气风格还要跟品牌一致。

有的是搞怪潮牌,客服要跟用户打成一片;有的是高端美妆,客服要专业优雅。

同一个LLM,要同时扮演N种不同性格的角色。

角色设计:不只是改system prompt

很多人觉得角色扮演 = 写个System Prompt就完事了。

我一开始也这么想。

你是一个资深客服...

结果呢?聊两句就崩了。该专业的变啰嗦,该亲和的变敷衍。

角色金字塔

搞了三个版本后,我总结出一个方法:角色金字塔。

第一层:身份设定

  • 你是谁?什么岗位?什么性格?
  • 语气要专业还是随和?
  • 回复长度偏好?

第二层:行为规则

  • 遇到投诉怎么办?
  • 超出权限如何升级?
  • 促销信息怎么引导?

第三层:领域知识

  • 商品SKU库
  • 售后政策条款
  • 最近活动规则

每一层单独定义,然后按优先级合并。

实际代码

这是我的角色配置结构:

@dataclass
class AgentPersona:
    name: str
    brand_voice: str          # 品牌语调
    tone: str                 # "professional" | "casual" | "friendly"
    response_style: str       # 回复风格偏好
    max_response_tokens: int  # 回复长度限制
    
    def build_system_prompt(self, product_catalog, policy_rules):
        return f"""
你叫{self.name},是XX品牌的客服。
性格特点:{self.tone}
回复风格:{self.response_style}

【行为准则】
1. 用户问商品 → 先查产品目录再回答
2. 遇到投诉 → 表示理解 + 给出解决方案
3. 超过权限 → 转接人工客服

【产品信息】
{format_catalog(product_catalog)}

【售后政策】
{format_policy(policy_rules)}
"""

动态知识注入

这里有个坑:商家每天都在更新产品和活动。你不可能每次更新都重新微调。

我的做法是动态RAG注入

每次用户提问时,先通过向量检索找到相关的商品信息和当前促销活动,拼接到prompt中。

async def handle_user_query(query: str, persona: AgentPersona):
    # 1. 检索相关知识
    products = await vector_search(query, index="products", top_k=3)
    policies = await vector_search(query, index="policies", top_k=2)
    promos = await vector_search(query, index="promotions", top_k=2)
    
    # 2. 构建带角色的prompt
    system_msg = persona.build_system_prompt()
    context = f"相关商品:{products}\n售后政策:{policies}\n当前活动:{promos}"
    
    # 3. 调用LLM
    response = await llm.chat([
        {"role": "system", "content": system_msg},
        {"role": "user", "content": f"上下文:{context}\n用户提问:{query}"}
    ])
    return response

这个方案有一个好处:不需要微调,换角色就换一套persona配置,商家自己都能配。

情绪管理:最难的地方

客服场景里,用户有时候就是来发泄的。Agent怎么应对情绪化对话,我踩了不少坑。

一开始的版本,遇到用户骂人,Agent会一本正经地说:“请不要使用不文明语言。”

结果用户更怒了。

后来我加了个情绪标签系统:

用户情绪识别:
- anger → 先共情,再解决问题
- frustration → 快速给方案
- confusion → 拆解问题,一步步引导
- neutral → 直接回答问题
EMOTION_PROMPTS = {
    "anger": "先表达理解,不要解释或反驳:'{user_name},我很理解您的心情...'",
    "frustration": "直接给出明确方案:'这个情况我们需要这样处理...'",
    "confusion": "拆解问题:'我帮您梳理一下,主要有这几个方面...'",
    "neutral": "直接回答用户问题,简洁清晰。"
}

这一改,用户满意度直接从72%干到了89%。

多角色切换的工程挑战

最坑的一个场景:一个用户同时问售前和售后问题。

Agent需要同时扮演"销售顾问"和"售后专员"两个角色。我最初的做法是切分会话窗口,但用户体验很割裂。

最后方案是:角色堆叠

把多个视角的规则叠加到同一个Agent里,用标签区分当前回答的视角:

multi_role_prompt = """
你具备两个身份,根据用户问题的性质切换:

【身份A - 销售顾问】
负责:商品推荐、活动介绍
风格:热情、主动引导

【身份B - 售后专员】
负责:退换货、投诉处理
风格:稳重、解决问题为主

判断用户问题的类型,选择对应的身份回复。
如果是混合问题,先处理售后再引导销售。
"""

效果还行。虽然做不到完美,但用户满意度上了80%。

性能优化:别让角色扮演太慢

多了prompt拼接和RAG检索,响应时间很容易超过3秒。

我的优化三板斧:

  1. prompt预编译:角色配置中的固定部分(身份设定、行为规则)预渲染好,只替换动态部分
  2. RAG缓存:常用的商品和活动信息,有TTL缓存,不用每次都查向量库
  3. 流式输出:LLM响应用stream输出,用户感受不到延迟

上线后,P95延迟从4.2s降到了1.8s。

写在最后

Agent角色扮演这件事,往浅了说是prompt工程,往深了说是产品设计。

真正决定用户体验的,不是Agent能回答多少问题,而是它能不能让用户感觉——对面坐着的是一个有血有肉的人。

当然,这只是电商客服的场景。角色Agent在游戏NPC、虚拟主播、在线教育、心理咨询等领域还有很多玩法。

后续打算写一篇Agent角色扮演在游戏NPC中的应用,感兴趣的可以关注。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐