OpenAI 是一家人工智能 (AI) 研究实验室。 本指南将帮助你快速上手 OpenAI 的聊天模型。有关 ChatOpenAI 所有功能和配置的详细文档,请参阅 API 参考
Chat Completions API 兼容性ChatOpenAI 完全兼容 OpenAI 的(旧版)Chat Completions API。如果你想连接到其他支持 Chat Completions API 的模型提供商,也可以这样做 - 请参阅说明
托管在 Azure 上的 OpenAI 模型请注意,某些 OpenAI 模型也可以通过 Microsoft Azure 平台 访问。

概述

集成详情

可序列化Python 支持下载量版本
ChatOpenAI@langchain/openaiNPM - 下载量NPM - 版本

模型特性

请参阅下表标题中的链接,了解如何使用特定功能的指南。

设置

要访问 OpenAI 聊天模型,你需要创建一个 OpenAI 账户,获取一个 API 密钥,并安装 @langchain/openai 集成包。

凭据

前往 OpenAI 的网站 注册 OpenAI 并生成 API 密钥。完成此操作后,设置 OPENAI_API_KEY 环境变量:
export OPENAI_API_KEY="your-api-key"
如果你想对模型调用进行自动追踪,也可以通过取消注释以下变量来设置你的 LangSmith API 密钥:
# export LANGSMITH_TRACING="true"
# export LANGSMITH_API_KEY="your-api-key"

安装

LangChain 的 ChatOpenAI 集成位于 @langchain/openai 包中:
npm install @langchain/openai @langchain/core

实例化

现在我们可以实例化模型对象并生成聊天补全:
import { ChatOpenAI } from "@langchain/openai"

const llm = new ChatOpenAI({
  model: "gpt-5.4",
  temperature: 0,
  // 其他参数...
})

调用

const aiMsg = await llm.invoke([
  {
    role: "system",
    content: "你是一个乐于助人的助手,可以将英语翻译成法语。请翻译用户的句子。",
  },
  {
    role: "user",
    content: "我喜欢编程。"
  },
])
aiMsg
AIMessage {
  "id": "chatcmpl-ADItECqSPuuEuBHHPjeCkh9wIO1H5",
  "content": "J'adore la programmation.",
  "additional_kwargs": {},
  "response_metadata": {
    "tokenUsage": {
      "completionTokens": 5,
      "promptTokens": 31,
      "totalTokens": 36
    },
    "finish_reason": "stop",
    "system_fingerprint": "fp_5796ac6771"
  },
  "tool_calls": [],
  "invalid_tool_calls": [],
  "usage_metadata": {
    "input_tokens": 31,
    "output_tokens": 5,
    "total_tokens": 36
  }
}
console.log(aiMsg.content)
J'adore la programmation.

自定义 URL

你可以通过传递 configuration 参数来自定义 SDK 发送请求的基础 URL,如下所示:
import { ChatOpenAI } from "@langchain/openai";

const llmWithCustomURL = new ChatOpenAI({
  model: "gpt-5.4",
  temperature: 0.9,
  configuration: {
    baseURL: "https://your_custom_url.com",
  },
});

await llmWithCustomURL.invoke("你好!");
configuration 字段也接受官方 SDK 支持的其他 ClientOptions 参数。 如果你在 Azure OpenAI 上托管,请参阅专用页面

自定义请求头

你可以在同一个 configuration 字段中指定自定义请求头:
import { ChatOpenAI } from "@langchain/openai";

const llmWithCustomHeaders = new ChatOpenAI({
  model: "gpt-5.4",
  temperature: 0.9,
  configuration: {
    defaultHeaders: {
      "Authorization": `Bearer SOME_CUSTOM_VALUE`,
    },
  },
});

await llmWithCustomHeaders.invoke("你好!");

禁用流式传输用量元数据

某些代理或第三方提供商的 API 接口与 OpenAI 大体相同,但不支持最近新增的用于返回流式用量的 stream_options 参数。你可以通过禁用流式用量来使用 ChatOpenAI 访问这些提供商:
import { ChatOpenAI } from "@langchain/openai";

const llmWithoutStreamUsage = new ChatOpenAI({
  model: "gpt-5.4",
  temperature: 0.9,
  streamUsage: false,
  configuration: {
    baseURL: "https://proxy.com",
  },
});

await llmWithoutStreamUsage.invoke("你好!");

调用微调模型

你可以通过传入相应的 modelName 参数来调用微调过的 OpenAI 模型。 这通常采用 ft:{OPENAI_MODEL_NAME}:{ORG_NAME}::{MODEL_ID} 的形式。例如:
import { ChatOpenAI } from "@langchain/openai";

const fineTunedLlm = new ChatOpenAI({
  temperature: 0.9,
  model: "ft:gpt-3.5-turbo-0613:{ORG_NAME}::{MODEL_ID}",
});

await fineTunedLlm.invoke("你好!");

生成元数据

