知识库是open webui的一个重要组件,您可以在其中存储系统在交互过程中可以参考的结构化信息,从而使响应更加个性化,有更强的场景感知能力。以下几种情况下考虑使用知识库:

  1. 经常需要引用的重要项目信息或特定数据
  2. 需要使用的自定义命令、工作流或配置
  3. 每次聊天中都需要遵循相同的偏好、指南或规则
  4. 在多个成员之间共享知识

        本文先创建一个简单的知识库,再分析知识库的创建过程代码,然后说明如何使用知识库,接下来对于直接应用知识库代码进行分析,再接下来对于创建自带知识库大模型源码进行分析,最后对于在对话中使用自带知识库大模型的代码进行分析。

一、创建知识库

        创建知识库本身非常简单,进入【工作空间】并选择【知识库】,进入知识库页面。

        点击[+]进入增加知识库页面,然后填写主题、目标并设置可见性:

        点击【创建知识】,完成知识库创建,进入知识库列表页面

        用户点击【+】,可添加知识:

        我们上传一个文件,完成知识库的知识添加:

        二、数据模型

        知识库相关表包括knowledge和file表,knowledge存储知识库基本信息,file表存储知识库的文件,二者为1:n的关系,file结构在系列1已讲解,在此不再赘述,knowledge结构如下:

        其中:

   id:知识库唯一标识

   user_id:创建知识库的用户唯一标识

   name:知识库名称,创建时用户输入

   description:知识库描述,创建时用户输入

   data:知识库引用的文件

   meta:知识库元数据

   created_at:知识库创建时间

   updated_at:知识库更新时间

   access_control:知识库访问权限

        三、创建过程分析

        知识库创建过程主要包括三个步骤,先创建库并保存基本信息,然后是上传知识库文件,最后是把知识库与文件关联。

        1)创建知识库

        创建知识库请求数据如下:

{
    "name": "北京市2024年政府工作报告",
    "description": "为各部门编写明年工作计划提供参考",
    "access_control": null
}

       对应入口函数为create_new_knowledge,该方法很简单,调用Knowledges.insert_new_knowledge把知识库记录插入到knowledge表中,并返回知识库信息到前端,具体如下:

@router.post("/create", response_model=Optional[KnowledgeResponse])
async def create_new_knowledge(
    request: Request, form_data: KnowledgeForm, user=Depends(get_verified_user)
):
    if user.role != "admin" and not has_permission(
        user.id, "workspace.knowledge", request.app.state.config.USER_PERMISSIONS
    ):
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail=ERROR_MESSAGES.UNAUTHORIZED,
        )

    knowledge = Knowledges.insert_new_knowledge(user.id, form_data)

    if knowledge:
        return knowledge
    else:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=ERROR_MESSAGES.FILE_EXISTS,
        )

        insert_new_knowledge方法的代码也是简单易懂,直接贴在这里,不做分析:

    def insert_new_knowledge(
        self, user_id: str, form_data: KnowledgeForm
    ) -> Optional[KnowledgeModel]:
        with get_db() as db:
            knowledge = KnowledgeModel(
                **{
                    **form_data.model_dump(),
                    "id": str(uuid.uuid4()),
                    "user_id": user_id,
                    "created_at": int(time.time()),
                    "updated_at": int(time.time()),
                }
            )

            try:
                result = Knowledge(**knowledge.model_dump())
                db.add(result)
                db.commit()
                db.refresh(result)
                if result:
                    return KnowledgeModel.model_validate(result)
                else:
                    return None
            except Exception:
                return None

       返回到前端数据如下:

{
    "id": "4c8c248b-0f31-4193-a571-225aa28398a5",
    "user_id": "e6d4a214-8982-40ad-9bbc-77ee14534d58",
    "name": "北京市2024年政府工作报告",
    "description": "为各部门编写明年工作计划提供参考",
    "data": null,
    "meta": null,
    "access_control": null,
    "created_at": 1756195064,
    "updated_at": 1756195064,
    "files": null
}

        2)上传文件

        上传文件具体分析见系列1

        3)关联文件

        关联文件请求数据如下:

{"file_id":"56d30a2a-2566-44b6-8105-362b1834fd88"} #刚刚上传文件唯一标识

        关联文件入口函数为add_file_to_knowledge_by_id,具体代码如下。

@router.post("/{id}/file/add", response_model=Optional[KnowledgeFilesResponse])
def add_file_to_knowledge_by_id(
    request: Request,
    id: str, #路径参数,知识库唯一标识
    form_data: KnowledgeFileIdForm,
    user=Depends(get_verified_user),
):

    #根据知识库唯一标识从knowledge查询
    knowledge = Knowledges.get_knowledge_by_id(id=id)

    if not knowledge:#不存在则报400错误
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=ERROR_MESSAGES.NOT_FOUND,
        )

    if ( #权限检查,如果没有权限则报400错误
        knowledge.user_id != user.id
        and not has_access(user.id, "write", knowledge.access_control)
        and user.role != "admin"
    ):
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=ERROR_MESSAGES.ACCESS_PROHIBITED,
        )

    #根据文件唯一标识查file表

    file = Files.get_file_by_id(form_data.file_id)
    if not file:#如果文件不存在,则返回400错误
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=ERROR_MESSAGES.NOT_FOUND,
        )
    if not file.data:#如果文件内容为空,则返回400错误
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=ERROR_MESSAGES.FILE_NOT_PROCESSED,
        )

    # 把内容插入到向量库
    try:
        process_file(
            request,

            #collection_name=id保证一个知识库所有文件插入到一个集合中
            ProcessFileForm(file_id=form_data.file_id, collection_name=id),
            user=user,
        )
    except Exception as e:
        log.debug(e)
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=str(e),
        )

    #下面的检查没意义,因为前面的代码已经检查,如果knowledge为空,则返回错误

    if knowledge:
        data = knowledge.data or {} 
        file_ids = data.get("file_ids", []) #从knowledge的data字段获取file_ids 

        if form_data.file_id not in file_ids: #保证表单中携带的file_id在file_ids中
            file_ids.append(form_data.file_id) # 把文件fild_id增加到file_ids中

            #更新knowledge的data字段
            data["file_ids"] = file_ids

            knowledge = Knowledges.update_knowledge_data_by_id(id=id, data=data)

            if knowledge:
                files = Files.get_file_metadatas_by_ids(file_ids)

                return KnowledgeFilesResponse(#返回知识库完整信息
                    **knowledge.model_dump(),
                    files=files,
                )
            else:
                raise HTTPException(
                    status_code=status.HTTP_400_BAD_REQUEST,
                    detail=ERROR_MESSAGES.DEFAULT("knowledge"),
                )
        else:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST,
                detail=ERROR_MESSAGES.DEFAULT("file_id"),
            )
    else:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail=ERROR_MESSAGES.NOT_FOUND,
        )

        完成文件与知识库关联后返回前端数据如下:

