基于RAG与向量数据库的智能PDF问答系统构建指南

news2026/5/4 8:03:47
1. 项目概述打造一个能与PDF“对话”的智能助手最近在折腾一个挺有意思的项目叫Huxley PDF。简单来说它就是一个能让你和你的PDF文档“聊天”的Web应用。你上传一份PDF比如一份几十页的技术报告、一份合同或者一篇学术论文然后就可以像问一个专家一样直接向它提问它会基于PDF里的内容给你精准的答案。这玩意儿本质上是一个基于大语言模型LLM的检索增强生成RAG应用核心是把非结构化的PDF文本通过向量化技术变成一个可以被“检索”的知识库。我之所以花时间研究并复现这个项目是因为在日常工作和学习中处理PDF文档实在太频繁了。传统的CtrlF搜索只能匹配关键词对于“请总结一下第三章的核心观点”或者“对比一下方案A和方案B的优缺点”这类需要理解和推理的问题完全无能为力。而Huxley PDF这类工具正好填补了这个空白。它背后的技术栈非常典型集成了Streamlit做快速Web开发LangChain作为LLM应用框架OpenAI的API提供核心的文本理解和生成能力再配合向量数据库如FAISS实现高效的语义搜索。对于想入门AI应用开发的开发者来说这是一个绝佳的练手项目能让你一站式理解从文档处理、向量化到问答生成的完整链路。2. 核心架构与工作原理解析2.1 技术栈选型背后的逻辑Huxley PDF选择的技术组合在当前的AI应用开发中几乎是“黄金搭档”。我们来拆解一下每个组件的角色和选型理由Streamlit作为前端框架。它的最大优势是“快”。对于数据科学和机器学习项目开发者通常不想在前端HTML/CSS/JavaScript上耗费太多精力。Streamlit允许你完全用Python脚本构建交互式Web应用任何.py文件的修改都能实时热更新到界面极大地提升了原型开发速度。对于Huxley PDF这样一个工具类、交互逻辑相对固定的应用Streamlit是最高效的选择。LangChain作为应用编排框架。LLM本身是“原子化”的要构建一个可用的应用你需要串联起提示词模板、文档加载、文本分割、向量存储、检索链等多个环节。LangChain提供了一套高级的抽象如Chain、Agent、Retriever将这些环节标准化、模块化。使用LangChain你可以用很少的代码就搭建起一个RAG流水线而无需从零开始处理每一步的底层API调用和数据流转。它降低了开发门槛让开发者能更专注于业务逻辑。OpenAI API提供核心的Embedding文本转向量和Completion文本生成能力。这里其实包含两个关键模型Embedding模型如text-embedding-ada-002负责将一段文本比如一个句子或一个段落转换成一个高维度的数值向量例如1536维。这个向量的神奇之处在于语义相似的文本其向量在空间中的距离通常用余弦相似度衡量也更近。这是实现语义搜索的基石。大语言模型如gpt-3.5-turbo或gpt-4负责理解用户问题并结合检索到的上下文信息生成通顺、准确的答案。它扮演了“信息整合与表达者”的角色。向量数据库项目提到了FAISS和Pinecone。FAISS是Meta开源的库用于高效进行向量相似性搜索和聚类尤其适合单机、中小规模数据集的快速检索。Pinecone则是全托管的云端向量数据库擅长处理海量向量数据并提供自动缩放、持久化存储等能力。在Huxley PDF的初始版本中使用FAISS是合理的因为它轻量、无需额外服务适合本地快速验证。如果未来需要处理成千上万的PDF或支持多用户迁移到Pinecone这类服务是更优解。注意技术选型不是一成不变的。例如如果你希望完全本地部署可以考虑用SentenceTransformers库的模型如all-MiniLM-L6-v2替代OpenAI Embedding用开源LLM如Llama 2、ChatGLM通过llama.cpp或Ollama替代OpenAI API。但这会显著增加本地计算资源消耗和部署复杂度。2.2 RAG流程从PDF到答案的完整旅程理解Huxley PDF如何工作关键在于弄懂RAGRetrieval-Augmented Generation检索增强生成的流程。整个过程可以清晰地分为“索引构建”和“问答执行”两个阶段。阶段一索引构建文档处理与向量化这是“喂食”阶段发生在你上传PDF之后。目标是构建一个可供快速检索的向量索引。文档加载使用PyMuPDFfitz或Unstructured库读取PDF文件提取出纯文本。这一步需要处理PDF复杂的排版、分栏、图片、表格等提取质量直接影响后续效果。文本分割一篇PDF可能长达数百页直接扔给LLM会超出其上下文长度限制Token限制且包含大量无关信息。因此需要用CharacterTextSplitter或更智能的RecursiveCharacterTextSplitter将文本切割成大小适中的“块”chunks。这里有两个关键参数chunk_size每个块的大小如400字符。太小会丢失上下文太大会降低检索精度并增加LLM处理负担。通常设置在500-1000字符之间进行试验。chunk_overlap块与块之间的重叠字符数如80字符。设置重叠是为了避免一个完整的句子或概念被生硬地切分到两个块中保持语义的连贯性。向量化使用OpenAI的Embedding模型将每一个文本块转换为一个对应的向量。存储索引将文本块对应向量这对数据存储到向量数据库如FAISS中建立索引。之后我们就可以通过计算向量相似度来快速找到相关的文本块。阶段二问答执行检索与生成这是“问答”阶段发生在你提出问题时。问题向量化将用户输入的问题例如“这份合同中的违约责任条款是什么”使用同样的Embedding模型转换为一个向量。语义检索在FAISS索引中计算问题向量与所有文本块向量的相似度如余弦相似度找出最相似的K个文本块例如前4个。这步实现了基于“意思”而不仅仅是“关键词”的搜索。上下文组装将检索到的K个相关文本块与用户的问题一起按照特定的格式组装成一个“增强的提示词”Prompt提交给LLM。一个典型的Prompt模板可能是“请基于以下上下文回答问题。如果上下文不包含答案请说‘根据提供的信息无法回答’。上下文{检索到的文本块} 问题{用户问题} 答案”答案生成LLM接收到这个包含了相关上下文的Prompt后会综合理解生成一个准确、基于文档的答案并返回给用户。通过这两个阶段的配合RAG既利用了LLM强大的语言理解和生成能力又通过检索机制为其“注入”了准确、实时的外部知识你的PDF内容有效避免了LLM的“幻觉”问题让答案有据可依。3. 从零开始环境搭建与核心代码实现3.1 项目环境与依赖安装首先我们需要一个干净的Python环境。强烈建议使用conda或venv创建虚拟环境避免包冲突。# 创建并激活虚拟环境 (以conda为例) conda create -n huxley-pdf python3.9 conda activate huxley-pdf接下来安装核心依赖。requirements.txt文件应该包含以下内容streamlit1.28.0 langchain0.0.350 openai1.3.0 pymupdf1.23.0 # 用于PDF文本提取 faiss-cpu1.7.4 # 向量数据库CPU版本 tiktoken0.5.0 # 用于计算Token控制上下文长度 python-dotenv1.0.0 # 管理环境变量如API密钥使用pip一键安装pip install -r requirements.txt实操心得faiss-cpu在Windows上安装有时会遇到编译问题。如果安装失败可以尝试从 这里 使用conda安装conda install -c conda-forge faiss-cpu。对于生产环境或大数据集可以考虑faiss-gpu版本以利用GPU加速。3.2 核心代码模块拆解与实现原项目的Huxley.py给出了主干逻辑。我们在此基础上补充细节和优化实现一个更健壮、功能更完整的版本。我们将创建一个名为app.py的Streamlit主文件。1. 导入依赖与初始化设置import streamlit as st from langchain.document_loaders import PyPDFLoader from langchain.text_splitter import RecursiveCharacterTextSplitter from langchain.embeddings import OpenAIEmbeddings from langchain.vectorstores import FAISS from langchain.chains import RetrievalQA from langchain.chat_models import ChatOpenAI from langchain.callbacks import StreamlitCallbackHandler import os from dotenv import load_dotenv import tempfile # 加载环境变量将API KEY保存在.env文件中更安全 load_dotenv() # 设置页面配置 st.set_page_config( page_titleHuxley PDF - 智能文档助手, page_icon, layoutwide )2. 侧边栏配置与说明侧边栏是放置API密钥输入和应用说明的理想位置。def render_sidebar(): with st.sidebar: st.title(⚙️ 设置与说明) # API密钥输入优先使用环境变量提供输入框备用 api_key st.text_input( OpenAI API Key, typepassword, valueos.getenv(OPENAI_API_KEY, ), help请输入你的OpenAI API密钥。你也可以在项目根目录创建.env文件并写入OPENAI_API_KEY你的密钥。 ) if api_key: os.environ[OPENAI_API_KEY] api_key else: st.warning(请输入API密钥以继续。) st.markdown(---) st.markdown(### 如何使用) st.markdown( 1. **上传PDF**在主页面上传你的PDF文档。 2. **等待处理**系统将自动解析文档并构建知识索引首次上传需要一些时间。 3. **开始提问**在下方输入框提出任何关于该PDF的问题。 4. **获取答案**AI将基于文档内容给出精准回答。 ) st.markdown(### ⚠️ 注意事项) st.markdown( - 确保PDF是**可复制文本**的非扫描版图片。 - 处理大型PDF100页可能需要较长时间和更多Token消耗。 - 答案质量取决于文档清晰度和问题相关性。 - 所有处理均在本地进行文档内容不会发送给除OpenAI外的第三方。 ) return api_key3. 主函数应用逻辑核心这是整个应用的大脑我们将分步骤实现。def main(): st.title( Huxley PDF - 与你的文档对话) st.caption(上传你的PDF然后像咨询专家一样向它提问。) # 渲染侧边栏并获取API密钥状态 api_key render_sidebar() # 检查API密钥 if not api_key: st.info(请在左侧侧边栏输入OpenAI API密钥以启动应用。) st.stop() # 文件上传器 uploaded_file st.file_uploader(选择或拖拽一个PDF文件, typepdf) # 初始化session_state用于在Streamlit重运行间保持状态 if vector_store not in st.session_state: st.session_state.vector_store None if processed_file_name not in st.session_state: st.session_state.processed_file_name None # 文件处理流程 if uploaded_file is not None: # 检查是否是新文件避免重复处理 if st.session_state.processed_file_name ! uploaded_file.name: with st.spinner(f正在处理 {uploaded_file.name}请稍候...): try: # 步骤1: 保存上传的临时文件并加载 with tempfile.NamedTemporaryFile(deleteFalse, suffix.pdf) as tmp_file: tmp_file.write(uploaded_file.getvalue()) tmp_file_path tmp_file.name loader PyPDFLoader(tmp_file_path) documents loader.load() # 步骤2: 文本分割使用更智能的分割器 text_splitter RecursiveCharacterTextSplitter( chunk_size1000, # 每个块1000字符 chunk_overlap200, # 块间重叠200字符 length_functionlen, separators[\n\n, \n, 。, , , , , , ] ) chunks text_splitter.split_documents(documents) st.success(f文档分割完成共得到 {len(chunks)} 个文本块。) # 步骤3: 创建向量存储 embeddings OpenAIEmbeddings(openai_api_keyapi_key) # 使用FAISS从文档块创建向量存储 vector_store FAISS.from_documents(chunks, embeddings) # 保存到session_state st.session_state.vector_store vector_store st.session_state.processed_file_name uploaded_file.name # 清理临时文件 os.unlink(tmp_file_path) st.success(✅ 文档索引构建完成现在你可以开始提问了。) except Exception as e: st.error(f处理PDF时发生错误: {e}) else: st.info(f文档 {uploaded_file.name} 已就绪可直接提问。) # 问答交互界面 st.divider() st.subheader( 向文档提问) # 初始化聊天历史 if messages not in st.session_state: st.session_state.messages [] # 显示历史消息 for message in st.session_state.messages: with st.chat_message(message[role]): st.markdown(message[content]) # 问题输入 if prompt : st.chat_input(输入你的问题例如总结一下本文的主要观点。): # 添加用户问题到历史 st.session_state.messages.append({role: user, content: prompt}) with st.chat_message(user): st.markdown(prompt) # 检查向量存储是否就绪 if st.session_state.vector_store is None: st.error(文档索引未就绪请先上传并处理PDF文件。) st.stop() # 生成答案 with st.chat_message(assistant): with st.spinner(正在思考...): try: # 创建检索器 retriever st.session_state.vector_store.as_retriever( search_kwargs{k: 4} # 检索最相关的4个文本块 ) # 创建LLM实例 llm ChatOpenAI( model_namegpt-3.5-turbo, temperature0.1, # 低温度值使输出更确定、更基于事实 openai_api_keyapi_key, streamingTrue, # 启用流式输出 ) # 创建检索问答链 qa_chain RetrievalQA.from_chain_type( llmllm, chain_typestuff, # “stuff”类型将检索到的所有文档塞入上下文 retrieverretriever, return_source_documentsTrue, # 返回源文档用于引用 ) # 创建Streamlit回调以显示流式输出 st_callback StreamlitCallbackHandler(st.container()) # 执行查询 result qa_chain({query: prompt}, callbacks[st_callback]) answer result[result] source_docs result[source_documents] # 流式输出答案 response_placeholder st.empty() full_response # 模拟流式输出实际由callback处理这里为展示 for chunk in answer.split(): full_response chunk response_placeholder.markdown(full_response ▌) response_placeholder.markdown(full_response) # 显示引用来源增强可信度 with st.expander( 查看答案来源): for i, doc in enumerate(source_docs[:3]): # 显示前3个来源 st.caption(f来源片段 {i1}:) st.text(doc.page_content[:300] ...) # 显示片段前300字符 st.markdown(f*元数据: 页码 {doc.metadata.get(page, N/A)}*) st.divider() # 添加助手回答到历史 st.session_state.messages.append({role: assistant, content: answer}) except Exception as e: st.error(f生成答案时出错: {e}) else: # 未上传文件时的引导界面 st.markdown( ### 欢迎使用 Huxley PDF 这是一个基于AI的智能文档问答工具。上传你的PDF文档后你可以 - **快速总结**让AI为你提炼长篇文档的核心要点。 - **精准问答**针对文档细节提出具体问题获取基于原文的答案。 - **信息对比**询问文档中不同观点的异同。 - **内容解释**让AI用更通俗的语言解释复杂概念。 **⬆️ 请使用上方文件上传按钮开始。** ) st.image(https://via.placeholder.com/600x300/4A90E2/FFFFFF?textUploadaPDFtoStart, use_column_widthTrue) if __name__ __main__: main()这段代码构建了一个功能完整的Streamlit应用。它包含了文件上传、文档处理、向量索引构建、交互式问答会话以及答案溯源显示。相比原始代码我们增加了错误处理、状态管理、流式输出和源文档引用用户体验更佳。4. 高级功能扩展与性能优化基础版本跑通后我们可以从实用性和性能角度进行一系列增强。4.1 支持多种文档格式现实中的资料不只有PDF。我们可以利用LangChain丰富的DocumentLoader来扩展支持范围。from langchain.document_loaders import ( PyPDFLoader, UnstructuredWordDocumentLoader, UnstructuredPowerPointLoader, TextLoader, CSVLoader, UnstructuredHTMLLoader, ) import pandas as pd def get_document_loader(file_path, file_type): 根据文件类型返回对应的文档加载器 loaders { .pdf: PyPDFLoader, .docx: lambda path: UnstructuredWordDocumentLoader(path, modeelements), .pptx: UnstructuredPowerPointLoader, .txt: TextLoader, .csv: lambda path: CSVLoader(path, encodingutf-8), .html: UnstructuredHTMLLoader, } for ext, loader_class in loaders.items(): if file_path.lower().endswith(ext): return loader_class(file_path) raise ValueError(f不支持的文件格式: {file_type}。支持格式: {, .join(loaders.keys())}) # 在主函数中替换原有的PyPDFLoader调用 file_ext os.path.splitext(uploaded_file.name)[1].lower() loader get_document_loader(tmp_file_path, file_ext) documents loader.load()4.2 优化文本分割策略默认的字符分割可能切断完整的句子或段落。我们可以采用更精细的分割策略。from langchain.text_splitter import ( RecursiveCharacterTextSplitter, SentenceTransformersTokenTextSplitter, ) # 方案A基于标记Token的分割更贴合LLM上下文窗口 token_text_splitter SentenceTransformersTokenTextSplitter( chunk_size500, # 目标块大小Token数 chunk_overlap50, # 重叠Token数 model_nameall-MiniLM-L6-v2, # 用于计算Token的模型 ) # chunks token_text_splitter.split_documents(documents) # 方案B针对中文优化的递归字符分割 chinese_text_splitter RecursiveCharacterTextSplitter( chunk_size800, chunk_overlap150, separators[\n\n, \n, 。, , , , , , ], # 中文标点优先 length_functionlen, ) chunks chinese_text_splitter.split_documents(documents)4.3 集成对话历史与多轮问答让AI记住之前的对话上下文能实现更连贯的多轮问答。from langchain.memory import ConversationBufferMemory from langchain.chains import ConversationalRetrievalChain # 在session_state中初始化记忆 if memory not in st.session_state: st.session_state.memory ConversationBufferMemory( memory_keychat_history, return_messagesTrue, output_keyanswer ) # 创建带记忆的对话检索链 qa_chain ConversationalRetrievalChain.from_llm( llmllm, retrieverretriever, memoryst.session_state.memory, chain_typestuff, return_source_documentsTrue, verboseFalse, # 设置为True可查看链的详细执行过程用于调试 ) # 提问时记忆会自动被使用和更新 result qa_chain({question: prompt}) answer result[answer]4.4 成本控制与Token管理使用OpenAI API会产生费用管理Token使用和成本很重要。from langchain.callbacks import get_openai_callback import tiktoken def count_tokens(text, modelgpt-3.5-turbo): 粗略计算文本的Token数量 encoding tiktoken.encoding_for_model(model) return len(encoding.encode(text)) # 在问答环节使用回调跟踪消耗 with get_openai_callback() as cb: result qa_chain({query: prompt}) answer result[result] # 显示本次调用的消耗 st.sidebar.metric(本次消耗Token, cb.total_tokens) st.sidebar.metric(预估成本USD, f${cb.total_cost:.4f}) # 累计消耗存储在session_state中 if total_cost not in st.session_state: st.session_state.total_cost 0.0 st.session_state.total_cost cb.total_cost st.sidebar.metric(累计成本USD, f${st.session_state.total_cost:.4f})5. 部署上线与生产环境考量本地运行没问题后你可能希望将它部署成一个小型服务供团队内部使用。5.1 使用Docker容器化创建Dockerfile确保环境一致性。# 使用官方Python镜像 FROM python:3.9-slim # 设置工作目录 WORKDIR /app # 复制依赖文件并安装 COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt # 复制应用代码 COPY . . # 暴露Streamlit默认端口 EXPOSE 8501 # 健康检查 HEALTHCHECK CMD curl --fail http://localhost:8501/_stcore/health || exit 1 # 启动命令 ENTRYPOINT [streamlit, run, app.py, --server.port8501, --server.address0.0.0.0]构建并运行docker build -t huxley-pdf . docker run -p 8501:8501 -e OPENAI_API_KEY你的密钥 huxley-pdf5.2 使用云服务一键部署对于更简单的部署可以考虑云平台Streamlit Community Cloud最直接的选择。将代码推送到GitHub在 share.streamlit.io 关联仓库即可部署。注意在Secrets中设置OPENAI_API_KEY环境变量。Hugging Face Spaces同样支持Streamlit提供免费的CPU资源。在Space创建时选择Streamlit SDK上传代码即可。Railway / Render这些平台对Python应用友好提供简单的Git部署和自动HTTPS证书。部署注意事项API密钥安全绝对不要将API密钥硬编码在代码中或提交到Git。使用平台提供的Secrets/Environment Variables功能。文件存储Streamlit Cloud等无状态环境上传的文件在应用重启后会丢失。如果需要持久化存储向量索引需要集成外部存储如AWS S3、Google Cloud Storage并在每次启动时检查并加载已有索引。性能与超时处理大型PDF时构建向量索引可能超过云服务的默认超时时间如Streamlit Cloud有脚本运行时间限制。考虑将“索引构建”这一步异步化或提示用户处理需要时间。5.3 生产环境优化建议向量数据库升级将FAISS替换为Pinecone或Weaviate。它们提供持久化存储、更好的可扩展性和多用户支持。代码改动很小主要是初始化客户端的部分。# 示例使用Pinecone from langchain.vectorstores import Pinecone import pinecone pinecone.init(api_keyYOUR_PINECONE_API_KEY, environmentYOUR_ENV) index_name huxley-pdf-index # 创建索引 vector_store Pinecone.from_documents(chunks, embeddings, index_nameindex_name) # 加载已有索引 vector_store Pinecone.from_existing_index(index_name, embeddings)缓存机制为相同的文档和问题添加缓存避免重复计算节省成本和时间。可以使用langchain.cache配合SQLiteCache或RedisCache。from langchain.cache import SQLiteCache import langchain langchain.llm_cache SQLiteCache(database_path.langchain.db)异步处理对于耗时的文档解析和索引构建可以使用asyncio或任务队列如Celery在后台处理避免阻塞Web请求。6. 常见问题排查与实战技巧在实际开发和使用的过程中你肯定会遇到各种问题。这里我总结了一份“避坑指南”。6.1 问题排查速查表问题现象可能原因解决方案上传PDF后无反应或报错1. PDF是扫描件图片2. PyMuPDF读取权限问题3. 文件损坏1. 使用OCR工具如pytesseract先转换或换用pdfplumber尝试。2. 确保文件路径正确有读取权限。3. 尝试用其他PDF阅读器打开确认文件完好。处理大型PDF时内存溢出一次性加载整个PDF到内存1. 使用PyPDFLoader的lazy_load模式如果支持。2. 增加文本分割的chunk_size减少块数量。3. 升级服务器内存或使用流式处理库。AI回答“我不知道”或胡言乱语1. 检索到的文本块不相关2. Prompt设计不佳3. LLM温度参数过高1. 调整search_kwargs{k: 4}中的k值增加检索数量尝试不同的相似度算法如similarity_score_threshold。2. 优化Prompt明确指令如“严格基于上下文回答”。3. 降低temperature如设为0.1。回答不包含具体细节或页码检索时未保留元数据或Prompt未要求引用1. 确保split_documents时add_start_indexTrue。2. 在Prompt模板中加入“请引用原文中的具体语句”的要求。3. 使用return_source_documentsTrue并前端展示来源。Streamlit应用运行缓慢1. 每次交互都重新计算索引2. 未使用session_state缓存1. 将vector_store、processed_file_name等存入st.session_state。2. 使用st.cache_resource装饰器缓存Embedding模型和LLM实例。OpenAI API报错认证、限额1. API密钥错误或过期2. 达到速率或使用限额1. 检查密钥是否正确是否有余额。2. 在OpenAI控制台查看使用情况考虑升级套餐或添加付款方式。6.2 提升问答质量的实战技巧预处理是关键垃圾进垃圾出。上传前尽量使用Adobe Acrobat或在线工具优化PDF确保文本可选中。对于扫描件pytesseractpdf2image是可行的本地OCR方案但准确率是挑战。分块策略的艺术没有放之四海而皆准的chunk_size。对于技术手册chunk_size800可能不错对于小说chunk_size1500可能更好。重叠overlap非常重要通常设置为chunk_size的10%-20%能有效防止关键信息被割裂。Prompt工程微调LangChain默认的Prompt可能不够强。你可以自定义一个更详细的Prompt模板来提升效果from langchain.prompts import PromptTemplate custom_prompt PromptTemplate( input_variables[context, question], template你是一个严谨的文档分析助手。请严格根据以下提供的上下文内容来回答问题。如果上下文中的信息不足以回答问题请直接说“根据文档无法回答此问题”不要编造信息。 上下文 {context} 问题{question} 基于上下文的答案 ) # 在创建QA链时指定prompt qa_chain RetrievalQA.from_chain_type( llmllm, chain_typestuff, retrieverretriever, chain_type_kwargs{prompt: custom_prompt}, # 传入自定义prompt return_source_documentsTrue, )混合搜索策略单纯基于向量的语义搜索有时会漏掉精确的关键词匹配。可以结合传统的关键词搜索如BM25和向量搜索进行加权融合这就是“混合搜索”能兼顾语义相关性和字面匹配度。Weaviate等向量数据库原生支持此功能。让答案“有据可查”在界面中展示答案引用的源文本片段和页码能极大增加用户信任度。这需要你在分割文档时保留元数据如页码并在检索时返回。这个项目从技术上看是当前AI应用开发模式的一个经典缩影。它验证了一个想法利用现有的强大基础模型LLM结合领域特定的数据你的PDF通过精巧的工程化管道RAG就能快速构建出解决实际问题的智能工具。整个过程里最耗时的往往不是写代码而是调试分块策略、优化Prompt、解决各种依赖和环境问题。但当你看到它能从一份复杂的文档中准确找出你要的条款时那种成就感是非常实在的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2581018.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;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…