ai agent -- prompt汇总

一.prompt是什么?

Prompt(提示词)就是你发给大模型的"指令 + 上下文 + 问题"的全部内容。

模型本身不会主动做事,它只会根据你给的文字,接着往下写。你给它的那段文字,就是 prompt。

一个标准的 Agent 提示词架构:system 负责"定规矩 + 给工具",human 负责"提需求"。

二.PromptTemplate的作用是什么

以前我们的prompt是用模板字符串放的

现在要用更专业的PromptTemplate

js 复制代码
import { PromptTemplate } from "@langchain/core/prompts";

// 定义一个带变量的模板
const prompt = PromptTemplate.fromTemplate(
  "写一首关于{topic}的{style}诗"
);

// 运行时填入具体变量
const formatted = await prompt.invoke({ topic: "秋天", style: "短小精悍" });
console.log(formatted.toString());
// 输出:写一首关于秋天的短小精悍诗

PromptTemplate的好处是什么?

  1. 🛡️ 输入校验 ------ 把 Bug 挡在发给模型之前。

    字符串里面如果变量不存在就是undefined,在PromptTemplate里面会直接报错,要bug在开发阶段就发现,不会在上线以后才爆发。

  2. 🧩 与 LangChain 链(Chain)原生集成。

pomptTemplate和langchain无缝连接成为一个可调式的东西,但是模板字符串不行。

三.pelinePromptTemplate是什么?

PipelinePromptTemplate 让你把多个 PromptTemplate 像管道一样串联起来,前一个的输出作为后一个的输入,最终拼成一个完整的 Prompt。

好问题!PipelinePromptTemplate 是 LangChain 里一个比较"进阶"但非常实用的工具。先说清楚它解决什么痛点,再看什么时候该用。


一句话定义

PipelinePromptTemplate 让你把多个 PromptTemplate 像管道一样串联起来,前一个的输出作为后一个的输入,最终拼成一个完整的 Prompt。


它解决的核心痛点:Prompt 的组合与复用

假设你有这样一个场景:

场景 问题
多个 Agent 都需要"基础系统指令"(安全规则、输出格式等) 每个模板都复制粘贴一遍?改一处要改 N 个文件
不同业务线共用同一套"角色设定",但任务描述不同 角色设定和任务描述耦合在一起,没法独立复用
提示词越来越长,想分层管理 一个 200 行的模板字符串,维护起来头大

PipelinePromptTemplate 就是为"分层组合提示词"而生的。


不用 Pipeline 的写法(全部耦合):

ini 复制代码
const template = PromptTemplate.fromTemplate(`
你必须遵守以下安全规则:
- 不泄露敏感信息
- 不确定的事明确说不知道

你是一个有 10 年经验的资深代码审查专家。

请审查以下代码,指出 bug 和性能问题:
{code}
`);

改一个安全规则?所有模板都要改。角色要复用给另一个 Chain?又复制一遍。

用 Pipeline 的写法(分层解耦):

每一个template下面都要定义一个坑位,在PipeLine里面做坑位和prompt的对应。

他将roleTemplate的输出写到{role_layer}里面。

PipelinePromptTemplate = 提示词里的"组件化/模块化"。当你发现自己在复制粘贴同一段提示词时,就是该用它的时候了。

四.ChatPromptTemplate是什么?

ChatPromptTemplate 是 LangChain 中专为聊天模型(Chat Model)设计的提示词模板。它用来结构化地构建 messages 数组------也就是 system、user、assistant 这些不同角色的消息组合。

第一种写法

js 复制代码
import { ChatPromptTemplate } from '@langchain/core/prompts';

const prompt = ChatPromptTemplate.fromMessages([
  ['system', '你是一个{role},请用{style}风格回答。'],
  ['human', '{question}']
]);

const messages = await prompt.formatMessages({
  role: '资深前端工程师',
  style: '简洁专业',
  question: 'React 18 有哪些新特性?'
});

const response = await model.invoke(message)

以前我们是这样写的

第二种写法

SystemMessagePromptTemplate 和 HumanMessagePromptTemplate 也能实现ChatPromptTemplate。

js 复制代码
import { ChatPromptTemplate } from '@langchain/core/prompts';
import {
  SystemMessagePromptTemplate,
  HumanMessagePromptTemplate,
} from '@langchain/core/prompts';

const systemTemplate = SystemMessagePromptTemplate.fromTemplate(
  '你是一个{role},请用{style}风格回答。'
);

const humanTemplate = HumanMessagePromptTemplate.fromTemplate(
  '{question}'
);

const prompt = ChatPromptTemplate.fromMessages([
  systemTemplate,
  humanTemplate,
]);

const messages = await prompt.formatMessages({
  role: '资深前端工程师',
  style: '简洁专业',
  question: 'React 18 有哪些新特性?',
});

const response = await model.invoke(messages);

console.log(response.content);

