☰
【Java+AI零花钱项目实战一】工程基建与骨架(IDEA+ClaudeCode+ccSwitch+Qwen+Spec-Driven+SpringAI)
2026/10/7 7:50:00 网站建设 项目流程

1. 为什么我要用 Spec-Driven 方式搭这个 Java+AI 零花钱项目骨架

先说清楚这个项目是什么:一个给鸿蒙 APP 配套的零花钱智能管理后端服务,主打家庭成员零花钱看板、收支记录、语音交互记账、价值零花钱统计这些能力。适合谁看?适合已经会写 Spring Boot、但还没把 AI 编码工具真正用进日常开发流程的 Java 开发者。你能从这篇里拿到什么?一套可复制的工程骨架、一份能直接跑的 ccSwitch 配置、一段 SpringAI 接入 Qwen 的验证代码,以及一次从规格文档到可运行接口的完整动作。

我这次不打算用「让 AI 随便写点代码」的方式开局。原因很直接:AI 编码最大的问题不是写不出来,而是写得太随意。同一个需求,你今天让它写一版,明天让它改一版,两次的包结构、命名风格、异常处理可能完全不一样。项目稍微大一点,代码就开始互相打架。

Spec-Driven 的核心逻辑就一句话:AI 是执行的肌肉,规格是项目的大脑。所有代码生成、迭代、修复、校验,都必须严格遵循提前定义好的规范文档。你先把「要做什么、用什么技术、按什么风格写」定死,再让 AI 去填代码,它就不会跑偏。

具体到操作层面,我先把四份核心文档产出来:code-style-guide.md(编码规范)、mission.md(项目使命与功能约束)、tech-stack.md(技术约束)、roadmap.md(迭代路线)。这四份文档是后续所有 AI 编码的唯一标准,后面每一轮生成代码,我都会让 ClaudeCode 先读它们再动手。

工程骨架这一阶段我定为 M0,目标是搭出可构建、可迭代、可校验的标准化结构,统一全项目的代码结构、依赖版本、校验规则和构建流程。M0 跑通之后,M1 的认证与家庭域、M2 的零花钱核心业务,都可以直接往上叠,不用回头改地基。

技术选型上我锁定了这套组合:JDK 25、Spring Boot 4.1.0、SpringAI 2.0.0、PostgreSQL 18、MyBatis、Maven 3.9.16,部署方式是 Docker 镜像打包上云服务器。AI 编码通道用 ClaudeCode 配合 ccSwitch 管理多模型,主力模型走 Qwen 系列。这套组合的好处是版本新、AI 原生适配好,SpringAI 直接提供了模型调用的抽象层,不用自己封装 HTTP 客户端。

下面我按「先定规范、再搭骨架、最后验证」的顺序,把每一步的可复制配置都摊开讲。你跟着做,能拿到一个能跑起来的后端工程,以及一套能持续用的 AI 编码工作流。

2. TaoToken 前置准备:给 ClaudeCode 配一条稳定的模型通道

在动手写代码之前,得先把 AI 编码工具的模型通道打通。ClaudeCode 本身是个命令行 Agent,它需要一个能调用的模型后端。我这边用 ccSwitch 来管理多模型通道,好处是切换模型不用改环境变量,改一个配置文件就行。

先说清楚 TaoToken 在这里的角色:它是一个模型 API 聚合服务,提供统一的调用入口,你拿到一个 API Key 之后,就能通过它调用包括 Qwen 在内的多种模型。对于 ClaudeCode 这种需要频繁调用的场景,统一入口比每个模型单独配一套 Key 要省事得多。

你需要准备的东西:

第一,一个可用的 API Key。到 TaoToken 控制台的 API Keys 页面创建一个,创建时给它起个能认出来的名字,比如claudecode-dev,方便后面区分用途。创建完把 Key 复制出来,注意这个 Key 只显示一次,丢了就得重建。

第二,确认你要用的模型 ID。Qwen 系列在 TaoToken 上的模型标识需要和你在 ccSwitch 里填的保持一致,常见的是qwen-max、qwen-plus这类。具体以你控制台里模型列表显示的为准,别凭记忆填。

第三,ClaudeCode 的安装。如果你还没装,用 npm 全局装一下就行:

npm install -g @anthropic-ai/claude-code

