第 20 期 | Agent 评测与反馈:LLM-as-a-judge

⏱ 预计阅读 20 分钟 更新于 2026/5/7
💡 进群学习加 wx: agentupdate
(申请发送: agentupdate)

好的,各位未来的 AI 全栈大师们!我是你们的导师,一个在 AI 领域摸爬滚打十年的老兵,也是一个对教育充满热情的布道者。很高兴能在《LangChain 全栈大师课:从零基础到生产级 AI 应用》的课堂上再次与大家相见。

经过前两期的预热和基础铺垫,我们已经对 LangChain 有了初步的认识,知道它是构建复杂 LLM 应用的“瑞士军刀”。但光有工具还不够,我们还得学会怎么“用”这个工具,怎么和底层的 AI 模型打交道。

今天,我们要揭开 AI 应用中最核心、最艺术,也最容易被忽视的一环——Prompt Engineering 的神秘面纱。在我们的“智能客服知识库”项目中,Prompt Engineering 简直就是客服小助手的“灵魂画师”,它决定了我们的 AI 是一个只会鹦鹉学舌的复读机,还是一个真正能理解用户意图、提供精准且有温度服务的智能伙伴。


🎯 本期学习目标

在本期课程中,你将不仅仅是学习 Prompt Engineering 的理论,更要将它实实在在地运用到我们的智能客服项目中,让你的 AI 应用能力实现质的飞跃:

  1. 理解 Prompt Engineering 的核心原理及其在 AI 应用中的重要性:掌握如何通过精心设计的 Prompt,与大模型进行高效沟通,从而实现特定任务。
  2. 掌握 LangChain 中 PromptTemplate 的基本使用:学会如何利用 LangChain 提供的强大工具,为我们的智能客服构建可复用、可定制化的指令。
  3. 学习如何设计结构化、清晰的 Prompt:提升客服小助手理解用户意图、提取关键信息和生成精准回复的能力,告别“牛头不对马嘴”的尴尬。
  4. 初步探索 Few-shot Prompting:了解如何通过提供少量示例,让模型更好地理解任务模式和期望的输出格式,进一步提升客服回复的质量和一致性。

📖 原理解析

各位同学,听好了!如果你觉得 Prompt Engineering 就是简单地给 AI 提个问题,那你就大错特错了。它可不是简单的问答游戏,它更像是一门和 AI 沟通的艺术,你得学会怎么和这个超级聪明的“小朋友”把话说清楚,把你的需求表达得明明白白。

在我们的“智能客服知识库”项目中,用户可能会问各种各样的问题:“我的订单在哪里?”,“如何申请退货?”,“你们的会员积分怎么用?”,甚至是一些模糊的抱怨。我们的智能客服需要做的,不仅仅是找到答案,更要理解用户真正的意图,提取关键信息,然后以一种专业、友好、符合品牌调性的方式给出回复。这一切的背后,都离不开 Prompt Engineering 的功劳。

Prompt Engineering 是什么? 简单来说,Prompt Engineering 就是设计和优化输入给大型语言模型 (LLM) 的文本指令(即 Prompt),以引导模型产生期望输出的过程。它包含了一系列技巧和策略,旨在最大化 LLM 的性能,使其在特定任务上表现得更准确、更相关、更高效。

为什么 Prompt Engineering 对智能客服如此关键?

  1. 意图理解(Intent Understanding):用户输入的自然语言往往含糊不清,Prompt 可以指导 LLM 识别出用户提问的核心意图,例如是查询订单、退换货还是技术支持。
  2. 信息提取(Information Extraction):从用户输入中提取关键实体,如订单号、商品名称、问题描述等,为后续的知识库检索或 API 调用提供参数。
  3. 回复生成(Response Generation):在获取到相关信息后,Prompt 可以指导 LLM 以特定的语气、格式和内容生成最终回复,确保回复的专业性、准确性和用户友好性。
  4. 角色扮演与约束(Role-playing & Constraints):通过 Prompt,我们可以让 LLM 扮演一个“资深客服专家”的角色,并限制其回答范围,避免生成无关或不当的内容。