{
    "id": "4c8c248b-0f31-4193-a571-225aa28398a5",
    "user_id": "e6d4a214-8982-40ad-9bbc-77ee14534d58",
    "name": "北京市2024年政府工作报告",
    "description": "为各部门编写明年工作计划提供参考",
    "data": {
        "file_ids": [
            "56d30a2a-2566-44b6-8105-362b1834fd88",

            ……
        ]
    },
    "meta": null,
    "access_control": null,
    "created_at": 1756195064,
    "updated_at": 1756195256,
    "files": [
        {
            "id": "56d30a2a-2566-44b6-8105-362b1834fd88",
            "meta": {
                "name": "beijing_annual_report_2024.pdf",
                "content_type": "application/pdf",
                "size": 329811,
                "data": {},
                "collection_name": "4c8c248b-0f31-4193-a571-225aa28398a5"
            },
            "created_at": 1756195250,
            "updated_at": 1756195250
        }
    ]
}

        四、使用知识库

       使用知识库有两种方式,一种是在对话时直接引用,一种是对基础大模型挂接创建好的知识库,相当于创建自带知识库的大模型。

        1)直接引用

        直接引用知识库非常简单,在聊天窗口输出‘#’便弹出知识库及文件列表,用户可以选择知识库获直接选择知识库中的文件,具体见下图:

        2)基础大模型挂接知识库

        进入【工作空间】并选择【模型】进入模型管理页面:

       用户点击【+】进入新增模型页面,在该页面可以填写模型名称、选择基础模型、填写描述和设置可见性,还可以调整模型参数:

        用户点击【选择】知识,显示可挂接知识库列表

         用户可以选择一个知识库完成挂载。当然,用户也可以通过【上传文件】直接为模型挂载外部知识。

          挂载了知识库的大模型成为一个新的模型,用户可以在对话式跟选择其他大模型一样自由选择。

        五、直接引用知识库分析

        1)获取知识库列表

        用户输入‘#’后,前端会调用后端接口获取知识库列表。对应入口为:

        http://{ip:port}/api/v1/knowledge/

该方法逻辑很简单。就是访问knowledge表并返回知识库列表,所以不予分析

@router.get("/", response_model=list[KnowledgeUserResponse])
async def get_knowledge(user=Depends(get_verified_user)):

        ……

        应答消息如下:

