当前位置: 首页 > news >正文

别再空谈RAG了!手把手教你用LangChain + Chroma + 本地SearXng,从零搭建一个能联网搜索的智能问答助手

从零构建智能问答系统:LangChain + Chroma + SearXng实战指南

引言

在信息爆炸的时代,如何快速获取准确答案成为技术团队面临的共同挑战。传统搜索引擎返回的是海量网页链接,而大语言模型虽然能生成流畅回答,却存在信息滞后和幻觉问题。检索增强生成(RAG)技术结合了两者优势,让AI既能实时获取最新信息,又能生成结构化的专业回答。

本文将带你从零搭建一个能联网搜索的智能问答系统,核心技术栈包括:

  • LangChain:大语言模型应用开发框架
  • Chroma:轻量级向量数据库
  • SearXng:隐私友好的开源元搜索引擎

不同于理论讲解,我们聚焦于可落地的工程实践,涵盖环境配置、代码实现、调试技巧全流程。即使没有AI项目经验,按照本文步骤也能在2小时内构建出可用的问答系统。

1. 环境准备与工具链配置

1.1 基础环境搭建

推荐使用Python 3.10+环境,通过conda管理依赖:

conda create -n rag python=3.10 conda activate rag

安装核心依赖库:

pip install langchain chromadb sentence-transformers searxng

常见问题排查

  • 如遇到grpc安装失败,尝试先安装pip install grpcio==1.48.2
  • 在ARM架构设备(如Mac M系列)上需额外安装pip install chromadb --no-deps后手动安装依赖

1.2 本地SearXng部署

SearXng提供Docker一键部署方案:

docker pull searxng/searxng:latest docker run -d --name searxng -p 8080:8080 searxng/searxng

验证服务是否正常:

curl "http://localhost:8080/search?q=test&format=json"

配置要点:

  • 修改/etc/searxng/settings.yml启用更多搜索引擎
  • 建议设置server.limiter=false关闭速率限制
  • 通过docker logs searxng查看实时日志

2. 核心模块实现

2.1 文档处理流水线

建立document_processor.py实现文本加载与分块:

from langchain.text_splitter import RecursiveCharacterTextSplitter from langchain.document_loaders import DirectoryLoader def process_documents(data_dir): loader = DirectoryLoader(data_dir, glob="**/*.md") documents = loader.load() splitter = RecursiveCharacterTextSplitter( chunk_size=1000, chunk_overlap=200, length_function=len ) return splitter.split_documents(documents)

关键参数说明:

参数推荐值作用
chunk_size500-1500影响检索精度和上下文完整性
chunk_overlap10-20%避免语义断裂
separators["\n\n", "\n", " "]中文建议增加"。 "

2.2 向量数据库初始化

创建vector_db.py配置Chroma数据库:

from langchain.vectorstores import Chroma from langchain.embeddings import HuggingFaceEmbeddings embedding_model = HuggingFaceEmbeddings( model_name="GanymedeNil/text2vec-large-chinese", model_kwargs={'device': 'cpu'} ) def init_vectorstore(docs, persist_dir="chroma_db"): return Chroma.from_documents( documents=docs, embedding=embedding_model, persist_directory=persist_dir )

性能优化技巧:

  • 使用parquet格式存储向量:chroma_client = chromadb.PersistentClient(path=persist_dir)
  • 批量插入时设置batch_size=100
  • 对大规模数据启用allow_dangerous_deserialization=True

2.3 混合检索器实现

hybrid_retriever.py中组合本地与网络检索:

from langchain.retrievers import BaseRetriever from typing import List from langchain.schema import Document import requests class HybridRetriever(BaseRetriever): def __init__(self, vector_retriever, searxng_url): self.vector_retriever = vector_retriever self.searxng_url = searxng_url def _get_relevant_documents(self, query: str) -> List[Document]: # 本地向量检索 local_docs = self.vector_retriever.get_relevant_documents(query) # 网络搜索 search_results = requests.get( f"{self.searxng_url}/search", params={"q": query, "format": "json"} ).json() web_docs = [ Document( page_content=result.get("content", ""), metadata={"source": result["url"]} ) for result in search_results.get("results", []) ] return local_docs + web_docs

注意:实际部署时应添加请求超时和重试机制,处理网络不稳定的情况

3. 问答系统集成

3.1 提示工程优化

设计兼顾准确性和安全性的提示模板:

from langchain.prompts import PromptTemplate PROMPT_TEMPLATE = """ 你是一位专业的信息助理,请根据以下规则回答问题: 可用资源: {context} 回答要求: 1. 标注信息来源(📚表示本地知识库,🌐表示网络结果) 2. 保持客观中立,不编造不存在的信息 3. 对可能引发争议的内容明确标注"该观点存在争议" 当前问题:{question} """ prompt = PromptTemplate( template=PROMPT_TEMPLATE, input_variables=["context", "question"] )

3.2 完整链路组装

qa_system.py中构建端到端流程:

from langchain.chains import RetrievalQA from langchain.llms import Ollama # 使用本地模型 def build_qa_system(retriever): llm = Ollama(model="qwen:7b") return RetrievalQA.from_chain_type( llm=llm, retriever=retriever, chain_type="stuff", chain_type_kwargs={"prompt": prompt}, return_source_documents=True )

启动交互式问答:

qa = build_qa_system(hybrid_retriever) while True: query = input("\n请输入问题:") result = qa({"query": query}) print(f"\n答案:{result['result']}") print("\n来源:") for doc in result['source_documents']: print(f"- {doc.metadata['source']}")

4. 高级功能扩展

4.1 结果重排序策略

