> ## Documentation Index
> Fetch the complete documentation index at: https://docs.rotavision.com/llms.txt
> Use this file to discover all available pages before exploring further.

# LangChain

> Witness LangChain apps through the provider middleware underneath, and the LangGraph path for graph-structured agents.

There is no `watch_langchain`, and Sakshi does not invent one. LangChain does not
run models itself: it builds on the same provider SDKs Sakshi already wraps, and
modern LangChain agents compile to a graph. So a LangChain app is witnessed
through the surfaces that already exist, with no LangChain dependency in the SDK.

There are two accurate paths, and you can use both together.

## Path A: wrap the provider client (recommended for model evidence)

A LangChain chat model calls a provider SDK client underneath. Build that client
yourself, wrap it with the matching Sakshi middleware, and hand the wrapped client
to the chat model. Every completion then lands an `llm_call` step with the served
model identity (para-56), tokens, and outcome.

<CodeGroup>
  ```python OpenAI-backed theme={null}
  from openai import OpenAI
  from langchain_openai import ChatOpenAI
  from sakshi.middleware import watch_openai_compatible

  client = watch_openai_compatible(OpenAI())
  llm = ChatOpenAI(model="gpt-5.2", client=client.chat.completions)

  with sakshi.witness(agent_id, client_ref="APP-2026-04471") as decision:
      reply = llm.invoke("Assess this applicant.")
      decision.action(outcome="approved", mode="auto")
  ```

  ```python Anthropic-backed theme={null}
  from anthropic import Anthropic
  from langchain_anthropic import ChatAnthropic
  from sakshi.middleware import watch_anthropic

  client = watch_anthropic(Anthropic())
  llm = ChatAnthropic(model="claude-opus-4-6", client=client.messages)

  with sakshi.witness(agent_id, client_ref="APP-2026-04471") as decision:
      reply = llm.invoke("Assess this applicant.")
      decision.action(outcome="approved", mode="auto")
  ```
</CodeGroup>

The middleware wraps the client and exposes the same `chat.completions` or
`messages` surface LangChain calls, so what gets recorded is exactly what the
[OpenAI](/integrations/openai) and [Anthropic](/integrations/anthropic) pages
describe. Consult your LangChain version for the precise constructor argument that
accepts a preconstructed client.

## Path B: witness the graph (recommended for agents)

A LangChain agent built with LangGraph, or with a helper like `create_react_agent`,
compiles to a graph that exposes `invoke` and `stream`. Wrap it with
`watch_langgraph`, and decorate individual nodes with `witness_node`. This path is
provider-agnostic: it does not need to know which model sits underneath.

```python theme={null}
from sakshi.middleware import watch_langgraph

agent = watch_langgraph(compiled_agent)

with sakshi.witness(agent_id, client_ref="APP-2026-04471") as decision:
    result = agent.invoke({"messages": [("user", "Assess this applicant.")]})
    decision.action(outcome="approved", mode="auto")
```

Combine both paths for the fullest evidence: Path B records the graph and node
control flow, and Path A records the model calls inside each node.

<Tip>
  If your LangChain app is a graph, start with Path B. See
  [LangGraph](/integrations/langgraph) for `watch_langgraph` and `witness_node`.
</Tip>

<Card title="Full SDK reference" icon="code" href="/sdk/python">
  The client, the witness session, and enforcement.
</Card>