[
    {

        #以下是知识库基本信息
        "id": "4c8c248b-0f31-4193-a571-225aa28398a5",
        "user_id": "e6d4a214-8982-40ad-9bbc-77ee14534d58",
        "name": "北京市2024年政府工作报告",
        "description": "为各部门编写明年工作计划提供参考",
        "data": {
            "file_ids": [
                "56d30a2a-2566-44b6-8105-362b1834fd88"
            ]
        },
        "meta": null,
        "access_control": null,
        "created_at": 1756195064,
        "updated_at": 1756195256,

        #以下是知识库归属用户信息
        "user": {
            "id": "e6d4a214-8982-40ad-9bbc-77ee14534d58",
            "name": "acaluis",
            "email": "acaluis@sina.com",
            "role": "admin",
            "profile_image_url": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pVUAAAAAXNSR0IArs4c6QAABItJREFUeF7tnF2IVHUYxp9zzpyZ2Q9ZtdZscfdmEzOtZfEDtmhtIxXRQEQIuxFUikRFKOou0RtRgrqIBNmCQLab6IM1yjVaK8QLBVGkUlwFFSoldHXdna+dE3OOLnvOfszsTLXPP565G+Z/Zp7z/M5z3vO+/2Wte52zPehF44AlIDQsfCECwsVDQMh4CIiAsDlApkc1REDIHCCTo4QICJkDZHKUEAEhc4BMjhIiIGQOkMlRQgSEzAEyOUqIgJA5QCZHCREQMgfI5CghAkLmAJkcJURAyBwgk6OECAiZA2RylBABIXOATI4SIiBkDpDJUUIEhMwBMjlGJyS58ghiTWtGLPWy95E5vRfZXz8ms7l0OcYCceYsRbKjE1ZtY+hsc9d7kOrZVLoDZCuNBRJf9i7ii7cDthuy1Bu6hdRPOzB843syq0uTYyyQqrVH4cxt88/SG7oJK14HOAnAyyN78VOkT75VmgNkq4wEEmveiETbAViJmb6duWvfwXm0BVb14/77/O3fMNS9Gl52gMzu4nKMBJJ47j24CzYDlg0Mp5E59z6cuc/CaWgPEmNwcTcOiF3XjOTKLth1TwTmD/6O1I9vwKlfgnjr28Ftq5AaQ4u7cUDcp7YhvmwPrFi1b/zwH6cw9M06RJ+6TC3uxgFJrvoMscZVwc04n0XmwkfInN7nvw31JYYWd6OAOA3PI7ni0Ejx9gauI9W7DcM3z/hA3IVbg/S4NQGv/stIHX8V+f6+4tWUZIVRQKK9R7ROROuLX/DPHkTm3AckdheXYRSQ6vW9sB95JijmucFgTPJLZ+gsQ09gBhZ3Y4BEe4+JbkfRdaYVd2OAJF84jFjzhsJ/AynkA9lLXUj/vGvce0DVum/hPLY8+Myw4m4EkDG9R/oO0qfeQa7v83GBRGuNScXdCCDxlt2hpi//13kMftUxYYUcMwk2qLgbAWSy3mMiKqFjRjWQxZ9zpncFPRBn3ktItn8Iq6q+Iqe89G2kT76J3NWvK/qef/tgeiCJ5fvgLnodsGOVeWFIcacGYrm1qFrbPdJ7VEbEjM6dGog7fxPibfthuTOCJ9jBP/1Ru5fpL4mNXdMA9+mdI/smJnTu1EDCvUd5I/XR3X2B4sPpcElEp2ERLRC7vhXJFz+BXdsU2FLmo2u0J/GK9DDTwCD0k7RAxvQeA9eQ+mEL8rfOTsmz6IS40OXn+r5A6sRrU/qe/2oxLZDRf8RQMCN35Ut/1F7OK9qT5O9eRarnFcqxPCWQaO9R6R55dJex3NtfORfDVI+hBBIdoVc6ixqzT0Jc3OmA+L3Hy8dgz3rywcU1+WS31CswCpm1uNMBiW7D/lPGRfdJWIs7HZBSr/j/6zoBISMrIAJC5gCZHCVEQMgcIJOjhAgImQNkcpQQASFzgEyOEiIgZA6QyVFCBITMATI5SoiAkDlAJkcJERAyB8jkKCECQuYAmRwlREDIHCCTo4QICJkDZHKUEAEhc4BMjhIiIGQOkMlRQgSEzAEyOUqIgJA5QCZHCREQMgfI5CghAkLmAJkcJURAyBwgk6OEkAH5G7gElAPcU3ncAAAAAElFTkSuQmCC"
        },

        #以下是知识库文件信息
        "files": [
            {
                "id": "56d30a2a-2566-44b6-8105-362b1834fd88",
                "meta": {
                    "name": "beijing_annual_report_2024.pdf",
                    "content_type": "application/pdf",
                    "size": 329811,
                    "data": {},
                    "collection_name": "4c8c248b-0f31-4193-a571-225aa28398a5"
                },
                "created_at": 1756195250,
                "updated_at": 1756195250
            }
        ]
    }
]

        2)发起补足请求

        发起补足请求时,数据如下:

 {
    "stream": true,
    "model": "qwen3:1.7b",
    "messages": [
        {
            "role": "user",
            "content": "请简单总结一下北京是2023年政府工作报告内容"
        },
        {
            "role": "assistant",
            "content": "\n2023年北京政府工作报告指出,全年地区生产总值增长5.2%(约4.4万亿元),一般公共预算收入增长8.2%(突破6000亿元),城镇调查失业率4.4%。报告强调全面贯彻落实党的二十大精神,统筹推进京津冀协同发展、国际交往中心建设、法治政府建设等重点工作,提出要深化“五子”联动、提升城市功能,推动高质量发展。同时,注重稳中求进、改革创新,强化风险防范,确保经济和社会稳定。 [1]"
        },
        {
            "role": "user",
            "content": "有哪些保护历史文化名城的举措?"
        }
    ],
    "params": {},
    "files": [
        {
            "id": "56d30a2a-2566-44b6-8105-362b1834fd88",
            "meta": {
                "name": "beijing_annual_report_2024.pdf",
                "content_type": "application/pdf",
                "size": 329811,
                "data": {},
                "collection_name": "4c8c248b-0f31-4193-a571-225aa28398a5"
            },
            "created_at": 1756195250,
            "updated_at": 1756195250,
            "collection": {
                "name": "北京市2024年政府工作报告",
                "description": "为各部门编写明年工作计划提供参考"
            },
            "name": "beijing_annual_report_2024.pdf",
            "description": "北京市2024年政府工作报告 - 为各部门编写明年工作计划提供参考",
            "knowledge": true,
            "type": "file",
            "status": "processed"
        }
    ],
    "tool_servers": [],
    "features": {
        "image_generation": false,
        "code_interpreter": false,
        "web_search": false,
        "memory": false
    },
    "variables": {
        "{{USER_NAME}}": "acaluis",
        "{{USER_LOCATION}}": "Unknown",
        "{{CURRENT_DATETIME}}": "2025-08-26 21:53:22",
        "{{CURRENT_DATE}}": "2025-08-26",
        "{{CURRENT_TIME}}": "21:53:22",
        "{{CURRENT_WEEKDAY}}": "Tuesday",
        "{{CURRENT_TIMEZONE}}": "Etc/GMT-8",
        "{{USER_LANGUAGE}}": "zh-CN"
    },
    "model_item": {
        "id": "qwen3:1.7b",
        "name": "qwen3:1.7b",
        "object": "model",
        "created": 1756216316,
        "owned_by": "ollama",
        "ollama": {
            "name": "qwen3:1.7b",
            "model": "qwen3:1.7b",
            "modified_at": "2025-08-20T03:50:50.085066919Z",
            "size": 1359293444,
            "digest": "8f68893c685c3ddff2aa3fffce2aa60a30bb2da65ca488b61fff134a4d1730e7",
            "details": {
                "parent_model": "",
                "format": "gguf",
                "family": "qwen3",
                "families": [
                    "qwen3"
                ],
                "parameter_size": "2.0B",
                "quantization_level": "Q4_K_M"
            },
            "connection_type": "local",
            "urls": [
                0
            ],
            "expires_at": 1756216600
        },
        "connection_type": "local",
        "tags": [],
        "actions": [],
        "filters": []
    },
    "session_id": "BOfZ2Yucswcg5PgRAAAJ",
    "chat_id": "1a56ce9b-f31c-4fe2-8ffa-a6f5e9ff2f69",
    "id": "134db67e-11c3-48f1-a072-2130a31c7e6c",
    "background_tasks": {
        "follow_up_generation": true
    }
}

        此时处理逻辑完全与系列4-初级RAG相同,可参见open webui源码分析4-初级RAG-CSDN博客,此处不再赘述。

    六、创建自带知识库的大模型

       1)数据模型

       自带知识库大模型涉及的表为model表,model表结构如下:

     id:大模型唯一标识

     user_id:大模型创建者唯一标识

     base_model_id:基础大模型唯一标识

     name:大模型名称

     meta:大模型元数据

    params:大模型参数

    created_at:大模型创建时间

    updated_at:大模型信息修改时间

    access_control:权限

    is_active:是否激活

     2)创建过程分析

     创建自带知识库大模型请求参数如下: 

