微信扫码
添加专属顾问
LangChain开发必看!一文讲透OpenAI与ChatOpenAI接口的核心区别与适用场景。 核心内容: 1. completions与chat completions接口的功能差异解析 2. Base Model与Instruct Model的底层对应关系 3. 实际开发中的最佳实践与版本演进趋势
今天来聊一个非常具体的技术问题。
对于工程师来说,当我们使用LangChain来连接一个LLM推理服务时,多多少少会碰到一个疑问:到底应该调用OpenAI还是ChatOpenAI?我发现,每次解释这个问题时,都会费很多唇舌,所以干脆写下来供更多人参考。这背后其实涉及到两个关键问题:
completions 和 chat completions 两个接口的区别。
LLM推理时用到的chat template。
通过LangChain来调用LLM的时候,通常会引用下面这两个类:
from langchain_openai import OpenAI
from langchain_openai import ChatOpenAI
从这两个类的名字就不难猜出,它们是用来调用OpenAI提供的LLM接口的。具体来说,是这两个接口:
OpenAI用来调用 /v1/completions 接口。
ChatOpenAI用来调用 /v1/chat/completions 接口。
不过呢,由于OpenAI的影响力实在太大,很多其他闭源和开源的LLM,在提供推理服务的API时,也都不约而同地遵循了OpenAI的接口形式。这两个接口成了事实性的标准。
这两个接口的区别是什么呢?
/v1/completions 接口提供的是「续写」能力,也就是最基础的predict next token的能力。你提供一段prompt,它返回一段续写的文本。接口的输入和输出,都是文本。
/v1/chat/completions 接口提供的是对话能力。接口的输入是一个message list,输出是一个message。
一般来说,上一节提到的这两个接口,分别对应两类LLM模型:
Base Model: 仅经过预训练的基础模型,所以也称为Pretrained Model。它只能对输入的prompt进行续写。这一类模型在推理时只能提供 /v1/completions 接口。
Instruct Model: 在预训练之后经过进一步指令微调过的模型。只有这一类模型在推理时才能提供 /v1/chat/completions 接口。
以Llama 3模型系列为例:
在以上这个表格中,以“-Instruct”结尾命名的模型,就属于Instruct Model;反之就是Base Model。
OpenAI在早期推出API服务的时候,/v1/completions 和 /v1/chat/completions 这两个接口是都提供的。但随着时间的推移和技术的迭代,大部分AI应用场景都能用指令对话的形式来支持,所以后来OpenAI也就不再为最新的模型提供 /v1/completions 接口了。现在如果访问OpenAI关于 /v1/completions 接口的API reference文档页面[1],你会发现这个接口已经被标记为“Legacy”了。
结合前一节所讨论的,我们现在容易得出结论,如果我们想调用OpenAI的GPT模型,那么应该选择使用LangChain的ChatOpenAI这个类。
但是,如果我们使用开源推理框架(如vLLM[2])来为了开源模型在本地架设推理服务,那么通常来说,这个推理服务可能会同时支持/v1/completions 和 /v1/chat/completions 这两个接口。当我们使用LangChain进行调用的时候:
如果加载的是一个Base Model,那么只有 /v1/completions 接口可用,/v1/chat/completions 接口是不可用的(或者说,调用它没有意义)。我们只能使用LangChain的OpenAI这个类进行调用。
如果加载的是一个Instruct Model,那么理论上来说,我们应该调用 /v1/chat/completions 接口进行推理。也就是使用LangChain的ChatOpenAI这个类来进行调用。但是,由于对话消息在经过格式化之后,最终也是表达成一个文本串的,所以其实 /v1/completions 也是可用的,这时候就可以调用LangChain的OpenAI这个类。这个过程我们后面的章节再仔细展开。
根据前面的分析,我们知道了,调用 /v1/chat/completions 接口,我们需要使用LangChain的ChatOpenAI这个类,并且传入一个message list。下面是一段示例代码:
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
llm = ChatOpenAI(
openai_api_key="EMPTY",
openai_api_base="http://127.0.0.1:8000/v1",
model_name="llama3.2-1B-instruct"
)
prompt = ChatPromptTemplate.from_messages([
("system", "Your are a helpful assistant."),
("user", "Hello, how are you?"),
("assistant", "I'm doing well, thank you for asking."),
("user", "Can you tell me a joke?")
]
)
chain = prompt | llm
reponse = chain.invoke({})
在这段代码中,我们看到,传入给LLM的是一个有结构的对话历史列表。但是,不管是Base Model还是Instruct Model,模型最终接受的输入,应该是一段free text(再转成token)。那么问题来了,这个有结构的对话历史列表,是如何转成free text的呢?显然,这里需要一个模板(template),这就是所谓的chat template[3]。
对于前面示例代码中的 llama3.2-1B-instruct 模型,它所对应的chat template是下面这个样子的:
这是一个遵循Jinja格式的模版[4]。模板表达了各种message(包括system message,user message,assistant message以及其它类型的message)的渲染方式。
基于这个chat template,前面示例代码中的对话历史内容,最终输入到LLM时会转化成如下的free text(也就是prompt):
<|begin_of_text|><|start_header_id|>system<|end_header_id|>
Cutting Knowledge Date: December 2023
Today Date: 28 Dec 2024
Your are a helpful assistant.<|eot_id|><|start_header_id|>user<|end_header_id|>
Hello, how are you?<|eot_id|><|start_header_id|>assistant<|end_header_id|>
I'm doing well, thank you for asking.<|eot_id|><|start_header_id|>user<|end_header_id|>
Can you tell me a joke?<|eot_id|><|start_header_id|>assistant<|end_header_id|>
那么,这个chat template是从哪里来的呢?对于vLLM来说,它启动的时候,有两种方式可以获取到chat template:
一种方式是从模型文件夹中加载。具体地说,chat template的内容存在于tokenizer_config.json文件中。
另一种方式是vLLM通过启动参数--chat-template来指定一个chat template模板文件。
我们顺便看一个tokenizer_config.json文件的具体例子。还是以前面示例代码中调用的 llama3.2-1B-instruct 模型为例,它的chat template模板内容就存在tokenizer_config.json文件中的chat_template字段中,如下:
这里多说一句:我们需要注意的是,tokenizer_config.json文件中并不一定包含chat_template字段。具体有没有这个字段,取决于模型文件的创建过程。对于Llama 3模型来说,我们从Meta官方[5]申请并下载到模型文件之后,一般情况下,需要使用Hugging Face的Transformers框架中提供的一个工具[6],将模型转换成hf的通用格式。这样,vLLM以及其它开源生态中的框架或工具才能方便地加载它。
以 llama3.2-1B-instruct 模型为例,这个模型格式的转换过程,需要执行以下命令来调用Transformers的这个工具:
python src/transformers/models/llama/convert_llama_weights_to_hf.py --input_dir <llama3.2-1B-instruct model source folder> --model_size 1B --llama_version 3.2 --output_dir <llama3.2-1B-instruct model output folder> --instruct
在以上命令中,如果带着--instruct参数,那么转换成的模型配置文件tokenizer_config.json中就包含chat_template字段;否则就不包含chat_template字段。
注意,以上命令执行之前,需要先执行huggingface-cli login命令登录Hugging Face,并确保在"meta-llama/Llama-3.2-1B-Instruct"的Hugging Face模型主页上提交了访问申请并获批,只有这样这个命令才能执行成功。
由上一节可知,假如tokenizer_config.json文件中没有包含chat_template字段,并且vLLM在启动时也没有指定--chat-template,那么,vLLM会以未指定chat template模板的方式启动起来。
这个时候,如果还是像本文前面的代码那样调用LangChain的ChatOpenAI,就会出现意想不到的结果。一定要注意!具体会得到怎样的结果,取决于你使用的vLLM运行环境中Transformers的版本:
如果Transformers的版本小于4.44,vLLM会自动使用一个默认的chat template。这时候从调用结果上很可能看不出什么大问题,但实际上模型回答的准确度已经大打折扣,这个错误非常不易察觉。
如果Transformers的版本大于等于4.44,vLLM会抛一个异常,如下:
openai.BadRequestError: Error code: 400 - {'object': 'error', 'message': 'As of transformers v4.44, default chat template is no longer allowed, so you must provide a chat template if the tokenizer does not define one.', 'type': 'BadRequestError', 'param': None, 'code': 400}
显然,高版本的Transformers和vLLM对于这个情况的处理,更合理一些。通过明显的报错避免了不易察觉的错误。
如前所述,由于对话消息在经过格式化之后,最终也是表达成一个文本串的,所以也可以调用LangChain的OpenAI这个类来完成。这时候其实背后是在调用 /v1/completions 这个接口。相当于client端在调用OpenAI之前,先把prompt按照需要的对话格式拼好。下面的代码,可以实现跟前面调用ChatOpenAI的代码同样的效果:
from langchain_openai import OpenAI
from langchain_core.prompts import PromptTemplate
from datetime import datetime
llm = OpenAI(
openai_api_key="EMPTY",
openai_api_base="http://127.0.0.1:8000/v1",
model_name="llama3.2-1B-instruct"
)
prompt_text = """<|begin_of_text|><|start_header_id|>system<|end_header_id|>
Cutting Knowledge Date: December 2023
Today Date: {today_date}
Your are a helpful assistant.<|eot_id|><|start_header_id|>user<|end_header_id|>
Hello, how are you?<|eot_id|><|start_header_id|>assistant<|end_header_id|>
I'm doing well, thank you for asking.<|eot_id|><|start_header_id|>user<|end_header_id|>
Can you tell me a joke?<|eot_id|><|start_header_id|>assistant<|end_header_id|>
"""
prompt = PromptTemplate.from_template(prompt_text)
chain = prompt | llm
reponse = chain.invoke({"today_date":datetime.now().strftime('%d %b %Y')})
现在我们总结一下本文开头提出的问题:
对于Base Model的推理服务,只能使用LangChain的OpenAI这个类来调用。
对于Instruct Model的推理服务:
如果vLLM启动时加载到了正确的chat template(或从模型目录中或从启动参数中),那么:
推荐使用LangChain的ChatOpenAI这个类来调用。这是最推荐的一种方式。
也可以使用LangChain的OpenAI这个类来调用。但要求在调用之前先把prompt按照所需的对话格式拼好(chat template实际上没有用到)。
如果vLLM启动时没有加载到正确的chat template,那么就只能使用LangChain的OpenAI这个类来调用(要求在调用之前先把prompt按照所需的对话格式拼好)。
(正文完)
53AI,企业落地大模型首选服务商
产品:场景落地咨询+大模型应用平台+行业解决方案
承诺:免费POC验证,效果达标后再合作。零风险落地应用大模型,已交付160+中大型企业
2026-08-28
一切皆插件之后,Agent 工程的新范式
2026-08-19
做了十年 java 开发,我是怎么转到 AI 智能体的
2026-07-19
正本清源:企业 AI 不是建在 Harness 上,而是用 Harness 承载业务流程
2026-07-17
OpenWiki Brains 与 wiki memory 模式:智能体记忆从反应式推到主动式
2026-07-05
AI Agent 慢在哪?Node.js 探针把模型、工具和服务链路一次串起来
2026-07-05
拆解LangChain刚开源的OpenWiki:如何落地个人Wiki知识库
2026-07-01
LangGraph Runtime 是什么?一文讲清Runtime与Context的作用与用法!
2026-06-26
拆解Agent Harness的11大核心组件与工程实践(附下载)
2026-07-05
2026-07-17
2026-07-01
2026-06-26
2026-07-19
2026-07-05
2026-08-19
2026-08-28
2026-03-26
2025-11-03
2025-10-29
2025-07-14
2025-07-13
2025-07-05
2025-06-26
2025-06-13
欢迎您使用【53AI 官方网站】(以下简称“本网站”或“我们”)。本《会员服务协议》(以下简称“本协议”)是您(以下简称“会员”或“用户”)与【深圳市博思协创网络科技有限公司】之间关于注册、登录及使用本网站会员服务所订立的法律协议。
在您注册或登录前,请务必审慎阅读、充分理解各条款内容,特别是免除或限制责任的条款、知识产权条款、争议解决条款等。此类条款将以加粗形式提示您注意。 当您通过微信公众号授权、手机验证码验证或其他方式成功登录本网站时,即视为您已完全理解并同意接受本协议的全部内容。
一、 定义
本网站:指由【深圳市博思协创网络科技有限公司】运营的,域名为【53ai.com】的网站及相关移动端页面。
会员服务:指本网站向注册会员提供的知识库文章查阅、内容检索及其他相关增值服务。
知识库内容:指本网站发布的包括但不限于文字、图表、数据、研究报告、行业分析等数字化内容资源。
二、 账号注册与登录
登录方式:本网站支持以下登录方式,您可根据实际情况选择:
微信公众号授权登录:您同意将您的微信OpenID信息授权给本网站,用于创建或关联会员账号。
手机验证码登录:您需提供真实有效的手机号码,并通过短信验证码完成身份验证与登录/注册。
账号安全:您的账号仅限您本人使用,禁止赠与、借用、租用、转让或售卖。因您保管不善导致的账号被盗、密码泄露等损失,由您自行承担。
实名认证:根据相关法律法规要求,我们可能要求您在特定功能下完成实名认证。如您拒绝提供,可能无法使用部分或全部服务。
未成年人保护:若您未满18周岁,请在法定监护人的陪同下阅读本协议,并在征得监护人同意后使用本服务。
三、 服务内容与规范
知识库查阅权限:会员登录后,有权按照其会员等级对应的权限范围,在线浏览、检索本网站知识库中的相关文章及内容。
服务变更:我们有权根据业务发展需要,调整、变更或终止部分服务内容,并将以网站公告、公众号消息等方式提前通知。
禁止行为:您在使用服务时不得实施以下行为:
利用技术手段批量爬取、下载、转存知识库内容;
将知识库内容用于商业目的或未经授权地向第三方传播;
干扰本网站正常运行或侵犯其他用户合法权益;
发布违法违规信息或从事违反公序良俗的活动。
四、 知识产权声明
权利归属:本网站知识库中的排版设计、软件代码等内容的知识产权均归【公司全称】或原权利人所有,受《中华人民共和国著作权法》等法律保护。
有限许可:本网站授予会员一项非独占、不可转让、不可转授权的普通许可,仅限于个人学习、研究之目的在线查阅知识库内容。
侵权追责:未经书面许可,任何单位或个人不得以任何形式复制、转载、摘编、镜像、汇编或以其他方式使用上述内容。一经发现,我们保留追究其法律责任的权利。
五、 个人信息保护
我们重视对您个人信息的保护。关于我们如何收集、使用、存储和保护您的个人信息,请单独阅读 《隐私政策》。
您通过微信公众号授权或手机号验证所提供的信息,我们将严格按照《个人信息保护法》的规定处理,仅用于身份识别、服务提供及安全验证等必要用途。
您可以随时通过网站设置或联系客服行使查阅、更正、删除个人信息及撤回授权同意的权利。
六、 免责声明
内容准确性:知识库内容仅供参考,不构成专业建议。我们不对其完整性、准确性、时效性作任何明示或暗示的保证,您应自行判断并承担使用风险。
不可抗力:因自然灾害、政策法规变化、网络故障、第三方平台接口异常(如微信接口维护、运营商短信通道故障)等不可抗力导致的服务中断或延迟,我们不承担违约责任。
第三方链接:本网站可能包含指向第三方网站的链接,该等网站的内容和服务不受我们控制,请您自行甄别风险。
七、 违约责任
如您违反本协议约定,我们有权视情节采取警告、限制功能、暂停服务、注销账号等措施,并保留要求赔偿损失的权利。
如因您的违约行为导致我们遭受行政处罚、第三方索赔或商誉损失,您应承担全部赔偿责任(包括但不限于罚款、赔偿金、律师费、公证费等)。
八、 法律适用与争议解决
本协议的订立、执行和解释均适用中华人民共和国大陆地区法律。
因本协议产生的或与本协议有关的任何争议,双方应友好协商解决;协商不成的,任何一方均可向【公司所在地】有管辖权的人民法院提起诉讼。
九、 其他
本协议构成双方就本服务达成的完整协议,取代此前任何口头或书面约定。
本协议任一条款被认定为无效或不可执行的,不影响其他条款的效力。
我们对本协议享有最终解释权,并在法律允许的范围内保留随时修改的权利。修改后的协议一经公布即生效,继续使用服务即视为同意修订内容。