FastAPI端点与独立脚本运行ChromaDB+LangChain检索系统的输出差异
问题分析
你遇到的核心问题是:RAG系统在独立脚本中能正确检索并返回基于文档的结果,但集成到FastAPI后,LLM返回的是通用常识内容,未使用检索到的上下文。这说明检索环节未正常工作——FastAPI环境下的向量数据库没有加载到正确的文档,或者retriever没有返回相关片段,导致LLM只能生成无上下文的通用回答。
可能的原因
向量数据库加载异常
- FastAPI运行时的工作目录与独立脚本不同,尽管你用了绝对路径,但可能存在权限问题(比如macOS的隐私权限限制FastAPI进程访问Desktop目录),导致无法加载Chroma持久化的向量数据。
- 导入
utils.processing时,向量库初始化代码重复执行,可能加载了空的或错误的向量库。
异步/同步执行冲突
FastAPI的端点是异步函数,而LangChain的RetrievalQA.run()是同步方法,直接在异步上下文调用可能引发隐性问题(比如线程安全导致的检索失败),但未抛出异常,仅表现为无上下文返回。环境变量与初始化时机问题
- 虽然processing.py中硬编码了OPENAI_API_KEY,但FastAPI运行时的环境可能未正确继承该变量,不过从返回结果看LLM能正常调用,这个可能性较低,但仍需确认。
解决方案
步骤1:排查向量库加载状态
在processing.py中添加日志,确认向量库加载的文档数量:
# 在vectordb初始化后添加 print(f"Chroma加载文档数:{len(vectordb.get()['documents'])}")
分别运行独立脚本和FastAPI,对比打印的文档数:
- 如果FastAPI环境下文档数为0,说明未加载到正确的向量库,需检查路径权限:
- 确保FastAPI运行的终端有访问
/Users/rodrigoburberg/Desktop/RAG_MPEP/RAG_MPEP/assets目录的权限(macOS可在「系统设置-隐私与安全性-文件与文件夹」中添加终端权限)。 - 尝试将Chroma持久化目录改为项目内的相对路径(比如
./assets),避免绝对路径带来的权限或环境差异问题。
- 确保FastAPI运行的终端有访问
步骤2:修复异步/同步冲突
将FastAPI端点改为同步函数,或用asyncio.to_thread包装同步调用:
方案A:改为同步端点
@app.post("/query") def query_endpoint(query: Input): try: response = process_query(query.human_input) return Output(output=response) except Exception as e: raise HTTPException(status_code=500, detail=f"处理失败:{str(e)}")
方案B:用asyncio包装同步调用
import asyncio @app.post("/query") async def query_endpoint(query: Input): try: # 将同步任务放到线程池执行 response = await asyncio.to_thread(process_query, query.human_input) return Output(output=response) except Exception as e: raise HTTPException(status_code=500, detail=f"处理失败:{str(e)}")
步骤3:确保初始化代码仅执行一次
避免每次导入processing.py都重复初始化向量库和QA链,用单例模式或缓存优化:
# processing.py中修改初始化逻辑 from functools import lru_cache from langchain.embeddings.openai import OpenAIEmbeddings from langchain.vectorstores import Chroma from langchain.chat_models import ChatOpenAI from langchain.chains import RetrievalQA import os @lru_cache(maxsize=None) def get_qa_chain(): # 建议用.env文件管理API密钥,避免硬编码 os.environ["OPENAI_API_KEY"] = "你的API密钥" embeddings = OpenAIEmbeddings() vectordb = Chroma(persist_directory="/Users/rodrigoburberg/Desktop/RAG_MPEP/RAG_MPEP/assets", embedding_function=embeddings) llm = ChatOpenAI(temperature=0) doc_retriever = vectordb.as_retriever() return RetrievalQA.from_chain_type(llm=llm, chain_type="stuff", retriever=doc_retriever) def query_document(user_query): mpep100_qa = get_qa_chain() result = mpep100_qa.run(user_query) return result
步骤4:验证检索结果
临时修改query_document函数,打印检索到的文档片段,确认是否获取到相关上下文:
def query_document(user_query): mpep100_qa = get_qa_chain() # 打印检索到的文档 docs = mpep100_qa.retriever.get_relevant_documents(user_query) print(f"检索到的文档:{[doc.page_content[:200] for doc in docs]}") result = mpep100_qa.run(user_query) return result
如果打印的文档为空或无关,说明向量库本身或检索配置有问题,需重新生成向量库;如果有相关文档,问题则出在QA链的调用环节。
内容的提问来源于stack exchange,提问作者Rodrigo Burberg
相关产品推荐
相关产品推荐

