第 16 期 | 多 Agent 协作:将任务拆解为工作流

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

本期副标题:构建你的第一个智能客服助手雏形:连接大模型与基础提示词

Alright,各位未来的 AI 架构师们,欢迎来到《LangChain 全栈大师课》!我是你们的老朋友,一个在 AI 领域摸爬滚打了十年的老兵,也是你们最热心的导师。今天,咱们就从零开始,一起把 LangChain 这把屠龙刀耍起来!

你们可能已经感受到了,自从大语言模型(LLM)横空出世,整个技术圈都沸腾了。但光有强大的 LLM 还不够,就像你手握一把顶级跑车引擎,却发现它没有车架、没有方向盘、没有刹车。LangChain,就是那个能把这颗引擎武装起来,让它真正跑起来,甚至能上赛道的“车架”和“控制系统”。

我们的终极目标是打造一个生产级的智能客服知识库 (Intelligent Support Copilot)。别小看客服,它可是企业与用户沟通的第一线,效率和体验至关重要。想象一下,如果你的客服团队能有一个 24/7 在线、秒级响应、而且能精准理解用户意图并提供个性化帮助的 AI 助手,那会是怎样一种降维打击?今天,我们就先给这个客服助手搭个最简单的骨架,让它能开口说话,理解一点点我们的问题。准备好了吗?Let's roll!

🎯 本期学习目标

在本期课程中,你将不仅仅是敲几行代码,更要建立起对 LangChain 乃至整个 LLM 应用开发的基本认知。具体来说,学完本期,你将:

  1. 理解 LangChain 的核心价值与设计哲学:跳出“API 调用”的思维,明白为什么我们需要一个像 LangChain 这样的框架来构建复杂的 LLM 应用。
  2. 掌握 LangChain 的基础组件:深入理解 LLMs、Prompts 和 Chains 这三大基石,它们是 LangChain 世界的“Hello World”。
  3. 搭建你的第一个 LangChain 应用:亲手构建一个能回应简单问题的智能客服助手雏形,体验从想法到代码的实现过程。
  4. 建立 LLM 应用开发的全局观:初步认识到 LangChain 如何将零散的 LLM 能力编织成一个有逻辑、可扩展的系统,为后续更高级的开发打下坚实基础。

📖 原理解析

LangChain 是什么?它为何而生?

首先,咱们得把一个概念掰扯清楚:LangChain 不是一个大模型,它是一个框架。它的核心使命是帮助开发者更高效、更灵活地构建基于大语言模型(LLM)的应用程序。你可以把它想象成一个乐高积木盒,里面有各种各样预制好的、可组合的模块,让你能快速搭建出各种复杂的结构。

为什么我们需要 LangChain?

直接调用 OpenAI、Anthropic 或其他厂商的 LLM API 当然可以。但当你开始构建一个稍微复杂点的应用时,你会发现:

  • 提示词管理很麻烦:不同的场景需要不同的提示词,如何高效地创建、管理和复用这些提示词?
  • 上下文管理是噩梦:LLM 没有记忆,每次交互都是独立的。如何让它记住之前的对话,保持连贯性?
  • 工具集成是刚需:LLM 擅长文本生成和理解,但不擅长计算、查询数据库、调用外部 API。如何让 LLM 像个“大脑”一样,指挥“四肢”去执行任务?
  • 编排复杂工作流:一个真实的应用往往不是简单的“输入 -> LLM -> 输出”,而是多步推理、条件判断、并行处理等复杂流程。
  • 可观测性与调试:当应用变复杂时,如何追踪 LLM 的推理路径,找出问题所在?

LangChain 就是来解决这些痛点的。它提供了一套标准化的接口和抽象,将 LLM 的能力进行封装、串联和扩展,让你能专注于业务逻辑,而不是底层细节。

LangChain 的核心组件:LLMs, Prompts, Chains