{
  "id": "openwebui", #自带知识库大模型唯一标识
  "base_model_id": "deepseek-r1:1.5b", #基础模型
  "name": "政府工作报告", #大模型名称
  "meta": {
    "profile_image_url": "/static/favicon.png",
    "description": "挂接2023年北京市政府工作报告",
    "suggestion_prompts": null,
    "tags": [],
    "capabilities": { #大模型的各项能力
      "vision": false, #视觉
      "file_upload": false,#wenjian shangchuan 
      "web_search": false, #web搜索
      "image_generation": false, #生成图片
      "code_interpreter": false, #代码解释
      "citations": false #支持应用
    },
    "knowledge": [#知识库信息
      {
        "id": "161dd6ea-2e14-4b60-b8a2-48993ec9e4f2",
        "user_id": "e6d4a214-8982-40ad-9bbc-77ee14534d58",
        "name": "政府工作报告",
        "description": "共享政府工作报告内容",
        "data": {
          "file_ids": [
            "ca856fca-3eef-44d7-882d-24b312a72c48"
          ]
        },
        "meta": null,
        "access_control": null,
        "created_at": 1756275107,
        "updated_at": 1756275184,
        "user": {
          "id": "e6d4a214-8982-40ad-9bbc-77ee14534d58",
          "name": "acaluis",
          "email": "acaluis@sina.com",
          "role": "admin",
          "profile_image_url": "data:image/png;base64,CC"
        },
        "files": [
          {
            "id": "ca856fca-3eef-44d7-882d-24b312a72c48",
            "meta": {
              "name": "microsoft_annual_report_2022.pdf",
              "content_type": "application/pdf",
              "size": 1285495,
              "data": {},
              "collection_name": "161dd6ea-2e14-4b60-b8a2-48993ec9e4f2"
            },
            "created_at": 1756275120,
            "updated_at": 1756275120
          }
        ],
        "type": "collection" #这里的type设置很重要,后面会用到
      }
    ]
  },
  "params": {},
  "access_control": null
}

       创建自带知识库大模型入口为http://{ip:port}/api/v1/models/create,对应方法为create_new_model,该方法非常简单。

