Agent入门开发(2):个性化功能添加

上期文章我们完成了基础智能体的搭建,讲解了大模型接口调用、上下文记忆管理等核心实现,同时也指出了纯对话式 Agent 的天然短板:仅依托大模型静态知识库,无法获取实时数据、不具备外部能力拓展

本期将以实时天气查询、本地代码检测与修复两大个性化功能为例,讲解 Agent 工具增强的开发思路,通过接入第三方 API、本地文件读写等方式,弥补基础智能体的能力局限,实现自定义功能拓展,完成进阶版智能体开发。

一、实时天气查询

既然原生大模型智能体本身不具备联网能力,就必须借助第三方开放服务作为外部数据源。通过对接第三方官方接口,即可让本地智能体跨网络调取真实、最新的外部数据,此处我们以调用高德地图 api 为例。

1.密钥获取

进入高德开放平台 | 高德地图API,完成注册与实名认证后,点击控制台。

在应用管理处添加新应用后点击"添加Key",服务平台选择**"Web服务"** ,完成 Key 的添加。将其复制在程序中保存为静态变量 AMAP_KEY,它是调用高德地图天气等第三方服务的唯一授权凭证。

2.getWeather 方法

申请到 Key 后,我们就可以编写真正获取实时天气的功能方法 getWeather。该方法实现了智能体对接外部服务,遵循拼接请求地址 、 发送网络请求 、解析 JSON 数据 、安全处理与结果封装的流程。与调用大模型接口类似,该方法的模板较为固定,可以直接套用。

java 复制代码
//高德地图天气查询
//city 获取目标城市的数据
public static String getWeather(String city) throws Exception {

    // 1. 拼接请求地址:传入城市和密钥,构造完整接口URL
    String url = "https://restapi.amap.com/v3/weatherInfo?city=%s&key=%s".formatted(city, AMAP_KEY);

    // 2. 构建GET请求对象
    HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create(url))
            .GET()
            .build();
    
    // 3. 发送请求并获取响应
    HttpResponse<String> resp = httpClient.send(request, HttpResponse.BodyHandlers.ofString());

    // 4. 解析返回的JSON数据
    JsonNode root = mapper.readTree(resp.body());

    // 5. 安全校验与数据提取
    JsonNode lives = root.path("lives");
    if (lives.isEmpty()) {
        return "获取天气失败:" + root.path("info").asText();
    }

    JsonNode live = lives.get(0);
    // 6. 封装返回
    return "日期:%s\n城市:%s,天气:%s,温度:%s℃,风向:%s,湿度:%s"
            .formatted(
                    live.path("reporttime").asText(),
                    city,
                    live.path("weather").asText(),
                    live.path("temperature").asText(),
                    live.path("winddirection").asText(),
                    live.path("humidity").asText()
            );
}
3.智能体功能对接

可以看到,getWeather() 方法需要字符串类的实参 city。当我们询问天气时,智能体应该先提取出城市名字,再根据getWeather() 方法返回的 "日期:%s\n城市:%s,天气:%s,温度:%s℃,风向:%s,湿度:%s"语句做出相应回答。可见智能体可能需要多轮交互才能呈现用户想要的最终结果。因此,我们需对原代码略作调整,将程序与智能体收发消息的过程单独封装成 send() 方法。

java 复制代码
public static String send(String prompt) throws Exception {
    stringBu.append(prompt);

    Map<String, Object> body = new HashMap<>();
    body.put("model", "deepseek-chat");
    body.put("messages", new Object[]{Map.of("role", "user",
            "content", stringBu.toString())});
    body.put("temperature", 0.1); // 0 ~ 2 数字越小回答越严谨,越简单
    //用 ObjectMapper 把Map 转成json格式的字符串
    String json = mapper.writeValueAsString(body);
    //创建Http 请求对象
    HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create(URL))
            .header("Authorization", "Bearer " + API_KEY)
            .header("Content-Type", "application/json")
            .POST(HttpRequest.BodyPublishers.ofString(json))
            .build();
    //用HttpClient 发送请求对象,并且得到响应对象
    HttpResponse<String> resp = httpClient.send(request,
            HttpResponse.BodyHandlers.ofString());
    //把响应数据JSON转成java 对象
    JsonNode root = mapper.readTree(resp.body());
    String str =
            root.path("choices").get(0).path("message").path("content").asText();
    stringBu.append(str);
    return str;
}