五.MessagesPlaceholder是什么?

MessagesPlaceholder 用来在 ChatPromptTemplate 里预留一个"消息列表的插入位置",让你可以把一整组消息(比如历史对话、few-shot 示例)动态地插进 prompt 里,而不是只能插一段纯文本字符串。

上述信息生成的消息就是:

六.FewShotPromptTemplate是什么的?

FewShotPromptTemplate 是 把"示例问答对"按你定义的格式自动拼进 prompt 里,让模型照着学。​ 它是零样本和微调之间的甜点方案------不需要训练,效果却能提升一大截。

js 复制代码
const fewShotPrompt = new FewShotPromptTemplate({
  examples,                  // 示例数组
  examplePrompt: exampleTemplate,  // 每条示例怎么渲染
  prefix: '请为下面的词语生成3个近义词,用顿号分隔:',  // 示例前面的说明
  suffix: '输入:{user_input}\n输出:',               // 示例后面的用户问题
  inputVariables: ['user_input'],  // suffix 里用到的变量
});

七.ExampleSelector 是什么?

一句话:ExampleSelector(示例选择器)是 LangChain 中用来代替固定 examples 数组的工具------它能根据你当前的输入,从一堆候选示例中自动挑最相关 / 最合适的几条,动态塞进 FewShotPromptTemplate

就是从一大堆example里面找到最合适的案例。

ExampleSelector = few-shot 示例的动态过滤器。​ 把它传给 FewShotPromptTemplateexampleSelector 参数,就能根据用户问题自动选最相关的示例,既省 token 又提效果。最常用的实现是 SemanticSimilarityExampleSelector(基于 Embedding + 向量检索)

八.FewShotChatMessagePromptTemplate 是什么?

它做的事情就是:根据用户当前输入,从示例池里挑几条最相关的,自动渲染成 HumanMessage + AIMessage 对,塞进聊天消息列表里。
它就是FewShotPromptTemplat的升级版

聊天模型的 API(如 OpenAI 的 /chat/completions)接收的是消息列表 ,每条消息带 role,比如下面这样:

js 复制代码
[
  { "role": "system", "content": "你是一个翻译助手" },
  { "role": "user", "content": "0°C" },
  { "role": "assistant", "content": "32°F" },
  { "role": "user", "content": "25°C" }
]

如果你用普通的 FewShotPromptTemplate,它只会吐出一个大字符串,丢失了 role 信息,模型效果会打折扣。

FewShotChatMessagePromptTemplate自动把每条示例渲染成一对 HumanMessage + AIMessage,完美适配聊天格式。

七.使用案例

4-1 使用PromptTemplate.fromTemplate定义模板

js 复制代码
import 'dotenv/config';
import {ChatOpenAI} from '@langchain/openai';
import {PromptTemplate} from '@langchain/core/prompts';

const model = new ChatOpenAI({
  modelName: 'qwen-max',
  apiKey: process.env.OPENAI_API_KEY,
  temperature: 0,
  configuration: {
    baseURL: process.env.OPENAI_BASE_URL,
  },
  timeout: 60000,
  maxRetries: 3,
});

const template = PromptTemplate.fromTemplate(
 `你是一个专业信息汇总助手,请根据本周数据填写本周工作总结。
  公司名称: {companyName}
  部门名称: {departmentName}
  直接汇报对象: {reportTo}
  本周时间范围: {weekRange}
  团队目标: {teamGoal}
`);

const prompt = await template.format({
  companyName: '腾讯科技',
  departmentName: '研发部',
  reportTo: '张总',
  weekRange: '2023年1月1日至2023年1月7日',
  teamGoal: '完成新项目上线,提升团队效率。',
});

const stream = await model.stream(prompt);

console.log(`AI 回答如下:\n`)

for await (const part of stream) {
   process.stdout.write(part.content);
}

好处是:模板固定,数据可以随意变化。

js 复制代码
const prompt = await template.format({
  companyName: '腾讯科技',
  departmentName: '研发部',
  reportTo: '张总',
  weekRange: '2023年1月1日至2023年1月7日',
  teamGoal: '完成新项目上线,提升团队效率。',
});

4-2 使用PipelinePromptTemplate管理模板

js 复制代码
import 'dotenv/config';
import { ChatOpenAI } from '@langchain/openai';
import { PipelinePromptTemplate, PromptTemplate } from '@langchain/core/prompts';

// 初始化模型
const model = new ChatOpenAI({
  modelName: process.env.MODEL_NAME,
  apiKey: process.env.OPENAI_API_KEY,
  temperature: 0,
  configuration: {
    baseUrl: process.env.OPENAI_BASE_URL,
  },
});

// A. 人设模块
const personaPrompt = PromptTemplate.fromTemplate(
  `你是一名资深工程团队负责人,写作风格:{tone}。
你擅长把枯燥的技术细节写得既专业又有温度。\n`
);

