Ops 多模态 RAG(Retrieval-Augmented Generation) ,结合 Spring AI + Qdrant,可以用来做一个「运维知识库 + 多模态检索问答」的案例。下面我将简单实现一下这个案例:
🌐 场景设计
背景:
- 运维团队需要快速排查问题,但信息分散在 文档(markdown/PDF)、图片(监控截图)、日志(结构化/半结构化) 里。
- 我们用 Spring AI (方便整合LLM)+ Qdrant (向量数据库)做一个 多模态 RAG ,支持输入:
- 文本问题(自然语言问答)
- 图片截图(例如:用户上传一张服务器 CPU 监控图,让系统结合已有知识库解释异常)
- 日志片段(半结构化输入)
目标:
- 用户输入"CPU usage looks spiky" + 一张 CPU 曲线图,系统去 Qdrant 检索最相关的知识文档 & 历史故障案例,并由 LLM 给出解释 + 建议。
🔧 技术架构
- Spring AI
- 用
ChatClient
调用大模型(支持文本和多模态输入) - 集成
Qdrant
作为向量检索层
- 用
- Qdrant
- 存储多模态 Embeddings(文本/图像/日志)
- 使用
collection
区分数据类型(如ops_text_docs
,ops_images
,ops_logs
)
- Embedding 模型
- 文本:
text-embedding-3-small
- 图像:CLIP-based embedding(如
openai/clip-vit-base-patch32
) - 日志:同文本 embedding 处理
- 文本:
📂 Qdrant Schema 设计
json
{
"ops_text_docs": {
"vector_size": 1536,
"distance": "Cosine"
},
"ops_images": {
"vector_size": 512,
"distance": "Cosine"
},
"ops_logs": {
"vector_size": 1536,
"distance": "Cosine"
}
}
💻 Spring AI 代码示例
1. 配置依赖(pom.xml
)
xml
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-openai-spring-boot-starter</artifactId>
<version>1.0.0-M1</version>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-qdrant-spring-boot-starter</artifactId>
<version>1.0.0-M1</version>
</dependency>
2. Qdrant 配置(application.yml
)
yaml
spring:
ai:
openai:
api-key: ${OPENAI_API_KEY}
vectorstore:
qdrant:
host: localhost
port: 6333
3. 向量存储服务
java
@Service
public class KnowledgeIngestService {
private final QdrantVectorStore qdrant;
private final OpenAiEmbeddingClient embeddingClient;
public KnowledgeIngestService(QdrantVectorStore qdrant,
OpenAiEmbeddingClient embeddingClient) {
this.qdrant = qdrant;
this.embeddingClient = embeddingClient;
}
public void ingestTextDoc(String id, String content) {
EmbeddingResponse embedding = embeddingClient.embed(content);
qdrant.add(
new Document(id, content, embedding.getVector())
);
}
public void ingestLog(String id, String log) {
EmbeddingResponse embedding = embeddingClient.embed(log);
qdrant.add(
new Document(id, log, embedding.getVector())
);
}
public void ingestImage(String id, byte[] imageBytes) {
float[] vector = MyClipEmbeddingModel.encodeImage(imageBytes);
qdrant.add(
new Document(id, "image", vector)
);
}
}
4. RAG 服务
java
@Service
public class OpsRagService {
private final QdrantVectorStore qdrant;
private final ChatClient chatClient;
public OpsRagService(QdrantVectorStore qdrant, ChatClient chatClient) {
this.qdrant = qdrant;
this.chatClient = chatClient;
}
public String answerQuestion(String question, byte[] optionalImage, String optionalLog) {
// 1. 构造查询向量
List<float[]> queryVectors = new ArrayList<>();
queryVectors.add(embedding(question));
if (optionalLog != null) queryVectors.add(embedding(optionalLog));
if (optionalImage != null) queryVectors.add(MyClipEmbeddingModel.encodeImage(optionalImage));
// 2. 检索知识库
List<Document> retrievedDocs = new ArrayList<>();
for (float[] qv : queryVectors) {
retrievedDocs.addAll(qdrant.similaritySearch(qv, 3));
}
// 3. 拼接上下文
String context = retrievedDocs.stream()
.map(Document::getContent)
.collect(Collectors.joining("\n---\n"));
// 4. 调用 LLM
return chatClient.prompt()
.system("You are an Ops assistant. Use the following context:\n" + context)
.user(question)
.call()
.content();
}
private float[] embedding(String text) {
return new OpenAiEmbeddingClient().embed(text).getVector();
}
}
🚀 使用方式
java
@RestController
@RequestMapping("/ops")
public class OpsController {
private final OpsRagService ragService;
public OpsController(OpsRagService ragService) {
this.ragService = ragService;
}
@PostMapping("/ask")
public String ask(@RequestParam String question,
@RequestParam(required=false) MultipartFile image,
@RequestParam(required=false) String log) throws IOException {
return ragService.answerQuestion(
question,
image != null ? image.getBytes() : null,
log
);
}
}
✅ 这样,你就有了一个 Spring AI + Qdrant 的多模态 RAG 运维知识库:
- 可以问文本问题
- 可以上传监控截图
- 可以输入日志片段
- 最后由大模型结合知识库,给出解释和建议。