第 10 期 | 检索技巧 (Retrievers):让知识触手可及 (EN)
Hello, future AI masters! I am your instructor. I am thrilled to embark on this exciting LangChain full-stack development journey with you. Having witnessed AI evolve from research labs to everyday households over the past decade, it is now time for you to build with it firsthand!
Our LangChain Full-Stack Masterclass isn't just about theoretical talk. We will use a continuous Intelligent Support Copilot project as our main thread, guiding you hand-in-hand to build a production-grade AI application from scratch. In each session, we will center around this project, snapping the most cutting-edge LangChain technologies together like Lego blocks onto our support assistant. You'll watch it evolve from a simple "echo chamber" into a "super brain" capable of understanding human intent and solving real problems.
The subtitle for this session is: Deep Dive into LangChain Core Components and the Foundation of Intelligent Support. We will lay the groundwork for the entire project, giving you a bird's-eye view of LangChain, and build the first prototype of our support copilot—an active "listener" that can understand and summarize customer queries.
🎯 Learning Objectives for This Session
After completing this session, you will be able to:
- Understand LangChain's Core Value: Grasp how LangChain simplifies LLM application development and its irreplaceable role in building complex AI systems.
- Master the Foundational Components: Proficiently use core building blocks like LLMs (Language Models), PromptTemplates, and OutputParsers.
- Build a Support Copilot Prototype: Get hands-on experience building an assistant that receives customer queries and accurately summarizes them, taking your first step into practical application.
- Identify Potential Development Pitfalls: Learn common anti-patterns and best practices in LangChain development early on to avoid detours and head straight for success.
📖 Deep Dive into the Concepts
Alright, buckle up! We are now diving deep into the core world of LangChain. You might ask, with so many LLM libraries out there, why learn LangChain? My answer is simple: LangChain is not just a library; it is a framework and an ecosystem. It is a powerful tool that allows you to truly engineer and productize the immense capabilities of LLMs.
Imagine your future support copilot: it won't just answer questions; it will need to query orders, generate emails, and even interact with external systems. If you use raw LLM APIs directly, you will quickly sink into a swamp of "spaghetti code." LangChain acts like a precise orchestral conductor, elegantly choreographing complex LLM calls, data processing, and external tool integrations.
For our Intelligent Support Copilot project, LangChain's core value lies in:
- Modularity and Composability: Breaking down an LLM application into reusable components (e.g., one component for understanding user intent, another for querying the knowledge base, and another for generating the response), and then freely combining them like Lego blocks.
- Chain Thinking (Chains): Linking these components together to form an orderly workflow, processing user requests step-by-step.
- Data Flow Management: Efficiently and structurally passing data between components to ensure information is neither lost nor jumbled.
The Three Cornerstones of LangChain
While building our first support copilot prototype, we will primarily interact with LangChain's three most fundamental, yet most important, concepts:
LLM (Language Models):
- The Concept (The Way): This is the "brain" of our support copilot. It is responsible for understanding and generating natural language. Whether it's OpenAI's GPT series, Anthropic's Claude, or a locally deployed Llama 2, they serve as the core computational unit of your AI system. LangChain provides an abstraction layer, allowing you to easily swap between different LLMs without changing much of your business logic.
- The Practice (The Art): In LangChain, an LLM is encapsulated as an interface. You simply instantiate it, and then you can feed it text just like calling a function, and it will return text back to you.
PromptTemplate:
- The Concept (The Way): If the LLM is the brain, the PromptTemplate is the "instruction manual" for that brain. You can't expect the LLM to magically know what you want it to do. You need to tell it clearly, explicitly, and structurally. PromptTemplates allow you to pre-define the skeleton of your instructions and dynamically fill in variables, much like a fill-in-the-blank exercise. This is crucial for ensuring the style, accuracy, and consistency of your support copilot's responses.
- The Practice (The Art): It takes user input (like a customer's query), combines it with preset system roles and instructions, and generates a complete prompt ready to be fed to the LLM.
OutputParser:
- The Concept (The Way): The raw output from an LLM is usually free-form text, but our applications often require structured data for further processing (e.g., extracting order numbers or issue types from the copilot's summary). The OutputParser's job is to translate the LLM's "plain talk" into JSON, lists, or other specific formats that machines can understand. This is the critical bridge connecting the LLM to subsequent business logic.
- The Practice (The Art): It receives the text output from the LLM and attempts to parse it into our desired format based on predefined rules.
Support Copilot Prototype Workflow (Mermaid Diagram)
Now, let's use a diagram to clearly illustrate how our first support copilot prototype works when a customer asks a question:
graph TD
A[User Query: "My order #123 hasn't shipped yet"] --> B(PromptTemplate: Construct Instructions)
B -- Fill variable {customer_query} --> C{Complete Prompt: "You are a support assistant... Summarize: My order #123 hasn't shipped yet"}
C --> D[LLM e.g., GPT-3.5-Turbo: Understand and Generate Summary]
D -- Raw Text Output --> E(OutputParser: Parse to structured data or plain text)
E -- Summarized Query --> F[Copilot Response: "The customer is asking about unshipped order #123"]
style A fill:#f9f,stroke:#333,stroke-width:2px,color:#333
style F fill:#bbf,stroke:#333,stroke-width:2px,color:#333
style B fill:#e0f7fa,stroke:#0097a7,stroke-width:1px,color:#333
style C fill:#fff3e0,stroke:#ff8f00,stroke-width:1px,color:#333
style D fill:#e8f5e9,stroke:#4caf50,stroke-width:1px,color:#333
style E fill:#ffebee,stroke:#d32f2f,stroke-width:1px,color:#333Diagram Explanation:
- User Query: The customer inputs their question; this is the starting point of our workflow.
- PromptTemplate (Construct Instructions): This component receives the raw user query and embeds it into our preset prompt template. This template tells the LLM its role (Support Copilot), its task (Summarize the query), and how to format the output.
- Complete Prompt: After processing by the PromptTemplate, a complete prompt containing all instructions and the user's query is generated, ready to be sent to the LLM.
- LLM (Language Model): Our "brain" receives the prompt and begins processing. Based on the instructions and its powerful language understanding capabilities, it generates a summary of the customer's query.
- OutputParser (Parse Output): The LLM's output is plain text. The OutputParser is responsible for processing it. In this session, we might just simply return the plain text, but in future lessons, it will become much smarter, parsing the text into structured data like JSON.
- Copilot Response: Finally, the parsed summary text is presented to the user or internal support staff, completing this interaction.
This simple chain structure is the essence of LangChain. It breaks down complex AI tasks into manageable, composable steps, allowing you to clearly see the data flow and processing logic.
💻 Hands-On Coding (Application in the Copilot Project)
Enough theory—it's time to roll up our sleeves and turn these concepts into the very first lines of code for our Intelligent Support Copilot!
Project Requirement: Intelligent Support Query Summarizer
The first step in our Intelligent Support Copilot project is to enable the assistant to accurately and concisely summarize customer queries. This sounds simple, but it is the foundation for all subsequent complex features (like intent recognition, knowledge base retrieval, and ticket creation). A good summary helps human agents quickly grasp the core issue and provides clean input for downstream automated processing.
We will use Python for our hands-on practice and provide TypeScript code snippets as a reference.
Environment Setup
Before we begin, please ensure you have Python (3.9+ recommended) and npm/yarn (if using TypeScript) installed.
1. Create the project directory and install dependencies:
# Create project folder
mkdir intelligent-support-copilot
cd intelligent-support-copilot
# Create and activate virtual environment (Python best practice)
python -m venv venv
source venv/bin/activate # macOS/Linux
# Or venv\Scripts\activate # Windows
# Install LangChain core, OpenAI integration, and dotenv
pip install langchain langchain-openai python-dotenv
# If you also want to see the TypeScript example (optional)
# mkdir ts-example
# cd ts-example
# npm init -y
# npm install langchain @langchain/openai @langchain/core dotenv
# npm install -D typescript @types/node ts-node
# cd .. # Return to project root
2. Set up your OpenAI API Key:
Create a .env file in the root directory of your project and paste your OpenAI API Key inside. Remember never to hardcode your API Key directly in your code or commit it to version control!
OPENAI_API_KEY="sk-YOUR_OPENAI_API_KEY_HERE"
Python Hands-On Code
Create a main.py file:
import os
from dotenv import load_dotenv
# Import ChatOpenAI from langchain_openai to interact with OpenAI models
from langchain_openai import ChatOpenAI
# Import ChatPromptTemplate from langchain_core.prompts to create prompt templates
from langchain_core.prompts import ChatPromptTemplate
# Import StrOutputParser from langchain_core.output_parsers to parse LLM output into strings
from langchain_core.output_parsers import StrOutputParser
# Import RunnablePassthrough from langchain_core.runnables to simply pass inputs through
# This is a crucial concept representing the foundational building blocks of LangChain Expression Language (LCEL)
# Load environment variables (including OPENAI_API_KEY)
load_dotenv()
print("--- 智能客服小助手:问题总结器启动 ---")
# --- 1. Initialize the Language Model (LLM) ---
# We choose ChatOpenAI because it is better suited for conversational and instruction-following tasks
# model="gpt-3.5-turbo" is an economical choice with solid performance
# The temperature parameter controls the model's creativity (0.0 means more deterministic, 1.0 means more creative)
# For summarizing support queries, we aim for accuracy and stability, so we set a lower temperature
llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0.3)
print("✅ LLM (GPT-3.5-Turbo) 初始化完成。")
# --- 2. Define the PromptTemplate ---
# This is the "instruction manual" for our support copilot. It tells the LLM its role and task.
# from_messages allows us to define conversational prompts, including system and user messages.
# The "system" message sets the LLM's identity and behavioral guidelines.
# The "user" message is the actual user input, where {customer_query} is a placeholder to be filled at runtime.
prompt = ChatPromptTemplate.from_messages([
("system", "你是一个经验丰富且专业的智能客服助手。你的任务是简洁、准确、客观地总结客户提出的问题,提取核心要点,不添加任何额外信息或猜测。"),
("user", "客户原始问题:\n{customer_query}\n\n请严格按照上述要求总结客户问题:")
])
print("✅ PromptTemplate 定义完成。")
# --- 3. Define the OutputParser ---
# For this session's simple summarization task, we just need to return the LLM's text output directly as a string.
# StrOutputParser is the most basic parser.
output_parser = StrOutputParser()
print("✅ OutputParser (StrOutputParser) 定义完成。")
# --- 4. Assemble into a LangChain Chain ---
# One of LangChain's core concepts is the "Chain".
# We use LangChain Expression Language (LCEL) to assemble these components.
# The pipe operator "|" means passing the output of the previous component as the input to the next.
# Flow: User Input -> Prompt Filling -> LLM Processing -> OutputParser Parsing -> Final Output
customer_problem_summarizer_chain = prompt | llm | output_parser
print("✅ LangChain 链组装完成:Prompt -> LLM -> OutputParser。")
# --- 5. Hands-On Practice: Simulate customer queries and get summaries ---
print("\n--- 模拟客户提问场景 ---")
# Scenario 1: Simple order inquiry
customer_issue_1 = "我的订单号是 #20230815-001,我已经付款了,但是到现在还没有收到发货通知。网站上显示还在处理中,请问我的包裹什么时候能发货?我急着用!"
print(f"\n[客户原始问题 1]:\n{customer_issue_1}\n")
print("📞 智能客服助手正在总结中...")
summary_1 = customer_problem_summarizer_chain.invoke({"customer_query": customer_issue_1})
print(f"[智能客服总结 1]:\n{summary_1}\n")
# Expected output example: The customer is asking about the shipping status of order #20230815-001, which has been paid for but no shipping notice has been received, and hopes it ships soon.
# Scenario 2: Complex query with multiple intents
customer_issue_2 = "我昨天在你们网站购买了一个智能音箱,订单号是 #20230816-002。我发现我选错了颜色,我想把黑色换成白色。另外,我看到你们最近有活动,满500减50,我的订单是499元,能申请优惠吗?"
print(f"\n[客户原始问题 2]:\n{customer_issue_2}\n")
print("📞 智能客服助手正在总结中...")
summary_2 = customer_problem_summarizer_chain.invoke({"customer_query": customer_issue_2})
print(f"[智能客服总结 2]:\n{summary_2}\n")
# Expected output example: The customer has two requests regarding order #20230816-002: 1. Change the smart speaker color from black to white; 2. Ask if their 499 RMB order qualifies for the "50 off 500" promotion.
# Scenario 3: Vague query
customer_issue_3 = "你们的产品是不是不太好用啊?我买了一个,感觉老是卡顿,是不是质量问题啊?"
print(f"\n[客户原始问题 3]:\n{customer_issue_3}\n")
print("📞 智能客服助手正在总结中...")
summary_3 = customer_problem_summarizer_chain.invoke({"customer_query": customer_issue_3})
print(f"[智能客服总结 3]:\n{summary_3}\n")
# Expected output example: The customer is reporting lag issues with the purchased product and suspects a quality defect.
print("--- 智能客服小助手:问题总结器运行完毕 ---")
Run the code:
python main.py
You will see output similar to the following (exact summary text may vary slightly depending on the LLM model and temperature settings):
--- 智能客服小助手:问题总结器启动 ---
✅ LLM (GPT-3.5-Turbo) 初始化完成。
✅ PromptTemplate 定义完成。
✅ OutputParser (StrOutputParser) 定义完成。
✅ LangChain 链组装完成:Prompt -> LLM -> OutputParser。
--- 模拟客户提问场景 ---
[客户原始问题 1]:
我的订单号是 #20230815-001,我已经付款了,但是到现在还没有收到发货通知。网站上显示还在处理中,请问我的包裹什么时候能发货?我急着用!
📞 智能客服助手正在总结中...
[智能客服总结 1]:
客户询问订单号 #20230815-001 的发货状态,该订单已付款但尚未收到发货通知,目前网站显示仍在处理中,客户急需了解包裹何时能发货。
[客户原始问题 2]:
我昨天在你们网站购买了一个智能音箱,订单号是 #20230816-002。我发现我选错了颜色,我想把黑色换成白色。另外,我看到你们最近有活动,满500减50,我的订单是499元,能申请优惠吗?
📞 智能客服助手正在总结中...
[智能客服总结 2]:
客户关于订单号 #20230816-002 有两点需求:一是希望将购买的智能音箱颜色从黑色更换为白色;二是询问其订单金额 499 元是否能参与满 500 减 50 的优惠活动。
[客户原始问题 3]:
你们的产品是不是不太好用啊?我买了一个,感觉老是卡顿,是不是质量问题啊?
📞 智能客服助手正在总结中...
[智能客服总结 3]:
客户反映购买的产品存在卡顿问题,并质疑产品质量。
--- 智能客服小助手:问题总结器运行完毕 ---
TypeScript Example (Brief overview, identical logic to Python)
If you are a TypeScript enthusiast, LangChain also provides excellent TS support. The core logic is almost entirely identical to Python, with just some syntax differences.
Create a ts-example/src/main.ts file:
// ts-example/src/main.ts
import { ChatOpenAI } from "@langchain/openai";
import { ChatPromptTemplate } from "@langchain/core/prompts";
import { StringOutputParser } from "@langchain/core/output_parsers";
import * as dotenv from "dotenv";
// Load environment variables
dotenv.config();
async function main() {
console.log("--- 智能客服小助手:问题总结器启动 (TypeScript) ---");
// 1. Initialize the language model
const llm = new ChatOpenAI({
modelName: "gpt-3.5-turbo",
temperature: 0.3,
});
console.log("✅ LLM (GPT-3.5-Turbo) 初始化完成。");
// 2. Define the PromptTemplate
const prompt = ChatPromptTemplate.fromMessages([
["system", "你是一个经验丰富且专业的智能客服助手。你的任务是简洁、准确、客观地总结客户提出的问题,提取核心要点,不添加任何额外信息或猜测。"],
["user", "客户原始问题:\n{customer_query}\n\n请严格按照上述要求总结客户问题:"],
]);
console.log("✅ PromptTemplate 定义完成。");
// 3. Define the OutputParser
const outputParser = new StringOutputParser();
console.log("✅ OutputParser (StringOutputParser) 定义完成。");
// 4. Assemble into a LangChain Chain
// In TypeScript, we use the .pipe() method to connect components
const customerProblemSummarizerChain = prompt.pipe(llm).pipe(outputParser);
console.log("✅ LangChain 链组装完成:Prompt -> LLM -> OutputParser。");
// 5. Hands-On Practice: Simulate customer queries
const customerIssue = "我的订单号是 #20230815-001,我已经付款了,但是到现在还没有收到发货通知。网站上显示还在处理中,请问我的包裹什么时候能发货?我急着用!";
console.log(`\n[客户原始问题]:\n${customerIssue}\n`);
console.log("📞 智能客服助手正在总结中...");
const summary = await customerProblemSummarizerChain.invoke({ customer_query: customerIssue });
console.log(`[智能客服总结]:\n${summary}\n`);
console.log("--- 智能客服小助手:问题总结器运行完毕 (TypeScript) ---");
}
main().catch(console.error);
Run the TypeScript code:
# Inside the ts-example directory
cd ts-example
npx ts-node src/main.ts
You will see output similar to the Python version. This perfectly demonstrates LangChain's