图片来源网络,侵权联系删。

文章目录
- [1. 引言](#1. 引言)
- [2. 核心概念解析:Tools、Memory、LLM 如何协同工作?](#2. 核心概念解析:Tools、Memory、LLM 如何协同工作?)
-
- [2.1 三大组件类比 Web 开发](#2.1 三大组件类比 Web 开发)
- [2.2 协同工作流程(Mermaid)](#2.2 协同工作流程(Mermaid))
- [3. 实战项目:构建"智能旅行规划助手"](#3. 实战项目:构建“智能旅行规划助手”)
-
- [3.1 功能需求](#3.1 功能需求)
- [3.2 工具定义(Tools)](#3.2 工具定义(Tools))
- [4. 工程实现:Node.js 后端 + React 前端](#4. 工程实现:Node.js 后端 + React 前端)
-
- [4.1 后端:Express + OpenAI 实现 Agent 编排](#4.1 后端:Express + OpenAI 实现 Agent 编排)
- [4.2 前端:React 展示行程规划结果](#4.2 前端:React 展示行程规划结果)
- [5. 关键优化:提升可靠性与用户体验](#5. 关键优化:提升可靠性与用户体验)
-
- [5.1 防幻觉:强制数据驱动](#5.1 防幻觉:强制数据驱动)
- [5.2 内存管理:防止 Token 超限](#5.2 内存管理:防止 Token 超限)
- [5.3 错误处理](#5.3 错误处理)
- [6. 总结与延伸:从 Demo 到生产](#6. 总结与延伸:从 Demo 到生产)
1. 引言

如果你是一名 Web 开发者,你一定熟悉这样的场景:
用户在前端填写表单 → 后端调用数据库查询用户信息 → 调用支付网关 → 发送邮件通知 → 返回成功页面
这个流程中包含了三个关键要素:
- 工具(Tools):数据库、支付接口、邮件服务
- 状态(Memory):用户会话、订单 ID、临时数据
- 逻辑(Logic):业务规则、判断分支、错误处理
而 AI Agent 正是这一模式的智能化延伸:
- LLM 扮演"动态业务逻辑引擎"
- Tools 提供外部能力(API、函数、数据库)
- Memory 维护上下文与历史状态
💡 本文将通过一个旅行规划助手 实战项目,手把手带你用 Node.js + React 实现一个具备 Tools 调用、Memory 管理、流式响应的完整 Agent 系统,所有代码均可直接运行。
2. 核心概念解析:Tools、Memory、LLM 如何协同工作?

2.1 三大组件类比 Web 开发
| Agent 组件 | Web 开发类比 | 作用 |
|---|---|---|
| LLM | 业务逻辑层(Service Layer) | 动态决策:该调用哪个工具?如何组合结果? |
| Tools | 微服务 / API 客户端 | 封装外部能力:查天气、订酒店、搜航班 |
| Memory | Session / Vuex / Redis | 存储对话历史、用户偏好、中间状态 |
2.2 协同工作流程(Mermaid)
Hotel_API Weather_API Agent Backend Frontend User Hotel_API Weather_API Agent Backend Frontend User "帮我规划去杭州的周末行程" POST /plan { query: "...", sessionId: "abc" } 初始化 Memory + 注册 Tools LLM 分析 → 需查天气和酒店 GET /weather?city=杭州&days=2 返回天气数据 POST /search { city: "杭州", dates: [...] } 返回酒店列表 LLM 生成行程建议 返回结构化 JSON 渲染行程卡片 展示"杭州周末游"方案
✅ 关键点 :LLM 不直接访问外部世界,而是通过 Tool Call 间接操作,确保安全与可控。
3. 实战项目:构建"智能旅行规划助手"

3.1 功能需求
用户输入自然语言,如:
- "帮我安排一个杭州的周末短途旅行"
- "我想带家人去三亚,预算5000元"
系统需:
- 自动识别目的地、日期、人数、预算
- 调用天气 API 获取未来天气
- 调用模拟酒店搜索接口
- 生成包含天气、推荐酒店、行程建议的结构化报告
3.2 工具定义(Tools)
ts
// src/tools/index.ts
export const TOOLS = [
{
name: "get_weather_forecast",
description: "获取某城市未来N天的天气预报",
parameters: {
type: "object",
properties: {
city: { type: "string", description: "城市名,如 杭州" },
days: { type: "integer", minimum: 1, maximum: 7, default: 2 }
},
required: ["city"]
}
},
{
name: "search_hotels",
description: "根据城市和日期搜索可用酒店",
parameters: {
type: "object",
properties: {
city: { type: "string" },
checkIn: { type: "string", format: "date" },
checkOut: { type: "string", format: "date" },
guests: { type: "integer", default: 2 }
},
required: ["city", "checkIn", "checkOut"]
}
}
];
🔍 这相当于 Web 后端的 OpenAPI 文档,LLM 会据此决定调用哪个"微服务"。
4. 工程实现:Node.js 后端 + React 前端

4.1 后端:Express + OpenAI 实现 Agent 编排
ts
// src/server.ts
import express from 'express';
import { OpenAIApi, Configuration } from 'openai';
import { v4 as uuidv4 } from 'uuid';
const app = express();
app.use(express.json());
// 内存存储(生产环境用 Redis)
const sessions: Record<string, any[]> = {};
// 模拟工具实现
const toolsImpl = {
get_weather_forecast: async ({ city, days = 2 }) => ({
city,
forecast: Array(days).fill().map((_, i) => ({
date: new Date(Date.now() + i * 86400000).toISOString().split('T')[0],
condition: Math.random() > 0.5 ? 'sunny' : 'cloudy',
temp: 20 + Math.floor(Math.random() * 15)
}))
}),
search_hotels: async ({ city, checkIn, checkOut, guests = 2 }) => ({
hotels: [
{ name: `${city}中心精品酒店`, price: 400, rating: 4.5 },
{ name: `${city}湖景度假村`, price: 600, rating: 4.8 }
]
})
};
app.post('/api/plan', async (req, res) => {
const { query, sessionId = uuidv4() } = req.body;
// 1. 加载或初始化会话历史
if (!sessions[sessionId]) sessions[sessionId] = [];
sessions[sessionId].push({ role: 'user', content: query });
// 2. 构建系统提示词
const systemPrompt = `
你是一名专业旅行顾问。请严格按以下步骤执行:
1. 从用户输入中提取:城市、日期范围、人数、预算
2. 调用工具获取天气和酒店信息
3. 生成结构化 JSON 响应,格式如下:
{
"destination": "杭州",
"summary": "简要行程建议",
"weather": [...],
"hotels": [...]
}
`;
// 3. 调用 OpenAI(启用 function calling)
const openai = new OpenAIApi(new Configuration({ apiKey: process.env.OPENAI_API_KEY }));
const completion = await openai.createChatCompletion({
model: 'gpt-4o',
messages: [
{ role: 'system', content: systemPrompt },
...sessions[sessionId]
],
functions: TOOLS.map(tool => ({
name: tool.name,
description: tool.description,
parameters: tool.parameters
})),
function_call: 'auto'
});
const message = completion.data.choices[0].message;
// 4. 处理工具调用
if (message.function_call) {
const { name, arguments: argsStr } = message.function_call;
const args = JSON.parse(argsStr);
const result = await toolsImpl[name](args);
// 添加工具响应到历史
sessions[sessionId].push(
{ role: 'assistant', content: null, function_call: message.function_call },
{ role: 'function', name, content: JSON.stringify(result) }
);
// 二次调用生成最终回答
const finalCompletion = await openai.createChatCompletion({
model: 'gpt-4o',
messages: [
{ role: 'system', content: systemPrompt },
...sessions[sessionId]
],
response_format: { type: 'json_object' }
});
const finalMessage = finalCompletion.data.choices[0].message;
sessions[sessionId].push({ role: 'assistant', content: finalMessage.content });
return res.json(JSON.parse(finalMessage.content!));
}
// 无工具调用,直接返回
sessions[sessionId].push({ role: 'assistant', content: message.content });
res.json({ error: '无法解析请求' });
});
app.listen(3001, () => console.log('Agent server running on http://localhost:3001'));
4.2 前端:React 展示行程规划结果
tsx
// src/App.tsx
import React, { useState } from 'react';
import axios from 'axios';
function App() {
const [query, setQuery] = useState('');
const [result, setResult] = useState<any>(null);
const [sessionId] = useState(localStorage.getItem('session') || Date.now().toString());
React.useEffect(() => {
localStorage.setItem('session', sessionId);
}, [sessionId]);
const handleSubmit = async () => {
const res = await axios.post('http://localhost:3001/api/plan', { query, sessionId });
setResult(res.data);
};
return (
<div style={{ padding: '20px', maxWidth: '800px', margin: '0 auto' }}>
<h1>✈️ 智能旅行规划助手</h1>
<input
value={query}
onChange={(e) => setQuery(e.target.value)}
placeholder="例如:帮我安排杭州周末游"
style={{ width: '70%', padding: '8px' }}
/>
<button onClick={handleSubmit} style={{ padding: '8px 16px' }}>规划行程</button>
{result && (
<div style={{ marginTop: '20px' }}>
<h2>目的地:{result.destination}</h2>
<p><strong>建议:</strong>{result.summary}</p>
<h3>🌤️ 天气预报</h3>
<ul>
{result.weather?.map((w: any) => (
<li key={w.date}>{w.date}: {w.condition}, {w.temp}°C</li>
))}
</ul>
<h3>🏨 推荐酒店</h3>
<ul>
{result.hotels?.map((h: any) => (
<li key={h.name}>{h.name} - ¥{h.price}/晚 ({h.rating}⭐)</li>
))}
</ul>
</div>
)}
</div>
);
}
export default App;
5. 关键优化:提升可靠性与用户体验

5.1 防幻觉:强制数据驱动
在系统提示词中明确:
"你必须仅基于工具返回的数据生成回答。禁止编造酒店名称、天气或价格。"
5.2 内存管理:防止 Token 超限
- 限制对话历史最多保留 6 轮
- 自动摘要旧对话(如:"此前用户计划去杭州...")
5.3 错误处理
- 工具调用失败时返回友好提示
- 前端显示加载状态和错误信息
6. 总结与延伸:从 Demo 到生产

通过本次实战,我们验证了:
✅ Tools + Memory + LLM = 可控、可靠、可扩展的 Agent 架构
✅ Web 开发者完全可以用现有技术栈构建智能体
✅ 工程化实践比模型理论更重要
下一步建议
- 替换模拟工具为真实 API(如 OpenWeatherMap、Booking.com API)
- 引入向量数据库实现长期记忆(如用户偏好:"不喜欢住高层酒店")
- 增加流式响应(SSE / WebSocket)提升交互体验
- 集成 LangChain简化工具注册与内存管理
推荐资源
- 📦 LangChain.js ------ 官方 JavaScript SDK
- 🧪 Vercel AI SDK ------ 构建流式 AI 应用
- 📊 LangSmith ------ 调试与监控 Agent
🌟 记住:你不是在"做 AI",而是在"用 AI 扩展你的 Web 工程能力边界"。
