第 15 期 | Agent 核心:打造自主决策小助手

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

🎯 本期学习目标

嘿,各位未来的 AI 架构师们!欢迎来到《LangChain 全栈大师课》的第一站。我是你们的导师,一个在 AI 领域摸爬滚打十年的老兵,也是一个对教育充满激情的“传道士”。今天,我们要做的就是奠定你的 LangChain 大厦的基石——理解并驾驭 LLM 和 Prompt Template。

学完这期,你将能:

  1. 洞悉 LLM 在 LangChain 中的核心定位与抽象:看透 LangChain 如何让你轻松“调教”各种大模型。
  2. 精通 Prompt Template 的构建与应用:学会如何编写既高效又灵活的“魔法咒语”,让 LLM 乖乖听话。
  3. 为智能客服构建基础问答能力:将 LLM 与 Prompt Template 组合,让我们的客服小助手拥有“开口说话”的本领。
  4. 掌握 Prompt 迭代优化策略:了解如何通过不断试错和调整,提升客服小助手回复的精准度和专业性。

准备好了吗?系好安全带,我们出发!

📖 原理解析

首先,咱们把话挑明了:LLM (Large Language Model) 就是我们智能客服的“大脑”。它负责理解用户的意图,消化各种信息,然后生成连贯、有逻辑的回复。没有它,我们的客服小助手就是个空壳。

但问题来了,市面上的 LLM 模型五花八门,有 OpenAI 的 GPT 系列,有 Google 的 Gemini,还有 Hugging Face 上无数开源模型。难道我们每换一个模型,就要重写一遍代码吗?这不合理,也不高效!

这时候,LangChain 就登场了。它就像一个“翻译官”兼“调度员”,为我们提供了一个统一的接口来与各种 LLM 交互。无论你用的是 GPT-3.5 还是 GPT-4,甚至是自己微调的模型,LangChain 都能让你用一套标准化的方式去调用它们。它把不同模型的底层 API 调用细节都封装起来了,让你能专注于业务逻辑,而不是模型适配。

那么,我们怎么跟这个“大脑”沟通呢?直接扔一句话过去就行吗?当然可以,但结果往往不尽如人意。就像你跟一个新同事交代工作,只说一句“把那个搞定”,他可能根本不知道“那个”是哪个,“搞定”到什么程度。

这就是 Prompt Template (提示词模板) 的用武之地。它不是简单的提示词,而是一个可以复用的“话术蓝图”。我们通过定义模板,告诉 LLM 它的角色(比如“你是一个专业的客服助手”),它需要完成的任务(“请礼貌且详细地回答用户问题”),以及输入的信息(“用户的问题是:{user_query}”)。通过这种结构化的方式,我们极大地提高了 LLM 理解任务的准确性和回复的质量。

简而言之,LLM 是智能客服的“大脑”,而 Prompt Template 则是我们与“大脑”沟通的“语言规范”。两者结合,才能让我们的客服小助手变得既聪明又听话。

让我们通过一张图来直观地理解这个核心工作流:

graph TD
    subgraph 智能客服系统
        A[用户输入: "我的订单状态如何?"]
        A --> B{PromptTemplate};
        B -- 填充变量: {user_query} --> C[构建完整Prompt: "你是一个专业的客服助手,请根据用户问题提供帮助。问题: 我的订单状态如何?"];
        C --> D(LangChain LLM 抽象层);
        D -- API 调用 --> E[大型语言模型 (LLM Provider, 如 OpenAI GPT-3.5)];
        E -- 返回原始响应 --> F(LangChain OutputParser 模块);
        F --> G[结构化/清洗回复];
        G --> H[智能客服回复: "请提供订单号,我将为您查询。"];
    end

    style A fill:#FFDDC1,stroke:#FF8C00,stroke-width:2px
    style B fill:#D1FFC1,stroke:#008000,stroke-width:2px
    style C fill:#C1E0FF,stroke:#1E90FF,stroke-width:2px
    style D fill:#E0C1FF,stroke:#8A2BE2,stroke-width:2px
    style E fill:#FFC1E0,stroke:#FF1493,stroke-width:2px
    style F fill:#C1FFD1,stroke:#3CB371,stroke-width:2px
    style G fill:#FFD1C1,stroke:#FF6347,stroke-width:2px
    style H fill:#FFDDC1,stroke:#FF8C00,stroke-width:2px

