AI agents are getting better at answering questions. The challenge is getting them to help with real business workflows in a way people can follow, audit, and approve.
That was the theme of our recent webinar with LangChain. We looked at what it takes to build agents over enterprise content, where trust matters as much as the final output.
Key takeaways:
- Integrating LangChain with Box allows developers to build intelligent agents that leverage Box’s secure, governed content layer for real-world business workflows
- Your organization can keep business logic auditable and explainable by combining Box Extract for structured metadata retrieval with deterministic code for risk scoring
- And ensure critical actions pause for human approval before state changes are committed by using LangGraph’s checkpointing and human-in-the-loop interrupts
Christian Bromann from LangChain kicked things off by demoing an Enterprise Knowledge Assistant built with LangChain and Box. His demo showed a deep agent planning work, streaming progress, calling tools, using specialist subagents, and returning grounded answers over content stored in Box. You can check out Christian’s open source demo here.
For this post, I’ll focus on the second demo from the webinar: a Contract Review & Approval agent built with Box, LangChain Deep Agents, and LangGraph. The agent reviews a contract stored in Box, extracts key terms with Box AI, scores risk with deterministic code, writes metadata back to the file, and pauses for a human reviewer before it commits the final action.
The full demo repo is open source here: https://github.com/box-community/contract-review-agent
The workflow
At a high level, the demo follows this flow:
- A contract lives in Box
- The agent finds the contract with Box Search
- Box Extract pulls out structured contract terms
- LangChain Deep Agents orchestrates the workflow
- Deterministic code scores the contract risk
- LangGraph pauses the run for human approval
- After approval, the agent writes the results back to metadata on Box

The interesting part is how little custom glue is required. Box handles the content, permissions, AI extraction, and metadata. LangChain handles the agent orchestration. LangGraph handles checkpointing and human-in-the-loop control.
Box as the content layer
For the demo, I started with a folder of sample contracts in Box.

Box is the source of truth for the files. The contracts are already stored, permissioned, governed, and shareable. The agent works with that content through standard Box APIs.
The demo uses four Box capabilities:
- Box Search to find the right contract
- Box Extract to pull structured terms from the file
- Box metadata to store review results back on the file
- Box AI Ask to support follow-up questions about the contract
The metadata piece is especially important. After the agent extracts terms and scores risk, the results get written back onto the file in Box. That includes fields like status, risk level, counterparty, renewal date, and risk flags.