在 LangChain 的世界里,有几个核心概念是你必须掌握的:

  1. LLMs (Large Language Models)

    • 这是最基础的组件,代表了对各种大语言模型的抽象封装。无论是 OpenAI 的 GPT 系列,还是 Google 的 Gemini,亦或是开源的 Llama,LangChain 都提供统一的接口。
    • 它负责将你的请求发送给大模型,并接收大模型的响应。你可以配置模型名称、温度(temperature,控制创造性)、最大 token 数等参数。
    • 在我们的智能客服项目中,LLMs 就是那个“大脑”,负责理解用户提问并生成回答。
  2. Prompts (提示词)

    • 提示词是与 LLM 沟通的语言。好的提示词能让 LLM 给出更精准、更有用的回答。
    • LangChain 提供了 PromptTemplate(提示词模板),它允许你定义带有占位符的提示词,然后动态地填充变量。这大大提高了提示词的复用性和管理效率。
    • 对于客服助手,我们可以定义一个模板,告诉 LLM 它的角色(“你是一个专业的客服助手”),并插入用户的问题。
  3. Chains (链)

    • 链是 LangChain 的核心概念之一,它将多个组件(比如 LLM 和 Prompt)连接起来,形成一个有序的工作流。
    • 最简单的链可能只是“提示词模板 -> LLM”,但复杂的链可以包含多个步骤、逻辑判断,甚至调用外部工具。
    • LangChain 引入了 LCEL (LangChain Expression Language),这是一种非常强大且灵活的方式来构建链,它允许你像管道一样串联各种组件。

智能客服助手雏形的工作流 (Mermaid 图解)

为了更好地理解这三个核心组件如何协同工作,我们来看一下我们的智能客服助手雏形的工作流:

graph TD
    A[用户提问] --> B{PromptTemplate: 格式化提问};
    B -- 填充变量 --> C[LLM: 大语言模型];
    C -- 生成回答 --> D[OutputParser: 格式化输出 (可选)];
    D --> E[智能客服助手返回回答];

    style A fill:#f9f,stroke:#333,stroke-width:2px;
    style B fill:#bbf,stroke:#333,stroke-width:2px;
    style C fill:#ccf,stroke:#333,stroke-width:2px;
    style D fill:#fbf,stroke:#333,stroke-width:2px;
    style E fill:#9f9,stroke:#333,stroke-width:2px;

工作流解释:

  1. 用户提问 (User Input):用户向客服助手提出问题。
  2. PromptTemplate (提示词模板):客服助手接收到用户提问后,并不会直接将其发送给 LLM。相反,它会使用一个预定义的 PromptTemplate 来格式化这个问题。这个模板会给 LLM 提供上下文、角色设定(例如:“你是一个专业的智能客服助手”),并包含用户提问的占位符。
  3. LLM (大语言模型):格式化后的完整提示词被发送给大语言模型。LLM 基于其训练数据和提示词的指令,生成一个针对用户问题的回答。
  4. OutputParser (输出解析器 - 可选):有时候,LLM 的原始输出可能需要进一步处理,例如提取特定信息、转换为 JSON 格式等。OutputParser 组件可以帮助我们对 LLM 的输出进行结构化或格式化。在我们的雏形阶段,可能暂时不需要这个,但未来会非常有用。
  5. 智能客服助手返回回答:最终,经过 LLM 处理并可能经过解析的回答,会返回给用户。

这就是一个最基础的 LangChain 应用循环。是不是感觉“道”与“术”开始连接起来了?

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

好了,原理讲了一堆,是时候撸起袖子干活了!我们将用 Python 和 TypeScript 分别演示如何构建这个智能客服助手雏形。

前期准备

  1. 安装 LangChain 库
    • Python:
      pip install langchain langchain-openai python-dotenv
      
    • TypeScript:
      npm install langchain @langchain/openai dotenv
      # 或 yarn add langchain @langchain/openai dotenv
      
  2. 设置 OpenAI API Key
    • 在项目根目录下创建 .env 文件,并添加你的 OpenAI API Key。
    OPENAI_API_KEY="YOUR_OPENAI_API_KEY_HERE"
    
    • 重要提示:永远不要把 API Key 硬编码到代码里,使用环境变量是最佳实践!

