🚀 AI Agent 入门实战:基于 LangChain + MCP 构建智能导游助手

🚀 AI Agent 入门实战:基于 LangChain + MCP 构建智能导游助手

前言

我是前端出身,这几年 AI 带来的变化非常明显。它不是简单的工具升级,而是在重塑整个开发方式。

我开始学习 AI Agent,主要有三个原因:

  1. 技术趋势已经很明确,AI 正在快速进入开发流程
  2. 只会写传统 CRUD 的竞争力越来越弱,前端也需要新的能力栈
  3. AI 相关岗位和项目需求在增长,早点入门,才能尽早建立自己的第二曲线

这是我学习 AI Agent 开发以来做的第一个入门项目。这个项目里,我尝试把几个核心概念真正串起来,包括:

  • 提示词设计
  • RAG 检索增强
  • Tool 工具调用
  • MCP 协议接入
  • 自定义 MCP 服务实现

如果文中有理解不够准确的地方,或者你有更好的实现方式,欢迎交流指正。

什么是 AI Agent?

AI Agent 可以理解为一个具备"感知、决策、执行"能力的智能应用。

更通俗一点说:

  • 大模型负责思考
  • 工具负责执行
  • 记忆负责上下文
  • 循环负责多步任务推进

所以,AI Agent 不只是一个会聊天的模型,而是一个能真正帮你做事的系统。


这篇文章能给你带来什么?

如果你也是前端开发者,想入门 AI Agent,这篇文章会帮你:

  1. 建立认知:理解 AI Agent 是什么、能做什么
  2. 掌握原理:工具调用、RAG 检索、MCP 协议等核心概念
  3. 动手实践:从零实现一个完整的 AI Agent 应用
  4. 串联知识:提示词工程、RAG、Tool、MCP 一次讲清

项目效果

先看一段实际运行效果:

bash 复制代码
🤖 重出江湖(输入 "quit" 或 "exit" 可退出)
请开始你的表演:
> 帮我生成余干县旅游攻略
⏳ 处理中...
🚀 工具调用中 [maps_text_search]
🚀 工具调用中 [writeFile]
✅ 结果:
已为您生成余干县旅游攻略,文件保存在:
./txt/余干县旅游攻略.md

请继续你的表演:
> 那边天气怎么样?
⏳ 处理中...
🚀 工具调用中 [maps_weather]
✅ 结果:
余干县今天天气:
🌤️ 多云转晴
🌡️ 温度:18-27°C
💨 风力:东南风3-4级
💧 湿度:65%

这里最关键的一点是:第二句里的"那边",AI 依然能理解指的是上一轮提到的"余干县"。这就是上下文记忆在起作用。


项目架构

整个项目的数据流很简单:

text 复制代码
用户输入
  ↓
main.mjs:管理对话入口和历史记录
  ↓
byQueryMergePrompt.mjs:做 RAG 检索,补充知识上下文
  ↓
runAgent.mjs:组装提示词,调用模型,进入工具循环
  ↓
工具层:MCP 工具、地图工具、自定义写文件工具
  ↓
返回结果给用户

关键理解点

  1. Agent 的核心是"循环"
  2. 每一步都会累加上下文
  3. 大模型负责决定要不要调用工具、调用什么工具
  4. 工具返回结果后,大模型会继续思考,直到任务完成

核心实现

1. 对话记忆

这个项目里,我先用一个消息集合 historyPrompt 来保存对话历史。

你可以把它理解成一个会持续追加的消息数组,里面记录了:

  • 用户说了什么
  • 模型回复了什么
  • 工具返回了什么

这样下一轮对话时,模型就能看到完整上下文,从而理解"那边"指的是上一轮提到的地点。

javascript 复制代码
const historyPrompt = [];

const result = await runner({ historyPrompt, currentQuery: cmd });

historyPrompt.push(new HumanMessage(cmd));
historyPrompt.push(result);

这是一种最直接、最好理解的做法,特别适合入门阶段。

不过要注意,这种方式更适合 Demo 和学习场景。真正做线上项目时,LangChain 还有更正规的记忆管理方案,比如会话状态管理、消息裁剪、长期存储等能力,可以用来处理更长的上下文和多轮会话。


2. RAG 检索增强

RAG 的作用很简单:先查资料,再回答问题

它解决的是大模型容易"胡编乱造"的问题。

我的实现思路是:

  1. abu.txt 拆成小片段
  2. 转成向量
  3. 根据用户问题查最相关的片段
  4. 把结果拼进系统提示词里
javascript 复制代码
const retriever = await vectorstoreRef.similaritySearchWithScore(query, 3);

const docs = retriever.filter((doc) => {
  const [document, score] = doc;
  return score && score > 0.5;
});

这里我做了一个相似度过滤,避免无关片段干扰模型判断。这个细节很重要,不然检索结果一乱,后面的回答也会跟着飘。


3. MCP 工具接入

MCP 的价值是统一工具接入标准。

你可以把它理解成 AI 工具的"标准接口":

  • 本地工具可以通过 stdio 接入
  • 远程服务可以通过 HTTP 接入
  • 模型只需要面对统一工具格式,不用关心底层实现