@router.post("/create", response_model=Optional[ModelModel])
async def create_new_model(
    request: Request,
    form_data: ModelForm,
    user=Depends(get_verified_user),
):

    # 权限检查,保证不会非法创建
    if user.role != "admin" and not has_permission(
        user.id, "workspace.models", request.app.state.config.USER_PERMISSIONS
    ):
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail=ERROR_MESSAGES.UNAUTHORIZED,
        )

    model = Models.get_model_by_id(form_data.id)
    if model:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail=ERROR_MESSAGES.MODEL_ID_TAKEN,
        )

    else:
        model = Models.insert_new_model(form_data, user.id)#大模型插入到model表中
        if model:
            return model
        else:
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail=ERROR_MESSAGES.DEFAULT(),
            )

    七、访问自带知识库大模型分析 

        补足请求报文如下:

{
  "stream": true,
  "model": "open-webui",
  "messages": [
    {
      "role": "user",
      "content": "如何给大模型挂载知识库"
    }
  ],
  "params": {},
  "tool_servers": [],
  "features": {
    "image_generation": false,
    "code_interpreter": false,
    "web_search": false,
    "memory": false
  },
  "variables": {
    "{{USER_NAME}}": "acaluis",
    "{{USER_LOCATION}}": "Unknown",
    "{{CURRENT_DATETIME}}": "2025-08-27 09:52:59",
    "{{CURRENT_DATE}}": "2025-08-27",
    "{{CURRENT_TIME}}": "09:52:59",
    "{{CURRENT_WEEKDAY}}": "Wednesday",
    "{{CURRENT_TIMEZONE}}": "Etc/GMT-8",
    "{{USER_LANGUAGE}}": "zh-CN"
  },
  "model_item": {
    "id": "open-webui",
    "name": "open webui",
    "object": "model",
    "created": 1756258460,
    "owned_by": "ollama",
    "info": {
      "id": "open-webui",
      "user_id": "e6d4a214-8982-40ad-9bbc-77ee14534d58",
      "base_model_id": "qwen3:1.7b",
      "name": "open webui",
      "params": {},
      "meta": {
        "profile_image_url": "/static/favicon.png",
        "description": "open webui相关知识",
        "capabilities": {
          "vision": true,
          "file_upload": true,
          "web_search": true,
          "image_generation": true,
          "code_interpreter": true,
          "citations": true
        },
        "suggestion_prompts": null,
        "tags": [],
        "knowledge": [
          {
            "id": "31e80ee3-fac1-4641-85f8-b18befdeccf7",
            "user_id": "e6d4a214-8982-40ad-9bbc-77ee14534d58",
            "name": "open webui",
            "description": "提供openwebui所有技术文档",
            "data": {
              "file_ids": [
                "fb73f36c-8d7a-47c3-97e7-773f86e0e671",
                "...",
                "60d87f8b-ba0c-48af-861f-d9a648e947ac"
              ]
            },
            "meta": null,
            "access_control": null,
            "created_at": 1756257946,
            "updated_at": 1756258216,
            "user": {
              "id": "e6d4a214-8982-40ad-9bbc-77ee14534d58",
              "name": "acaluis",
              "email": "acaluis@sina.com",
              "role": "admin",
              "profile_image_url": "data:image/png;base64,iVBO……CC"
            },
            "files": [#所有文件向量化到一个集合中,并且集合名与知识库id相同
              {
                "id": "60d87f8b-ba0c-48af-861f-d9a648e947ac",
                "meta": {
                  "name": "yacy.md",
                  "content_type": "application/octet-stream",
                  "size": 1342,
                  "data": {},
                  "collection_name": "31e80ee3-fac1-4641-85f8-b18befdeccf7"
                },
                "created_at": 1756258215,
                "updated_at": 1756258215
              },
              "..."
            ]
          }
        ]
      },
      "access_control": null,
      "is_active": true,
      "updated_at": 1756258460,
      "created_at": 1756258460
    },
    "preset": true,
    "actions": [],
    "filters": [],
    "tags": []
  },
  "session_id": "UcI0SMW8hwAaKZPyAAAF",
  "chat_id": "d6aef4da-3cba-439c-aaad-341844bf4bca",
  "id": "08f6a2a1-da85-490a-9f83-728fcee1a104",
  "background_tasks": {
    "title_generation": true,
    "tags_generation": true,
    "follow_up_generation": true
  }
}

        与自带知识库大模型对话时,知识库相关部分处理集中在process_chat_payload方法中,具体如下。