Python 实战

import os
from dotenv import load_dotenv
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough

# 1. 加载环境变量
load_dotenv()
openai_api_key = os.getenv("OPENAI_API_KEY")

if not openai_api_key:
    raise ValueError("OPENAI_API_KEY 未设置。请检查 .env 文件。")

print("✅ 环境变量加载成功,开始构建智能客服助手...")

# 2. 初始化 LLM (大语言模型)
# 我们使用 ChatOpenAI,因为它更适合对话场景。
# temperature 参数控制模型的“创造性”,0 表示更确定、更少随机性。
llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0, api_key=openai_api_key)
print("✅ LLM 初始化完成。")

# 3. 定义 PromptTemplate (提示词模板)
# 这是一个 ChatPromptTemplate,可以包含 System, Human, AI 等不同角色的消息。
# 对于客服助手,System 消息用于设定其角色和行为。
prompt = ChatPromptTemplate.from_messages(
    [
        ("system", "你是一位专业的智能客服助手。你的任务是友好、准确、简洁地回答用户关于我们产品和服务的问题。如果问题超出你的知识范围,请礼貌地告知用户并建议他们联系人工客服。"),
        ("human", "{question}"), # {question} 是一个占位符,将由用户输入填充
    ]
)
print("✅ PromptTemplate 定义完成。")

# 4. 定义 OutputParser (输出解析器)
# 这里我们使用 StrOutputParser,它只是简单地将 LLM 的输出转换为字符串。
output_parser = StrOutputParser()
print("✅ OutputParser 定义完成。")

# 5. 构建 Chain (链) - 使用 LangChain Expression Language (LCEL)
# LCEL 允许我们像管道一样串联组件,非常直观和强大。
# 流程:用户输入 -> 提示词模板 -> LLM -> 输出解析器
rag_chain = (
    {"question": RunnablePassthrough()} # 接收用户的原始输入作为 "question" 变量
    | prompt                            # 将 "question" 填充到 prompt 模板中
    | llm                               # 将填充好的 prompt 发送给 LLM
    | output_parser                     # 解析 LLM 的输出
)
print("✅ Chain 构建完成。")

# 6. 模拟用户提问,运行客服助手
print("\n--- 智能客服助手开始服务 ---")

# 场景一:产品查询
user_question_1 = "请问你们的智能手表有哪些主要功能?"
print(f"\n用户提问: {user_question_1}")
response_1 = rag_chain.invoke({"question": user_question_1})
print(f"客服助手: {response_1}")

# 场景二:服务咨询
user_question_2 = "我的订单号是 XYZ12345,请问什么时候能发货?"
print(f"\n用户提问: {user_question_2}")
response_2 = rag_chain.invoke({"question": user_question_2})
print(f"客服助手: {response_2}")

# 场景三:超出知识范围的问题
user_question_3 = "请问明天北京的天气怎么样?"
print(f"\n用户提问: {user_question_3}")
response_3 = rag_chain.invoke({"question": user_question_3})
print(f"客服助手: {response_3}")

print("\n--- 智能客服助手服务结束 ---")

TypeScript 实战

import * as dotenv from "dotenv";
import { ChatOpenAI } from "@langchain/openai";
import { ChatPromptTemplate } from "@langchain/core/prompts";
import { StringOutputParser } from "@langchain/core/output_parsers";
import { RunnablePassthrough } from "@langchain/core/runnables";

// 1. 加载环境变量
dotenv.config();
const openaiApiKey = process.env.OPENAI_API_KEY;

if (!openaiApiKey) {
  throw new Error("OPENAI_API_KEY 未设置。请检查 .env 文件。");
}

