基于RAG与LangChain构建多PDF智能问答系统:从原理到实践

news2026/5/7 21:34:55
1. 项目概述一个能与多份PDF“对话”的智能助手如果你经常需要从一堆PDF报告、论文或手册里找信息肯定体会过那种“大海捞针”的烦躁。一页页翻用CtrlF搜索关键词结果要么是搜不到要么是搜出一堆不相关的内容真正需要的那段话可能藏在某个复杂的句子里传统搜索根本无能为力。这个项目Multi-PDFs ChatApp AI Agent就是为了解决这个痛点而生的。简单来说它让你能用“说话”的方式和你的PDF文档库互动。你不再需要记住精确的关键词只需要像问同事一样用自然语言提问比如“总结一下第三季度财报的要点”、“对比A方案和B方案在成本上的差异”或者“根据这份技术手册设备X的日常维护步骤是什么”。这个基于Streamlit构建的Web应用会利用LangChain框架、Google Gemini Pro大语言模型以及FAISS向量数据库从你上传的所有PDF中理解问题、找到最相关的信息片段并生成一个准确、连贯的答案。它本质上是一个检索增强生成RAG系统的完整实现。RAG是当前让大模型“落地”、克服其“幻觉”和知识滞后问题的关键技术。这个项目把RAG的整个流水线——从文档加载、文本切分、向量化存储到语义检索和智能生成——都封装成了一个开箱即用的应用。无论是学生研究文献、分析师处理市场报告还是开发者查阅技术文档都能通过这个工具极大提升信息获取效率。接下来我会带你深入这个项目的内部拆解它的每一处设计并分享我在搭建和优化类似系统时踩过的坑和总结的经验。2. 核心架构与组件选型解析一个能“读懂”多份PDF并回答问题的系统背后是一套精密的协作流程。理解这个架构不仅能帮你用好这个应用更能让你在需要定制或排查问题时知道从何下手。2.1 整体工作流程从PDF到答案的旅程整个系统的运作可以看作一个五步流水线下图清晰地展示了这个过程文档摄入与解析用户通过Web界面Streamlit上传一个或多个PDF文件。后端使用PyPDF2库打开这些文件逐页提取出纯文本内容。这里第一个注意事项就来了PyPDF2对某些复杂排版或扫描版PDF的文本提取能力有限如果遇到提取乱码或大量空白可能需要换用pdfplumber或pymupdf又名fitz库它们对格式的兼容性更好。文本分块与向量化直接处理整本PDF是不现实的因为大模型有上下文长度限制。因此需要把提取的长文本切割成大小合适的“块”。这个项目采用了滑动窗口分块技术。简单说就是像用一个固定长度的窗口在文本上滑动每次截取一段并且相邻的窗口之间会有部分重叠。这样做的好处是即使一个问题相关的信息恰好被标准分块切在了两个块的边界重叠部分也能保证上下文信息的连贯性提高检索的准确性。分块后的文本通过langchain_google_genai调用Google的嵌入模型将每一段文字转换成一个高维度的向量可以理解为一串代表语义的数字指纹。向量存储与索引生成的海量向量需要被高效地存储和检索。这里选用了FAISSFacebook AI Similarity Search库。FAISS就像一个为向量特化的超级搜索引擎它会把所有文本块的向量构建成一个索引。当用户提问时系统能在这个索引中快速找到与问题语义最相似的几个文本块这个过程比在原始文本中逐字匹配要快得多、也准得多。语义检索与上下文组装用户输入问题后问题文本同样被转换成向量。FAISS接收这个“问题向量”并在索引中执行相似度搜索找出前k个比如前4个最相似的文本块。这些块就是系统认为与问题最相关的原始材料。它们被从数据库中取出拼接在一起形成提供给大模型的“参考上下文”。答案生成与呈现最后拼接好的上下文和用户的问题被一起构造成一个提示词Prompt发送给Google Gemini Pro模型。Prompt通常会这样设计“请基于以下上下文信息回答问题{上下文}。问题是{用户问题}。如果上下文不包含答案请直接说‘根据提供的信息无法回答’。” 模型基于这个指令和上下文生成最终的自然语言答案并通过Streamlit界面流畅地Streaming展示给用户。2.2 关键技术栈选型背后的考量为什么是LangChain Gemini FAISS Streamlit这个组合这背后每一环都有其道理。LangChain 编排框架而非必选项。LangChain的核心价值在于它提供了一套高级抽象如DocumentLoader、TextSplitter、VectorStore让开发者能像搭积木一样快速构建RAG应用无需从零处理每个细节。它封装了与多种模型、数据库交互的复杂性。但要注意LangChain有时会带来额外的复杂性和性能开销。对于追求极致控制或性能的场景直接调用各组件API也是完全可行的路径。这个项目使用LangChain极大地加速了原型开发和代码可读性。Google Gemini Pro 性能与成本的平衡。在众多大模型中选择Gemini Pro有几个原因一是其API易于获取且稳定二是在长文本理解和推理任务上表现优异适合处理从PDF中提取的复杂信息三是相较于某些按Token精细计费的模型其定价模式可能对中等使用量的场景更友好。项目也提到了兼容OpenAI GPT、Claude等这体现了LangChain的优势——通过更换ChatModel的配置就能轻松切换模型供应商提供了灵活性。FAISS 本地向量检索的效率之选。FAISS是Meta开源的库专为稠密向量相似性搜索优化尤其擅长处理百万级甚至更大规模的向量集。它支持CPU和GPU加速并且可以持久化到磁盘。在这个项目中使用faiss-cpu版本意味着无需昂贵的GPU也能运行降低了部署门槛。相比其他向量数据库如Pinecone、Weaviate等云服务FAISS是本地部署、零成本的解决方案适合对数据隐私敏感或希望离线运行的项目。Streamlit 快速构建原型的利器。对于数据科学家和算法工程师来说Streamlit能以极少的代码将Python脚本转化为交互式Web应用。它内置了文件上传、按钮、聊天框、状态显示等组件非常适合快速搭建AI demo界面。其“代码即UI”的理念让开发者能专注于核心逻辑而非前端细节。这个项目的UI包括侧边栏上传、聊天历史展示都是用Streamlit简洁的API实现的。实操心得组件选型的替代方案这个技术栈是一个优秀的起点但并非唯一解。例如文本分块可以用更精细的RecursiveCharacterTextSplitter它尝试按段落、句子等自然边界分割可能比固定窗口保留更多语义完整性。向量数据库可以换成ChromaDB它更轻量且自带持久化和元数据管理。前端也可以用Gradio它同样简单且在自定义复杂布局时可能更灵活。了解这些备选方案能帮助你在项目需求变化时快速调整。3. 环境搭建与核心配置详解纸上得来终觉浅绝知此事要躬行。让我们一步步把这个项目跑起来并深入每个配置项的细节。3.1 从零开始的环境准备首先你需要一个Python环境建议3.8以上。我强烈推荐使用conda或venv创建独立的虚拟环境避免包版本冲突。# 克隆项目代码 git clone https://github.com/GURPREETKAURJETHRA/Multi-PDFs_ChatApp_AI-Agent.git cd Multi-PDFs_ChatApp_AI-Agent # 创建并激活虚拟环境 (以conda为例) conda create -n pdf-chatbot python3.10 conda activate pdf-chatbot # 安装依赖 pip install -r requirements.txt安装过程可能会因网络问题卡住特别是安装faiss-cpu时。如果遇到超时可以尝试使用国内镜像源例如pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple3.2 获取并配置Google API密钥这是整个项目能运行起来的最关键一步。没有有效的API密钥模型调用将全部失败。访问 Google AI Studio 原MakerSuite。你需要一个Google账号。点击“Create API Key”按钮。系统可能会提示你创建一个项目按指引操作即可。成功创建后你会获得一个以AIza开头的长字符串这就是你的API密钥。请像保护密码一样保护它不要上传到任何公开仓库。接下来在项目的根目录下与app.py同级创建一个名为.env的文件。这个文件用于存储环境变量确保敏感信息不写入代码。# .env 文件内容 GOOGLE_API_KEY你的API密钥粘贴在这里例如GOOGLE_API_KEYAIzaSyB_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx重要安全警告务必确保.env文件被添加到.gitignore中防止误提交。在app.py中项目使用python-dotenv库的load_dotenv()函数来读取这个密钥然后通过os.getenv(GOOGLE_API_KEY)调用。这是管理配置的标准安全实践。3.3 首次运行与界面初探配置完成后在终端运行以下命令启动应用streamlit run app.py几秒钟后你的默认浏览器会自动打开一个标签页地址通常是http://localhost:8501。你将看到类似下图的界面应用界面主要分为两部分左侧边栏这里是控制中心。包含PDF文件上传区域、“Submit Process”按钮以及一些可能的配置选项如选择分块大小、重叠长度等。主区域聊天交互区。上方会显示聊天历史下方有一个输入框供你提问。首次运行时侧边栏会显示文件上传器。你可以拖放或点击选择你的PDF文件。选择后务必记得点击“Submit Process”按钮。这个动作会触发后台的文档处理流水线加载、分块、向量化、存储。你会在界面上看到处理进度提示。处理完成后你就可以在主聊天框输入问题了。试试问一些基于PDF内容的问题比如“这份文档主要讲了什么”或者更具体的内容。4. 核心代码模块深度拆解理解了流程和界面我们深入到代码层面看看每个核心功能是如何实现的。我们以app.py为主要分析对象。4.1 文档加载与智能分块策略在app.py中处理上传文件的函数通常命名为process_documents或类似会执行以下操作# 伪代码示意核心逻辑 from langchain.document_loaders import PyPDFLoader from langchain.text_splitter import RecursiveCharacterTextSplitter def process_uploaded_files(uploaded_files): all_docs [] for uploaded_file in uploaded_files: # 1. 临时保存上传的文件 with open(temp_file_path, wb) as f: f.write(uploaded_file.getbuffer()) # 2. 使用LangChain的PDF加载器 loader PyPDFLoader(temp_file_path) documents loader.load() # 返回一个Document对象列表每个对象包含一页文本和元数据 all_docs.extend(documents) # 3. 文本分块 - 这是影响效果的关键 text_splitter RecursiveCharacterTextSplitter( chunk_size1000, # 每个块的最大字符数 chunk_overlap200, # 块与块之间的重叠字符数 length_functionlen, separators[\n\n, \n, , ] # 优先按段落再按句子再按单词分割 ) chunks text_splitter.split_documents(all_docs) return chunks参数调优经验chunk_size太小会导致信息碎片化模型缺乏足够上下文太大会使检索精度下降且可能超出模型上下文窗口。1000-1500字符是一个常见的起始点。对于技术文档可以稍大对于对话或小说可以稍小。chunk_overlap这是保证上下文连贯性的“安全边际”。通常设置为chunk_size的10%-20%。200-300字符的重叠能有效防止关键信息被割裂。separatorsRecursiveCharacterTextSplitter会按这个列表的顺序尝试分割这比简单的滑动窗口更能尊重文档的自然结构段落-句子。4.2 向量化与FAISS索引构建分块后的文本需要变成向量并存入FAISS。# 伪代码示意核心逻辑 from langchain_google_genai import GoogleGenerativeAIEmbeddings from langchain.vectorstores import FAISS def create_vector_store(text_chunks): # 1. 初始化嵌入模型 # 注意这里需要你的GOOGLE_API_KEY已通过环境变量设置 embeddings GoogleGenerativeAIEmbeddings(modelmodels/embedding-001) # 指定嵌入模型 # 2. 从文本块创建向量存储 # 这一步会调用Google的嵌入API将每个chunk转换为向量然后由FAISS在内存中创建索引 vector_store FAISS.from_documents(documentstext_chunks, embeddingembeddings) # 3. 可选将索引保存到本地磁盘下次无需重新处理 vector_store.save_local(faiss_index) return vector_store关键点GoogleGenerativeAIEmbeddings是LangChain提供的包装器它负责调用Google的嵌入API。每次调用都会产生费用和网络延迟。FAISS.from_documents是一个同步操作如果文档很多比如上千页这个过程可能会耗时较长。在Streamlit应用中你需要用st.spinner或进度条给用户反馈。保存索引到本地save_local是一个最佳实践。这样用户再次打开应用时如果上传相同的文档可以直接加载已有索引无需重新调用API和计算速度极快。4.3 检索链与对话记忆的实现这是应用的大脑负责理解问题、查找资料、组织对话。# 伪代码示意核心逻辑 from langchain_google_genai import ChatGoogleGenerativeAI from langchain.chains import ConversationalRetrievalChain from langchain.memory import ConversationBufferMemory def setup_conversation_chain(vector_store): # 1. 初始化大语言模型 llm ChatGoogleGenerativeAI(modelgemini-pro, temperature0.3, convert_system_message_to_humanTrue) # 2. 初始化对话记忆 # Memory用于保存多轮对话的历史让AI能记住之前的问答上下文。 memory ConversationBufferMemory(memory_keychat_history, return_messagesTrue, output_keyanswer) # 3. 构建对话检索链 # 这是LangChain的核心链它把检索器retriever、语言模型llm和记忆memory串联起来。 retriever vector_store.as_retriever(search_kwargs{k: 4}) # 检索最相关的4个块 conversation_chain ConversationalRetrievalChain.from_llm( llmllm, retrieverretriever, memorymemory, return_source_documentsTrue, # 非常重要返回用于生成答案的源文档片段 verboseFalse # 设为True可以看到链的详细执行步骤用于调试 ) return conversation_chain参数解析与调优modelgemini-pro: 指定使用Gemini Pro聊天模型。temperature0.3: 控制模型输出的随机性。0表示最确定、最保守1表示最有创意、最随机。对于事实性问答设置为0.1-0.3可以获得更稳定、准确的答案。search_kwargs{k: 4}: 这是检索器参数k值决定了每次检索返回多少个文本块。k太小可能信息不全k太大会引入噪声并增加提示词长度可能触发模型token限制。通常从4开始尝试根据答案质量调整。return_source_documentsTrue:强烈建议开启。这能让应用在返回答案的同时也返回它参考了哪些原文片段。这对于验证答案的可靠性、进行溯源至关重要是构建可信AI应用的基本要求。4.4 Streamlit前端交互逻辑Streamlit的代码是声明式的状态管理需要一些技巧。# app.py 主逻辑简化示意 import streamlit as st def main(): st.set_page_config(page_titleChat with PDFs) st.header(Chat with Multiple PDFs ) # 1. 初始化会话状态 # Streamlit脚本会从上到下重新执行用st.session_state来保持状态如聊天历史、向量库 if conversation not in st.session_state: st.session_state.conversation None if chat_history not in st.session_state: st.session_state.chat_history [] # 2. 侧边栏文件上传与处理 with st.sidebar: uploaded_files st.file_uploader(Upload your PDFs, type[pdf], accept_multiple_filesTrue) if st.button(Process): with st.spinner(Processing...): # 调用前面定义的函数 raw_text get_pdf_text(uploaded_files) text_chunks get_text_chunks(raw_text) vectorstore get_vectorstore(text_chunks) # 创建对话链并存入会话状态 st.session_state.conversation get_conversation_chain(vectorstore) st.success(Processing complete! You can now ask questions.) # 3. 主聊天界面 user_question st.chat_input(Ask a question about your documents:) if user_question: # 显示用户问题 with st.chat_message(user): st.write(user_question) # 获取并显示AI回答 with st.chat_message(assistant): with st.spinner(Thinking...): if st.session_state.conversation is None: st.warning(Please upload and process PDFs first.) else: # 调用对话链 response st.session_state.conversation({question: user_question}) answer response[answer] source_docs response.get(source_documents, []) st.write(answer) # 流式输出答案 # 显示来源可折叠保持界面简洁 with st.expander(View source passages): for i, doc in enumerate(source_docs): st.caption(f**Passage {i1}** (Page {doc.metadata.get(page, N/A)}):) st.text(doc.page_content[:500] ...) # 只显示前500字符这个结构清晰地分离了UI、状态管理和业务逻辑是构建稳定Streamlit应用的常见模式。5. 高级功能扩展与性能优化基础功能跑通后我们可以思考如何让它更强大、更实用。5.1 支持更多文件格式与复杂文档当前项目主要处理PDF和TXT。现实中的文档可能是Word、PPT、Excel甚至网页。扩展加载器LangChain社区有丰富的DocumentLoader。from langchain.document_loaders import UnstructuredWordDocumentLoader, UnstructuredPowerPointLoader, CSVLoader # 根据文件后缀选择不同的加载器处理扫描件图片PDF这需要OCR技术。可以使用pymupdf提取页面图片然后通过pytesseract或Google Cloud Vision API进行文字识别再将结果交给文本分块流程。这会显著增加处理时间和成本。处理复杂表格普通文本提取会破坏表格结构。可以考虑使用专为表格设计的库如camelot或tabula将表格提取为DataFrame再以结构化文本如Markdown表格的形式嵌入到上下文中。5.2 提升检索质量超越简单相似度搜索基础的向量相似度搜索有时会失灵比如问题“去年的利润是多少”而文档中写的是“2023年净利润为1亿元”。由于“去年”和“2023年”的向量可能不接近导致检索失败。查询重写/扩展在检索前先用LLM对原始问题进行优化。例如将“去年的利润”重写为“2023年利润 2022年利润 净利润”。# 简化的查询扩展示例 from langchain.llms import OpenAI from langchain.chains import LLMChain from langchain.prompts import PromptTemplate rewrite_prompt PromptTemplate( input_variables[question], template你是一个专业的搜索引擎优化助手。请将以下用户问题扩展成2-3个相关的关键词或短语用空格分隔{question} ) llm ChatGoogleGenerativeAI(modelgemini-pro, temperature0) rewrite_chain LLMChain(llmllm, promptrewrite_prompt) expanded_query rewrite_chain.run(original_question) # 然后用 expanded_query 去做向量检索混合搜索结合稠密向量检索语义相似和稀疏向量检索关键词匹配如BM25。LangChain支持通过EnsembleRetriever将多个检索器的结果融合取长补短。元数据过滤在存储向量时可以为每个块附加元数据如{“source”: “财报.pdf”, “page”: 5, “section”: “财务摘要”}。检索时可以要求“只从‘财报.pdf’中检索”或“只检索第5到10页”这能极大提升精准度。5.3 优化性能与用户体验索引持久化与缓存如前所述一定要实现vector_store.save_local()和FAISS.load_local()。可以为每个上传的文件集计算一个哈希值如MD5以哈希值为索引名存储。下次用户上传相同文件时直接加载已有索引。异步处理文档处理尤其是调用嵌入API是I/O密集型任务。可以使用asyncio和langchain的异步接口让文件处理在后台进行不阻塞UI响应。流式输出现在的答案是一次性生成的。可以启用LLM的流式响应让答案一个字一个字地显示出来提供更即时的反馈感。Gemini API和LangChain都支持流式输出。设置超时与重试网络请求可能失败。在调用conversation_chain时应添加超时和重试逻辑提高应用的健壮性。6. 常见问题排查与实战心得在实际部署和使用中你肯定会遇到各种问题。这里我总结了一份“避坑指南”。6.1 安装与依赖问题问题安装faiss-cpu失败提示找不到合适的版本或编译错误。原因FAISS的预编译轮子可能不兼容你的操作系统或Python版本。解决首先确保Python版本是3.8-3.11的64位版本。尝试使用conda安装conda install -c conda-forge faiss-cpu。conda的环境管理通常更省心。如果必须用pip可以尝试安装更通用的版本pip install faiss-cpu --no-binary :all:这会从源码编译需要系统有C编译环境。问题运行时报错ImportError: cannot import name ... from langchain原因LangChain版本更新较快API可能有变动。项目requirements.txt中指定的版本可能与你安装的最新版不兼容。解决查看项目根目录或GitHub页面是否有对LangChain版本的明确要求。可以尝试安装特定版本pip install langchain0.0.xxx。或者根据错误信息去LangChain官方文档查看新版本的导入方式。6.2 API密钥与网络问题问题应用能启动但一提问就报错提示API密钥无效或权限不足。检查1确认.env文件在正确位置且密钥格式正确没有多余空格或换行。检查2确认你的Google Cloud项目已启用Gemini API。拥有API密钥不代表服务已启用需要去 Google Cloud Console 的“API和服务”仪表板中手动启用“Generative Language API”。检查3检查账户是否有足够的配额或余额。新项目可能有免费额度但用完后需要设置账单。问题处理文档或回答问题时速度非常慢甚至超时。分析慢可能发生在两个环节1. 调用Google嵌入API文档向量化2. 调用Gemini Pro API生成答案。前者耗时与文档总长度成正比后者与问题复杂度相关。优化对于文档处理实现索引持久化避免重复处理。对于问答检查检索的k值是否过大比如超过10减少不必要的上下文长度。网络问题考虑应用部署在离Google服务器较近的区域或者为请求配置合理的超时时间。6.3 应用功能与效果问题问题AI的回答完全是胡编乱造与文档内容无关“幻觉”严重。诊断这是RAG系统最典型的问题。首先点击“View source passages”查看AI检索到的源文本。如果源文本本身就不相关那么问题出在检索阶段。检索阶段优化尝试减小chunk_size如从1000降到500增加chunk_overlap如从100增到200。或者尝试使用RecursiveCharacterTextSplitter并调整separators。也可以考虑启用search_typemmr最大边际相关性在相似性的基础上增加结果的多样性。如果检索到的文本是相关的但答案还是胡扯问题可能出在生成阶段。检查你的Prompt是否明确要求模型“严格基于上下文回答”。可以强化Prompt例如“请仅根据提供的上下文信息回答问题。如果上下文没有提供足够信息请直接说‘根据所给信息无法回答’。不要使用你已有的知识。”问题无法进行多轮对话AI记不住之前说过的话。检查确认ConversationBufferMemory已正确初始化并传入ConversationalRetrievalChain。在Streamlit中确保st.session_state.conversation这个链对象在多次用户输入间被持久化而不是每次都被重新创建。注意记忆的长度是有限的。如果对话轮次非常多最早的历史可能会被丢弃。你可以使用ConversationSummaryMemory或ConversationBufferWindowMemory来管理更长的对话历史。问题上传大文件如200页的PDF时应用卡死或无响应。原因同步处理大量文本和网络请求阻塞了Streamlit的主线程。解决前端反馈用st.progress和st.status给用户明确的进度提示。后台处理将耗时的文档处理任务放入单独的线程或进程中避免阻塞UI。Streamlit本身对长时间运行的操作支持有限可以考虑结合asyncio或像joblib这样的库。分步处理对于极大的文件可以提示用户分卷上传或者在后端实现分批处理。这个项目是一个功能完整且设计良好的RAG应用起点。从理解架构、动手部署到深入代码、优化排错整个过程是学习现代AI应用开发的绝佳路径。我最深的体会是构建一个“能用”的RAG系统不难但要让其“好用”、“可靠”需要在每一个环节——从文档预处理的分块策略到检索的精度与召回平衡再到Prompt工程和错误处理——都投入精力去细致调优。它不仅仅是一个工具更是一个需要持续迭代和打磨的产品。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2592721.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…

网络编程(Modbus进阶)

思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…