相关大模型自带知识库处理流程如下:

1)从模型中获取其自带知识库信息

2)开始向量库查询前发送通知到前端

3)把知识库数据追加到表单的 files中

4)调用chat_completion_files_handler执行RAG相关处理

5)把向量库查询完成状态通知前端

async def process_chat_payload(request, form_data, user, metadata, model):

    ……

    #直接获取大模型自带知识库信息

    model_knowledge = model.get("info", {}).get("meta", {}).get("knowledge", False)

    if model_knowledge:
        await event_emitter(#通过websocket把当前状态(搜索知识库)发送到前端
            {
                "type": "status",
                "data": {
                    "action": "knowledge_search",
                    "query": user_message,
                    "done": False,
                },
            }
        )

        knowledge_files = []
        for item in model_knowledge:#遍历自带知识库,追加到 knowledge_files数组中
            if item.get("collection_name"):#如果知识库是集合
                knowledge_files.append(
                    {
                        "id": item.get("collection_name"),
                        "name": item.get("name"),
                        "legacy": True,
                    }
                )
            elif item.get("collection_names"):#如果知识库是多个集合
                knowledge_files.append(
                    {
                        "name": item.get("name"),
                        "type": "collection",
                        "collection_names": item.get("collection_names"),
                        "legacy": True,
                    }
                )
            else: #刚刚创建挂接知识库大模型走这个分支
                knowledge_files.append(item)

        files = form_data.get("files", [])
        files.extend(knowledge_files) #把知识库数据追加到表单files中
        form_data["files"] = files #更新表单files内容

    ……


    try:

        #调用chat_completion_files_handler执行RAG相关处理
        form_data, flags = await chat_completion_files_handler(request, form_data, user)
        sources.extend(flags.get("sources", []))
    except Exception as e:
        log.exception(e)

    ……

    if model_knowledge: #最后发送知识库查询完成消息通过websocket推送到前端
        await event_emitter(
            {
                "type": "status",
                "data": {
                    "action": "knowledge_search",
                    "query": user_message,
                    "done": True,
                    "hidden": True,
                },
            }
        )

        与大模型自带知识库相关的代码在chat_completion_files_handler中,该方法在RAG中已经做分析,此处不再重复贴代码。现在需要对其中的get_sources_from_items方法进行重点分析。针对当前的带知识库大模型,item.type='collection',所以重点分析该分支的代码。