从图中可以看到,用户的问题首先被 Prompt Template 接收,然后结合预设的模板,生成一个完整且结构化的 Prompt。这个 Prompt 再通过 LangChain 的 LLM 抽象层,发送给底层的 LLM 模型。LLM 处理后返回原始响应,LangChain 还可以进一步通过 OutputParser 进行解析和清洗,最终生成我们希望展示给用户的客服回复。整个过程,LangChain 扮演了关键的桥梁角色。

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

好了,理论说得再漂亮,不如代码跑起来!现在,我们来为我们的“智能客服知识库”项目,搭建最基础的问答模块。

1. 环境准备

首先,确保你已经安装了 LangChain 和你打算使用的 LLM 提供商的 SDK。这里我们以 OpenAI 为例。

pip install langchain openai # Python 用户
# 或者
npm install langchain openai # TypeScript 用户

2. 设置 API Key

划重点! 永远不要把你的 API Key 硬编码到代码里!这既不安全也不专业。最佳实践是使用环境变量。

Python: 在你的 .env 文件中(或者直接设置系统环境变量):

OPENAI_API_KEY="你的OpenAI API Key"

然后在代码中加载:

import os
from dotenv import load_dotenv

load_dotenv() # 加载 .env 文件中的环境变量

openai_api_key = os.getenv("OPENAI_API_KEY")
if not openai_api_key:
    raise ValueError("OPENAI_API_KEY 环境变量未设置!")

TypeScript: 在你的 .env 文件中:

OPENAI_API_KEY="你的OpenAI API Key"

在代码中加载(确保安装 dotenvnpm install dotenv):

import * as dotenv from 'dotenv';
dotenv.config(); // 加载 .env 文件中的环境变量

const openaiApiKey = process.env.OPENAI_API_KEY;
if (!openaiApiKey) {
    throw new Error("OPENAI_API_KEY 环境变量未设置!");
}
// 在初始化 OpenAI 客户端时传入
// new OpenAI({ apiKey: openaiApiKey, ... });

3. LLM 初始化

接下来,我们来初始化我们的 LLM 模型。这里我们选择 OpenAI 的 gpt-3.5-turbo,因为它性价比高,响应速度快,非常适合作为客服场景的起点。

Python 代码:

import os
from dotenv import load_dotenv
from langchain_openai import ChatOpenAI # 导入 ChatOpenAI,更推荐用于对话场景
from langchain.prompts import ChatPromptTemplate
from langchain.chains import LLMChain

# 1. 加载环境变量
load_dotenv()
openai_api_key = os.getenv("OPENAI_API_KEY")
if not openai_api_key:
    raise ValueError("OPENAI_API_KEY 环境变量未设置!请在 .env 文件中配置。")

# 2. 初始化 LLM 模型
# temperature 参数控制模型的创造性。
# 0 表示最保守、最确定性的回复,1 表示最具创造性、最发散的回复。
# 客服场景通常需要准确和一致的回复,所以我们会设置一个较低的值,比如 0.1-0.5。
llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0.3, api_key=openai_api_key)

print("LLM 模型初始化成功!")

# 模拟运行
# response = llm.invoke("你好,你是一个什么样的模型?")
# print(f"LLM 原始回复: {response.content}")

TypeScript 代码:

import * as dotenv from 'dotenv';
import { ChatOpenAI } from '@langchain/openai'; // 导入 ChatOpenAI
import { ChatPromptTemplate } from '@langchain/core/prompts';
import { LLMChain } from 'langchain/chains';

// 1. 加载环境变量
dotenv.config();
const openaiApiKey = process.env.OPENAI_API_KEY;
if (!openaiApiKey) {
    throw new Error("OPENAI_API_KEY 环境变量未设置!请在 .env 文件中配置。");
}

// 2. 初始化 LLM 模型
// temperature 参数控制模型的创造性。
// 0 表示最保守、最确定性的回复,1 表示最具创造性、最发散的回复。
// 客服场景通常需要准确和一致的回复,所以我们会设置一个较低的值,比如 0.1-0.5。
const llm = new ChatOpenAI({
    model: "gpt-3.5-turbo",
    temperature: 0.3, // 较低的温度值保证回复的稳定性和准确性
    openAIApiKey: openaiApiKey,
});

console.log("LLM 模型初始化成功!");

// 模拟运行
// async function runLLMDemo() {
//     const response = await llm.invoke("你好,你是一个什么样的模型?");
//     console.log(`LLM 原始回复: ${response.content}`);
// }
// runLLMDemo();

