npx claudepluginhub giuseppe-trisciuoglio/developer-kit --plugin developer-kit-javaThis skill is limited to using the following tools:
references/examples.mdreferences/references.mdSearches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Searches prompts.chat for AI prompt templates by keyword or category, retrieves by ID with variable handling, and improves prompts via AI. Use for discovering or enhancing prompts.
Compares coding agents like Claude Code and Aider on custom YAML-defined codebase tasks using git worktrees, measuring pass rate, cost, time, and consistency.
Implements RAG systems with LangChain4j: document ingestion pipelines, embedding stores, and vector search for chat-with-documents and knowledge-enhanced AI applications.
Create a new Spring Boot project with required dependencies:
pom.xml:
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-spring-boot-starter</artifactId>
<version>1.8.0</version>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-open-ai</artifactId>
<version>1.8.0</version>
</dependency>
Configure document loading and processing with validation:
Validation Checkpoint: After ingestion, verify embedding count matches segment count and test retrieval with a sample query.
@Configuration
public class RAGConfiguration {
@Bean
public EmbeddingModel embeddingModel() {
return OpenAiEmbeddingModel.builder()
.apiKey(System.getenv("OPENAI_API_KEY"))
.modelName("text-embedding-3-small")
.build();
}
@Bean
public EmbeddingStore<TextSegment> embeddingStore() {
return new InMemoryEmbeddingStore<>();
}
}
Create document ingestion service:
@Service
@RequiredArgsConstructor
public class DocumentIngestionService {
private final EmbeddingModel embeddingModel;
private final EmbeddingStore<TextSegment> embeddingStore;
public void ingestDocument(String filePath, Map<String, Object> metadata) {
Document document = FileSystemDocumentLoader.loadDocument(filePath);
document.metadata().putAll(metadata);
DocumentSplitter splitter = DocumentSplitters.recursive(
500, 50, new OpenAiTokenCountEstimator("text-embedding-3-small")
);
List<TextSegment> segments = splitter.split(document);
List<Embedding> embeddings = embeddingModel.embedAll(segments).content();
embeddingStore.addAll(embeddings, segments);
// Validation: verify embedding count matches segments
if (embeddings.size() != segments.size()) {
throw new IllegalStateException("Embedding count mismatch: expected " + segments.size() + ", got " + embeddings.size());
}
}
public boolean validateIngestion(String testQuery) {
// Validation: test retrieval with sample query
Embedding queryEmbedding = embeddingModel.embed(testQuery).content();
List<EmbeddingMatch<TextSegment>> results = embeddingStore.search(
EmbeddingSearchRequest.builder()
.queryEmbedding(queryEmbedding)
.maxResults(1)
.build()
).matches();
return !results.isEmpty();
}
}
Setup content retrieval with filtering:
Validation Checkpoint: After configuration, test retrieval with a known query to verify embeddings are searchable.
@Configuration
public class ContentRetrieverConfiguration {
@Bean
public ContentRetriever contentRetriever(
EmbeddingStore<TextSegment> embeddingStore,
EmbeddingModel embeddingModel) {
return EmbeddingStoreContentRetriever.builder()
.embeddingStore(embeddingStore)
.embeddingModel(embeddingModel)
.maxResults(5)
.minScore(0.7)
.build();
}
}
Define AI service with context retrieval:
interface KnowledgeAssistant {
@SystemMessage("""
You are a knowledgeable assistant with access to a comprehensive knowledge base.
When answering questions:
1. Use the provided context from the knowledge base
2. If information is not in the context, clearly state this
3. Provide accurate, helpful responses
4. When possible, reference specific sources
5. If the context is insufficient, ask for clarification
""")
String answerQuestion(String question);
}
@Service
@RequiredArgsConstructor
public class KnowledgeService {
private final KnowledgeAssistant assistant;
public KnowledgeService(ChatModel chatModel, ContentRetriever contentRetriever) {
this.assistant = AiServices.builder(KnowledgeAssistant.class)
.chatModel(chatModel)
.contentRetriever(contentRetriever)
.build();
}
public String answerQuestion(String question) {
return assistant.answerQuestion(question);
}
}
public class BasicRAGExample {
public static void main(String[] args) {
var embeddingStore = new InMemoryEmbeddingStore<TextSegment>();
var embeddingModel = OpenAiEmbeddingModel.builder()
.apiKey(System.getenv("OPENAI_API_KEY"))
.modelName("text-embedding-3-small")
.build();
var ingestor = EmbeddingStoreIngestor.builder()
.embeddingModel(embeddingModel)
.embeddingStore(embeddingStore)
.build();
ingestor.ingest(Document.from("Spring Boot is a framework for building Java applications with minimal configuration."));
var retriever = EmbeddingStoreContentRetriever.builder()
.embeddingStore(embeddingStore)
.embeddingModel(embeddingModel)
.build();
}
}
interface MultiDomainAssistant {
@SystemMessage("""
You are an expert assistant with access to multiple knowledge domains:
- Technical documentation
- Company policies
- Product information
- Customer support guides
Tailor your response based on the type of question and available context.
Always indicate which domain the information comes from.
""")
String answerQuestion(@MemoryId String userId, String question);
}
@Service
@RequiredArgsConstructor
public class HierarchicalRAGService {
private final EmbeddingStore<TextSegment> chunkStore;
private final EmbeddingStore<TextSegment> summaryStore;
private final EmbeddingModel embeddingModel;
public String performHierarchicalRetrieval(String query) {
List<EmbeddingMatch<TextSegment>> summaryMatches = searchSummaries(query);
List<TextSegment> relevantChunks = new ArrayList<>();
for (EmbeddingMatch<TextSegment> summaryMatch : summaryMatches) {
String documentId = summaryMatch.embedded().metadata().getString("documentId");
List<EmbeddingMatch<TextSegment>> chunkMatches = searchChunksInDocument(query, documentId);
chunkMatches.stream()
.map(EmbeddingMatch::embedded)
.forEach(relevantChunks::add);
}
return generateResponseWithChunks(query, relevantChunks);
}
}
@RequiredArgsConstructor
@Service
public class SimpleRAGPipeline {
private final EmbeddingModel embeddingModel;
private final EmbeddingStore<TextSegment> embeddingStore;
private final ChatModel chatModel;
public String answerQuestion(String question) {
Embedding queryEmbedding = embeddingModel.embed(question).content();
EmbeddingSearchRequest request = EmbeddingSearchRequest.builder()
.queryEmbedding(queryEmbedding)
.maxResults(3)
.build();
List<TextSegment> segments = embeddingStore.search(request).matches().stream()
.map(EmbeddingMatch::embedded)
.collect(Collectors.toList());
String context = segments.stream()
.map(TextSegment::text)
.collect(Collectors.joining("\n\n"));
return chatModel.generate(context + "\n\nQuestion: " + question + "\nAnswer:");
}
}
@Service
@RequiredArgsConstructor
public class HybridSearchService {
private final EmbeddingStore<TextSegment> vectorStore;
private final FullTextSearchEngine keywordEngine;
private final EmbeddingModel embeddingModel;
public List<Content> hybridSearch(String query, int maxResults) {
// Vector search
List<Content> vectorResults = performVectorSearch(query, maxResults);
// Keyword search
List<Content> keywordResults = performKeywordSearch(query, maxResults);
// Combine and re-rank using RRF algorithm
return combineResults(vectorResults, keywordResults, maxResults);
}
}
Embedding Count Mismatch: Thrown when segments != embeddings. Check splitter configuration and model availability.
Empty Retrieval Results: Call validateIngestion(testQuery) to verify embeddings are searchable. Check if document was ingested successfully.
Low Retrieval Scores: Verify minScore threshold (default 0.7) is not too high for your use case. Test with known queries.
Poor Retrieval Results
Slow Performance
High Memory Usage