langchain4j [特性] 区分用于嵌入查询和嵌入文档/密钥的API

pxyaymoc  于 6个月前  发布在  其他
关注(0)|答案(6)|浏览(63)

我们可能需要在EmbeddingModel.java中区分用于嵌入查询和嵌入文档/密钥的API。
DashScope的嵌入服务长期以来一直为两种文本类型(查询、文档)提供输入参数:
https://github.com/langchain4j/langchain4j/blob/main/langchain4j-dashscope/src/main/java/dev/langchain4j/model/dashscope/QwenEmbeddingModel.java#L24
https://help.aliyun.com/zh/dashscope/developer-reference/text-embedding-api-details
FlagOpen/FlagEmbedding也为查询和密钥提供了不同的高级API:
https://github.com/FlagOpen/FlagEmbedding/tree/master/FlagEmbedding/llm_embedder#using-flagembedding
在我们当前的实现中,我们提醒用户在嵌入查询时添加特定的前缀文本:
https://github.com/langchain4j/langchain4j-embeddings/blob/main/langchain4j-embeddings-bge-small-en-v15/src/main/java/dev/langchain4j/model/embedding/bge/small/en/v15/BgeSmallEnV15EmbeddingModel.java#L16
然而,这个提示很难注意到,因为langchain4j和langchain4j-embedding是两个不同的项目。对于基于SPI动态加载EmbeddingModel的应用程序,设计一个通用解决方案就更难了。
我们应该考虑在EmbeddingModel.java中添加一个可选的embedQuery()方法,该方法可以默认调用现有的embed()方法以保持兼容性。对于为查询和文档提供不同方法的EmbeddingModel实现,可以根据需要重写embedQuery()方法。

xuo3flqw

xuo3flqw1#

你好,@jiangsier-xyz,很好的观点。
我们应该进行一些研究,检查所有关键的嵌入模型提供商,看看他们是否提供这个功能,并找到一个共同点。如果能有一个比较表格或者类似的东西就更好了。

xam8gpfp

xam8gpfp2#

你好,@jiangsier-xyz,很好的观点。我们应该做一些研究,检查所有关键的嵌入模型提供商,看看他们是否提供这个功能,并找到一个共同点。如果能有一个比较表格或者类似的东西就更好了。

这是基于langchain4j的调查:
| 嵌入模型 | 区分查询和文档 | 输入类型 | 备注 |
| ------------ | ------------ | ------------ | ------------ |
| Azure AI | ✅ | document query text | https://learn.microsoft.com/en-us/azure/machine-learning/reference-model-inference-embeddings?#embeddinginputtype |
| Bedrock Titan | | | https://docs.aws.amazon.com/bedrock/latest/userguide/model-parameters-titan-embed-text.html |
| Cohere | ✅ | search_document search_query classification clustering | https://docs.cohere.com/reference/embed |
| DashScope Qwen | ✅ | query document | https://help.aliyun.com/zh/dashscope/developer-reference/text-embedding-api-details |
| Jina: jina-embeddings-v2-base-en | | | https://jina.ai/embeddings/#apiform |
| Jina: jina-colbert-v1-en | ✅ | query document | https://jina.ai/embeddings/#apiform |
| Mistral | | | https://docs.mistral.ai/api/#operation/createEmbedding |
| Nomic | | | https://docs.nomic.ai/reference/endpoints/nomic-embed-text |
| Ollama | | | https://github.com/ollama/ollama/blob/main/docs/api.md#generate-embeddings |
| OpenAI | | | |
| Qianfan | | | https://cloud.baidu.com/doc/WENXINWORKSHOP/s/alj562vvu |
| Vertex AI | ✅ | RETRIEVAL_QUERY RETRIEVAL_DOCUMENT SEMANTIC_SIMILARITY CLASSIFICATION CLUSTERING QUESTION_ANSWERING FACT_VERIFICATION | https://cloud.google.com/vertex-ai/generative-ai/docs/embeddings/get-text-embeddings |
| Zhipu | | | https://open.bigmodel.cn/dev/api#text_embedding |
| FlagOpen/FlagEmbedding | ✅ | query key | https://github.com/FlagOpen/FlagEmbedding/tree/master/FlagEmbedding/llm_embedder#using-flagembedding |
| sentence-transformers/all-MiniLM-L6-v2 | | | https://huggingface.co/sentence-transformers/all-MiniLM-L6-v2 |
我的测试经验表明,由于查询在字面意义上可能与已存储的文档存在显著差异,而这并不是传统的搜索形式,因此利用相同类型的嵌入确实会导致召回率效果不佳。

whhtz7ly

whhtz7ly3#

@jiangsier-xyz 做得很好,系统化它,谢谢你!你有没有一个新的/更新的API的建议?它应该只包括查询/文档或其他任务吗?我可以看到至少分类是有用的。

mccptt67

mccptt674#

@jiangsier-xyz 做得很好,系统化它,谢谢!你有没有一个新的/更新的API的建议?它应该只包括查询/文档或其他任务吗?我可以看到至少分类是有用的。
设计一个枚举?就像这样:

public enum EmbeddingInputType {
    DOCUMENT,
    QUERY,
    CLASSIFICATION;
}
public interface EmbeddingModel {
    ...
    default Response<Embedding> embed(String text, EmbeddingInputType type) {
        return embed(TextSegment.from(text), type);
    }

    default Response<Embedding> embed(TextSegment textSegment, EmbeddingInputType type) {
        Response<List<Embedding>> response = embedAll(singletonList(textSegment), type);
        ValidationUtils.ensureEq(response.content().size(), 1,
                "Expected a single embedding, but got %d", response.content().size());
        return Response.from(response.content().get(0), response.tokenUsage(), response.finishReason());
    }

    default Response<List<Embedding>> embedAll(List<TextSegment> textSegments, EmbeddingInputType type) {
        // NOTE: The default implementation is type-insensitive.
        return embedAll(textSegments);
    }
}
piok6c0g

piok6c0g5#

@jiangsier-xyz 枚举听起来不错!
我计划(在不久的将来)使所有模型的API更加灵活,并将它们与 Result<T> 类型解耦,因此,而不是为这个即将被弃用的功能引入新的方法,我会立即引入一个新的API,如下所示:

public interface EmbeddingModel {
    
    EmbeddingResult embed(EmbeddingRequest request)
}

public class EmbeddingRequest {

    private final List<String> texts; // need to think if this should be TextSegmnets or some other types to accomodate for the possibility of multi-modal embedding models in the future
    private final InputType type;
}

WDYT?

nlejzf6q

nlejzf6q6#

@jiangsier-xyz 枚举听起来不错!
我计划(在不久的将来)使所有模型的API更加灵活,并将它们与Result<T>类型解耦,因此,而不是为这个即将被弃用的功能引入新的方法,我会立即引入一个新的API,如下所示:

public interface EmbeddingModel {
    
    EmbeddingResult embed(EmbeddingRequest request)
}

public class EmbeddingRequest {

    private final List<String> texts; // need to think if this should be TextSegmnets or some other types to accomodate for the possibility of multi-modal embedding models in the future
    private final InputType type;
}

WDYT?
看起来很棒!更优雅。期待这个变化。

相关问题