Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 71 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

Spring AI Summary 是基于 Spring AI 框架的模块化示例工程集合,用于学习 Spring AI 核心功能。包含聊天、向量数据库、RAG、MCP、Agent 等多个功能模块的示例代码。

## 技术栈

- **Java**: 21
- **Spring Boot**: 3.3.6
- **Spring AI**: 1.0.0
- **构建工具**: Maven 3.6+ (推荐使用 mvnd 加速)
- **Lombok**: 用于简化 POJO 代码

## 常用命令

```bash
# 编译整个项目
mvn clean compile -DskipTests

# 编译单个模块 (如 spring-ai-chat-deepseek)
mvn clean compile -DskipTests -pl spring-ai-chat/spring-ai-chat-deepseek

# 运行测试
mvn test -pl <module-path>

# 打包
mvn clean package -DskipTests
```

## 模块结构

```
spring-ai-summary/
├── spring-ai-chat/ # 聊天示例 (DeepSeek, Doubao, OpenAI, Qwen, Ollama, 多模型)
├── spring-ai-vector/ # 向量数据库 (MariaDB, Redis, Milvus)
├── spring-ai-rag/ # RAG 检索增强生成
├── spring-ai-mcp/ # MCP 协议 (客户端/服务端 + Nacos 集成)
├── spring-ai-evaluation/ # 模型评估
├── spring-ai-chat-memory/ # 对话记忆 (JDBC, 本地存储)
├── spring-ai-tool-calling/ # 工具调用
├── spring-ai-agent/ # Agent 模式 (工作流、评估优化、编排)
└── spring-ai-observability/ # 可观测性 (指标、链路追踪)
```

## 配置说明

每个子模块在 `src/main/resources/` 下有独立的配置文件 (application.properties 或 application.yml)。API 密钥通过环境变量注入:

```properties
spring.ai.deepseek.api-key=${spring.ai.deepseek.api-key}
spring.ai.openai.api-key=${OPENAI_API_KEY}
```

敏感配置文件 (如 `application-deepseek.properties`) 已被 `.gitignore` 排除。

## 运行示例

1. 配置对应模块的 API 密钥环境变量
2. 运行模块的 Application 主类 (如 `DsChatApplication`)
3. 默认端口在各模块配置文件中定义 (通常 8080-8082)
4. 通过 Actuator 端点监控: `http://localhost:<port>/actuator`

## 学习路径建议

1. `spring-ai-chat` - 聊天应用开发 (必选起点)
2. `spring-ai-tool-calling` - 工具调用能力
3. `spring-ai-vector` - 向量数据库集成
4. `spring-ai-mcp` / `spring-ai-rag` / `spring-ai-agent` - 高级应用模式
18 changes: 18 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,24 @@
</dependency>
</dependencies>
</dependencyManagement>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<source>21</source>
<target>21</target>
<compilerArgs>
<arg>-parameters</arg>
</compilerArgs>
</configuration>
</plugin>
</plugins>
</build>

<repositories>
<repository>
<id>spring-milestones</id>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
CREATE TABLE IF NOT EXISTS SPRING_AI_CHAT_MEMORY (
conversation_id VARCHAR(36) NOT NULL,
conversation_id VARCHAR(36) NOT NULL,
content TEXT NOT NULL,
type VARCHAR(10) NOT NULL,
`timestamp` TIMESTAMP NOT NULL,
`timestamp` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT TYPE_CHECK CHECK (type IN ('USER', 'ASSISTANT', 'SYSTEM', 'TOOL'))
);
);

CREATE INDEX IF NOT EXISTS SPRING_AI_CHAT_MEMORY_CONVERSATION_ID_TIMESTAMP_IDX
ON SPRING_AI_CHAT_MEMORY(conversation_id, `timestamp`);
CREATE INDEX SPRING_AI_CHAT_MEMORY_CONVERSATION_ID_TIMESTAMP_IDX ON SPRING_AI_CHAT_MEMORY(conversation_id, `timestamp`);
42 changes: 42 additions & 0 deletions spring-ai-chat/spring-ai-chat-ollama/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,47 @@
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-ollama</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
<version>2.0.25</version>
</dependency>

<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>3.10.0</version>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-chat-memory-repository-jdbc</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<source>21</source>
<target>21</target>
<compilerArgs>
<arg>-parameters</arg>
</compilerArgs>
</configuration>
</plugin>
</plugins>
</build>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
package com.glmapper.ai.chat.ollama.base;

import com.alibaba.fastjson2.JSONObject;
import com.glmapper.ai.chat.ollama.util.OkhttpUtil;


import java.util.List;