本方法根据传入的数据找到所有的collection,然后调用向量库查询。

有一点需要注意******:大模型自带知识库情况下,知识库所有文件均存储在向量库的同一个集合中,这个集合的唯一标识与知识库唯一标识相同******。

def get_sources_from_items(
    request,
    items,
    queries,
    embedding_function,
    k,
    reranking_function,
    k_reranker,
    r,
    hybrid_bm25_weight,
    hybrid_search,
    full_context=False,
    user: Optional[UserModel] = None,
):
    log.debug(
        f"items: {items} {queries} {embedding_function} {reranking_function} {full_context}"
    )

    extracted_collections = []
    query_results = []

    for item in items:
        query_result = None
        collection_names = []

        if item.get("type") == "text":

            ……

        elif item.get("type") == "note":

            ……

        elif item.get("type") == "file":
            ……

        elif item.get("type") == "collection":#重点代码在这里
            if (
                item.get("context") == "full"
                or request.app.state.config.BYPASS_EMBEDDING_AND_RETRIEVAL
            ):#该分支不需要考虑
                ……
            else:
                if item.get("legacy"):#该分支不需要考虑
                    collection_names = item.get("collection_names", [])
                else:#把知识库id,同时也是向量库集合id,追加到collection_names列表中
                    collection_names.append(item["id"])

        elif item.get("docs"):
                ……
        elif item.get("collection_name"):
                ……
        elif item.get("collection_names"):
                ……

        if query_result is None and collection_names: #查询向量库多个集合
            collection_names = set(collection_names).difference(extracted_collections)
            if not collection_names:
                log.debug(f"skipping {item} as it has already been extracted")
                continue

            try:
                if full_context: #缺省不走本分支
                    query_result = get_all_items_from_collections(collection_names)
                else:
                    query_result = None  # Initialize to None
                    if hybrid_search:#缺省不走本分支
                        try:
                            query_result = query_collection_with_hybrid_search(
                                collection_names=collection_names,
                                queries=queries,
                                embedding_function=embedding_function,
                                k=k,
                                reranking_function=reranking_function,
                                k_reranker=k_reranker,
                                r=r,
                                hybrid_bm25_weight=hybrid_bm25_weight,
                            )
                        except Exception as e:
                            log.debug(
                                "Error when using hybrid search, using non hybrid search as fallback."
                            )

                    #重点在这里。查询知识库所有文件所在的向量库集合
                    if not hybrid_search and query_result is None:
                        query_result = query_collection(
                            collection_names=collection_names,
                            queries=queries,
                            embedding_function=embedding_function,
                            k=k,
                        )
            except Exception as e:
                log.exception(e)

            extracted_collections.extend(collection_names)

        if query_result: 
            if "data" in item: #如果知识库中有data项,则删除
                del item["data"]

            #删除了data的知识库到query_result并追加到query_results列表中
            query_results.append({**query_result, "file": item})

    sources = []
    for query_result in query_results:#根据所有查询组织返回数据
        try:
            if "documents" in query_result:
                if "metadatas" in query_result:
                    source = {#用查询结果设置source,document,metadata和distance
                        "source": query_result["file"],
                        "document": query_result["documents"][0],
                        "metadata": query_result["metadatas"][0],
                    }
                    if "distances" in query_result and query_result["distances"]:
                        source["distances"] = query_result["distances"][0]

                    sources.append(source)
        except Exception as e:
            log.exception(e)

    return sources
 

Logo

一站式 AI 云服务平台

更多推荐