这在上期文章已讲解,此处不再赘述。

原本的 chat() 方法则需要添加额外规则,让智能体能够"识别用户意图"和"调度外部工具"。

java 复制代码
public static String agentChat(String prompt) throws Exception{
    String input = """
     用户问题:%s
     规制:
     1.如果在查询天气信息 输出格式-> 天气:城市
     2.如果不是问天气信息,就正常回答
     回答问题简洁明了,不要捏造数据
    """.formatted(prompt);
    
    String resp = send(input);
    
    //根据响应消息调用对应的工具
    if(resp.startsWith("天气:")){
        String[] strArr = resp.split(":");
        String weather = getWeather(strArr[1]);
        String finalPrompt = "城市:%s 天气情况%s,用简洁的话帮我整理一下,带一句小提示,开头不要加天气:城市".formatted(strArr[1],weather);
        return send(finalPrompt);
    }
    
    return resp;
}

我们通过提示词规制约束大模型,让它看到天气问题时,必须输出固定格式"天气:城市"。程序通过识别这个特定指令,就能判断用户意图。当检测到返回结果以"天气:" 开头时,程序自动截取城市名,调用我们之前写好的 getWeather() 方法获取实时数据,再将真实天气数据发给大模型,让其整理成温暖、简洁的自然语言回答。

需要注意,大模型对提示词的要求较为严格,错别字或其它细微差异都可能导致其输出不符要求,遇到类似问题时可以尝试重新设计提示词。

4.结果演示

可以看到,智能体可以查询不同城市的实时天气信息了,并且就算问题中没有出现"天气"二字,智能体还是能通过上下文记忆推断出我们在询问天气。

二、本地代码检测与修复

除了实时天气查询这类获取外部数据的功能,我们还能为智能体添加本地文件操作类的实用能力。此处以修改桌面代码文件为例。

1.意图理解和功能选择

要在原基础上增添新功能,其实就是修改规则提示词并增加功能分支。

我们只需要在 chat 方法的提示词中,新增一条代码检查的识别规则,让 AI 在识别到检查、修改、桌面文件等相关指令时,按照固定格式"代码检查:文件名"输出,方便程序精准捕捉意图、自动触发对应功能。

同时在方法中增加代码检查分支判断,与天气查询功能保持一致的实现逻辑,让智能体可以同时支持天气查询、代码检测两大扩展功能。

java 复制代码
public static String chat(String prompt) throws Exception {
        String input = """
                用户问题:%s
                规制:
                    1.如果在查询天气信息 输出格式-> 天气:城市
                    2.如果不是问天气信息,就正常回答
                    3.要[检查/修改/桌面文件] 输出格式-> 代码检查:文件名.后缀
                    回答简洁明了,不要捏造数据
                """.formatted(prompt);
        String resp = send(input).trim();

        //根据响应消息调用对应的工具
        if (resp.startsWith("天气:")) {
            String[] strArr = resp.split(":");
            String weather = getWeather(strArr[1]);
            String finalPrompt = "城市:%s 天气情况%s,用简洁的话帮我整理一下,带一句小提示,开头不要加天气:城市".formatted(strArr[1], weather);
            return send(finalPrompt);
        }

        //判断是否需要修改代码文件
        if (resp.startsWith("代码检查:")) {
            String[] strArr = resp.split(":");
            String filePath = "C:\\Users\\Administrator\\Desktop\\" + strArr[1];
            //System.out.println("fileName:" + filePath);
            codeCheck(filePath);
        }
        return resp;
}
2.检查与纠错

