尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
本地RAG系统实战:基于LangChain、bge-m3与Chroma搭建离线知识库问答
做本地RAG这件事我是被一个很朴素的问题逼上路的团队里的产品文档、项目记录、技术方案散落在各个目录里想找一个半年前的结论翻聊天记录和共享盘翻到怀疑人生。数据传到在线问答平台又始终绕不开隐私这一关于是决定在本地机器上搭一套完全离线运行的检索增强生成系统。这套系统用LangChain作为编排框架串联整个处理链路bge-m3负责把中文文档和问题映射成高质量向量Chroma作为轻量级向量库完成存储和检索LLM选用本地模型保证问答生成不依赖外网最后用Gradio快速搭出一个浏览器问答界面。整条链路数据不出本机项目源码可以直接参考复现。如果你是刚开始接触RAG的开发者或者正在为团队内部知识库发愁这篇文章就是为你准备的实操记录。1. 先拆解整体设计这套系统到底在做什么1.1 为什么选本地RAG而不是直接上在线平台在开始写代码之前先明确一个问题为什么不直接把文档丢给大模型做长上下文问答原因很简单文档数量和长度决定了大模型上下文窗口不可能无限扩展几份几十页的文档还能硬塞一旦到了上百份文档直接拼接的结果就是又慢又贵而且准确率断崖式下降。RAG的核心思路是先检索、后生成——每次问答时只把和问题最相关的几个片段喂给大模型既控制成本又提升答案准确性。本地部署的另一个决定性因素是隐私。团队内部文档往往包含未公开的功能规划、客户沟通细节把这些内容传到外部服务就意味着数据合规风险不可控。全本地部署之后文档和向量数据全部留在自己的机器上模型推理也在本地完成天然满足数据不出内网这个约束。再加上网络不稳定的时候在线接口的延迟和限流会直接卡死体验本地模型虽然效果略弱一些但胜在稳定可控。这个方案的适用场景非常明确企业内网知识库、个人笔记库问答、离线环境下的文档检索、需要对提示词和检索流程做深度定制的场景。不适用的情况也有比如你需要最强生成能力并且数据不敏感那直接使用在线大模型API会省很多事。1.2 五大组件的分工与协作这套系统的五个组件各管一段职责非常清晰。组件职责类比LangChain编排整个处理流程管理文档加载、分割、提示词、链路组装项目经理bge-m3把自然语言文本转换成语义向量翻译官Chroma向量存储与相似度检索档案库管理员LLM基于检索到的上下文生成最终回答写手Gradio提供浏览器交互界面前台接待LangChain在这套架构里的作用容易被低估。很多人觉得RAG核心是模型和向量库但实际上链路的稳定性、可维护性全靠编排层。文档加载、文本分割、向量化、检索、提示词组装、输出解析任何一个环节脱节整个系统就废了。LangChain的价值在于把这些环节抽象成统一接口替换某个组件不需要重写其余代码。比如今天用Chroma明天想换成别的向量库只需要改初始化那几行。bge-m3和Chroma是一对黄金搭档。bge-m3生成的向量质量直接决定检索结果准不准Chroma则负责在收到查询向量后快速返回最相似的文档块。这里有一个容易被忽略的点bge-m3输出的向量维度是1024维而很多英文场景常用的模型是384或768维选向量库的时候要确认它支持这个维度Chroma没有这个限制这也是我选它的重要原因。LLM放在本地运行意味着完全离线可用。虽然生成能力相比超大在线模型有差距但配合检索到的精准上下文回答质量在实际使用中完全够用。Gradio把整个过程封装成一个网页输入问题、点击回车、得到带引用来源的回答体验和在线产品没太大区别。1.3 一次问答背后的完整链路我来走一遍完整的问答流程。你输入我们之前的发布流程规范是什么这个问题之后系统内部经历五个步骤。第一步问题理解与向量化。bge-m3把我们之前的发布流程规范是什么转换成一个1024维的向量。这个向量的语义空间里它和发布流程规范文档上线步骤这些概念的距离都比较近。第二步向量检索。Chroma在向量库里搜索找出与查询向量余弦相似度最高的K个文档块。这里K就是top_k参数默认我设置的是4意味着每次只取最相关的4个片段作为上下文依据。第三步上下文组装。LangChain把这4个文档块的原文内容按顺序拼接起来再配合系统提示词和用户问题生成完整的Prompt。第四步模型推理。本地LLM拿到Prompt之后根据上下文片段生成回答。因为上下文是检索出来的真实文档模型的生成被牢牢限制在文档内容范围内幻觉明显减少。第五步结果输出。Gradio把答案渲染到聊天窗口整个过程通常在几秒内完成取决于机器性能。这个流程看起来简单但每一步都有不少坑。比如文本分割的大小怎么定、top_k设多少合适、向量模型需不需要归一化、提示词怎么写才能让模型只看文档不瞎编。这些细节会在后面的章节逐个展开。2. 关键技术点决定系统成败的细节都在这里2.1 文档加载不同格式资料如何统一处理RAG的第一步是喂数据但你手里的资料大概率不是统一格式。我的实践项目里就有Markdown文档、纯文本笔记、PDF产品手册三种格式如果还有Word文档或者表格情况更复杂。LangChain的文档加载器把不同格式统一转换为Document对象。Document对象包含两个核心字段page_content是文档正文metadata里可以放来源路径、页码、标题等信息。我在项目里用的是DirectoryLoader按目录批量加载再配合PyPDFLoader单独处理PDF。这里有一个关键设计做多格式处理时建议把metadata记录下来后面检索到某个片段时用户能看到这个片段来自哪个文件这对结果的可信度提升很大。我踩过的坑是编码问题。很多Windows环境生成的文本文件是gbk编码默认UTF-8读取会直接报错或者读出来是乱码。加载文本的时候务必要显式指定编码或者用chardet这类工具先探测文件编码。另外PDF加载对扫描件无能为力除非额外接OCR链路但那是另一个复杂度级别本文暂时不涉及。2.2 文本分割chunk_size不是随便拍的文档加载完后是一整块长文本直接向量化的话一个几万字的文档变成了一个向量检索精度基本等于零。这里就引出一个关键工程问题怎么把文档切成合适的片段。我推荐的是RecursiveCharacterTextSplitter它按照换行符、句号、分号、字符的优先级递归切分尽量保证语义完整性。chunk_size决定每个片段的字符数chunk_overlap决定相邻片段之间重叠多少个字符。我最初用的是业界常见的chunk_size1000, chunk_overlap200但实测中文场景下效果一般。中文信息密度比英文高同样的向量维度下1000个中文字符蕴含的信息量远超1000个英文字符检索时容易引入无关内容。后来我把参数调整为chunk_size512, chunk_overlap64检索精度明显提升。这里给一个经验值中文文档使用512到768的chunk_size比较合适如果文档逻辑段落很短甚至可以调到256。overlap设置64到128足够过大反而会让多个检索结果高度重复浪费上下文空间。实际测试中还有一个容易被忽略的点如果文档里有代码块或者表格文本分割很容易把它们拦腰截断导致检索出来的片段语义残缺。解决办法是在分割之前做一步预处理把代码块和表格单独提取出来或者用自定义分隔符列表把行内代码也纳入分割特征。2.3 选型bge-m3的核心理由嵌入模型的选择是整个系统里影响检索效果最关键的变量之一。实际用过几个主流模型之后我把bge-m3确定为首选。中文语义理解能力是第一个理由。bge-m3在中文语料上经过了充分的预训练对中文的同义词、句式变化、领域术语的理解明显好于通用英文模型。我实测过同一个问题在不同模型下的检索结果bge-m3返回的片段相关性最稳定。第二个理由是bge-m3支持8192个token的长文本处理这意味着即使某段业务文档比较长也能整体编码而不丢失上下文信息。配合前面说的文本分割即使分割后单个片段仍然较长模型也能完整编码。第三个理由是归一化习惯。使用bge-m3时必须要设置normalize_embeddingsTrue让向量进行L2归一化。归一化之后向量之间的内积等价于余弦相似度Chroma的检索结果会更有区分度。很多人忽略这一步导致检索分数全部堆在一个很小的区间里排序不稳定。还有一个细节bge-m3的模型体积较大首次下载需要几个GB的存储空间。如果你的机器磁盘紧张可以考虑用轻量级替代方案但效果会有明显差距。我的建议是只要磁盘和显存允许优先选择bge-m3。2.4 向量库持久化与LLM接入的衔接向量库承担着记忆的职责——文档向量化之后存储在这里下次系统启动时直接加载不需要重新处理原始文档这个机制依赖Chroma的持久化能力。我在项目里使用persist_directory参数指定持久化目录向量数据写入本地磁盘。系统重启后只需要连接这个目录就能恢复向量库完全跳过重复切分和向量化过程。实践中的一个建议是索引构建脚本和问答脚本分开写。索引脚本负责加载文档、分割、向量化、写入向量库按需执行问答脚本启动时只加载已有向量库。这样可以避免每次启动都重建索引节省大量时间。LLM接入我采用的是本地模型方案。本地推理的工具选择很多比较省心的是用Ollama拉起服务再通过LangChain的Ollama包装器连接。我选的是一个7B参数量的中文模型量化版本显存占用在6G到8G之间普通消费级显卡就能跑。如果机器没有独立显卡纯CPU推理也能用只是单次回答会慢一些。这里提醒一下首轮推理时模型需要加载到内存或显存速度会明显变慢后面就稳定了。如果你手头有在线API的访问权限也可以替换Ollama为客户端的ChatOpenAI只需要改一处初始化代码和对应的base_url、api_key配置。LangChain统一抽象的好处就在这。3. 实操记录从零到一跑通整套系统3.1 环境准备与依赖安装本次实操基于Python 3.10环境需要先准备这些依赖包langchain langchain-community langchain-chroma langchain-huggingface sentence-transformers chromadb gradio pypdf安装命令很简单pip install langchain langchain-community langchain-chroma langchain-huggingface sentence-transformers chromadb gradio pypdf这里的版本兼容问题值得说一句。LangChain迭代非常快API变动频繁我不建议全部无脑装最新版。实操时选择一套经过验证的版本组合然后锁死在requirements.txt里。如果你用的版本比我新A类API可能被移动到其他包中。导入方式也要注意from langchain_huggingface import HuggingFaceEmbeddings from langchain_chroma import Chroma from langchain_community.document_loaders import DirectoryLoader在旧版本中这些模块有的位于langchain.embeddings或langchain.vectorstores新版已经拆分到独立包中混用会直接报ImportError。如果你打开别人的老项目第一件事就是检查导入路径。3.2 项目目录结构规划我建议按这样的结构组织项目local_rag/ ├── docs/ # 原始文档存放目录 │ ├── product_manual.md │ ├── api_doc.pdf │ └── meeting_notes.txt ├── chroma_db/ # 向量库持久化目录 ├── config.py # 全局配置 ├── build_index.py # 索引构建脚本 ├── rag_chain.py # RAG问答主流程 ├── app.py # Gradio界面入口 └── requirements.txt # 依赖锁定为什么要单独拆build_index.py因为索引构建和问答是两个生命周期完全不同的任务索引可能每周重建一次问答是持续进行的在线服务。分开写让整个流程边界清晰调试也方便。实际使用中我发现如果哪天你换了一版文档只需要重新跑一遍build_index.py问答侧什么都不用动。3.3 索引构建脚本源码解析先看配置文件# config.py from pathlib import Path # 原始文档目录 DOC_DIR Path(./docs) # 向量库持久化目录 PERSIST_DIR Path(./chroma_db) # 向量模型 EMBEDDING_MODEL BAAI/bge-m3 # 文本分割参数 CHUNK_SIZE 512 CHUNK_OVERLAP 64 # 检索参数 TOP_K 4 SEARCH_SCORE_THRESHOLD 0.5这里推荐用配置文件集中管理所有参数而不是散落在各个脚本里。调参的时候只改一处系统其余部分自动生效。接下来是索引构建的核心逻辑# build_index.py from pathlib import Path from config import DOC_DIR, PERSIST_DIR, EMBEDDING_MODEL, CHUNK_SIZE, CHUNK_OVERLAP from langchain_community.document_loaders import DirectoryLoader from langchain_text_splitters import RecursiveCharacterTextSplitter from langchain_huggingface import HuggingFaceEmbeddings from langchain_chroma import Chroma def load_documents(): # 按目录加载常见的文本和Markdown文件 loader DirectoryLoader( str(DOC_DIR), glob**/*.md, show_progressTrue, use_multithreadingTrue, loader_kwargs{encoding: utf-8}, ) docs loader.load() # 补充加载PDF文件 pdf_loader DirectoryLoader( str(DOC_DIR), glob**/*.pdf, show_progressTrue, use_multithreadingTrue, ) pdf_docs pdf_loader.load() return docs pdf_docs def split_documents(docs): splitter RecursiveCharacterTextSplitter( chunk_sizeCHUNK_SIZE, chunk_overlapCHUNK_OVERLAP, separators[\n\n, \n, 。, , , ;, ;, , ], keep_separatorTrue, ) return splitter.split_documents(docs) def build_index(): print( 加载文档) docs load_documents() print(f 共加载 {len(docs)} 个文档) print( 分割文本) chunks split_documents(docs) print(f 共切分为 {len(chunks)} 个片段) print( 初始化向量模型) embeddings HuggingFaceEmbeddings( model_nameEMBEDDING_MODEL, encode_kwargs{normalize_embeddings: True}, ) print( 构建向量库并持久化) vector_store Chroma.from_documents( documentschunks, embeddingembeddings, persist_directorystr(PERSIST_DIR), ) print(f 向量库已保存至 {PERSIST_DIR}) if __name__ __main__: build_index()这里的几个细节值得关注。loader_kwargs{encoding: utf-8}不是可选项而是必填项否则碰到gbk编码的txt文件直接抛异常。separators里我加入了中文标点符号让分割器优先在句子边界切断避免把一整段逻辑完整的内容劈成两半。normalize_embeddingsTrue被显式设置这个参数对检索稳定性的影响前面已经说过再次强调。如果你有Word文档需要处理可以额外引入Docx2txtLoader来加载思路完全相同在load_documents里再追加一个分支即可。3.4 RAG问答主流程源码解析问答脚本负责加载既有向量库、组装检索器和LLM链路# rag_chain.py from config import PERSIST_DIR, EMBEDDING_MODEL, TOP_K, OLLAMA_BASE_URL, OLLAMA_MODEL from langchain_huggingface import HuggingFaceEmbeddings from langchain_chroma import Chroma from langchain_community.llms import Ollama from langchain_core.prompts import ChatPromptTemplate from langchain_core.runnables import RunnablePassthrough from langchain_core.output_parsers import StrOutputParser def format_docs(docs): # 把检索到的Document列表拼成一整段上下文 return \n\n.join(doc.page_content for doc in docs) def init_vector_store(): embeddings HuggingFaceEmbeddings( model_nameEMBEDDING_MODEL, encode_kwargs{normalize_embeddings: True}, ) vector_store Chroma( persist_directorystr(PERSIST_DIR), embedding_functionembeddings, ) return vector_store def init_retriever(vector_store): return vector_store.as_retriever( search_typesimilarity, search_kwargs{ k: TOP_K, score_threshold: 0.5, }, ) def build_rag_chain(): vector_store init_vector_store() retriever init_retriever(vector_store) llm Ollama( base_urlOLLAMA_BASE_URL, modelOLLAMA_MODEL, temperature0.1, num_ctx4096, ) template 你是一个严谨的文档问答助手。请仅根据以下资料片段回答问题不要引入资料之外的信息。 如果资料内容不足以回答问题请直接回答资料中未找到相关内容。 资料片段 {context} 问题{question} 请给出准确、简洁的回答 prompt ChatPromptTemplate.from_template(template) rag_chain ( {context: retriever | format_docs, question: RunnablePassthrough()} | prompt | llm | StrOutputParser() ) return rag_chainretriever | format_docs是LangChain的管道操作检索器返回的Document列表经过format_docs函数转换成纯文本再填入Prompt模板的{context}位置。num_ctx4096设置模型的上下文长度这个值要大于chunk_size乘以top_k否则检索到的内容超出模型能处理的窗口后边的片段会被截断。temperature0.1是我调好的值。问答场景追求的是忠实于文档不是创意发挥temperature设太高会导致模型自己胡编乱造。类似地提示词里明确写了不要引入资料之外的信息这是降低幻觉的最后一层保险。3.5 Gradio界面与启动最后一步把上面的链路包装成一个网页界面# app.py import gradio as gr from rag_chain import build_rag_chain # 初始化RAG链路 rag_chain build_rag_chain() def ask(question, history): if not question.strip(): return 请输入问题 try: answer rag_chain.invoke(question) return answer except Exception as e: return f系统异常{str(e)} def main(): with gr.Blocks(title本地知识库问答系统) as demo: gr.Markdown(# 本地知识库问答系统\n基于LangChain bge-m3 Chroma构建) chatbot gr.Chatbot(height500, label对话区域) msg gr.Textbox(label输入你的问题, placeholder例如我们之前的发布流程规范是什么, lines2) clear gr.ClearButton([msg, chatbot]) def respond(message, chat_history): history chat_history or [] answer ask(message, history) history.append((message, answer)) return , history msg.submit(respond, [msg, chatbot], [msg, chatbot]) demo.launch(server_name127.0.0.1, server_port7860, inbrowserTrue) if __name__ __main__: main()这里我用了新版Gradio的Blocks组件支持真正的多轮对话历史。如果你在别的地方看到的是旧版gr.Interface那是单轮问答的写法改造起来需要换一套逻辑。ClearButton用来一键清空对话记录。server_name127.0.0.1表示只在本机访问如果你需要局域网内其他机器访问改成0.0.0.0即可但要注意访问控制别暴露在不安全网络里。启动方式就两步先执行python build_index.py构建索引再执行python app.py打开界面。4. 运行效果、常见问题与调优心得4.1 首次运行与后续启动首次运行build_index.py时有几个阶段需要耐心等待。第一步是下载bge-m3模型权重几个GB的文件取决于网速。下载完成后模型的加载还需要一点时间。真正做向量化时如果机器没有GPUCPU处理几百个文本片段可能要几分钟到十几分钟这个阶段会看到进度条滚动不用着急。问答阶段的速度主要取决于LLM推理。GPU机器上7B模型量化版本一次生成大约1到3秒纯CPU机器可能要10秒以上。实际使用中我发现一个规律问题的检索耗时很稳定变化主要在生成阶段token数越多越耗时。4.2 高频问题排查速查表问题现象原因排查解决方案ImportError: cannot import name Chroma版本更新导致导入路径变化确认使用langchain_chroma包升级或固定依赖版本加载文件乱码或报编码错误文件是gbk编码在所有loader的loader_kwargs里指定encodingutf-8必要时先转码检索返回结果不相关chunk_size偏大或top_k不够调小chunk_size到512附近适当调大top_k再观察bge-m3下载极慢网络问题使用镜像源下载模型不同网络的方案差异很大回答总是说资料中未找到score_threshold设置过高把score_threshold降到0.4或者直接移除回答引用无关上下文chunk_overlap过大导致语义重叠缩小overlap到64并检查chunk_size是否过大Chroma启动后数据重复多次插入相同文档但未去重构建索引前检查持久化目录或使用ID稳定机制重建库GPU显存不足模型太大或上下文太长换用小尺寸量化模型或者调低num_ctx表格里的每一条我都实际遇到过。最典型的是score_threshold这个参数很多人不知道它会把低于阈值的检索结果全部过滤掉。如果阈值设成0.7而你的文档向量和问题向量本来就不太近那结果就是每次检索都返回空。我的建议是第一次搭建时不要设这个参数跑通之后再根据实际分数调整。你可以在检索器里打印出相似度分数再做因地制宜的设定。4.3 效果调优的几个小技巧基础版本跑通之后可以考虑以下几个方向做效果升级。第一个是检索增强。单纯依靠向量检索在关键词匹配上偶尔会漏掉重要片段。可以引入BM25文本检索与向量检索做一个混合召回用LangChain的EnsembleRetriever把两种检索器组合起来分数加权融合。实测混合检索在带专有名词、产品名、编号的文档里效果提升明显因为这类内容向量检索不一定识别得准。第二个是重排序。Chroma返回的top_k文档不一定按相关性严格排序可以接一个Reranker对检索结果二次打分。这会增加一些模型推理开销但对于答案质量要求高的场景非常值得。如果你准备用重排序top_k可以先设置在12到20重排序后取前4个这样效果最佳。第三个是提示词与输出结构优化。让模型在回答末尾以引用列表形式输出信息来源用户可以直接跳回原文检查。这个扩展的实现在Gradio界面上也不复杂只需要给Prompt模板加一个输出格式约束把格式说明写清楚然后在respond函数里解析返回的带引用格式文本。第四个是文档更新策略。如果知识库内容经常变化每次全量重建索引成本较高。可以配合文件名哈希或文档ID机制判断哪些文档变了、哪些是新增的只对变动文档重新向量化。Chroma支持按ID更新和删除这个能力在内容频繁更新的场景下非常有用。最后说两句实在话这套系统从搭建到稳定运行我前后改了三版。最开始的版本把所有代码堆在一个脚本里改一个参数要重新加载整个项目后来拆成索引构建和问答两条链路清爽多了。最大的感受是RAG的门槛不在概念而在工程细节。文本分割参数、向量归一化、检索阈值、prompt约束每一个看似不起眼的点都直接决定体验。建议你跑通之后再回头调参把每个参数的实际影响都亲手验证一遍比看多少篇文章都管用。如果后续想让系统更顺手可以再加一个文档管理面板直接在网页里上传文件和重建索引也可以给Gradio界面做用户隔离和访问控制多人协作时总得知道每个答案对应哪份知识库。按这个框架逐步扩展就好核心链路不用动。
RELATED

