首页/新闻资讯/正文详情

用 LlamaIndex 搭建知识库问答应用实战

发布时间:2026/9/27 1:49:17 来源:云帆数科 栏目:资讯中心
用 LlamaIndex 搭建知识库问答应用实战
用 LlamaIndex 搭建知识库问答应用实战需求说明背景与目标资料分散在几十个文件里PDF、Word、Markdown 都有关键词搜索经常找不到想找的那段翻到之后还要人工核对出处。目标很明确“问一句答案和出处一起给”。功能概述PDF、Word、Markdown 等资料上传后进入本地知识库用自然语言提问回答基于知识库内容生成并附引用来源来源可展开查看命中的原文片段、匹配度PDF 还会标出页码。技术方案界面 Streamlit索引和检索 LlamaIndex模型通义千问DashScope向量库 Chroma 存在项目本地。下文按功能、配置、索引管线、问答编排和开发过程中遇到的问题展开代码和参数取自项目现状涉及运行输出的地方以实际输出为准。一、能做什么界面是三栏左侧导航和最近对话中间对话流右侧知识库概览和参数面板。左侧导航有四个视图对话、知识库、文件管理、模型设置。目前这些可用上传 PDF / DOCX / PPTX / XLSX / CSV / TXT / MD三条上传路径侧边栏上传文件弹窗、文件管理页批量上传、对话输入框的附件按钮附件随问题一起发先入库再回答所有提问都走知识库检索回答下方引用来源里能看到文件名、匹配度、页码或工作表名、片段预览深度思考开关开启后走模型原生思考回答上方可展开完整思考过程联网搜索开关Tavily网页结果与知识库片段一起进上下文来源里标联网模型切换底部输入区可切 qwen3.7-max / qwen-max / qwen-plus / qwen-turbo多会话新建、切换、按首次提问自动命名、重命名参数可调Top-K、相似度阈值、chunk_size / chunk_overlap切块参数重建索引后生效文件管理列表、下载、删除、手动重建索引一次提问的完整链路文件 │ SimpleDirectoryReader 解析 ▼ Document │ SentenceSplitter 切块 ▼ Node ──▶ text-embedding-v4 嵌入 ──▶ Chroma本地持久化 ▲ │ VectorIndexRetriever · Top-K │ 提问 ──▶ 命中片段 ──▶ 阈值过滤 ──▶ 拼上下文 ◀── Tavily 联网结果可选转 TextNode │ ▼ qwen3.7-max 生成 │ ▼ 回答 引用来源二、目录结构rag-knowledge-chat/ ├── streamlit_app.py # 入口页面配置、全局样式、视图分发 ├── requirements.txt ├── .env.example ├── .streamlit/ │ └── config.toml # 主题品牌蓝 #2563EB、大圆角 ├── app/ │ ├── config.py # 路径、模型名、批大小、支持格式 │ ├── models.py # AppSettings检索与回答设置 │ ├── state.py # 多会话状态st.session_state │ ├── services/ │ │ ├── document_service.py # 上传保存、文件清单、解析 │ │ ├── index_service.py # 模型配置 索引加载 / 重建 │ │ ├── chat_service.py # 检索 → 联网 → 生成 │ │ └── web_search.py # Tavily 联网搜索 │ ├── components/ │ │ ├── sidebar.py # 左侧导航 上传弹窗 最近对话 │ │ ├── chat_view.py # 对话主视图 底部输入区 │ │ ├── right_panel.py # 右侧知识库 / 模型面板 │ │ ├── manage_views.py # 知识库 / 文件管理 / 模型设置 │ │ └── common.py # 跨视图复用组件 │ └── utils/ │ └── formatting.py # 图标、字节、相对时间 ├── data/ │ └── uploads/ # 上传的原始文件 └── storage/ ├── chroma/ # 向量索引 └── meta/ # files.json 文件清单分层很直白入口只管分发services 干脏活components 管渲染互相不交叉。三、环境与模型配置3.1 依赖Python 用 3.12。依赖都在 requirements.txtstreamlit1.39.0 python-dotenv1.0.1 requests2.31.0 llama-index-core0.14.25 llama-index-llms-dashscope0.6.1 llama-index-embeddings-dashscope0.6.0 llama-index-vector-stores-chroma0.6.0 llama-index-readers-file0.5.0 chromadb1.0.0 pypdf5.0.0 python-docx1.1.2 python-pptx1.0.2 openpyxl3.1.5 pandas2.2.0llama-index-core 锁了 0.14.25。后面 pypdf、python-docx、python-pptx、openpyxl 这几个解析依赖加 pandas 读表格是给 SimpleDirectoryReader 按扩展名分派解析器用的少一个对应格式就报错。3.2 .env 配置项DASHSCOPE_API_KEY LLM_MODELqwen3.7-max EMBED_MODELtext-embedding-v4 APP_TITLEHomeRag APP_SUBTITLE你的个人知识库助手 # 可选联网搜索不配则开关置灰 TAVILY_API_KEY读取集中在 app/config.py全部走os.getenv带默认值ROOT_DIRPath(__file__).resolve().parents[1]load_dotenv(ROOT_DIR/.env,overrideFalse)APP_TITLEos.getenv(APP_TITLE,HomeRag)LLM_MODELos.getenv(LLM_MODEL,qwen3.7-max)EMBED_MODELos.getenv(EMBED_MODEL,text-embedding-v4)这种写法 .env 缺项也能跑起来。路径全部基于__file__定位从哪个目录启动都不影响数据目录的位置。3.3 两个必须显式传的模型参数第一个是 api_key。DashScope 的 LLM 类不会自动读DASHSCOPE_API_KEY环境变量不传就抛 pydantic 的 ValidationError报错里只有一个 api_key 为 None 的字段第一次遇到得反应一会儿才能定位到环境变量这层。处理方式就是显式取出来显式传def_require_api_key()-str:api_keyos.getenv(DASHSCOPE_API_KEY)ifnotapi_key:raiseRuntimeError(未找到 DASHSCOPE_API_KEY请在本目录 .env 中配置。)returnapi_key Settings.llmDashScope(model_nameLLM_MODEL,api_keyapi_key)第二个是 embedding 批大小。DashScopeEmbedding的默认embed_batch_size是 25这个数字对应 text-embedding-v1/v2 的限制换成 text-embedding-v4 后单次请求最多 10 条超出直接 400batch size should not be larger than 10。这个错误出现在 dashscope 的 logger.error 里堆栈上看不出原因我第一次碰上时排查了一阵。解法# text-embedding-v3/v4 单次请求最多 10 条文本必须显式调小EMBED_BATCH_SIZEint(os.getenv(EMBED_BATCH_SIZE,10))Settings.embed_modelDashScopeEmbedding(model_nameEMBED_MODEL,api_keyapi_key,embed_batch_sizeEMBED_BATCH_SIZE,)实测 12 条文本按 10 2 两批走完返回 1024 维向量以实际输出为准。这类第三方适配层的默认值换模型版本时要翻一眼源码里的常量别只盯着异常堆栈看。四、索引管线从文件到向量4.1 上传与文件清单三个上传入口都汇到同一个函数文件落到data/uploads/同时在storage/meta/files.json登记一条名称、路径、大小。校验扩展名不在支持列表里的直接跳过。defsave_uploaded_files(uploaded_files:Iterable)-list[Path]:saved[]manifest_load_manifest()foruploadedinuploaded_files:suffixPath(uploaded.name).suffix.lower()ifsuffixnotinSUPPORTED_EXTENSIONS:continuetargetUPLOAD_DIR/Path(uploaded.name).name target.write_bytes(uploaded.getbuffer())manifest[target.name]{path:str(target),size:target.stat().st_size,}saved.append(target)_save_manifest(manifest)returnsaved用清单而不是直接扫目录是为了让文件管理里的删除、列表、下载有统一的依据也方便后面做多知识库时按清单分桶。4.2 解析与切块解析用SimpleDirectoryReader把清单里的文件一次性读成 Document 列表解析器按扩展名自动分派defload_documents():files[Path(item[path])foriteminlist_files()]ifnotfiles:return[]returnSimpleDirectoryReader(input_files[str(path)forpathinfiles],).load_data()切块用SentenceSplitter默认chunk_size512、chunk_overlap50两个参数在界面高级切块参数里可调128–2048 / 0–300改完重建索引生效splitterSentenceSplitter(chunk_sizesettings.chunk_size,chunk_overlapsettings.chunk_overlap,)nodessplitter.get_nodes_from_documents(documents)4.3 写入 Chroma 与重建向量库使用chromadb.PersistentClient指向项目内的storage/chroma集合名叫rag_knowledge_chat。重建的逻辑是先把旧集合整个删掉再建新集合然后解析、切块、嵌入一路写进去clientget_client()try:client.delete_collection(COLLECTION_NAME)exceptException:passcollectionclient.get_or_create_collection(COLLECTION_NAME)vector_storeChromaVectorStore(chroma_collectioncollection)documentsload_documents()nodesSentenceSplitter(chunk_sizesettings.chunk_size,chunk_overlapsettings.chunk_overlap,).get_nodes_from_documents(documents)VectorStoreIndex(nodes,storage_contextStorageContext.from_defaults(vector_storevector_store),)完成后界面上会 toast 一条索引重建完成2 份文档 / 14 个片段这样的汇总数字以实际输出为准。另外每次重建会在storage/chroma/下多留一个 UUID 命名的段目录这是 Chroma 的内部机制不影响使用想清理就把应用停掉、删掉旧目录再重新建一次索引。4.4 加载索引提问时走的不是这条重建路径而是直接从已有向量库挂载vector_storeChromaVectorStore(chroma_collectionget_collection())returnVectorStoreIndex.from_vector_store(vector_storevector_store,)不重新解析、不重新嵌入所以提问是秒级响应。一个推论换 LLM 不影响索引随便切换 embedding 模型必须重建索引不然新旧向量不在一个语义空间里。界面上嵌入模型做成只读锁死 text-embedding-v4就是为了不给自己留这个坑。五、问答编排检索、思考与联网5.1 检索与相似度过滤检索按当前设置取 Top-K默认 3界面可调 1–10。取完之后做一步手动过滤retrieverindex.as_retriever(similarity_top_ksettings.top_k)nodesretriever.retrieve(question)# 该版本的 VectorIndexRetriever 不识别 similarity_cutoff手动过滤。cutoffsettings.similarity_cutoffifcutoffandcutoff0:nodes[nodefornodeinnodesifnode.scoreisNoneornode.scorecutoff]手动过滤的原因这个版本的VectorIndexRetriever静默忽略similarity_cutoff参数传了不报错也不生效。阈值默认 0.3是按我实测的分数分布定的命中片段大多在 0.5 上下0.3 能滤掉完全不相关的又不会把勉强相关的全砍掉以实际输出为准。5.2 提示词回答质量的大头在这一段。全文照抄项目的 QA_TEMPLATE你是一个严谨的知识库问答助手。 请只依据下面提供的【参考资料】回答问题资料可能来自本地知识库或联网搜索。 规则 1. 不要把模型自身记忆当成知识库事实不要虚构来源。 2. 如果资料不足以支持答案请明确回答 当前知识库中没有足够信息回答这个问题。 3. 如果可以回答先给出直接结论再分点补充关键细节保持清晰、简洁。 4. 回答中的关键信息都应能在参考资料中找到依据。 --------------------- 参考资料 {context_str} --------------------- 用户问题 {query_str} 回答两个点是有意为之规则 1 压住模型拿自己记忆凑答案的倾向规则 2 给一个固定话术资料不够时直接说没有而不是硬编。检索一个片段都没命中时代码里也是直接返回这句固定话术不调模型省一次请求。5.3 深度思考深度思考开关对应的是模型原生思考不开独立提示词。调用时透传 DashScope 的enable_thinking参数try:responsellm.complete(prompt,enable_thinkingsettings.deep_thinking)exceptExceptionasexc:# 当前模型不支持该参数时自动降级为默认调用。ifenable_thinkingnotinstr(exc):raiseresponsellm.complete(prompt)这里有个容易搞反的点qwen3.7-max 默认就是开启思考的不传参数它也会返回思考过程要真正关掉必须显式传enable_thinkingFalse开启时传参、关闭时不传的做法是无效的。实测同一个问题关掉 3.8 秒返回、开启 14 秒左右带完整思考以实际输出为准所以把它做成开关默认关。思考过程从原始响应里取def_extract_thinking(response)-str|None:messageresponse.raw[output][choices][0][message]returnmessage.get(reasoning_content)orNone拿到之后放在回答上方的深度思考过程折叠区里不占正文。界面步骤条也会跟着变开启时显示深度思考并生成回答关闭时就是生成回答。5.4 联网搜索联网走 Tavily一次取 4 条responserequests.post(TAVILY_ENDPOINT,json{api_key:api_key,query:query,max_results:4},timeout30,)搜索结果的标题、链接、摘要包装成TextNode和知识库片段共用同一套引用和提示词管道nodeTextNode(text[联网搜索结果] item.get(content,),metadata{file_name:item.get(title)or网页结果,url:item.get(url),source_type:web,},)文本前缀让模型能区分资料来源metadata 里的source_type让引用区渲染成联网徽标加可点链接而不是匹配度。网页结果没有向量分数NodeWithScore的 score 传 None。没配TAVILY_API_KEY时开关是置灰的不会误开。六、状态与存储存在哪、什么会丢6.1 数据都在哪data/uploads/ 上传的原始文件 storage/meta/files.json 文件清单名称、路径、大小 storage/chroma/chroma.sqlite3 向量索引chunk 文本 向量 元数据对话历史不进磁盘放在st.session_state里结构是一张会话表加一个活跃指针st.session_state.conversations{10 位会话 id:{title:...,messages:[...],created_at:...,updated_at:...,},}st.session_state.active_conversation_id会话 id会话标题在第一条用户消息进来时自动生成取前 18 个字符超长补省略号最近对话列表按updated_at倒序。6.2 重启后什么留下留下上传的文件、文件清单、向量索引。索引是PersistentClient写在项目内的跟进程的工作目录无关服务重启后新进程直接就能检索不用重建。我实测的方式是全新 Python 进程连上同一个目录查集合拿到的 chunk 数和界面上显示的一致检索问题能正常命中以实际输出为准。丢对话历史。刷新页面或者重启服务之前的会话就没了。当前版本就是这样接受这个设定聊天记录当临时产物用知识库本身是持久的。6.3 删掉文件后要重建索引删除源文件只动两处data/uploads/里的文件和files.json里的登记向量库不动。我实测过一次这个不一致从文件管理里把文件删完files.json已经清空直接查 Chroma 还能数出 14 个残留片段以实际输出为准。也就是说删掉的文件仍可能被检索到、出现在引用来源里。对齐的方式是删完去知识库页点一下重建索引。删除操作的 toast 里也带了这句提示但确实容易忽略记着这个行为就行。七、跑起来7.1 安装与配置cdllamaindex-rag/study/rag-knowledge-chat# 虚拟环境或 conda 环境都行Python 3.12pipinstall-rrequirements.txtcp.env.example .env# 编辑 .env至少填上 DASHSCOPE_API_KEY7.2 启动与使用streamlit run streamlit_app.py默认开在 8501 端口。使用流程左侧上传文件或文件管理页、对话附件默认上传后自动重建索引对话里提问空会话时也可以先点推荐问题展开回答下方的引用来源核对命中片段和匹配度需要深入分析开深度思考需要实时信息开联网搜索底部随时切模型右侧面板调 Top-K 和相似度阈值八、限制与下一步Reranker检索结果质量还能再上一档Metadata filter按文件、类型过滤检索范围多知识库现在所有文件进同一个 collectionOCRpypdf 走的是文本层扫描版 PDF 解析不出文字会话持久化把 conversations 结构写一份到storage/meta/conversations.json增量索引现在重建是全量文件多了之后解析和嵌入都要重来Agent / Tool Calling问答之外的动作型需求想读代码的话先看app/services/index_service.py和app/services/chat_service.py一个负责索引一个负责问答编排这两个文件读通剩下的都是界面。仓库地址https://github.com/zwzhangyu/ai-agent-lab项目目录llamaindex-rag/study/rag-knowledge-chat