上文代码中调用的 codeCheck() 方法即是检查与纠错功能的实现,它不需要第三方工具的数据,只用本地文件的读写。我们只需要得到文件路径,读取桌面指定代码文件的全部内容,再结合定制提示词交给大模型完成代码检测。如果有错误,我们还可通过控制台交互来选择是否执行修复操作,最终将优化后的代码重新写入本地文件,以此实现纯本地环境下的代码检查与自动纠错。

java 复制代码
//检查代码文件
public static void codeCheck(String filePath) throws Exception {
    File file = new File(filePath);
    //读取文件数据
    BufferedReader br = new BufferedReader(new FileReader(file));
    StringBuilder codeData = new StringBuilder();
    String line = "";
    while ((line = br.readLine()) != null) {
        codeData.append(line);
    }
    System.out.println("code:" + codeData.toString());

    //发给AI 检查
    String codePrompt = """
            你是专业编程机器,检查代码中是否存在以下问题
             1.代码格式错误
             2.代码语法错误
             3.代码逻辑错误
             源代码:%s
             如果代码没有错误,就直接提示代码没有明显错误。
            """.formatted(codeData);
    String codeResp = send(codePrompt);
    //System.out.println("AI:\n"+ codeResp);

    //提示:是否让AI 修改代码
    System.out.println("是否需要AI修改代码:(y/n)");
    Scanner scanner = new Scanner(System.in);
    String str = scanner.nextLine();

    if ("y".equalsIgnoreCase(str)) {
        String fixPrompt = """
                帮我修改代码中的错误,只输出代码内容,不要其它信息
                不要带上```java ``` 这个内容
                源代码:%s
                """.formatted(codeData);
        String fixCode = send(fixPrompt);

        //把修复的代码写入文件
        FileOutputStream fos = new FileOutputStream(file);
        fos.write(fixCode.getBytes());
        fos.flush();
        System.out.println("修改完成!");
    }
}
3.效果演示

我们先在桌面新建一个代码文件用于演示。

让智能体检查并纠错:

原文件被修改成正确版本:

三、总结与反思

由此我们拓宽了个人智能体的开发思路,完成了实时天气查询和本地代码检测与修复两大个性化功能添加,然而它们还有不少局限性,例如天气查询不能同时查找多个城市,无法查看往后天气;代码检修目前只能应用与桌面等。这些功能还能得到进一步优化。

同时,由于目前功能较少,我们可以通过叠加提示词和增添功能分支来完善智能体,但若往后智能体要拓展更多功能,这样的方式免不了造成代码冗余、维护困难等问题。这些潜在问题需要我们在后续的开发中一步步解决。

相关推荐
8486981191 小时前
Cursor 用 Java + Vue3 做了一个可落地的酒店管理系统(HMS),支持多门店、RBAC、财务结算,源码开源!
java·开发语言·开源
IP老炮不瞎唠2 小时前
什么是Grok?以及如何解决卡顿、风控问题
服务器·网络
淼淼爱喝水2 小时前
eNSP 防火墙 NAT 策略配置(Easy IP/No-PAT/NAPT/ 黑洞路由)
服务器·网络·tcp/ip·ensp·防火墙·nat
杨浦老苏2 小时前
AI使用追踪和代理网关GoModel
人工智能·docker·ai·api·群晖
程序员老邢2 小时前
【技术底稿 23】Ollama + Docker + Ubuntu 部署踩坑实录:网络通了,参数还在调
java·经验分享·后端·ubuntu·docker·容器·milvus
:1212 小时前
java数组2
java·算法·排序算法
2601_955256472 小时前
服务器日志管理最佳实践:logrotate配置详解、云日志服务对比与Docker日志限制方案
运维·服务器·docker
企业架构师老王2 小时前
药品生产环节:用实在Agent自动生成批记录与打印领料单的合规设计与架构落地
大数据·人工智能·ai·架构
叶子上的考拉2 小时前
解决远程连接服务器反应较慢问题
linux·运维·服务器