4. Prompt Template 创建

现在,我们来定义一个针对智能客服场景的 Prompt Template。我们将设定小助手的角色,并告诉它如何处理用户的问题。

Python 代码:

# ... (接上文 LLM 初始化代码)

# 3. 创建 Prompt Template
# 我们使用 ChatPromptTemplate,因为它更适合像 GPT 这样的聊天模型。
# MessagesPlaceholder 用于未来引入记忆或外部上下文,这里先用 HumanMessageTemplate 模拟。
prompt_template = ChatPromptTemplate.from_messages(
    [
        ("system", "你是一个专业的智能客服助手,你的职责是礼貌、准确、详细地回答用户关于产品或服务的问题。"),
        ("human", "用户问题:{user_query}"),
    ]
)

print("Prompt Template 创建成功!")

# 模拟运行
# formatted_prompt = prompt_template.format_messages(user_query="我的订单号是多少?")
# print("格式化后的 Prompt:")
# for message in formatted_prompt:
#     print(f"  {message.type}: {message.content}")

TypeScript 代码:

// ... (接上文 LLM 初始化代码)

// 3. 创建 Prompt Template
// 我们使用 ChatPromptTemplate,因为它更适合像 GPT 这样的聊天模型。
// MessagesPlaceholder 用于未来引入记忆或外部上下文,这里先用 HumanMessageTemplate 模拟。
const promptTemplate = ChatPromptTemplate.fromMessages([
    ["system", "你是一个专业的智能客服助手,你的职责是礼貌、准确、详细地回答用户关于产品或服务的问题。"],
    ["human", "用户问题:{user_query}"],
]);

console.log("Prompt Template 创建成功!");

// 模拟运行
// async function runPromptDemo() {
//     const formattedPrompt = await promptTemplate.formatMessages({ user_query: "我的订单号是多少?" });
//     console.log("格式化后的 Prompt:");
//     formattedPrompt.forEach(message => {
//         console.log(`  ${message._getType()}: ${message.content}`);
//     });
// }
// runPromptDemo();

5. 组合 LLM 和 Prompt Template (构建 Chain)

LangChain 最强大的地方之一就是它能将不同的组件(LLM、Prompt Template、Memory、Tool 等)像乐高积木一样组合起来,形成一个“链 (Chain)”。这里我们使用最基础的 LLMChain 来连接 LLM 和 Prompt Template。

Python 代码:

# ... (接上文 Prompt Template 创建代码)

# 4. 组合 LLM 和 Prompt Template (构建 Chain)
# LLMChain 将 Prompt Template 的输出作为 LLM 的输入。
qa_chain = LLMChain(llm=llm, prompt=prompt_template, verbose=True) # verbose=True 可以看到Chain的运行细节

print("LLMChain 构建成功!")

# 5. 智能客服小助手基础问答能力演示
async def ask_customer_copilot(user_question: str):
    """
    智能客服小助手提问函数。
    """
    print(f"\n--- 用户提问 ---")
    print(f"用户: {user_question}")
    print(f"--- 小助手思考中 ---")

    # 调用 Chain 运行,传入用户问题作为 user_query 变量
    response = await qa_chain.ainvoke({"user_query": user_question}) # 使用 ainvoke 进行异步调用
    
    print(f"--- 智能客服回复 ---")
    # LLMChain 的结果通常在 'text' 键中
    print(f"小助手: {response['text']}")
    return response['text']

# 运行演示
import asyncio

async def main():
    await ask_customer_copilot("我的订单号是多少?")
    await ask_customer_copilot("你们的产品有什么特色?")
    await ask_customer_copilot("如何申请退货?")

if __name__ == "__main__":
    asyncio.run(main())

Python 代码运行结果示例:

LLM 模型初始化成功!
Prompt Template 创建成功!
LLMChain 构建成功!

--- 用户提问 ---
用户: 我的订单号是多少?
--- 小助手思考中 ---
> Entering new LLMChain chain...
Prompt after formatting:
System: 你是一个专业的智能客服助手,你的职责是礼貌、准确、详细地回答用户关于产品或服务的问题。
Human: 用户问题:我的订单号是多少?

> Finished chain.
--- 智能客服回复 ---
小助手: 您好!为了更好地帮助您查询订单号,请您提供一下您的姓名、注册邮箱或手机号码,以便我核对您的账户信息。感谢您的配合!

