一、核心设计补全:意图识别与 Agent 路由的底层逻辑

多 Agent 系统的核心是 “精准路由”—— 让用户的自然语言问题,被正确分配到专业的子 Agent 处理,而这一切的前提是主 Agent 的双层意图识别机制

1. 主 Agent 的双层意图识别:从 “泛识别” 到 “精准匹配”

/chat接口中,我设计了 “第一层:基础意图分类(闲聊 / 无效 / 业务)+ 第二层:业务意图拆解(情感分析 / 主题挖掘等)” 的双层识别逻辑,核心实现如下:

核心代码与设计思考
# 主Agent对话接口中核心意图识别逻辑
intent_result = await dispatcher.scheduling_agent._identify_intent(request.message)
intent_type = intent_result.get("intent_type", IntentType.FULL_ANALYSIS)
routed_to = intent_type.value if hasattr(intent_type, "value") else str(intent_type)
yield f"data: {json.dumps({'routed_to': routed_to, 'intent_layer': intent_result.get('matched_layer', 1)}, ensure_ascii=False)}\n\n"

# ── 第一层意图短路逻辑:闲聊/无效问题快速响应 ──
if intent_type == IntentType.SMALL_TALK:
    async for chunk in llm_client.astream(
        [
            {"role": "system", "content": _SmallTalk.SYSTEM_PROMPT},
            {"role": "user", "content": request.message},
        ],
        temperature=0.8,
        max_tokens=400,
    ):
        yield f"data: {json.dumps({'content': chunk}, ensure_ascii=False)}\n\n"
    yield "data: [DONE]\n\n"
    return

if intent_type == IntentType.INVALID_QUESTION:
    yield f"data: {json.dumps({'content': '抱歉,您的问题超出了本系统的分析范围...'}, ensure_ascii=False)}\n\n"
    yield "data: [DONE]\n\n"
    return

# ── 第二层意图:业务分析意图拆解 ──
agent_names = dispatcher.scheduling_agent._decompose_tasks(intent_type, context)
sub_results = {}
for name in agent_names:
    if name in dispatcher.agents:
        sub_results[name] = await dispatcher.agents[name].execute(context)

设计思考

  • 分层识别的价值:第一层识别解决 “非业务问题快速响应”(如闲聊直接走 SmallTalkAgent,无需加载数据集),第二层识别解决 “业务问题精准分工”,既提升响应速度,又保证分析专业性;
  • 意图结果透传:通过 SSE 将routed_to(路由目标 Agent)、intent_layer(匹配层级)推送给前端,便于前端展示 “当前分析维度”,提升交互透明度;
  • 容错兜底:默认兜底为FULL_ANALYSIS(全量分析),避免意图识别失败导致系统不可用。

2. 子 Agent 专属接口:精细化承接特定场景需求

除了主 Agent 的 “自动路由”,我还设计了/sub-chat接口,支持用户直接指定子 Agent 对话(如仅调用营销文案 Agent),核心实现与设计如下:

核心代码与设计思考
# 子Agent能力映射表:固化Prompt与数据集依赖
AGENT_SYSTEM_PROMPTS = {
    "data_summary": ("你是数据摘要专家,专注于电商评论数量、评分分布、时间趋势等基础统计分析。只回答数据摘要相关问题。", True),
    "sentiment_analysis": ("你是情感分析专家,专注于电商评论的情感倾向、好差评比例、情感趋势分析。只回答情感分析相关问题。", True),
    "topic_mining": ("你是主题挖掘专家,专注于LDA主题建模、关键词聚类、评论话题识别。只回答主题挖掘相关问题。", True),
    "competitor": ("你是竞品分析专家,专注于产品横向对比、竞争优劣势分析。只回答竞品分析相关问题。", True),
    "marketing": ("你是营销文案专家,专注于基于用户评论生成营销文案、卖点提炼、差评应对话术。只回答营销文案相关问题。", True),
    "small_talk": (_SmallTalk.SYSTEM_PROMPT, False),
}

