NLLM Nucleus LLM

LangChain / LlamaIndex 接入多个大模型 —— 一份代码跑通 Claude、GPT、Gemini

用过 LangChain 的人都踩过这个坑:

from langchain_anthropic import ChatAnthropic
from langchain_openai import ChatOpenAI
from langchain_google_genai import ChatGoogleGenerativeAI

三个 provider 包,三份 pip 依赖,三份 API Key,三份限流和错误码的坑,升级一次 LangChain 大概率有一个 provider 包会跟不上。你的 requirements.txt 越来越大, 真正的业务代码反而只占几行。

这篇文章给你一个更简单的做法:只用 langchain-openai,通过统一 OpenAI 兼容 网关调用 Claude、GPT、Gemini。全文代码都能直接复制运行。

为什么只装一个 provider 包就够了

LangChain 的 ChatOpenAI 默认连的是 api.openai.com,但它支持把 base_url 改到任意兼容 OpenAI 协议的服务。这是 LangChain 早就支持的特性,只是很多人 没注意到。

我们需要的只是一个兼容 OpenAI 协议、背后能调用 Claude/GPT/Gemini 的网关。 nucleus-llm 就是这样一个网关 —— 部署在新加坡,接受人民币付款,协议完全兼容 OpenAI /v1/chat/completions

最终的依赖只剩一行:

langchain-openai

没了。不再需要 langchain-anthropiclangchain-google-genai,不再需要各家的 原生 SDK。

最小可运行示例

环境

pip install "langchain-openai>=0.1.0" "langchain-core>=0.3.0"
export NLLM_API_KEY="sk-proxy-你的key"

调用 Claude(通过 LangChain)

import os
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage

llm = ChatOpenAI(
    model="claude-sonnet-4-6",
    base_url="https://llm.nucleusenterprise.ai/v1",
    api_key=os.environ["NLLM_API_KEY"],
)

reply = llm.invoke([HumanMessage(content="用一句话介绍你自己,并告诉我你是哪个模型")])
print(reply.content)

注意三点:

  1. import 的是 ChatOpenAI,但运行的是 Claude。这是因为 nucleus-llm 把 OpenAI 请求格式转成了 Anthropic 的原生 Messages API,再把响应转回来。
  2. 所有 LangChain 的链式操作(|with_structured_outputbind_tools)都 仍然可用,因为它们只依赖 ChatOpenAI 的接口。
  3. 切换到 GPT 或 Gemini,只改 model 一个字段。

一个工厂函数,动态切换模型

实际项目里你很可能想根据任务类型动态选模型。比如:分类用 Haiku,代码生成用 Codex,长文总结用 Gemini Pro。下面是一个极简的工厂:

import os
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage

BASE_URL = "https://llm.nucleusenterprise.ai/v1"
API_KEY = os.environ["NLLM_API_KEY"]

def make_llm(model: str, **kwargs) -> ChatOpenAI:
    return ChatOpenAI(
        model=model,
        base_url=BASE_URL,
        api_key=API_KEY,
        **kwargs,
    )

# 按任务类型选模型
llms = {
    "classify":  make_llm("claude-haiku-4-5",  temperature=0),
    "codegen":   make_llm("gpt-5.3-codex",     temperature=0.2),
    "longtext":  make_llm("gemini-3.1-pro",    temperature=0.7),
    "reasoning": make_llm("claude-opus-4-6",   temperature=0.0),
}

def route(task: str) -> ChatOpenAI:
    # 你的路由逻辑,这里只是示例
    if "代码" in task or "code" in task.lower():
        return llms["codegen"]
    if len(task) > 4000:
        return llms["longtext"]
    if "分类" in task:
        return llms["classify"]
    return llms["reasoning"]

tasks = [
    "把这段代码重构成 async:...",
    "帮我分类以下用户反馈是 bug 还是功能请求:...",
    "总结这篇 20000 字的论文的核心观点:..." + " 论文内容 " * 500,
]

for t in tasks:
    llm = route(t)
    print(f"[{llm.model_name}] {llm.invoke([HumanMessage(content=t[:100])]).content[:80]}")

同样的代码,如果用各家原生 SDK 写,至少要多写 100 行样板。