// B. 背景模块
const contextPrompt = PromptTemplate.fromTemplate(
  `公司:{company_name}
部门:{team_name}
直接汇报对象:{manager_name}
本周时间范围:{week_range}
本周部门核心目标:{team_goal}\n`
);

// C. 任务模块
const taskPrompt = PromptTemplate.fromTemplate(
  `以下是本周团队的开发活动 (Git / Jira 汇总):
{dev_activities}

请你从这些原始数据中提炼出:
1. 本周整体成就亮点
2. 潜在风险和技术债
3. 下周重点计划建议\n`
);

// D. 格式模块
const formatPrompt = PromptTemplate.fromTemplate(
  `请用 Markdown 输出周报,结构包含:
1. 本周概览 (2-3 句话的 Summary)
2. 详细拆分 (按模块或项目分段)
3. 关键指标表格,表头为:模块 | 亮点 | 风险 | 下周计划

注意:
- 尽量引用一些具体数据 (如提交次数、完成的任务编号)
- 语气专业,但可以偶尔带一点轻松的口吻,符合 {company_values}。
`
);

// E. 最终组合 Prompt (把上面几个模块拼在一起)
const finalWeeklyPrompt = PromptTemplate.fromTemplate(
  `{persona_block}
{context_block}
{task_block}
{format_block}

现在请生成本周的最终周报:`
);

const pipelinePrompt = new PipelinePromptTemplate({
  pipelinePrompts: [
    { name: 'persona_block', prompt: personaPrompt },
    { name: 'context_block', prompt: contextPrompt },
    { name: 'task_block', prompt: taskPrompt },
    { name: 'format_block', prompt: formatPrompt },
  ],
  finalPrompt: finalWeeklyPrompt,
  inputVariables: [
    'tone',
    'company_name',
    'team_name',
    'manager_name',
    'week_range',
    'team_goal',
    'dev_activities',
    'company_values',
  ],
});

const pipelineFormatted = await pipelinePrompt.format({
  tone: '专业、清晰、略带幽默',
  company_name: '星航科技',
  team_name: 'AI 平台组',
  manager_name: '王总',
  week_range: '2025-02-03 ~ 2025-02-09',
  team_goal: '完成智能周报 Agent 的 MVP 版本,并打通 Git / Jira 数据源。',
  dev_activities:
    '- Git: 58 次提交,3 个主要分支合并\n' +
    '- Jira: 完成 12 个 Story,关闭 7 个 Bug\n' +
    '- 关键任务: 完成智能周报 Pipeline 设计、实现 Prompt 拆分、接入 ExampleSelector',
  company_values: '「极致、开放、靠谱」的价值观',
});

console.log('PipelinePromptTemplate 组合后的 Prompt: ');
console.log(pipelineFormatted);

上面我们说一个prompt对应一个坑位名,其实他们都可以写到最后一个里面,然后在pipeline的时候一次性的使用。

4-3 Template还能跨文件使用

js 复制代码
import 'dotenv/config';
import { ChatOpenAI } from '@langchain/openai';
import { PipelinePromptTemplate, PromptTemplate } from '@langchain/core/prompts';
import {personaPrompt, contextPrompt} from './pipeline-prompt-template.mjs'

// 初始化模型
const model = new ChatOpenAI({
  modelName: process.env.MODEL_NAME,
  apiKey: process.env.OPENAI_API_KEY,
  temperature: 0,
  configuration: {
    baseUrl: process.env.OPENAI_BASE_URL,
  },
});

// A. 工作模块
const workPrompt = PromptTemplate.fromTemplate(
  `下面是你本季度工作的具体信息:{okr_facts}
  你更具这些信息,生成本周周报,并给我一些建议。
`
);

// B. 邮件模块
const emailPrompt = PromptTemplate.fromTemplate(
  `你帮我我按照周报的信息写一篇邮件,邮件的主要内容为:
  邮件开头是目的,
  本季度的概览,
  下季度的计划
  语气要专业,克制坦诚,能要老板看到成绩,也感受到问题所在,寻求改进的办法。
  `
);

// E. 最终组合 Prompt (把上面几个模块拼在一起)
const finalWeeklyPrompt = PromptTemplate.fromTemplate(
  `{persona_block}
   {context_block}
   {task_block}
   {format_block}
现在请生成本季度回顾邮件:`
);

const pipelinePrompt = new PipelinePromptTemplate({
  pipelinePrompts: [
    { name: 'persona_block', prompt: personaPrompt },
    { name: 'context_block', prompt: contextPrompt },
    { name: 'task_block', prompt: workPrompt },
    { name: 'format_block', prompt: emailPrompt },
  ],
  finalPrompt: finalWeeklyPrompt,
  inputVariables: [
    'tone',
    'company_name',
    'team_name',
    'manager_name',
    'week_range',
    'team_goal',
    'dev_activities',
    'company_values',
    'okr_facts'
  ],
});

