Open-Source Wikis

/

LangChain

/

How to contribute

/

Patterns and conventions

langchain-ai/langchain

Patterns and conventions

Coding norms enforced across langchain-ai/langchain. Most of these come from CLAUDE.md / AGENTS.md; the rest are observable in the source.

Stable public interfaces

LangChain treats every symbol exported from a package's __init__.py as a public API. Breaking changes are rare and require a deprecation cycle.

Rules of thumb before changing a public function or class:

  • Check whether the symbol is re-exported from libs/<package>/<package>/__init__.py. If it is, treat the signature as load-bearing.
  • New parameters should be keyword-only: def f(..., *, new_param: T = default).
  • Don't change defaults of arguments like model= in shipped code unless you flag it as a breaking change in the PR description.
  • Mark experimental APIs with the MkDocs Material !!! warning admonition in their docstring.

The repo uses langchain_core._api deprecation utilities — surface_langchain_deprecation_warnings, surface_langchain_beta_warnings, LangChainDeprecationWarning, LangChainBetaWarning — to flag pending removals at import time.

Type hints everywhere

All Python code must include type hints and return types. langchain-core and langchain are checked under mypy in strict = true with enable_error_code = "deprecated". Specific patterns:

  • from __future__ import annotations is not universally used; many files prefer fully evaluated annotations because Pydantic validators need them.
  • Generic type variables are declared at the top of the file (TypeVar("T"), TypeVar("ResponseT")).
  • TYPE_CHECKING guards for heavy imports (e.g. langgraph.graph.state.CompiledStateGraph) so that runtime import cost stays low.
  • Annotated[T, OmitFromSchema] is used in agent state definitions to control what shows up in the public schema.

Docstrings

Google-style with an Args: section (and Returns:, Raises: where relevant). Examples:

def trim_messages(
    messages: list[AnyMessage],
    *,
    max_tokens: int,
    token_counter: Callable[[list[AnyMessage]], int],
) -> list[AnyMessage]:
    """Trim a message list to fit within a token budget.

    Args:
        messages: The messages to trim, oldest first.
        max_tokens: Maximum allowed token count.
        token_counter: Function returning a token count for a message list.

    Returns:
        A truncated message list that fits within the budget.

    Raises:
        ValueError: If `max_tokens` is non-positive.
    """

Conventions:

  • Types live in the signature, not in the docstring.
  • Don't repeat the default value in the docstring unless it is post-processed or set conditionally.
  • Use single backticks for inline code (`tool_call`), never Sphinx-style double backticks.
  • Use American English spelling.

Error handling

  • No bare except: — always catch a specific exception type.
  • Use a msg variable for the exception text and pass it in: msg = f"..."; raise ValueError(msg). This is what the project's ruff config enforces (EM101, EM102 are disabled in select files but flagged everywhere else).
  • No eval(), exec(), or pickle on user-controlled input — see the _security/ module in langchain-core for the policy hooks.
  • Don't leak resources: use context managers for files, sockets, and HTTP clients.

Import discipline

  • No relative imports anywhere (ban-relative-imports = "all" in every ruff config).
  • Heavy or optional dependencies use lazy imports. Examples:
    • libs/langchain_v1/langchain/chat_models/base.py does importlib.import_module(module_path) inside init_chat_model so a user without langchain_anthropic installed can still use OpenAI.
    • libs/core/langchain_core/runnables/__init__.py declares a _dynamic_imports map and overrides __getattr__ to import on first access.
  • Re-exports happen at the package root __init__.py, never via *.

Pydantic patterns

  • Pydantic v2 throughout. pyproject.toml pins pydantic>=2.7.4,<3.0.0.
  • Custom validators use @field_validator and @model_validator (not the v1 @validator).
  • Some classes use langchain_core.utils.pydantic.pre_init (registered as a classmethod-decorator in ruff config) for backwards-compatible initialization shimming.

File reference style in docs

When referencing source files in prose or docstrings, use full paths from the repo root:

  • Good: libs/core/langchain_core/runnables/base.py
  • Bad: base.py (ambiguous; broken link in rendered docs)

This is enforced by reviewers; the wiki tooling and the API reference site assume full paths.

Conventional commits

PR titles are linted. Format: <type>(<scope>): <description>.

  • Allowed types and scopes are listed in .github/workflows/pr_lint.yml.
  • The description starts with a lowercase letter unless it's a proper noun or backtick-wrapped named entity.
  • Wrap class/function/parameter names in backticks.

Example titles from recent history:

feat(langchain): add new chat completion feature
fix(core): resolve type hinting issue in vector store
chore(anthropic): update infrastructure dependencies
fix(openai): infer Azure chat profiles from model name

File organization within a package

Path Convention
<pkg>/<pkg>/__init__.py Re-exports the public API only
<pkg>/<pkg>/_internal/ or _<name>.py Private modules — the leading underscore signals "do not import from outside this package"
<pkg>/<pkg>/data/ Static JSON/TOML data (e.g. partner model profiles)
<pkg>/<pkg>/py.typed Empty marker file declaring PEP 561 type-info availability
<pkg>/scripts/ Maintenance scripts, not part of the package
<pkg>/tests/unit_tests/ No-network tests
<pkg>/tests/integration_tests/ Network-allowed tests

Test files mirror the source layout: tests/unit_tests/messages/test_ai.py covers langchain_core/messages/ai.py.

Model references in code and docs

Always cite the latest GA models in docstrings and example snippets. Avoid preview/beta IDs unless they are the only option. Verify model IDs against the provider's official docs before committing — model lists in this repo go stale quickly because providers ship new models constantly.

For machine-readable capability data (context window, tool support, multimodal flags), use the langchain-profiles CLI in libs/model-profiles/langchain_model_profiles/cli.py. Each partner's data/ directory holds the resulting JSON.

Cross-cutting "danger zones"

  • libs/core/langchain_core/runnables/base.py — every change here touches every downstream caller. Be especially careful with new generic parameters or async semantics.
  • libs/core/langchain_core/messages/content.py — adding a new content-block type means every partner needs a translator update.
  • libs/langchain_v1/langchain/agents/middleware/types.py — the AgentMiddleware base class signature is part of the middleware ABI; changing it ripples through every built-in middleware and every external middleware author.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Patterns and conventions – LangChain wiki | Factory