装完之后先别急着跑,因为默认它指向的是官方通道,我们要把它改到自己的通道上。这一步靠环境变量和 ccSwitch 配合完成。

关于 Base URL,这里要特别注意:ClaudeCode 走的是 Anthropic 兼容协议,所以 Base URL 要填 TaoToken 的 API 地址https://taotoken.net/api,不要带任何多余路径。Key 就填你刚才创建的那个。Model ID 填你在控制台确认过的 Qwen 模型标识。

我建议你先在终端里用 curl 验证一下 Key 能不能通,再往 ClaudeCode 里配。验证命令:

curl https://taotoken.net/api/v1/messages \ -H "x-api-key: 你的Key" \ -H "anthropic-version: 2023-06-01" \ -H "content-type: application/json" \ -d '{ "model": "qwen-max", "max_tokens": 64, "messages": [{"role": "user", "content": "回复 ok"}] }'

如果返回里能看到模型输出,说明通道是通的。如果返回 401,那就是 Key 有问题;如果返回模型不存在的错误,那就是 Model ID 填错了。这两个错误后面排障章节会细讲。

通道打通之后,ClaudeCode 就能正常发起请求了。这时候你再回到 IDEA 里,把工程建起来,让 ClaudeCode 在工程目录下工作,它就能读到你的规格文档,按规范生成代码。

有一点要提醒:模型调用是有成本的,尤其是让 AI 一次性生成大段代码的时候,token 消耗会比你想象得快。我的做法是,设计探讨阶段用便宜的对话模型,等方案定稿了,再用编码能力强的模型去生成代码,减少来回试错的次数。这个习惯能帮你省下不少费用。

3. 可复制配置:ccSwitch 通道与 SpringAI 接入参数

这一节是全文最干的部分,我把 ccSwitch 的配置片段、Maven 依赖坐标、SpringAI 的接入参数全部摊开,你直接复制改改就能用。

3.1 ccSwitch 配置文件

ccSwitch 的配置一般放在用户目录下的配置文件中,我用的是 JSON 格式。下面这份是我实际在用的结构,你可以照着改:

{ "providers": [ { "name": "taotoken-qwen", "type": "anthropic", "baseUrl": "https://taotoken.net/api", "apiKey": "sk-你的Key", "models": [ { "id": "qwen-max", "name": "Qwen Max", "maxTokens": 8192 }, { "id": "qwen-plus", "name": "Qwen Plus", "maxTokens": 8192 } ], "active": true } ], "current": "taotoken-qwen" }

几个关键点:type填anthropic,因为 ClaudeCode 走的是 Anthropic 协议;baseUrl就是https://taotoken.net/api,不要加/v1之类的后缀,ccSwitch 会自己拼;apiKey填你创建的那个 Key;models数组里可以放多个模型,切换的时候改current字段就行。

改完配置后,重启一下 ClaudeCode 会话,让它重新读取配置。你可以在 ClaudeCode 里发一句「你现在用的是哪个模型」来确认切换是否生效。

3.2 Maven 依赖坐标

工程用 Maven 管理依赖,pom.xml里核心的坐标如下。Spring Boot 用 4.1.0,SpringAI 用 2.0.0,数据库驱动用 PostgreSQL:

<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>4.1.0</version> <relativePath/> </parent> <properties> <java.version>25</java.version> <spring-ai.version>2.0.0</spring-ai.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-starter-model-openai</artifactId> <version>${spring-ai.version}</version> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>3.0.4</version> </dependency> <dependency> <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> </dependency> </dependencies>

注意 SpringAI 2.0.0 的 starter 命名和 1.x 有区别,spring-ai-starter-model-openai是新的命名方式。如果你用的是别的模型协议,starter 名字会不一样,但结构是一样的。

3.3 SpringAI 接入 Qwen 的 application.yml

SpringAI 通过 OpenAI 兼容协议接入 Qwen,配置写在application.yml里:

spring: ai: openai: base-url: https://taotoken.net/api api-key: ${TAOTOKEN_API_KEY} chat: options: model: qwen-max temperature: 0.7 max-tokens: 2048 datasource: url: jdbc:postgresql://localhost:5432/pocketmoney username: ${DB_USER} password: ${DB_PASSWORD} driver-class-name: org.postgresql.Driver mybatis: mapper-locations: classpath:mapper/*.xml type-aliases-package: com.pocketmoney.domain