const pipelineFormatted = await pipelinePrompt.format({
  tone: '专业、清晰、略带幽默',
  company_name: '星航科技',
  team_name: 'AI 平台组',
  manager_name: '王总',
  week_range: '2025-02-03 ~ 2025-02-09',
  team_goal: '完成智能周报 Agent 的 MVP 版本,并打通 Git / Jira 数据源。',
  dev_activities:
    '- Git: 58 次提交,3 个主要分支合并\n' +
    '- Jira: 完成 12 个 Story,关闭 7 个 Bug\n' +
    '- 关键任务: 完成智能周报 Pipeline 设计、实现 Prompt 拆分、接入 ExampleSelector',
  company_values: '「极致、开放、靠谱」的价值观',
  okr_facts:`
    提取文件信息
    O1:完成在线特征平台的 V1 上线,覆盖 3 条核心业务链路;
    O2:训练并上线新一代推荐模型,首页 CTR 提升 6.3%;
    O3:推动 GPU 资源利用率优化项目,整体利用率从 42% 提升到 67%;
    重要事件:一次线上 P1 事故,一次跨部门联合专项;
    团队:新增 2 位同学,整体人效相比去年同期提升约 18%
  `
});

console.log('PipelinePromptTemplate 组合后的 Prompt: ');
console.log(pipelineFormatted)

4-3 pipelinePromp管道也能跨文件使用

const pipelineWithPartial = await pipelinePrompt.partial({ company_name: '星航科技', company_values: '「极致、开放、靠谱」的价值观', tone: '偏正式但不僵硬', }); 就是预先填入一些参数。

partial()就是将后面format()里面重复的参数都提取到这个里面来。

js 复制代码
import { pipelinePrompt } from "./pipeline-prompt-template.mjs";

const pipelineWithPartial = await pipelinePrompt.partial({
    company_name: '星航科技',
    company_values: '「极致、开放、靠谱」的价值观',
    tone: '偏正式但不僵硬',
});

const partialFormatted = await pipelineWithPartial.format({
    team_name: 'AI 平台组',
    manager_name: '刘东',
    week_range: '2025-02-10 ~ 2025-02-16',
    team_goal: '上线周报 Agent 到内部试用环境,并收集反馈。',
    dev_activities:
        '- 小明: 完成 Git/Jira 集成封装\n' +
        '- 小红: 实现 Prompt 配置化加载\n' +
        '- 小强: 接入权限系统,支持按部门过滤数据',
});

const partialFormatted2 = await pipelineWithPartial.format({
    team_name: 'AI 工程效率组',
    manager_name: '王强',
    week_range: '2025-02-17 ~ 2025-02-23',
    team_goal: '打通 CI/CD 可观测链路,并推动落地到核心服务。',
    dev_activities:
        '- 阿俊: 完成流水线执行数据的链路追踪接入\n' +
        '- 小白: 梳理核心服务发布流程,补齐变更记录\n' +
        '- 小七: 研发发布回滚一键脚本 PoC 版本',
});

console.log(partialFormatted);
console.log('\n============= 分割线:第二份周报模板 =============\n');
console.log(partialFormatted2);

4-3 使用ChatPromptTemplate

在现实开发中,我们更加喜欢使用这个

就是在一个数组里面放上 ytemMessage 和 HumanMessage。

js 复制代码
import 'dotenv/config';
import { ChatOpenAI } from '@langchain/openai';
import { ChatPromptTemplate } from '@langchain/core/prompts';

const model = new ChatOpenAI({
  modelName: process.env.MODEL_NAME,
  apiKey: process.env.OPENAI_API_KEY,
  temperature: 0,
  configuration: {
    baseURL: process.env.OPENAI_BASE_URL,
  },
});

const chatPrompt = ChatPromptTemplate.fromMessages([
  [
    'system',
    `你是一名资深工程团队负责人,擅长用结构化、易读的方式写技术周报。
写作风格要求:{tone}。

请根据后续用户提供的信息,帮他生成一份适合给老板和团队同时抄送的周报草稿。`,
  ],
  [
    'human',
    `本周信息如下:

公司名称:{company_name}
团队名称:{team_name}
直接汇报对象:{manager_name}
本周时间范围:{week_range}

本周团队核心目标:
{team_goal}

本周开发数据 (git 提交 / jira 任务等):
{dev_activities}

请据此输出一份 Markdown 周报,结构建议包含:
1. 本周概览(2-3 句话)
2. 详细拆分(按项目或模块分段)
3. 关键指标表格(字段示例:模块 / 亮点 / 风险 / 下周计划)

语气专业但有人情味。`,
  ],
]);

