第三章:提示、消息和结构化输出 - 总结
章节概述
本章教授在 LangChain.js 中使用大语言模型(LLM)的三种基本技术:消息、提示模板和结构化输出。这些技术为构建代理和 RAG 系统奠定基础。
核心思想:根据用例选择正确的方法
- 消息:用于代理、动态工作流、多步推理
- 模板:用于 RAG 系统、可重用提示、一致性
第一部分:基于消息的提示
核心概念
消息数组是 LangChain.js 中代理系统的基础。消息保留了对话结构,这正是代理进行多步推理和工具使用所需要的。
消息类型
| 消息类型 | 用途 | 示例 |
|---|---|---|
| SystemMessage | 设置 AI 的行为、个性和角色 | new SystemMessage("You are a helpful coding assistant.") |
| HumanMessage | 表示用户输入或问题 | new HumanMessage("What is a variable?") |
| AIMessage | 表示 AI 之前的响应 | new AIMessage("A variable stores data...") |
关键代码示例
示例 1:消息 vs 模板
// 方法 1:消息(由代理使用)
const messages = [
new SystemMessage("You are a helpful translator."),
new HumanMessage("Translate 'Hello, world!' to French"),
];
const response = await model.invoke(messages);
// 方法 2:模板(由 RAG 使用)
const template = ChatPromptTemplate.fromMessages([
["system", "You are a helpful translator."],
["human", "Translate '{text}' to {language}"],
]);
const chain = template.pipe(model);
const response = await chain.invoke({ text: "Hello, world!", language: "French" });
示例 2:动态消息构建
// 动态构建消息的函数
function createConversation(role: string, examples: Array<{question: string; answer: string}>, newQuestion: string): BaseMessage[] {
const messages: BaseMessage[] = [new SystemMessage(`You are a ${role}.`)];
// 添加少样本示例
examples.forEach(({ question, answer }) => {
messages.push(new HumanMessage(question));
messages.push(new AIMessage(answer)); // 通过示例教学
});
messages.push(new HumanMessage(newQuestion));
return messages;
}
工作原理
消息数组:
- 使用
new SystemMessage()和new HumanMessage()直接构建 - 直接传递给
model.invoke(messages) - 无模板或变量替换
- 由 LangChain 中的代理使用
少样本学习:
- 通过展示示例对话来教学 AI
- 每个示例在数组中成为一对 HumanMessage → AIMessage
- AI 从这些示例中学习模式
第二部分:基于模板的提示
核心概念
模板允许你创建带有变量的可重用、可维护的提示。此方法对许多用例很有价值,包括 RAG 系统、一致的格式化,以及任何需要提示可重用性的场景。
邮件合并类比
提示模板的工作方式类似于邮件合并。创建一个带有占位符({name}、{orderId})的模板,然后每次填充具体细节。这确保了一致性并使更新更容易。
关键代码示例
示例 3:基本模板
// 创建可重用的模板
const template = ChatPromptTemplate.fromMessages([
["system", "You are a helpful assistant that translates {input_language} to {output_language}."],
["human", "{text}"],
]);
// 通过管道连接到模型以创建可重用的链
const chain = template.pipe(model);
// 使用不同的值使用模板
const result = await chain.invoke({
input_language: "English",
output_language: "French",
text: "Hello, how are you?"
});
示例 4:模板格式
// ChatPromptTemplate:用于带有系统/人类消息的聊天模型
const chatTemplate = ChatPromptTemplate.fromMessages([
["system", "You are a {role} who speaks in {style} style."],
["human", "{question}"],
]);
// PromptTemplate:简单的基于字符串的格式
const stringTemplate = PromptTemplate.fromTemplate(
"Write a {adjective} {item} about {topic}."
);
const prompt = await stringTemplate.format({ adjective: "funny", item: "poem", topic: "JavaScript" });
示例 5:少样本提示
// 定义教学示例
const examples = [
{ input: "happy", output: "😊" },
{ input: "sad", output: "😢" },
{ input: "excited", output: "🎉" },
];
// 创建示例模板
const exampleTemplate = ChatPromptTemplate.fromMessages([
["human", "{input}"],
["ai", "{output}"],
]);
// 创建少样本模板
const fewShotTemplate = new FewShotChatMessagePromptTemplate({
examplePrompt: exampleTemplate,
examples: examples,
inputVariables: [],
});
// 与最终问题结合
const finalTemplate = ChatPromptTemplate.fromMessages([
["system", "Convert emotions to emojis based on these examples:"],
fewShotTemplate,
["human", "{input}"],
]);
示例 6:模板组合
// 可重用的提示片段
const systemTemplate = "You are an expert {domain} educator.";
const contextTemplate = "Teaching level: {level}\nAudience: {audience}";
const taskTemplate = "Explain {topic} in simple terms.";
// 组合它们
const fullTemplate = ChatPromptTemplate.fromMessages([
["system", systemTemplate + "\n\n" + contextTemplate],
["human", taskTemplate],
]);
// 使用部分模板(预填充一些变量)
const partialTemplate = await template.partial({
role: "Technical Writer",
company: "DevDocs Pro",
});
工作原理
模板的好处:
- 可重用片段:编写一次公共部分,混合和匹配
- 一致性:相似提示的相同结构
- 灵活性:不同需求的不同组合
- 可维护性:在一个地方更新共享片段
- 对 RAG 至关重要:从可重用组件构建文档处理模板
少样本提示:
- 通过展示示例来教学 AI
- 比仅使用指令更可靠
- 非常适合结构化输出和一致的格式化
- 对许多用例很有价值,包括用于响应格式化的 RAG 系统
第三部分:结构化输出
核心概念
结构化输出使用 Zod 模式将 AI 文本响应转换为类型安全的、经过验证的数据结构。这对于构建需要可靠数据提取的生产应用程序至关重要。
什么是 Zod?
Zod 是一个 TypeScript 优先的模式验证库,它定义数据结构和规则。
关键代码示例
示例 7:基本结构化输出
// 使用 Zod 模式定义结构
const PersonSchema = z.object({
name: z.string().describe("The person's full name"),
age: z.number().describe("The person's age in years"),
email: z.string().email().describe("The person's email address"),
occupation: z.string().describe("The person's job or profession"),
});
// 创建返回结构化输出的模型
// strict: true 确保模型输出完全匹配模式(推荐)
const structuredModel = model.withStructuredOutput(PersonSchema, {
strict: true,
});
// 获取类型化数据而不是自由文本!
const result = await structuredModel.invoke("My name is Alice, I'm 28...");
console.log(result.name); // 类型安全访问
示例 8:复杂的嵌套模式
// 带有嵌套对象和数组的复杂模式
const CompanySchema = z.object({
name: z.string().describe("Company name"),
founded: z.number().describe("Year the company was founded"),
headquarters: z.object({ // 嵌套对象
city: z.string(),
country: z.string(),
}).describe("Company headquarters location"),
products: z.array(z.string()).describe("List of main products or services"),
employeeCount: z.number().describe("Approximate number of employees"),
isPublic: z.boolean().describe("Whether the company is publicly traded"),
});
// 使用严格模式创建结构化模型以确保可靠的模式合规性
const structuredModel = model.withStructuredOutput(CompanySchema, {
strict: true,
});
// 将模板与结构化输出结合
const chain = template.pipe(structuredModel);
工作原理
结构化输出的好处:
- 类型安全性:TypeScript 知道结构,为我们提供自动完成和类型检查
- 无需手动解析:AI 为你完成提取和格式化
- 自动验证:Zod 自动验证数据
- 一致性:无论输入风格如何,格式都一致
- 易于集成:易于与数据库、API 和 UI 一起使用
何时使用结构化输出:
- 从文本或文档中数据提取
- 使用经过验证的数据数据库插入
- 具有保证格式的 API 响应
- 从自然语言表单填充
- 具有预定义类别的分类任务
- 需要结构化文档元数据的 RAG 系统
决策框架:消息 vs 模板
| 方法 | 用于 | 章节 |
|---|---|---|
| 消息 | 代理、动态工作流、多步推理、工具集成 | 代理入门 |
| 模板(经典方法) | 可重用提示、变量替换、一致性、RAG 系统、少样本学习 | 文档、嵌入与语义搜索 |
两种方法都有价值:消息用于动态工作流,模板用于可重用性和一致性。
关键要点
消息
- 直接消息构建 - 以编程方式构建对话
- SystemMessage、HumanMessage、AIMessage - 核心消息类型
- 多轮对话 - 维护对话状态
- 由代理使用 - 代理系统的基础
- 为代理做好准备 - 构建自主代理的基础
模板
- 模板减少代码重复 - 编写一次,随处使用
- 使用
{name}语法的变量 - 创建动态提示 - ChatPromptTemplate for chat models - 适用于消息数组
- PromptTemplate for simple cases - 基于字符串的模板
- Few-shot prompting - 通过示例教学以获得更好的结果
- Composition - 组合模板以创建复杂提示
- Structured outputs with Zod - 获取类型化数据,而不仅仅是文本
- Type safety - 验证 AI 响应匹配你的模式
- 对许多用例很有价值 - 可重用性、一致性、RAG 系统
- 为 RAG 系统做好准备 - 文档检索和语义搜索的基础
全局视角
- 知道何时使用每种方法 - 代理使用消息,RAG 使用模板
- 两者都必不可少 - 现代 LangChain.js 使用两种范式
- 可维护性 - 在一个地方更新提示
- 类型安全 - 在整个过程中利用 TypeScript
代码文件列表
- 01-messages-vs-templates.ts - 比较消息数组和提示模板的两种方法
- 02-message-construction.ts - 演示各种消息构建模式,包括基本消息类型、多轮对话、动态消息构建和消息元数据
- 03-basic-template.ts - 展示如何创建和使用基本的 ChatPromptTemplate
- 04-template-formats.ts - 比较 ChatPromptTemplate 和 PromptTemplate
- 05-few-shot.ts - 演示使用 FewShotChatMessagePromptTemplate 的少样本提示
- 06-composition.ts - 展示如何组合多个提示片段
- 07-structured-output.ts - 演示如何使用 withStructuredOutput() 和 Zod 模式获取结构化输出
- 08-zod-schemas.ts - 演示使用复杂嵌套 Zod 模式提取详细的公司信息
下一步
完成本章后,你将能够:
- 理解何时使用消息 vs 模板
- 为代理工作流构建消息数组
- 为 RAG 系统创建可重用的提示模板
- 在提示中使用变量和动态内容
- 实现少样本提示(通过示例教学)
- 组合多个提示
- 使用 Zod 模式生成结构化输出
- 为你的用例选择正确的方法
下一步:学习 函数调用与工具,将 AI 输出转换为现实世界的操作。
这个是微软的学习指南: langchainjs 入门指南