一个好的 Prompt,通常包含以下几个核心要素:

  • 指令 (Instruction):清晰明确地告诉模型要做什么。
  • 上下文 (Context):提供必要的背景信息,帮助模型更好地理解任务。
  • 输入数据 (Input Data):用户实际的查询或需要处理的数据。
  • 输出格式 (Output Format):明确期望的输出结构(如 JSON、列表、段落)。
  • 示例 (Examples - Few-shot):通过提供少量输入-输出对的示例,让模型学习任务模式。
  • 约束 (Constraints):限制模型的行为,如语气、长度、不允许提及的内容等。

Mermaid 图解:Prompt Engineering 在智能客服中的工作流

理解了这些,我们再来看一下 Prompt Engineering 在我们的智能客服项目中的核心地位。它就像一个翻译官,把我们人类的需求翻译成 AI 能懂的语言,再把 AI 的“思考”翻译成人类能懂的答案。

graph TD
    A[用户输入原始问题] --> B{Prompt Engineering - 意图理解}
    B --> C[Prompt Template for Intent Classification]
    C --> D[LLM (e.g., GPT-4)]
    D --> E{分类意图: ORDER_STATUS, REFUND, PRODUCT_INFO...}
    E -- 匹配意图 --> F[从知识库/DB中检索相关信息]
    F --> G{Prompt Engineering - 回复生成}
    G --> H[Prompt Template for Response Generation]
    H --> I[LLM (e.g., GPT-4)]
    I --> J[生成最终客服回复]
    J --> K[返回给用户]

    subgraph Prompt Engineering 的核心作用
        C
        H
    end

    style B fill:#f9f,stroke:#333,stroke-width:2px
    style G fill:#f9f,stroke:#333,stroke-width:2px

从图中可以看到,无论是理解用户意图,还是基于检索到的信息生成最终回复,Prompt Engineering 都扮演着核心的“灵魂画师”角色。它确保了 AI 能够“开窍”,而不是“开溜”。

LangChain 中的 PromptTemplate

LangChain 对 Prompt Engineering 提供了非常友好的抽象——PromptTemplate。它允许我们定义一个带有占位符的字符串模板,然后动态地填充这些占位符,生成最终的 Prompt。这大大提升了 Prompt 的可维护性和复用性。

想象一下,如果每次用户提问,你都要手动构造一个包含所有指令、上下文和用户问题的长字符串,那简直是地狱!PromptTemplate 就是来拯救你的!

💻 实战代码演练 (客服项目中的具体应用)

好了,理论铺垫到此为止,是时候撸起袖子干活了!我们将用 LangChain 的 PromptTemplate 来武装我们的智能客服小助手。

场景一:意图分类 - 让客服小助手准确理解用户想干嘛

在智能客服中,第一步往往是理解用户的意图。例如,用户问“我的快递到哪了?”,我们应该识别出这是“订单状态查询”;如果问“买错了,能退吗?”,则是“退货政策咨询”。

我们将构建一个 Prompt Template,让 LLM 帮助我们进行意图分类。

# Python 代码示例
from langchain_core.prompts import PromptTemplate
from langchain_openai import ChatOpenAI
from langchain_core.output_parsers import StrOutputParser

import os
# 设置你的 OpenAI API Key
# 实际项目中,请使用环境变量或更安全的配置方式
# os.environ["OPENAI_API_KEY"] = "YOUR_OPENAI_API_KEY" # 替换为你的实际 API Key

print("--- 场景一:意图分类 - 让客服小助手准确理解用户想干嘛 ---")

