LangChain
Protect LangChain chains with OGuardAI so PII is tokenized before the model and restored in the output
The OGuardAI SDKs ship an optional LangChain integration that wraps any LangChain Runnable so PII
in the input is tokenized before the chain runs and restored in the chain output afterward. The
wrapped runnable and the model only ever see the tokenized safe_text; the sealed session never
enters the chain, its callbacks, or its memory. Each integration is a thin seam over the SDK
guarded_call / guardedCall primitive.
Install
The integration is an optional extra, so LangChain is only pulled in when you use it.
Python
pip install "oguardai-sdk[langchain]"TypeScript
pnpm add @oguardai/sdk @langchain/coreTwo entry points
Both give the same core guarantee: the wrapped runnable and the model see only tokenized text. They differ in how they interact with LangChain callbacks and tracers.
guarded_invoke/guardedInvokeruns the transform and rehydrate outside LangChain. No LangChain callback or tracer ever observes the raw input or the restored output. Prefer this when a PII-exporting tracer (for example LangSmith) is attached to your chain.protect/protectRunnablereturns a composableRunnableyou can drop into a larger chain. Its own input and output boundary (raw in, restored out) is visible to callbacks and tracers attached at or above that node, so use it when the outer chain is not exported to a PII-sensitive destination.
Python
from guardai_sdk import OGuardAIClient
from guardai_sdk.integrations.langchain import protect, guarded_invoke
client = OGuardAIClient(base_url="http://localhost:3000")
# Boundary-safe: nothing raw or restored reaches a LangChain callback or tracer.
answer = guarded_invoke(chain, client, "Email Julia Schneider at julia@firma.example")
# Composable Runnable (see the tracer note above).
guarded = protect(chain, client)
answer = guarded.invoke("Email Julia Schneider at julia@firma.example")TypeScript
import { OGuardAIClient } from "@oguardai/sdk";
import { protectRunnable, guardedInvoke } from "@oguardai/sdk/integrations/langchain";
const client = new OGuardAIClient({ baseUrl: "http://localhost:3000" });
// Boundary-safe: nothing raw or restored reaches a LangChain callback or tracer.
const answer = await guardedInvoke(chain, client, "Email Julia Schneider at julia@firma.example");
// Composable Runnable (see the tracer note above).
const guarded = protectRunnable(chain, client);
const composed = await guarded.invoke("Email Julia Schneider at julia@firma.example");In both cases the chain sees only Email {{person:p_001:ad4f97591c16}} at {{email:e_001:1bcaef1a4aff}}, and the returned
answer has the real values restored.
Structured input
String input is safe by construction: only the tokenized text reaches the chain. For a structured input (a dict of prompt variables, or a message object), pass an extractor to pull the single text to protect and a builder to rebuild the chain input. Structured input without an extractor is rejected (fail loud) so a raw value can never be sent by accident.
Python
guarded = protect(
chain,
client,
input_extractor=lambda payload: payload["question"],
safe_input_builder=lambda payload, safe: {"question": safe},
output_key="answer",
)TypeScript
const guarded = protectRunnable(chain, client, {
inputExtractor: (payload) => payload.question,
safeInputBuilder: (_payload, safe) => ({ question: safe }),
outputKey: "answer",
});The builder receives the raw original input, so it is your responsibility to pass back only the
fields your chain needs and never a raw PII field. When several fields need protecting, use the
structured transform API directly instead of this single-text integration.
How it works
- The integration calls
/v1/transformon the input text, replacing PII with semantic tokens. - The wrapped runnable runs on the tokenized
safe_textand returns its output. - The integration calls
/v1/rehydrateon that output using the sealed session, restoring the real values per the output channel.
If the transform fails, the wrapped runnable is never invoked (fail closed).