/**
* 联系人模块
*/
public class ContactApi {

/**
*
* @param appId
* @return
*/
public static JSONObject a(String appId){
JSONObject param = new JSONObject();
param.put("appId",appId);
return OkhttpUtil.postJSON("/login/checkOnline",param);
}

/**
* 获取通讯录列表
* @param appId
* @return
*/
public static JSONObject fetchContactsList(String appId){
JSONObject param = new JSONObject();
param.put("appId",appId);
return OkhttpUtil.postJSON("/contacts/fetchContactsList",param);
}

/**
* 获取群/好友简要信息
* @param appId
* @return
*/
public static JSONObject getBriefInfo(String appId, List<String> wxids){
JSONObject param = new JSONObject();
param.put("appId",appId);
param.put("wxids",wxids);
return OkhttpUtil.postJSON("/contacts/getBriefInfo",param);
}

/**
* 获取群/好友详细信息
* @param appId
* @return
*/
public static JSONObject getDetailInfo(String appId, List<String> wxids){
JSONObject param = new JSONObject();
param.put("appId",appId);
param.put("wxids",wxids);
return OkhttpUtil.postJSON("/contacts/getDetailInfo",param);
}

/**
* 搜索好友
* @param appId
* @return
*/
public static JSONObject search(String appId,String contactsInfo){
JSONObject param = new JSONObject();
param.put("appId",appId);
param.put("contactsInfo",contactsInfo);
return OkhttpUtil.postJSON("/contacts/search",param);
}

/**
* 添加联系人/同意添加好友
* @param appId
* @return
*/
public static JSONObject search(String appId,Integer scene,Integer option,String v3, String v4,String content){
JSONObject param = new JSONObject();
param.put("appId",appId);
param.put("scene",scene);
param.put("option",option);
param.put("v3",v3);
param.put("v4",v4);
param.put("content",content);
return OkhttpUtil.postJSON("/contacts/addContacts",param);
}

/**
* 删除好友
* @param appId
* @return
*/
public static JSONObject deleteFriend(String appId,String wxid){
JSONObject param = new JSONObject();
param.put("appId",appId);
param.put("wxid",wxid);
return OkhttpUtil.postJSON("/contacts/deleteFriend",param);
}

/**
* 设置好友仅聊天
* @param appId
* @return
*/
public static JSONObject setFriendPermissions(String appId,String wxid,Boolean onlyChat){
JSONObject param = new JSONObject();
param.put("appId",appId);
param.put("wxid",wxid);
param.put("onlyChat",onlyChat);
return OkhttpUtil.postJSON("/contacts/setFriendPermissions",param);
}

/**
* 设置好友备注
* @param appId
* @return
*/
public static JSONObject setFriendRemark(String appId,String wxid,String remark){
JSONObject param = new JSONObject();
param.put("appId",appId);
param.put("wxid",wxid);
param.put("onlyChat",remark);
return OkhttpUtil.postJSON("/contacts/setFriendRemark",param);
}

/**
* 获取手机通讯录
* @param appId
* @return
*/
public static JSONObject getPhoneAddressList(String appId,List<String> phones){
JSONObject param = new JSONObject();
param.put("appId",appId);
param.put("wxid",phones);
return OkhttpUtil.postJSON("/contacts/getPhoneAddressList",param);
}

/**
* 上传手机通讯录
* @param appId
* @return
*/
public static JSONObject uploadPhoneAddressList(String appId,List<String> phones,Integer opType){
JSONObject param = new JSONObject();
param.put("appId",appId);
param.put("wxid",phones);
param.put("opType",opType);
return OkhttpUtil.postJSON("/contacts/uploadPhoneAddressList",param);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package com.glmapper.ai.chat.ollama.base;

import com.alibaba.fastjson2.JSONObject;
import com.glmapper.ai.chat.ollama.util.OkhttpUtil;


/**
* 下载模块
*/
public class DownloadApi {

/**
* 下载图片
*/
public static JSONObject downloadImage(String appId, String xml, Integer type){
JSONObject param = new JSONObject();
param.put("appId",appId);
param.put("xml",xml);
param.put("type",type);
return OkhttpUtil.postJSON("/message/downloadImage",param);
}

/**
* 下载语音
*/
public static JSONObject downloadVoice(String appId, String xml, Long msgId){
JSONObject param = new JSONObject();
param.put("appId",appId);
param.put("xml",xml);
param.put("msgId",msgId);
return OkhttpUtil.postJSON("/message/downloadVoice",param);
}

/**
* 下载视频
*/
public static JSONObject downloadVideo(String appId, String xml){
JSONObject param = new JSONObject();
param.put("appId",appId);
param.put("xml",xml);
return OkhttpUtil.postJSON("/message/downloadVideo",param);
}

/**
* 下载emoji
*/
public static JSONObject downloadEmojiMd5(String appId, String emojiMd5){
JSONObject param = new JSONObject();
param.put("appId",appId);
param.put("emojiMd5",emojiMd5);
return OkhttpUtil.postJSON("/message/downloadEmojiMd5",param);
}
/**
* cdn下载
*/
public static JSONObject downloadImage(String appId, String aesKey, String fileId, String type, String totalSize, String suffix){
JSONObject param = new JSONObject();
param.put("appId",appId);
param.put("aesKey",aesKey);
param.put("fileId",fileId);
param.put("totalSize",totalSize);
param.put("type",type);
param.put("suffix",suffix);
return OkhttpUtil.postJSON("/message/downloadCdn",param);
}


}
Loading