相关推荐

逻辑回归多分类实战:处理有序特征与类别不平衡的关键策略

逻辑回归多分类实战:处理有序特征与类别不平衡的关键策略

1. 先看清这个数据集再动手Car Evaluation 这个分类任务,我前前后后跑过好几遍。六列特征、不到两千条样本,光看体量会以为是个入门练手题,实际上它把所有典型问题都藏在小体积里了:类别严重偏斜、特征全是有序分类变量、标签之间…

📅 2026/10/17 7:29:19
从零制作VOC数据集:目标检测训练数据全流程指南

从零制作VOC数据集:目标检测训练数据全流程指南

不需要主标题,直接从二级标题开始。内容围绕项目标题展开,贴合领域专业调性。1. 动手前先弄懂:VOC数据集到底长什么样很多刚接触目标检测的朋友,第一次跑通训练脚本之后,都会遇到一个坎——想训练自己的模型&#xff0…

📅 2026/10/17 7:29:19
从涟漪到光束:波的原理、应用与现代驾驭技术全解

从涟漪到光束:波的原理、应用与现代驾驭技术全解

小时候在河边玩,往水里扔一块石头,波纹一圈一圈荡出去,当时只觉得好看。很多年后做跟光电、通信相关的工作,才意识到那其实是我第一次亲眼看见一种能量在空间里传递——涟漪不会把水分子推到岸边,但波纹能跨过整片水面…