如果你需要额外的信息,例如对数概率(logprobs)或令牌用量,这些信息将在 invoke 响应的消息 response_metadata 字段中直接返回。
需要 @langchain/core 版本 >=0.1.48。
import { ChatOpenAI } from "@langchain/openai";

// 详情请见 https://cookbook.openai.com/examples/using_logprobs
const llmWithLogprobs = new ChatOpenAI({
  model: "gpt-5.4",
  logprobs: true,
  // topLogprobs: 5,
});

const responseMessageWithLogprobs = await llmWithLogprobs.invoke("你好!");
console.dir(responseMessageWithLogprobs.response_metadata.logprobs, { depth: null });
{
  content: [
    {
      token: 'Hello',
      logprob: -0.0004740447,
      bytes: [ 72, 101, 108, 108, 111 ],
      top_logprobs: []
    },
    {
      token: '!',
      logprob: -0.00004334534,
      bytes: [ 33 ],
      top_logprobs: []
    },
    {
      token: ' How',
      logprob: -0.000030113732,
      bytes: [ 32, 72, 111, 119 ],
      top_logprobs: []
    },
    {
      token: ' can',
      logprob: -0.0004797665,
      bytes: [ 32, 99, 97, 110 ],
      top_logprobs: []
    },
    {
      token: ' I',
      logprob: -7.89631e-7,
      bytes: [ 32, 73 ],
      top_logprobs: []
    },
    {
      token: ' assist',
      logprob: -0.114006,
      bytes: [
         32,  97, 115,
        115, 105, 115,
        116
      ],
      top_logprobs: []
    },
    {
      token: ' you',
      logprob: -4.3202e-7,
      bytes: [ 32, 121, 111, 117 ],
      top_logprobs: []
    },
    {
      token: ' today',
      logprob: -0.00004501419,
      bytes: [ 32, 116, 111, 100, 97, 121 ],
      top_logprobs: []
    },
    {
      token: '?',
      logprob: -0.000010206721,
      bytes: [ 63 ],
      top_logprobs: []
    }
  ],
  refusal: null
}

自定义工具

自定义工具支持具有任意字符串输入的工具。当你预期字符串参数较长或复杂时,它们尤其有用。 如果你使用的是支持自定义工具的模型,则可以使用 ChatOpenAI 类和 customTool 函数来创建自定义工具。
import { ChatOpenAI, customTool } from "@langchain/openai";
import { createAgent, HumanMessage } from "langchain";

const codeTool = customTool(
  async () => {
    // ... 添加执行输入的代码
    return "代码执行成功";
  },
  {
    name: "execute_code",
    description: "执行代码片段",
    format: { type: "text" },
  }
);

const model = new ChatOpenAI({ model: "gpt-5.4" });

const agent = createAgent({
  model,
  tools: [codeTool],
});

const result = await agent.invoke({
  messages: [new HumanMessage("使用工具执行代码")],
});
console.log(result);

strict: true

自 2024 年 8 月 6 日起,OpenAI 支持在调用工具时使用 strict 参数,这将强制模型遵守工具参数的模式。了解更多
需要 @langchain/openai >= 0.2.6
如果设置为 strict: true,工具定义也将被验证,并且只接受 JSON 模式的一个子集。至关重要的是,模式不能有可选参数(那些带有默认值的参数)。请阅读完整文档了解支持哪些类型的模式。
这是一个调用工具的示例。将额外的 strict: true 参数传递给 .bindTools 会将该参数传递给所有工具定义:
import { ChatOpenAI } from "@langchain/openai";
import { tool } from "@langchain/core/tools";
import * as z from "zod";

const weatherTool = tool((_) => "no-op", {
  name: "get_current_weather",
  description: "获取当前天气",
  schema: z.object({
    location: z.string(),
  }),
})

const llmWithStrictTrue = new ChatOpenAI({
  model: "gpt-5.4",
}).bindTools([weatherTool], {
  strict: true,
  tool_choice: weatherTool.name,
});

// 尽管问题与天气无关,但由于我们传递了 `tool_choice` 和 `strict: true`,它将调用该工具并传递正确的参数。
const strictTrueResult = await llmWithStrictTrue.invoke("127862 乘以 12898 除以 2 是多少?");

console.dir(strictTrueResult.tool_calls, { depth: null });
[
  {
    name: 'get_current_weather',
    args: { location: 'current' },
    type: 'tool_call',
    id: 'call_hVFyYNRwc6CoTgr9AQFQVjm9'
  }
]
如果你只想将此参数应用于选定的工具,也可以直接传入 OpenAI 格式的工具模式:
import { zodToJsonSchema } from "zod-to-json-schema";

const toolSchema = {
  type: "function",
  function: {
    name: "get_current_weather",
    description: "获取当前天气",
    strict: true,
    parameters: zodToJsonSchema(
      z.object({
        location: z.string(),
      })
    ),
  },
};

const llmWithStrictTrueTools = new ChatOpenAI({
  model: "gpt-5.4",
}).bindTools([toolSchema], {
  strict: true,
});

