怎样用NotebookLM做资料消化和可引用结论提取
2026-07-15 3400933
2026-07-15 0
做 AI Agent 开发的同学,大概率都走过这个弯路:把所有工具逻辑全写在 Agent 项目里,查数据库、读文件、调接口全部揉在一起。写的时候快捷省事,维护时却问题百出 —— 换个项目要重写一遍,遇到 Java/Python 写的能力没法直接复用,工具和模型强耦合,代码越写越乱。

直到 MCP(Model Context Protocol,模型上下文协议) 的出现,给这套混乱的工具调用体系定了行业标准。它不是又一个 HTTP 接口封装,而是专门为大模型设计的、打通「本地 + 远程、跨语言 + 跨进程」的上下文扩展通信标准。本文从痛点出发,结合实战代码,把 MCP 的本质、原理、落地用法一次性讲透。
先看一段非常典型的「项目内工具写法」,也是很多同学入门 Agent 时的默认实现:把用户查询、数据计算、文件操作等逻辑,直接写在 Agent 工程的工具函数里。
这种写法乍一看简单直接,但天生存在两个致命短板:
更深层的问题是:没有统一规范。工具返回什么格式、参数怎么描述、结果怎么塞进大模型上下文,全靠开发者自定义,换个人接手就要重新理解整套逻辑。
而 MCP 协议,就是专门解决这些问题的标准答案。
MCP 全称 Model Context Protocol,即模型上下文协议。它的核心目标非常明确:标准化 LLM 与外部工具、外部资源之间的通信,彻底解耦大模型和工具实现。
一句话理解:不管你的工具是 Node 写的、Java 写的、Python 写的,不管是跑在本地子进程还是远程服务器,Agent 都能用完全同一套协议去调用它,返回结果会自动变成大模型能读懂的上下文内容。
它的本质不是 “调用接口拿数据”,而是给大模型扩展上下文—— 让原本只有训练知识和对话窗口的 LLM,能访问本地文件、数据库、第三方服务、跨语言程序,把外部世界的信息和能力,变成模型可支配的上下文资源。
MCP 在上层定义了统一的消息格式与语义,底层提供了两种传输通道,分别对应本地跨进程和远程服务化场景。
Stdio 即标准输入输出流(stdin/stdout/stderr),是操作系统给每个进程天生自带的通信管道。
child_process 拉起 MCP 工具子进程,往子进程的 stdin(标准输入)写入 MCP 请求报文,从 stdout(标准输出)读取工具返回结果。除了本地进程,MCP 也支持 HTTP 作为传输层,实现跨机器、跨网络的工具调用。
最关键的一点是:上层调用逻辑完全一致。Agent 侧不需要关心底层是 stdio 还是 HTTP,只需要改配置,业务代码一行不用动,就能无缝切换本地工具和远程工具。
很多人会有疑问:走 HTTP 调用工具,和我直接用 fetch 调接口有什么区别?这是对 MCP 最常见的误解,两者的核心定位天差地别。
表格
| 维度 | fetch / 普通 HTTP 接口 | MCP 协议 |
|---|---|---|
| 核心定位 | 通用数据请求工具,与大模型无关 | 模型上下文扩展专用协议,原生服务 LLM |
| 语义规范 | 无统一标准,接口格式完全自定义 | 内置 listTools/callTool/readResource 标准语义,统一工具发现与调用 |
| 上下文能力 | 不感知上下文,拿到数据需手动拼接进 prompt | 原生设计用于扩充 LLM 上下文,标准化外部资源导入流程 |
| 通信方式 | 仅支持 HTTP 网络调用 | Stdio 本地跨进程 + HTTP 远程双模式 |
| 跨语言支持 | 需要自行封装进程通信与报文解析 | 协议层屏蔽语言差异,多语言工具统一接入 |
简单来说:
下面我们动手写一个可运行的 MCP 服务:实现用户信息查询能力,独立于 Agent 运行,通过 stdio 对外提供服务。
初始化项目并安装依赖:
bash
运行
复制代码pnpm init -y
pnpm add @modelcontextprotocol/sdk zod
在 package.json 中开启 ESM 模块:
json
复制代码{
"type": "module"
}
新建 src/my-mcp-server.mjs,写入以下代码:
javascript
运行
复制代码import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { z } from 'zod';// 模拟数据库,后续可替换为真实数据库/服务
const database = {
users: {
'001': { id: '001', name: '祖豪', email: '[email protected]', role: 'admin' },
'002': { id: '002', name: '光光', email: '[email protected]', role: 'user' },
'003': { id: '003', name: '小红', email: '[email protected]', role: 'user' },
}
};// 1. 创建 MCP 服务实例
const server = new McpServer({
name: 'my-mcp-server',
version: '1.0.0'
});// 2. 注册查询用户工具
server.registerTool(
'query_user',
{
description: '查询数据库中的用户信息。输入用户ID,返回该用户的详细信息(姓名、邮箱、角色)',
// 入参必须用 z.object 包裹,供大模型识别参数结构
inputSchema: z.object({
userId: z.string().describe('用户ID, 例如:001, 002, 003')
})
},
// 回调接收完整参数对象,解构获取字段
async ({ userId }) => {
const user = database.users[userId];
if (!user) {
return {
content: [
{ type: 'text', text: `用户 ID ${userId} 不存在。可用的ID: 001, 002, 003` }
]
};
} return {
content: [
{
type: 'text',
text: `用户 ${user.id} 的信息是:姓名:${user.name},邮箱:${user.email},角色:${user.role}`
}
]
};
}
);// 3. 绑定 stdio 传输通道,启动服务
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("MCP 用户查询服务已启动,等待 Agent 调用...");
这里也是很多人写 MCP 时最容易出错的地方:
inputSchema 必须用 z.object() 包裹,不能直接写字段,否则 SDK 无法解析参数结构,大模型也识别不了工具。console.error 输出到 stderr。console.log 会写入 stdout,污染 MCP 协议 JSON 报文,导致客户端解析失败。connect 不是 connent,拼写错误会直接报方法不存在。写好了 MCP 服务,Agent 端不需要自己手写进程通信、报文解析,LangChain 官方提供的 @langchain/mcp-adapters 可以直接接入,还支持同时管理多个 MCP 服务。
bash
运行
复制代码pnpm add @langchain/mcp-adapters @langchain/openai @langchain/langgraph
javascript
运行
复制代码import { MultiServerMCPClient } from "@langchain/mcp-adapters";
import { ChatOpenAI } from "@langchain/openai";
import { createReactAgent } from "@langchain/langgraph/prebuilt";// 配置多个 MCP 服务,可混合本地 stdio 和远程 HTTP
const mcpServersConfig = {
userServer: {
command: "node",
args: ["src/my-mcp-server.mjs"] // 本地 MCP 服务文件路径
}
// 可继续添加 Java/Python 编写的 MCP 服务
// calcServer: { command: "java", args: ["-jar", "calc-mcp.jar"] }
};async function runAgent() {
// 1. 初始化多 MCP 客户端,自动拉起所有子进程
const client = new MultiServerMCPClient(mcpServersConfig);
await client.initialize(); // 2. 自动获取所有 MCP 暴露的工具,转换为 LangChain 标准工具
const allTools = client.getTools();
console.error("加载到的工具列表:", allTools.map(t => t.name)); // 3. 初始化大模型与 ReAct Agent
const llm = new ChatOpenAI({ model: "gpt-3.5-turbo" });
const agent = createReactAgent({ llm, tools: allTools }); // 4. 对话:大模型自动判断并调用 MCP 工具
const res = await agent.invoke({
messages: [{ role: "user", content: "帮我查询用户001的信息" }]
}); console.log("最终回答:", res.messages.at(-1).content); // 销毁所有 MCP 子进程,释放资源
await client.close();
}runAgent().catch(console.error);
写到这里我们再回头看,MCP 带来的不只是一个通信协议,更是 Agent 开发的架构升级。