Implementation:Arize ai Phoenix LangChain Adapter
Overview
The LangChainModelAdapter is a concrete implementation of the BaseLLMAdapter abstract class that wraps LangChain model instances for use within the Phoenix evaluator framework. It resides in the phoenix-evals sub-package and adapts LangChain's invoke/ainvoke, with_structured_output, and bind_tools interfaces to the four core adapter methods. The adapter is registered as a multi-provider component, supporting both OpenAI and Anthropic LangChain backends.
Description
The module defines the LangChainModelAdapter class and three supporting functions: identify_langchain_client(), get_anthropic_langchain_rate_limit_errors(), and get_openai_langchain_rate_limit_errors(). Key design characteristics:
- Client identification: Detects LangChain models by checking for the
"langchain"module namespace or the presence ofinvoke/predictmethods. - Dual provider registration: The adapter is registered under both
openaiandanthropicproviders via separate@register_providerdecorators, each with its own client factory and rate limit error type. - Message format conversion: Converts Phoenix's internal
MessageTypedDicts (withMessageRoleenums) to LangChain-native message objects (HumanMessage,AIMessage,SystemMessage). Falls back tolangchain_community.adapters.openai.convert_openai_messages()for plain dict formats. - Capability detection: For structured output, the adapter dynamically checks the model's capabilities:
with_structured_outputfor native structured outputbind_toolsorbind_functionsfor tool-based extraction
- Graceful degradation: Under
AUTOmode, the adapter attempts structured output first, then falls back to tool calling, logging warnings on each failure. - Schema normalization: Adds
titleanddescriptionfields to schemas when missing, as LangChain's structured output requires them.
Usage
from langchain_openai import ChatOpenAI
from phoenix.evals.llm.adapters.langchain.adapter import LangChainModelAdapter
# Create a LangChain model and wrap it
llm = ChatOpenAI(model="gpt-4o", api_key="sk-...")
adapter = LangChainModelAdapter(client=llm, model="gpt-4o")
# Text generation
response = adapter.generate_text("What is the capital of France?")
# Structured output
schema = {
"type": "object",
"properties": {
"answer": {"type": "string"},
"confidence": {"type": "number"}
},
"required": ["answer", "confidence"]
}
result = adapter.generate_object("What is 2+2?", schema=schema)
from langchain_anthropic import ChatAnthropic
# Works with Anthropic LangChain models too
llm = ChatAnthropic(model="claude-sonnet-4-20250514")
adapter = LangChainModelAdapter(client=llm, model="claude-sonnet-4-20250514")
# Async text generation
response = await adapter.async_generate_text("Summarize this.")
Code Reference
I/O Contract
generate_text / async_generate_text
| Direction | Type | Description |
|---|---|---|
| Input | Union[PromptLike, MultimodalPrompt] |
A string prompt, list of message dicts, list of Message TypedDicts, or legacy MultimodalPrompt
|
| Input | **kwargs |
Additional keyword arguments forwarded to the LangChain model's invoke() or ainvoke() method
|
| Output | str |
The string content from the LangChain response (from .content attribute or str() fallback)
|
generate_object / async_generate_object
| Direction | Type | Description |
|---|---|---|
| Input | Union[PromptLike, MultimodalPrompt] |
A prompt in any supported format |
| Input | Dict[str, Any] |
A JSON schema defining the expected output structure |
| Input | ObjectGenerationMethod |
AUTO (default: tries structured output then tool calling), STRUCTURED_OUTPUT, or TOOL_CALLING
|
| Output | Dict[str, Any] |
A dictionary from with_structured_output or extracted from tool_calls[0].args
|
| Raises | ValueError |
If the model supports neither structured output nor tool calling, or both methods fail |
Usage Examples
LangChain Method Dispatch
The adapter uses a priority chain for text generation:
# Priority: invoke() -> predict() -> __call__()
# For async: ainvoke() -> apredict() -> sync fallback
llm = ChatOpenAI(model="gpt-4o")
adapter = LangChainModelAdapter(client=llm, model="gpt-4o")
# Uses llm.invoke() internally
result = adapter.generate_text("Hello")
# Uses llm.ainvoke() internally
result = await adapter.async_generate_text("Hello")
Model Name Resolution
# The adapter resolves model name from the LangChain model
adapter = LangChainModelAdapter(client=llm, model="gpt-4o")
print(adapter.model_name) # "gpt-4o" (from client.model_name or client.model)
Related Pages
- Arize_ai_Phoenix_LLM_Base_Types - Abstract base class
BaseLLMAdapterand core type definitions - Arize_ai_Phoenix_OpenAI_Adapter - Direct OpenAI adapter (non-LangChain)
- Arize_ai_Phoenix_Anthropic_Adapter - Direct Anthropic adapter (non-LangChain)
- Arize_ai_Phoenix_LLM_Prompts - Prompt template and message abstraction layer
- Arize_ai_Phoenix_Evals_Rate_Limiters - Rate limiting subsystem integrated via provider-specific error types
- Arize_ai_Phoenix_Evals_Executors - Task execution framework that orchestrates adapter calls