const weatherToolResult = await llmWithStrictTrueTools.invoke([{
  role: "user",
  content: "伦敦现在的天气怎么样?"
}])

weatherToolResult.tool_calls;
[
  {
    name: 'get_current_weather',
    args: { location: 'London' },
    type: 'tool_call',
    id: 'call_EOSejtax8aYtqpchY8n8O82l'
  }
]

结构化输出

我们也可以将 strict: true 传递给 .withStructuredOutput()。这是一个例子:
import { ChatOpenAI } from "@langchain/openai";

const traitSchema = z.object({
  traits: z.array(z.string()).describe("输入中包含的特征列表"),
});

const structuredLlm = new ChatOpenAI({
  model: "gpt-5.4-mini",
}).withStructuredOutput(traitSchema, {
  name: "extract_traits",
  strict: true,
});

await structuredLlm.invoke([{
  role: "user",
  content: `我身高 6'5",喜欢水果。`
}]);
{ traits: [ `6'5" tall`, 'love fruit' ] }

Responses API

兼容性以下要点适用于 @langchain/openai>=0.4.5-rc.0
OpenAI 支持一个面向构建智能体应用的 Responses API。它包含一套内置工具,包括网络和文件搜索。它还支持对话状态的管理,允许你在不显式传入先前消息的情况下继续对话线程。 如果使用了这些功能之一,ChatOpenAI 将自动路由到 Responses API。你也可以在实例化 ChatOpenAI 时指定 useResponsesApi: true

内置工具

ChatOpenAI 配置内置工具将使其响应基于外部信息,例如文件或网络中的上下文。模型生成的 AIMessage 将包含有关内置工具调用的信息。

网络搜索

要触发网络搜索,请像使用其他工具一样,将 {"type": "web_search_preview"} 传递给模型。
你也可以将内置工具作为调用参数传递:
llm.invoke("...", { tools: [{ type: "web_search_preview" }] });
import { ChatOpenAI } from "@langchain/openai";

const llm = new ChatOpenAI({ model: "gpt-5.4-mini" }).bindTools([
  { type: "web_search_preview" },
]);

await llm.invoke("今天有什么正面的新闻故事?");

请注意,响应包含结构化的内容块,其中既包含响应文本,也包含引用其来源的 OpenAI 注释。输出消息还将包含来自任何工具调用的信息。

文件搜索

要触发文件搜索,请像使用其他工具一样,将文件搜索工具传递给模型。你需要填充一个 OpenAI 管理的向量存储,并在工具定义中包含向量存储 ID。更多详情请参见 OpenAI 文档
import { ChatOpenAI } from "@langchain/openai";

const llm = new ChatOpenAI({ model: "gpt-5.4-mini" }).bindTools([
  { type: "file_search", vector_store_ids: ["vs..."] },
]);

await llm.invoke("OpenAI 的深度研究靠不靠谱?");

网络搜索一样,响应将包含带引用的内容块,以及来自内置工具调用的信息。

计算机使用

ChatOpenAI 支持 computer-use-preview 模型,这是一个专为内置计算机使用工具设计的特殊模型。要启用,请像传递其他工具一样传递计算机使用工具 目前,计算机使用的工具输出存在于 AIMessage.additional_kwargs.tool_outputs 中。要回复计算机使用工具调用,你需要在创建相应的 ToolMessage 时设置 additional_kwargs.type: "computer_call_output" 更多详情请参见 OpenAI 文档
import { AIMessage, ToolMessage } from "@langchain/core/messages";
import { ChatOpenAI } from "@langchain/openai";
import * as fs from "node:fs/promises";

const findComputerCall = (message: AIMessage) => {
  const toolOutputs = message.additional_kwargs.tool_outputs as
    | { type: "computer_call"; call_id: string; action: { type: string } }[]
    | undefined;

  return toolOutputs?.find((toolOutput) => toolOutput.type === "computer_call");
};

const llm = new ChatOpenAI({ model: "computer-use-preview" })
  .bindTools([
    {
      type: "computer-preview",
      display_width: 1024,
      display_height: 768,
      environment: "browser",
    },
  ])
  .bind({ truncation: "auto" });

let message = await llm.invoke("在 bing.com 上查看最新的 OpenAI 新闻。");
const computerCall = findComputerCall(message);

if (computerCall) {
  // 对计算机调用操作作出发应
  const screenshot = await fs.readFile("./screenshot.png", {
    encoding: "base64",
  });

  message = await llm.invoke(
    [
      new ToolMessage({
        additional_kwargs: { type: "computer_call_output" },
        tool_call_id: computerCall.call_id,
        content: [
          {
            type: "computer_screenshot",
            image_url: `data:image/png;base64,${screenshot}`,
          },
        ],
      }),
    ],
    { previous_response_id: message.response_metadata["id"] }
  );
}

代码解释器

ChatOpenAI 允许你使用内置的代码解释器工具来支持沙盒化的代码生成和执行。
import { ChatOpenAI } from "@langchain/openai";

const llm = new ChatOpenAI({
  model: "o4-mini",
  useResponsesApi: true,
});

