LangChain integration
LangChain with Plan2API: Gemini, Claude, GPT and Kimi through ChatOpenAI
LangChain's ChatOpenAI runs 5 Gemini models, 9 Claude models, GPT and Kimi through Plan2API: set base_url to https://api.plan2api.com/v1, pass a p2a_ key and add use_responses_api=False. Gemini ids get the full 1,048,576-token context with no Gemini API key.
- Python package
- langchain-openai
- JS package
- @langchain/
openai - base_url
- https://
api.plan2api.com/ v1 - Python switch
- use_
responses_ api=False
Updated
LangChain settings for Plan2API
ChatOpenAI is the only class you need to talk to Plan2API, whether you're writing Python or JavaScript. In Python, if you don't pass explicit arguments, ChatOpenAI reads your key from OPENAI_API_KEY and checks OPENAI_API_BASE, then OPENAI_BASE_URL for the custom endpoint. The table below covers the arguments and environment variables you'll use.
| Setting | Python | JavaScript |
|---|---|---|
| Package | langchain-openai | @langchain/ |
| Base URL | base_ | configuration: { baseURL } |
| API key | api_ | apiKey: process.env.PLAN2API_ |
| Model | model="gemini/ | model: "gemini/ |
| Stay on Chat Completions | use_ | openai/ |
Set up ChatOpenAI for Plan2API
- Sign up with a Google account, connect your Claude, ChatGPT, Google AI or Kimi subscription, and copy your
p2a_API key. - Run
pip install -U langchain-openaiin your Python environment. - Export your key in the shell with
export PLAN2API_KEY="p2a_...". - Instantiate
ChatOpenAIwithbase_url="https://api.plan2api.com/v1",api_keyset to your key, anduse_responses_api=False. - Call
invoke,streamorbind_toolson the client just as you would with standard OpenAI models.
If you're in JavaScript, run npm install @langchain/openai @langchain/core and initialize the client with new ChatOpenAI({ model, apiKey, configuration: { baseURL } }). The example below runs Gemini with invoke, streams a response from Claude and asks Kimi for a tool call.
import os
from langchain_core.tools import tool
from langchain_openai import ChatOpenAI
def plan2api(model: str) -> ChatOpenAI:
return ChatOpenAI(
model=model,
base_url="https://api.plan2api.com/v1",
api_key=os.environ["PLAN2API_KEY"],
use_responses_api=False,
)
gemini = plan2api("gemini/gemini-3.8-flash-high")
print(gemini.invoke("Explain vector clocks in two sentences.").content)
claude = plan2api("claude/claude-sonnet-5")
for chunk in claude.stream("Write a haiku about pull requests."):
print(chunk.content, end="", flush=True)
print()
@tool
def get_weather(city: str) -> str:
"""Return the current weather for a city."""
return f"Sunny in {city}"
kimi = plan2api("kimi/k3").bind_tools([get_weather])
reply = kimi.invoke("What is the weather in Berlin?")
print(reply.tool_calls)Gemini in LangChain without a Gemini API key
The native LangChain Gemini integration is ChatGoogleGenerativeAI from the langchain-google-genai package, which needs an API key in GOOGLE_API_KEY (or GEMINI_API_KEY as a fallback) on the Gemini Developer API, or an API key, service account or Application Default Credentials on Vertex AI.
With Plan2API, you use ChatOpenAI and a gemini/ model id to run against your Google AI Pro or Ultra subscription through Antigravity, using the Gemini subscription API instead of a separate Gemini API key. The five gemini/ ids are gemini/gemini-4-argon-high, gemini/gemini-3.8-flash-high, gemini/gemini-3-flash, gemini/gemini-3.5-flash-lite and gemini/gemini-3.1-flash-lite.
- All five models, including gemini/gemini-3.8-flash-high, give you the full 1,048,576-token context window.
- Every
gemini/model accepts text, image, audio and video input. temperatureandtop_pvalues are passed straight through to Gemini.- JSON mode (
json_objectandjson_schemaonresponse_format) works out of the box. reasoning_effortis supported, andChatOpenAIsends it as a top-levelreasoning_effortfield on the request.
Pick a model id
The prefix on the model id selects the provider (gemini/, openai/, kimi/, or claude/ for the Claude subscription API), GET /v1/models lists every id Plan2API serves, including providers you haven't connected (those return HTTP 403 no_credentials), and Codex ids run on your own ChatGPT plan, so pick one your plan includes. The table below lists example model ids, the subscription each one needs and a key note on each.
| model | Subscription | Note |
|---|---|---|
| gemini/ | Google AI Pro or Ultra | 1,048,576-token context |
| gemini/ | Google AI Pro or Ultra | 1,048,576-token context |
| claude/ | Claude Pro or Max | No JSON response_ |
| claude/ | Claude Pro or Max | 1M context, up to 128K output |
| openai/ | ChatGPT (Codex) | Use openai/ |
| kimi/ | Kimi Code | temperature fixed at 1 |
Keep ChatOpenAI on Chat Completions
Plan2API serves POST /v1/chat/completions and has no /v1/responses endpoint, which matters when ChatOpenAI decides to switch to OpenAI's Responses API on its own.
In Python (langchain-openai 1.7.3), use_responses_api defaults to None, and the client switches to the Responses API by itself if the model name contains codex, if the model starts with gpt-6 and has tools bound, or if you pass options like reasoning, include, truncation or output_version='responses/v1'. Passing use_responses_api=False forces Chat Completions in every case, even on codex/ ids. When you want to control reasoning in Python, pass reasoning_effort='high' rather than a reasoning dict, which would otherwise trigger the Responses API.
In JavaScript (@langchain/openai 1.8.0), useResponsesApi defaults to false, but a model name containing codex or gpt-5.6, or any Responses-only options, will still switch the client over to /v1/responses, so stick to openai/ model ids such as openai/gpt-6.1-sol for your ChatGPT Codex models.
In @langchain/openai, codex/ model ids and any id containing gpt-5.6 ignore useResponsesApi: false and call /v1/responses, so always use the openai/ prefix in JavaScript and skip GPT-5.6 models there.
Streaming, tools and what doesn't work
- Calling
stream()yields token chunks across Gemini, Claude, Codex and Kimi models. - When you set a custom
base_url, LangChain Python leavesstream_usageoff by default, and passingstream_usage=Truerequests token counts throughstream_options(include_usage). bind_toolsaccepts@toolfunctions and Pydantic classes on all four providers, returning the model's calls in the message'stool_callslist.with_structured_outputdefaults tomethod='json_schema', which sends aresponse_formatthat works on Gemini, Codex and Kimi, while Claude models return HTTP400unsupported_parameterunless you passmethod="function_calling".- In Python,
ChatOpenAIsendsmax_tokensover the wire asmax_completion_tokens, which the API accepts alongsidemax_tokens. OpenAIEmbeddingsdoes not work because there is no/v1/embeddingsendpoint.- The legacy
OpenAItext completion class does not work because there is no/v1/completionsendpoint.
Troubleshooting LangChain with Plan2API
401invalid_api_key:PLAN2API_KEYis unset, the key doesn't start withp2a_, or the client sent it in anx-api-keyheader instead ofAuthorization: Bearer.403no_credentials: your vault has no connected subscription for the provider prefix you requested, so connect an account for that provider in the dashboard.400model_not_found: the model string isn't recognized, so checkGET /v1/modelsand pass the full prefixed id.400unsupported_parameter: you calledwith_structured_outputwith its defaultjson_schemamethod or set a non-textresponse_formaton aclaude/model, which you fix by settingmethod="function_calling".- Requests hitting
/v1/responses:ChatOpenAIswitched off Chat Completions, so adduse_responses_api=Falsein Python and replacecodex/prefixes withopenai/and avoidgpt-5.6ids in JavaScript. 429daily_requests: you used the Free plan's 50 chat requests for the day (resets at 00:00 UTC), and an agent loop spends one request per model call, so a single tool round trip costs 2; wait for theRetry-Afterwindow or move to one of the Pro and Scale plans, which have no daily request cap.
If an error happens after a streaming response has already started, it arrives as a final server-sent event in the stream rather than an HTTP status code.
Use the AI subscriptions you already pay for as one OpenAI-compatible API key.
- Free: 1 subscription, 50 requests a day, no card
- Pro: $12 a month
FAQ
Can LangChain use Gemini through an OpenAI-compatible API?
Yes, point ChatOpenAI at base_url="https://api.plan2api.com/v1" and pass a gemini/ model id such as gemini/gemini-3.8-flash-high. Add your p2a_ key and use_responses_api=False, and the request runs on your Google AI Pro or Ultra subscription through /v1/chat/completions.
Do I need a Gemini API key for LangChain with Plan2API?
No. Plan2API runs Gemini requests through your connected Google AI Pro or Ultra subscription, whereas ChatGoogleGenerativeAI needs a Gemini API key (GOOGLE_API_KEY or GEMINI_API_KEY) or Vertex AI credentials.
Does Plan2API work with the Responses API in LangChain?
No, it only serves /v1/chat/completions. Pass use_responses_api=False to ChatOpenAI in Python so LangChain doesn't switch endpoints.
How do I get structured output from Claude in LangChain?
Call with_structured_output(Schema, method="function_calling") on your ChatOpenAI instance. The default json_schema method sends a non-text response_format, which Claude models reject with 400 unsupported_parameter.
Does LangChain.js work with Plan2API?
Yes, pass your model, key and base URL to new ChatOpenAI({ model, apiKey, configuration: { baseURL } }). Use openai/ ids instead of codex/ ids, as codex/ names (and any id containing gpt-5.6) force @langchain/openai onto the Responses API.
Can I use OpenAIEmbeddings with Plan2API?
No, Plan2API does not have a /v1/embeddings endpoint, so OpenAIEmbeddings calls fail. Use a separate embeddings provider for vectors and keep ChatOpenAI on Plan2API for chat.
Sources
- LangChain ChatOpenAI (Python)docs.langchain.com
- LangChain ChatOpenAI (JavaScript)docs.langchain.com
- LangChain ChatGoogleGenerativeAIdocs.langchain.com
- langchain-openai ChatOpenAI source (GitHub)github.com
- langchain-openai 1.7.3 on PyPIpypi.org
- LangChain.js ChatOpenAI source (GitHub)github.com
- LangChain.js Responses API model routing (GitHub)github.com
- langchain-google-genai auth settings (GitHub)github.com