news 2026/10/20 16:20:23

Spring AI + MCP 构建 Java Agent 实战:从架构到踩坑全解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Spring AI + MCP 构建 Java Agent 实战:从架构到踩坑全解析

先说结论:Spring AI + MCP 这套组合,是我最近半年用下来觉得最“稳”的 Java 侧 Agent 落地方式。它解决的核心问题不是“把模型接进来”,而是“怎么让模型安全、可控、可扩展地调用真实业务能力”。如果你正在 Java 技术栈里做 AI Agent、智能助手、流程自动化这类项目,这篇内容值得你从头到尾看一遍。

MCP(Model Context Protocol)本身是对外开放的协议标准,Spring AI 把它原生接进了 Spring Boot 生态,意味着你不需要自己解析 function calling、不需要自己维护工具注册表、更不需要为每个模型厂商单独写一套适配层。配合 Spring Boot 的自动配置和 Bean 体系,基本可以做到“加一个工具=加一个类”,这对想要构建标准化、可扩展 Agent 系统的团队来说,价值非常直接。

这篇我会从架构设计、环境配置、核心代码、踩坑记录四个层面展开,全程以真实项目“某内部智能助手”为例。项目不大,但麻雀虽小五脏俱全:模型接入、工具调用、上下文管理、对话记忆、问题排查都覆盖到了。

1. 整体设计与思路拆解

1.1 Agent 落地难,难的根本不是“大模型”

很多团队做 Agent 的第一个误区是:把大模型当成核心工作量。真做下来你会发现,模型能力再强,没有一套规矩的工具调用机制,Agent 就是个“能聊天但啥也干不了”的花瓶。

实际项目里,Agent 要让模型去做事,比如查库存、发审批、查工单、算价格,必须打通三层:

  • 模型层:决定“什么时候该调用哪个工具”
  • 工具层:把业务系统的能力暴露给模型,可插拔、可复用
  • 协调层:管理上下文、控制对话历史、记录工具调用结果

如果这三层全用自家代码硬撸,第一个项目能跑,第二个项目就得返工。工具一多,模型经常“不知道该调哪个”;换了模型供应商,原来的 function calling 格式全部作废;再想支持第三方工具,又得写一套新连接器。这套路我太熟了,痛过才知道要提前用标准协议。

1.2 MCP 像什么?像 AI 世界的万能插头

MCP 这个协议,核心思路一句话:把工具、数据资源、提示词都定义成标准化的“能力端点”,模型客户端通过统一协议发现和调用它们。

用生活类比最直观:你的手机需要一个充电头,但市面上的充电协议五花八门。MCP 就是那个“USB-C 接口”——从此以后,企业系统不用关心接的是哪家模型,模型也不用关心你内部是什么技术栈。只要双方实现了 MCP 协议,就能直接协作。

协议里最常用的三种能力:

能力类型作用典型场景
Tools可执行的工具,模型主动调用查天气、查库存、发送审批
Resources可读取的数据资源读取内部知识库、读取配置信息
Prompts可复用的提示词模板团队按统一规范复用提示词

这套抽象对 Agent 系统的最大意义是:工具层和模型层彻底解耦。协议在中间,业务系统只管实现服务端,模型接入只管做客户端,两边互不绑架。

1.3 Spring AI 是 Java 生态里最舒服的“接线层”

Java 做 AI 应用,很早以前是很别扭的。要么调 SDK 裸写,要么包一层 HTTP 请求自己封装,日志、重试、注入全都要手动处理。Spring AI 出现后,最大的贡献是把“模型交互”纳入了 Spring 的编程模型。

用过 Spring Boot 的人上手 Spring AI 几乎没有成本:

  • Starter 依赖一键引入
  • 自动配置帮你把 ChatModel、ChatClient 这些东西全部准备好
  • 配置走 application.yml,换模型厂商基本只改配置不改代码
  • @Tool注解把业务方法和模型工具直接绑定

再加上 Spring Boot 对 MCP 的原生支持,这一套组合下来,构建 Agent 的体验甚至比很多脚本语言框架还要顺畅。

2. 架构与标准化设计

2.1 分层架构:接入层、协调层、工具层

我在“某内部智能助手”项目里用到的分层结构,经过几轮优化后基本定型成这个形式,你可以直接参考:

  • 接入层:负责和模型厂商通信,统一封装 ChatModel 和 ChatClient。业务代码不直接碰模型 SDK。
  • 协调层:Agent 核心逻辑,负责工具发现、调用决策、上下文管理、对话记忆。这是整个系统的“大脑”。
  • 工具层:所有业务能力都以 MCP 工具形式暴露。工具内部再调用底层业务服务或第三方接口。

