找回密码
 立即注册
首页 业界区 业界 (dify)如何使用dify自定义知识库【dify外部链接知识库】 ...

(dify)如何使用dify自定义知识库【dify外部链接知识库】

蒲善思 2025-6-2 23:51:16
尝试dify自定义知识库

根据官网教程,可以从知识库的右上角外部知识库进行添加外部知识库
前往 “知识库” 页,点击右上角的 “外部知识库 API”,轻点 “添加外部知识库 API”
按照页面提示,依次填写以下内容:

  • 知识库的名称,允许自定义名称,用于区分所连接的不同外部知识 API;
  • API 接口地址,外部知识库的连接地址,示例 api-endpoint/retrieval;详细说明请参考外部知识库 API;
  • API Key,外部知识库连接密钥,详细说明请参考外部知识库 API;
    1.png

因为APIEndpoint需要网络url地址,这里使用本地当作服务器进行尝试
1 使用python+flask框架构建本地后端

教程:python flask框架详解
1.1简单上手
  1. from flask import Flask
  2. app = Flask(__name__)
  3. @app.route('/')
  4. def hello_world():
  5.    return 'Hello World'
  6. if __name__ == '__main__':
  7.    app.run()
复制代码
在简单上手中,我们使用到了装饰器:@app.route('/'),要先了解装饰器,然后了解falsk这个装饰器以及其他类似的装饰器的用法。
1.2falsk的其他装饰器以及用法:

【扩展阅读,可跳过】
@app.route()


  • 作用:将视图函数与指定的 URL 路径进行绑定。
  • 示例
  1. @app.route('/') # 路由装饰器,绑定URL路径
  2. def home():
  3.     return 'Hello, World!'
复制代码
@app.before_request()


  • 作用:注册一个函数,在每个请求执行之前调用。适用于一些请求前的预处理,比如认证检查、日志记录等。
  • 示例
  1. @app.before_request
  2. def before_request():
  3.     print("This runs before every request.")
复制代码
@app.after_request()


  • 作用:注册一个函数,在每个请求执行之后调用。适用于请求处理后的操作,如修改响应数据、日志记录等。
  • 示例
  1. @app.after_request
  2. def after_request(response):
  3.     print("This runs after each request.")
  4.     return response  # 必须返回响应对象
复制代码
@app.errorhandler()


  • 作用:注册一个函数,用于处理指定 HTTP 错误码的错误。例如,处理 404 页面未找到或 500 服务器错误等。
  • 示例
    1. @app.errorhandler(404)
    2. def page_not_found(error):
    3.     return "Page not found", 404
    复制代码
@app.before_first_request()


  • 作用:在应用处理第一个请求之前执行一次。适用于一些应用初始化的操作,例如数据库连接或缓存初始化等。
  • 示例
    1. @app.before_first_request
    2. def before_first_request():
    3.     print("This runs once before the first request.")
    复制代码
@app.route() 支持 HTTP 方法的装饰器


  • 作用:@app.route() 装饰器可以通过 methods 参数指定哪些 HTTP 方法(如 GET、POST、PUT、DELETE 等)可以触发该路由。
  • 示例
    1. @app.route('/submit', methods=['POST'])
    2. def submit():
    3.     return 'Form Submitted'
    复制代码
2 修改路由以及服务器设置

2.1 基础设置

由于dify启动时会占用本地默认的 127.0.0.1:5000,为了避免冲突,我们就需要通过修改端口的形式来规避这个问题,用到的接口是:
  1. app.run(debug=True, host='127.0.0.1', port=5001)
复制代码
app.run 中提供了修改基本信息的接口:

  • host:服务器的地址,window默认为 127.0.0.1
  • debug:调试模式是否启动
  • port:端口号。这里使用不同的端口号来分辨dify以及知识库服务器。
2.2test code


  • 根据需求会post一个json的请求体
    2.png

    因此我们假设他传来的是json、调用get方法
  1. from flask import Flask , request, jsonify
  2. app = Flask(__name__)
  3. @app.route('/retrieval',methods=['POST'])
  4. def get_data():
  5.     data = request.get_json()
  6.     print(data)
  7.     return jsonify(data)
  8. @app.route('/')
  9. def default():
  10.     return 'hello'
  11. if __name__ == '__main__':
  12.     app.run(debug=True, host='127.0.0.1', port=5001)
  13.     get_data()
复制代码
2.2.1 本地测试

先进行本地测试一下:
3.png

主页成功,测试 /retrieval页面:
4.png

5.png

问题不大,因为我们没有上传json文件,启动dify尝试一下
3  dify添加api测试

发现会报错,没办法访问:
6.png

3.1 问题解决:


  • 问题思考
从计算机网络的角度来说,dify在WSL中运行,由于虚拟化,容器本地环境与windows的本地环境并不一致,即:当使用127.0.0.1进行访问时,访问的是容器内的主机,但我们的window环境并不在容器内部署,因此无法访问到window环境的127.0.0.1。中间需要一些NAT【单纯指网络地址转换】才能访问到主机

  • 问题解决:找到了网上的一篇博主的推文:【docker知识】从容器中如何访问到宿主机 里面提及了如何在容器内访问解释为主机的url
    将API ENDPOINT改为:host.docker.internal
    7.png

  • 结果:
    8.png

    更换为docker能转换的url就能访问成功。
4 完善post类

根据api规范进行构造:
9.png