That makes the contract easier to work with downstream. Developers can query the metadata, sync it to another system, trigger a workflow, build a dashboard, or route the file for additional review.
The agent setup
The core agent definition is small:
export const agent = createDeepAgent({
model: buildModel(),
tools: [...readTools, ...actionTools],
subagents: buildSubagents(readTools),
systemPrompt: ORCHESTRATOR_PROMPT,
});This is LangChain’s createDeepAgent. I pass in a model, tools, subagents, and a system prompt. Deep Agents gives me the planning and multi-step orchestration.
The detail worth calling out is the split between readTools and actionTools:
- Read tools inspect or analyze content. Those can be shared with subagents.
- Action tools change something in Box or pause for a human. Those stay with the main agent.
That separation is deliberate. Specialist subagents can help research and analyze the contract, while the lead agent controls the steps that mutate state or require approval.
Wrapping Box APIs as LangChain tools
A tool is the bridge between the agent and Box. Here is the tool that extracts contract terms:
const extractContractTerms = tool(
async ({ fileId }: { fileId: string }) => {
const data = await getBoxService().extractStructured(
[fileId],
[...CONTRACT_FIELDS],
);
return `Extracted contract terms from fileId ${fileId}:\n${JSON.stringify(data, null, 2)}`;
},
{
name: "extract_contract_terms",
description:
"Use Box AI Extract to pull the standard set of key terms out of one contract file " +
"(counterparty, dates, renewal, liability cap, termination, value, data protection, etc.). " +
"Returns a JSON object. Run this before score_contract_risk.",
schema: z.object({
fileId: z.string().describe("The Box fileId of the contract to analyze."),
}),
},
);A LangChain tool has a few basic parts: the function, the name, the description, and the schema.
The function body here is short because the real work happens inside Box. The tool wraps that Box capability so the agent can decide when to use it.
The description and schema matter a lot. They tell the model what the tool does, when to call it, and what input it needs. In practice, writing a good tool means writing code and explaining the tool clearly enough for the model to use it correctly.
Extracting contract terms with Box AI
Under the hood, the extraction tool calls Box Extract through the Box Node SDK:
async extractStructured(
fileIds: string[],
fields: ExtractField[],
): Promise<Record<string, unknown>> {
const response = await this.client.ai.createAiExtractStructured({
items: fileIds.map((id) => ({ id, type: "file" as const })),
fields: fields.map((f) => ({
key: f.key,
displayName: f.displayName ?? f.key,
description: f.description,
prompt: f.prompt,
type: f.type ?? "string",
})),
});
return (response?.answer as Record<string, unknown>) ?? {};
}The app gives Box AI a file and a set of fields: counterparty, renewal date, liability cap, termination terms, contract value, data protection terms, and anything else the review needs.
Box AI reads the document server-side and returns structured key-value pairs.
That keeps the content close to where it already lives. The app does not need to build a separate ingestion pipeline just to understand the contract. Box stores the file, Box AI extracts the terms, and the agent uses those terms in the rest of the workflow.
The LLM extracts, the playbook decides
Once the agent has the contract terms, it scores risk.
That score comes from deterministic code:
function scoreRisk(terms: Record<string, unknown>): RiskResult {
const flags: string[] = [];
let score = 0;
const liabilityCap = String(terms.liability_cap ?? "").toLowerCase();
if (
yes(terms.liability_uncapped) ||
/uncapp|no cap|unlimited/.test(liabilityCap)
) {
score += 30;
flags.push("Uncapped or unlimited liability exposure");
} else if (!liabilityCap.trim()) {
score += 15;
flags.push("No liability cap found in the contract");
}
// ... more rules: auto-renewal, termination, value, data protection ...
return {
score,
flags,
level: score >= 60 ? "high" : score >= 30 ? "medium" : "low",
};
}This is intentionally boring code.
For legal, procurement, security, and compliance workflows, a risk score needs to be explainable. If a contract gets flagged as high risk, someone should be able to see which rule fired and why.
That is the pattern I like here:
The LLM extracts, the playbook decides.
Use the model to read messy documents and pull out structure. Keep business judgment in code that teams can inspect, test, and change.
Pausing for human approval
The final step is the human-in-the-loop gate.
Once an agent can update metadata, route a file, send a message, or commit a change, a human approval step becomes important. In this demo, the agent prepares a recommendation, then stops and waits.
That pause is handled with LangGraph’s interrupt:
// Pause the run and hand control to a human. The UI renders an approval
// card from this payload and resumes with the reviewer's decision.
const decision = interrupt({
type: "approval_request",
...payload,
}) as { decision?: string; note?: string } | string;In the UI, this becomes an approval card.

At that point, the agent has already found the contract, extracted the terms, scored the risk, and prepared the recommendation. Then it waits.
When the reviewer approves or rejects, the agent resumes from the same point with the reviewer’s decision as the return value. The run does not restart from the beginning.
That gives the workflow a durable approval checkpoint. The agent can help with the work, while a person still controls the moment where something gets committed.
Writing the result back to Box
As I mentioned, after approval, the agent writes the results back to Box metadata.
That can include:
- Review status
- Risk level
- Counterparty
- Renewal date
- Risk flags
- Approval decision

Now the review result lives with the contract itself. The file remains in Box, the metadata stays on the file, and the output can be searched, shared, synced, or used by another workflow.
This is where the demo starts to feel more like an enterprise workflow than some ephemeral chat experience. The agent produces durable output in the system where the team already manages the content.
What this pattern gives you
A few design choices make this workflow easier to trust:
- Ground the agent in governed content:The files and permissions live in Box; the agent works with the content it is allowed to access
- Show the work: LangChain and LangGraph can stream tool calls, progress updates, and intermediate steps so users can follow what the agent is doing
- Use AI for the fuzzy parts:Box Extract turns messy contract language into structured fields
- Keep business rules auditable:Risk scoring happens in deterministic code
- Pause before action:LangGraph checkpoints the run, waits for human input, and resumes after a decision
That combination is what makes the pattern useful for enterprise workflows. You get agentic orchestration, governed content, structured extraction, auditable logic, and human approval in one flow.
Try it yourself
Both demos from the webinar are open source:
You can also start with the Box developer docs used in the demo:
The takeaway: LangChain gives you the agent orchestration layer. Box gives you the governed content, AI, metadata, and permissions layer. With a small amount of glue between them, you can build agents that do more than answer questions — they can help teams complete real workflows while staying visible, auditable, and human-approved.
