Spring AI对接Deepseek 使用Charles代理api.deepseek.com 拦截报文,查看Tool和Skill的本质

目录

出发

SkillController

OrderTools

[Skill SKILL.md](#Skill SKILL.md)

官网

安装和注册

安装电脑端的证书

核查&查找证书

[配置SSL Proxy代理](#配置SSL Proxy代理)

IDEA本地启动VM添加代理

Java导入证书

测试验证


出发

通过Charles 拦截,spring ai 对接 Deepseek 的报文。

SkillController

java 复制代码
package com.haiwei.javaai.controller;

import com.haiwei.javaai.tool.LoggingAdvisor;
import com.haiwei.javaai.tool.OrderTools;
import lombok.extern.slf4j.Slf4j;
import org.springaicommunity.agent.tools.SkillsTool;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.tool.ToolCallback;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@Slf4j
@RestController
public class SkillController {

    private final ChatClient chatClient;

    private final OrderTools orderTools;

    public SkillController(ChatClient.Builder chatClientBuilder, ResourceLoader resourceLoader, OrderTools orderTools) {
        // 加载Skill文件
        Resource resource = resourceLoader.getResource("classpath:skills");

        // 将Skill添加为Skill Tool
        ToolCallback skillsTool = SkillsTool.builder()
                .addSkillsResource(resource)
                .build();

        // 生成Chat Client 添加默认Skill 和 日志
        this.chatClient = chatClientBuilder
                .defaultTools(skillsTool)
                .defaultAdvisors(new LoggingAdvisor())
                .build();

        // 添加工具
        this.orderTools = orderTools;
    }

    @GetMapping("/char/get1")
    public Object get1() {

        String message = "帮我查一下订单123456的状态";

        log.info("Start call LLM,message:{}");
        String content = chatClient.prompt()
                .user(message)
                // 添加工具类
                .tools(orderTools)
                .call().content();
        log.info(content);
        return content;
    }

}

OrderTools

java 复制代码
package com.haiwei.javaai.tool;

import com.haiwei.javaai.utils.JsonUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.ai.tool.annotation.ToolParam;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;

@Slf4j
@Component
public class OrderTools {

    @Tool(description = "根据订单ID查询订单详情,返回订单状态、金额、创建时间等信息")
    public Object getOrderById(
            @ToolParam(description = "订单ID") Long orderId
    ) {
        Map<String, Object> map = new HashMap<>();
        map.put("orderId", orderId);
        map.put("price", "2000");
        map.put("state", "待发货");
        log.info("getOrderById ,result:{}", JsonUtil.toJson(map));
        return map;
    }

    @Tool(description = "查询今日新增订单数量")
    public int getTodayOrderCount() {
        log.info("getTodayOrderCount ,result:{}", 11);
        return 11;
    }

    @Tool(description = "取消指定订单,需要订单ID")
    public boolean cancelOrder(
            @ToolParam(description = "要取消的订单ID") Long orderId
    ) {
        log.info("cancelOrder ,orderId:{},result:{}", orderId, false);
        return false;
    }
}

Skill SKILL.md

java 复制代码
---
name: team-java-standards
description: Review code against team Java coding standards.
  Use for all code review tasks.
---

# Team Java Coding Standards Review

## Instructions

审查代码时,检查以下团队规范:

### 强制规范(违反必须指出)
1. 禁止 @Autowired 字段注入,使用构造器注入
2. Controller 方法必须有 @Operation 注解(Springdoc OpenAPI)
3. 不允许在 Controller 中直接处理异常,使用 @RestControllerAdvice

### 建议规范(违反给出建议)
4. Service 方法建议添加 @Transactional(readOnly=true)
5. DTO 和 Entity 之间必须使用 MapStruct 转换
6. 日志使用 Slf4j,禁止 System.out.println

## Output Format

输出格式:
- 🔴 强制规范违反:(行号) 说明 + 问题代码 + 修正代码
- 🟡 建议规范违反:(行号) 说明 + 问题代码 + 修正代码
- ✅ 通过项:简要说明
- 不同问题之间使用 ================================== 隔离

官网

Charles Web Debugging Proxy

Charles 是一个 HTTP 代理 / HTTP 监控器 / 反向代理,它使开发者能够查看其机器与互联网之间所有的 HTTP 和 SSL / HTTPS 流量。这包括请求、响应以及 HTTP 头信息(其中包含 cookie 和缓存信息)。

安装和注册

注册:首次打开的Charles需要注册

点击Help ------ Register Charles进入注册界面

填入Registered Name和生成的license key,点击 Register

注册成功后,Charles会提示是否关闭,同意关闭后再手动打开

在线破解链接:https://www.zzzmode.com/mytools/charles/

在链接中输入Registered Name,点击生成,即可生成激活码license key

安装电脑端的证书

如果不配置证书的话,无法抓取Https请求,Https请求会是Unknown

点击Help ---> SSL Proxying---> install charles Root Certificate

注意:证书信息中的文字,需要安装到【收信人的证书颁发结构】存储区域,不能使用默认

注意:如果按照默认安装路径,则会按照到【中间正式办法机构】中,是不受信任的,如下

这里就需要选证书存储类型了,如下:

最后【下一步】点击是,即可成功。

核查&查找证书

打开证书页面:按 Win + R,输入 certmgr.msc 并回车

输入Charles,点击【立即查找】

双击打开:

重新安装:点击help -> SSL Proxying -> Install Charles Root Certificate 安装证书

多次安装的目录:

两个问题:

  1. 路径不对,没有安装到【受信任的***】
  2. 截止时间不对

全部删除,重新安装

以管理员身份重新运行Charles:

重新安装后时间就对了:

配置SSL Proxy代理

添加SSL Proxying Setting:

这样配置后依然有问题:

Charles 安装的root cat,并且已经配置了ssl proxy。 为什么 使用spring ai对接Deepseekapi时,访问成功了,但charles没有拦截到

IDEA本地启动VM添加代理

点击顶部工具栏的 "Edit Configurations..."(或从 Run -> Edit Configurations)

在左侧选择你的Spring Boot启动类

在右侧找到 "VM options" 输入框,粘贴以下内容:

-Dhttp.proxyHost=127.0.0.1 -Dhttp.proxyPort=8888 -Dhttps.proxyHost=127.0.0.1 -Dhttps.proxyPort=8888

重新启动:访问,可以看到已经抓到了,但是乱码

修改代理为:api.deepseek.com则java代码报错:

un.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

这个错误说明Java不信任Charles的根证书。虽然你在Charles中导入了根证书到系统信任库,但Java有自己独立的信任库(cacerts),需要单独导入。

解决方案:将Charles证书导入Java信任库

Java导入证书

保存证书:

添加pem文件名称,并将charles.pem复制到C:/下

导入:Windows(以管理员身份运行CMD),执行命令:

keytool -import -alias charles -file C:\charles.pem -keystore "%JAVA_HOME%\lib\security\cacerts" -storepass changeit -noprompt

验证是否成功:

keytool -list -keystore "%JAVA_HOME%\lib\security\cacerts" -storepass changeit | findstr charles

如果看到类似 charles, 日期, trustedCertEntry,说明导入成功。

测试验证

可以抓包,并是明文了

报文参考:

复制代码
第一次请求:
request:
{
	"messages": [{
		"content": "帮我查一下订单123456的状态",
		"role": "user"
	}],
	"model": "deepseek-chat",
	"tools": [{
		"function": {
			"name": "Skill",
			"description": "Execute a skill within the main conversation\n\n<skills_instructions>\nWhen users ask you to perform tasks, check if any of the available skills below can help complete the task more effectively. Skills provide specialized capabilities and domain knowledge.\n\nHow to use skills:\n- Invoke skills using this tool with the skill name only (no arguments)\n- When you invoke a skill, you will see <command-message>The \"{name}\" skill is loading</command-message>\n- The skill's prompt will expand and provide detailed instructions on how to complete the task\n\nNOTE: Response always starts start with the base directory of the skill execution environment. You can use this to retrieve additional files of call shell commands.\nSkill description follows after the base directory line.\n\nImportant:\n- Only use skills listed in <available_skills> below\n- Do not invoke a skill that is already running\n</skills_instructions>\n\n<available_skills>\n<skill>\n  <name>team-java-standards</name>\n  <description>Review code against team Java coding standards.</description>\n</skill>\n</available_skills>\n",
			"parameters": {
				"$schema": "https://json-schema.org/draft/2020-12/schema",
				"type": "object",
				"properties": {
					"command": {
						"type": "string",
						"description": "The skill name (no arguments). E.g., \"pdf\" or \"xlsx\""
					}
				},
				"required": ["command"],
				"additionalProperties": false,
				"strict": true
			}
		},
		"type": "function"
	}, {
		"function": {
			"name": "getTodayOrderCount",
			"description": "查询今日新增订单数量",
			"parameters": {
				"$schema": "https://json-schema.org/draft/2020-12/schema",
				"type": "object",
				"properties": {},
				"required": [],
				"additionalProperties": false,
				"strict": true
			}
		},
		"type": "function"
	}, {
		"function": {
			"name": "getOrderById",
			"description": "根据订单ID查询订单详情,返回订单状态、金额、创建时间等信息",
			"parameters": {
				"$schema": "https://json-schema.org/draft/2020-12/schema",
				"type": "object",
				"properties": {
					"orderId": {
						"type": "integer",
						"description": "订单ID"
					}
				},
				"required": ["orderId"],
				"additionalProperties": false,
				"strict": true
			}
		},
		"type": "function"
	}, {
		"function": {
			"name": "cancelOrder",
			"description": "取消指定订单,需要订单ID",
			"parameters": {
				"$schema": "https://json-schema.org/draft/2020-12/schema",
				"type": "object",
				"properties": {
					"orderId": {
						"type": "integer",
						"description": "要取消的订单ID"
					}
				},
				"required": ["orderId"],
				"additionalProperties": false,
				"strict": true
			}
		},
		"type": "function"
	}]
}


response:
{
	"id": "0c6472cf-59ec-476d-9ba2-f287dd6ddafb",
	"object": "chat.completion",
	"created": 1784780816,
	"model": "deepseek-v4-flash",
	"choices": [{
		"index": 0,
		"message": {
			"role": "assistant",
			"content": "好的,我来查询订单123456的详细信息。",
			"tool_calls": [{
				"index": 0,
				"id": "call_00_1KTYLj2phdBZEQjwsLbF3305",
				"type": "function",
				"function": {
					"name": "getOrderById",
					"arguments": "{\"orderId\": 123456}"
				}
			}]
		},
		"logprobs": null,
		"finish_reason": "tool_calls"
	}],
	"usage": {
		"prompt_tokens": 805,
		"completion_tokens": 56,
		"total_tokens": 861,
		"prompt_tokens_details": {
			"cached_tokens": 768
		},
		"prompt_cache_hit_tokens": 768,
		"prompt_cache_miss_tokens": 37
	},
	"system_fingerprint": "fp_8b330d02d0_prod0820_fp8_kvcache_20260402"
}


第二次请求:
request:
{
	"messages": [{
		"content": "帮我查一下订单123456的状态",
		"role": "user"
	}, {
		"role": "assistant",
		"content": "好的,我来查询订单123456的详细信息。",
		"tool_calls": [{
			"id": "call_00_1KTYLj2phdBZEQjwsLbF3305",
			"function": {
				"arguments": "{\"orderId\": 123456}",
				"name": "getOrderById"
			},
			"type": "function",
			"index": 0
		}]
	}, {
		"content": "{\"orderId\":123456,\"price\":\"2000\",\"state\":\"待发货\"}",
		"role": "tool",
		"tool_call_id": "call_00_1KTYLj2phdBZEQjwsLbF3305"
	}],
	"model": "deepseek-chat",
	"tools": [{
		"function": {
			"name": "Skill",
			"description": "Execute a skill within the main conversation\n\n<skills_instructions>\nWhen users ask you to perform tasks, check if any of the available skills below can help complete the task more effectively. Skills provide specialized capabilities and domain knowledge.\n\nHow to use skills:\n- Invoke skills using this tool with the skill name only (no arguments)\n- When you invoke a skill, you will see <command-message>The \"{name}\" skill is loading</command-message>\n- The skill's prompt will expand and provide detailed instructions on how to complete the task\n\nNOTE: Response always starts start with the base directory of the skill execution environment. You can use this to retrieve additional files of call shell commands.\nSkill description follows after the base directory line.\n\nImportant:\n- Only use skills listed in <available_skills> below\n- Do not invoke a skill that is already running\n</skills_instructions>\n\n<available_skills>\n<skill>\n  <name>team-java-standards</name>\n  <description>Review code against team Java coding standards.</description>\n</skill>\n</available_skills>\n",
			"parameters": {
				"$schema": "https://json-schema.org/draft/2020-12/schema",
				"type": "object",
				"properties": {
					"command": {
						"type": "string",
						"description": "The skill name (no arguments). E.g., \"pdf\" or \"xlsx\""
					}
				},
				"required": ["command"],
				"additionalProperties": false,
				"strict": true
			}
		},
		"type": "function"
	}, {
		"function": {
			"name": "getTodayOrderCount",
			"description": "查询今日新增订单数量",
			"parameters": {
				"$schema": "https://json-schema.org/draft/2020-12/schema",
				"type": "object",
				"properties": {},
				"required": [],
				"additionalProperties": false,
				"strict": true
			}
		},
		"type": "function"
	}, {
		"function": {
			"name": "getOrderById",
			"description": "根据订单ID查询订单详情,返回订单状态、金额、创建时间等信息",
			"parameters": {
				"$schema": "https://json-schema.org/draft/2020-12/schema",
				"type": "object",
				"properties": {
					"orderId": {
						"type": "integer",
						"description": "订单ID"
					}
				},
				"required": ["orderId"],
				"additionalProperties": false,
				"strict": true
			}
		},
		"type": "function"
	}, {
		"function": {
			"name": "cancelOrder",
			"description": "取消指定订单,需要订单ID",
			"parameters": {
				"$schema": "https://json-schema.org/draft/2020-12/schema",
				"type": "object",
				"properties": {
					"orderId": {
						"type": "integer",
						"description": "要取消的订单ID"
					}
				},
				"required": ["orderId"],
				"additionalProperties": false,
				"strict": true
			}
		},
		"type": "function"
	}]
}



response:
{
	"id": "bd07b4f8-1398-4cb0-b800-278024fc3c14",
	"object": "chat.completion",
	"created": 1784780817,
	"model": "deepseek-v4-flash",
	"choices": [{
		"index": 0,
		"message": {
			"role": "assistant",
			"content": "订单 **123456** 的详细信息如下:\n\n| 字段 | 内容 |\n|------|------|\n| **订单编号** | 123456 |\n| **订单金额** | ¥2,000.00 |\n| **订单状态** | ⏳ **待发货** |\n\n目前该订单处于 **待发货** 状态,尚未发货。请问还有其他需要帮忙的吗?"
		},
		"logprobs": null,
		"finish_reason": "stop"
	}],
	"usage": {
		"prompt_tokens": 889,
		"completion_tokens": 79,
		"total_tokens": 968,
		"prompt_tokens_details": {
			"cached_tokens": 768
		},
		"prompt_cache_hit_tokens": 768,
		"prompt_cache_miss_tokens": 121
	},
	"system_fingerprint": "fp_8b330d02d0_prod0820_fp8_kvcache_20260402"
}
相关推荐
niaiheni3 小时前
Fastjson 1.2.83 “Gadget-Free“ RCE
网络·安全·web安全
意疏3 小时前
远程办公软件哪个安全性高?UU远程8项安全防线全覆盖
网络·安全
牛马之星4 小时前
气体涡轮流量计如何维护
网络·经验分享
MonolithIoT4 小时前
实战方案|设备备件无人值守仓库:连续化产线运维备件 7×24 小时数字化管控方案
运维·网络·数据库
三8445 小时前
BGP/GRE练习
网络
念恒123066 小时前
网络基础
linux·网络·c++
白山云北诗6 小时前
漏洞扫描+渗透测试:从资产摸底到风险验证,完成二次安全收口
网络·安全·web安全·渗透测试·漏洞扫描·ddos防护·cc防护
爱研究的小梁7 小时前
乾元通聚合路由及管理平台支持全面适配信创
网络·人工智能·信息与通信