models_io (legacy alias) — Re-export façade for prompts/llms/chat_models/parsers

Re-export façade for prompts/llms/chat_models/parsers

Module langchain_classic/models_io/ — Re-export façade for prompts/llms/chat_models/parsers. Part of the Models I/O group.

🎯 Why This Module Exists

This module is documented from the models_io_deep.md Phase 1B research artifact. See sections below for design decisions, algorithms, error philosophy, performance, and evolution clues.

—
Source files
0
Sub-directories
Models I/O
Category
Python
Language

Façade Backwards-compat

Architecture

flowchart LR
  subgraph Core["langchain_classic/models_io/"]
    BASE["Base abstraction"]
    IMPLS["Concrete implementations"]
    BASE --> IMPLS
  end
  subgraph Up["Upstream callers"]
    U1["chains/"]
    U2["agents/"]
  end
  subgraph Down["Downstream"]
    D1["langchain_core"]
    D2["External providers"]
  end
  Up --> Core
  Core --> Down

Data Flow

sequenceDiagram
  participant Caller as Caller
  participant Models_I as models_io (legacy alias)
  participant Core as langchain_core
  participant Ext as External
  Caller->>Models_I: invoke(input)
  Note over Models_I: Validate & route
  Models_I->>Core: delegate primitive
  Core->>Ext: provider call
  Ext-->>Core: response
  Core-->>Models_I: typed output
  Models_I-->>Caller: result

Existence rationale

These four modules are the provider façade between user code and the actual LLM/embedding service. After the package split, the real implementations migrated to langchain_community.{llms,chat_models,embeddings} and provider packages (langchain_openai, langchain_anthropic, …). What remains in langchain_classic is:

  1. A **lazy __getattr__ trampoline** that forwards langchain_classic.llms.OpenAI to langchain_community.llms.OpenAI.
  2. A deprecation warning emitted on first access.
  3. A handful of classic, non-trivial wrappers that pre-date the split: CacheBackedEmbeddings, init_chat_model (provider-detection), prompts/example_selector/ re-exports.

The point of this design is migration: legacy code keeps working (with warnings) while users are nudged toward the canonical import path.

Design decisions

DecisionChoiceAlternativeRationale
Lazy __getattr__ per moduleFirst-access import + warnEager importsAvoids loading 70+ provider deps on import langchain
Deprecation messages with replacement path"...moved to langchain_openai"Generic warningActionable for the user
CacheBackedEmbeddings lives in langchain_classicUnique algorithmMove to communityIt's provider-agnostic and used by every retriever pipeline; staying in classic gives it a stable home
prompts/ re-exports langchain_core.prompts.*Pure shimImplement hereTemplates are core abstractions; classic should not duplicate
init_chat_model provider routingString like "openai:gpt-4o-mini" parsedOne factory per providerLets configuration files specify model without import-time provider choice

Algorithm deep-dive — CacheBackedEmbeddings

Problem. Embedding the same documents twice (during a re-index, during dev iteration, during testing) wastes API calls. Cache the result.

Trace. embed_documents(texts):

  1. keys = [hash_func(t) for t in texts] (default SHA256).
  2. cached = byte_store.mget(keys) — bytes-typed values for hits, None for misses.
  3. Decode hits via decoder to get back float vectors.
  4. missing_idx = [i for i, c in enumerate(cached) if c is None].
  5. new_vectors = underlying_embedder.embed_documents([texts[i] for i in missing_idx]).
  6. byte_store.mset([(keys[i], encoder(new_vectors[j])) for j, i in enumerate(missing_idx)]).
  7. Splice cached + new in original order; return.

embed_query does not cache by default — queries are usually unique strings (typos, paraphrases) so cache hit rate is low and the cost of cache pollution outweighs the win.

**Why a ByteStore rather than a typed Mapping[str, list[float]].** Lets the same cache back arbitrary content (embeddings now, raw bytes later) and slots into any of LocalFileStore, RedisStore, InMemoryByteStore. The encoder/decoder are pluggable.

Error philosophy

Deprecated trampolines emit a warning (suppressed in interactive REPLs to avoid spam) and proceed. Real errors come from the underlying community/provider package and propagate unchanged.

Cross-module dependencies

langchain_classic.{llms, chat_models, embeddings}  ──`__getattr__`──►  langchain_community.{llms, chat_models, embeddings}
                                                                                              │
                                                                                              ▼
                                                                                  provider packages (httpx, openai, …)

langchain_classic.prompts  ──re-exports──►  langchain_core.prompts (PromptTemplate, ChatPromptTemplate, MessagesPlaceholder, FewShotPromptTemplate, …)

CacheBackedEmbeddings ──►  storage.ByteStore  ──►  Local / In-memory / Redis backends

Evolution clues

Step-by-Step Walkthrough

Follow a typical operation through the models_io/ module:

  1. Caller invokes the public surface — usually .invoke(input) on a Runnable, or a legacy __call__(inputs_dict) on a Chain subclass.
  2. Pydantic validation — every entry point is a BaseModel; constructor args, input dicts, and tool args_schema are validated before any expensive work runs. Fail-fast on type errors.
  3. CallbackManager.configure — a fresh manager is built per call, fans on_*_start events to all subscribers (LangSmith tracer, stdout handler, custom logging), and stamps a UUID4 run_id for tree reconstruction.
  4. models_io (legacy alias)-specific logic — the module's core method runs: prompt rendering, retrieval, tool execution, memory load, document split, etc. See the deep-dive sections above.
  5. Provider call — typically a single HTTP request to OpenAI/Anthropic/etc., or a local SDK call. Retries are handled by tenacity with exponential backoff and a configurable max-attempts knob.
  6. Streaming fan-out — if the provider streams tokens, each chunk fires on_llm_new_token through the callback manager so downstream observers (UI, log, tracer) see partial output.
  7. OutputParser pass — if a parser is attached, the raw provider output is parsed into a structured Python object; OutputParserException may trigger a retry chain (RetryWithErrorOutputParser).
  8. Memory write-back — for chains/agents that have a BaseMemory attached, save_context(inputs, outputs) persists the turn before returning to the caller.
  9. on_*_end fan-out — the callback manager closes the run span; tracers serialise the Run tree and ship it to LangSmith asynchronously.
  10. Result returned — caller receives a typed object (AIMessage, dict, BaseModel, list[Document], ...) matching the module's declared output schema.

What Could Go Wrong

Failure Mode Trigger Detection Recovery
Provider 5xx / rate-limit OpenAI/Anthropic/etc. transient error HTTP status from SDK tenacity retries with exponential backoff up to max_retries; then surface to caller
Output parser failure LLM returned malformed JSON / wrong schema OutputParserException in parser RetryWithErrorOutputParser re-prompts with the parser error included; or surface
Pydantic validation Caller passes wrong-shaped dict ValidationError at __init__ / invoke Surface immediately — no fallback is correct here
Callback handler exception User-supplied tracer raises Try/except around each fan-out Logged and swallowed by default; raise_error=True to opt in to propagation
Provider auth missing OPENAI_API_KEY unset SDK AuthenticationError Surface with a helpful message; no retry (would just fail again)

Performance Profile

Hot Paths

Resource Usage

Directory Map

Source tree for models_io (legacy alias)
models_io/  (source listing unavailable)