我这里做了两个来源的工具:

  • 自己写的本地 MCP 服务
  • 高德地图提供的远程 MCP 服务

本地 MCP 的写法大概是这样:

javascript 复制代码
server.registerTool(
  'Read_parsed_file',
  {
    description: '我可以帮你读取文件,解析文件',
    inputSchema: {
      path: z.string().describe('文件路径')
    }
  },
  async ({ path }) => {
    const content = fs.readFileSync(path, 'utf-8');
    return {
      content: [{
        type: 'text',
        text: `文件内容:${content}`
      }]
    };
  }
);

4. 工具调用循环

这是整个 Agent 最核心的地方。

流程很简单:

  1. 模型先思考
  2. 如果需要工具,就返回 tool_calls
  3. 执行工具
  4. 把工具结果加入上下文
  5. 再次调用模型
  6. 直到没有工具调用为止
javascript 复制代码
let response = await model.bindTools(tools).invoke(prompt);
prompt.push(response);

let toolCalls = response.tool_calls;

while (toolCalls?.length) {
  for (const tool of toolCalls) {
    const foundTool = tools.find(t => t.name === tool.name);
    const toolResponse = await foundTool.invoke(tool.args);

    prompt.push(new ToolMessage({
      content: toolResponse,
      tool_call_id: tool.id
    }));
  }

  response = await model.bindTools(tools).invoke(prompt);
  prompt.push(response);
  toolCalls = response.tool_calls;
}

这里最容易踩坑的点是 tool_call_id。这个字段不能漏,不然工具结果和模型调用对不上,后面很容易报错。


代码结构说明

main.mjs

负责对话入口和历史记录管理。

核心作用是把用户输入和模型回复保存下来,保证下一轮还能接着聊。

runAgent.mjs

负责 Agent 主逻辑。

包括模型初始化、工具绑定、RAG 拼接、工具调用循环。

byQueryMergePrompt.mjs

负责 RAG 检索。

把本地知识库转成向量,再根据用户输入检索相关内容。

mcp-server.mjs

负责本地 MCP 工具服务。

这里主要演示一个文件读取工具,帮助理解 MCP 的标准接入方式。

tools.mjs

负责自定义工具。

这里实现的是文件写入功能,适合生成旅游攻略这类场景。


踩坑与优化

1. 历史消息要成对保存

用户输入和模型回复都要存进历史记录,不然下一轮对话模型就会"失忆"。

2. tool_call_id 不能漏

模型一次可能调用多个工具,结果必须用 tool_call_id 对上,否则会出问题。

3. MCP 路径尽量用绝对路径

本地启动 MCP 服务时,路径写错非常常见。

如果用了相对路径,运行目录一变就容易挂。

4. RAG 检索要做过滤

向量库返回的不一定全是高相关结果,做相似度过滤很有必要。

5. 记忆不要无限堆积

historyPrompt 这种方式很好理解,但如果不做裁剪,长对话会越来越长。

正式项目里,建议用 LangChain 的记忆管理能力来控制上下文长度。


总结

通过这个项目,我最直接的收获是把 AI Agent 的核心链路跑通了:

  • 让模型会思考
  • 让工具会执行
  • 让记忆能延续上下文
  • 让 RAG 给回答提供依据
  • 让 MCP 把外部能力接进来

这个项目虽然还是一个入门 Demo,但已经把 Agent 的基本形态搭出来了。

对我来说,最重要的不是"做了一个能跑的项目",而是开始真正理解:

AI Agent 不是单纯的聊天,而是把大模型变成能做事的系统。


关于作者

我是 辣椒炒代码,一名前端开发者,也是 AI Agent 的学习者。

这篇文章记录了我从零搭建第一个 AI Agent 项目的过程,希望能帮同样来自前端方向的同学,快速建立对 AI Agent 的基本认知,并真正跑通一个可用的实战案例。

标签#AI Agent #LangChain #MCP协议 #RAG #实战教程 #导游助手 #前端开发

相关推荐
ruanCat2 小时前
前端工程化工具链从零配置:simple-git-hooks + lint-staged + commitlint
前端·git·代码规范
Jackson__2 小时前
AI时代,前端开发者到底还剩下什么?又该往哪里走?
前端·ai编程
C澒3 小时前
微前端容器标准化:容器标准化演进
前端·架构
卖报的大地主3 小时前
Learn Claude Code Agent 开发 | 2、插拔式工具系统:扩展功能不修改核心循环
前端·chrome
qzhqbb3 小时前
Web 服务器(Nginx、Apache)
服务器·前端·nginx
天若有情6733 小时前
前端进阶必看:吃透这些高阶知识,告别CRUD,迈向高级前端工程师
前端·状态模式
coderYYY3 小时前
git push报错Authentication failed for ‘xxx’也不会弹要求输入用户名密码的最终解决方法
前端·git·gitee·github
l1t4 小时前
QWen 3.5plus总结的总结基准测试结果的正确方法
前端·数据库
kyriewen114 小时前
为什么我的代码在测试环境跑得好好的,一到用户电脑就崩?原来凶手躲在地址栏旁边
开发语言·前端·javascript·chrome·ecmascript·html5