console.log("✅ 环境变量加载成功,开始构建智能客服助手...");

// 2. 初始化 LLM (大语言模型)
const llm = new ChatOpenAI({
  model: "gpt-3.5-turbo",
  temperature: 0, // 控制模型的“创造性”,0 表示更确定、更少随机性
  apiKey: openaiApiKey,
});
console.log("✅ LLM 初始化完成。");

// 3. 定义 PromptTemplate (提示词模板)
const prompt = ChatPromptTemplate.fromMessages([
  [
    "system",
    "你是一位专业的智能客服助手。你的任务是友好、准确、简洁地回答用户关于我们产品和服务的问题。如果问题超出你的知识范围,请礼貌地告知用户并建议他们联系人工客服。",
  ],
  ["human", "{question}"], // {question} 是一个占位符,将由用户输入填充
]);
console.log("✅ PromptTemplate 定义完成。");

// 4. 定义 OutputParser (输出解析器)
const outputParser = new StringOutputParser();
console.log("✅ OutputParser 定义完成。");

// 5. 构建 Chain (链) - 使用 LangChain Expression Language (LCEL)
// LCEL 允许我们像管道一样串联组件,非常直观和强大。
// 流程:用户输入 -> 提示词模板 -> LLM -> 输出解析器
const ragChain = RunnablePassthrough.assign({
  question: (input: string) => input, // 接收用户的原始输入作为 "question" 变量
})
  .pipe(prompt) // 将 "question" 填充到 prompt 模板中
  .pipe(llm) // 将填充好的 prompt 发送给 LLM
  .pipe(outputParser); // 解析 LLM 的输出

console.log("✅ Chain 构建完成。");

// 6. 模拟用户提问,运行客服助手
async function runCustomerService() {
  console.log("\n--- 智能客服助手开始服务 ---");

  // 场景一:产品查询
  const userQuestion1 = "请问你们的智能手表有哪些主要功能?";
  console.log(`\n用户提问: ${userQuestion1}`);
  const response1 = await ragChain.invoke(userQuestion1);
  console.log(`客服助手: ${response1}`);

  // 场景二:服务咨询
  const userQuestion2 = "我的订单号是 XYZ12345,请问什么时候能发货?";
  console.log(`\n用户提问: ${userQuestion2}`);
  const response2 = await ragChain.invoke(userQuestion2);
  console.log(`客服助手: ${response2}`);

  // 场景三:超出知识范围的问题
  const userQuestion3 = "请问明天北京的天气怎么样?";
  console.log(`\n用户提问: ${userQuestion3}`);
  const response3 = await ragChain.invoke(userQuestion3);
  console.log(`客服助手: ${response3}`);

  console.log("\n--- 智能客服助手服务结束 ---");
}

runCustomerService();

代码讲解与客服项目中的具体应用

上面的代码,无论是 Python 还是 TypeScript 版本,都清晰地展示了 LangChain 的核心三件套:

  • LLM (ChatOpenAI):我们选择了 gpt-3.5-turbo,因为它速度快、成本低,非常适合作为我们客服助手的“大脑”。temperature=0 的设置确保了客服助手回答的确定性和一致性,避免了不必要的“创造性”回答,这在客服场景中至关重要。
  • PromptTemplate (ChatPromptTemplate):我们通过 system 消息给 LLM 设定了一个明确的角色:“专业的智能客服助手”。这个角色设定是 LLM 应用成功的关键,它能引导模型在正确的上下文和风格下生成回答。{question} 占位符则实现了提示词的动态化。
  • Chain (LCEL):通过 | (Python) 或 .pipe() (TypeScript) 操作符,我们将用户输入、提示词模板、LLM 和输出解析器像管道一样连接起来。这种声明式的链式调用,是 LangChain 现代化开发的精髓,它让复杂的逻辑变得清晰易懂。RunnablePassthrough 在这里的作用是确保用户的原始输入能够被传递到链的下一个环节,也就是 prompt 中的 {question} 占位符。

