LangChain 怎么改自定义 base_url:Python、JS 写法、环境变量优先级与 404 排查

2026-10-11 46 0

在 LangChain 里换成自定义 base_url,只需要改模型对象的初始化参数,链、Agent 和 Prompt 都不用动:

  • Python(langchain-openai):给 ChatOpenAI、OpenAI 或 OpenAIEmbeddings 传 base_url="https://你的端点/v1"
  • JS / TS(@langchain/openai):写在 configuration: { baseURL: "https://你的端点/v1" } 里

这里的地址要以 /v1 结尾,不要写到 /chat/completions。大部分接入问题出在这个地址上,或者出在环境变量相互覆盖上。下面按写法、优先级、地址格式、流式统计和协议边界依次说明。

Python:直接传 base_url

安装 langchain-openai 后,最清楚的写法是在构造时把地址和 Key 一起传进去:

import os
from langchain_openai import ChatOpenAI

llm = ChatOpenAI(
    model="模型ID",                       # 用端点方提供的模型 ID
    base_url="https://api.nexaix.net/v1",
    api_key=os.environ["NEXAIX_API_KEY"],
)

print(llm.invoke("用一句话回答:1+1 等于几?").content)

base_url 和旧参数名 openai_api_base 是同一个东西。老项目里写的是 openai_api_base=... 也能用,没必要为了这次迁移专门改名。如果你的 langchain-openai 版本比较旧,构造参数的命名可能和这里有出入,以你所用版本的参考文档为准。

Embedding 的写法相同:

from langchain_openai import OpenAIEmbeddings

emb = OpenAIEmbeddings(
    model="embedding模型ID",
    base_url="https://api.nexaix.net/v1",
    api_key=os.environ["NEXAIX_API_KEY"],
)

前提是这个端点确实提供你要的 embedding 模型。对话模型和向量模型往往要分别确认,地址填对了不代表两类模型都有。

如果你用的是通用初始化函数 init_chat_model,base_url 同样作为关键字参数传入:

from langchain.chat_models import init_chat_model

llm = init_chat_model(
    "模型ID",
    model_provider="openai",
    base_url="https://api.nexaix.net/v1",
    api_key=os.environ["NEXAIX_API_KEY"],
)

model_provider="openai" 的意思是按 OpenAI 协议去调用,跟模型由哪家提供无关。接任何 OpenAI 兼容端点都这样写。

以 NexAIX 为例

接 NexAIX 时,地址固定填 https://api.nexaix.net/v1,Key 用控制台生成的那一把,model 填模型页上标明的模型 ID。其余代码保持不变。模型清单会调整,每个模型属于开源权重自有算力部署还是闭源官方授权渠道,也在模型页上写明,开始写代码前先去 模型清单 核对一下要用的模型 ID。还没有 Key 的话,在官网导航「获取 API Key」注册,注册会送测试额度,可以先跑通上面那段最小示例。

不想改代码:用环境变量,但要清楚优先级

不在代码里写死地址,也可以靠环境变量切换。LangChain 确定 base_url 时按下面的顺序查找,前面的一旦有值,后面的就不再看:

  1. 代码里显式传入的 base_url(或 openai_api_base)
  2. 环境变量 OPENAI_API_BASE,由 LangChain 初始化时读取
  3. 环境变量 OPENAI_BASE_URL,由底层 openai 官方 SDK 读取
export OPENAI_API_KEY="你的Key"
export OPENAI_BASE_URL="https://api.nexaix.net/v1"

这个顺序会造成一个常见情况:你设置了 OPENAI_BASE_URL,请求却还是发到别的地址。原因通常是机器上、.env 文件里或 CI 配置里还留着一个 OPENAI_API_BASE,它的优先级更高,把你新设的值盖掉了。排查时把两个变量都打印出来看:

import os
print(os.getenv("OPENAI_API_BASE"), os.getenv("OPENAI_BASE_URL"))

两种方式各有适用场景:

  • 显式传参:适合生产代码,读代码就能知道请求发到哪里,不受部署环境里残留变量的影响。
  • 环境变量:适合同一份代码在开发、测试、生产环境之间切换不同端点。

建议选定一种,不要同时用。环境变量里的 OPENAI_API_KEY 还要跟着地址一起换。用自定义地址配官方 Key,或者反过来,都会返回 401。Key 在不同环境里怎么存放和分发,可以参考 AI API Key 怎么拿、怎么存、怎么分。

base_url 必须带 /v1,但不能写到 /chat/completions

OpenAI SDK 和 LangChain 会自动在 base_url 后面拼接 /chat/completions、/embeddings 等子路径。所以只需要填到版本前缀为止:

base_url 与 SDK 自动拼接子路径的关系,以及漏写 /v1 或多写路径导致 404 的对照

你填的 base_url实际请求的地址结果
https://api.nexaix.net/v1.../v1/chat/completions正确
https://api.nexaix.net.../chat/completions404
https://api.nexaix.net/v1/chat/completions.../v1/chat/completions/chat/completions404

遇到 404,先把 SDK 实际请求的完整地址拼出来对照一下,大多数情况一眼就能看出问题。末尾多一个斜杠一般不会出错,但统一写成不带斜杠的形式更省心。Dify、One API 这类工具对 /v1 的处理规则和这里不完全相同,不要直接照搬,可以参考 Dify 添加 OpenAI 兼容模型 里的说明。

JS / TS:地址放在 configuration 里

@langchain/openai 的地址不在顶层参数里,而是作为底层 client 的配置项传入,写在 configuration.baseURL:

import { ChatOpenAI } from "@langchain/openai";

const llm = new ChatOpenAI({
  model: "模型ID",
  apiKey: process.env.NEXAIX_API_KEY,
  configuration: {
    baseURL: "https://api.nexaix.net/v1",
  },
});

const res = await llm.invoke("用一句话回答:1+1 等于几?");
console.log(res.content);

有两处容易写错:参数名是 baseURL,URL 三个字母都是大写,不是 Python 那样的 base_url;它必须放在 configuration 对象里面。如果写错位置,请求会悄悄发回默认地址,看到的报错通常是 Key 无效。如果你还会在 Node 里直接用 openai SDK,可以对照 Node.js 调用 AI API。

改完地址后,流式输出的 token 用量变成空的

这是 LangChain 的默认行为,不是端点出了问题。很多非官方端点在流式返回中不带 token usage,所以 LangChain 发现你用的是自定义地址时(例如读取到了 OPENAI_BASE_URL),会默认关闭流式用量统计 stream_usage。

如果你接的服务支持在流式响应里返回用量,需要手动打开:

llm = ChatOpenAI(
    model="模型ID",
    base_url="https://api.nexaix.net/v1",
    api_key=os.environ["NEXAIX_API_KEY"],
    stream_options={"include_usage": True},
)

这个参数在不同版本里的写法可能略有差别,以你所用版本的文档为准。如果打开后用量仍然为空,说明端点本身没有在流式响应里返回 usage。这种情况下要统计成本,可以改用非流式调用拿用量,或者到服务方控制台查看按 Key 统计的用量。

ChatOpenAI 只处理 OpenAI 标准协议里的字段

ChatOpenAI 按 OpenAI 官方接口协议解析响应。第三方模型额外返回的非标准字段,比如部分思考模型的 reasoning_content,不会被自动提取出来。表现为请求成功、正文也有,但思考内容读不到。

只需要最终回答的话,不用处理这个问题。如果业务确实要用思维链字段,就要换用该模型厂商对应的 LangChain 集成包,或者自己写一层适配去解析原始响应。地址改得再对,ChatOpenAI 也不会帮你解析这些字段。

改完之后按这个顺序验证

  1. 跑最小示例:用上面的 invoke 发一句短问题,能拿到回答就说明地址、Key、模型 ID 三项都对了。
  2. 404:检查 /v1 有没有漏掉、有没有多写 /chat/completions;如果用的是环境变量,确认没有残留的 OPENAI_API_BASE。
  3. 401:检查 Key 和地址是不是同一家的;JS 里检查 baseURL 是否放在 configuration 里。
  4. 模型不存在:model 要和服务方提供的模型 ID 完全一致,大小写和连字符都要对上。
  5. 流式没有用量、思考内容缺失:分别对照前面两节。

这几步之外的错误码,比如 429 限流和 5xx,原因和处理方式可以查 AI API 错误码怎么看。最小示例跑通以后,把同一个 llm 对象传给原来的链或 Agent 就行,其余代码都不需要改。

相关文章

GPT API 模型下线潮怎么破:从旧版迁移、合规避坑到 GPT-5.6 与 gpt-oss 混合调用
开源权重模型 API 和官方授权渠道有什么区别:精度、上下文、留存与限流怎么看
怎么验证 AI API 有没有记录对话内容:能查什么、查不到什么、怎么防
模型推理精度 BF16 和 FP8 有什么区别:显存、速度、质量与选型
LangChain 怎么改自定义 base_url:Python、JS 写法、环境变量优先级与 404 排查
One API 怎么添加 OpenAI 兼容渠道:代理地址、密钥、模型名与测试报错排查

评论(0)

暂无评论

发布评论