Langchainjs - 提示、消息和结构化输出 - 总结

4 阅读7分钟

第三章:提示、消息和结构化输出 - 总结

章节概述

本章教授在 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

代码文件列表

  1. 01-messages-vs-templates.ts - 比较消息数组和提示模板的两种方法
  2. 02-message-construction.ts - 演示各种消息构建模式,包括基本消息类型、多轮对话、动态消息构建和消息元数据
  3. 03-basic-template.ts - 展示如何创建和使用基本的 ChatPromptTemplate
  4. 04-template-formats.ts - 比较 ChatPromptTemplate 和 PromptTemplate
  5. 05-few-shot.ts - 演示使用 FewShotChatMessagePromptTemplate 的少样本提示
  6. 06-composition.ts - 展示如何组合多个提示片段
  7. 07-structured-output.ts - 演示如何使用 withStructuredOutput() 和 Zod 模式获取结构化输出
  8. 08-zod-schemas.ts - 演示使用复杂嵌套 Zod 模式提取详细的公司信息

下一步

完成本章后,你将能够:

  • 理解何时使用消息 vs 模板
  • 为代理工作流构建消息数组
  • 为 RAG 系统创建可重用的提示模板
  • 在提示中使用变量和动态内容
  • 实现少样本提示(通过示例教学)
  • 组合多个提示
  • 使用 Zod 模式生成结构化输出
  • 为你的用例选择正确的方法

下一步:学习 函数调用与工具,将 AI 输出转换为现实世界的操作。

这个是微软的学习指南: langchainjs 入门指南