The Anatomy of an AI Agent: Memory, Tools, and the Engineering That Makes LLMs Act
Agent: From Concept to Practice — How to Build an AI Assistant That Actually Gets Things Done
Introduction: The "Ceiling" of Large Models and the "Breakthrough" of Agents
By 2026, the capabilities of large language models (LLMs) are beyond doubt. You can ask them anything, and they will give you astonishing answers. But if you try to get them to "remember what we talked about last week," "read this webpage and fill out a form for me," or "check the company's latest internal sales data" — you will find that a bare LLM instantly becomes powerless.
This is not because the model isn't smart enough, but because large models inherently have several structural shortcomings:
First, LLMs are stateless. Every conversation is a "first meeting" for the model. You spent two hours discussing project background with it last week; ask again today, and it has completely forgotten. To make the model remember context, you need a Memory module — store conversation history in a database, Redis, or frontend local storage, and send relevant history records to the model with each request.
Second, LLMs can only "speak," not "act." You ask it to visit a webpage, write a file, or call an API — it can only tell you the approach and then wait for you to do it yourself. To make the model actually execute operations, you need to equip it with Tools — enabling the model to call external functions, read and write files, send network requests, and execute command-line instructions.
Third, LLMs' knowledge has a cutoff date. Once a model is trained, its knowledge is frozen at the time point of its training data. The latest World Cup news, today's stock prices, the company's internal private documents — it knows none of these. You need RAG (Retrieval-Augmented Generation) to access external knowledge bases, and MCP (Model Context Protocol) to standardize the integration of third-party tools.
Fourth, LLMs lack domain depth. Getting them to make PowerPoint presentations, analyze the stock market and automatically trade, or execute complex multi-step workflows — these require distilling general capabilities into domain-specific professional skills (Skills).
And Agent, precisely, is the product of addressing all the above problems by adding a Memory module, Tool-use capability, RAG knowledge retrieval, MCP protocol support, and a Skills system to the LLM.
Agent = LLM + Memory + Tool + RAG + MCP + Skills
This is not a simple addition, but a qualitative leap — the LLM transforms from "a model that can chat" into "an agent that can get things done."
How an Agent Works: The Full Process from Receiving to Completing a Task
When a user presents a complex task to an Agent in the form of a prompt, a precise collaborative process unfolds inside the Agent:
Planning / Reasoning: The LLM first understands the user's intent and breaks the complex task down into executable sub-steps. For example, for "help me analyze the quality of this project's code," the Agent will plan: first list the file structure → read key files → analyze code patterns → provide a report.
Memory Retrieval: The Agent checks whether historical memory needs to be loaded. If the user previously discussed the background of this project, the Agent will extract relevant context from the memory module, avoiding the need for the user to repeat explanations.
Tool Use: The Agent determines which tools need to be called and executes them step by step. Reading files, searching code, running tests — each tool call has clear input parameters and return results, and the Agent decides the next action based on the result of the previous step.
Knowledge Enhancement (RAG): When a task involves internal private knowledge, the Agent retrieves relevant document fragments from a vector database and injects the retrieval results into the context via a Prompt Template, giving the model knowledge "beyond its training data."
Response and Feedback: The Agent aggregates all tool execution results and reasoning processes, generates the final answer, and completes the user's task.
The core idea of the entire process is: The LLM is the brain, tools are the hands, memory is experience, and RAG is the external knowledge base — none can be missing.
LangChain: The "Universal Glue" for Agent Development
In the field of Agent development, LangChain is one of the most mature open-source frameworks. It was born even earlier than many of OpenAI's technologies, and its core value lies in unification and compatibility — there are dozens of large model vendors on the market, each with its own API format. LangChain provides a layer of abstraction, allowing you to use the same code to call different models like DeepSeek, OpenAI, and Anthropic.
In our practice, the technology stack selection is:
- Backend Framework: NestJS (Node.js enterprise-level framework)
- Agent Framework: LangChain.js (single agent) + LangGraph (multi-agent collaboration)
- Tool Ecosystem: MCP / RAG / Skills
Below, let's look at a real code example to see how LangChain gives an LLM tool-calling capabilities.
Step 1: Bind the Model
import { ChatOpenAI } from '@langchain/openai';
const model = new ChatOpenAI({
modelName: 'deepseek-v4-flash',
apiKey: process.env.DEEPSEEK_API_KEY,
temperature: 0,
configuration: {
baseURL: 'https://api.deepseek.com/v1',
},
});
LangChain's ChatOpenAI is compatible with the OpenAI interface specification. By simply modifying baseURL and modelName, you can seamlessly switch to domestic models like DeepSeek. This on-demand loading, plug-and-play design allows teams to flexibly choose the most cost-effective model without being locked into a single vendor.
Step 2: Define Tools
import { tool } from '@langchain/core/tools';
import { z } from 'zod';
const readFileTool = tool(
async ({ filePath }) => {
const content = await fs.readFile(filePath, 'utf-8');
console.log(`[Tool Call] read_file(${filePath}) successfully read ${content.length} bytes`);
return content;
},
{
name: 'read_file',
description: 'Use this tool to read file content. Call this tool when the user asks to read a file, view code, or analyze file content.',
schema: z.object({
filePath: z.string().describe('The file path to read'),
}),
}
);
A Tool consists of two core parts:
- Function (async processing function): The logic that actually performs the operation. Here, it reads the file content and returns it.
- Description Object: Contains
name(tool name),description(detailed function description, covering usage scenarios and parameter requirements), andschema(parameter constraints). Theschemais defined using Zod, ensuring that the parameter types and formats passed when the LLM calls the tool are completely correct.
There is a crucial design detail here that is easily overlooked: constantly feedback execution status during tool execution. An Agent's task can be complex and time-consuming. If the user sees no feedback for a long time, they will assume the program has frozen and exit. Printing a log at each step is a fundamental discipline of Agent development.
Step 3: Register Tools and Create the Agent
const tools = [readFileTool];
const modelWithTools = model.bindTools(tools);
const messages = [
new SystemMessage('You are a code assistant that can use tools to read files and explain code.'),
new HumanMessage('Please read the tool.mjs file content and explain the code'),
];
let response = await modelWithTools.invoke(messages);
messages.push(response);
LangChain provides the bindTools method to register tools with the model. When a user makes a request like "read a file and explain the code," the model will:
- Recognize the need to call the
read_filetool - Generate structured
tool_calls, containing the tool ID, name, and parameters - Pause its own text generation and wait for the tool to return results
- Associate the tool's returned results with the corresponding
tool_call_idand append them to the conversation history - Generate the final answer based on the complete context (user question + tool return content)
This process is very ingenious: The LLM has "self-awareness" — when it judges that a tool needs to be called, it will not forcefully fabricate content, but instead generates a tool_calls array to inform the system "I need to call these tools." After the tools execute asynchronously, the results are associated back to the corresponding calls via id, and the entire task context is completely preserved in the historical conversation list. The LLM understands all of this based on natural language, yet can achieve precise function call orchestration.
Performance Optimization: Parallel Execution with Promise.all
When an Agent needs to call multiple tools, if executed serially — read file A, then file B, then file C — the total time equals the sum of all operation times. In complex tasks, this can lead to users waiting for tens of seconds or even minutes.
The solution is to use JavaScript's Promise mechanism to achieve parallel execution:
const [weatherData, tweetsData] = await Promise.all([
getWeather(), // takes 2000ms
getTweets(), // takes 500ms
]);
// Total time ≈ 2000ms (the longest one), not 2500ms
Promise is the core of asynchronous programming introduced in ES6, and it has three states:
- Pending: The asynchronous operation has not yet completed
- Fulfilled: The operation completed successfully, state changes from Pending to Fulfilled
- Rejected: The operation failed, state changes from Pending to Rejected
The key characteristic is: The state can only change from Pending to either Fulfilled or Rejected, and once changed, it is irreversible. This guarantees the determinism of asynchronous operations.
Promise.all() takes an array of Promises, starts all asynchronous tasks in parallel, waits for all tasks to complete, and returns an array of results, with the result order strictly matching the input array order. Combined with async/await (ES8 syntax), asynchronous code reads as clearly as synchronous code.
In an Agent scenario, when the LLM determines that there are no dependencies between multiple tool calls — for example, reading three unrelated configuration files simultaneously — Promise.all should be used for parallel execution, reducing the total time from "the sum of three operations" to "the slowest operation." This is a key technique for building high-performance Agents.
From Demo to Product: The Complete Picture of Agent Development
Let's return to a concrete example: having an Agent "create a React + Vite TodoList application." This task will be planned by the LLM into three steps:
- Create the project with the Vite scaffolding → Call CLI tool
- Write the TodoList component code → Call file write tool
- Start the dev server to verify → Call CLI tool again
Every step is a tool call, and the result of each step influences the decision for the next. This is the core principle behind hand-writing a simplified Claude Code — LLM + file system tools + command-line tools.
LangGraph goes even further, supporting multi-agent collaboration: you can have an "Architect Agent" responsible for planning and design, a "Coder Agent" responsible for implementation, and a "Reviewer Agent" responsible for checking code quality — they collaborate through message passing, each performing its own role.
Conclusion: Agents Are Actually Not Complicated
Returning to the original question: Are Agents complicated?
Taken apart, none of the pieces are complicated. The LLM itself can think and plan; equip it with Tools and it can do work; pair it with Memory and it can remember what you want it to remember; connect it to RAG and it can query internal knowledge bases. Put these together — an extended large model that knows internal knowledge, can think and plan, and can act to get things done — that is an Agent.
The real challenge lies not in understanding these concepts, but in Harness Engineering. How to design stable tool interfaces? How to handle tool call exceptions? How to optimally schedule between concurrency and serial execution? How to make an Agent's behavior predictable and debuggable?
This is precisely the mission of AI Full-Stack Agent Product Development: to land AI technology through solid engineering practices and realize the commercial value of AI technology (FDE — Frontier Development Engineering).
From the first line of hello-langchain code to an Agent product supporting tens of millions of users — this road is only just beginning now.