const llmWithTools = llm.bindToools([
  {
    type: "code_interpreter",
    // 创建一个新的容器
    container: { type: "auto" }
  },
]);

const response = await llmWithTools.invoke(
  "编写并运行代码以回答问题:3^3 是多少?"
);
请注意,上述命令创建了一个新的容器。我们可以通过指定现有的容器 ID 来跨调用重用容器。
const tool_outputs: Record<string, any>[] = response.additional_kwargs.tool_outputs
const container_id = tool_outputs[0].container_id

const llmWithTools = llm.bindTools([
  {
    type: "code_interpreter",
    // 重用上一次调用的容器
    container: container_id,
  },
]);

远程 MCP

ChatOpenAI 支持内置的远程 MCP 工具,允许模型发起的对 MCP 服务器的调用发生在 OpenAI 服务器上。
import { ChatOpenAI } from "@langchain/openai";

const llm = new ChatOpenAI({
    model: "o4-mini",
    useResponsesApi: true,
});

const llmWithMcp = llm.bindTools([
    {
        type: "mcp",
        server_label: "deepwiki",
        server_url: "https://mcp.deepwiki.com/mcp",
        require_approval: "never"
    }
]);

const response = await llmWithMcp.invoke(
    "2025-03-26 版本的 MCP 规范 (modelcontextprotocol/modelcontextprotocol) 支持哪些传输协议?"
);
MCP 审批在收到指令时,OpenAI 将在对远程 MCP 服务器进行调用之前请求批准。在上面的命令中,我们指示模型永远不需要批准。我们还可以将模型配置为始终请求批准,或者始终为特定工具请求批准:
...
const llmWithMcp = llm.bindTools([
  {
    type: "mcp",
    server_label: "deepwiki",
    server_url: "https://mcp.deepwiki.com/mcp",
    require_approval: {
      always: {
        tool_names: ["read_wiki_structure"],
      },
    },
  },
]);
const response = await llmWithMcp.invoke(
    "2025-03-26 版本的 MCP 规范 (modelcontextprotocol/modelcontextprotocol) 支持哪些传输协议?"
);
使用此配置,响应可能包含类型为 mcp_approval_request 的工具输出。要为审批请求提交批准,你可以在后续消息中将其构建为内容块:
const approvals = [];
if (Array.isArray(response.additional_kwargs.tool_outputs)) {
  for (const content of response.additional_kwargs.tool_outputs) {
    if (content.type === "mcp_approval_request") {
      approvals.push({
        type: "mcp_approval_response",
        approval_request_id: content.id,
        approve: true,
      });
    }
  }
}

const nextResponse = await model.invoke(
  [
    response,
    new HumanMessage({ content: approvals }),
  ],
);

图像生成

ChatOpenAI 允许你通过 responses API 使用内置的图像生成工具在多轮对话中创建图像。
import { ChatOpenAI } from "@langchain/openai";

const llm = new ChatOpenAI({
  model: "gpt-5.4",
  useResponsesApi: true,
});

const llmWithImageGeneration = llm.bindTools([
  {
    type: "image_generation",
    quality: "low",
  }
]);

const response = await llmWithImageGeneration.invoke(
  "用绿色字体画一个随机的短词。"
)

推理模型

兼容性:以下要点适用于 @langchain/openai>=0.4.0
当使用像 o1 这样的推理模型时,withStructuredOutput 的默认方法是 OpenAI 内置的结构化输出方法(相当于将 method: "jsonSchema" 作为选项传入 withStructuredOutput)。JSON 模式的使用方式大多与其他模型相同,但有一个重要的注意事项:在定义模式时,z.optional() 不会被遵循,你应该改用 z.nullable() 这是一个例子:
import * as z from "zod";
import { ChatOpenAI } from "@langchain/openai";

// 不会按预期工作
const reasoningModelSchemaOptional = z.object({
  color: z.optional(z.string()).describe("输入中提到的颜色"),
});

const reasoningModelOptionalSchema = new ChatOpenAI({
  model: "o1",
}).withStructuredOutput(reasoningModelSchemaOptional, {
  name: "extract_color",
});

await reasoningModelOptionalSchema.invoke([{
  role: "user",
  content: `我身高 6'5",喜欢水果。`
}]);
{ color: 'No color mentioned' }
这是一个使用 z.nullable() 的例子:
import * as z from "zod";
import { ChatOpenAI } from "@langchain/openai";

// 这个会按预期工作
const reasoningModelSchemaNullable = z.object({
  color: z.nullable(z.string()).describe("输入中提到的颜色"),
});

const reasoningModelNullableSchema = new ChatOpenAI({
  model: "o1",
}).withStructuredOutput(reasoningModelSchemaNullable, {
  name: "extract_color",
});

await reasoningModelNullableSchema.invoke([{
  role: "user",
  content: `我身高 6'5",喜欢水果。`
}]);
{ color: null }

提示词缓存