这里base-url填https://taotoken.net/api,SpringAI 会自动在末尾拼上/v1/chat/completions这类路径。api-key我用环境变量注入,避免把 Key 硬编码进代码仓库。model填qwen-max,和 ccSwitch 里保持一致。

3.4 目录结构

工程骨架的目录结构我按分层的方式组织,方便后续按模块叠加:

pocketmoney-backend/ ├── pom.xml ├── docs/ │ ├── mission.md │ ├── tech-stack.md │ ├── code-style-guide.md │ └── roadmap.md ├── src/main/java/com/pocketmoney/ │ ├── PocketMoneyApplication.java │ ├── config/ │ │ └── AiConfig.java │ ├── controller/ │ │ └── HealthController.java │ ├── service/ │ │ └── AiChatService.java │ └── domain/ ├── src/main/resources/ │ ├── application.yml │ └── mapper/ └── src/test/java/com/pocketmoney/

docs目录放四份规格文档,这是 Spec-Driven 的根基,AI 每次生成代码前都要读。config放 SpringAI 的配置类,controller放接口,service放业务逻辑,domain放实体。这个结构不复杂,但足够清晰,后面加模块直接往对应目录里塞就行。

配置都就位之后,下一步就是让 ClaudeCode 按规格生成代码,然后验证接口能不能跑通。

4. 验证请求:从规格文档到可运行接口

配置写完不算完,得验证整条链路是通的。这一节我演示一次完整的动作:让 ClaudeCode 读规格文档,生成一个 AI 对话接口,然后实际发请求确认返回正常。

4.1 先让 ClaudeCode 读规格

在 IDEA 的终端里进入工程目录,启动 ClaudeCode 会话。第一句话我通常这么说:

请先阅读 docs 目录下的 mission.md、tech-stack.md、code-style-guide.md, 然后告诉我这个项目的技术约束和编码规范要点。

这一步的目的是让 Agent 把规格加载进上下文。它会返回一份摘要,你核对一下有没有理解偏差。如果它把技术栈说错了,说明文档写得不够明确,回去补文档,别急着让它写代码。

4.2 生成 AI 对话接口

确认理解无误后,发第二条指令:

基于 docs 下的规格文档,实现一个 AI 对话接口: 路径 POST /api/ai/chat,接收 JSON 参数 {"message": "用户输入"}, 调用 SpringAI 的 ChatClient 返回模型回复,返回结构 {"reply": "模型输出"}。 按 code-style-guide.md 的规范写,包含 controller、service 和配置类。

ClaudeCode 会开始生成代码。它一般会先创建AiConfig配置类,注入ChatClient.Builder,然后写AiChatService,最后写AiChatController。生成过程中它可能会编译校验,如果报错会自己修。

生成完之后,你检查一下几个点:包名对不对、有没有按规范加注释、异常处理有没有做。有问题就直接在会话里说「controller 里缺少参数校验,补上」,它会改。

4.3 启动服务并验证

代码就位后,启动 Spring Boot 应用:

mvn spring-boot:run

看到Started PocketMoneyApplication就说明起来了。然后用 curl 发一个请求:

curl -X POST http://localhost:8080/api/ai/chat \ -H "Content-Type: application/json" \ -d '{"message": "帮我记一笔零花钱收入 50 元"}'

如果返回类似下面的结构,说明整条链路通了:

{ "reply": "已记录:零花钱收入 50 元。当前余额已更新。" }

这里模型返回的内容是它自己组织的,不一定和上面完全一样,但结构对就行。如果返回 500,去看日志,大概率是 API Key 没注入或者模型 ID 不对。

4.4 验证通过后提交代码

接口跑通之后,第一件事是提交代码。在 IDEA 里把工程初始化成 Git 仓库,配置好远程地址,然后提交:

git init git add . git commit -m "M0: 工程骨架与 AI 对话接口" git remote add origin 你的仓库地址 git push -u origin main

提交之前确认.gitignore里排除了target/和本地配置文件,别把编译产物和密钥推上去。这一步做完,M0 的骨架就算落地了,后面 M1 的认证模块可以直接在这个基础上加。

5. 本篇常见错误排查

配置和验证过程中,最容易撞上几个固定错误。我把它们列出来,你对着日志查就行。

