
1. 项目概述这不是“第九掌”而是Spring AI在阿里云生态落地的实战切口“降SpringAI阿里第9掌-或跃在渊-ReactAgent”——这个标题乍看像武侠小说里的秘籍名但拆开来看它其实是一条非常精准的技术路径信号“降”不是贬义而是指降低接入门槛、降低使用成本、降低运维复杂度“Spring AI”是核心框架“阿里”明确指向阿里云基础设施与服务生态“第9掌”是戏谑说法实则暗示这是系列化实践中的关键一环而“或跃在渊”出自《周易》形容蓄势待发、临界突破的状态精准对应当前Spring AI在企业级Agent开发中从概念验证走向生产部署的转折点最后的“ReactAgent”是技术落点——一个基于React模式构建、可响应式调度工具与记忆、具备状态管理能力的智能体。我从去年底开始在三个客户现场推进Spring AI Agent落地其中两个跑在阿里云ECSRDSOSS组合上一个直接部署在阿里云Serverless应用引擎SAE。过程中最常被问到的问题就是“Spring Boot项目怎么无缝对接阿里云的向量库、大模型API、对象存储和消息队列”——这恰恰是本项目要解决的底层缝合问题。它不讲大模型原理不堆Prompt工程技巧只聚焦一件事让一个标准Spring Boot工程在不改一行业务逻辑的前提下通过最小依赖变更和配置调整原生支持阿里云全栈AI服务并能以React模式驱动多步骤任务流。关键词“SpringAI”“阿里”“ReactAgent”不是并列关系而是层级依赖SpringAI是骨架阿里是血肉提供算力、存储、网络、安全等基础能力ReactAgent是神经反射系统定义“感知-决策-执行-反馈”的闭环节奏。所谓“降”本质是把原本需要手动拼接OpenAI/Anthropic SDK、自建向量库、硬编码OSS上传逻辑的散装方案收束进Spring AI官方抽象层并用阿里云官方SDK做深度适配。比如你不再需要写ossClient.putObject(...)而是声明一个AliyunOssToolBean再把它注册进ToolRegistryAgent运行时自动调用——这才是真正的“降维”。这个项目适合三类人一是正在用Spring Boot做后台系统的Java工程师想快速给现有系统加AI能力二是负责AI平台建设的架构师需要评估Spring AI在阿里云环境的可行性与扩展瓶颈三是刚学完LangChain/Spring AI基础、卡在“本地跑通→线上部署”这一关的开发者。它不教你怎么写100行Prompt但会告诉你当你的Agent要调用阿里云短信API发验证码时如何让TextToSpeechTool自动注入AcsClient实例且密钥管理符合阿里云RAM最佳实践当Agent需要读取用户上传到OSS的PDF合同并提取条款时如何让DocumentLoaderTool天然支持oss://bucket-name/path/file.pdf协议。这些细节才是真实世界里“能用”和“好用”的分水岭。2. 整体设计思路为什么选择React模式而非Chain为什么必须绑定阿里云2.1 ReactAgent不是新发明而是对Spring AI原生能力的精准补位Spring AI 0.8.x之后官方明确将ChatClient作为核心交互入口但默认提供的DefaultChatClient本质上仍是单轮问答模式Single-turn。当你需要让Agent完成“查订单→解析发票→比对金额→触发退款”这样的多跳任务时就必须自己实现状态维护、工具调用链路、错误回滚机制——这正是React模式的价值所在。ReactReason, Act, Observe不是指前端框架React.js而是认知科学中的反应式智能体范式Agent持续观察环境Observe、基于规则或LLM推理决定下一步动作Reason、执行具体操作Act然后循环。Spring AI本身不内置React引擎但提供了ToolExecutor、MessageHistory、StatefulChatMemory等模块足够我们搭出轻量级React内核。我试过两种方案第一种是直接集成LangChain4j的ReactExecutor但它与Spring AI的ChatModel抽象层存在类型冲突需大量Adapter代码第二种是基于Spring AI的ChatClientToolRegistry 自研ReactLoop仅增加3个核心类ReactState、ReactStep、ReactEngine却完全复用Spring AI的配置体系、消息序列化、流式响应等能力。最终选了后者因为它的侵入性最低——你现有的Bean ChatClient chatClient()配置无需改动只需额外声明Bean ReactEngine reactEngine()所有旧有Prompt模板、SystemMessage、Tool定义全部兼容。这正是“降”的第一层含义不颠覆现有技术栈只做增量增强。2.2 阿里云绑定不是厂商锁定而是对国产化基础设施的务实适配标题里强调“阿里”绝非营销噱头。当前国内企业级AI落地面临三大刚性约束数据不出域、API调用受控、运维体系统一。阿里云恰好覆盖这三点百炼大模型API满足合规要求RDS PostgreSQL PGVector插件提供成熟向量数据库方案OSS提供高可靠对象存储RAM权限体系确保密钥最小化授权。更重要的是阿里云SDKaliyun-java-sdk-*与Spring生态深度整合——spring-cloud-starter-alicloud-oss、spring-cloud-starter-alicloud-acm等starter已成事实标准。对比其他云厂商阿里云在Java生态的适配成熟度更高。举个例子Spring AI的EmbeddingClient接口需要实现向量化逻辑AWS Bedrock需处理复杂的签名V4而阿里云百炼API仅需AcsClientCommonRequest且官方SDK已内置重试、熔断、日志埋点。再如OSS文件加载MinIO需自行处理Endpoint、Region映射而aliyun-spring-boot-starter-oss直接通过spring.cloud.alicloud.oss.*配置即可注入OssTemplate。这种“开箱即用”的体验大幅降低了ReactAgent的工程化成本。所以“绑定阿里云”本质是选择一条阻力最小、审计友好的国产化落地路径而非技术偏好。2.3 “或跃在渊”的真实含义从单点工具调用迈向业务流程编织很多团队卡在“Agent能调API但不会编排业务”。比如一个电商客服Agent能查订单也能发短信但无法自动判断“订单超时未支付→触发催付短信→若30分钟未支付→关闭订单”。这就是React模式要解决的核心问题——状态驱动的流程编织Orchestration。我们设计的ReactAgent内核包含四个不可变状态IDLE等待输入、REASONINGLLM生成Action Plan、ACTING执行Tool、OBSERVING接收Tool返回并更新Context。每个状态转换都由ReactStep定义而ReactStep本身是Spring Bean支持Autowired注入任意Service这意味着你可以把“检查库存”、“调用风控接口”、“写审计日志”等业务逻辑无缝嵌入Agent执行流。这种设计让Agent不再是黑盒LLM调用器而是可调试、可监控、可审计的业务组件。我们在某银行项目中将ReactAgent嵌入信贷审批流程当用户提交申请Agent自动调用CreditScoreTool对接内部评分系统、IdentityVerifyTool调用人脸识别API、RiskAssessTool调用风控模型每步结果存入ReactState失败时自动触发FallbackStep转人工审核。整个过程在SkyWalking中呈现为清晰的Span链路运维人员一眼就能看出卡在哪一步。这才是“或跃在渊”的实质——Agent已具备跃出技术Demo深渊、潜入真实业务深水区的能力。3. 核心细节解析Spring AI 阿里云的七处关键缝合点3.1 Maven配置为什么必须用阿里云Maven仓库镜像Spring AI的里程碑版本如0.8.1发布在Spring Milestone仓库而国内访问该仓库极不稳定。直接配置repository会导致mvn clean compile卡在下载spring-ai-core依赖上。解决方案不是换镜像站而是用阿里云Maven仓库代理所有远程源。关键配置如下!-- pom.xml -- repositories repository idaliyun-maven/id urlhttps://maven.aliyun.com/repository/public/url releases enabledtrue/enabled /releases snapshots enabledfalse/enabled /snapshots /repository !-- Spring Milestone仓库代理 -- repository idspring-milestones/id urlhttps://maven.aliyun.com/repository/spring-milestones/url releases enabledfalse/enabled /releases snapshots enabledtrue/enabled /snapshots /repository /repositories注意两点第一spring-milestones仓库的URL必须是https://maven.aliyun.com/repository/spring-milestones而非https://repo.spring.io/milestone这是阿里云官方镜像地址第二snapshotsenabledtrue/enabled/snapshots必须开启因为Spring AI的预发布版如0.8.1-M1属于Snapshot版本。我曾因漏掉此配置导致spring-ai-spring-boot-starter始终拉取不到最新版白白浪费两天排查时间。更进一步建议在~/.m2/settings.xml中全局配置镜像mirrors mirror idaliyunmaven/id mirrorOf*/mirrorOf name阿里云公共仓库/name urlhttps://maven.aliyun.com/repository/public/url /mirror /mirrors这样所有Maven项目自动受益。实测数据显示启用阿里云镜像后依赖下载速度从平均12秒/包降至0.8秒/包首次构建时间缩短67%。这不是锦上添花而是项目启动的生死线。3.2 系统提示词配置如何让Agent理解“阿里云语境”Spring AI的SystemMessage配置看似简单但直接影响Agent对阿里云服务的认知深度。常见错误是直接复制OpenAI示例Prompt导致Agent在调用AliyunOssTool时仍试图生成AWS S3命令。正确做法是构建三层提示词体系基础层Base Prompt定义Agent角色与能力边界你是阿里云生态专属智能体仅能调用已注册的阿里云SDK工具如OSS、SMS、RDS禁止虚构API或猜测参数。所有操作必须符合阿里云RAM权限策略。工具层Tool Prompt为每个Tool注入领域知识对AliyunSmsTool附加说明发送短信前必须校验手机号格式/^1[3-9]\d{9}$/模板CODE需从阿里云短信控制台获取签名名称必须与备案一致。上下文层Context Prompt动态注入运行时信息在ReactEngine执行前将当前用户所属租户的AccessKeyID脱敏后、RegionId、BucketName等注入MessageContext使LLM能在Reasoning阶段引用。实际配置中我们用application.yml分环境管理spring: ai: chat: default-system-message: | 你是一个运行在阿里云环境的ReactAgent当前Region: ${ALIYUN_REGION:cn-shanghai} 可用工具AliyunOssTool用于文件存储、AliyunSmsTool用于短信通知 安全守则绝不输出AccessKeySecret绝不调用未授权API。提示default-system-message支持多行字符串|符号避免长Prompt被YAML解析器截断。测试发现加入RegionId后Agent调用OSS API的成功率从82%提升至99.7%因为LLM不再需要猜测Endpoint。3.3 工具注册为什么Tool必须是Spring Bean而非普通对象Spring AI的ToolRegistry要求所有Tool必须是Spring管理的Bean原因在于依赖注入与生命周期管理。以AliyunOssTool为例其构造函数需要OssTemplate和OssPropertiesComponent public class AliyunOssTool implements Tool { private final OssTemplate ossTemplate; private final OssProperties ossProperties; public AliyunOssTool(OssTemplate ossTemplate, OssProperties ossProperties) { this.ossTemplate ossTemplate; this.ossProperties ossProperties; } Override public String execute(String input) { // 使用ossTemplate上传文件自动携带ossProperties配置 return ossTemplate.putObject(my-bucket, path/ UUID.randomUUID(), input.getBytes()); } }如果手动new AliyunOssTool()OssTemplate无法注入且ossProperties需硬编码。而声明为Component后Spring自动完成依赖装配。更重要的是OssTemplate本身是ConditionalOnClass(OssTemplate.class)条件化Bean只有引入spring-cloud-starter-alicloud-oss时才创建——这实现了按需加载避免无用依赖污染Classpath。实操心得所有Tool类必须添加Component或Service注解并确保其构造函数参数均为Spring Bean。曾有同事将AliyunRdsTool的JdbcTemplate参数改为DataSource导致启动报NoSuchBeanDefinitionException因为JdbcTemplate是Spring Boot自动配置的Bean而DataSource需手动声明。3.4 向量存储为什么选用RDSPGVector而非阿里云OpenSearch阿里云OpenSearch确实提供向量检索但其Java SDK与Spring Data不兼容且不支持Query注解。而RDS PostgreSQL开启PGVector插件后可直接使用Spring Data JPAEntity public class DocumentChunk { Id private String id; private String content; Column(columnDefinition vector(1536)) private float[] embedding; } Repository public interface DocumentChunkRepository extends JpaRepositoryDocumentChunk, String { Query(SELECT d FROM DocumentChunk d ORDER BY d.embedding - :embedding LIMIT 5) ListDocumentChunk findSimilar(Param(embedding) float[] embedding); }关键优势有三第一embedding - :embedding是PGVector原生相似度运算符性能优于OpenSearch的近似搜索第二DocumentChunk实体可与其他业务表如Order、User建立JPA关联实现“订单文档用户画像”联合检索第三RDS的备份、监控、SQL审计能力直接复用无需新建运维体系。我们在某政务项目中用RDSPGVector支撑10亿级文档向量化P99查询延迟稳定在120ms以内而OpenSearch同规格集群P99达380ms。注意启用PGVector需在RDS控制台执行CREATE EXTENSION vector;且RDS版本需≥PostgreSQL 14。低于此版本需升级切勿尝试手动编译安装可能导致实例崩溃。3.5 消息历史如何用Redis实现跨请求Stateful Chat MemoryReactAgent必须记住多轮对话状态但Spring AI默认InMemoryChatMemory在重启后丢失。我们采用RedisChatMemory但做了两处关键改造Key命名空间隔离避免不同用户Session混用Bean public ChatMemory chatMemory(RedisConnectionFactory connectionFactory) { RedisChatMemory redisChatMemory new RedisChatMemory(connectionFactory); // 关键为每个用户生成唯一key前缀 redisChatMemory.setKeyPrefix(chat:memory: getUserIdFromContext() :); return redisChatMemory; }TTL自动清理防止Redis内存溢出// 在RedisChatMemory.save()后追加TTL设置 redisTemplate.expire(key, Duration.ofHours(24));实测发现未加TTL时10万用户并发下Redis内存每日增长12GB加TTL后稳定在3GB。另外getMessages()方法默认返回全部历史但ReactAgent只需最近5轮因此重写findMessagesByConversationIdOverride public ListMessage findMessagesByConversationId(String conversationId) { // 仅取最近5条减少网络传输 return super.findMessagesByConversationId(conversationId).stream() .skip(Math.max(0, size() - 5)) .collect(Collectors.toList()); }3.6 流式响应如何让ReactAgent的每步Action都实时推送Spring AI的StreamingChatClient默认只流式返回LLM输出但ReactAgent需要将REASONING、ACTING、OBSERVING各阶段结果实时推送给前端。解决方案是自定义StreamingChatClient包装器Component public class ReactStreamingChatClient { private final StreamingChatClient streamingChatClient; private final SseEmitter emitter; // 前端建立的SSE连接 public void executeReactStep(ReactStep step) { // 步骤开始时推送状态 emitter.send(SseEmitter.event().name(step-start).data(step.getType())); // 执行Tool并流式返回结果 streamingChatClient.stream(step.getPrompt()) .doOnNext(chunk - emitter.send(SseEmitter.event().name(chunk).data(chunk.getContent()))) .doOnComplete(() - emitter.send(SseEmitter.event().name(step-end).data(step.getResult()))); } }前端用EventSource监听step-start、chunk、step-end事件即可实现“Agent思考中… → 调用OSS上传 → 上传完成”这样的渐进式反馈。相比WebSocketSSE更轻量且Nginx默认支持无需额外配置。3.7 安全加固如何让Agent调用阿里云API时符合RAM最小权限原则所有Tool的阿里云客户端AcsClient、OssClient必须使用RAM子账号的AK/SK且权限策略需精确到API级别。例如AliyunSmsTool的RAM Policy应为{ Version: 1, Statement: [ { Action: [dybaseapi:SendSms], Effect: Allow, Resource: * } ] }绝对禁止授予Action: [*]。更进一步我们为每个Tool创建独立RAM角色sms-tool-role仅允许dybaseapi:SendSmsoss-tool-role仅允许oss:GetObject,oss:PutObjectrds-tool-role仅允许rds:DescribeDBInstances然后在application.yml中配置角色ARNaliyun: sms: role-arn: acs:ram::1234567890123456:role/sms-tool-role oss: role-arn: acs:ram::1234567890123456:role/oss-tool-roleAcsClient初始化时自动扮演该角色实现权限动态切换。此举让Agent即使被注入恶意Prompt也无法越权调用其他API——这是生产环境的底线。4. 实操过程从零搭建一个可运行的ReactAgent Demo4.1 环境准备四步完成阿里云服务开通开通百炼大模型API登录阿里云百炼控制台 → 创建应用 → 获取API_KEY和API_SECRET→ 记录Endpoint如https://dashscope.aliyuncs.com/api/v1。注意免费额度仅限qwen-max生产环境需购买qwen-plus。创建RDS PostgreSQL实例规格选2核4G起步版本选PostgreSQL 14网络选与ECS同VPC。创建后进入数据库管理 → 执行CREATE EXTENSION vector;启用PGVector。开通OSS并创建BucketBucket名称需全局唯一如my-reactagent-bucket-2024读写权限设为私有跨域CORS配置允许http://localhost:3000开发环境。配置RAM子账号与权限创建子账号react-agent-user→ 为其附加自定义Policy见3.7节→ 生成AK/SK → 将AK/SK存入阿里云ACM配置中心非明文写入application.yml。提示所有服务必须在同一地域如cn-shanghai否则跨Region调用会失败。我们曾因OSS在cn-beijing、RDS在cn-shanghai导致Agent上传文件时抛出InvalidEndpoint异常排查耗时6小时。4.2 项目初始化Maven依赖与Spring Boot版本选择使用Spring Boot 3.2.xJava 17这是Spring AI 0.8.x的强制要求。pom.xml核心依赖dependencies !-- Spring AI 核心 -- dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-spring-boot-starter/artifactId version0.8.1/version /dependency !-- 阿里云OSS -- dependency groupIdcom.alibaba.cloud/groupId artifactIdspring-cloud-starter-alicloud-oss/artifactId version2.3.1/version /dependency !-- 阿里云短信 -- dependency groupIdcom.aliyun/groupId artifactIdaliyun-java-sdk-dysmsapi/artifactId version2.1.1/version /dependency !-- RDS PGVector -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-data-jpa/artifactId /dependency dependency groupIdorg.postgresql/groupId artifactIdpostgresql/artifactId /dependency !-- Redis -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-data-redis/artifactId /dependency /dependencies关键版本匹配spring-cloud-starter-alicloud-oss2.3.1 适配 Spring Boot 3.2.x若误用2.2.x会因WebMvcConfigurer接口变更导致启动失败。4.3 核心代码实现ReactEngine的300行精简版以下为ReactEngine核心逻辑已删减日志与异常处理保留主干Component public class ReactEngine { private final ChatClient chatClient; private final ToolRegistry toolRegistry; private final ChatMemory chatMemory; public ReactEngine(ChatClient chatClient, ToolRegistry toolRegistry, ChatMemory chatMemory) { this.chatClient chatClient; this.toolRegistry toolRegistry; this.chatMemory chatMemory; } public FluxReactResponse execute(String userMessage, String conversationId) { // 1. 初始化ReactState ReactState state ReactState.builder() .conversationId(conversationId) .messages(chatMemory.findMessagesByConversationId(conversationId)) .build(); // 2. 进入React循环最多5轮防死循环 return Flux.generate( () - state, (stateRef, sink) - { if (stateRef.isCompleted()) { sink.complete(); return; } // Step 1: Reasoning - 让LLM生成Action Plan String reasoningPrompt buildReasoningPrompt(stateRef); Message response chatClient.call(reasoningPrompt); // Step 2: Parse Action from LLM output ReactAction action parseAction(response.getContent()); // Step 3: Acting - 执行Tool String toolResult toolRegistry.invoke(action.getToolName(), action.getInput()); // Step 4: Observing - 更新State stateRef stateRef.next(action, toolResult); chatMemory.save(stateRef.getMessages(), conversationId); // 发送响应 sink.next(new ReactResponse(action, toolResult)); }, stateRef - { // 清理资源 chatMemory.delete(conversationId); } ); } private String buildReasoningPrompt(ReactState state) { return 你正在执行React模式。当前状态%s 可用工具%s 请生成下一步Action格式{tool:toolName,input:toolInput} .formatted(state.getStatus(), toolRegistry.getToolNames()); } }ReactResponse是自定义DTO包含actionType、toolName、result字段前端据此渲染不同UI组件。整个循环逻辑控制在300行内却完整覆盖React四态证明Spring AI的抽象能力足够支撑复杂Agent。4.4 配置文件application.yml的12处关键参数# application.yml spring: profiles: active: prod ai: chat: # 百炼API配置 model: qwen-plus base-url: https://dashscope.aliyuncs.com/api/v1 api-key: ${ALIYUN_API_KEY} # 系统提示词 default-system-message: | 你是一个阿里云ReactAgent当前Region: cn-shanghai 可用工具AliyunOssTool文件存储、AliyunSmsTool短信通知 安全守则绝不输出AK/SK绝不调用未授权API。 cloud: alicloud: # OSS配置 oss: endpoint: https://oss-cn-shanghai.aliyuncs.com bucket: my-reactagent-bucket-2024 access-key-id: ${ALIYUN_OSS_AK} access-key-secret: ${ALIYUN_OSS_SK} # 短信配置 sms: region-id: cn-shanghai sign-name: 【我的应用】 template-code: SMS_123456789 datasource: url: jdbc:postgresql://rm-xxx.pg.rds.aliyuncs.com:3306/reactdb?currentSchemapublic username: ${ALIYUN_RDS_USER} password: ${ALIYUN_RDS_PASS} redis: host: r-bp1xxx.redis.cn-shanghai.rds.aliyuncs.com port: 6379 password: ${ALIYUN_REDIS_PASS}注意所有敏感配置AK/SK必须通过阿里云ACM或Kubernetes Secret注入application.yml中仅留占位符。本地开发可用application-dev.yml生产环境由ACM动态下发。4.5 启动与验证curl命令直击核心链路启动应用后用curl模拟一次完整React流程# 1. 发起对话触发REASONING curl -X POST http://localhost:8080/api/react \ -H Content-Type: application/json \ -d {userMessage:帮我把这份合同存到OSS并发短信通知张三,conversationId:conv-001} # 2. 查看日志确认输出 # [REASONING] LLM生成: {tool:AliyunOssTool,input:合同内容...} # [ACTING] 执行OSS上传返回URL: https://my-bucket.oss-cn-shanghai.aliyuncs.com/... # [OBSERVING] 更新State准备下一步... # 3. 再次请求触发短信发送 curl -X POST http://localhost:8080/api/react \ -H Content-Type: application/json \ -d {userMessage:继续,conversationId:conv-001} # 4. 日志显示 # [REASONING] LLM生成: {tool:AliyunSmsTool,input:13800138000,合同已存至OSS链接https://...} # [ACTING] 短信发送成功MessageId: abc123...整个链路在2秒内完成证明ReactEngine与阿里云服务无缝协同。这是“降”的终极体现——技术细节被封装开发者只关注业务意图。5. 常见问题与排查技巧实录踩过的12个坑与解决方案5.1 百炼API调用失败HTTP 401 Unauthorized现象chatClient.call()抛出HttpClientErrorException.Unauthorized日志显示{message:Invalid API Key}。根因百炼API Key需在Header中以Authorization: Bearer ${API_KEY}格式传递但Spring AI默认使用X-DashScope-Signature。解决方案自定义RestTemplate重写HttpHeadersBean public RestTemplate restTemplate() { RestTemplate restTemplate new RestTemplate(); restTemplate.setInterceptors(Collections.singletonList((request, body, execution) - { request.getHeaders().set(Authorization, Bearer System.getProperty(aliyun.api.key)); return execution.execute(request, body); })); return restTemplate; }实操心得百炼文档未明确说明Header格式此坑导致3个团队集体卡顿。务必在application.yml中配置aliyun.api.key并在RestTemplate中注入。5.2 PGVector向量查询为空ORDER BY embedding - ?无结果现象findSimilar()方法返回空List但数据库确认有数据。根因PGVector的-运算符要求左右向量维度严格一致而Spring AI的EmbeddingClient默认生成1536维向量但RDS PostgreSQL的vector(1536)列可能被误建为vector(768)。解决方案检查表结构SELECT column_name, data_type FROM information_schema.columns WHERE table_namedocument_chunk;若embedding列为vector(768)执行ALTER TABLE document_chunk ALTER COLUMN embedding TYPE vector(1536) USING embedding::vector(1536);5.3 OSS上传403 ForbiddenSignatureDoesNotMatch现象AliyunOssTool调用ossTemplate.putObject()时抛出com.aliyun.oss.OSSException: The request signature we calculated does not match the signature you provided.根因spring-cloud-starter-alicloud-oss2.3.1默认使用V4签名但OSS Bucket若创建于旧版控制台可能强制V2签名。解决方案在application.yml中显式指定签名版本spring: cloud: alicloud: oss: signature-version: V25.4 Redis连接超时Cannot get Jedis connection现象RedisChatMemory初始化失败日志org.springframework.dao.DataAccessResourceFailureException: Cannot get Jedis connection。根因阿里云Redis实例开启SSL加密连接但spring-boot-starter-data-redis默认走非SSL端口。解决方案启用SSL并指定证书spring: redis: ssl: true lettuce: pool: max-active: 20同时将Redis连接字符串改为rediss://注意s。5.5 ReactAgent无限循环LLM反复生成同一Action现象Agent卡在REASONING状态连续5次生成{tool:AliyunOssTool,input:...}。根因SystemMessage未明确禁止重复调用LLM将“上传文件”视为唯一解。解决方案在系统提示词末尾追加硬性约束spring: ai: chat: default-system-message: | ...原有内容 约束同一工具在单次对话中最多调用1次禁止重复调用。5.6 短信发送失败InvalidPhoneNumbers现象AliyunSmsTool调用SendSmsRequest返回InvalidPhoneNumbers。根因阿里云短信API要求手机号去空格、去横线且必须为11位纯数字。解决方案在Tool执行前清洗号码public String execute(String input) { String phone input.replaceAll([^0-9], ); // 移除所有非数字字符 if (phone.length() ! 11) { throw new IllegalArgumentException(手机号格式错误 input); } // 继续调用SDK }5.7 流式响应中断SSE连接频繁断开现象前端EventSource收到部分chunk后断开错误码net::ERR_INCOMPLETE_CHUNKED_ENCODING。根因Nginx默认proxy_buffer太小无法缓存大块流式响应。解决方案Nginx配置追加location /api/react { proxy_pass http://backend; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection upgrade; proxy_cache_bypass $http_upgrade; # 关键增大缓冲区 proxy_buffering off; proxy_buffer_size 128k; proxy_buffers 4 256k; proxy_busy_buffers_size 256k; }5.8 RDS连接池耗尽HikariPool-1 - Connection is not available现象高并发下AliyunRdsTool调用失败日志Connection is not available, request timed out after 30000ms。根因HikariCP默认maximumPoolSize10而ReactAgent