这个分层最大的好处是职责单一。协调层不知道“查库存”具体怎么实现,它只知道有一个工具叫query_stock,参数是商品 ID,返回是库存数据。工具层也不知道模型是什么品牌,它只负责把自己的能力注册成标准协议端点。

2.2 为什么不用裸 function calling?

可能有人问:我用 OpenAI 的 function calling 或者各家 SDK 的原生工具调用,不是挺好吗?为什么非要套 MCP?

直说我的观点:小 Demo 用原生 function calling 没问题,但生产级 Agent 系统有几个绕不开的坎:

第一,供应商绑定。原生 function calling 的参数结构、返回格式、错误处理都是跟着厂商走的。今天用甲厂商,明天换乙厂商,代码审计一遍。MCP 是中立协议,两边都适配,换料不换锅。

第二,工具治理是硬需求。工具数量超过十个,就要面临工具清单从哪里来、权限怎么控、调用日志怎么记、哪个工具耗时过高怎么监控。MCP 把工具生命周期管理收敛到统一层面,这套治理逻辑才有地方放。

第三,生态互通。MCP 出来以后,行业里已经有不少现成的 Server 实现,数据库、文件系统、开发工具、常用办公套件都能找到协议实现。这意味着你花一次学习成本,后续可以接入大量现成能力。

当然,MCP 也不是银弹。它的学习曲线不算陡,但如果你只是临时写一个脚本调一下模型,确实没必要上 MCP。什么时候该用?当你确定要把它做成一个长期维护、不断加功能的系统时,就用。

2.3 可扩展性到底从哪里来

“可扩展”这个词很容易被说成口号。在我看来,可扩展性要落地到三个具体的地方:

  • 协议扩展:新能力通过 MCP Server 暴露,Agent 端零代码接入。你给我一个 MCP Server 地址,我就能把新工具接到现有系统里。
  • 配置扩展:模型切换、工具连接、系统提示词都通过配置驱动,不写死在代码里。环境隔离、灰度发布、多租户差异化配置都能轻松支持。
  • 代码扩展:用 Spring 的 Bean 机制管理工具注册,新增工具就是新增一个带有@Tool方法的@Component。依赖注入自动把业务服务送进来,工具类内部代码依然遵循 Spring 最佳实践。

这个设计带来的感觉是:Agent 系统的增长方式从“改代码”变成了“挂载能力”。两者完全不是一回事。

3. 环境准备与核心配置

3.1 依赖引入,能用 Starter 就别手撸

项目基于 Spring Boot 3.x,构建工具用的 Maven。Spring AI 相关的核心依赖就三个:

<dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-starter-model-openai</artifactId> <version>1.0.0</version> </dependency> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-starter-mcp-client</artifactId> <version>1.0.0</version> </dependency> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-starter-mcp-server</artifactId> <version>1.0.0</version> </dependency>

依赖版本这个事多说一句:Spring AI 迭代速度很快,1.0 之前的 API 变动相当频繁。建议以你实际引入时的最新稳定版本为准,尽量不要用 SNAPSHOT 版本跑生产。踩过这种坑的人应该懂我为什么特别强调这一句。

Starter 依赖的好处是把底层 SDK、自动配置、默认参数全都打包进来了。你不需要自己构建 MCP Client 实例,也不需要手动配置模型提供商连接,写个配置就好。

3.2 模型接入配置

我这里用的是 OpenAI 兼容接口,便于切换。如果你的模型厂商支持 OpenAI 兼容协议,配置几乎一模一样:

spring: ai: openai: base-url: https://api.example.com/v1 api-key: ${LLM_API_KEY} chat: options: model: gpt-4o-mini temperature: 0.2

temperature: 0.2是我在 Agent 场景里比较偏好的值。Agent 需要执行任务,输出要尽量稳定、可控、贴近指令,不需要太多创造性。如果你做的是文案生成、创意类对话,这个值可以再调高。曾经把一个工具调用类的 Agent 温度调到了 0.8,结果模型经常“自由发挥”,把参数名都改得乱七八糟,查了好久才发现是温度惹的祸。

3.3 MCP Server 端配置:把业务能力变成协议端点

