LangChain agents are where many teams' first real agents live — and where the audit question first gets awkward, because the framework orchestrates tool calls your logging never sees coherently. Here's the honest five minutes: wire the Wytness wrapper in once, add one callback, and every tool call your LangChain agent makes lands on the tape — signed, sealed, verifiable.
How the pieces fit
Three layers cooperate, and it helps to name them before the code. LangChain runs your agent and exposes lifecycle callbacks around every tool invocation. Microsoft's AGT ships a LangChain integration — a trust-gating callback that can gate tool execution against an agent's trust score. And the Wytness wrapper, initialised once at process start, turns everything written to AGT's audit log into signed, PII-sealed events on your tape. One honest detail the setup depends on: AGT's LangChain callback does trust verification — it does not emit audit entries by itself. The recording half is a thin callback you add, and it's shorter than this paragraph.
The whole setup
# 1. Wytness wrapper — wire in once at process start.import wytness_aifrom wytness_ai import AuditLogwytness_ai.init(pii_fields=["customer.email"]) # 2. AGT's LangChain trust callback — Microsoft's pattern.from langchain.agents import AgentExecutorfrom agentmesh.integrations.langchain import AgentMeshTrustCallback trust_cb = AgentMeshTrustCallback(agent_did="billing-agent")audit = AuditLog() # 3. Wrap tool-call lifecycle to write an AuditEntry per invocation.class WytnessAuditCallback: def on_tool_end(self, tool_name, params, result, **_): audit.log( event_type="tool_invocation", agent_did="billing-agent", action=tool_name, policy_decision="allow", data={"params": params, "result": result}, ) agent_executor = AgentExecutor( agent=my_agent, tools=my_tools, callbacks=[trust_cb, WytnessAuditCallback()],) agent_executor.invoke({"input": "Send the Q1 invoice to Acme Corp"}) wytness_ai.shutdown()That's the entire integration. init() reads your WYTNESS_* environment values — API key, signing key, sealing keys — exactly as in the Python quickstart, and every audit.log(...) call becomes one signed event on its way to ingest. Declare the personal fields your tools handle in pii_fields and they cross the wire as tokens, never as values.
What you get per tool call
Run the agent and open Events: one row per tool invocation, in order, inside one session — the lookup, the invoice creation, the send, each with its parameters, result, duration, and verification mark. Because the callback sits on the framework's lifecycle rather than inside any single tool, new tools your agent gains are recorded the day they're added, without anyone remembering to instrument them. And the model calls LangChain makes underneath are captured too — init() wraps the OpenAI and Anthropic clients automatically, so the reasoning steps appear on the tape between the tool calls they caused, token counts included.
Beyond LangChain
The same pattern covers the rest of the framework zoo — AGT ships integrations for LangGraph, CrewAI, Haystack, MCP, and more, plus a framework-agnostic HTTP middleware when you'd rather capture at the request boundary. The full matrix, and this example in copy-paste form, live in the Framework Integrations docs. The shape is always the same: initialise the wrapper once, hook the framework's lifecycle, and let the tape do the rest.
This guide replaces the original v1-SDK version that lived at this address; the v1 package it covered is in security-only maintenance and new integrations should follow the pattern above.
Questions about your framework mix? Ask us.