const chatMessages = await chatPrompt.formatMessages({
  tone: '专业、清晰、略带鼓励',
  company_name: '星航科技',
  team_name: '智能应用平台组',
  manager_name: '王总',
  week_range: '2025-05-05 ~ 2025-05-11',
  team_goal: '完成内部 AI 助手灰度上线,并确保核心链路稳定。',
  dev_activities:
    '- 小李: 完成 AI 助手工单流转能力,对接客服系统,提交 25 次\n' +
    '- 小张: 接入日志检索和知识库查询,提交 19 次\n' +
    '- 小王: 完善监控、告警与埋点,新增 10 条核心告警规则\n' +
    '- 实习生小陈: 补充使用文档和 FAQ,支持 3 个内部试点团队',
});

console.log('ChatPromptTemplate 生成的消息:');
console.log(chatMessages);

const response = await model.invoke(chatMessages);

console.log('\nAI 生成的周报草稿:');
console.log(response.content);

4-4使用pipelinePromptTemplate 和 ChatPromptTemplat

这套代码的核心做法是:PipelinePromptTemplate 把多个"内容模块"拼装好,再统一塞进一个 ChatPromptTemplate 里交给模型。

  • **普通 PromptTemplate** → 输出一个字符串,没有角色概念
  • **ChatPromptTemplate** → 输出一个消息数组,每条消息带 role

如果你把 finalPrompt 设成普通 PromptTemplate,所有内容会被拍扁成一段纯文本,system 指令和用户输入混在一起,模型对指令的遵循度会明显下降。

使用方式:

js 复制代码
const finalChatPrompt = ChatPromptTemplate.fromMessages([
  ['system', `你是一名资深工程团队负责人...`],
  ['human', `人设与写作风格:\n{persona_block}\n...`],
]);

它让模型先"进入角色",再接收任务,比把所有东西揉成一段 user prompt 效果好得多。

直接用pipeline管理是将所有的信息一股脑都塞进了message里面,现在引入ChatPromptTemplate,就是将告诉大模型,哪些是进 systemmessage 的,哪些是进 humanMessage 的。

在代码里指责图如下:

PipelinePromptTemplate​ 像一个「内容编辑部」------各路记者写好稿件(子 prompt),交到总编手里。

ChatPromptTemplate​ 就是「总编」------他决定哪篇放头版(system)、哪篇放正文(human)、哪篇放附录(assistant),最终排成一份结构完整的报纸交给印刷机(model)
** Pipeline** 管"内容从哪来、怎么拼",ChatPromptTemplate 管"内容怎么组织成消息交给模型"。两者各司其职,Pipeline 在外层、ChatPromptTemplatefinalPrompt,是这个架构最干净、最强大的组合方式。

js 复制代码
import 'dotenv/config';
import { ChatOpenAI } from '@langchain/openai';
import {
  PipelinePromptTemplate,
  PromptTemplate,
  ChatPromptTemplate,
} from '@langchain/core/prompts';
import {
  personaPrompt,
  contextPrompt,
} from './pipeline-prompt-template.mjs';

// 初始化 Chat 模型
const model = new ChatOpenAI({
  modelName: 'qwen-max',
  apiKey: process.env.OPENAI_API_KEY,
  temperature: 0,
  configuration: {
    baseURL: process.env.OPENAI_BASE_URL,
  },
});

// A. 本场景自己的任务说明模块
const weeklyTaskPrompt = PromptTemplate.fromTemplate(
  `以下是本周与你所在团队相关的关键事实与数据(Git / Jira / 运维等):
{dev_activities}

请你基于这些信息,帮我生成一份【技术周报】,重点包含:
1. 本周整体达成情况
2. 关键成果与亮点
3. 主要问题 / 风险
4. 下周的改进方向与优先级建议
`,
);

// B. 本场景自己的格式要求模块
const weeklyFormatPrompt = PromptTemplate.fromTemplate(
  `请用 Markdown 写这份周报,结构建议为:
1. 本周概览(2-3 句话)
2. 详细拆分(按项目或模块分段)
3. 关键指标表格(字段示例:模块 / 亮点 / 风险 / 下周计划)

语气要求:{tone},既专业清晰,又适合发给老板并抄送团队。`,
);

// C. 最终的 ChatPromptTemplate:接收由 Pipeline 拼好的几块内容
const finalChatPrompt = ChatPromptTemplate.fromMessages([
  [
    'system',
    `你是一名资深工程团队负责人,擅长把复杂的技术细节总结成结构化、易读的周报。

下面是一些已经预先整理好的信息块,请你综合理解后,再根据用户补充的信息生成周报。`,
  ],
  [
    'human',
    `人设与写作风格:
{persona_block}

团队与本周背景:
{context_block}

任务与输入数据:
{task_block}

输出格式要求:
{format_block}

现在请基于以上信息,直接输出最终的周报内容。`,
  ],
]);

