不学 Python,Java 也能调大模型?15 分钟跑通第一个 AI 接口(Java 架构师的 AI 工程笔记 01)

news2026/3/19 14:57:19
文章目录Java 架构师的 AI 工程笔记一5 个概念 第一次跟 AI 对话理论篇一、Java 工程师为什么能搞 AI Agent二、开始写代码之前你得搞懂这 5 个概念2.1 Token——LLM 的计费单位2.2 Prompt——你给 LLM 的指令2.3 Temperature——控制输出的稳定性2.4 Context Window——对话的内存大小2.5 Function Calling——Agent 的核心引擎三、Spring AI 的分层架构四、幻觉——LLM 一本正经地胡说实战篇五、跑通第一个对话程序5.1 申请通义千问 API Key5.2 项目结构5.3 配置文件5.4 启动类5.5 第一个对话接口5.6 Temperature 对比实验六、与机票比价 Agent 的集成七、FAQ 与踩坑记录本章小结Java 架构师的 AI 工程笔记一5 个概念 第一次跟 AI 对话这是 Spring AI Alibaba 系列的第一篇。目标让你的 Spring Boot 项目在 15 分钟内接入大模型对话能力。理论篇一、Java 工程师为什么能搞 AI Agent带团队做 AI 转型时最先被问到的问题就是“AI 不都是 Python 的吗我们 Java 团队能搞得了”想明白一件事就不纠结了。AI Agent 的核心不是训练模型而是工程化——把大模型的能力串起来做成一个能干活的系统。这恰恰是 Java 工程师擅长的工具注册和调度 → 你写了多年的 Spring 依赖注入多步编排和状态管理 → 你熟悉的工作流引擎高可用、可观测、分布式 → Java 生态的强项企业级落地 → Spring Boot 就是事实标准所以问题不是Java 能不能搞 AI而是有没有好用的框架。Spring AI Alibaba 就是答案——Spring 团队和阿里一起做的API 风格跟 Spring 全家桶一脉相承。二、开始写代码之前你得搞懂这 5 个概念不需要懂 Transformer 和 Attention 机制。但下面 5 个概念直接影响你写代码时的每一个决策跳过任何一个后面都会踩坑。2.1 Token——LLM 的计费单位Token 不是字也不是词是模型处理文本的最小单位。中文大约 1 个字 ≈ 1-2 个 Token。我想查北京到上海的机票 → 大约 12-15 个 Token为什么要关心这个因为它影响三件事影响说明钱API 按 Token 数计费输入和输出分别算容量一次对话能装的信息有上限Context Window速度Token 越多响应越慢通义千问的价格参考2025模型输入每百万 Token输出每百万 Token上下文长度qwen-turbo¥2¥6128Kqwen-plus¥4¥12128Kqwen-max¥20¥6032K开发建议调试用 qwen-turbo便宜上线用 qwen-plus均衡核心场景用 qwen-max最强。2.2 Prompt——你给 LLM 的指令Prompt 是你发给大模型的文本。它不是简单的输入而是有结构的角色作用示例System设定 AI 的人格和规则“你是一个专业机票分析师只回答机票相关问题”User用户的实际问题“帮我查北京到上海明天的机票”Assistant模型之前的回答用于多轮对话“已为您查到以下航班…”System Prompt 是 Agent 的灵魂。后面你会发现很多时候调 System Prompt 比改代码有用 10 倍。2.3 Temperature——控制输出的稳定性Temperature 是一个 0 到 1 之间的参数决定了 LLM 回答的随机程度。用 Java 来类比temperature0 就像一个确定性的switch-case给同样的输入永远走同一个分支temperature1 更像Random.nextInt()每次执行结果都不一样。Temperature效果适用场景0每次回答几乎相同Agent 工具调用、数据分析0.3轻微变化Agent 推荐值0.7默认值有一定随机性普通对话1.0每次都不一样创意写作怎么选一个合理的值看你的业务对一致性的要求场景推荐值原因Function Calling / 工具调用0参数必须精确随机性会导致 JSON 格式错误或传错参数Agent 决策与推理0 - 0.3推理链路要稳定但允许微小灵活性客服 / FAQ 问答0.3 - 0.5回答要准确但措辞可以自然一点不要像机器人普通对话 / 聊天0.7平衡准确性和趣味性大多数模型的默认值营销文案 / 创意写作0.8 - 1.0需要发散思维每次生成不同的表达一个实用的定值策略先从 0.7默认值开始发现输出太飘就往下调太死板就往上调。线上环境建议把 temperature 写进配置文件而不是硬编码方便随时调整。⚠️重点Agent 中涉及工具调用、结构化输出的环节建议用较低的 temperature0-0.3。但 Agent 不只有工具调用——如果某个环节需要生成面向用户的自然语言回复比如总结、推荐理由适当提高到 0.5-0.7 反而更自然。关键是按环节分别设置而不是整个 Agent 一刀切。2.4 Context Window——对话的内存大小Context Window 是一次对话能容纳的总 Token 数。所有东西都要塞进去System Prompt、历史对话、当前问题、工具描述、模型回答。超出上限怎么办旧的对话会被截断模型会忘掉之前聊过的内容。这就是为什么后面要专门学 Memory 管理第 4 章。2.5 Function Calling——Agent 的核心引擎这是最重要的概念。没有 Function Calling就没有 Agent。传统 LLM 只能输出文本。Function Calling 让 LLM 能够调用函数——准确说是 LLM 告诉你它想调用什么函数、传什么参数真正的执行由你的代码完成。关键点LLM 不直接调用 API——它只输出 JSON 格式的调用意图你的代码负责执行——接收意图调真正的 API结果喂回给 LLM——LLM 拿到结果后组织成自然语言回复用 Java 类比LLM 就像一个智能路由器根据用户请求决定调用哪个 Service 方法但它自己不执行方法。你写的 Service 才是干活的。三、Spring AI 的分层架构Spring AI 的设计跟 Spring Data 一个思路——统一抽象多种实现![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url…%2Fdocs%2Fdiagrams%2F01-spring-ai-arch.pngpos_idimg-mcMan5b9-1773812809398面向ChatModel接口编程底层换成任何 LLM 都不需要改业务代码。跟你用 JPA 换数据库一个道理。而ChatClient是 ChatModel 上面的高层封装关系类似JdbcTemplate和DataSource。日常开发用 ChatClient 就够了链式调用、拦截器、流式输出都支持。Spring AI Alibaba 在这套抽象之上提供了通义千问的完整实现加上百炼平台集成、增强 RAG 等额外能力。四、幻觉——LLM 一本正经地胡说这个必须单独拿出来说因为它是 Agent 开发中最容易踩的坑。LLM 会非常自信地给出完全编造的答案用户: 国航 CA1234 航班什么时候起飞 LLM: 国航 CA1234 航班每天 08:30 从北京首都机场起飞 ← 完全编造的因为 LLM 本质是文本接龙——预测最可能的下一个 Token不是查事实。这也是 Agent 存在的核心原因之一Agent 通过 Function Calling 获取真实数据而不是让 LLM 瞎编。我们的机票比价 Agent 不会编造票价而是调用真实 API 查询。实战篇五、跑通第一个对话程序5.1 申请通义千问 API Key访问阿里云百炼平台注册并登录进入控制台在左侧菜单找到「API-KEY 管理」点击「创建 API Key」选择默认业务空间复制生成的 Keysk-xxxx 格式后面配置要用 新账号有免费额度够学完这个系列。5.2 项目结构整个系列用 Maven 父子工程管理每章一个子模块spring-ai-alibaba-course/ ├── pom.xml ← 父 POMBOM 版本管理 ├── quick-start/ ← 本章代码 │ ├── pom.xml │ └── src/main/java/com/ai/course/quickstart/ │ ├── QuickStartApplication.java │ └── controller/ │ └── ChatController.java ├── chat-client/ ← 第 2 章后续添加 ├── function-calling/ ← 第 3 章后续添加 └── ... ← 每章一个子模块父 POM 的核心配置完整代码见仓库propertiesjava.version21/java.versionspring-boot.version3.5.11/spring-boot.versionspring-ai-alibaba.version1.1.2.2/spring-ai-alibaba.version/propertiesdependencyManagementdependencies!-- Spring Boot BOM --dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-dependencies/artifactIdversion${spring-boot.version}/versiontypepom/typescopeimport/scope/dependency!-- Spring AI Alibaba BOM --dependencygroupIdcom.alibaba.cloud.ai/groupIdartifactIdspring-ai-alibaba-bom/artifactIdversion${spring-ai-alibaba.version}/versiontypepom/typescopeimport/scope/dependency/dependencies/dependencyManagement为什么不用spring-boot-starter-parent做 parent因为它会锁死 parent 位置。通过 BOM 导入既统一了版本又保留了自定义父 POM 的自由度。子模块 POMquick-start/pom.xml——注意依赖不写版本号全部由父 POM 管理parentgroupIdcom.ai.course/groupIdartifactIdspring-ai-alibaba-course/artifactIdversion1.0.0/version/parentartifactIdquick-start/artifactIddependenciesdependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependencydependencygroupIdcom.alibaba.cloud.ai/groupIdartifactIdspring-ai-alibaba-starter-dashscope/artifactId/dependency/dependencies5.3 配置文件# quick-start/src/main/resources/application.ymlspring:application:name:quick-startai:dashscope:api-key:${AI_DASHSCOPE_API_KEY}# 通过环境变量注入别硬编码chat:options:model:qwen-plustemperature:0.7server:port:8080⚠️安全提醒API Key 永远不要写在代码里。设置环境变量Linux/Macexport AI_DASHSCOPE_API_KEYsk-xxxxxWindowsset AI_DASHSCOPE_API_KEYsk-xxxxxIDEARun Configuration → Environment variables5.4 启动类packagecom.ai.course.quickstart;importorg.springframework.boot.SpringApplication;importorg.springframework.boot.autoconfigure.SpringBootApplication;SpringBootApplicationpublicclassQuickStartApplication{publicstaticvoidmain(String[]args){SpringApplication.run(QuickStartApplication.class,args);}}5.5 第一个对话接口Spring AI 推荐用ChatClient高层 API而不是底层的ChatModel。关系就像JdbcTemplate和DataSourcepackagecom.ai.course.quickstart.controller;importorg.springframework.ai.chat.client.ChatClient;importorg.springframework.web.bind.annotation.*;importreactor.core.publisher.Flux;RestControllerRequestMapping(/api/chat)publicclassChatController{// 用 ChatClient 而不是 ChatModel —— 链式 API 更简洁支持 Advisor 拦截privatefinalChatClientchatClient;publicChatController(ChatClient.BuilderchatClientBuilder){this.chatClientchatClientBuilder.defaultSystem(你是一个友好的AI助手。).build();}/** * 同步对话 * 试试GET /api/chat?message你好 */GetMappingpublicStringchat(RequestParam(valuemessage,defaultValue你好)Stringmessage){returnchatClient.prompt().user(message).call().content();}/** * 流式对话 —— 打字机效果 * 试试GET /api/chat/stream?message介绍一下春季热门航线 */GetMapping(value/stream,producestext/html;charsetUTF-8)publicFluxStringchatStream(RequestParam(valuemessage,defaultValue你好)Stringmessage){returnchatClient.prompt().user(message).stream().content();}}启动项目打开浏览器访问http://localhost:8080/api/chat?message你好你应该能看到通义千问的回复。流式接口/api/chat/stream会一个字一个字地吐出来体验明显好很多。LLM 生成完整回答可能要 5-10 秒流式让用户边生成边看到不用干等。5.6 Temperature 对比实验理论篇讲了 Temperature 影响输出稳定性现在亲眼看看。加一个实验接口packagecom.ai.course.quickstart.controller;importorg.slf4j.Logger;importorg.slf4j.LoggerFactory;importorg.springframework.ai.chat.client.ChatClient;importorg.springframework.ai.chat.prompt.ChatOptions;importorg.springframework.web.bind.annotation.*;importjava.util.*;importjava.util.concurrent.CompletableFuture;RestControllerRequestMapping(/api/experiment)publicclassExperimentController{privatestaticfinalLoggerlogLoggerFactory.getLogger(ExperimentController.class);privatefinalChatClientchatClient;publicExperimentController(ChatClient.Builderbuilder){// 通过 System Prompt 限制回答长度让对比更直观this.chatClientbuilder.defaultSystem(你是一个简洁的助手回答限制在20字以内。).build();}/** * Temperature 对比实验 * GET /api/experiment/temperature?message用一个词形容春天 * * 同一问题分别用 temperature 0 和 1.0 各调用 3 次 * temperature0 的回答几乎相同temperature1.0 每次都不一样 */GetMapping(/temperature)publicMapString,ListStringtemperatureExperiment(RequestParam(valuemessage,defaultValue用一个词形容春天)Stringmessage){double[]temperatures{0.0,1.0};introunds3;log.info(开始 Temperature 对比实验消息{},message);MapString,CompletableFutureListStringfuturesnewLinkedHashMap();for(doubletemp:temperatures){Stringkeytemperature_temp;futures.put(key,CompletableFuture.supplyAsync(()-{ListStringresponsesnewArrayList();for(inti0;irounds;i){log.info([{}] 第 {} 次调用开始...,key,i1);longstartSystem.currentTimeMillis();StringcontentchatClient.prompt().user(message).options(ChatOptions.builder().temperature(temp).build()).call().content();longcostSystem.currentTimeMillis()-start;log.info([{}] 第 {} 次调用完成耗时 {}ms回答{},key,i1,cost,content);responses.add(content);}returnresponses;}));}MapString,ListStringresultsnewLinkedHashMap();futures.forEach((key,future)-results.put(key,future.join()));log.info(Temperature 对比实验完成);returnresults;}}直接访问GET /api/experiment/temperature默认问题用一个词形容春天你会看到类似结果{temperature_0.0:[温暖,温暖,温暖],temperature_1.0:[生机,温柔,绚烂]}temperature0三次回答完全一样——输出稳定可预测temperature1.0每次回答都不同——充满随机性和创意这就是为什么 Agent 场景要用低 temperature——你需要 LLM 的输出稳定可预测。六、与机票比价 Agent 的集成本章搭建的 quick-start 是整个系列的起点。后面的章节会在这个基础上逐步加能力第 2 章用 ChatClient 的 Advisor 和 Prompt 模板让对话更可控第 3 章通过 Function Calling 接入机票查询工具从编造数据进化为查真实数据第 4 章加 Memory实现多轮对话“北京飞上海” → “明天的” → “最便宜的”当前模块的配置模型、温度和父 POM 的依赖管理会被所有后续模块复用。七、FAQ 与踩坑记录Q1启动报错No qualifying bean of type ChatModel最常见的原因是缺依赖或者环境变量没设确认 pom.xml 里有spring-ai-alibaba-starter-dashscope确认环境变量AI_DASHSCOPE_API_KEY已设置且值正确确认 application.yml 里用的是${AI_DASHSCOPE_API_KEY}而不是写死的 KeyQ2调用报401 Unauthorized或InvalidApiKeyKey 无效或过期。到百炼平台检查 Key 状态。新账号第一次使用需要先开通百炼服务并创建 API Key。另外看看环境变量里的 Key 有没有多余的空格或换行。Q3流式接口返回乱码三个排查方向GetMapping的produces必须是text/event-stream;charsetUTF-8如果有 Nginx 反代加proxy_buffering off;浏览器直接访问 SSE 显示可能不友好用curl或前端EventSource测Q4第一次调用特别慢10 秒以上正常。第一次请求涉及到底层 HTTP 连接建立、模型加载等。后续请求会快很多。如果持续很慢检查网络是否需要代理。本章小结理论篇实战篇Token 与计费环境搭建Prompt 三种角色同步对话Temperature 稳定性流式输出Context Window 容量Temperature 实验Function Calling 核心下一章ChatClient 的高级用法和 Prompt 工程。会用到 Advisor 拦截器、Prompt 模板、结构化输出——让 LLM 的返回直接变成 Java 对象。本文代码GitHub - quick-start 模块如果这篇文章对你有帮助欢迎点赞收藏。有问题欢迎评论区交流。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2426729.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…

网络编程(Modbus进阶)

思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…