近两年,AI的快速发展推动了许多互联网产品的AI集成。我也在加班加点学习智能体 (Agent)开发。 最近遇到一个需求,除了需要与AI正常互动聊天外,还要求AI针对性地分析一些数据,确保对话更专业、垂直,这个时候需要利用一种叫:RAG技术,我就了解到了dify这个开源平台 。 在我之前的文章中也提到过,如果大家不打算深耕AI底层,只想将AI应用集成到日常业务中,智能体开发是一个不错的选择。
市面上也开源了很多现成的智能体开发平台,比如:扣子、dify 这些平台 。我们就可以安装到自己的本地电脑进行学习对接。
今天主要和大家分享的是 dify平台的搭建和对接,核心需求是 通过API调用dify 提供的知识库相关的服务。
业务需求是一个管理系统,是用python 做的,对接了AI大模型接口,通过和AI的聊天来控制软件的某些功能,现在新增一个需求是要分析系统里的一些文件。找了很多知识库RAG相关的文章和开源的框架。
RagFlow :官方文档ragflow.com.cn/docs/ 这个是只针对知识库进行处理的,但是对于硬件要有有点高
所以最终选择了 Dify 这个开源平台,他是一个Agent敏捷开发平台,内置了知识库相关的功能,这篇文章主要分享的就是 怎么通过API 来使用Dify平台的知识库功能。
Dify 官方文档:docs.dify.ai/api-referen…
github 开源地址:github.com/langgenius/…
好了,背景和介绍就说这么多,下面主要来分享 部署和知识库API调用 的相关代码
部署:我们采用docker部署,简单快捷
源码从git上下载下来后执行下面命令
cd docker
cp .env.example .env
docker compose up -d
具体针对性配置 可参考官方文档,通过浏览器可以正常访问后,算启动成功。
下面分享一个对接dify的知识库的相关代码,因为参数太多,大家按需选择:
以下代码仅供参考,大家按需分配,具体参数参考dify的官方文档
python版:
import requests
import json
class DifyHelper:
def __init__(self):
# 基础URL和API密钥
self.base_url = 'API地址'
self.api_key = 'apiKey在启动的后台里申请'
def datasets_add(self, params):
"""
创建空知识库.
:param params: 参数数组
:return: 创建成功返回知识库信息,失败返回空字典
"""
params_data = {
'name': params['name'], # 知识库的名称
'description': params['description'], # 知识库的描述(可选)。
'indexing_technique': 'high_quality', # 要使用的索引技术 可用选项: high_quality 高质量, economy 经济
'embedding_model': 'multimodal-embedding-v1', # 嵌入模型的名称 做配置项
'embedding_model_provider': 'langgenius/tongyi/tongyi', # 嵌入模型的提供者 做配置项
'retrieval_model': {
'search_method': 'hybrid_search', # 用于检索的搜索方法 可用选项: hybrid_search(混合), semantic_search, full_text_search, keyword_search
'reranking_enable': True, # 是否启用重新排序模型以改善搜索结果。
'reranking_mode': 'reranking_model', # 重新排序模式。 可用选项: reranking_model, weighted_score
'reranking_model': {
'reranking_provider_name': 'langgenius/tongyi/tongyi', # 重新排序模型的提供商。 做配置项
'reranking_model_name': 'gte-rerank', # 重新排序模型的名称。 做配置项
},
'top_k': 4, # 返回的顶部匹配结果数量。
'score_threshold_enabled': True, # 是否应用分数阈值来过滤结果。
'score_threshold': 0.5, # 结果包含的最低分数。
},
'summary_index_setting': { # 摘要索引设置
'enable': None, # 是否启用摘要,true表示启用
'model_name': None, # 使用的模型名称,如 "qwen-vl-plus"
'model_provider_name': None, # 模型提供商,如 "langgenius/tongyi/tongyi"
'summary_prompt': None, # 摘要提示词,用于指导AI生成摘要
},
}
result = self.make_client(self.base_url + '/datasets', params_data, 'POST', {
'Authorization': 'Bearer ' + self.api_key,
})
if 'id' not in result:
return {}
return result
def datasets_update(self, dataset_id, params):
"""
更新知识库.
:param dataset_id: 知识库ID
:param params: 参数数组
:return: 更新成功返回知识库信息,失败返回空字典
"""
if not dataset_id:
return {}
# 目前只支持更新 名字和描述
params_data = {
'name': params['name'], # 知识库的名称
'description': params['description'], # 知识库的描述(可选)。
}
result = self.make_client(self.base_url + f'/datasets/{dataset_id}', params_data, 'PATCH', {
'Authorization': 'Bearer ' + self.api_key,
})
if 'id' not in result:
return {}
return result
def datasets_delete(self, dataset_id):
"""
删除知识库.
:param dataset_id: 知识库ID
:return: 删除操作是否执行
"""
self.make_client(self.base_url + f'/datasets/{dataset_id}', {}, 'DELETE', {
'Authorization': 'Bearer ' + self.api_key,
})
return True
def datasets_create_by_file(self, dataset_id, file):
"""
从文件创建文档.
:param dataset_id: 知识库ID
:param file: 文件对象,需要有getRealPath()和getClientFilename()方法
:return: 创建结果
"""
# 构建multipart请求数据
multipart = [
('data', json.dumps(self.document_hierarchical_rule())),
('file', (file.filename, file.stream, 'application/octet-stream')),
]
result = self.multipart_request(self.base_url + f'/datasets/{dataset_id}/document/create-by-file', multipart, {
'Authorization': 'Bearer ' + self.api_key,
})
return json.loads(result)
def datasets_update_by_file(self, dataset_id, document_id, file):
"""
用文件更新文档.
:param dataset_id: 知识库ID
:param document_id: 文档ID
:param file: 文件对象,需要有getRealPath()和getClientFilename()方法
:return: 更新结果
"""
# 构建multipart请求数据
multipart = [
('data', json.dumps(self.document_hierarchical_rule())),
('file', (file.filename, file.stream, 'application/octet-stream')),
]
result = self.multipart_request(self.base_url + f'/datasets/{dataset_id}/documents/{document_id}/update-by-file', multipart, {
'Authorization': 'Bearer ' + self.api_key,
})
return json.loads(result)
def datasets_document_embedding_status(self, dataset_id, batch):
"""
获取文档嵌入状态(进度).
:param dataset_id: 知识库ID
:param batch: 批次ID
:return: 嵌入状态信息,失败返回空字典
"""
result = self.make_client(self.base_url + f'/datasets/{dataset_id}/documents/{batch}/indexing-status', {}, 'GET', {
'Authorization': 'Bearer ' + self.api_key,
})
if not result:
return {}
return result
def document_hierarchical_rule(self):
"""
文档规则定义
子父级 分割
:return: 返回文档的结构和处理规则配置
"""
return {
'doc_form': 'hierarchical_model',
'doc_language': 'Chinese Simplified', # 文档语言
'process_rule': { # 文档处理规则
'mode': 'hierarchical', # 处理模式,可选值 "automatic"(自动) 或 "custom"(自定义), hierarchical 分层
'rules': [ # 自定义规则配置
'parent_mode': 'paragraph', # 分层模式中父块的检索模式。 可用选项: full-doc, paragraph
'pre_processing_rules': [
{'enabled': True, 'id': 'remove_extra_spaces'},
{'enabled': True, 'id': 'remove_urls_emails'}, # 删除所有 URL 和电子邮件地址
],
'segmentation': { # 将文档内容分割成块的规则。
'separator': "\n\n", # 分段分隔符,默认使用 "###"
'max_tokens': 1024, # 每段最大token数,默认500
},
'subchunk_segmentation': { # 将父块分割为较小子块的规则(用于分层模式)。
'separator': "\n",
'max_tokens': 1024,
},
],
},
}
def make_client(self, url, params, method='POST', headers=None):
"""
通用HTTP客户端方法
:param url: 请求的URL
:param params: 请求参数
:param method: 请求方式,默认为POST
:param headers: 请求头
:return: 返回解析后的JSON响应,失败时返回空字典
"""
if headers is None:
headers = {}
headers['content-type'] = 'application/json'
try:
response = requests.request(method, url, json=params, headers=headers, verify=False)
body = response.text
print('Dify 接口调用 result 请求日志:', body)
if not body:
print('Dify 接口调用 返回值为空时 请求日志:', {
'url': url, 'method': method, 'params': params, 'result': body
})
return {}
return json.loads(body)
except Exception as e:
print('Dify 接口调用异常===>', {'msg': str(e), 'data': params, 'url': url})
return {}
def multipart_request(self, url, files, headers=None):
"""
发送multipart请求
:param url: 请求的URL
:param files: multipart数据
:param headers: 请求头
:return: 返回响应的文本
"""
if headers is None:
headers = {}
response = requests.post(url, files=files, headers=headers)
return response.text
java版:(springboot框架)代码仅供参考,用的时候根据自己需求调试
package com.example.helper;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import okhttp3.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
/**
* DifyHelper类用于操作和管理知识库,通过外部API进行交互。
*/
@Component
public class DifyHelper {
private static final Logger logger = LoggerFactory.getLogger(DifyHelper.class);
// 基础API URL
private final String baseUrl = "";
// API密钥
private final String apiKey = "";
private final OkHttpClient client;
public DifyHelper() {
this.client = new OkHttpClient();
}
/**
* 创建空知识库.
* @param params 参数数组
* @return 创建成功返回知识库信息,失败返回空数组
*/
public JSONObject datasetsAdd(Map<String, Object> params) {
Map<String, Object> paramsData = new HashMap<>();
paramsData.put("name", params.get("name")); // 知识库的名称
paramsData.put("description", params.get("description")); // 知识库的描述(可选)
paramsData.put("indexing_technique", "high_quality"); // 要使用的索引技术,可用选项: high_quality 高质量, economy 经济
paramsData.put("embedding_model", "multimodal-embedding-v1"); // 嵌入模型的名称 做配置项
paramsData.put("embedding_model_provider", "langgenius/tongyi/tongyi"); // 嵌入模型的提供者 做配置项
paramsData.put("retrieval_model", createRetrievalModel()); // 检索模型
paramsData.put("summary_index_setting", createSummaryIndexSetting()); // 摘要索引设置
return makeClient(baseUrl + "/datasets", paramsData, "POST");
}
/**
* 更新知识库.
* @param datasetId 知识库ID
* @param params 参数数组
* @return 更新成功返回知识库信息,失败返回空数组
*/
public JSONObject datasetsUpdate(String datasetId, Map<String, Object> params) {
if (datasetId == null || datasetId.isEmpty()) {
return new JSONObject();
}
Map<String, Object> paramsData = new HashMap<>();
paramsData.put("name", params.get("name")); // 知识库的名称
paramsData.put("description", params.get("description")); // 知识库的描述(可选)
return makeClient(baseUrl + "/datasets/" + datasetId, paramsData, "PATCH");
}
/**
* 删除知识库.
* @param datasetId 知识库ID
* @return 删除操作是否执行
*/
public boolean datasetsDelete(String datasetId) {
makeClient(baseUrl + "/datasets/" + datasetId, new HashMap<>(), "DELETE");
return true;
}
/**
* 从文件创建文档.
* @param datasetId 知识库ID
* @param file 文件对象
* @return 创建结果
*/
public JSONObject datasetsCreateByFile(String datasetId, File file) {
Map<String, Object> multipartData = new HashMap<>();
multipartData.put("data", JSON.toJSONString(documentHierarchicalRule()));
RequestBody fileBody = RequestBody.create(file, MediaType.parse("application/octet-stream"));
MultipartBody multipartBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM)
.addFormDataPart("data", JSON.toJSONString(documentHierarchicalRule()))
.addFormDataPart("file", file.getName(), fileBody)
.build();
return makeMultipartRequest(baseUrl + "/datasets/" + datasetId + "/document/create-by-file", multipartBody);
}
/**
* 获取文档嵌入状态(进度).
* @param datasetId 知识库ID
* @param batch 批次ID
* @return 嵌入状态信息,失败返回空数组
*/
public JSONObject datasetsDocumentEmbeddingStatus(String datasetId, String batch) {
return makeClient(baseUrl + "/datasets/" + datasetId + "/documents/" + batch + "/indexing-status", new HashMap<>(), "GET");
}
// 构建检索模型
private Map<String, Object> createRetrievalModel() {
Map<String, Object> retrievalModel = new HashMap<>();
retrievalModel.put("search_method", "hybrid_search"); // 用于检索的搜索方法 可用选项: hybrid_search(混合), semantic_search, full_text_search, keyword_search
retrievalModel.put("reranking_enable", true); // 是否启用重新排序模型以改善搜索结果。
retrievalModel.put("reranking_mode", "reranking_model"); // 重新排序模式。 可用选项: reranking_model, weighted_score
retrievalModel.put("reranking_model", createRerankingModel()); // 重新排序模型
retrievalModel.put("top_k", 4); // 返回的顶部匹配结果数量。
retrievalModel.put("score_threshold_enabled", true); // 是否应用分数阈值来过滤结果。
retrievalModel.put("score_threshold", 0.5); // 结果包含的最低分数。
return retrievalModel;
}
// 构建重新排序模型
private Map<String, Object> createRerankingModel() {
Map<String, Object> rerankingModel = new HashMap<>();
rerankingModel.put("reranking_provider_name", "langgenius/tongyi/tongyi"); // 重新排序模型的提供商。 做配置项
rerankingModel.put("reranking_model_name", "gte-rerank"); // 重新排序模型的名称。 做配置项
return rerankingModel;
}
// 构建摘要索引设置
private Map<String, Object> createSummaryIndexSetting() {
Map<String, Object> summaryIndexSetting = new HashMap<>();
summaryIndexSetting.put("enable", null); // 是否启用摘要,true表示启用
summaryIndexSetting.put("model_name", null); // 使用的模型名称,如 "qwen-vl-plus"
summaryIndexSetting.put("model_provider_name", null); // 模型提供商,如 "langgenius/tongyi/tongyi"
summaryIndexSetting.put("summary_prompt", null); // 摘要提示词,用于指导AI生成摘要
return summaryIndexSetting;
}
// 文档规则定义
private Map<String, Object> documentHierarchicalRule() {
Map<String, Object> rule = new HashMap<>();
rule.put("doc_form", "hierarchical_model");
rule.put("doc_language", "Chinese Simplified"); // 文档语言
Map<String, Object> processRule = new HashMap<>();
processRule.put("mode", "hierarchical");
Map<String, Object> segmentation = new HashMap<>();
segmentation.put("separator", "\n\n"); // 分段分隔符,默认使用 "\n\n"
segmentation.put("max_tokens", 1024); // 每段最大token数
processRule.put("segmentation", segmentation);
rule.put("process_rule", processRule);
return rule;
}
// 通用HTTP请求方法
private JSONObject makeClient(String url, Map<String, Object> params, String method) {
try {
RequestBody body = RequestBody.create(JSON.toJSONString(params), MediaType.parse("application/json"));
Request request = new Request.Builder()
.url(url)
.addHeader("Authorization", "Bearer " + apiKey)
.method(method, body)
.build();
try (Response response = client.newCall(request).execute()) {
if (response.isSuccessful()) {
String responseBody = response.body().string();
logger.info("API 调用结果: {}", responseBody);
return JSON.parseObject(responseBody);
}
}
} catch (IOException e) {
logger.error("API 调用异常", e);
}
return new JSONObject();
}
// 发送multipart请求
private JSONObject makeMultipartRequest(String url, MultipartBody multipartBody) {
try {
Request request = new Request.Builder()
.url(url)
.addHeader("Authorization", "Bearer " + apiKey)
.post(multipartBody)
.build();
try (Response response = client.newCall(request).execute()) {
if (response.isSuccessful()) {
String responseBody = response.body().string();
logger.info("API 调用结果: {}", responseBody);
return JSON.parseObject(responseBody);
}
}
} catch (IOException e) {
logger.error("API 调用异常", e);
}
return new JSONObject();
}
}