如果你的输入超过一定大小(撰写本文时为 1024 个令牌),较新的 OpenAI 模型将自动缓存你的部分提示词,以降低需要长上下文的用例的成本。 注意: 给定查询缓存的令牌数量尚未在 AIMessage.usage_metadata 中标准化,而是包含在 AIMessage.response_metadata 字段中。 这是一个例子:
// @lc-docs-hide-cell

const CACHED_TEXT = `## 组件

LangChain 为构建 LLM 有用的各种组件提供了标准、可扩展的接口和外部集成。
有些组件由 LangChain 实现,有些组件我们依赖第三方集成,还有其他一些是混合的。

### 聊天模型

<span data-heading-keywords="chat model,chat models"></span>

语言模型,它们使用一系列消息作为输入,并返回聊天消息作为输出(与使用纯文本相对)。
这些通常是较新的模型(较旧的模型通常是 \`LLMs\`,见下文)。
聊天模型支持为对话消息分配不同的角色,有助于区分来自 AI、用户和指令(例如系统消息)的消息。

尽管底层模型是“消息进,消息出”,LangChain 包装器也允许这些模型将字符串作为输入。
这使它们拥有与 LLM 相同的接口(并且更易于使用)。
当字符串作为输入传入时,它将在传递给底层模型之前,在底层转换为一个 \`HumanMessage\`

LangChain 不托管任何聊天模型,我们依赖第三方集成。

在构建 ChatModels 时,我们有一些标准化的参数:

- \`model\`: 模型名称

Chat Models 也接受特定于该集成的其他参数。

<Warning>
**一些聊天模型已经针对**工具调用**进行了微调,并为此提供了专用的 API。**

通常,此类模型在工具调用方面比非微调模型更擅长,并且推荐用于需要工具调用的用例。
请参阅[工具调用部分](/oss/javascript/langchain/tools)以获取更多信息。
</Warning>

有关如何使用聊天模型的详细信息,请参阅[相关的操作指南](/oss/javascript/langchain/models)。

#### 多模态

一些聊天模型是多模态的,可以接受图像、音频甚至视频作为输入。
这些仍然不太常见,这意味着模型提供商尚未就定义 API 的“最佳”方式达成标准化。
多模态输出更加不常见。因此,我们将多模态抽象保持得相当轻量级,
并计划随着该领域的成熟,进一步巩固多模态 API 和交互模式。

在 LangChain 中,大多数支持多模态输入的聊天模型也接受 OpenAI 内容块格式的值。
到目前为止,这仅限于图像输入。对于像 Gemini 这样支持视频和其他字节输入的模型,API 也支持原生的、模型特定的表示形式。

有关如何使用多模态模型的详细信息,请参阅[相关的操作指南](/oss/javascript/how-to/#multimodal)。

### LLMs

<span data-heading-keywords="llm,llms"></span>

<Warning>
**纯文本输入/文本输出的 LLM 往往是较旧或较低级的。许多流行的模型最好作为[聊天补全模型](/oss/javascript/langchain/models)使用,**

即使对于非聊天用例也是如此。

你可能正在寻找[上面的部分](/oss/javascript/langchain/models)。
</Warning>

语言模型,它们接受字符串作为输入并返回字符串。
这些通常是较旧的模型(较新的模型通常是[聊天模型](/oss/javascript/langchain/models),见上文)。

尽管底层模型是“字符串进,字符串出”,LangChain 包装器也允许这些模型将消息作为输入。
这使它们拥有与[聊天模型](/oss/javascript/langchain/models)相同的接口。
当消息作为输入传入时,它们将在传递给底层模型之前,在底层被格式化为一个字符串。

LangChain 不托管任何 LLMs,我们依赖第三方集成。

有关如何使用 LLMs 的详细信息,请参阅[相关的操作指南](/oss/javascript/langchain/models)。

### 消息类型

一些语言模型将消息数组作为输入并返回一条消息。
有几种不同类型的消息。
所有消息都具有 \`role\`\`content\`\`response_metadata\` 属性。

\`role\` 描述了谁在说这条消息。
LangChain 为不同的角色提供了不同的消息类。

\`content\` 属性描述了消息的内容。
它可以是几种不同的事物:

- 一个字符串(大多数模型处理这种类型的内容)
- 一个对象列表(这用于多模态输入,其中对象包含有关该输入类型和该输入位置的信息)

#### HumanMessage

这代表来自用户的消息。

#### AIMessage

这代表来自模型的消息。除了 \`content\` 属性外,这些消息还具有:

**\`response_metadata\`**

\`response_metadata\` 属性包含有关响应的额外元数据。这里的数据通常是特定于每个模型提供商的。
这是可能存储对数概率和令牌用量等信息的地方。

**\`tool_calls\`**

这代表语言模型调用工具的决定。它们作为 \`AIMessage\` 输出的一部分包含在内。
可以通过 \`.tool_calls\` 属性从那里访问它们。

此属性返回一个 \`ToolCall\` 列表。一个 \`ToolCall\` 是具有以下参数的对象:

- \`name\`: 应调用的工具的名称。
- \`args\`: 传递给该工具的参数。
- \`id\`: 该工具调用的 ID。

#### SystemMessage

这代表系统消息,告诉模型如何行动。并非每个模型提供商都支持此功能。

#### ToolMessage

这代表工具调用的结果。除了 \`role\`\`content\` 外,此消息还具有:

- 一个 \`tool_call_id\` 字段,它传达了为生成此结果而对工具进行的调用的 ID。
- 一个 \`artifact\` 字段,可用于传递工具执行的任意工件,这些工件对于跟踪有用但不应发送给模型。

#### (旧版)FunctionMessage

这是一个旧版的消息类型,对应于 OpenAI 的旧版函数调用 API。应改用 \`ToolMessage\` 来对应更新的工具调用 API。

这代表函数调用的结果。除了 \`role\`\`content\` 外,此消息还具有一个 \`name\` 参数,传达了为生成此结果而被调用的函数的名称。

### 提示模板

<span data-heading-keywords="prompt,prompttemplate,chatprompttemplate"></span>

提示模板有助于将用户输入和参数转换为对语言模型的指令。
这可以用来指导模型的响应,帮助它理解上下文并生成相关且连贯的基于语言的输出。

提示模板将一个对象作为输入,其中每个键代表提示模板中要填充的变量。

提示模板输出一个 PromptValue。这个 PromptValue 可以传递给 LLM 或 ChatModel,也可以转换为字符串或消息数组。
这个 PromptValue 存在的原因是便于在字符串和消息之间切换。

有几种不同类型的提示模板:

#### 字符串提示模板

这些提示模板用于格式化单个字符串,通常用于较简单的输入。
例如,构建和使用 PromptTemplate 的常见方法如下:

\`\`\`typescript
import { PromptTemplate } from "@langchain/core/prompts";

const promptTemplate = PromptTemplate.fromTemplate(
  "给我讲一个关于 {topic} 的笑话"
);

await promptTemplate.invoke({ topic: "猫" });
\`\`\`

#### 聊天提示模板

这些提示模板用于格式化消息数组。这些“模板”本身由模板数组组成。
例如,构建和使用 ChatPromptTemplate 的常见方法如下:

\`\`\`typescript
import { ChatPromptTemplate } from "@langchain/core/prompts";

const promptTemplate = ChatPromptTemplate.fromMessages([
  ["system", "你是一个乐于助人的助手"],
  ["user", "给我讲一个关于 {topic} 的笑话"],
]);

await promptTemplate.invoke({ topic: "猫" });
\`\`\`

在上面的例子中,这个 ChatPromptTemplate 在调用时将构建两条消息。
第一个是系统消息,没有要格式化的变量。
第二个是 HumanMessage,并将由用户传入的 \`topic\` 变量进行格式化。

#### MessagesPlaceholder

<span data-heading-keywords="messagesplaceholder"></span>

这个提示模板负责在特定位置添加一个消息数组。
在上面的 ChatPromptTemplate 中,我们看到了如何格式化两条消息,每条都是一个字符串。
但是,如果我们希望用户传入一个消息数组,将其插入到特定位置呢?
这就是你使用 MessagesPlaceholder 的方式。

\`\`\`typescript
import {
  ChatPromptTemplate,
  MessagesPlaceholder,
} from "@langchain/core/prompts";
import { HumanMessage } from "@langchain/core/messages";

const promptTemplate = ChatPromptTemplate.fromMessages([
  ["system", "你是一个乐于助人的助手"],
  new MessagesPlaceholder("msgs"),
]);

promptTemplate.invoke({ msgs: [new HumanMessage({ content: "你好!" })] });
\`\`\`

这将生成一个包含两条消息的数组,第一个是系统消息,第二个是我们传入的 HumanMessage。
如果我们传入了 5 条消息,那么它总共将生成 6 条消息(系统消息加上传入的 5 条)。
这对于让消息数组插入到特定位置很有用。

在不显式使用 \`MessagesPlaceholder\` 类的情况下实现相同效果的另一种方法是:

\`\`\`typescript
const promptTemplate = ChatPromptTemplate.fromMessages([
  ["system", "你是一个乐于助人的助手"],
  ["placeholder", "{msgs}"], // <-- 这是更改的部分
]);
\`\`\`

有关如何使用提示模板的详细信息,请参阅[相关的操作指南](/oss/javascript/how-to/#prompt-templates)。

### 示例选择器

实现更好性能的一种常见提示技术是在提示中包含示例。
这为语言模型提供了它应该如何行动的具体例子。
有时这些例子是硬编码到提示中的,但对于更高级的情况,动态选择它们可能更好。
示例选择器是负责选择示例然后将其格式化为提示的类。

有关如何使用示例选择器的详细信息,请参阅[相关的操作指南](/oss/javascript/how-to/#example-selectors)。

### 输出解析器

<span data-heading-keywords="output parser"></span>

<Note>
**这里的信息指的是从模型获取文本输出并尝试将其解析为更结构化表示的解析器。**

越来越多的模型支持函数(或工具)调用,这会自动处理此问题。
建议使用函数/工具调用而不是输出解析。
请参阅 [LangChain 工具文档](/oss/javascript/langchain/tools)。

</Note>

负责获取模型的输出并将其转换为更适合下游任务的格式。
当你使用 LLMs 生成结构化数据,或标准化来自聊天模型和 LLMs 的输出时非常有用。

输出解析器必须实现两个主要方法:

- “获取格式指令”:一个方法,返回一个字符串,其中包含有关语言模型的输出应如何格式化的指令。
- “解析”:一个方法,接受一个字符串(假定为语言模型的响应)并将其解析为某种结构。

还有一个可选的方法:

- “使用提示解析”:一个方法,接受一个字符串(假定为语言模型的响应)和一个提示(假定为生成此类响应的提示)并将其解析为某种结构。提供提示主要是为了在 OutputParser 想要以某种方式重试或修复输出时,需要提示中的信息来做到这一点。

输出解析器接受字符串或 \`BaseMessage\` 作为输入,并且可以返回任意类型。

LangChain 有许多不同类型的输出解析器。以下是 LangChain 支持的输出解析器列表。下表包含各种信息:

**名称**:输出解析器的名称

**支持流式传输**:输出解析器是否支持流式传输。

**输入类型**:预期的输入类型。大多数输出解析器同时适用于字符串和消息,但有些(如 OpenAI Functions)需要带有特定参数的消息。

**输出类型**:解析器返回对象的输出类型。

**描述**:我们对该输出解析器以及何时使用它的评论。

当前日期是 ${new Date().toISOString()}`;