相关推荐

linux ai agent 玩乐项目 agnte 编写
linux ai agent 玩乐项目 agnte 编写

系统定位 LinuxAI Desktop 是一个运行在 Linux 桌面机上的本地优先(local-first)自主 AI Agent。它在用户自有机器上同时具备:感知(读桌面 / 文件 / 系统 / 网络)决策(本地大模型 意图识别 规划&#xf… · 2026/9/27 1:49:10

NCBI数据库入门与实战:从序列检索到批量下载的完整指南
NCBI数据库入门与实战:从序列检索到批量下载的完整指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/27 1:49:04

YOLOv8+ByteTrack车辆检测与流量统计实战:从训练到部署
YOLOv8+ByteTrack车辆检测与流量统计实战:从训练到部署

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/27 1:49:04

[极客大挑战 2019]Havefun_CTF2
[极客大挑战 2019]Havefun_CTF2

靶场环境:一起来撸猫 页面展示 解题过程 步骤一: 右击查看源代码或Ctrl u 键,下翻发现在408---414行出现以下php代码。 步骤二: 分析代码,构造语句 ?catdog 步骤三: 回到原环境在url后面拼接语句 -… · 2026/9/27 2:34:33

识光CIOE亮相:SPAD-SoC三大产品线如何勾勒单光子感知的量产路径
识光CIOE亮相:SPAD-SoC三大产品线如何勾勒单光子感知的量产路径

在刚刚落幕的中国国际光电博览会(CIOE)上,苏州识光芯科技术有限公司(识光,Sophoton)携多款SPAD-SoC新品亮相。从单点、线阵到面阵,三条产品线并非孤立展示,而是呈现出一种清晰的技术逻辑:以全芯片化架构为底座,用不同形态的芯片去接住高度分化的产业需求。 统一技术… · 2026/9/27 2:34:03

3步搞定app开发人员网站被黑挂马怎么选安全方案
3步搞定app开发人员网站被黑挂马怎么选安全方案

3步搞定app开发人员网站被黑挂马怎么选安全方案 半夜三点,手机突然弹出短信:“您的网站www.yourapp.com存在恶意代码”。你慌了神,点开后台,发现首页被替换成了博彩广告,SEO收录瞬间归零。这种 网站被黑挂马不知道怎么办… · 2026/9/27 2:34:03

国企干部民主评议场景,衡识人才测评等360评估系统适配
国企干部民主评议场景,衡识人才测评等360评估系统适配

引文/摘要又到年终干部考核季。不少国企组织人事部门都在面对同一道题:民主评议怎么搞,才能既合规又高效,还能真正沉淀出有用的数据?传统纸票模式下,评议结果常常“评完就归档”,难以支撑干部选拔与梯队建设… · 2026/9/27 2:33:57

立创EDA安装全攻略:专业版与标准版选型及避坑指南
立创EDA安装全攻略:专业版与标准版选型及避坑指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/27 2:33:57

Vue 全局事件总线详解
Vue 全局事件总线详解

一、什么是事件总线 1.1 定义 事件总线(Event Bus)本质上就是一个居中转发消息的"邮局":发送方不直接找接收方,而是把消息丢给总线,总线再帮转给所有订阅了这个消息的人。 在 Vue 里,它用来解决任意两个组件之间通信的问题,不限于父子,不限于兄弟,只要挂在同一条总线… · 2026/9/27 2:33:57

MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现
MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现

简介:这套Matlab仿真工具完整呈现雷达信号脉冲压缩过程,从线性调频(LFM)信号生成、目标回波仿真到匹配滤波压缩处理均有可运行代码支撑,面向电子信息工程、计算机、数学等专业学生,适用于课程设计、期末大作… · 2026/9/27 0:00:01

汕头网站建设制作厂家避坑指南:5大注意事项救急
汕头网站建设制作厂家避坑指南:5大注意事项救急

汕头网站建设制作厂家避坑指南:5大注意事项救急 改个需求建站公司拖一周,这种憋屈事我见得太多了。 很多汕头老板找本地建站团队,签合同前看着方案挺美,一上线就变脸。 今天不聊虚的,直接拆解找 汕头网站建设制作厂家 时的5个核心 注意事项… · 2026/9/27 0:00:01

多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习
多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习

简介:基于PyTorch的多模态虚假新闻检测项目完整代码包,面向自然语言处理与计算机视觉交叉方向的开发者、科研人员及毕业设计选题者,解决社交媒体中文本与图像联合识别虚假新闻的问题。系统以BERT预训练模型提取文本语义特征,以Res… · 2026/9/27 0:00:01

MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现
MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现

简介:这套Matlab仿真工具完整呈现雷达信号脉冲压缩过程,从线性调频(LFM)信号生成、目标回波仿真到匹配滤波压缩处理均有可运行代码支撑,面向电子信息工程、计算机、数学等专业学生,适用于课程设计、期末大作… · 2026/9/27 0:00:01

汕头网站建设制作厂家避坑指南:5大注意事项救急
汕头网站建设制作厂家避坑指南:5大注意事项救急

汕头网站建设制作厂家避坑指南:5大注意事项救急 改个需求建站公司拖一周,这种憋屈事我见得太多了。 很多汕头老板找本地建站团队,签合同前看着方案挺美,一上线就变脸。 今天不聊虚的,直接拆解找 汕头网站建设制作厂家 时的5个核心 注意事项… · 2026/9/27 0:00:01

多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习
多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习

简介:基于PyTorch的多模态虚假新闻检测项目完整代码包,面向自然语言处理与计算机视觉交叉方向的开发者、科研人员及毕业设计选题者,解决社交媒体中文本与图像联合识别虚假新闻的问题。系统以BERT预训练模型提取文本语义特征,以Res… · 2026/9/27 0:00:01

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码