5.1 401 错误:Key 无效或没传对

报错长这样:

{"error":{"type":"authentication_error","message":"invalid x-api-key"}}

原因通常是三个:Key 复制的时候带了空格、Key 已经失效、或者请求头字段名写错了。ClaudeCode 走 Anthropic 协议时用的是x-api-key头,SpringAI 走 OpenAI 协议时用的是Authorization: Bearer头,两者不一样。先确认你当前是在哪条链路上报的错,再检查对应的头。

如果是 SpringAI 报 401,检查application.yml里的api-key有没有正确读到环境变量。可以在启动日志里搜一下配置加载情况,或者临时把 Key 直接写进去测试,确认是环境变量的问题还是 Key 本身的问题。

5.2 local proxy failed:本地代理配置冲突

报错长这样:

Error: connect ECONNREFUSED 127.0.0.1:7890 local proxy failed

这是 ClaudeCode 或 npm 读到了系统里的代理配置,但代理服务没开。检查环境变量HTTP_PROXY、HTTPS_PROXY有没有被设置,如果有就清掉:

unset HTTP_PROXY unset HTTPS_PROXY

Windows 上用set HTTP_PROXY=清空。清完之后重启终端再试。这个错误和网络环境有关,确保你的终端能直连到 API 地址就行。

5.3 reading choices:响应结构解析失败

报错长这样:

java.lang.NullPointerException: Cannot invoke "java.util.List.get(int)" because "choices" is null

这是 SpringAI 解析模型响应时没拿到预期的choices字段。常见原因是 Base URL 配错了,请求打到了错误的路径上,返回的根本不是模型响应。检查base-url是不是https://taotoken.net/api,有没有多加或少加路径段。另一个原因是模型 ID 不存在,服务端返回了错误结构,SpringAI 按正常结构解析就空了。去控制台核对模型 ID。

5.4 OAuth 相关报错

如果你在 ClaudeCode 里看到 OAuth 相关的提示,说明它还在尝试走官方登录流程,没读到 ccSwitch 的配置。检查 ccSwitch 配置文件路径对不对,current字段指向的 provider 是不是你配的那个。改完配置要重启 ClaudeCode 会话,它不会热加载。

5.5 三件套检查清单

不管报什么错,先核对这三样:Base URL 是不是https://taotoken.net/api、Key 是不是当前有效的、Model ID 是不是控制台里存在的。这三样对了,大部分连接问题都能排除。如果三样都对还报错,把完整报错贴到会话里让 ClaudeCode 帮你分析,它读得到上下文,定位会比你自己翻日志快。

6. 后续怎么用这套骨架继续叠加功能

M0 跑通之后,这个工程就是一个能持续迭代的基座了。我的用法是:每开一个新模块,先在docs下补一份该模块的规格文档,然后让 ClaudeCode 读规格生成代码,生成完自己验证,验证通过就提交。整个过程你只做两件事——写规格、审结果。

这套流程跑顺之后,你会发现瓶颈不在写代码,而在两件事:一是规格写得够不够清楚,二是 token 费用扛不扛得住。规格写得模糊,AI 就会自由发挥,返工次数上去,费用也跟着涨。所以我现在写规格会尽量把边界条件、异常场景、返回结构都写死,宁可前期多花十分钟,也别让 AI 猜。

费用这块,我的经验是分阶段用不同模型。设计探讨阶段用便宜的对话模型,方案定稿后用编码能力强的模型生成代码。另外注意模型的闲时和忙时价差,有些模型能差一倍,把思考类的工作放在忙时做,把生成类的工作放到闲时跑,能省不少。

工程骨架已经就位,下一阶段就是往里面填业务了。认证与家庭域、零花钱核心业务、AI 语音交互,都可以按同样的 Spec-Driven 流程往下推。你先把这套骨架在自己机器上跑通,后面加功能就是重复「写规格、生成、验证、提交」这个循环。

需要创建 API Key 或者查接入文档的话,可以从这几个入口进:API Keys 页面在https://taotoken.net/api-keys,接入文档在https://taotoken.net/doc。想先试试模型对话效果,用https://taotoken.net/chat就行。如果你打算长期用这套流程做编码和 Agent 开发,Coding Plan 页面https://taotoken.net/coding-plan里有更划算的套餐说明。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询