How to Integrate LangGraph for banking with LangSmith for production AI
Combining LangGraph for banking with LangSmith gives you a production path for regulated AI agents: deterministic workflow control from LangGraph, plus traceability, debugging, and evaluation from LangSmith. That matters when your agent is handling things like KYC checks, loan pre-screening, payment disputes, or policy lookup where every step needs to be observable and auditable.
The practical win is simple: build the business logic as a graph, then instrument every node so you can see exactly what the agent did, what it saw, and where it failed.
Prerequisites
- •Python 3.10+
- •
langgraph - •
langchain-core - •
langsmith - •An LLM provider key set in your environment
- •A LangSmith account and API key
- •A LangSmith project created for this integration
- •Basic familiarity with Python async/sync functions
Install the packages:
pip install langgraph langchain-core langsmith
Set environment variables:
export LANGCHAIN_TRACING_V2=true
export LANGCHAIN_API_KEY="ls__your_key"
export LANGCHAIN_PROJECT="banking-agent-prod"
export OPENAI_API_KEY="your_openai_key"
Integration Steps
- •Create a banking workflow with LangGraph
Use LangGraph to model the agent as a state machine. For banking, keep the graph explicit: intake, policy check, decision, and response.
from typing import TypedDict
from langgraph.graph import StateGraph, END
class BankingState(TypedDict):
customer_id: str
request_type: str
risk_flag: bool
decision: str
def intake_node(state: BankingState) -> BankingState:
return state
def policy_check_node(state: BankingState) -> BankingState:
# Replace with real KYC/AML/risk rules
state["risk_flag"] = state["request_type"] in ["wire_transfer", "new_payee"]
return state
def decision_node(state: BankingState) -> BankingState:
state["decision"] = "manual_review" if state["risk_flag"] else "approved"
return state
graph = StateGraph(BankingState)
graph.add_node("intake", intake_node)
graph.add_node("policy_check", policy_check_node)
graph.add_node("decision", decision_node)
graph.set_entry_point("intake")
graph.add_edge("intake", "policy_check")
graph.add_edge("policy_check", "decision")
graph.add_edge("decision", END)
app = graph.compile()
- •Add LangSmith tracing through environment configuration
LangGraph runs on top of LangChain primitives, so once tracing is enabled with LANGCHAIN_TRACING_V2=true, your graph executions show up in LangSmith automatically. If you want explicit control over metadata, pass tags and run names when invoking.
result = app.invoke(
{
"customer_id": "cust_123",
"request_type": "wire_transfer",
"risk_flag": False,
"decision": ""
},
config={
"run_name": "banking-risk-workflow",
"tags": ["banking", "kyc", "prod"],
"metadata": {
"tenant": "retail-banking",
"environment": "production"
}
}
)
print(result)
This gives you trace-level visibility into each node execution in LangSmith.
- •Instrument individual nodes with LangSmith run context
For production systems, don’t rely only on graph-level traces. Add node-level metadata so you can debug specific policy decisions and branch behavior.
from langsmith import Client
client = Client()
def policy_check_node(state: BankingState) -> BankingState:
risk_reason = None
if state["request_type"] == "wire_transfer":
risk_reason = "wire transfer requires enhanced review"
state["risk_flag"] = True
elif state["request_type"] == "new_payee":
risk_reason = "new payee triggers fraud controls"
state["risk_flag"] = True
else:
state["risk_flag"] = False
client.create_run(
name="policy_check_audit",
run_type="tool",
inputs={"customer_id": state["customer_id"], "request_type": state["request_type"]},
outputs={"risk_flag": state["risk_flag"], "reason": risk_reason},
project_name="banking-agent-prod",
)
return state
Use this pattern for compliance-sensitive branches where auditors need a durable record beyond the default trace.
- •Wrap an LLM call inside a graph node and trace it
Most banking agents need an LLM for summarization or customer-facing responses. Keep the orchestration in LangGraph and the observability in LangSmith.
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
prompt = ChatPromptTemplate.from_messages([
("system", "You are a banking assistant. Keep responses concise and compliant."),
("human", "{message}")
])
def response_node(state: dict) -> dict:
message = (
f"Customer {state['customer_id']} request {state['request_type']} "
f"was {state['decision']}."
)
chain = prompt | llm
response = chain.invoke({"message": message})
state["final_response"] = response.content
return state
If tracing is enabled, this LLM call appears inside the same end-to-end run in LangSmith.
- •Run the full graph and verify traces in LangSmith
Now connect the response node into your graph and execute it with production-like inputs.
from typing import TypedDict
from langgraph.graph import StateGraph, END
class AppState(TypedDict):
customer_id: str
request_type: str
risk_flag: bool
decision: str
final_response: str
def intake_node(state: AppState) -> AppState:
return state
def policy_check_node(state: AppState) -> AppState:
state["risk_flag"] = state["request_type"] in ["wire_transfer", "new_payee"]
return state
def decision_node(state: AppState) -> AppState:
state["decision"] = "manual_review" if state["risk_flag"] else "approved"
return response_node(state)
graph = StateGraph(AppState)
graph.add_node("intake", intake_node)
graph.add_node("policy_check", policy_check_node)
graph.add_node("decision", decision_node)
graph.set_entry_point("intake")
graph.add_edge("intake", "policy_check")
graph.add_edge("policy_check", "decision")
graph.add_edge("decision", END)
app = graph.compile()
output = app.invoke(
{
"customer_id": "cust_123",
"request_type": "wire_transfer",
"risk_flag": False,
"decision": "",
"final_response": ""
},
config={
"run_name": "banking-agent-prod",
"tags": ["langgraph", "langsmith", "banking"]
}
)
print(output["decision"])
print(output["final_response"])
Testing the Integration
Run a simple smoke test that checks both graph execution and trace emission.
result = app.invoke(
{
"customer_id": "cust_999",
"request_type": "balance_inquiry",
"risk_flag": False,
"decision": "",
"final_response": ""
},
config={
"run_name": "__integration_test__",
"tags": ["smoke-test"]
}
)
assert result["decision"] == "approved"
assert isinstance(result["final_response"], str)
print("Integration test passed")
Expected output:
Integration test passed
In LangSmith, you should see a run named __integration_test__ with child spans for each node and any LLM calls made inside them.
Real-World Use Cases
- •
KYC triage agent
Use LangGraph to route customers through identity verification steps, then use LangSmith to inspect failures by branch, model prompt, or data source. - •
Fraud review assistant
Build a graph that scores transactions, escalates suspicious cases, and generates analyst summaries. Trace every decision path for auditability. - •
Policy-driven customer support
Route requests like chargebacks, card replacement, or wire limits through deterministic steps while using LangSmith to evaluate response quality across versions.
Keep learning
- •The complete AI Agents Roadmap — my full 8-step breakdown
- •Free: The AI Agent Starter Kit — PDF checklist + starter code
- •Work with me — I build AI for banks and insurance companies
By Cyprian Aarons, AI Consultant at Topiax.
Want the complete 8-step roadmap?
Grab the free AI Agent Starter Kit — architecture templates, compliance checklists, and a 7-email deep-dive course.
Get the Starter Kit