文档知识库，一般是基于向量数据库封装的并提供文档存储与相似搜索的接口（所以也叫，文档向量知识库）。其实，不基于向量数据库封装也行，比如基于本文搜索。


### 1、内置的适配（可以根据业务，按需定制）

| 知识库                              | 所在插件                                | 描述                                         |
| --------------------- | ------------------------ | ------------------------- |
| InMemoryRepository         | solon-ai                                  | 内存知识库（数据在 map 里）     |
| WebSearchRepository       | solon-ai                                  | 联网搜索知识库                        |
| | | |
| ChromaRepository             | [solon-ai-repo-chroma](/article/988)              | Chroma 矢量存储知识库                |
| DashVectorRepository             | [solon-ai-repo-dashvector](/article/1024)              | DashVector 矢量存储知识库                |
| ElasticsearchRepository     | [solon-ai-repo-elasticsearch](/article/989)      | ElasticSearch 矢量存储知识库                |
| MilvusRepository               | [solon-ai-repo-milvus](/article/941)               | Milvus 矢量存储知识库                |
| QdrantRepository              | [solon-ai-repo-qdrant](/article/990)               | Qdrant 矢量存储知识库                |
| RedisRepository                | [solon-ai-repo-redis](/article/942)                 | Redis Search 矢量存储知识库       |
| TcVectorDbRepository       | [solon-ai-repo-tcvectordb](/article/991)         | TcVectorDb 腾讯云矢量存储知识库                |


相关配置，参考具体插件介绍。


### 2、Repository 接口

只读知识库接口。比如封装网络搜索，只读接口即可

```java
public interface Repository {
    //检索
    default List<Document> search(String query) throws IOException {
        return search(new QueryCondition(query));
    }

    //检索
    List<Document> search(QueryCondition condition) throws IOException;
}
```

可写知识库接口（可读，可写）

```java
public interface RepositoryStorable extends Repository {
    //异步保存文档
    default CompletableFuture<Void> asyncSave(List<Document> documents, BiConsumer<Integer, Integer> progressCallback) {
        CompletableFuture<Void> future = new CompletableFuture<>();

        RunUtil.async(() -> {
            try {
                save(documents, progressCallback);
                future.complete(null);
            } catch (Exception ex) {
                future.completeExceptionally(ex);
            }
        });

        return future;
    }

    //保存文档
    void save(List<Document> documents, BiConsumer<Integer, Integer> progressCallback) throws IOException;


    //保存文档
    default void save(List<Document> documents) throws IOException {
        save(documents, null);
    }

    //保存文档
    default void save(Document... documents) throws IOException {
        save(Arrays.asList(documents));
    }

    //删除文档
    void deleteById(String... ids) throws IOException;

    //是否存在文档
    boolean existsById(String id) throws IOException;
}
```


### 3、简单示例

```java
private void load(RepositoryStorable repository, String file) throws IOException {
    //加载器
    HtmlSimpleLoader loader = new HtmlSimpleLoader(new File(file));
    
    //加载后再分割（按需）
    List<Document> documents = new SplitterPipeline() 
            .next(new RegexTextSplitter("\n\n"))
            .next(new TokenSizeTextSplitter(500))
            .split(loader.load());
    
    //入库
    repository.insert(documents); 
}
```