理论上是从 Dify_class-> Records开始构建的,但是依赖类需要写在前面,不用担心,这些都是基本功,不难的,就是复杂了一点,理清楚逻辑之后慢慢写就好:
PS: 所有__repr__不要求写,我写着方便调试罢了
4.1 Dify_class 传入dify数据类
  1. class Dify_class:
  2.     def __init__(self,posted_data:dict):
  3.         """
  4.         dify有4个属性。
  5.         三个必填:知识库id、输入筛选器、检索设置(类)
  6.         一个选填:元数据信息(类)
  7.         :param posted_data: 收到的post,从json转换为字典形式
  8.         """
  9.         self.knowledge_id:str = posted_data.get('knowledge_id')
  10.         self.query:str = posted_data.get('query')
  11.         self.retrieval_setting = Retrieval_setting(
  12.             posted_data.get('retrieval_setting')
  13.         )
  14.         self.metadata_condition = Metadata_condition(
  15.             posted_data.get('metadata_condition')
  16.         )
  17.     def __repr__(self):
  18.         res = f"knowledge_id:{self.knowledge_id} \nquery:{self.query} \n"f"{self.retrieval_setting.__repr__()}"
  19.         if self.metadata_condition != None:
  20.             res.join(self.metadata_condition.__repr__())
  21.         return res
复制代码
4.1.1 dify_class 两个依赖类
  1. class Retrieval_setting:
  2.     def __init__(self, posted_data:dict):
  3.         self.top_k:int = posted_data.get('top_k')
  4.         self.score_threshold:float = posted_data.get('score_threshold')
  5.     def __repr__(self):
  6.         return f"\nretrieval_setting: \ntop_k:{self.top_k} \nscore_threshold:{self.score_threshold}"
  7. class Metadata_condition:
  8.     def __init__(self, posted_data:dict):
  9.         if posted_data == None:
  10.             self.logical_operator = None
  11.             self.conditions = None
  12.             self.status = -1 # 用于查看有多少参数,用于repr, -1则为空,2则为都有(未完善)
  13.         else:
  14.             self.conditions = posted_data.get('conditions')
  15.             logical_operator_:str = posted_data.get('logical_operator')
  16.             if logical_operator_ != None:
  17.                 self.logical_operator = logical_operator_
  18.                 self.status = 2
  19.             else:
  20.                 self.logical_operator = None
  21.                 self.status = 1
  22.     def __repr__(self):
  23.         if self.status == -1:
  24.             return "None"
  25.         else:
  26.             return f'logical_operator:{self.logical_operator}\nconditions:{self.conditions}'
复制代码
4.2 record类
  1. class Records:
  2.     def __init__(self,_content:str, _score:float, _title:str, _metadata:dict=None):
  3.         self.content = _content
  4.         self.score = _score
  5.         self.title = _title
  6.         self.metadata = Metadata(_metadata)
  7.     def to_dict(self):
  8.         """
  9.         将record类转换为字典
  10.         :return: 返回单个字典类型的records
  11.         """
  12.         res_dict =  dict(
  13.             {
  14.                 "metadata":{
  15.                     "path":self.metadata.path,
  16.                     "description":self.metadata.description
  17.                 },
  18.                 "score":self.score,
  19.                 "title":self.title,
  20.                 "content":self.content
  21.             }
  22.         )
  23.         return res_dict
  24.     def __repr__(self):
  25.         #没写metadata的
  26.         return f'*************\nscore:{self.score} \ncontent:{self.content} \ntitle:{self.title} \n*************\n'
复制代码
4.2.1 record 依赖类
  1. class Metadata:
  2.     def __init__(self, record_dict:dict=None):
  3.         if record_dict != None:
  4.             self.path = record_dict.get("path")
  5.             self.description = record_dict.get("description")
  6.         else:
  7.             self.path = None
  8.             self.description = None
复制代码
4.3 测试dify类

类main函数【用于测试】
test.json文件:
  1. {
  2.     "knowledge_id": "your-knowledge-id",
  3.     "query": "你的问题",
  4.     "retrieval_setting":{
  5.         "top_k": 2,
  6.         "score_threshold": 0.5
  7.     }
  8. }
复制代码
main:
  1. if __name__ == '__main__':
  2.     import json
  3.     with open('test.json', mode='r',encoding='utf8') as fp:
  4.         data = json.load(fp)
  5.         dify_t = Dify_class(data)
  6.         print(dify_t)
  7.     test_record = Records("test_content", 1.0, "dify_test")
  8.     print(test_record)
复制代码
5 接入服务器连接

5.1 导入相关包
  1. from flask import Flask , request, jsonify
  2. import dify_class ,json
  3. #dify_class是4中的文件名称
复制代码
5.2 设置服务器
  1. app = Flask(__name__)
  2. @app.route('/retrieval',methods=['POST'])
  3. def get_data():
  4.     data = request.get_json()       #获取请求的json数据
  5.     dify_t = dify_class.Dify_class(data)    #初始化dify请求类
  6.     print(dify_t)                           #调试输出
  7.     res = []
  8.     for i in range(dify_t.retrieval_setting.top_k): #模拟 topk
  9.         res.append(
  10.             dify_class.Records("test_content", 1.0, "dify_test").to_dict()  #测试回复类,构造一个请求类->返回他的字典形式->放入res列表中
  11.         )
  12.     res_dict = {
  13.         "records": res
  14.     }
  15.     json_res = json.dumps(res_dict)
  16.     return json_res, 200
复制代码
5.3 主函数
  1. #outside knowledge id_0001
  2. if __name__ == '__main__':
  3.     app.run(debug=True, host='127.0.0.1', port=5001)
  4.     get_data()
复制代码
5.4 测试

<ol>启动服务器
10.png

进行召回测试
11.png


终于是显示测试效果出来了。能够返回你测试的样例就说明成功了
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册