LangChain
LangChain integrates with Curate-Me through the base_url parameter on
ChatOpenAI. No middleware, no monkeypatching — the SDK’s existing
configuration surface is enough.
Minimal example
import os
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(
base_url=os.environ.get("CM_GATEWAY_URL", "https://api.curate-me.ai/v1/openai"),
api_key="unused",
model="gpt-4o",
default_headers={"X-CM-API-Key": os.environ["CM_API_KEY"]},
)
print(llm.invoke("What is the Curate-Me gateway?").content)The full example lives at
examples/integrations/langchain/main.py.
Its smoke test (tests/test_smoke.py) runs on every PR.
What you get for free
- Cost tracking per call (token-accurate, billed in USD)
- Rate limiting via IETF
RateLimit-*response headers - PII scanning on prompts before they reach the upstream provider
- Model allowlist enforcement
- HITL approval gates for high-cost calls
- Full request trace in the Curate-Me dashboard
Supported versions
| Library | Tested range |
|---|---|
langchain | >=0.3.0,<0.5.0 |
langchain-openai | >=0.2.0,<0.4.0 |
langchain-core | >=0.3.0,<0.4.0 |
Known limitations
- Streaming:
llm.stream(...)works, and per-chunk content is proxied unmodified. The final cost-record event lands when the stream closes —X-CM-Request-Idis in the headers (sent before the stream body) so you can correlate before the stream finishes. - Tools: function-calling works via the standard
bind_tools(...)API. The gateway tracks tool-call cost as part of the parent request, not as a separate trace row. - Embeddings: use
OpenAIEmbeddingsthe same way; route through/v1/openai/embeddings. Verified by the mock gateway in CI.
Troubleshooting
# Sanity check: make a call and inspect the response headers.
from openai import OpenAI
client = OpenAI(
base_url="https://api.curate-me.ai/v1/openai",
api_key="cm_sk_test_key", # placeholder — real key from dashboard
default_headers={"X-CM-API-Key": os.environ["CM_API_KEY"]},
)
resp = client.with_raw_response.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "ping"}],
)
print("request_id:", resp.headers.get("X-CM-Request-Id"))If X-CM-Request-Id is missing, you’re talking directly to OpenAI —
re-check the base_url.