const weeklyChatPipelinePrompt = new PipelinePromptTemplate({
  pipelinePrompts: [
    { name: 'persona_block', prompt: personaPrompt }, // 复用人设
    { name: 'context_block', prompt: contextPrompt }, // 复用背景
    { name: 'task_block', prompt: weeklyTaskPrompt }, // 本文件自己的任务模块
    { name: 'format_block', prompt: weeklyFormatPrompt }, // 本文件自己的格式模块
  ],
  // 注意:这里的 finalPrompt 是 ChatPromptTemplate,而不是普通 PromptTemplate
  finalPrompt: finalChatPrompt,
  inputVariables: [
    'tone',
    'company_name',
    'team_name',
    'manager_name',
    'week_range',
    'team_goal',
    'dev_activities',
  ],
});

// E. 示例:构造一份消息数组并喂给 Chat 模型
const promptValue = await weeklyChatPipelinePrompt.formatPromptValue({
  tone: '专业、清晰、略带鼓励',
  company_name: '星航科技',
  team_name: 'AI 平台组',
  manager_name: '王总',
  week_range: '2025-05-12 ~ 2025-05-18',
  team_goal: '完成周报自动生成能力的灰度验证,并收集团队反馈。',
  dev_activities:
    `- Git: 本周合并 4 个主要特性分支,包含 Prompt 配置化和日志观测优化\n` +
    `- Jira: 关闭 9 个 Story / 5 个 Bug,新增 2 个 TechDebt 任务\n` +
    `- 运维: 本周线上 P1 事故 0 起,P2 1 起(由配置变更引起,已完成复盘)\n` +
    `- 其他:完成与数据平台、运维平台两次联合评审会议`,
});

console.log('Pipeline + ChatPromptTemplate 生成的消息:');
console.log(promptValue.toChatMessages());

const response = await model.invoke(promptValue.toChatMessages());

console.log(`AI 回答如下:\n`);
console.log(response.content);

// const response = await model.invoke(messages);

4-5 chatpromptTemplate的另一种使用方式

js 复制代码
import 'dotenv/config';
import { ChatOpenAI } from '@langchain/openai';
import {
  ChatPromptTemplate,
  SystemMessagePromptTemplate,
  HumanMessagePromptTemplate,
} from '@langchain/core/prompts';

const model = new ChatOpenAI({
  modelName: process.env.MODEL_NAME,
  apiKey: process.env.OPENAI_API_KEY,
  temperature: 0,
  configuration: {
    baseURL: process.env.OPENAI_BASE_URL,
  },
});

const systemTemplate = SystemMessagePromptTemplate.fromTemplate(
  `你是一名资深工程团队负责人,擅长用结构化、易读的方式写技术周报。
写作风格要求:{tone}。

请根据后续用户提供的信息,帮他生成一份适合给老板和团队同时抄送的周报草稿。`,
);

const humanTemplate = HumanMessagePromptTemplate.fromTemplate(
  `本周信息如下:

公司名称:{company_name}
团队名称:{team_name}
直接汇报对象:{manager_name}
本周时间范围:{week_range}

本周团队核心目标:
{team_goal}

本周开发数据(Git 提交 / Jira 任务等):
{dev_activities}

请据此输出一份 Markdown 周报,结构建议包含:
1. 本周概览(2-3 句话)
2. 详细拆分(按项目或模块分段)
3. 关键指标表格(字段示例:模块 / 亮点 / 风险 / 下周计划)

语气专业但有人情味。`,
);

const composedTemplate = ChatPromptTemplate.fromMessages([
  systemTemplate,
  humanTemplate,
]);

const chatMessages = await composedTemplate.formatMessages({
  tone: '专业、清晰、略带鼓励',
  company_name: '星航科技',
  team_name: '智能应用平台组',
  manager_name: '王总',
  week_range: '2025-05-05 ~ 2025-05-11',
  team_goal: '完成内部 AI 助手灰度上线,并确保核心链路稳定。',
  dev_activities:
    '- 小李:完成 AI 助手工单流转能力,对接客服系统,提交 25 次\n' +
    '- 小张:接入日志检索和知识库查询,提交 19 次\n' +
    '- 小王:完善监控、告警与埋点,新增 10 条核心告警规则\n' +
    '- 实习生小陈:补充使用文档和 FAQ,支持 3 个内部试点团队',
});

console.log('使用 SystemMessagePromptTemplate / HumanMessagePromptTemplate 生成的消息:');
console.log(chatMessages);

const response = await model.invoke(chatMessages).then(console.log);
console.log('使用 ChatOpenAI 生成的结果:');
console.log(response.content);

4.6 messageplaceholder的完整实例

js 复制代码
import 'dotenv/config';
import { ChatOpenAI } from '@langchain/openai';
import {
 
  HumanMessage,
  AIMessage
} from '@langchain/core/messages';
import {
   MessagesPlaceholder,
  ChatPromptTemplate
} from '@langchain/core/prompts';