添加reranker.py提升结果质量:

from sentence_transformers import CrossEncoder reranker = CrossEncoder("cross-encoder/ms-marco-MiniLM-L-6-v2") def rerank_documents(query, documents, top_k=3): pairs = [(query, doc.page_content) for doc in documents] scores = reranker.predict(pairs) scored_docs = list(zip(scores, documents)) scored_docs.sort(reverse=True) return [doc for _, doc in scored_docs[:top_k]]

4.2 缓存机制实现

使用Redis缓存高频查询:

import redis from hashlib import md5 r = redis.Redis(host='localhost', port=6379) def get_cache_key(query): return f"qa_cache:{md5(query.encode()).hexdigest()}" def cached_query(query, qa_system): cache_key = get_cache_key(query) cached = r.get(cache_key) if cached: return json.loads(cached) result = qa_system({"query": query}) r.setex(cache_key, 3600, json.dumps(result)) # 缓存1小时 return result

4.3 监控与日志

集成Prometheus监控指标:

from prometheus_client import start_http_server, Counter QUERY_COUNT = Counter('qa_query_total', 'Total query count') LATENCY_HIST = Histogram('qa_latency_seconds', 'Query latency') @LATENCY_HIST.time() def execute_query(query): QUERY_COUNT.inc() return qa_system({"query": query}) start_http_server(8000) # 暴露/metrics端点

5. 生产环境部署建议

5.1 性能优化配置

Chroma数据库调优参数:

# chroma_config.yaml persist_directory: /data/chroma chroma_db_impl: "duckdb+parquet" allow_reset: false anonymized_telemetry: false

启动参数建议:

uvicorn qa_server:app --host 0.0.0.0 --port 8000 \ --workers 4 \ --no-access-log \ --http h11 \ --timeout-keep-alive 30

5.2 安全防护措施

推荐的安全实践:

  1. 为SearXng配置HTTPS
  2. 使用rate-limiter-flexible限制API调用频率
  3. 对用户输入进行严格的SQL注入检测
  4. 定期备份向量数据库快照

Nginx示例配置:

location /api/ { proxy_pass http://localhost:8000; limit_req zone=api burst=10 nodelay; proxy_set_header X-Real-IP $remote_addr; }

5.3 持续维护方案

建议的监控指标:

指标名称监控方式告警阈值
查询延迟PrometheusP99 > 3s
内存使用cAdvisor>80% 持续5分钟
搜索失败率Logstash错误率 > 1%

日志分析架构:

Filebeat -> Logstash -> Elasticsearch -> Kafka(实时告警)
http://www.jsqmd.com/news/665547/

相关文章:

  • 5秒极速转换:m4s-converter完整指南,永久保存你的B站缓存视频
  • 从Sigmoid到CrossEntropy:一个LogSumExp技巧如何串联起深度学习的‘防爆’计算
  • 破局私域孤岛:以Go语言驱动的壹信即时通讯源码全景解析,探路开源im系统与即时通讯app定制新范式 - 壹软科技
  • STM32驱动电磁阀,除了代码你还需要搞定这些硬件(电源、485、MOS管电路图详解)
  • 手把手教你学Simulink——基于Simulink的轴向磁通电机多物理场耦合仿真
  • 艾尔登法环存档迁移工具深度技术解析与实现指南
  • 无锡GEO优化运营推广拓客公司排行:精准获客实力盘点 - 速递信息
  • UE5启动崩溃:从报错日志到精准修复的实战指南
  • FanControl终极指南:免费Windows风扇智能控制软件完全教程
  • 告别V8依赖:在Windows 10上精简编译PDFium库的保姆级避坑指南
  • 避坑指南:PyTorch中ReflectionPad2d和ReplicationPad2d用错了?详解两者区别与适用场景
  • 如何快速解密网易云音乐NCM格式:3步完成音频格式转换的完整指南
  • SliderCaptcha技术实现深度解析:构建现代Web安全验证的5个核心考量
  • 告别Paho和Mosquitto:深入评测mqttclient这个轻量级C库在Linux和RT-Thread下的性能表现
  • Python 协程执行顺序可视化解析
  • [具身智能-385]:自主机器人的定位系统
  • S2-Pro Java面试题深度解析与模拟面试应用
  • 细聊钢格板供应企业质量咋审核,推荐哪家更放心 - 工业品网
  • 从零到一上线你的第一个AI建站工具网站:全流程保姆级攻略
  • AIGC联动创新:使用Stable Diffusion与cv_resnet101_face-detection进行可控人像生成
  • SimCLR对比学习实战:手把手教你用Visdom可视化PyTorch训练全过程(含Loss/Acc曲线)
  • 终极B站缓存视频合并方案:让你的离线视频瞬间“活“过来
  • 如何打破音乐平台的枷锁:Unlock Music Electron完整指南
  • 深挖2026年靠谱的冷库厂商,解读冷库品牌供应商如何选择 - 工业设备
  • 从图形桌面到命令行:聊聊Windows的Explorer、CMD和PowerShell那些剪不断理还乱的关系
  • 别再手动处理.mat文件了!用Python+TensorFlow 1.x搞定西储大学轴承数据预处理(附完整代码)
  • 从零到一:实战UPF2.1 Power Intent编写全流程解析
  • 盘点靠谱的钢格板加工厂家,哪家运输包装好且制造品质过硬价格合理? - 工业推荐榜
  • 告别Redis命令行困扰:3个场景揭秘AnotherRedisDesktopManager如何提升开发效率
  • 代码生成率提升300%,发布回滚率却飙升210%?这才是2024最紧急的DevSecOps盲区!