# 1. 定义意图分类的 PromptTemplate
# 我们会给模型一些明确的指令,告诉它有哪些可能的意图,并要求它只返回意图名称
intent_classification_template = """
你是一名专业的电商客服意图分类机器人。你的任务是根据用户的提问,将其归类到最符合的意图类别中。
请从以下可用类别中选择一个,并只返回该类别的名称。如果没有任何类别匹配,请返回 "UNKNOWN"。

可用类别:
- ORDER_STATUS: 查询订单状态、物流信息
- REFUND_RETURN: 申请退货、退款、查询退换货政策
- PRODUCT_INFO: 查询商品详情、库存、功能、推荐
- ACCOUNT_MANAGEMENT: 账户问题、密码重置、个人信息修改
- TECHNICAL_SUPPORT: 技术故障、网站使用问题
- COMPLAINT_SUGGESTION: 投诉、建议、反馈
- OTHER: 其他不属于上述类别的通用问题

用户提问: "{user_query}"
请选择最匹配的意图类别:
"""

# 使用 PromptTemplate 创建一个可格式化的 Prompt 对象
intent_prompt = PromptTemplate.from_template(intent_classification_template)

# 2. 初始化 LLM
# 这里我们使用 OpenAI 的 GPT-3.5-turbo 模型
# temperature 参数设置为 0,表示我们希望模型给出确定性、一致性的回答,这对于分类任务很重要
llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)

# 3. 构建 LangChain 链
# PromptTemplate | LLM | OutputParser
intent_chain = intent_prompt | llm | StrOutputParser()

# 4. 模拟用户提问并获取意图分类
user_queries = [
    "我的包裹到哪了?",
    "我买的衣服尺寸不合适,想退货怎么办?",
    "这款手机的电池续航怎么样?",
    "我的账户好像被盗了,登录不进去。",
    "你们网站太卡了,能不能优化一下?",
    "你们今天晚餐吃什么?", # 一个不相关的提问
    "我有一个关于商品材质的问题" # 另一个商品信息相关提问
]

print("\n--- 开始意图分类测试 ---")
for query in user_queries:
    # 使用 chain.invoke() 来执行链,传入用户查询
    classified_intent = intent_chain.invoke({"user_query": query})
    print(f"用户提问: '{query}' -> 分类意图: '{classified_intent}'")

# TypeScript 代码示例 (概念演示,不直接运行,需配置环境)
"""
// import { PromptTemplate } from "@langchain/core/prompts";
// import { ChatOpenAI } from "@langchain/openai";
// import { StringOutputParser } from "@langchain/core/output_parsers";

// // 设置你的 OpenAI API Key
// // process.env.OPENAI_API_KEY = "YOUR_OPENAI_API_KEY";

// console.log("--- 场景一:意图分类 - 让客服小助手准确理解用户想干嘛 ---");

// const intentClassificationTemplate = `
// 你是一名专业的电商客服意图分类机器人。你的任务是根据用户的提问,将其归类到最符合的意图类别中。
// 请从以下可用类别中选择一个,并只返回该类别的名称。如果没有任何类别匹配,请返回 "UNKNOWN"。

// 可用类别:
// - ORDER_STATUS: 查询订单状态、物流信息
// - REFUND_RETURN: 申请退货、退款、查询退换货政策
// - PRODUCT_INFO: 查询商品详情、库存、功能、推荐
// - ACCOUNT_MANAGEMENT: 账户问题、密码重置、个人信息修改
// - TECHNICAL_SUPPORT: 技术故障、网站使用问题
// - COMPLAINT_SUGGESTION: 投诉、建议、反馈
// - OTHER: 其他不属于上述类别的通用问题

// 用户提问: "{user_query}"
// 请选择最匹配的意图类别:
// `;

// const intentPrompt = PromptTemplate.fromTemplate(intentClassificationTemplate);

// const llm = new ChatOpenAI({ modelName: "gpt-3.5-turbo", temperature: 0 });

// const intentChain = intentPrompt.pipe(llm).pipe(new StringOutputParser());

// const userQueries = [
//     "我的包裹到哪了?",
//     "我买的衣服尺寸不合适,想退货怎么办?",
//     "这款手机的电池续航怎么样?",
//     "我的账户好像被盗了,登录不进去。",
//     "你们网站太卡了,能不能优化一下?",
//     "你们今天晚餐吃什么?",
//     "我有一个关于商品材质的问题"
// ];

// async function runIntentClassification() {
//     console.log("\n--- 开始意图分类测试 ---");
//     for (const query of userQueries) {
//         const classifiedIntent = await intentChain.invoke({ user_query: query });
//         console.log(`用户提问: '${query}' -> 分类意图: '${classifiedIntent}'`);
//     }
// }

// runIntentClassification();
"""