我强烈建议你一开始就把工具定义为 MCP Server 模式,而不是仅仅依赖内存里的 ToolCallback。原因很简单:MCP Server 可以被外部复用。同一个工具,既能服务当前 Agent,未来也能被其他系统调用。

先看配置:

spring: ai: mcp: server: enabled: true name: internal-assistant-server version: 1.0.0

再看一个具体的工具类。项目里第一个接入的是“内部工单查询”能力:

@Component public class TicketTools { private final TicketService ticketService; public TicketTools(TicketService ticketService) { this.ticketService = ticketService; } @Tool(description = "根据工单ID查询内部工单详情,返回工单状态、处理人、最后更新时间") public String queryTicketDetail(String ticketId) { TicketDO detail = ticketService.queryById(ticketId); if (detail == null) { return "工单不存在: " + ticketId; } return "工单[" + ticketId + "]状态=" + detail.getStatus() + ",处理人=" + detail.getOwner() + ",最后更新时间=" + detail.getGmtModified(); } }

这里的关键点在@Tool注解的description。很多人不重视这个字段,觉得就是写给人看的注释。实际不是,模型的工具选择决策完全依赖这个描述。描述写得模糊,模型就不知道该在什么时候用这个工具。见过团队把描述写成“查询工单”,模型就经常在用户询问“我的报销到哪一步了”时错误地调用它。把描述改成“根据工单ID查询内部工单详情,返回工单状态、处理人、最后更新时间”之后,误调用率显著下降。

3.4 MCP Client 端配置:Agent 如何发现工具

Agent 端要做的,就是配置 MCP Client 并连接 Server。我用的是 Stdio 模式,也就是本地进程通信,一个进程对应一个 Server:

spring: ai: mcp: client: enabled: true name: internal-assistant-client version: 1.0.0 connections: - type: stdio name: internal-assistant-server command: java args: - -jar - /opt/mcp-servers/internal-assistant-server.jar

这种模式适合和自家服务部署在一起的工具。如果你的工具跑在独立服务上,MCP 还支持 HTTP 模式(streamable HTTP),配置一个 URL 就能远程调用。我当时先跑了 Stdio,等工具 Server 多了以后准备切到 HTTP 统一管理,但是单机演示和内部验证用 Stdio 更简单直接。

MCP Client 启动后会自动发现 Server 暴露的工具清单,这些工具会并入 Spring AI 的 ToolCallback 体系。也就是说,Agent 调用一个 MCP 工具和调用一个本地函数,对模型来说没有区别,统一走协议封装。

3.5 工具注册成功怎么验证

有一个很直接的验证方法:启动项目后看日志。Spring AI 的 MCP 自动配置启动时,会打印工具列表。如果你配置正确,控制台会列出类似以下内容:

Registered MCP tool: queryTicketDetail(String ticketId)

看到这个输出,说明 Server 端和 Client 端握手成功、工具已注册。这一步没通过,后面 Agent 再怎么调都不会触发工具。

4. 实战:构建一个标准化、可扩展的 Agent 系统

4.1 需求场景设定

先交代一下项目背景:某公司内部需要一个智能助手,能帮助员工查询工单、查看公告、提交简单的审批请求。所有数据都来自内部系统,不直接暴露数据库,也不允许模型自由发挥去捏造数据。

这个场景非常适合 Agent + MCP。员工用自然语言提问,Agent 决定调用哪个工具,工具返回真实数据,模型再组织语言回复。

4.2 配置 ChatClient 与工具回调

Spring AI 1.0 后的标准做法是用ChatClient作为交互入口。先创建配置类:

@Configuration public class AgentConfig { @Bean ChatClient chatClient(ChatClient.Builder builder) { return builder .defaultSystem("你是某公司内部智能助手。请根据用户问题判断是否需要调用工具。" + "如果工具返回的结果不足以回答问题,明确告知用户,不要编造数据。") .build(); } }

注意这里我加了一个明确的系统提示词:不要编造数据。模型有时候会为了“完成对话”而强行输出不存在的工单信息,这在企业内部场景是不可接受的。系统提示词里写清楚底线,比在业务代码里做各种校验都更治本。

接下来,在调用处把工具带有选择性地注入:

@Service public class AssistantService { private final ChatClient chatClient; private final List<ToolCallback> toolCallbacks; public AssistantService(ChatClient chatClient, List<ToolCallback> toolCallbacks) { this.chatClient = chatClient; this.toolCallbacks = toolCallbacks; } public String ask(String userMessage) { return chatClient.prompt() .user(userMessage) .tools(toolCallbacks) .call() .content(); } }