--- 用户提问 ---
用户: 你们的产品有什么特色?
--- 小助手思考中 ---
> Entering new LLMChain chain...
Prompt after formatting:
System: 你是一个专业的智能客服助手,你的职责是礼貌、准确、详细地回答用户关于产品或服务的问题。
Human: 用户问题:你们的产品有什么特色?

> Finished chain.
--- 智能客服回复 ---
小助手: 您好!我们的产品主要有以下几个特色:
1.  **创新技术**:我们采用了最新的[某项核心技术,例如:AI驱动的个性化推荐算法],确保用户体验的领先性。
2.  **用户友好**:界面设计简洁直观,操作流程优化,即使是初次使用的用户也能快速上手。
3.  **稳定可靠**:经过严格的测试和优化,系统运行稳定,数据处理高效,保障您的使用无忧。
4.  **优质服务**:我们提供24/7的专业客服支持,随时为您解答疑问,解决问题。
请问您对我们产品的哪一方面更感兴趣呢?我可以为您提供更详细的信息。

--- 用户提问 ---
用户: 如何申请退货?
--- 小助手思考中 ---
> Entering new LLMChain chain...
Prompt after formatting:
System: 你是一个专业的智能客服助手,你的职责是礼貌、准确、详细地回答用户关于产品或服务的问题。
Human: 用户问题:如何申请退货?

> Finished chain.
--- 智能客服回复 ---
小助手: 您好!申请退货的具体流程如下:
1.  **登录账户**:请您首先登录您的[平台名称/官网]账户。
2.  **查找订单**:在“我的订单”或“订单管理”页面找到您需要退货的订单。
3.  **提交退货申请**:点击订单详情页的“申请退货”按钮,并按照页面提示填写退货原因、选择退货商品及数量。
4.  **等待审核**:提交申请后,我们的客服团队会在[通常审核时间,例如:1-3个工作日]内进行审核。请您留意站内信或邮箱通知。
5.  **寄回商品**:审核通过后,您将收到退货地址和寄回商品的指引。请确保商品包装完好,附件齐全。
6.  **退款处理**:我们收到退回商品并确认无误后,将在[通常退款时间,例如:7个工作日]内为您办理退款。
如果您在操作过程中遇到任何问题,欢迎随时联系在线客服或拨打客服热线。

TypeScript 代码:

// ... (接上文 Prompt Template 创建代码)

// 4. 组合 LLM 和 Prompt Template (构建 Chain)
// LLMChain 将 Prompt Template 的输出作为 LLM 的输入。
const qaChain = new LLMChain({
    llm: llm,
    prompt: promptTemplate,
    verbose: true, // verbose=true 可以看到Chain的运行细节
});

console.log("LLMChain 构建成功!");

// 5. 智能客服小助手基础问答能力演示
async function askCustomerCopilot(userQuestion: string): Promise<string> {
    /**
     * 智能客服小助手提问函数。
     */
    console.log(`\n--- 用户提问 ---`);
    console.log(`用户: ${userQuestion}`);
    console.log(`--- 小助手思考中 ---`);

    // 调用 Chain 运行,传入用户问题作为 user_query 变量
    // invoke 方法返回一个对象,LLMChain 的结果通常在 'text' 键中
    const response = await qaChain.invoke({ user_query: userQuestion });

    console.log(`--- 智能客服回复 ---`);
    console.log(`小助手: ${response.text}`);
    return response.text;
}

// 运行演示
async function main() {
    await askCustomerCopilot("我的订单号是多少?");
    await askCustomerCopilot("你们的产品有什么特色?");
    await askCustomerCopilot("如何申请退货?");
}

if (require.main === module) {
    main();
}

TypeScript 代码运行结果示例:

LLM 模型初始化成功!
Prompt Template 创建成功!
LLMChain 构建成功!

--- 用户提问 ---
用户: 我的订单号是多少?
--- 小助手思考中 ---
> Entering new LLMChain chain...
Prompt after formatting:
System: 你是一个专业的智能客服助手,你的职责是礼貌、准确、详细地回答用户关于产品或服务的问题。
Human: 用户问题:我的订单号是多少?

> Finished chain.
--- 智能客服回复 ---
小助手: 您好!为了更好地帮助您查询订单号,请您提供一下您的姓名、注册邮箱或手机号码,以便我核对您的账户信息。感谢您的配合!