@router.post("/sub-chat", summary="子Agent专属对话(SSE流式)")
async def sub_agent_chat(request: SubAgentChatRequest, db: AsyncSession = Depends(get_db)):
    agent_key = request.agent_key
    if agent_key not in AGENT_SYSTEM_PROMPTS:
        async def err_gen():
            yield f"data: {json.dumps({'conversation_id': conversation_id, 'cannot_answer': True, 'content': '未知的 Agent 类型'}, ensure_ascii=False)}\n\n"
            yield "data: [DONE]\n\n"
        return _sse_stream(err_gen())

    system_prompt, needs_dataset = AGENT_SYSTEM_PROMPTS[agent_key]
    # 加载数据集(如需)+ 执行子Agent逻辑
    if needs_dataset and request.dataset_id:
        df = await _load_df(request.dataset_id, db)
        if df is not None and agent_key in dispatcher.agents:
            context = {...}
            agent_result = await dispatcher.agents[agent_key].execute(context)
            context_text = f"\n\n当前数据集分析结果:\n{json.dumps(agent_result, ensure_ascii=False, default=str)[:1500]}"
    
    # 流式返回子Agent响应
    messages = [
        {"role": "system", "content": system_prompt},
        {"role": "user", "content": request.message + context_text},
    ]
    async for chunk in llm_client.astream(messages, temperature=0.6, max_tokens=600):
        yield f"data: {json.dumps({'content': chunk}, ensure_ascii=False)}\n\n"

设计思考

  • 能力映射表的价值:将 “Agent 类型 → 专属 System Prompt → 数据集依赖” 固化为映射表,既保证每个子 Agent 的 Prompt 专业性(避免回答越界),又统一管理 “是否需要数据集” 的规则,降低接口逻辑复杂度;
  • 上下文裁剪:将子 Agent 的分析结果截断到 1500 字内拼接到 Prompt 中,既保证 LLM 有足够的上下文,又避免 Token 超限;
  • 明确的不可回答机制:当子 Agent 无法处理(如无数据集、Agent 不存在)时,返回cannot_answer标识,前端可针对性提示,避免模糊的错误信息。

二、Prompt 工程:从 “通用提问” 到 “约束式生成”

Prompt 是 LLM 能力落地的核心,我在系统中设计了三类 Prompt 范式:子 Agent 专属 System Prompt、营销文案约束式 Prompt、分析结果总结 Prompt,以下是核心实现与思考:

1. 子 Agent 专属 System Prompt:边界约束 + 专业定位

如上文AGENT_SYSTEM_PROMPTS所示,每个子 Agent 的 System Prompt 都遵循 “身份定位 + 能力边界” 的设计原则:

# 示例:情感分析Agent的System Prompt
"你是情感分析专家,专注于电商评论的情感倾向、好差评比例、情感趋势分析。只回答情感分析相关问题。"

设计思考

  • 身份锚定:明确 “专家” 身份,提升 LLM 回答的专业性;
  • 能力边界:通过 “只回答 XXX 相关问题” 约束回答范围,避免答非所问;
  • 简洁性:不堆砌冗余信息,保证 Prompt 的轻量化(降低 Token 消耗)。

2. 营销文案约束式 Prompt:结构化输出 + 数据驱动

营销文案生成是核心业务场景,我设计了 “数据输入 + 格式约束 + 内容要求” 的三层 Prompt,核心实现如下:

核心代码与设计思考
prompt = f"""你是专业电商营销文案师。根据以下用户好评高频词,生成三种风格的标题文案。

好评高频词(Top30):{', '.join(top_words)}

请生成:
1. 情感种草风文案(3条,如"一用就爱上"风格)
2. 功能卖点风文案(3条,突出技术/材质/体验)
3. 数据背书风文案(3条,用数据说话)
4. 卖点提炼清单(3-5条,每条≤20字,可直接用于详情页)
5. 差评应对话术(关切型/解释型/补偿型各1条)

请以JSON格式返回:
{{
  "emotional_copy": ["文案1", "文案2", "文案3"],
  "feature_copy": ["文案1", "文案2", "文案3"],
  "data_copy": ["文案1", "文案2", "文案3"],
  "key_points": ["卖点1", "卖点2", "卖点3"],
  "response_templates": {{
    "caring": "关切型话术",
    "explanatory": "解释型话术",
    "compensatory": "补偿型话术"
  }}
}}"""

设计思考

  • 数据驱动:将好评高频词作为输入,避免 LLM “凭空创作”,保证文案贴合真实用户反馈;
  • 格式约束:明确要求 JSON 格式 + 字段名称,前端可直接解析,无需额外处理;
  • 风格示例:通过 “如 ' 一用就爱上 ' 风格” 降低 LLM 的理解偏差,保证生成内容符合业务预期;
  • 长度限制:卖点提炼要求 “每条≤20 字”,适配电商详情页的展示场景。

