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

# Capture from a LangChain app

> Log your production LLM calls into a task dataset with one callback. No changes to your chain, and it never breaks your app.

If your app already runs on LangChain, you can build a dataset from real traffic instead of writing a CSV. Add one callback to your model and every call is logged to a task.

## Install

```bash theme={null}
pip install "apprentice-sdk[langchain]"
```

## Add the callback

```python theme={null}
import os
from langchain.chat_models import init_chat_model
from apprentice import Apprentice
from apprentice.langchain import ApprenticeCallback

client = Apprentice(
    api_key=os.environ["APPRENTICE_API_KEY"],
    base_url=os.environ["APPRENTICE_BASE_URL"],
)

model = init_chat_model(
    "gpt-5-mini",
    callbacks=[ApprenticeCallback("support-bot", client)],
)
```

Every call through `model` now logs its input, output, model name, latency, and token counts to the `support-bot` task. You keep the model you already use. Apprentice observes, it does not choose your model.

## It cannot break your app

The capture path is fail-open by contract. If the Apprentice backend is slow, down, or unreachable, your LLM call still returns and your app is unaffected. The only loss is that one trace. Do not wrap the callback in a `try/except` to protect your app, it is already safe.

Captured traces arrive as **raw** rows: live, unverified. Verify them to gold, or upload curated rows as silver, before you rely on them for optimization.

## RAG: the retrieved context is captured

For a standard LangChain RAG chain, the callback records the retrieved context alongside the question, so the dataset holds the exact context the model saw:

```python theme={null}
inputs = {"question": question, "context": retrieved_passages}
```

This matters because a RAG prompt can only be optimized against the real context. If your chain has several retrievers or custom context formatting, use [`client.capture`](/reference/python-sdk#capture) directly and pass the context yourself.

## Redact before anything leaves your process

If your inputs contain sensitive data, pass a `redact` function. It runs in your process, before the trace is sent:

```python theme={null}
ApprenticeCallback("support-bot", client, redact=lambda s: my_scrubber(s))
```

## Next

Once you have traces, optimize the prompt the same way as the [JSON extraction guide](/how-to/json-extraction), or read the [capture reference](/reference/python-sdk#capture) for the manual path.