--- 用户提问 ---
用户: 你们的产品有什么特色?
--- 小助手思考中 ---
> Entering new LLMChain chain...
Prompt after formatting:
System: 你是一个专业的智能客服助手,你的职责是礼貌、准确、详细地回答用户关于产品或服务的问题。
Human: 用户问题:你们的产品有什么特色?

> Finished chain.
--- 智能客服回复 ---
小助手: 您好!我们的产品主要有以下几个特色:
1.  **创新技术**:我们采用了最新的[某项核心技术,例如:AI驱动的个性化推荐算法],确保用户体验的领先性。
2.  **用户友好**:界面设计简洁直观,操作流程优化,即使是初次使用的用户也能快速上手。
3.  **稳定可靠**:经过严格的测试和优化,系统运行稳定,数据处理高效,保障您的使用无忧。
4.  **优质服务**:我们提供24/7的专业客服支持,随时为您解答疑问,解决问题。
请问您对我们产品的哪一方面更感兴趣呢?我可以为您提供更详细的信息。

--- 用户提问 ---
用户: 如何申请退货?
--- 小助手思考中 ---
> Entering new LLMChain chain...
Prompt after formatting:
System: 你是一个专业的智能客服助手,你的职责是礼貌、准确、详细地回答用户关于产品或服务的问题。
Human: 用户问题:如何申请退货?

> Finished chain.
--- 智能客服回复 ---
小助手: 您好!申请退货的具体流程如下:
1.  **登录账户**:请您首先登录您的[平台名称/官网]账户。
2.  **查找订单**:在“我的订单”或“订单管理”页面找到您需要退货的订单。
3.  **提交退货申请**:点击订单详情页的“申请退货”按钮,并按照页面提示填写退货原因、选择退货商品及数量。
4.  **等待审核**:提交申请后,我们的客服团队会在[通常审核时间,例如:1-3个工作日]内进行审核。请您留意站内信或邮箱通知。
5.  **寄回商品**:审核通过后,您将收到退货地址和寄回商品的指引。请确保商品包装完好,附件齐全。
6.  **退款处理**:我们收到退回商品并确认无误后,将在[通常退款时间,例如:7个工作日]内为您办理退款。
如果您在操作过程中遇到任何问题,欢迎随时联系在线客服或拨打客服热线。

看到了吧?通过简单的 LLM 和 Prompt Template 组合,我们的智能客服小助手已经能够根据用户问题,生成像模像样的回复了!尽管它还没有记忆,也不知道具体的产品细节,但基础的对话能力已经具备。

坑与避坑指南

作为一名资深开发者,我见过太多新手在这里踩坑。所以,下面这些“避坑指南”,你务必收好!

  1. Prompt Engineering 是门艺术,更是科学!

    • 坑: 觉得 Prompt 就是随便写一句话。
    • 避坑: Prompt 是你和 LLM 沟通的“圣经”。一个好的 Prompt,能让 LLM 的能力发挥到极致;一个差的 Prompt,可能让 LLM 变成“人工智障”。
      • 清晰具体: 避免模糊、开放式的问题。例如,不要只问“产品怎么样?”,而是问“请详细介绍产品A的亮点和适用场景。”
      • 角色设定: 给 LLM 一个明确的角色,它会更好地扮演。比如我们的“专业的智能客服助手”。
      • 指令明确: 告诉它要做什么,不要做什么(例如“不要编造信息”)。
      • 提供示例 (Few-shot Prompting): 如果你对回复格式有要求,直接给出几个问答示例,LLM 会学得更快。我们后面会讲到。
  2. temperature 参数的玄学与科学

    • 坑:temperature 参数一无所知,或者随意设置。
    • 避坑: temperature 控制着 LLM 回复的“随机性”或“创造性”。
      • 0 接近确定性: 回复最稳定、最重复,适合需要高度准确和一致性的场景(如客服、代码生成)。
      • 1 接近随机性: 回复最具创造性、最发散,适合需要头脑风暴、文学创作的场景。
      • 客服场景: 建议将 temperature 设置在 0.10.5 之间。过高可能导致客服小助手“胡言乱语”,过低可能让它过于死板。
  3. API Key 安全:血的教训!

    • 坑: 将 API Key 直接写在代码中,或者提交到版本控制系统(如 Git)。
    • 避坑: 我再强调一遍:永远不要硬编码 API Key! 使用环境变量是行业标准。一旦你的 Key 泄露,轻则