// 1. 初始化模型
const model = new ChatOpenAI({
  modelName: process.env.MODEL_NAME || 'gpt-3.5-turbo',
  apiKey: process.env.OPENAI_API_KEY,
  temperature: 0.7,
  configuration: {
    baseURL: process.env.OPENAI_BASE_URL,
  },
});

// 2. 定义带 MessagesPlaceholder 的 prompt
const prompt = ChatPromptTemplate.fromMessages([
  ['system', '你是一个{role},请用{style}风格回答。回答时尽量简短。'],
  // 👇 历史对话插槽
  new MessagesPlaceholder('chat_history'),
  // 👇 用户当前输入
  ['human', '{input}'],
]);

// 3. 模拟多轮对话历史(第 3 轮了)
const chatHistory = [
  new HumanMessage('你好,我叫小明'),
  new AIMessage('你好小明!很高兴认识你,有什么我可以帮你的吗?'),
  new HumanMessage('我想学 React,从哪里开始比较好?'),
  new AIMessage('建议先从官方文档的「快速开始」入手,把组件、props、state 三个概念吃透,再学 Hooks。'),
];

// 4. 格式化消息
const messages = await prompt.formatMessages({
  role: '资深前端工程师',
  style: '简洁专业',
  chat_history: chatHistory,
  input: '那 React 18 的并发特性我什么时候该学?',
});

console.log(messages)

// 5. 调用模型
// const response = await model.invoke(messages);

// console.log('--- 模型回复 ---');
// console.log(response.content);

测试结果如下

4-7 FewShotPromptTemplate

js 复制代码
import { FewShotPromptTemplate, PromptTemplate } from '@langchain/core/prompts';
import 'dotenv/config';
import { ChatOpenAI } from '@langchain/openai';

const model = new ChatOpenAI({
  modelName: process.env.MODEL_NAME || 'gpt-3.5-turbo',
  apiKey: process.env.OPENAI_API_KEY,
  temperature: 0.7,
  configuration: {
    baseURL: process.env.OPENAI_BASE_URL,
  },
});

// 1. 定义示例
const examples = [
  {
    input: '高兴',
    output: '喜悦、开心、兴高采烈',
  },
  {
    input: '生气',
    output: '愤怒、恼火、暴跳如雷',
  },
  {
    input: '悲伤',
    output: '难过、心碎、黯然神伤',
  },
];

// 2. 定义每条示例的格式模板
const exampleTemplate = PromptTemplate.fromTemplate(
  `输入:{input}\n输出:{output}`
);

// 3. 组装 FewShotPromptTemplate
const fewShotPrompt = new FewShotPromptTemplate({
  examples,                  // 示例数组
  examplePrompt: exampleTemplate,  // 每条示例怎么渲染
  prefix: '请为下面的词语生成3个近义词,用顿号分隔:',  // 示例前面的说明
  suffix: '输入:{user_input}\n输出:',               // 示例后面的用户问题
  inputVariables: ['user_input'],  // suffix 里用到的变量
});

// 4. 使用
const prompt = await fewShotPrompt.format({
  user_input: '害怕',
});

console.log("prompt:",prompt);
const response = await model.invoke(prompt);
console.log("ai回答:",response.content);

4-8 ExampleSelector

从example里面找到关于温度的部分。

js 复制代码
import 'dotenv/config';
import { OpenAIEmbeddings } from '@langchain/openai';
import { MemoryVectorStore } from '@langchain/classic/vectorstores/memory';
import {
  FewShotPromptTemplate,
  PromptTemplate,
} from '@langchain/core/prompts';
import { SemanticSimilarityExampleSelector } from '@langchain/core/example_selectors';

// 1. 准备示例池
const examples = [
  { input: '0°C', output: '32°F' },
  { input: '10°C', output: '50°F' },
  { input: '20°C', output: '68°F' },
  { input: '30°C', output: '86°F' },
  { input: '40°C', output: '104°F' },
  { input: '高兴', output: '喜悦、开心、兴高采烈' },
  { input: '生气', output: '愤怒、恼火、暴跳如雷' },
];

// 2. 单条示例的渲染模板
const examplePrompt = PromptTemplate.fromTemplate(
  '输入:{input}\n输出:{output}'
);

const embeddings = new OpenAIEmbeddings({
  model: process.env.EMBEDDINGS_MODEL_NAME,
  apiKey: process.env.OPENAI_API_KEY,
  configuration: {
    baseURL: process.env.OPENAI_API_BASE_URL,
  }
});


const texts = examples.map(e => e.input);

// 2. 先创建好 vectorStore 实例(这里用 MemoryVectorStore 举例)
const vectorStore = await MemoryVectorStore.fromTexts(texts, examples, embeddings);

// 3. 截图里的写法:直接传实例和 k
const exampleSelector = new SemanticSimilarityExampleSelector({
  vectorStore, 
  k: 2,
});