运行结果示例:

--- 场景一:意图分类 - 让客服小助手准确理解用户想干嘛 ---

--- 开始意图分类测试 ---
用户提问: '我的包裹到哪了?' -> 分类意图: 'ORDER_STATUS'
用户提问: '我买的衣服尺寸不合适,想退货怎么办?' -> 分类意图: 'REFUND_RETURN'
用户提问: '这款手机的电池续航怎么样?' -> 分类意图: 'PRODUCT_INFO'
用户提问: '我的账户好像被盗了,登录不进去。' -> 分类意图: 'ACCOUNT_MANAGEMENT'
用户提问: '你们网站太卡了,能不能优化一下?' -> 分类意图: 'COMPLAINT_SUGGESTION'
用户提问: '你们今天晚餐吃什么?' -> 分类意图: 'UNKNOWN'
用户提问: '我有一个关于商品材质的问题' -> 分类意图: 'PRODUCT_INFO'

看到了吗?通过一个简单的 PromptTemplate,我们就能让 LLM 完美地完成了意图分类任务!这就是 Prompt Engineering 的魅力。

场景二:回复生成 - 让客服小助手给出专业、友好的回复

在智能客服中,仅仅分类意图是不够的,我们还需要根据用户意图和从知识库中检索到的信息,生成一个有帮助、有礼貌的回复。

假设我们已经识别出用户意图是 ORDER_STATUS,并且已经从数据库中查询到了订单信息(例如:订单号 123456,状态 已发货,预计送达 2023-10-26)。现在,我们来构建一个 Prompt Template,让 LLM 生成最终的客服回复。

# Python 代码示例
print("\n--- 场景二:回复生成 - 让客服小助手给出专业、友好的回复 ---")

# 1. 定义回复生成的 PromptTemplate
# 我们会给模型一个客服的角色,以及一些具体的回复要求和格式
response_generation_template = """
你是一名友善且专业的电商客服,你的任务是根据提供的订单信息,为用户生成一条礼貌、清晰的订单状态查询回复。
请确保回复包含以下信息:
1.  首先向用户问好。
2.  明确告知订单号。
3.  清晰说明当前订单状态。
4.  如果提供了预计送达日期,请一并告知。
5.  提供下一步的建议或安抚,例如“请耐心等待”或“如有其他问题随时联系”。
6.  回复的语气要积极、友好。

订单信息:
订单号: {order_id}
订单状态: {order_status}
预计送达日期: {delivery_date}

用户提问: "{user_query}"

请生成客服回复:
"""

response_prompt = PromptTemplate.from_template(response_generation_template)

# 2. LLM 保持不变,或者根据需要调整 temperature (可以稍微调高一点点,让回复更自然)
llm_for_response = ChatOpenAI(model="gpt-3.5-turbo", temperature=0.7)

# 3. 构建 LangChain 链
response_chain = response_prompt | llm_for_response | StrOutputParser()

# 4. 模拟获取到的订单信息并生成回复
order_data_1 = {
    "order_id": "EC20231025001",
    "order_status": "已发货",
    "delivery_date": "2023年10月28日",
    "user_query": "我的订单EC20231025001到哪了?"
}

order_data_2 = {
    "order_id": "EC20231024005",
    "order_status": "正在打包",
    "delivery_date": "暂无明确日期,预计3-5个工作日内发出",
    "user_query": "我的订单EC20231024005什么时候能发货?"
}

print("\n--- 开始回复生成测试 ---")

print(f"\n用户提问: '{order_data_1['user_query']}'")
generated_response_1 = response_chain.invoke(order_data_1)
print("客服回复:\n", generated_response_1)

print(f"\n用户提问: '{order_data_2['user_query']}'")
generated_response_2 = response_chain.invoke(order_data_2)
print("客服回复:\n", generated_response_2)

