LangChain Integration
BriefcaseLangChainHandler is a LangChain callback handler that captures
AI decisions for every LLM call, chain execution, tool invocation, and
retriever query in your application.
Installation
pip install briefcase-ai
pip install langchain-core langchain-openai # or your LLM provider
Constructor
from briefcase.integrations.frameworks import BriefcaseLangChainHandler
handler = BriefcaseLangChainHandler(
engagement_id="", # project identifier
workstream_id="", # workflow identifier
capture_llm=True, # capture LLM/chat model calls
capture_chains=True, # capture chain start/end
capture_tools=True, # capture tool invocations
capture_retrievers=True, # capture retriever queries
max_input_chars=10000, # truncation limit for inputs
max_output_chars=10000, # truncation limit for outputs
context_version=None, # version tag added to all records
async_capture=True, # export runs in background thread
client=None, # reserved for future use
)
Basic Usage
Pass the handler as a callback to any LangChain component:
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
llm = ChatOpenAI(model="gpt-4o", callbacks=[handler])
prompt = ChatPromptTemplate.from_template("Explain {topic} in one sentence.")
chain = prompt | llm
result = chain.invoke(
{"topic": "quantum computing"},
config={"callbacks": [handler]},
)
Retrieving Decisions
# Get CapturedDecision objects
decisions = handler.get_decisions()
# Get serializable dicts (for storage or logging)
dicts = handler.get_decisions_as_dicts()
print(f"Captured {handler.decision_count} decisions")
# Reset for next request
handler.clear()
CapturedDecision Fields
@dataclass
class CapturedDecision:
decision_id: str # UUID string
decision_type: str # "llm", "chain", "tool", "retriever"
function_name: str # model name or chain/tool class name
inputs: Dict[str, Any] # truncated input data
outputs: Dict[str, Any] # truncated output data
model_parameters: Dict[str, Any] # temperature, max_tokens, etc.
error: Optional[str] # set if the call raised an exception
started_at: Optional[datetime]
ended_at: Optional[datetime]
execution_time_ms: Optional[float]
parent_run_id: Optional[str] # parent chain run_id for nesting
engagement_id: str
workstream_id: str
tags: Dict[str, str] # merged from LangChain tags + metadata
token_usage: Optional[Dict[str, int]] # prompt/completion/total
context_version: Optional[str]
Capturing What Each Event Type Records
LLM calls (decision_type = "llm"):
inputs.promptsorinputs.messages— the prompt strings or chat messagesoutputs.text— the generated completion texttoken_usage—{"prompt_tokens": N, "completion_tokens": N, "total_tokens": N}model_parameters— temperature, max_tokens, top_p extracted from config
Chain events (decision_type = "chain"):
inputs— full chain input dict (keys depend on chain type)outputs— full chain output dictfunction_name— the chain class name (e.g.,"LLMChain","RetrievalQA")
Tool invocations (decision_type = "tool"):
inputs.input— the tool input stringoutputs.output— the tool output stringfunction_name— the tool name fromserialized["name"]
Retriever queries (decision_type = "retriever"):
inputs.query— the retrieval query stringoutputs.document_count— number of documents returnedoutputs.documents— list of{content_preview, metadata}dicts (200 char preview)
Advanced: Async Chains
The handler works with both sync and async LangChain invocations. For async, pass the same handler object:
result = await chain.ainvoke(
{"topic": "quantum computing"},
config={"callbacks": [handler]},
)
Advanced: Per-Request Context Versions
Set context_version to tag decisions with the knowledge version active
at request time:
handler = BriefcaseLangChainHandler(
engagement_id="my-project",
workstream_id="rag-pipeline",
context_version="knowledge-base-v2024-01",
)
All decisions from this handler instance will include
context_version = "knowledge-base-v2024-01".
Advanced: Export on Chain Completion
When a top-level chain ends (no parent run), the handler calls
_trigger_export which passes the full decision record (including child
spans) to the configured BriefcaseConfig.exporter.
To configure an exporter:
from briefcase.config import setup
from briefcase.exporters import SplunkHECExporter
setup(
exporter=SplunkHECExporter(
url="https://splunk.example.com:8088",
token="your-hec-token",
)
)
The export runs in a background daemon thread when async_capture=True
(the default), so it never blocks the calling thread.
Troubleshooting
No decisions captured: Confirm you passed the handler to both the LLM
and the chain's config={"callbacks": [...]}. LangChain propagates callbacks
downward, but not all chain types propagate automatically.
Missing token usage: Token usage is only available when the LLM response
includes llm_output.token_usage. This depends on your provider and model.
Handler not called: The handler uses duck-typing to avoid requiring
langchain-core at import time. If your LangChain version is older than 0.1.x,
verify the callback interface is compatible.
See Also
- Integrations Overview — comparison table
- End-to-End Workflow — LangChain + routing
- Infrastructure — Exporters — all export targets