3. 分析结果总结 Prompt:轻量化 + 场景化

主 Agent 在聚合子 Agent 分析结果后,需要将结构化数据转为自然语言回答,此时的 Prompt 设计核心是 “轻量化 + 场景化”:

summary_ctx = json.dumps(sub_results, ensure_ascii=False, default=str)[:2000]
prompt = f"""用户问题:{request.message}

以下是各分析模块的结果:
{summary_ctx}

请根据以上数据,用自然语言简洁地回答用户的问题。"""

设计思考

  • 上下文截断:限制在 2000 字内,平衡 “信息完整性” 与 “Token 消耗”;
  • 用户问题前置:让 LLM 优先聚焦用户核心诉求,避免回答偏离;
  • 指令简洁化:仅要求 “自然语言简洁回答”,避免过度约束导致回答僵硬。

三、工程化落地:意图识别与 Prompt 的避坑指南

在落地意图识别和 Prompt 工程的过程中,我踩了多个关键坑,也总结了对应的解决方案:

1. 意图识别的 “误判” 问题:多轮验证 + 兜底逻辑

  • 问题:初期直接通过关键词匹配意图,导致 “用户问‘竞品的情感分析’” 被误判为 “情感分析” 而非 “竞品分析”;
  • 解决方案
    1. 升级为 LLM 驱动的意图识别(而非关键词),Prompt 中明确要求识别 “核心诉求 + 分析维度”;
    2. 增加FULL_ANALYSIS兜底逻辑,即使意图识别失败,也会调用全量子 Agent 分析,保证回答可用;
    3. 前端透传routed_to字段,用户可手动切换子 Agent,弥补机器识别的不足。

2. Prompt 的 “格式失控” 问题:正则提取 + 兜底返回

  • 问题:营销文案生成时,LLM 偶尔返回非 JSON 格式(如额外的解释文字),导致前端解析失败;
  • 解决方案
    1. 用正则re.search(r'\{.*\}', response, re.DOTALL)提取 JSON 片段,忽略冗余内容;
    2. 解析失败时返回兜底文案,保证接口可用性;
    3. System Prompt 中强化 “仅返回 JSON,无需额外解释” 的约束。

3. 子 Agent 接口的 “数据集依赖” 问题:前置校验 + 友好提示

  • 问题:用户调用需要数据集的子 Agent(如情感分析)但未传dataset_id,导致接口报错;
  • 解决方案
    1. AGENT_SYSTEM_PROMPTS中标记needs_dataset,前置校验数据集是否存在;
    2. 无数据集时返回友好提示(如 “请先选择数据集,我才能帮你分析哦”),而非技术错误;
    3. 加载数据集失败时,仍保留纯 LLM 的 “通用回答” 能力(如 “情感分析通常包括好差评比例、情感趋势等维度...”)。

四、补充总结:多 Agent 系统的 “灵魂” 是 “精准分工 + 可控生成”

本次补充的「主 Agent 意图识别」「子 Agent 接口承接」「Prompt 工程」三大模块,是多 Agent 系统的 “灵魂”—— 意图识别解决 “该让谁做” 的问题,子 Agent 接口解决 “精准做” 的问题,Prompt 工程解决 “怎么做才符合预期” 的问题。

从技术落地角度,我最深的体会是:

  1. 意图识别不是 “越精准越好”,而是 “容错性越好越好”:即使识别有误,也要通过兜底逻辑保证系统可用;
  2. Prompt 不是 “越长越好”,而是 “约束越清晰越好”:结构化、轻量化的 Prompt,比大段模糊的描述更有效;
  3. 子 Agent 的 “专业化” 与 “易用性” 要平衡:既要有专属接口满足精细化需求,也要有主 Agent 的自动路由降低用户使用成本。

未来的优化方向也将围绕这三点展开:

  1. 意图识别引入用户反馈闭环(标记误判案例,优化 Prompt);
  2. Prompt 模板化管理(支持配置化修改,无需改代码);
  3. 子 Agent 能力动态扩展(支持新增 Agent 时自动注册到映射表)。

多 Agent 系统的本质,是用工程化的方式让 LLM 的能力 “分而治之”,而意图识别和 Prompt 则是连接用户需求与 Agent 能力的桥梁 —— 只有桥梁搭得稳、搭得准,整个系统才能真正从 “能用” 走向 “好用”。

Logo

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

更多推荐