# TypeScript 代码示例 (概念演示,不直接运行,需配置环境)
"""
// import { PromptTemplate } from "@langchain/core/prompts";
// import { ChatOpenAI } from "@langchain/openai";
// import { StringOutputParser } from "@langchain/core/output_parsers";

// // process.env.OPENAI_API_KEY = "YOUR_OPENAI_API_KEY";

// console.log("\n--- 场景二:回复生成 - 让客服小助手给出专业、友好的回复 ---");

// const responseGenerationTemplate = `
// 你是一名友善且专业的电商客服,你的任务是根据提供的订单信息,为用户生成一条礼貌、清晰的订单状态查询回复。
// 请确保回复包含以下信息:
// 1.  首先向用户问好。
// 2.  明确告知订单号。
// 3.  清晰说明当前订单状态。
// 4.  如果提供了预计送达日期,请一并告知。
// 5.  提供下一步的建议或安抚,例如“请耐心等待”或“如有其他问题随时联系”。
// 6.  回复的语气要积极、友好。

// 订单信息:
// 订单号: {order_id}
// 订单状态: {order_status}
// 预计送达日期: {delivery_date}

// 用户提问: "{user_query}"

// 请生成客服回复:
// `;

// const responsePrompt = PromptTemplate.fromTemplate(responseGenerationTemplate);

// const llmForResponse = new ChatOpenAI({ modelName: "gpt-3.5-turbo", temperature: 0.7 });

// const responseChain = responsePrompt.pipe(llmForResponse).pipe(new StringOutputParser());

// const orderData1 = {
//     order_id: "EC20231025001",
//     order_status: "已发货",
//     delivery_date: "2023年10月28日",
//     user_query: "我的订单EC20231025001到哪了?"
// };

// const orderData2 = {
//     order_id: "EC20231024005",
//     order_status: "正在打包",
//     delivery_date: "暂无明确日期,预计3-5个工作日内发出",
//     user_query: "我的订单EC20231024005什么时候能发货?"
// };

// async function runResponseGeneration() {
//     console.log("\n--- 开始回复生成测试 ---");

//     console.log(`\n用户提问: '${orderData1.user_query}'`);
//     const generatedResponse1 = await responseChain.invoke(orderData1);
//     console.log("客服回复:\n", generatedResponse1);

//     console.log(`\n用户提问: '${orderData2.user_query}'`);
//     const generatedResponse2 = await responseChain.invoke(orderData2);
//     console.log("客服回复:\n", generatedResponse2);
// }

// runResponseGeneration();
"""

运行结果示例:

--- 场景二:回复生成 - 让客服小助手给出专业、友好的回复 ---

--- 开始回复生成测试 ---

用户提问: '我的订单EC20231025001到哪了?'
客服回复:
 您好!您的订单号EC20231025001目前状态为【已发货】,预计将于2023年10月28日送达。请您耐心等待,物流信息更新后会及时通知您。如有其他问题,欢迎随时联系我们!

用户提问: '我的订单EC20231024005什么时候能发货?'
客服回复:
 您好!您的订单号EC20231024005目前状态为【正在打包】。抱歉,目前暂无明确的送达日期,但预计将在3-5个工作日内发出。请您放心,我们会尽快处理并安排发货。感谢您的耐心等待!

是不是很酷?我们的客服小助手不仅能识别意图,还能根据具体信息生成个性化、专业且友好的回复了!这就是 Prompt Engineering 带来的力量。通过精心设计的 Prompt,我们就像给 AI 注入了灵魂,让它变得“善解人意”。

场景三:Few-shot Prompting - 举例说明,让模型学得更快更准

有时候,仅仅通过指令描述任务可能不够,模型可能无法完全捕捉到我们期望的细微差别或输出格式。这时,Few-shot Prompting 就派上用场了。通过提供少量高质量的输入-输出示例,我们可以直接向模型展示“你想让它怎么做”。