// 无操作语句以隐藏输出
void 0;
import { ChatOpenAI } from "@langchain/openai";

const modelWithCaching = new ChatOpenAI({
  model: "gpt-5.4-mini",
});

// CACHED_TEXT 是一个长于 1024 个令牌的字符串
const LONG_TEXT = `你是一名海盗。始终用海盗的口吻回应。

在回答问题时使用以下内容作为上下文:

${CACHED_TEXT}`;

const longMessages = [
  {
    role: "system",
    content: LONG_TEXT,
  },
  {
    role: "user",
    content: "LangChain 支持哪些类型的消息?",
  },
];

const originalRes = await modelWithCaching.invoke(longMessages);

console.log("用量:", originalRes.response_metadata.usage);
用量: {
  prompt_tokens: 2624,
  completion_tokens: 263,
  total_tokens: 2887,
  prompt_tokens_details: { cached_tokens: 0 },
  completion_tokens_details: { reasoning_tokens: 0 }
}
const resWitCaching = await modelWithCaching.invoke(longMessages);

console.log("用量:", resWitCaching.response_metadata.usage);
用量: {
  prompt_tokens: 2624,
  completion_tokens: 272,
  total_tokens: 2896,
  prompt_tokens_details: { cached_tokens: 2432 },
  completion_tokens_details: { reasoning_tokens: 0 }
}

