LangGraph blueprint · Banking and fintech
Customer onboarding (KYC) with subgraphs
A LangGraph parent graph runs identity, address and sanctions-screening subgraphs in parallel, each with its own private state, then merges their results and either approves the applicant or pauses for a compliance analyst. It must never open an account when any check failed, was inconclusive or produced an unresolved sanctions hit.
- Steps
- 8
- Subjective questions
- 33
- Objective questions
- 33
The problem and the outcome
Problem: KYC checks are often handled by one tangled script or by manual hand-offs between teams. A single vendor timeout can lose progress, and auditors cannot see clearly why an applicant was approved.
Outcome: Each check becomes a separately testable subgraph, clean cases pass straight through, and every failed or doubtful case reaches an analyst with a summary. Durable checkpoints give a step-by-step record of how each decision was reached.
Architecture
How it works, step by step
- The applicant submits details and documents. The API starts a graph run on the parent StateGraph with thread_id set to the application ID, so every checkpoint and resume belongs to that one application.
- The intake node validates the input and writes the documents to encrypted object storage. It keeps only document references and minimal fields in state. Three edges from START-side intake fan out to the identity, address and sanctions wrapper nodes, which run in the same super-step.
- The identity subgraph has its own typed state for OCR output, face-match score, liveness result and retry count. It calls vendor APIs, retries transient failures inside the subgraph, and returns only a compact result object (status, reason codes, evidence refs) to the parent.
- The address subgraph matches proof-of-address data against the declared address. The sanctions subgraph screens the name and date of birth against sanctions and PEP lists and returns any potential hits with match details. Neither subgraph exposes its internal scratch state to the parent.
- The merge node is wired with add_edge from all three wrapper nodes, so it runs only after every branch finishes. The parent state key 'checks' uses a reducer (e.g. operator.add on a list), so parallel writes accumulate instead of conflicting. The Postgres checkpointer saves state at every super-step.
- A conditional edge on the merged checks routes the case. If all three are 'pass', it goes straight to account opening. Any 'fail', 'inconclusive', vendor error or sanctions hit goes to manual review, so the default path for anything unexpected is review.
- The review node first has an LLM draft a short case brief from the structured evidence only; the LLM summarises and never decides. The node then calls interrupt() with the brief. The run pauses durably until the analyst's decision arrives through Command(resume=...).
- The decision is applied: approve opens the account, reject closes the application with reason codes, and 'request more' uses Command(goto=..., update=...) to re-run only the affected subgraph. get_state_history on the thread gives the audit trail of every step.
Tech stack
- LangGraph StateGraph with compiled subgraphs
- PostgresSaver checkpointer (InMemorySaver in local tests)
- PostgreSQL for application records and audit
- Encrypted object storage for identity documents
- Licensed KYC vendor APIs for OCR, face match and list screening
- LLM for analyst case briefs only
- LangSmith tracing and Agent Server deployment
Key design decisions
- Each check is a subgraph with its own state schema, invoked from a wrapper node that maps parent state in and a compact result out. This keeps vendor scratch data and retries private and lets each team test its subgraph alone.
- Routing is fail-closed: only an explicit 'pass' from all three checks reaches auto-approval. Errors, timeouts and unknown statuses go to manual review.
- Raw documents and biometric data stay in the vault; graph state and checkpoints hold references and results only. This limits personal data in checkpoint tables and eases retention rules.
- Human review lives in the parent graph with interrupt(), not inside a subgraph. One review point sees all merged evidence and the resume contract stays simple.
- The LLM is limited to summarising structured evidence for analysts. Match decisions come from deterministic rules and vendor scores so outcomes can be explained to regulators.
Common mistakes
- Writing to the same state key from three parallel branches without a reducer raises an update conflict. Declare a reducer on 'checks' or give each check its own key.
- When a node resumes after interrupt(), it re-runs from the start. Any side effect before the interrupt, such as calling a vendor or sending a notification, must be idempotent or moved into an earlier node.
- Letting an LLM decide whether a sanctions hit is a true match creates unexplainable outcomes. Keep it to summarising evidence for the analyst.
- Reusing a thread_id across applications mixes checkpoints and can resume the wrong case. Derive it from the unique application ID.
- Putting full document images or OCR dumps in state bloats every checkpoint and copies personal data into many rows. Store references instead.
What to measure
- Straight-through approval rate (share of applications with no manual review)
- Manual review rate split by trigger: identity, address, sanctions or vendor error
- Time to decision, p50 and p95, for auto and reviewed cases
- Sanctions false-positive rate as confirmed by analysts
- Runs resumed successfully after a crash or vendor outage versus runs restarted
Most-asked interview questions
Subjective questions 33
1Why model identity, address and sanctions as subgraphs with their own state instead of one flat graph?Asked almost every time
Each check has different internals. Identity tracks OCR fields, face scores and retries, while sanctions tracks candidate hits and match scores. Putting all of that in one parent state makes every node see every field, invites accidental overwrites and makes the schema hard to change. As subgraphs, each check gets its own typed state and a narrow contract: the wrapper node passes in references and gets back a status, reason codes and evidence refs. Teams can unit test a subgraph on its own, swap a vendor without touching the parent, and run the three in parallel in one super-step. The parent stays small. It handles intake, merge, routing and review, and that is what auditors and reviewers mostly read.
Sourced from Docs by LangChain (MCP)
2Walk me through this KYC onboarding workflow end to end, from submission to the final decision.Asked almost every time
The API starts a run on the parent StateGraph with thread_id set to the application ID. Intake validates the input, stores documents in encrypted object storage and keeps only references in state. It then fans out to three wrapper nodes for identity, address and sanctions, which run in the same super-step. Each wrapper invokes a subgraph with private state and returns a compact result into a 'checks' list that uses a reducer. Merge runs after all three finish. A conditional edge sends the case to account opening only if every check is 'pass'. Everything else goes to review, where an LLM drafts a brief, interrupt() pauses the run, and the analyst's Command(resume=...) decides approve, reject or request more. The Postgres checkpointer records every step.
Sourced from Docs by LangChain (MCP)
3Why does the intake node keep only document references and minimal fields in graph state instead of the documents themselves?Asked almost every time
The checkpointer saves state at every super-step, and every saved copy lives in the checkpoint tables. Putting passport scans or selfies in state would copy sensitive personal data into many rows. That bloats storage, slows reads and writes, and makes deletion and access control much harder. Keeping the files in encrypted object storage and passing only references means the binary data sits in one place, with its own encryption, access policies and retention. Subgraphs fetch the files by reference when they need them. State stays small, checkpoints stay cheap, and the audit trail can still point to the exact evidence used. The same rule applies to vendor responses: store a summary and an evidence reference, not the raw payload.
Sourced from Docs by LangChain (MCP)
4How do you write the routing condition after merge so the system fails closed?Asked almost every time
The routing function should check for the one safe case, not list the bad ones. It returns 'open_account' only if there are exactly three checks, one each for identity, address and sanctions, every status equals 'pass', and the sanctions result has no hits. Any other situation returns 'review'. That covers a missing check, a duplicate, an unknown status string, a vendor error, a schema mismatch, or a sanctions hit. I also give the conditional edge an explicit path map, so only these two destinations are possible. Then a new status value added by a vendor update cannot open an account by accident. Unit tests cover each bad combination and confirm that only the all-pass case reaches account opening.
Sourced from Docs by LangChain (MCP)
5Why is the LLM only allowed to summarise, and how do you keep its case brief trustworthy?Asked almost every time
Approving a KYC case is a regulated decision. It must be deterministic, explainable and owned by a person or by fixed rules, not by a probabilistic model. So routing is plain code, and the analyst makes the review decision. The LLM only turns structured evidence into readable text. To keep the brief trustworthy, I pass it only the compact check results and reason codes, not raw documents. I ask for a fixed structure that cites the evidence refs. The analyst UI shows the brief next to the underlying structured data, so the analyst decides from facts, not prose. I log the prompt and model version, and I never parse the brief for a decision. If the LLM call fails, review still proceeds without a brief.
Sourced from Docs by LangChain (MCP)
6How do you make the account-opening step safe if it is retried or the process crashes mid-call?Asked almost every time
Opening an account is an external side effect, and a crash can happen after the core banking call succeeds but before the checkpoint is saved. On resume, the node runs again. So the core banking API must be called with an idempotency key derived from the application ID. A repeat call then returns the existing account instead of creating a second one. Before calling, the node can also look up whether an account already exists for this application. I keep this node small, one external call plus recording the result, so that re-running it is cheap and safe. The account number is written to state and to the application record. If the banking system returns an ambiguous error, the case goes to an operations queue, not to a blind retry.
Sourced from Docs by LangChain (MCP)
7How do you implement manual review so it survives restarts and does not repeat side effects?Very often asked
Review sits in a parent-graph node that calls interrupt() with the case brief and the merged evidence. Because we compile with a Postgres checkpointer and use the application ID as thread_id, the paused state is durable. A deploy or crash does not lose it, and the analyst can respond hours later. Their decision comes back through Command(resume=...). The key detail is that a resumed node runs again from the top. So I keep anything with side effects, such as generating the LLM brief or notifying the analyst queue, either idempotent with a stored key or in a separate node before review. After resume, a conditional route or Command(goto=...) applies approve, reject or re-run a single check.
Sourced from Docs by LangChain (MCP)
8How do you make this workflow auditable for a regulator?Very often asked
First, decisions come from deterministic rules over structured results, not from an LLM. The LLM only writes a summary for the analyst. Second, every super-step is checkpointed per thread, so get_state_history shows exactly which checks ran, what they returned, how the router branched and who resumed the review with what decision. I also write a separate append-only audit record in Postgres with reason codes, vendor reference IDs and analyst identity, because checkpoints follow retention rules and are not designed as the system of record. Third, state holds document references rather than images, so the audit trail can be shared without exposing unnecessary personal data. LangSmith traces help with debugging, but the audit table is what we show externally.
Sourced from Docs by LangChain (MCP)
9Why use the application ID as the thread_id, and what happens if the applicant submits the same application twice?Very often asked
The thread_id is the key the checkpointer uses to store state. Using the application ID ties every checkpoint, interrupt and resume to exactly one application, and that gives a clean audit trail. If the client retries the submit call, the API should check whether a thread for that ID already exists. If it does, return the current status instead of starting a new run on the same thread. Starting fresh input on an existing thread could restart the run and repeat vendor calls. I enforce this with a unique constraint on application ID in the application table, and the API treats submit as idempotent. A genuinely new application from the same person gets a new ID and thread, and duplicate-person detection is handled separately.
Sourced from Docs by LangChain (MCP)
10Where should retries live: inside the subgraph, as a node RetryPolicy, or in the parent graph?Very often asked
Transient failures such as timeouts, 429s and 5xx responses should be retried close to the call. That can be logic inside the subgraph, or a RetryPolicy on the node that calls the vendor, with backoff and a small maximum number of attempts. The subgraph tracks its retry count in its private state so the parent never sees that noise. Permanent failures, such as an unreadable document or a rejected request, should not be retried. They become a result with status 'inconclusive' or 'fail' and a reason code. When retries run out, the subgraph returns a vendor-error result, and the parent routes that case to review. The parent graph should only see final outcomes, not retry mechanics.
Sourced from Docs by LangChain (MCP)
11When 'request more' re-runs only the address subgraph, what goes wrong with an operator.add reducer on 'checks', and how do you fix it?Very often asked
operator.add only appends. After a re-run, 'checks' holds two address results: the old 'inconclusive' one and the new one. A naive router might see conflicting entries, or count four checks and fail. The fix is a custom reducer that merges results by check type, so the latest result for 'address' replaces the earlier one. Each result should carry an attempt number and a timestamp. That way the full history still exists in the checkpoints for audit, while the current state shows one authoritative result per check. The router then checks for exactly one result per type. An alternative is to keep the append-only list and have the router select the latest attempt per type, but the keyed reducer is simpler to reason about.
Sourced from Docs by LangChain (MCP)
12How does the merge node know all three branches finished, and what if one branch hangs?Very often asked
All three wrapper nodes run in the same super-step, and each has an edge to merge. LangGraph runs merge in the next super-step, after every node in the current step has finished. So merge always sees all three writes. The risk is a branch that never returns, for example a vendor call with no timeout, which would block the whole super-step. Every external call therefore needs a strict client timeout, and every subgraph needs a bound on total attempts. When a limit is hit, the subgraph returns a 'vendor_error' or 'inconclusive' result instead of raising forever. If the process dies mid-step, the checkpointer lets the run resume. Completed writes from other branches in that step can be kept, so only the unfinished work re-runs.
Sourced from Docs by LangChain (MCP)
13The sanctions screening vendor is down for an hour. How does the system behave?Very often asked
The sanctions subgraph retries with backoff up to its limit, then returns a result with status 'vendor_error' and a reason code. The router treats it as not passed and sends the case to review. No account opens without a completed screening. If an analyst cannot clear a case without a screening result, they can choose 'request more' to re-run just the sanctions subgraph once the vendor recovers. For a long outage, sending every case to an analyst wastes effort. A better option is a deferred-retry state: the case is parked and automatically re-runs the sanctions branch later, while staying blocked. A circuit breaker avoids hammering the vendor. A dashboard alert on vendor error rate tells operations what is happening.
Sourced from Docs by LangChain (MCP)
14Before calling Command(resume=...) with an analyst's decision, what must the API check?Very often asked
First, authentication and authorisation. The caller must be an analyst with permission for this case type, and for sanctions hits possibly a senior role. Second, separation of duties: the analyst should not be linked to the applicant, and some cases may need a second approver. Third, check that the thread is actually paused at the review interrupt, using get_state, so a stale or duplicate request cannot resume the wrong step. Fourth, validate the payload against a strict schema: a decision from a fixed set, required reason codes for reject, a target check for 'request more', and a non-empty justification. The analyst ID and timestamp go into the resume payload, so the decision is recorded in state and in the checkpoint history.
Sourced from Docs by LangChain (MCP)
15How do you reconcile data-protection duties such as deletion and minimisation with the need to keep KYC records for audit?Very often asked
Under India's DPDP Act, organisations should collect only what they need and delete it when it is no longer required. But financial regulation, such as RBI's KYC directions, requires some records to be kept for a set period. Legal and compliance teams define the retention schedule. Engineering makes it enforceable. Minimisation starts in the design: state holds references and compact results, not documents or raw vendor payloads. I sort data into classes: documents in object storage, decision records, and checkpoints. Each class gets its own retention rule and lifecycle policy. Checkpoints for completed threads can be pruned or archived once a durable decision record exists. Personal fields can be encrypted or tokenised. Access to everything is logged.
Sourced from Docs by LangChain (MCP)
16How would you test this graph before it touches real applicants?Very often asked
Unit-test each node and each routing function as plain functions. The router especially needs table-driven tests, where every combination of pass, fail, inconclusive, vendor error and sanctions hit must end in review unless all three pass. Test subgraphs on their own with mocked vendor clients, including timeouts, retries and malformed responses. Run integration tests of the full parent graph with InMemorySaver, and confirm that interrupt pauses the run and that Command(resume=...) with each decision reaches the right node. Add a crash test: kill the run mid-step, resume on the same thread, and confirm no duplicate account and no duplicate vendor charge. Use synthetic identities only. Before rollout, run shadow tests against a vendor sandbox.
Sourced from Docs by LangChain (MCP)
17Why not build this as a supervisor multi-agent system where an LLM decides which check to run next?Very often asked
KYC has a fixed, known process, and regulators expect it to be the same for every applicant. A supervisor pattern lets an LLM choose the next step, which adds variability, cost and delay, and makes it harder to prove that every check always ran. An explicit StateGraph gives a fixed path: all three checks always run, and routing is plain code anyone can read and test. Multi-agent patterns suit open-ended tasks where the steps are not known in advance. I would use an LLM only where language helps, such as the analyst brief or classifying a free-text document type, and always inside a node whose output is checked by code.
Sourced from Docs by LangChain (MCP)
18Two analysts open the same case and both submit a decision at nearly the same time. How do you prevent a double resume?Very often asked
Prevent it before it reaches the graph. The work queue assigns each case to one analyst through an atomic claim, for example a conditional update on the case row, and other analysts see it as locked. The resume API then checks that the caller holds the claim and that the thread is still waiting at the review interrupt. It sends Command(resume=...) only inside a lock keyed by the application ID, such as a database advisory lock or a status update from 'pending' to 'deciding'. The second request finds the case already decided and is rejected with a clear message. Both attempts are logged. The account-opening idempotency key is a last line of defence.
Sourced from Docs by LangChain (MCP)
19You need to change the graph, for example adding a new check, while thousands of threads are paused at review. How do you deploy safely?Very often asked
Paused threads resume against whatever graph code is deployed, so changes must be backward compatible. Additive changes are safest: new optional state keys with defaults, and new nodes that old threads never reach. Renaming or removing the review node, or changing the resume payload schema, can break paused threads. I would put a graph version in state at intake. For incompatible changes, I would keep both versions deployed and route each thread to the version it started on, until the old threads drain. A new mandatory check must not silently apply to cases that are already decided. Compliance decides whether in-flight cases need it, and the router enforces that policy by version.
Sourced from Docs by LangChain (MCP)
20Give a back-of-envelope estimate of checkpoint load for this workflow. State your assumptions.Often asked
These numbers are assumptions for illustration, not benchmarks. Suppose 50,000 applications a day. The happy path has roughly five super-steps in the parent: intake, the parallel checks, merge, routing to account opening, and finish. Subgraphs add their own internal steps, perhaps five to ten more. So I'd budget about 15 checkpoint writes per application, around 750,000 a day, or under 10 per second on average. Peak traffic could be five to ten times higher. If state stays small, a few kilobytes, that is a modest load for a properly indexed Postgres. The real cost drivers are state size and retention, which is why documents stay out of state. I would load-test with realistic state sizes before committing to a number.
Sourced from Docs by LangChain (MCP)
21Why InMemorySaver in development but a Postgres checkpointer in production?Often asked
InMemorySaver keeps checkpoints in process memory. It is fast and needs no setup, which is fine for tests and notebooks, but everything is lost when the process restarts. It also cannot be shared across workers. KYC cases may pause for hours or days while waiting for an analyst, and they must survive deployments, crashes and scaling events. A Postgres checkpointer stores state durably, so any worker can resume a thread, and the history supports audit and time travel. In production I also plan for connection pooling, indexes, a retention policy for old checkpoints within regulatory limits, backups, and encryption at rest, because checkpoints still contain personal fields such as name and date of birth.
Sourced from Docs by LangChain (MCP)
22Which streaming modes would you use for the applicant status page and for the analyst console?Often asked
The applicant only needs coarse progress, such as 'checks running', 'under review' or 'approved'. I would stream 'updates' from the parent graph and map node names to friendly statuses, or emit 'custom' events with exactly the text we want to show. I would never stream raw state to the applicant, because it can contain reason codes or sanctions details they should not see. The analyst console can use 'updates' with subgraph output enabled, to show which check is running, and 'messages' to stream the LLM brief token by token. 'debug' is for engineers, not production users. Clients usually poll or subscribe through the API layer, which also enforces access control.
Sourced from Docs by LangChain (MCP)
23A customer passed sanctions screening last month, and today they appear on an updated list. Does this workflow handle that?Often asked
No. This graph screens once at onboarding. Ongoing monitoring is a separate process. I would build a separate scheduled or event-driven job that re-screens the existing customer base when lists change, or at a regular interval. It could reuse the sanctions subgraph as a component, since subgraphs compose cleanly, but it would run under its own thread per monitoring case. A hit there creates a new review case with its own interrupt and analyst decision, and links to the original application for context. Keeping onboarding and monitoring separate stops completed onboarding threads from being reopened, and gives each process its own audit trail. Exact screening frequency is a compliance policy decision, not an engineering one.
Sourced from Docs by LangChain (MCP)
24How would you use time travel to investigate a case that was routed wrongly?Often asked
Call get_state_history on the application's thread and find the checkpoint just after merge. It shows the exact 'checks' values the router saw, and the next node it chose. Usually that shows whether the bug was in a subgraph's result or in the routing logic. To test a fix, I would work on a copy of the state in a separate debugging thread or environment, replay from that checkpoint, or fork it with update_state to try different inputs. I would not fork the production thread and re-run side-effecting nodes such as account opening. Time travel is a powerful diagnostic tool, but the production history should remain an accurate record of what actually happened.
Sourced from Docs by LangChain (MCP)
25Why use three fixed edges here rather than Send objects for the fan-out?Often asked
Send is meant for map-reduce over a list whose length is known only at run time, for example screening each of a variable number of company directors. It sends one node per item, each with its own input. Here there are always exactly three different checks, each with its own subgraph and schema, so static edges from intake are simpler. They are visible in the graph diagram and easy to review for compliance. Send would hide the structure without adding anything. If the product expanded to business onboarding with many beneficial owners, I would use Send inside the sanctions subgraph to screen each person in parallel, with a reducer collecting their hits.
Sourced from Docs by LangChain (MCP)
26Who decides the face-match threshold that separates 'pass' from 'inconclusive', and how is that reflected in the design?Often asked
The threshold is a risk decision owned by compliance and the fraud team, informed by vendor guidance and our own data on false accepts and false rejects. Engineering should not hard-code it. I keep thresholds in versioned configuration, and the identity subgraph records the threshold version it used in its result object. Then every decision can be traced to the rule that applied at the time. A score near the boundary should give 'inconclusive', not a forced pass or fail, so the case goes to an analyst. Threshold changes go through change control, and I would test a new threshold on historical outcomes before turning it on.
Sourced from Docs by LangChain (MCP)
27A case can wait days for an analyst. How do you manage SLAs and escalation for paused threads?Often asked
The interrupt itself is durable, because the paused state is stored in Postgres and costs nothing while waiting. But the graph does not track time. So the review node also writes a case record into a work-queue table with a priority, a due time and the thread_id. A scheduler watches due times and escalates overdue cases, reassigns them, or notifies a supervisor. Sanctions hits get higher priority. The applicant status page shows 'under review'. If a case must expire, for example because documents went stale, an expiry job resumes the thread with a controlled 'expire' decision, so the outcome is still recorded in the graph history, not changed outside it.
Sourced from Docs by LangChain (MCP)
28How can engineers debug inside a subgraph without exposing its private state to the parent or to applicants?Often asked
Subgraph state is saved with the checkpointer, but it stays separate from the parent's keys. Engineers with access can inspect it using get_state with subgraphs=True, or stream with subgraph output enabled, to see OCR output, face-match scores and retry counts at the point of failure. Only the compact result crosses into parent state. Access to these views goes through internal tools with role-based permissions and audit logging, never through the applicant API. Sensitive internal fields, such as extracted ID numbers, should be masked or kept as references even in subgraph state. That way debugging data is never more sensitive than it needs to be.
Sourced from Docs by LangChain (MCP)
29What would you monitor in production for this workflow?Often asked
Monitor business metrics and system metrics together. Business: share of cases auto-approved versus sent to review, review reasons by type, time from submission to decision, analyst queue depth and age, and approve, reject and request-more rates. A sudden rise in auto-approvals is as alarming as a rise in failures. System: vendor latency and error rates per subgraph, retry counts, timeouts, checkpoint write latency, run failure rate, count of stuck threads, and LLM brief failures. Tracing in LangSmith helps follow a single run across subgraphs. Alerts go to the right owners. Traces and logs must mask personal data.
Sourced from Docs by LangChain (MCP)
30If volume grew ten times, what would you change in this design?Often asked
The graph structure would stay the same. The infrastructure around it would change. I would run more graph workers behind a task queue, so submissions are accepted quickly and processed asynchronously. I would tune Postgres with connection pooling, read replicas for status queries and history, and partitioning or archiving of old checkpoints. Vendor rate limits usually become the bottleneck first, so I would add per-vendor concurrency limits, circuit breakers and possibly a second sanctions provider. The analyst queue would need staffing or better automation, for example tuning the screening setup to cut false-positive sanctions hits, which compliance must approve. The fail-closed routing would not be relaxed to save analyst time.
Sourced from Docs by LangChain (MCP)
31Would you use a LangGraph Store in this workflow? What would and wouldn't go in it?Sometimes asked
A Store gives memory shared across threads, organised by namespace. It could hold non-personal knowledge useful to many cases. Examples are analyst notes on recurring vendor quirks, reason-code explanations, or summaries of past false-positive sanctions patterns. The brief-drafting node could search these. I would not put applicant personal data there, because it would create a second copy outside the per-application retention and access model. Cross-application facts, such as 'this document number was used before', belong in a proper indexed database built for fraud checks, not in agent memory. If I used a Store, it would be PostgresStore with namespaces like ('kyc', 'playbook') and clear ownership.
Sourced from Docs by LangChain (MCP)
32If you deploy on LangSmith's Agent Server, which also exposes an MCP endpoint at /mcp, what security concerns arise?Sometimes asked
Agent Server exposes the graph over an API, and the /mcp endpoint lets MCP clients call deployed agents as tools. For a KYC workflow that is a serious exposure risk. Anyone who can call it could start runs or try to resume interrupts. I would put the server behind our own authentication and network controls, and allow only the backend service to start runs and only the analyst service to resume. I would disable or tightly restrict MCP access unless there is a reviewed use case. Even then I would offer only narrow, read-only operations. Secrets for vendor APIs stay in a secret manager. Tenant and role checks happen in our layer, not in the client.
Sourced from Docs by LangChain (MCP)
33How would you detect that the same person or document is used across multiple applications?Sometimes asked
That is a cross-application check, so it cannot live in one thread's private state. I would add a duplicate-detection step, either as a fourth parallel check or inside the identity subgraph. It looks up a keyed hash of the document number, plus device or contact signals where policy allows, in an indexed table of previous applications. A match is not an automatic rejection. It returns 'inconclusive' with a reason code and a reference to the linked application, and the case goes to review. Using a keyed hash instead of the raw number limits exposure. The table follows the same retention rules as the rest of the KYC data.
Sourced from Docs by LangChain (MCP)
Objective questions 33
1Which LangGraph mechanism pauses the run for a compliance analyst and then continues it with their decision?Asked almost every time
Why: interrupt() pauses a node and saves state through the checkpointer. Invoking the graph again with Command(resume=...) on the same thread_id continues from that point with the analyst's value.
Sourced from Docs by LangChain (MCP)
2Which routing rule correctly implements the fail-closed requirement after merge?Asked almost every time
Why: Only the single known-safe case may open an account. Every unexpected or incomplete state defaults to review.
Sourced from Docs by LangChain (MCP)
3Why is thread_id set to the application ID?Asked almost every time
Why: The checkpointer stores and loads state per thread_id, so the application ID ties all of an application's history together.
Sourced from Docs by LangChain (MCP)
4The sanctions subgraph uses a state schema with no keys in common with the parent graph. How should it be added to the parent?Very often asked
Why: A compiled subgraph added directly as a node communicates through shared state keys. When the schemas differ, you call the subgraph from a wrapper node and map state in and out explicitly.
Sourced from Docs by LangChain (MCP)
5Identity, address and sanctions wrapper nodes all append to the parent key 'checks' in the same super-step. What makes this work correctly?Very often asked
Why: Without a reducer, concurrent updates to one key in a super-step conflict. A reducer like operator.add combines the list updates from all branches.
Sourced from Docs by LangChain (MCP)
6Two parallel nodes write to a state key that has no reducer in the same super-step. What happens?Very often asked
Why: Without a reducer, LangGraph cannot merge several writes to one key in a single step and raises an InvalidUpdateError.
Sourced from Docs by LangChain (MCP)
7What should intake put in graph state for uploaded passport images?Very often asked
Why: Checkpoints copy state at every super-step, so state should hold references, not documents.
Sourced from Docs by LangChain (MCP)
8After an analyst's Command(resume=...), where does execution continue in the review node?Very often asked
Why: On resume LangGraph re-runs the interrupted node from its start. The interrupt() call then returns the resume value instead of pausing.
Sourced from Docs by LangChain (MCP)
9Given that the review node re-runs from its start on resume, what is a consequence for this design?Very often asked
Why: Code before interrupt() runs again on resume, so drafting the brief in a separate earlier node, or caching it, avoids a repeat LLM call.
Sourced from Docs by LangChain (MCP)
10Can interrupt() be used in a graph compiled without a checkpointer?Very often asked
Why: Human-in-the-loop pausing relies on persisted checkpoints to resume later.
Sourced from Docs by LangChain (MCP)
11Merge has edges from all three wrapper nodes, which ran in the same super-step. When does merge run?Very often asked
Why: Nodes in one super-step finish together, and merge is scheduled once for the following step.
Sourced from Docs by LangChain (MCP)
12'request more' re-runs only the address subgraph, and 'checks' uses operator.add. What is the risk?Very often asked
Why: operator.add only appends, so a keyed latest-wins reducer, or attempt-aware routing, is needed.
Sourced from Docs by LangChain (MCP)
13What role does the LLM play in this workflow?Very often asked
Why: The LLM only summarises. Routing is code and the review decision belongs to the analyst.
Sourced from Docs by LangChain (MCP)
14How should the account-opening node protect against creating two accounts if it re-runs after a crash?Very often asked
Why: A node can re-run after partial completion, so the external call itself must be idempotent.
Sourced from Docs by LangChain (MCP)
15Two analysts submit decisions for the same case at once. What is the best protection?Very often asked
Why: An exclusive claim plus a state check ensures only one decision resumes the run.
Sourced from Docs by LangChain (MCP)
16What is the main risk when deploying a new graph version while many threads are paused at review?Very often asked
Why: Resumes run the deployed code, so changes must be backward compatible or versioned.
Sourced from Docs by LangChain (MCP)
17Why must every vendor call in a subgraph have a strict timeout?Very often asked
Why: Merge waits for every branch, so a single unbounded call stalls the whole application.
Sourced from Docs by LangChain (MCP)
18Which checkpointer is appropriate for production KYC cases that may pause for days?Often asked
Why: Durable pauses that survive restarts and can be resumed by any worker need persistent storage such as Postgres.
Sourced from Docs by LangChain (MCP)
19Which mechanism lets the review node route to a specific subgraph wrapper and update state in one return value?Often asked
Why: Command combines a routing target with a state update from inside a node.
Sourced from Docs by LangChain (MCP)
20What is the best default treatment of an 'inconclusive' face-match result?Often asked
Why: The rules forbid opening an account on an inconclusive check, and an analyst should make the call.
Sourced from Docs by LangChain (MCP)
21The sanctions vendor times out on every retry. What should the subgraph return?Often asked
Why: An absent screening is not a clear result. Returning an explicit error keeps the system fail-closed.
Sourced from Docs by LangChain (MCP)
22Which call returns the sequence of checkpoints for an application, for audit or debugging?Often asked
Why: get_state_history lists the saved checkpoints of a thread.
Sourced from Docs by LangChain (MCP)
23Why use three static edges instead of Send for the fan-out?Often asked
Why: Send suits a variable-length map over items. Here there are always exactly three distinct checks.
Sourced from Docs by LangChain (MCP)
24Screening a variable number of company directors in parallel inside the sanctions subgraph is a good fit for…Often asked
Why: Send fans out one node invocation per item, which is the map-reduce pattern.
Sourced from Docs by LangChain (MCP)
25Which stream mode streams LLM tokens with node metadata, for example the brief appearing in the analyst console?Often asked
Why: 'messages' streams LLM tokens along with metadata about the node that produced them.
Sourced from Docs by LangChain (MCP)
26Which stream mode emits only the state changes made by each node?Often asked
Why: 'updates' emits per-node deltas, while 'values' emits the full state after each step.
Sourced from Docs by LangChain (MCP)
27How can an authorised engineer view a subgraph's internal state for a paused or failed run?Often asked
Why: Subgraph state is checkpointed and can be inspected with get_state(config, subgraphs=True).
Sourced from Docs by LangChain (MCP)
28What is a suitable use of a PostgresStore in this workflow?Often asked
Why: Stores hold cross-thread memory. Applicant personal data should stay in the per-application stores with their own retention rules.
Sourced from Docs by LangChain (MCP)
29Where should transient vendor retries be handled?Often asked
Why: Retries belong near the failing call, and the parent only sees the final outcome.
Sourced from Docs by LangChain (MCP)
30Which option best illustrates forking during time travel?Often asked
Why: update_state applied to a past checkpoint forks a new branch of execution from that point.
Sourced from Docs by LangChain (MCP)
31A sanctions hit that the screening vendor marks as a possible false positive should…Often asked
Why: Any unresolved sanctions hit must not open an account, and resolving it is the analyst's decision.
Sourced from Docs by LangChain (MCP)
32What is the key security concern with the Agent Server's /mcp endpoint for this workflow?Sometimes asked
Why: The MCP endpoint exposes agents as tools, so access must be locked down for a regulated workflow.
Sourced from Docs by LangChain (MCP)
33Why does the identity result record the threshold-configuration version it used?Sometimes asked
Why: Versioned thresholds make decisions explainable and auditable after rules change.
Sourced from Docs by LangChain (MCP)
Track your progress through every blueprint in your dashboard.
Start learning