通过这个简单的链,我们的智能客服助手现在能够:

  1. 理解用户提问:LLM 能够解析用户输入的自然语言。
  2. 扮演特定角色:它会以一个“专业客服”的口吻来回答问题。
  3. 提供基础信息:对于其“已知”的产品或服务问题,能给出通用性回答。
  4. 识别知识边界:当遇到超出其“认知”范围的问题时,能礼貌地拒绝并引导用户寻求人工帮助。

这,就是我们智能客服知识库的第一个里程碑!虽然还很基础,但它已经具备了对话能力,为我们后续的记忆、知识检索、工具调用等高级功能打下了坚实的基础。

坑与避坑指南

作为一名老兵,我见过太多新手在这里栽跟头。别担心,我来给你们指几条明路:

  1. API Key 管理不当
    • :直接把 OPENAI_API_KEY 硬编码在代码里,或者上传到 Git 仓库。这是安全大忌!
    • 避坑:永远使用环境变量 (.env 文件配合 python-dotenvdotenv)。在生产环境中,使用更安全的秘密管理服务(如 AWS Secrets Manager, Azure Key Vault, Kubernetes Secrets)。
  2. LLM 模型选择误区
    • :一上来就用最强大的模型(如 gpt-4),或者最便宜的模型(如 gpt-3.5-turbo),不考虑场景。
    • 避坑:根据场景权衡成本、速度和性能。客服场景初期,gpt-3.5-turbo 往往是性价比之王。需要更复杂推理、更高准确性时,才考虑升级。不同模型有不同的能力边界和 token 限制。
  3. 提示词工程的“玄学”
    • :提示词写得又长又臭,或者模糊不清,期望 LLM 能“猜”到你的意图。
    • 避坑:提示词工程是一门艺术,更是一门科学。清晰、具体、简洁是核心。给 LLM 明确的角色(Persona)、明确的任务(Task)、明确的约束(Constraints)和明确的输出格式(Format)。在本期的客服助手例子中,我们就明确了它的角色和处理超出知识范围问题的行为。
  4. 同步调用阻塞
    • :在 Web 服务或并发场景中,直接使用同步调用 chain.invoke(),导致服务器响应缓慢甚至阻塞。
    • 避坑:LangChain 的所有组件都支持异步调用 (.ainvoke() / await chain.invoke())。在生产级应用中,尤其是在 I/O 密集型任务(如调用外部 API)时,务必使用异步,以提高并发和响应速度。
  5. 缺乏错误处理
    • :对 LLM API 调用失败、网络中断、模型返回异常等情况不作处理,导致应用崩溃。
    • 避坑:始终用 try-except (Python) 或 try-catch (TypeScript) 包裹 LLM 调用,并实现重试机制和优雅降级策略。例如,当 LLM 调用失败时,可以尝试使用备用模型,或者直接提示用户稍后再试。

📝 本期小结

恭喜你!在本期课程中,我们不仅深入理解了 LangChain 的核心价值和它的三大基石——LLMs、Prompts 和 Chains,更亲手搭建了我们“智能客服知识库”的第一个版本。这个简单的客服助手虽然还不能上岗“996”,但它已经能开口说话,理解一些基本的用户意图,并且知道自己的能力边界。这正是我们从零基础迈向生产级应用的第一步!

我们看到了 LangChain 如何将原本散乱的 LLM 能力,通过结构化的组件和链式编排,变得可控、可复用、可扩展。这为我们后续要构建的更复杂的记忆模块、外部工具集成、知识库检索等高级功能,打下了坚实的基础。

在下一期,我们将深入探讨 LangChain 的**记忆(Memory)**模块。你可能会问,现在的客服助手是不是“金鱼记忆”?没错!它每次对话都像第一次见面。所以,如何让我们的客服助手记住用户的历史对话,提供更连贯、更个性化的服务?敬请期待下期内容!