预测输出

某些 OpenAI 模型(例如其 gpt-4ogpt-4o-mini 系列)支持预测输出,允许你提前传入 LLM 预期输出的已知部分以减少延迟。这对于编辑文本或代码等情况非常有用,其中只有一小部分模型的输出会更改。 这是一个例子:
import { ChatOpenAI } from "@langchain/openai";

const modelWithPredictions = new ChatOpenAI({
  model: "gpt-5.4-mini",
});

const codeSample = `
/// <summary>
/// 表示一个用户,包含名字、姓氏和用户名。
/// </summary>
public class User
{
/// <summary>
/// 获取或设置用户的名字。
/// </summary>
public string FirstName { get; set; }

/// <summary>
/// 获取或设置用户的姓氏。
/// </summary>
public string LastName { get; set; }

/// <summary>
/// 获取或设置用户的用户名。
/// </summary>
public string Username { get; set; }
}
`;

// 也可以提前使用 `model.bind({ prediction: {...} })` 进行绑定;
await modelWithPredictions.invoke(
  [
    {
      role: "user",
      content:
        "将 Username 属性替换为 Email 属性。只回复代码,不要使用 Markdown 格式。",
    },
    {
      role: "user",
      content: codeSample,
    },
  ],
  {
    prediction: {
      type: "content",
      content: codeSample,
    },
  }
);
AIMessage {
  "id": "chatcmpl-AQLyQKnazr7lEV7ejLTo1UqhzHDBl",
  "content": "/// <summary>\n/// 表示一个用户,包含名字、姓氏和电子邮件。\n/// </summary>\npublic class User\n{\n/// <summary>\n/// 获取或设置用户的名字。\n/// </summary>\npublic string FirstName { get; set; }\n\n/// <summary>\n/// 获取或设置用户的姓氏。\n/// </summary>\npublic string LastName { get; set; }\n\n/// <summary>\n/// 获取或设置用户的电子邮件。\n/// </summary>\npublic string Email { get; set; }\n}",
  "additional_kwargs": {},
  "response_metadata": {
    "tokenUsage": {
      "promptTokens": 148,
      "completionTokens": 217,
      "totalTokens": 365
    },
    "finish_reason": "stop",
    "usage": {
      "prompt_tokens": 148,
      "completion_tokens": 217,
      "total_tokens": 365,
      "prompt_tokens_details": {
        "cached_tokens": 0
      },
      "completion_tokens_details": {
        "reasoning_tokens": 0,
        "accepted_prediction_tokens": 36,
        "rejected_prediction_tokens": 116
      }
    },
    "system_fingerprint": "fp_0ba0d124f1"
  },
  "tool_calls": [],
  "invalid_tool_calls": [],
  "usage_metadata": {
    "output_tokens": 217,
    "input_tokens": 148,
    "total_tokens": 365,
    "input_token_details": {
      "cache_read": 0
    },
    "output_token_details": {
      "reasoning": 0
    }
  }
}
请注意,目前预测会作为额外的令牌计费,会增加你的使用量和成本,以换取更低的延迟。