对于智能客服,Few-shot 可以用来:

  • 确保特定类型问题的回复格式一致。
  • 指导模型在特定情境下使用特定词汇或语气。
  • 帮助模型处理一些边界情况或复杂的用户表达。
# Python 代码示例
from langchain_core.prompts import FewShotPromptTemplate, PromptTemplate

print("\n--- 场景三:Few-shot Prompting - 举例说明,让模型学得更快更准 ---")

# 1. 定义 Few-shot 示例
# 假设我们希望在用户表达感谢时,模型能给出更温馨、更人性化的回复,而不是简单的“不客气”
examples = [
    {
        "input": "非常感谢您的帮助,问题解决了!",
        "output": "非常高兴能帮到您!如果您未来还有任何疑问,请随时联系我们,我们乐意效劳!"
    },
    {
        "input": "谢谢,你们的服务真棒!",
        "output": "感谢您的认可,这是我们最大的动力!期待为您提供更好的服务!"
    },
    {
        "input": "太给力了,谢谢!",
        "output": "不客气,很高兴能为您提供帮助!祝您生活愉快!"
    },
]

# 2. 定义单个示例的 Prompt Template
# 这个模板用于格式化每个示例的输入和输出
example_formatter_template = """
用户: {input}
客服: {output}
"""
example_prompt = PromptTemplate.from_template(example_formatter_template)

# 3. 定义 FewShotPromptTemplate
# 它会把所有示例和用户实际的查询组合起来
few_shot_prompt = FewShotPromptTemplate(
    examples=examples,                # 示例列表
    example_prompt=example_prompt,    # 格式化示例的 Prompt Template
    prefix="你是一名友善且乐于助人的客服机器人。请参考以下对话示例,以相似的风格和语气回复用户:\n", # 前缀指令
    suffix="\n用户: {user_input}\n客服:", # 后缀,包含用户实际输入和模型要完成的部分
    input_variables=["user_input"],   # 用户输入变量
    example_separator="\n\n"          # 示例之间的分隔符
)

# 4. 初始化 LLM (可以稍微调高 temperature,让回复更具创造性)
llm_for_fewshot = ChatOpenAI(model="gpt-3.5-turbo", temperature=0.7)

# 5. 构建 LangChain 链
fewshot_chain = few_shot_prompt | llm_for_fewshot | StrOutputParser()

# 6. 模拟用户输入并获取回复
user_input_1 = "谢谢你们的耐心解答!"
user_input_2 = "你们客服效率真高,谢谢啦!"

print("\n--- 开始 Few-shot 回复生成测试 ---")

print(f"\n用户输入: '{user_input_1}'")
generated_fewshot_response_1 = fewshot_chain.invoke({"user_input": user_input_1})
print("客服回复:\n", generated_fewshot_response_1)

print(f"\n用户输入: '{user_input_2}'")
generated_fewshot_response_2 = fewshot_chain.invoke({"user_input": user_input_2})
print("客服回复:\n", generated_fewshot_response_2)

# TypeScript 代码示例 (概念演示,不直接运行,需配置环境)
"""
// import { FewShotPromptTemplate, PromptTemplate } from "@langchain/core/prompts";
// import { ChatOpenAI } from "@langchain/openai";
// import { StringOutputParser } from "@langchain/core/output_parsers";

// // process.env.OPENAI_API_KEY = "YOUR_OPENAI_API_KEY";

// console.log("\n--- 场景三:Few-shot Prompting - 举例说明,让模型学得更快更准 ---");

// const examples = [
//     {
//         input: "非常感谢您的帮助,问题解决了!",
//         output: "非常高兴能帮到您!如果您未来还有任何疑问,请随时联系我们,我们乐意效劳!"
//     },
//     {
//         input: "谢谢,你们的服务真棒!",
//         output: "感谢您的认可,这是我们最大的动力!期待为您提供更好的服务!"
//     },
//     {
//         input: "太给力了,谢谢!",
//         output: "不客气,很高兴能为您提供帮助!祝您生活愉快!"
//     },
// ];

// const examplePrompt = PromptTemplate.fromTemplate(`
//