这里把List<ToolCallback>注入进来,Spring 会自动收集所有 MCP 工具。想要控制某个 Agent 只能用某些工具,就在构建tools(...)时按名称过滤,非常灵活。

4.3 Agent 是怎么一步步“思考”和调用工具的

CallResponseSpec内部接入 Tool Calling 机制后,整个调用流程是这样的:

  1. 用户输入“帮我查一下工单 TK20250201 到哪一步了”
  2. 模型收到消息,判断需要调用工具
  3. 模型生成一个结构化的工具调用请求,包含工具名queryTicketDetail和参数"TK20250201"
  4. Spring AI 框架本地执行queryTicketDetail方法,拿到返回结果
  5. 工具结果作为一条消息回传给模型
  6. 模型基于工具结果生成最终回答:“这个工单当前状态是处理中,处理人是张三,最后更新时间为今天上午 10:24”

这个多轮工具调用循环是 Agent 的核心引擎。你不必自己写循环代码,框架帮你做了。但你必须理解它,这样才能在出现问题时快速定位是哪一环出了岔子。

实战中我发现,工具调用失败的常见原因往往不是框架有 Bug,而是模型选择的参数不合法。比如用户说“查一下昨天的工单”,模型如果把这个请求转换成queryTicketDetail(ticketId="昨天的工单"),那你得让工具在参数校验不过时返回一个友好的错误信息,模型看到错误信息后会尝试修正自己的调用。这也是工具方法内部要做防御的原因。

4.4 上下文管理:对话记忆与 token 预算

单轮问答很容易,难的是多轮对话。Agent 必须记住用户之前说过什么。Spring AI 提供了ChatMemory和MessageChatMemoryAdvisor,直接解决这个问题。

先定义一个内存型记忆组件:

@Bean ChatMemory chatMemory() { return MessageWindowChatMemory.builder() .maxMessages(20) .build(); }

然后在构建 ChatClient 时挂上记忆顾问:

@Bean ChatClient chatClient(ChatClient.Builder builder, ChatMemory chatMemory) { return builder .defaultSystem("你是某公司内部智能助手。请根据用户问题判断是否需要调用工具。" + "如果工具返回的结果不足以回答问题,明确告知用户,不要编造数据。") .defaultAdvisors(new MessageChatMemoryAdvisor(chatMemory)) .build(); }

.maxMessages(20)的意思是只保留最近 20 条消息。这个“20”不是随便写的。Agent 每轮对话不仅消耗 token,还消耗模型的注意力资源。历史太长,模型会“记不清”当前这轮问题的重点。我调过多个 Agent 项目,内部总结的经验是:短任务型 Agent 保持 10~20 条历史最佳;长度超过 50 条,不仅成本翻倍,回答质量也会肉眼可见地下降。

MessageWindowChatMemory 是滑动窗口策略,实现简单、效果可控。再复杂一点的场景可以考虑摘要压缩,把旧消息交给模型生成摘要再塞回上下文。但对多数内部助手来说,滑动窗口足够了。

4.5 系统提示词设计的几个心得

系统提示词对 Agent 行为的影响远超很多人的认知。在我这个项目里,经过多轮调优最终稳定下来的一段提示词,核心要素是角色、边界、调用策略:

你是某公司内部智能助手。 - 你的信息来源只有内部系统工具,不要编造数据。 - 用户问题涉及工单、公告、审批时,先调用对应工具获取真实数据。 - 工具返回数据为空时,如实告知用户,不猜测结果。 - 回答保持简洁,直接给出结论和关键信息。

提示词里明确写“先调用对应工具”这一点很重要。模型默认情况下是“懒惰”的,能直接回答的问题它不喜欢绕路调工具。除非系统提示词明确要求,否则它常常宁愿“猜一个答案”。对于 Agent 应用,这就是致命的。

5. 常见问题与排查技巧实录

5.1 工具一直在,但模型就是不调用

这是我被问过最多的问题,没有之一。排查思路按顺序走:

第一步,看注册日志,确认工具确实在 ToolCallback 列表里。有些情况下工具类没有被 Spring 扫描到,日志里根本没有这一行。

第二步,看description。描述模糊、或者没有提到任何触发关键词,模型就不知道该用。把用户可能的口语表达写进去是最实用的做法。比如“查一下昨天的工单”,“工单”这个词必须出现在描述里。