音频输出

某些 OpenAI 模型(例如 gpt-4o-audio-preview)支持生成音频输出。此示例展示了如何使用该功能:
import { ChatOpenAI } from "@langchain/openai";

const modelWithAudioOutput = new ChatOpenAI({
  model: "gpt-4o-audio-preview",
  // 你也可以将这些字段作为调用参数传递给 `.bind`。
  modalities: ["text", "audio"], // 指定模型应输出音频。
  audio: {
    voice: "alloy",
    format: "wav",
  },
});

const audioOutputResult = await modelWithAudioOutput.invoke("给我讲一个关于猫的笑话。");
const castAudioContent = audioOutputResult.additional_kwargs.audio as Record<string, any>;

console.log({
  ...castAudioContent,
  data: castAudioContent.data.slice(0, 100) // 为简洁起见进行了切片
})
{
  id: 'audio_67129e9466f48190be70372922464162',
  data: 'UklGRgZ4BABXQVZFZm10IBAAAAABAAEAwF0AAIC7AAACABAATElTVBoAAABJTkZPSVNGVA4AAABMYXZmNTguMjkuMTAwAGRhdGHA',
  expires_at: 1729277092,
  transcript: "猫为什么会坐在电脑键盘上?因为它想盯着老鼠(鼠标)!"
}
我们看到音频数据在 data 字段中返回。我们还会得到一个 expires_at 日期字段。这个字段表示音频响应在服务器上不再可访问的日期,在此期间内可用于多轮对话。

流式传输音频输出

OpenAI 也支持流式传输音频输出。这是一个例子:
import { AIMessageChunk } from "@langchain/core/messages";
import { concat } from "@langchain/core/utils/stream"
import { ChatOpenAI } from "@langchain/openai";

const modelWithStreamingAudioOutput = new ChatOpenAI({
  model: "gpt-4o-audio-preview",
  modalities: ["text", "audio"],
  audio: {
    voice: "alloy",
    format: "pcm16", // 流式传输时格式必须是 `pcm16`
  },
});

const audioOutputStream = await modelWithStreamingAudioOutput.stream("给我讲一个关于猫的笑话。");
let finalAudioOutputMsg: AIMessageChunk | undefined;
for await (const chunk of audioOutputStream) {
  finalAudioOutputMsg = finalAudioOutputMsg ? concat(finalAudioOutputMsg, chunk) : chunk;
}
const castStreamedAudioContent = finalAudioOutputMsg?.additional_kwargs.audio as Record<string, any>;

console.log({
  ...castStreamedAudioContent,
  data: castStreamedAudioContent.data.slice(0, 100) // 为简洁起见进行了切片
})
{
  id: 'audio_67129e976ce081908103ba4947399a3eaudio_67129e976ce081908103ba4947399a3e',
  transcript: '猫为什么会坐在电脑上?因为它想盯着老鼠(鼠标)!',
  index: 0,
  data: 'CgAGAAIADAAAAA0AAwAJAAcACQAJAAQABQABAAgABQAPAAAACAADAAUAAwD8/wUA+f8MAPv/CAD7/wUA///8/wUA/f8DAPj/AgD6',
  expires_at: 1729277096
}

音频输入

这些模型也支持将音频作为输入传递。为此,你必须如下所示指定 input_audio 字段:
import { HumanMessage } from "@langchain/core/messages";

const userInput = new HumanMessage({
  content: [{
    type: "input_audio",
    input_audio: {
      data: castAudioContent.data, // 重用第一个例子中的 base64 数据
      format: "wav",
    },
  }]
})

// 重用相同的模型实例
const userInputAudioRes = await modelWithAudioOutput.invoke([userInput]);

console.log((userInputAudioRes.additional_kwargs.audio as Record<string, any>).transcript);
这真是个很棒的笑话!想象猫为什么会做那些有趣的事情总是很有趣。用“盯着老鼠(鼠标)”来形容真是有创意又双关!

API 参考

有关所有 ChatOpenAI 功能和配置的详细文档,请参阅 API 参考