计科相关自感知识点的一个一个补充
[toc]
小知识点
绘图工具
让ai生成uml(统一建模语言)和mermaid(类似Markdown的语法来创建和修改图表)
文件
.csv :逗号分隔的⽂件,⽤于存储表格数据,可以⽤Excel打开
/ .avi :视频⽂件。
.tar / .gz :Linux下常⻅的压缩⽂件。
如何查看⽂件编码?
⽤VS Code或记事本打开⽂件,底部会显⽰⽂件编码(如UTF-8、GBK)。打开⽂件后,左上⻆ 文件 选择 另存为 就可以改变编码
x64与arm64处理器安装包
x64 架构长期以来一直是桌面计算机和服务器的主导架构,得益于其与旧 x86 应用程序的兼容性,以及其在处理高性能计算任务方面的能力。这意味着,对于运行复杂的桌面操作系统、大型数据库和高端游戏等,x64 提供了强大的支持。
而 arm64,由于其出色的能效比和对低功耗的优化,主要用于智能手机、平板电脑、嵌入式系统和轻薄笔记本电脑。近年来,随着 Apple 推出基于 arm64 的 M1 芯片,以及微软和 Qualcomm 合作开发的 Windows on ARM 项目,arm64 架构开始进入高性能计算和桌面计算领域,挑战 x64 的主导地位。
dll文件
.dll文件是Dynamic Link Library(动态链接库)文件的缩写,它是一种共享库文件,包含了程序所需的代码和数据。与静态链接库不同,动态链接库可以在程序运行时动态加载,使得程序的内存占用更小,同时也方便了程序的更新和维护。
鲁棒性
鲁棒性是 robustness 的音译,在中文中常常也被表达为健壮性和强壮性,总体来说其可以用于反映一个系统在面临着内部结构或外部环境的改变时也能够维持其功能稳定运行的能力 。
计算机系统:鲁棒性是一个系统或组件在出现不正确的或矛盾的输入时能够正确运行的程度。
人类语言技术:语言的鲁棒性(识别和分解等)是指人类即使在信息不完全、意思模糊或不断的变化情况下,仍然能够实现沟通的能力。
实用非线性控制:鲁棒性是一个系统在遇到了设计中所没有考虑过的情况时不受到影响的程度。
生物系统:鲁棒性是那些具有恢复、自动修复、自控制、自组装、自复制能力的系统所具有的特性。
面向对象的软件构造:鲁棒性是软件在非正常环境下(也就是在规范外的环境下,包括新的平台、网络超载、内存故障等)做出适当反应的能力。
句柄(HANDLE)
句柄是一个整数,单独的看它只是数字。
但这个整数是进程句柄表数组的下标,有了这个下标,操作系统就可以找到其索引的数据结构,并能找到数据结构里面的指针,然后根据这个指针获取内核里的某个对象。
proxy(代理)
一种充当 “中间媒介” 的服务或服务器,它位于客户端和目标服务器之间,帮助客户端与目标服务器间接交互。
常见作用:
- 突破访问限制:比如访问某些地区受限的网站(如学术资源、特定地区服务)。
- 隐藏真实地址:保护客户端的 IP 地址不被目标服务器直接获取,增强隐私。
- 缓存加速:代理服务器可缓存常用数据,再次请求时直接返回,提高访问速度。
- 过滤内容:企业或学校可能通过代理限制某些网站访问(如屏蔽不良内容)。
- 负载均衡:在服务器集群中,代理可分配请求到不同服务器,避免单台服务器压力过大。
前端开发中的常见场景:
在前端项目(如 Vue、React)开发时,常遇到 “跨域请求” 问题(浏览器限制不同域名间的直接数据交互)。此时可配置开发环境代理(如 Vue 的vue.config.js、Vite 的vite.config.js中设置proxy),让前端请求先经过本地代理服务器,再转发到后端接口,从而绕过跨域限制。
例如 Vue 项目配置:
1 | // vue.config.js |
TUN模式是一种网络隧道技术,主要用于VPN(虚拟专用网络)中的数据包传输。TUN(网络层隧道)和TAP(数据链路层隧道)是两种主要的隧道模式,它们在数据包的传输层次上有所不同。TUN模式专注于IP数据包(第三层)的隧道化,而TAP模式则是处理二层的数据帧。了解TUN模式的优缺点可以帮助更好地配置VPN和网络隧道策略。
TUN模式
优点
效率较高
更强的跨平台兼容性
适合路由流量
**适合在不同网络之间建立隧道,并基于IP地址路由特定流量。**因为TUN模式处理IP层数据包,适合通过配置路由表来控制哪些流量通过VPN隧道传输。这非常适用于那些只需要对特定IP地址或网段进行隧道化的情况,如远程访问特定内网资源。
节省网络资源,不涉及数据链路层TUN模式传输的数据包比TAP模式小,因为它省略了二层的头信息。对于需要频繁传输大量数据的场景,减少了网络带宽的占用,提高了整体数据传输效率。
TUN模式的缺点
TUN模式的应用场景
综上所述,TUN模式非常适合用于以下场景:
- 远程访问指定IP或网段资源(例如远程办公,连接公司内网)。
- 对带宽要求高的场景,因为TUN模式的数据包更小,传输效率更高。
- **需要对特定流量进行VPN保护,**而无需模拟完整局域网的场景。
大知识点
缓冲(buffer)
缓冲区是内存空间的一部分。也就是说,在内存空间中预留了一定的存储空间,这些存储空间用来缓冲输入或输出的数据,这部分预留的空间就叫做缓冲区。缓冲区根据其对应的是输入设备还是输出设备,分为输入缓冲区和输出缓冲区。
为什么要引入缓冲区
比如我们从磁盘里取信息,我们先把读出的数据放在缓冲区,计算机再直接从缓冲区中取数据,等缓冲区的数据取完后再去磁盘中读取,这样就可以减少磁盘的读写次数,再加上计算机对缓冲区的操作速度大大快于对磁盘的操作,故应用缓冲区可大大提高计算机的运行速度。
又比如,我们使用打印机打印文档,由于打印机的打印速度相对较慢,我们先把文档输出到打印机相应的缓冲区,打印机再自行逐步打印,这时我们的CPU可以处理别的事情。缓冲区就是一块内存区,它用在输入输出设备和CPU之间,用来缓存数据。它使得低速的输入输出设备和高速的CPU能够协调工作,避免低速的输入输出设备占用CPU,解放出CPU,使其能够高效率工作。
缓存(cache)
cache是一个非常大的概念。
一、CPU的Cache
CPU的Cache,它中文名称是高速缓冲存储器,读写速度很快,几乎与CPU一样。由于CPU的运算速度太快,内存的数据存取速度无法跟上CPU的速度,所以在cpu与内存间设置了cache为cpu的数据快取区。当计算机执行程序时,数据与地址管理部件会预测可能要用到的数据和指令,并将这些数据和指令预先从内存中读出送到Cache。一旦需要时,先检查Cache,若有就从Cache中读取,若无再访问内存,现在的CPU还有一级cache,二级cache。简单来说,Cache就是用来解决CPU与内存之间速度不匹配的问题,避免内存与辅助内存频繁存取数据,这样就提高了系统的执行效率。
二、磁盘的Cache
磁盘也有cache,硬盘的cache作用就类似于CPU的cache,它解决了总线接口的高速需求和读写硬盘的矛盾以及对某些扇区的反复读取。
三、浏览器的Cache
浏览器缓存(Browser Caching)是为了节约网络的资源加速浏览,浏览器在用户磁盘上对最近请求过的文档进行存储,当访问者再次请求这个页面时,浏览器就可以从本地磁盘显示文档,这样就可以加速页面的阅览,并且可以减少服务器的压力。游览器的缓存的数据只是短时间保存,可以人为的清空
缓存(cache)与缓冲(buffer)的主要区别
Buffer的核心作用是用来缓冲,缓和冲击(对输出设备的冲击,包括磁盘、打印机、显示器)。比如你每秒要写100次硬盘,对系统冲击很大,浪费了大量时间在忙着处理开始写和结束写这两件事嘛。用个buffer暂存起来,变成每10秒写一次硬盘,对系统的冲击就很小,写入效率高了,日子过得爽了。极大缓和了冲击。
Cache的核心作用是加快取用的速度(加快读取速度,包括CPU读内存、内存读磁盘、用户通过浏览器请求资源)。比如你一个很复杂的计算做完了,下次还要用结果,就把结果放手边一个好拿的地方存着,下次不用再算了。加快了数据取用的速度。
简单来说就是buffer偏重于写,而cache偏重于读。
JSON
JSON: JavaScript Object Notation JS对象简谱 , 是一种轻量级的数据交换格式.
2.JSON对象格式
我们通过java,js,xml和json这几种不同的语言来描述一个对象
对象是book,它有两个属性,分别是name和info
java格式
1 | > class Book{ |
1 | > var b = new Object(); |
1 | <book> |
1 | { |
一个对象, 由一个大括号表示.
括号中 描述对象的属性 .
通过键值对来描述对象的属性 (可以理解为, 大括号中, 包含的是一个个的键值对.)
格式
键与值之间使用冒号连接, 多个键值对之间使用逗号分隔.
键值对的键 应使用引号引住 (通常Java解析时, 键不使用引号会报错. 而JS能正确解 析.) 键值对的值, 可以是JS中的任意类型的数据
数组格式
在JSON格式中可以与对象互相嵌套
[元素1,元素2…]
案例
1 | { |
3.JSON数据解析
下面开始讲解如何使用IDEA将Java对象快速转换成JSON数据,和如何将JSON数据转换成Java对象
将Java中的对象 快速的转换为 JSON格式的字符串.
将JSON格式的字符串, 转换为Java的对象.
注意:
1.以下的导jar包操作如果不会,请去参考一些导jar包操作
2.在文章的底部提供了有关的jar包,需要自取
GSON解析
将对象转换为JSON字符串
1
2
3
4
5
6
7
8
9
10
11
12转换JSON字符串的步骤:
1. 引入JAR包
2. 在需要转换JSON字符串的位置编写如下代码即可:
String json = new Gson().toJSON(要转换的对象);
案例:
//1. 创建Gson类型的对象
Gson g = new Gson();
//2. 转换
//优化 可以使用匿名对象
book b = new book("100","金苹果","种植苹果的故事");
String s = g.toJson(b);
System.out.println(s);将JSON字符串转换为对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
151. 引入JAR包
2. 在需要转换Java对象的位置, 编写如下代码:
//1. 创建Gson类型的对象
Gson g = new Gson();
//2. 转换 {"id":"100","name":"金苹果","info":"种植苹果的故事","page":["远赴人间惊鸿晏","一度人间盛世颜","致hdd"]}
//2.1 返回book类型
book b = g.fromJson("{\"id\":\"100\",\"name\":\"金苹果\",\"info\":\"种植苹果的故事\"}", book.class);
System.out.println(b.getId());
//2.2 返回MAP类型,键值对形式
HashMap hm = g.fromJson("{\"id\":\"100\",\"name\":\"金苹果\",\"info\":\"种植苹果的故事\"}", HashMap.class);
System.out.println(hm.get("id"));
//2.3 MAP类型中值是一个数组形式
HashMap data = g.fromJson("{\"id\":\"100\",\"name\":\"金苹果\",\"info\":\"种植苹果的故事\",\"page\":[\"远赴人间惊鸿晏\",\"一度人间盛世颜\",\"致hdd\"]}", HashMap.class);
List list = (List) data.get("page");
System.out.println(list.get(1));
MCP
MCP (Model Context Protocol,模型上下文协议)定义了应用程序和 AI 模型之间交换上下文信息的方式。这使得开发者能够以一致的方式将各种数据源、工具和功能连接到 AI 模型(一个中间协议层),就像 USB-C 让不同设备能够通过相同的接口连接一样。MCP 的目标是创建一个通用标准,使 AI 应用程序的开发和集成变得更加简单和统一。
MCP 就是以更标准的方式让 LLM Chat 使用不同工具
MCP 的出现是 prompt engineering 发展的产物。更结构化的上下文信息对模型的 performance 提升是显著的。我们在构造 prompt 时,希望能提供一些更 specific 的信息(比如本地文件,数据库,一些网络实时信息等)给模型,这样模型更容易理解真实场景中的问题。
想象一下没有 MCP 之前我们会怎么做?我们可能会人工从数据库中筛选或者使用工具检索可能需要的信息,手动的粘贴到 prompt 中。随着我们要解决的问题越来越复杂,手工把信息引入到 prompt 中会变得越来越困难。
为了克服手工 prompt 的局限性,许多 LLM 平台(如 OpenAI、Google)引入了 function call 功能。这一机制允许模型在需要时调用预定义的函数来获取数据或执行操作,显著提升了自动化水平。
但是 function call 也有其局限性(我对于 function call vs MCP 的理解不一定成熟,欢迎大家补充),我认为重点在于 function call 平台依赖性强,不同 LLM 平台的 function call API 实现差异较大。例如,OpenAI 的函数调用方式与 Google 的不兼容,开发者在切换模型时需要重写代码,增加了适配成本。除此之外,还有安全性,交互性等问题。
数据与工具本身是客观存在的,只不过我们希望将数据连接到模型的这个环节可以更智能更统一。Anthropic 基于这样的痛点设计了 MCP,充当 AI 模型的**”万能转接头”**,让 LLM 能轻松的获取数据或者调用工具。更具体的说 MCP 的优势在于:
生态 - MCP 提供很多现成的插件,你的 AI 可以直接使用。
统一性 - 不限制于特定的 AI 模型,任何支持 MCP 的模型都可以灵活切换。
数据安全 - 你的敏感数据留在自己的电脑上,不必全部上传。(因为我们可以自行设计接口确定传输哪些数据)
用户如何使用 MCP?
对于用户来说,我们并不关心 MCP 是如何实现的,通常我们只考虑如何更简单的用上这一特性。
具体的使用方式参考官方文档:For Claude Desktop Users。这里不再赘述,配置成功后可以在 Claude 中测试:Can you write a poem and save it to my desktop? Claude 会请求你的权限后在本地新建一个文件。
并且官方也提供了非常多现成的 MCP Servers,你只需要选择你希望接入的工具,然后接入即可。
比如官方介绍的 filesystem 工具,它允许 Claude 读取和写入文件,就像在本地文件系统中一样。
MCP Architecture 解构
这里首先引用官方给出的架构图。

MCP 由三个核心组件构成:Host、Client 和 Server。让我们通过一个实际场景来理解这些组件如何协同工作:
假设你正在使用 Claude Desktop (Host) 询问:”我桌面上有哪些文档?”
- Host:Claude Desktop 作为 Host,负责接收你的提问并与 Claude 模型交互。
- Client:当 Claude 模型决定需要访问你的文件系统时,Host 中内置的 MCP Client 会被激活。这个 Client 负责与适当的 MCP Server 建立连接。
- Server:在这个例子中,文件系统 MCP Server 会被调用。它负责执行实际的文件扫描操作,访问你的桌面目录,并返回找到的文档列表。
整个流程是这样的:你的问题 → Claude Desktop(Host) → Claude 模型 → 需要文件信息 → MCP Client 连接 → 文件系统 MCP Server → 执行操作 → 返回结果 → Claude 生成回答 → 显示在 Claude Desktop 上。
这种架构设计使得 Claude 可以在不同场景下灵活调用各种工具和数据源,而开发者只需专注于开发对应的 MCP Server,无需关心 Host 和 Client 的实现细节。

原理:模型是如何确定工具的选用的?
在学习的过程中,我一直好奇一个问题:Claude(模型)是在什么时候确定使用哪些工具的呢?好在 Anthropic 为我们提供了详细的解释:
当用户提出一个问题时:
- 客户端(Claude Desktop / Cursor)将你的问题发送给 Claude。
- Claude 分析可用的工具,并决定使用哪一个(或多个)。
- 客户端通过 MCP Server 执行所选的工具。
- 工具的执行结果被送回给 Claude。
- Claude 结合执行结果构造最终的 prompt 并生成自然语言的回应。
- 回应最终展示给用户!
MCP Server 是由 Claude 主动选择并调用的。有意思的是 Claude 具体是如何确定该使用哪些工具呢?以及是否会使用一些不存在的工具呢(幻觉)?
**(原谅我之前解释的过于简单)**为了探索这个问题让我们深入源码。显然这个调用过程可以分为两个步骤:
- 由 LLM(Claude)确定使用哪些 MCP Server。
- 执行对应的 MCP Server 并对执行结果进行重新处理。
先给出一个简单可视化帮助理解:
模型如何智能选择工具?
先理解第一步模型如何确定该使用哪些工具?这里以 MCP 官方提供的 client example 为讲解示例,并简化了对应的代码(删除了一些不影响阅读逻辑的异常控制代码)。通过阅读代码,可以发现模型是通过 prompt 来确定当前有哪些工具。我们通过将工具的具体使用描述以文本的形式传递给模型,供模型了解有哪些工具以及结合实时情况进行选择。参考代码中的注释:
1 | # 省略了无关的代码 |
那 tool 的描述和代码中的 input_schema 是从哪里来的呢?通过进一步分析 MCP 的 Python SDK 源代码可以发现:大部分情况下,当使用装饰器 @mcp.tool() 来装饰函数时,对应的 name 和 description 等其实直接源自用户定义函数的函数名以及函数的 docstring 等。
1 |
|
总结:模型是通过 prompt engineering,即提供所有工具的结构化描述和 few-shot 的 example 来确定该使用哪些工具。另一方面,Anthropic 肯定对 Claude 做了专门的训练(毕竟是自家协议,Claude 更能理解工具的 prompt 以及输出结构化的 tool call json 代码)
工具执行与结果反馈机制
其实工具的执行就比较简单和直接了。承接上一步,我们把 system prompt(指令与工具调用描述)和用户消息一起发送给模型,然后接收模型的回复。当模型分析用户请求后,它会决定是否需要调用工具:
- 无需工具时:模型直接生成自然语言回复。
- 需要工具时:模型输出结构化 JSON 格式的工具调用请求。
如果回复中包含结构化 JSON 格式的工具调用请求,则客户端会根据这个 json 代码执行对应的工具。具体的实现逻辑都在 process_llm_response 中,代码,逻辑非常简单。
如果模型执行了 tool call,则工具执行的结果 result 会和 system prompt 和用户消息一起重新发送给模型,请求模型生成最终回复。
如果 tool call 的 json 代码存在问题或者模型产生了幻觉怎么办呢?通过阅读代码 发现,我们会 skip 掉无效的调用请求。
执行相关的代码与注释如下:
1 | # 省略无关的代码 |
结合这部分原理分析:
- 工具文档至关重要 - 模型通过工具描述文本来理解和选择工具,因此精心编写工具的名称、docstring 和参数说明至关重要。
- 由于 MCP 的选择是基于 prompt 的,所以任何模型其实都适配 MCP,只要你能提供对应的工具描述。但是当你使用非 Claude 模型时,MCP 使用的效果和体验难以保证(没有做专门的训练)。
6. 总结
MCP (Model Context Protocol) 代表了 AI 与外部工具和数据交互的标准建立。通过本文,我们可以了解到:
- MCP 的本质:它是一个统一的协议标准,使 AI 模型能够以一致的方式连接各种数据源和工具,类似于 AI 世界的”USB-C”接口。
- MCP 的价值:它解决了传统 function call 的平台依赖问题,提供了更统一、开放、安全、灵活的工具调用机制,让用户和开发者都能从中受益。
- 使用与开发:对于普通用户,MCP 提供了丰富的现成工具,用户可以在不了解任何技术细节的情况下使用;对于开发者,MCP 提供了清晰的架构和 SDK,使工具开发变得相对简单。
一个简单的 MCP Server 开发实践
对绝大部分 AI 开发者来说,我们只需要关心 Server 的实现
MCP servers 可以提供三种主要类型的功能:
- Resources(资源):类似文件的数据,可以被客户端读取(如 API 响应或文件内容)
- Tools(工具):可以被 LLM 调用的函数(需要用户批准)
- Prompts(提示):预先编写的模板,帮助用户完成特定任务
A.I 使用 LLM 构建 MCP 的最佳实践
在开始之前,Anthropic 为我们提供了一个基于 LLM 的 MCP Server 的最佳开发实践,总结如下:
- 引入 domain knowledge (说人话就是,告诉他一些 MCP Server 开发的范例和资料)
- 访问 https://modelcontextprotocol.io/llms-full.txt 并复制完整的文档文本。(实测这个太长了,可以忽略)
- 导航到 MCP TypeScript SDK 或 Python SDK Github 项目中并复制相关内容。
- 把这些作为 prompt 输入到你的 chat 对话中(作为 context)。
- 描述你的需求
- 你的服务器会开放哪些资源
- 它会提供哪些工具
- 它应该给出哪些引导或建议
- 它需要跟哪些外部系统互动
给出一个 example prompt:
1 | ... (这里是已经引入的 domain knowledge) |
剩下的部分也很重要,但是偏重于方法论,实践性较弱,我这里就不展开了,推荐大家直接看官方文档。
A.II 手动实践
使用 Python 实现一个 MCP Server,用来统计当前桌面上的 txt 文件数量和获取对应文件的名字(你可以理解为一点用都没有,但是它足够简单,主要是为了难以配置环境的读者提供一个足够短的实践记录)。
构造一个 prompt
1 | """ |
实现 MCP Server
以下代码由 Claude 3.7 直接生成。当然,这主要是因为我的需求足够简单,当你需要实现一个复杂的 MCP Server 时,你可能需要多步的引导和 Debug 才能得到最终的代码。
1 | import os |
理解 __name__ 变量
__name__是 Python 内置的特殊变量,用于标识当前模块的名称。当一个模块(
.py文件)被直接运行时(例如通过python 文件名.py命令),Python 会将该模块的__name__赋值为"__main__"。当一个模块被导入到其他模块中时(例如
import 模块名),该模块的__name__会被赋值为其模块名(即文件名,不含.py)。避免不必要的执行:如果没有这个判断,当脚本被导入到其他模块时,
mcp.run()会被自动执行,可能导致意外启动服务器、重复执行代码等问题,符合 Python 的模块化设计理念。
假设这个脚本是一个服务器模块 server.py:
- 直接运行
python server.py时,__name__ == "__main__"成立,服务器启动(mcp.run()执行)。 - 其他脚本
import server时,__name__为"server",条件不成立,服务器不会启动,仅能调用脚本中的其他函数 / 类。
测试 MCP Server
1 | $ mcp dev txt_counter.py |

接入 Claude
最后一步就是把我们写好的 MCP 接入到 Claude Desktop 中。
在配置文件中添加以下内容,记得替换 /Users/{username} 为你的实际用户名,以及其他路径为你的实际路径。
1 | { |
uv最好是绝对路径,推荐使用which uv获取。
配置好后重启,如果没问题就能看到对应的 MCP Server 了。

Step7. 实际使用
接下来,我们通过一个简单的 prompt 进行实际测试:
1 | 能推测我当前桌面上 txt 文件名的含义吗? |
它可能会请求你的使用权限,如图一所示,你可以点击 Allow for This Chat


看起来我们 MCP Server 已经正常工作了!