第三步,看用户的提问和工具参数是否匹配。模型只有在“当前上下文足够支撑参数填充”时才倾向调用。如果你问的是“我的工单到哪了”但工具要求传ticketId,模型不知道 ID 是什么,就会放弃调用。这种情况下,可以在工具描述里补充说明“如果用户未提供工单ID,引导用户提供”。

第四步,确认是否在同一轮内可以调用多个工具。部分模型对“单轮多工具调用”的支持不好,会一次只调一个,然后停下来等结果。这不是框架问题,是模型策略问题,换个对工具调用支持更强的模型即可解决。

5.2 工具返回的数据格式影响回答质量

工具方法返回的是字符串,用大段文本拼接,模型确实也能读,但不如结构化格式好。建议工具返回值尽量用 JSON 字符串形式。比如天气工具返回{"city":"北京","temperature":5,"condition":"晴"},模型直接从 JSON 提取关键信息,组织自然语言回答,比拼接的文本要准确得多。

我自己的工具方法统一用一个简单的格式:如果数据正常,返回 JSON 字符串;如果异常,返回{"error":"查询失败: ..."}。模型能识别 error 字段,在最终回答里会主动传达失败原因。这对用户体验是很大的提升。

5.3 上下文越来越长,成本飙升

滑动窗口能限制“对话历史”长度,但工具调用产生的 token 一样要花钱。如果你的 Agent 频繁调用工具,一次工具调用循环可能消耗几百 token,多轮就是几千。

经验做法是:

  • 工具结果尽量精简,只回传关键字段。不需要把整个数据库记录都塞给模型。
  • 对工具返回结果做截断,超过 500 字符的只保留前半部分和后半部分,中间用省略号代替。
  • 对话之间及时清理无用的历史,比如用户已经完成了一次咨询,就不需要把上一轮的完整工具调用过程一直留在上下文里。

5.4 Spring AI 自动配置冲突

这个坑比较隐蔽。Maven 里同时引入了多个 Spring AI 模块时,偶尔会出现自动配置冲突,表现是 MCP Client 连接失败、工具注册不生效。排查手段:

  • 检查依赖树,mvn dependency:tree查看是否有重复版本的 Spring AI 模块
  • 检查META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports里的自动配置类是否被手动排除
  • 确认没有引入两个不同版本号的spring-ai-core

由于 Spring AI 是较新的框架,社区资料不像老牌框架那么多。遇到诡异问题,第一反应应该是“查版本、查依赖树”,而不是怀疑代码写错了。

5.5 问题排查速查表

现象可能原因解决方向
日志无工具注册Server/Client 配置未生效检查 MCP 自动配置、依赖引入
模型不调用工具description 不明确重写描述,加入触发同义词
调用工具但参数错误上下文缺关键信息引导用户补全参数或工具内做容错
回答质量波动大temperature 过高Agent 任务调到 0.2 以下
老问题经常复现上下文被污染检查 ChatMemory 窗口设置
成本上涨明显工具结果太长截断返回 JSON,只保留关键字段

6. 扩展方向与实用建议

6.1 把外部公共工具接进来

内测稳定以后,我们开始接更多现成的 MCP Server。GitHub 上能找到不少开源实现,比如数据库查询、时间日期、文件读取、HTTP 请求等通用工具。接任何一个工具,本质上都是加一个依赖、加一段连接配置,Agent 核心代码不需要改动。这就是 MCP 标准的实际红利。

当然,接外部工具要注意权限问题。MCP Server 暴露的是真实能力,权限控制必须做在 Server 端。不要让一个“查公网 IP”的工具在有内网权限的 Agent 里随意使用。

6.2 多 Agent 拆分的思路

工具数量到了 30+ 以后,单 Agent 的决策压力会变大。模型面对三十个工具的时候,调用准确率明显低于面对五个工具。

此时可以考虑纵向拆分:一个“路由 Agent”先判断用户意图属于哪个领域,再把请求转发给对应领域的子 Agent。子 Agent 只挂自己领域的少量工具。这个架构能显著提升工具调用的准确率。Spring AI 目前提供了 ChatClient 级别的工具过滤机制,你可以轻松实现“按 Agent 过滤工具”的逻辑。

我用下来觉得判断的临界点大概在 20 个工具附近。工具少于这个数,单 Agent 更简单;超过这个数,拆多 Agent 收益更大。

6.3 别忽略可观测性

Agent 系统最让人头疼的就是“黑盒”。用户问一个问题,触发了几次工具调用,每次结果是什么,最终回答基于哪些数据——这些过程全透明地记录下来,才方便复盘和排查。