📅 2026/10/17 7:29:19
MORE NEWS

更多资讯

📰

改进型永磁同步电机DTC仿真模型:滞环与SVPWM转矩脉动抑制对比

简介:一套面向电机控制研究人员与电气工程专业学生的永磁同步电机(PMSM)直接转矩控制(DTC)改进版Simulink仿真模型,涵盖从电机本体、转矩磁链估算到滞环控制器与逆变器开关逻辑的完整闭环结构。压缩包共包含…

📰

AI生成式美术与手工版画融合:ArtCraft文创落地全流程解析

做文创这行,最尴尬的不是没想法,而是想法到了落地环节全变味。我去年接手一个节气主题的明信片设计,AI生成的概念草图一张比一张惊艳,结果打印机一跑,边缘假滑得像个塑料玩具,纸张纹理全部丢失,…

📰

artcraft手作材料包全流程指南:从设计稿到量产售卖

最近常有人问我,artcraft到底是什么。说实话,它不是一个能一句话讲清楚的软件,也不是某个平台的固定栏目。artcraft是我给自己一堆手作实验起的项目代号,ar t 和 craft 拼在一起,听起来像“艺术手工”,但更…

📰

大模型微调过拟合怎么办?三招实战反过拟合方案

直接用一句话说完:大模型过拟合不是它笨,是你没给它“开卷考之外的新题”。这是我在多次微调实验里最强烈的感受——训练集准确率一路冲到99.8%,验证集却卡在71%,一翻训练日志,loss曲线优雅得近乎完美,可一…

📰

《artcraft》:以艺术与工艺为核心的建造游戏设计与技术解析

不需要过分解读这个标题,它的字面意思就是“艺术工艺”。我基于这个理解,把它当作一款独立游戏项目的名称来处理,围绕其核心玩法、技术实现和创作理念展开。以下为博文正文。1. 项目缘起:为什么想做一个“艺术工坊”式的建造游戏说…

📰

AI预审如何降低招投标投诉驳回率:规则引擎与大模型融合实践

1. 项目背景与核心需求拆解先交代一下背景。我上一阶段参与的某公司电子招投标平台改造项目,客户提出的核心诉求非常直接:把投标投诉材料被驳回的比例降下来。他们在业务复盘时发现,近一个季度提交的投诉件里有接近三分之一被监管端退回&…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