我正在使用 Langchain4j 构建基于 RAG 的 AI 服务。我有一个微服务,它正在将我的文档(pdf、csv、words...)作为嵌入摄取并保存在我的 PostgreSQL 数据库(带有矢量扩展)中。
另一方面,我正在构建另一个微服务来保存人工智能对话逻辑。
为此,我正在创建下一个 bean
@Bean
public EmbeddingStore<TextSegment> embeddingStore() {
return new InMemoryEmbeddingStore<>();
}
@Bean
public ContentRetriever contentRetriever() {
return EmbeddingStoreContentRetriever.builder()
.embeddingStore(embeddingStore())
.embeddingModel(bedrockTitanEmbeddingModel())
.maxResults(10) // on each interaction we will retrieve the 5 most relevant segments
.minScore(0.2) // we want to retrieve segments very similar to the user query
.build();
}
@Bean
public RetrievalAugmentor retrievalAugmentor() {
return DefaultRetrievalAugmentor.builder()
.queryTransformer(queryTransformer())
.contentRetriever(contentRetriever())
.build();
}
@Bean
public AiAgent aiAgent() {
return AiServices.builder(ErekyAiAgent.class)
.retrievalAugmentor(retrievalAugmentor())
.chatLanguageModel(bedrockAnthropicChatModel())
.contentRetriever(contentRetriever())
.build();
}
ContentRetriever
要求我将embeddingStore作为强制参数。现在为了进行测试,我使用的是内存,但我看到 Langchain4j 有一个带有 pgvector 的实现。
在流程中我正在做的是:
List<TextSegment>
列表,这是一种 langchain4j 库。List<TextSegment>
转换为嵌入,并将它们与 List<TextSegment>
一起添加,而不将它们嵌入到我正在使用的嵌入存储中。逻辑是
List<String> documentTexts = getDocumentTextsFromUserQuestion(promptDto);
List<TextSegment> textSegments = getTextSegments(documentTexts);
embeddingStore.addAll(embedComponent.getEmbeddingsFromTextSegments(textSegments), textSegments);
return new PromptDTO(aiAgent.answer(documentTexts, promptDto.getText()));
我发现由于某种原因,逻辑总是需要我将该数据添加到嵌入存储中,以便能够根据我的数据给出正确的答案。当我使用 Langchain4j 的 pgvector 实现并做了同样的事情时,我看到该实现正在我的数据库中创建一个表,其中包含我在插入这个新表之前已经保存的数据以给出答案。并且数据正在被复制,有没有一种方法可以让这项工作无需重复?
而且由于我已经将数据保存在数据库中,所以我不能直接用从用户问题+用户问题中找到的数据来调用AI?
我在Python中这样做,调用chain.run记录数据库中找到的数据,问题是用户问题,它有效,我不需要这个中间嵌入存储。
chain = load_qa_chain(llm, chain_type="stuff")
# Call to the model
# response = st.session_state.conversation({'question': user_question})
response = chain.run(input_documents=document, question=user_question)
不确定您是否已经修复了拦截器。我遇到了与 MongoDb 类似的问题,虽然它不是在使用嵌入式存储的 MongoDB 实现时在数据库中创建的新集合,但它恰好是 ObjectId 的另一个问题。我的项目正在进行中,直到我意识到我可以使用 langchain4j 来实现各种人工智能操作。因此,我已经对服务类中的 MongoDB 集合进行了各种查询和聚合,数据已存储为嵌入。我所做的就是重用这些查询并将它们存储在
InMemoryEmbeddingStore
中。我的查询已经从原始提示中收到了最相关的嵌入。或者,您可以将要嵌入的信息以纯文本形式存储在数据库中,并使用 langchain4j EmbeddingModel 将数据转换为嵌入,以推送到 InMemoryEmbeddingStore 中。这是我的解决方法的第一次迭代。
// We will use initialize and use the ADA_002 to create embeddings on text field from database
EmbeddingModel embeddingModel = new OpenAiEmbeddingModel.OpenAiEmbeddingModelBuilder()
.modelName(OpenAiEmbeddingModelName.TEXT_EMBEDDING_ADA_002)
.apiKey(youTubeRagChainProperties.getOpenaiKey())
.maxRetries(2)
.build();
InMemoryEmbeddingStore<TextSegment> inMemoryEmbeddingStore = new InMemoryEmbeddingStore<>();
// we can use query service to get most relevant search results
List<QueryResults> querySearchResult = queryService.getDataFromVectorSearch(prompt);
querySearchResult.forEach(result -> {
TextSegment textSegment = TextSegment.from(result.getText());
Embedding embedding = embeddingModel.embed(textSegment).content();
inMemoryEmbeddingStore.add(embedding, textSegment);
});
// use embedding model and in memory store as retriever for optimal answer
EmbeddingStoreContentRetriever retriever = EmbeddingStoreContentRetriever.builder()
.embeddingModel(embeddingModel)
.embeddingStore(inMemoryEmbeddingStore)
.build();
String question = prompt;
// given the prompt with the added context and user question, we can now build our model
ChatLanguageModel chatLanguageModel = OpenAiChatModel.builder()
.apiKey(openAiKey)
.modelName(GPT_4o)
.timeout(Duration.ofSeconds(60))
.build();
// using our AI system interface build the prompt
Bot bot = AiServices.builder(Bot.class)
.chatLanguageModel(chatLanguageModel)
.contentRetriever(retriever)
.build();
return bot.chat(1, question);
langchain4j
InMemoryEmbeddingStore
的一个很棒的地方是您可以使用 ID 保存消息。 langchain4j 仍然经常更新一些内容,所以我相信您很快就能找到合适的解决方案。希望这有帮助!