建议至少记录三类日志:

  • 用户原始输入和最终回答
  • 每一次工具调用的工具名、入参、出参、耗时
  • 模型返回的中间推理内容(如果厂商 API 支持的话)

Spring AI 有 Advisor 机制,可以在调用链路上做切面和日志。我建议从第一天就加上这个能力,不要等出了问题再补。等到上线后再补日志,你连当时发生了什么都不知道。

6.4 最后一个小技巧

没有兜底规则,Agent 系统永远不够格上生产。

我经历过一次印象特别深的 incident。当时用户问了一个不在任何工具能力范围内的问题,模型牛头不对马嘴地调用了一个工具,把耗时的接口命中了一次,结果返回的数据完全无关。用户看到的回答是“已为您处理”,实际上什么都没发生。

从那以后,我在系统提示词和工具返回两个层面都做了兜底:一是明确要求“没有合适工具时,如实告诉用户目前无法处理”;二是工具内对无效请求直接返回{"error":"参数异常"}。两层兜底叠起来,再也没有出现过“假装处理成功”的尴尬场面。

这个经验是那些漂亮架构图里不会写出来的东西,但每一套能稳定运行的生产级 Agent 系统,背后都离不开这种对失败场景的执着。做 Agent 不是做 demo,能稳住的系统才是真功夫。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/20 16:20:21

ESP-IDF V6.0工具目录迁移:自定义IDF_TOOLS_PATH,彻底解决C盘爆红问题

如果你最近升级到ESP-IDF V6.0&#xff0c;大概率会撞上同一个坑&#xff1a;装完一查&#xff0c;OpenOCD、xtensa工具链、Python环境全都被塞进了用户目录下的.espressif文件夹。我的C盘是256G的SSD&#xff0c;平时装完一堆开发套件已经快满了&#xff0c;再来一个ESP-IDF的…

作者头像 李华
网站建设 2026/10/20 16:19:51

放弃本地虚拟机,用VSCode Remote-SSH实现远程Linux开发

1. 为什么我最终放弃了本地虚拟机&#xff0c;转向远程开发如果你日常在Windows上写代码&#xff0c;但代码最终要跑在Linux服务器上&#xff0c;那你一定经历过这种割裂感&#xff1a;本地用着顺手的编辑器&#xff0c;代码写完却要手动scp上传&#xff0c;或者用Xshell这类终…

作者头像 李华
网站建设 2026/10/20 16:19:26

WinRE.wim与boot.wim区别解析及离线修改实操指南

搞系统维护的人&#xff0c;十个里有八个都跟这两个文件打过照面&#xff0c;但真能说清楚"WinRE.wim"和"boot.wim"到底有什么区别、各自该怎么处理的&#xff0c;恐怕不到一半。我干这行这些年&#xff0c;见过太多人把这两个文件混为一谈&#xff0c;结果…

作者头像 李华
网站建设 2026/10/20 16:18:34

基于cve-search搭建漏洞管理平台:从部署到安全运营闭环

最近接了个任务&#xff0c;帮某公司搭一套内部的漏洞管理平台。他们之前处理安全通告的方式&#xff0c;说实话挺原始的&#xff1a;安全团队收到一条CVE推送&#xff0c;就开始查内部资产清单&#xff0c;人工比对哪些系统用了受影响组件&#xff0c;再逐个发邮件催修复。等一…

作者头像 李华
网站建设 2026/10/20 16:18:14

icmpsh内网隧道实战:ICMP协议隐蔽通信原理与部署指南

1. 内网隧道与 ICMP 通道的核心定位内网渗透做到一定深度&#xff0c;绕不开一个现实问题&#xff1a;目标网络边界防护越来越严&#xff0c;常规的 TCP/UDP 出站流量被防火墙、入侵检测设备盯得很死&#xff0c;很多端口直接封禁&#xff0c;正向连接进不去&#xff0c;反向连…

作者头像 李华
网站建设 2026/10/20 16:17:37

ROS点云与图像bag压缩录制实战:从环境检查到LZ4参数调优

1. 数据爆炸是刚需&#xff1a;一次实测算出点云加图像直录有多夸张先说个我自己踩过的坑。有次在园区里做环境采集&#xff0c;车上装了某款16线激光雷达和一台工业彩色相机&#xff0c;想着先把原始数据都录下来再说。跑了大概四十分钟&#xff0c;回来一看磁盘&#xff0c;好…

作者头像 李华