AI Agent - MCP Overview
提示工程 + RAG
LLM 可以开箱即用,通过提示工程和它直接对话并解决问题
随着 LLM 的能力越来越强,尤其是其推理模型的出现,LLM 的回答越来越准确
但 LLM 并非全知全能,预训练的数据有截止时间 - RAG
RAG 是一种 LLM 应用开发范式
将 LLM 与外部数据源相结合来提高准确性和相关性
先通过向量之间的相似度,用检索系统从外部数据源搜索数据,以识别与用户查询相关的信息
LLM 随后利用检索到信息生成更精确,更及时的响应
RAG 过程 - 通过 RAG 增加 LLM 的知识,大大提高了 LLM 回答的准确性和相关性
Key
Value
检索
通过向量数据库或者其它检索系统,找出与用户查询相关的信息
增强
将检索到的信息作为上下文提供给 LLM
生成
LLM 基于这些额外信息生成回答
Agent + Tool Call
RAG 解决的是让 LLM 使用内部知识,同时减少幻觉的问题,但 RAG 本身并没有增强 LLM 的行动能力 - Agent
Agent 本质上是赋予 LLM 使用工具并采取行动的开发范式
Agent 的工作流程
Key
...
AI Agent - Overview
技术更迭
LLM 应用工程化难题
模型与外部世界割裂
LLM 是基于概率计算的新范式,虽然很强大,但仍需要与传统的结构化计算范式相结合,即通过工具调用来完成精确任务
目前传统结构化工具与 LLM 之间是割裂的,LLM 难以直接动态地接入实时数据、数据库或企业工具
传统的 API 调用方式零散且不标准,导致开发效率低下
Agent 协作的孤岛效应
不同 Agent 框架(LangGraph、AutoGen、CrewAI)各自为政,缺乏统一的通信标准,跨平台协作很难实现
复杂场景的工程化瓶颈
从搜索助手到企业知识中台、RAG 与多 Agent 系统需要处理多源数据、多模态交互和长时任务,现有工具链难以提供统一的解决方案
MCP + A2A
标准化 + 可扩展
MCP
模型主控 + 客户端驱动
MCP 是一个为 LLM 更方便地利用外部资源(主要是工具)而设计的标准化接口,旨在打破 LLM 与外部数据、工具之间的壁垒
传统上,将 AI 系统连接到外部工具需要集成多个 API - 代码冗余 + 难以维护 + 扩展性差
MCP 将繁琐细节都隐藏到服务器端 - 开发者只需关心 LLM 想用 ...
New Java Feature - Foreign Function API
概述
Java 的外部函数接口这个特性,与外部内存接口一起,会极大地丰富 Java 语言的生态环境
像 Java 或者 Go 这样的通用编程语言,都需要和其它的编程语言或者环境打交道 - 如操作系统或者 C 语言
Java 通过 Java 本地接口 JNI 来支持该做法
本地方法接口示例1234567891011public class HelloWorld { static { System.loadLibrary("helloWorld"); } public static void main(String[] args) { new HelloWorld().sayHello(); } private native void sayHello();}
sayHello 使用了 native 修饰符,是一个本地方法,可以使用 C 语言实现 - 生成对应的 C 语言的头文件
1234$ javac -h . HelloWorld.java$ lsHello ...
New Java Feature - Foreign Memory API
概述
在讨论代码性能的时候,内存的使用效率是一个绕不开的话题 - Flink/Netty
为了避免 JVM GC 不可预测的行为以及额外的性能开销,一般倾向于使用 JVM 之外的内存来存储和管理数据 - 堆外数据 - off-heap data
使用堆外存储最常用的办法,是使用 ByteBuffer 来分配直接存储空间 - direct buffer
JVM 会尽最大努力直接在 direct buffer 上执行 IO 操作,避免数据在本地和 JVM 之间的拷贝
频繁的内存拷贝是性能的主要障碍之一
为了极致的性能,应用程序通常会尽量避免内存的拷贝
理想的情况下,一份数据只需要一份内存空间 - 即零拷贝
ByteBuffer
使用 ByteBuffer 来分配直接存储空间
1public static ByteBuffer allocateDirect(int capacity);
ByteBuffer 所在的 Java 包是 java.nio,ByteBuffer 的设计初衷是用于非阻塞编程
ByteBuffer 是异步编程和非阻塞编程的核心类,几乎所有的 Java 异步模式或者 ...
New Java Feature - Flow
指令式编程
最常用的代码控制模式
1System.out.println("Hello, World!");
通过代码发布指令,然后等待指令的执行以及指令执行带来的状态变化
并且根据目前的状态,来确定下一次要发布的指令,并且用代码把下一个指令表示出来
指令式编程模型关注的重点在于控制状态
1234567try { Digest messageDigest = Digest.of("SHA-256"); byte[] digestValue = messageDigest.digest("Hello, world!".getBytes());} catch (NoSuchAlgorithmException ex) { System.out.println("Unsupported algorithm: SHA-256");}
首先调用 Digest.of 方法,得到一个 Digest 实例
然后调用该实例的方法 Digest.dig ...
New Java Feature - Error Code
概述
Java 的异常处理是对代码性能有着重要影响的因素
Java 的异常处理,有着天生优势,特别是在错误排查方面的作用,很难找到合适的替代方案
用例123456789101112131415161718192021222324252627282930313233343536package me.zhongmingmao;import java.security.NoSuchAlgorithmException;public class UseCase { public static void main(String[] args) { String[] algorithms = {"SHA-128", "SHA-192"}; String availableAlgorithm = null; for (String algorithm : algorithms) { Digest md; try { md = Digest.of(algorithm) ...
New Java Feature - Exception
概述
Java 异常的使用和处理,是滥用最严重,诟病最多,也是最难平衡的一个难题
Java 语言支持三种异常的状况
非正常异常(Error)、运行时异常(Runtime Exception)、检查型异常(Checked Exception)
异常,除非特别声明,一般指的是 Checked Exception 和 Checked Exception
异常状况的处理会让代码的效率变低 - 不应该使用异常机制来处理正常情况
理想情况下,在执行代码时没有任何异常发生,否则业务执行的效率会大打折扣
几乎无法完成,不管是 JDK 核心类库还是业务代码,都存在大量的异常处理代码
软件都是由很多类库集成的,大部分类库,都只是从自身的角度去考虑问题,使用异常来处理问题
很难期望业务执行下来没有任何异常发生
抛出异常影响了代码的运行效率,而实际业务又没有办法完全不抛出异常
新的编程语言(Go),彻底抛弃类似于 Java 这样的异常机制,重新拥抱 C 语言的错误方式
性能
没有抛出异常的用例,能够支持的吞吐量要比抛出异常的用例大 1000 倍
案例
在设计算法公开接口时,算法的敏捷性是必须要要考虑的问题
...
New Java Feature - Switch Matching
案例
假设上面表示形状的封闭类和许可类是版本 1.0,它们被封装在一个基础 API 类库里 - 基础类库
而 isSquare 的实现代码,被封装在另一个 API 类库里 - 扩展类库
新加入一个许可类,用来表示长方形 - 基础类库的升级,扩展类库也要同步升级 - 但不一定能意识到
对于需要更改扩展类库这件事,基础类库的作者,不会通知到扩展类库的作者
一般情况下,基础类库和扩展类库是独立的作品,由不同的团队和社区维护
基础类库的作者不太可能意识到扩展类库的存在,更不可能去研究扩展类库的实现细节
扩展类库维护者也不会注意到基础类库的修改,更不容易想到基础类库的修改会影响到扩展类库的行为
模式匹配的 switch
具有模式匹配能力的 switch - 将模式匹配扩展到 switch 语句和 switch 表达式
允许测试多个模式,每个模式多可以有特定的操作 - 简洁安全地表达复杂的面向数据的查询
扩充的匹配类型
在 JDK 17 之前的 switch 关键字可以匹配的数据类型包括 - 数字、枚举和字符串 - 本质上都是整型的原始类型
在 JDK 17 之后,匹配的目标数据类型,可以是一个 ...
New Java Feature - Switch Expression
概述
JDK 14
在 Java 规范里,表达式完成对数据的操作
一个表达式的结果可以是一个数值(i * 4);或者是一个变量(i = 4);或者什么都不是(void 类型)
Java 语句是 Java 最基本的可执行单元
它本身不是一个数值,也不是一个变量
Java 语句的标志性符号是分号(代码)和大括号(代码块) - if-else 语句、赋值语句等
switch 表达式是一个表达式,而 switch 语句是一个语句
Switch 语句12345678910111213141516171819202122232425262728293031323334353637class DaysInMonth { public static void main(String[] args) { Calendar today = Calendar.getInstance(); int month = today.get(Calendar.MONTH); int year = today.get(Calendar.YEAR); int daysInMo ...
New Java Feature - Pattern Matching
概述
Java 模式匹配是一个新型的、而且还在持续快速演进的领域
类型匹配是模式匹配的一个规范,在 JDK 16 正式发布
一个模式是匹配谓词和匹配变量的组合
匹配谓词用来确定模式和目标是否匹配
在模式和目标匹配的情况下,匹配变量是从匹配目标里提取出来的一个或者多个变量
对于类型匹配来说,匹配谓词用来指定模式的数据类型,而匹配变量就是属于该类型的数据变量
对于类型匹配来说,匹配变量只有一个
模式12345678static boolean isSquare(Shape shape) { if (shape instanceof Rectangle) { Rectangle rect = (Rectangle) shape; return (rect.length == rect.width); } return (shape instanceof Square);}
模式拆分 - 类型判断 + 类型转换 - 增加出错概率
类型判断语句 - 匹配谓词
类型转换语句
声明一个新的本地变量,即匹配变量,来承载 ...