流式输出

LangChain 的 .stream() 方法在 nucleus-llm 上同样工作:

llm = ChatOpenAI(
    model="claude-sonnet-4-6",
    base_url="https://llm.nucleusenterprise.ai/v1",
    api_key=os.environ["NLLM_API_KEY"],
)

for chunk in llm.stream([HumanMessage(content="写一首关于新加坡的五言绝句")]):
    print(chunk.content, end="", flush=True)
print()

Tool Calling / Function Calling

OpenAI 格式的 tool calling 在 nucleus-llm 上对 Claude 和 Gemini 同样生效 —— 网关 会把 OpenAI 的 tools 字段翻译成各家原生的工具调用格式。

from langchain_openai import ChatOpenAI
from langchain_core.tools import tool

@tool
def get_weather(city: str) -> str:
    """Get the current weather for a city."""
    return f"{city} is sunny, 28°C"

llm = ChatOpenAI(
    model="claude-sonnet-4-6",
    base_url="https://llm.nucleusenterprise.ai/v1",
    api_key=os.environ["NLLM_API_KEY"],
).bind_tools([get_weather])

reply = llm.invoke("新加坡今天天气怎么样?")
print(reply.tool_calls)

LlamaIndex 同样适用

LlamaIndex 有 OpenAILike 专门为兼容网关设计:

from llama_index.llms.openai_like import OpenAILike

llm = OpenAILike(
    model="claude-sonnet-4-6",
    api_base="https://llm.nucleusenterprise.ai/v1",
    api_key=os.environ["NLLM_API_KEY"],
    is_chat_model=True,
)

print(llm.complete("Hello, who are you?"))

LlamaIndex 的所有上层 abstraction(RAG、Index、Query Engine)都建立在 LLM 接口之上,所以换到 OpenAILike 之后整个 pipeline 零改动。

Dify / FastChat / AutoGen 等其他框架

只要框架支持"自定义 OpenAI endpoint",就能直接用 nucleus-llm 作为后端:

  • Dify: 在模型供应商设置里选 "OpenAI-API-compatible",填 https://llm.nucleusenterprise.ai/v1
  • FastChat: 启动时加 --api-base https://llm.nucleusenterprise.ai/v1
  • AutoGen: config_list 里把 base_url 指过去
  • Continue.dev(VS Code 插件): 在配置里设 "apiBase"

可用模型速查

模型 适合场景 LangChain 里怎么写
claude-opus-4-6 复杂推理、agent ChatOpenAI(model="claude-opus-4-6", ...)
claude-sonnet-4-6 日常开发首选 ChatOpenAI(model="claude-sonnet-4-6", ...)
claude-haiku-4-5 分类、抽取、批量 ChatOpenAI(model="claude-haiku-4-5", ...)
gpt-5.4 通用 + 强 tool calling ChatOpenAI(model="gpt-5.4", ...)
gpt-5.3-codex 代码生成 ChatOpenAI(model="gpt-5.3-codex", ...)
gpt-5.4-mini 低成本通用 ChatOpenAI(model="gpt-5.4-mini", ...)
gemini-3.1-pro 超长上下文 ChatOpenAI(model="gemini-3.1-pro", ...)
gemini-3-flash 快速/批量 ChatOpenAI(model="gemini-3-flash", ...)

限制和注意事项

  1. 并非所有 OpenAI-only 的参数都透传 —— 比如 logit_biaslogprobs 对 Claude 和 Gemini 来说没有对应概念,设了也不会生效。
  2. function calling 的 schema 略有差异 —— OpenAI 的 JSON Schema 在 Claude 上可以用,但非常复杂的嵌套(尤其 oneOf / anyOf)可能需要简化。
  3. 本文的集成路径只针对后端服务(你自己写的 Python / Node 代码)。不要把它 用于 Claude Code / Codex CLI 这类客户端工具,那不是 nucleus-llm 的支持场景。

下一步

  • 在 llm.nucleusenterprise.ai 注册 获取 API Key
  • Clone nucleus-llm-examples GitHub 仓库,运行 python/04_langchain.py
  • 读续篇:《从 OpenAI 官方 API 迁移到统一网关的 5 分钟指南》