Django 搭建 AI 本地知识库:文档上传、向量检索与智能问答

发布时间:2026/8/3 3:05:17

Django 搭建 AI 本地知识库:文档上传、向量检索与智能问答 Django 搭建 AI 本地知识库文档上传、向量检索与智能问答把 PDF 上传到服务器再调用一次大模型并不等于拥有“本地知识库”。一个真正可用的 Django 知识库至少要解决六件事文件归属、文本切块、向量生成、相似度检索、权限过滤和答案引用。本文以 PostgreSQL、pgvector 和 Django ORM 为主线并把方案放进本地 RuyiDjangoCRM 的文档与多租户搜索边界中验证。最重要的结论是先确定用户能看哪些文档再在可见集合内做向量排序不能先搜全库再补权限。一条完整的知识库链路上传后的原始文件仍然要保留便于重新解析和审计真正用于检索的是切块后的文本。每个文本块至少记录原文档主键和组织主键页码或章节位置原始文本嵌入模型名称与版本固定维度的向量内容哈希避免重复入库。安装扩展pipinstallpgvector psycopg[binary]在 PostgreSQL 中启用向量类型CREATEEXTENSIONIFNOTEXISTSvector;用 Django 模型保存文本块和向量fromdjango.dbimportmodelsfrompgvector.djangoimportHnswIndex,VectorFieldclassKnowledgeChunk(models.Model):org_idmodels.UUIDField(db_indexTrue)documentmodels.ForeignKey(common.Document,on_deletemodels.CASCADE)positionmodels.PositiveIntegerField()contentmodels.TextField()content_hashmodels.CharField(max_length64,db_indexTrue)embedding_modelmodels.CharField(max_length80)embeddingVectorField(dimensions1536)classMeta:constraints[models.UniqueConstraint(fields[document,content_hash],nameuq_document_chunk_hash,)]indexes[HnswIndex(namechunk_embedding_hnsw,fields[embedding],m16,ef_construction64,opclasses[vector_cosine_ops],)]向量维度必须和嵌入模型一致。换模型时不要悄悄覆盖旧向量应记录模型版本并安排重建否则同一列里混入不同向量空间排序结果没有意义。切块不是越碎越好固定字符数切块适合做最小实验但生产系统应优先保留标题、段落、列表和代码块等结构。块太大召回内容噪声多块太小语义被截断还会增加向量数量和成本。defchunk_text(text:str,size:int800,overlap:int120):start0whilestartlen(text):yieldtext[start:startsize]startsize-overlap这个函数足以验证流程但面对 Markdown、PDF 表格和代码文档时应替换为结构化解析器并把页码或标题锚点一起保存。先做权限过滤再做向量排序RuyiDjangoCRM 的真实文档查询会同时检查组织、创建者、被分享用户和团队。向量检索必须复用同一套可见性条件fromdjango.db.modelsimportQfrompgvector.djangoimportCosineDistancedefsearch_chunks(profile,query_vector,limit5):visible_documentsDocument.objects.filter(orgprofile.org,statusactive,).filter(Q(created_byprofile.user)|Q(shared_toprofile)|Q(teams__inprofile.teams.all()))return(KnowledgeChunk.objects.filter(org_idprofile.org_id,document__invisible_documents).annotate(distanceCosineDistance(embedding,query_vector)).order_by(distance)[:limit])如果先从全库取前 20 个相似块再在 Python 中删除无权访问的结果既可能泄露标题、分数和片段也可能导致合法结果被越权结果挤出前 20 名。权限条件必须进入数据库查询本身。管理员分支也要显式处理。不要为了“方便”把所有知识库查询统一成管理员视角更不能依赖前端隐藏结果。让回答带上可核验引用检索结果不要只拼正文还要给每一块分配稳定引用编号context\n\n.join(f[{i}]{chunk.document.title}/ 片段{chunk.position}\n{chunk.content}fori,chunkinenumerate(chunks,start1))promptf 只依据下面资料回答。每个关键结论使用 [1] 这样的编号引用 资料不足时明确说不知道不要补写不存在的事实。{context}引用不是装饰。服务端还应保存本次回答命中的块主键、距离和文档版本以便用户点击原文也便于后续复盘错误召回。本地验证暴露出的两个误区我用一个可重复的关键词向量实验验证了上传后切成 3 块、余弦排序、返回引用片段的完整链路相关 11 项单元测试全部通过。这个实验故意不冒充真实语义模型关键词向量只能证明检索管线正确不能证明语义质量。第二个误区是只测“能搜到”。RuyiDjangoCRM 的搜索测试还验证了跨组织隔离、普通用户只能看到自己创建或被分配的对象以及组织内知识条目的可见规则。AI 知识库接入后这些测试应继续存在并增加“越权向量即使更相似也不能返回”的回归用例。结论一个可靠的本地知识库不是模型回答得像不像人而是每条材料从哪里来、谁有权看到、命中了哪一段、换模型后如何重建都能被解释和复现。参考资料pgvector 官方项目pgvector-python 的 Django 用法

相关新闻