How to Build a BFF Agent with LangGraph: A Step‑by‑Step Guide
This article walks through integrating an AI‑powered Agent into an internal BFF platform using LangGraph, detailing the architectural choices, state‑graph implementation, prompt engineering, knowledge‑base construction, tool integration, conversation handling, and context compression techniques to enable reliable script generation, execution, and validation.
Background
The Odyssey R&D platform is an internal TQL‑based development environment where developers write BFF (Backend‑for‑Frontend) GraphQL scripts. Inspired by recent AI coding tools such as Cursor and Claude‑Code, the author set out to add an Agent that can assist developers in writing, editing, and validating TQL scripts.
Technical Selection
Three integration approaches were considered: a simple conversational Agent, a full‑stack UI plugin, and embedding the Agent inside the host page via an iframe. The third option was chosen to maximise user experience and development efficiency.
Architecture Overview
The host page exposes script content, request parameters, debugging results, and tool interfaces to the Agent. The Agent perceives this context, calls backend services, and pushes actions (e.g., edit script, execute script) back to the host.
State Graph Implementation
A LangGraph state graph is defined with two main nodes – agent and tools – and conditional edges that route to tools when the LLM returns tool calls, otherwise to END. The graph is compiled into an executable agent.
import { StateGraph, END, START } from '@langchain/langgraph';
// Create state graph
const agentGraph = new StateGraph({
channels: {
messages: {
reducer: (prev, next) => [...prev, ...next],
default: () => [],
},
},
});
// Agent node
agentGraph.addNode('agent', async (state) => {
const response = await model.invoke(state.messages);
return { messages: [response] };
});
// Tools node
agentGraph.addNode('tools', async (state) => {
const lastMsg = state.messages[state.messages.length - 1] as AIMessage;
const toolMessages = [];
for (const toolCall of lastMsg.tool_calls || []) {
const result = await tools.find(t => t.name === toolCall.name).invoke(toolCall.args);
toolMessages.push(new ToolMessage({ content: result, tool_call_id: toolCall.id }));
}
return { messages: toolMessages };
});
// Edges
agentGraph.addEdge(START, 'agent');
agentGraph.addEdge('tools', 'agent');
agentGraph.addConditionalEdges('agent', (state) => {
const lastMsg = state.messages[state.messages.length - 1] as AIMessage;
return lastMsg.tool_calls?.length > 0 ? 'tools' : END;
}, { tools: 'tools', [END]: END });
// Compile graph
const graph = agentGraph.compile();Prompt Engineering
The Agent’s system prompt defines a role for a “small D” assistant that only knows TQL, along with a series of XML‑styled instructions to guide behavior, role‑setting, few‑shot examples, and positive‑example emphasis.
<role>You are 小 D, a professional TQL script assistant. You only write TQL syntax.</role>
<instructions>
<instruction>You lack deep TQL knowledge but have many internal tools to help.</instruction>
<instruction>When uncertain, query the system tools for clarification.</instruction>
<instruction>Respond in a professional, friendly, and structured Markdown format.</instruction>
<instruction>Ensure correct TQL syntax and clear query structure.</instruction>
</instructions>Knowledge Base Construction
RAG is used to store three categories of knowledge: popular online scripts (top‑100), internal directives and global functions, and server‑side code snippets. Scripts are split into individual documents, indexed, and imported into the internal kbase platform for fast retrieval.
Tool Integration
Two groups of tools are exposed to the Agent:
Remote (MCP) tools : kbase MCP server and deepwiki MCP server for knowledge retrieval.
Local tools : editScript – Update the GraphQL/TQL script content. editVariables – Modify the JSON variables used by the script. executeScript – Trigger script execution on the frontend. validateResult – Verify execution results and return structured feedback.
Conversation Management
Each user session receives a sessionId stored in Tair. The Agent’s SSE endpoint streams partial messages to the UI while persisting the full message list. When a UI‑only tool is invoked, the LangGraph flow is paused, the UI performs the action, and a hidden message is later re‑sent to resume the Agent with the updated context.
Context Compression
To keep token usage within limits, automatic compression is enabled when the context window exceeds 80 % of its capacity. The last three user rounds are always kept intact. The compression configuration is a simple JSON object.
{
"enabled": true,
"dangerThreshold": 80,
"keepRecentRounds": 3
}Conclusion
The resulting BFF Agent can generate, edit, execute, and validate TQL scripts autonomously, while handling long‑running UI interactions and keeping the LLM context efficient. Future improvements will focus on gathering failure cases, refining prompts, expanding the knowledge base, and further reducing token consumption.
Alibaba Cloud Developer
Alibaba's official tech channel, featuring all of its technology innovations.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