// 4. 组装 FewShotPromptTemplate
const fewShotPrompt = new FewShotPromptTemplate({
  exampleSelector,
  examplePrompt,
  prefix: '请参考下面的示例,回答用户的问题:',
  suffix: '输入:{input}\n输出:',
  inputVariables: ['input'],
});

// 5. 格式化并打印
const formatted = await fewShotPrompt.format({ input: '25°C' });
console.log('--- 动态生成的 Prompt ---');
console.log(formatted);

使用SemanticSimilarityExampleSelector的时候需要用到向量数据库,我用的是内存存储MemoryVectorStore,你也可以引入milvus

4.9使用FewShotChatMessagePromptTemplate

js 复制代码
import 'dotenv/config';
import { FewShotChatMessagePromptTemplate } from '@langchain/core/prompts';
import { ChatPromptTemplate, PromptTemplate } from '@langchain/core/prompts';
import { SemanticSimilarityExampleSelector } from '@langchain/core/example_selectors';
import { MemoryVectorStore } from '@langchain/classic/vectorstores/memory';
import { OpenAIEmbeddings } from '@langchain/openai';

// 1. 示例池
const examples = [
  { input: '0°C', output: '32°F' },
  { input: '10°C', output: '50°F' },
  { input: '20°C', output: '68°F' },
  { input: '高兴', output: '喜悦、开心、兴高采烈' },
];

// 2. 单条示例的渲染模板(聊天消息格式)
const examplePrompt = ChatPromptTemplate.fromMessages([
  ['human', '{input}'],
  ['ai', '{output}'],
]);

const embeddings = new OpenAIEmbeddings({
  model: process.env.EMBEDDINGS_MODEL_NAME,
  apiKey: process.env.OPENAI_API_KEY,
  configuration: {
    baseURL: process.env.OPENAI_API_BASE_URL,
  }
});

const texts = examples.map(e => e.input);
const vectorStore = await MemoryVectorStore.fromTexts(texts, examples, embeddings);

const exampleSelector = new SemanticSimilarityExampleSelector({
  vectorStore, 
  k: 2,
});

// 3. 👇 重点修复:显式加上 inputVariables
const fewShotPrompt = new FewShotChatMessagePromptTemplate({
  exampleSelector,
  examplePrompt,
  inputVariables: ['input'], 
});

// 4. 最终拼成完整的聊天提示
const finalPrompt = ChatPromptTemplate.fromMessages([
  ['system', '你是一个助手,请参考示例回答问题:'],
  fewShotPrompt,
  ['human', '{input}'],
]);

// 5. 格式化并打印
const messages = await finalPrompt.formatMessages({ input: '25°C' });
console.log('--- 动态生成的消息列表 ---');
console.log(messages);

对比下exampleselect和FewShotChatMessagePromptTemplate的返回值

从结果来看FewShotChatMessagePromptTemplate返回了对象数组,帮我们区分了是谁的message。其他都是返回的是字符串。

八.问题解答

为什么在mjs文件里面能够直接使用await而没有报错,比如下面这个文件

ES Module 里,await 可以直接写在模块的最顶层 ,不需要包在 async 函数里。这是 ES2022 正式引入的特性,叫 Top-level await
Node.js 执行这个模块时,遇到顶层 await暂停这个模块的执行,等 Promise resolve 后再继续往下走,同时不会阻塞其他模块加载


那为什么在commonjs里面如果没有async包裹,直接使用await就会报错,但是在ESModule里面没有报错?

原因很简单就是ESModule支持这么写,是他的语言特性。commonjs不支持而已。

不是没有 async,而是 ES Module 的顶层 await 不需要 async ​ 这是语言特性,Node.js 从 14.8+ 开始支持,LangChain 的文档和示例大量使用这种写法来让 demo 代码更简洁。

相关推荐
muddjsv2 小时前
前端性能优化实战:从加载到渲染的全面提速指南
前端·性能优化
deli0070073 小时前
JSON 树形查看器:粘贴即解析,折叠展开一目了然
前端·数据库·json·ai编程
guanguan0_03 小时前
PageProxy:页面维度接口地图 + 一键场景切换
前端·ai编程·请求代理·proxy工具
liangshanbo12153 小时前
虚拟列表深度面试题整理
java·开发语言·前端
IT_陈寒4 小时前
Redis内存警告竟是因为这个不起眼的配置项
前端·人工智能·后端
lilian2334 小时前
Harmony os 技术实战|拼豆制图43:压缩字符矩阵上线前如何拦住错位图纸
开发语言·前端·华为·矩阵·harmonyos
kyriewen4 小时前
我踩了3次同一个坑才明白:JavaScript里比0.1+0.2更隐蔽的5个数字陷阱
前端·javascript·面试
徐小夕4 小时前
表格、文档、甘特、大屏、表单一站打通:pxcharts超级表格4.0正式上线!
前端·算法·github
用户594404103565 小时前
Vue3 + TypeScript + Leaflet.js 实战:构建企业级地理信息应用
前端