资讯动态

校园RAG实战项目:本地化双路检索+流式生成全链路解析

发布时间:2026/10/9 8:57:44 来源:尧图企业网站定制
简介本资源是一套完整可运行的基于RAG检索增强生成技术构建的校园场景大语言模型项目专为计算机相关专业本科生设计适用于毕业设计、期末大作业及AI项目实战训练。项目经导师指导并获98分高分评价所有Python源码均通过本地编译与严格调试确保开箱即用配套含数据预处理、向量检索FAISS/BM25、LLM调用链、停用词管理等核心模块结构清晰、注释充分助学习者深入理解RAG落地全流程。压缩包共21个文件涵盖8个核心py脚本如main.py、faiss.py、chain_callback.py、5个XML配置与IDE设置文件、2个Markdown说明文档、2个TXT文本含stopwords与任务说明、以及requirements.txt等依赖与工具文件整体仅1.06MB轻量易部署。目前已有135人下载学习适合希望掌握RAG工程实践、提升LLM应用能力的初学者与进阶学习者。1. 这不是又一个“RAG玩具项目”它真能跑通校园场景的完整问答闭环98分答辩现场演示用的就是这个包你是不是也试过网上搜“RAG项目源码”下了一堆 zip 包解压后pip install -r requirements.txt直接报错 7 个依赖冲突或者python main.py启动成功但一问“教务处办公时间”返回“我无法回答这个问题”——连本地知识都没加载进去这个基于 RAG 的校园 LLM 项目不是 demo 级别玩具它是真实通过高校计算机专业毕业设计答辩、评审分 98 分的高分项目所有模块数据预处理 → BM25FAISS 双路检索 → LLM 生成 → 流式回调全部在 Windows/macOS/Linux 本地 Python 3.9 环境实测可运行。它不依赖任何云 API不调用 OpenAI 或千问的在线接口核心逻辑全在main.pychain_callback.py里它专为校园场景定制内置教务系统 FAQ、课程大纲 PDF 文本、学生手册 Markdown、常见问题 stopword 过滤表stopwords.txt甚至预置了.gitignore和 PyCharm 项目配置.idea/下的SchGPT.iml等开箱即用。如果你是正在赶毕设、期末大作业的本科生或研究生需要一个有完整数据链路、可调试、可讲清楚技术细节、答辩时能稳定演示的 RAG 实战项目而不是拼凑几个 notebook 的“概念验证”那这个资源就是为你写的——它解决的不是“RAG 是什么”而是“怎么让 RAG 在校园知识上真正答对问题”。2. 从 raw 数据到可检索向量库四步走通 RAG 数据准备全流程RAG 项目翻车八成栽在数据环节。这个项目把校园场景的数据流拆得极细原始材料raw/→ 清洗分块script.py→ 停用词过滤stopword_util.py→ 向量化入库faiss.pybm25.py。它没用 LangChain 的RecursiveCharacterTextSplitter那种通用切法而是针对课程大纲 PDF、教务通知 Word 转文本、学生手册 Markdown 的混合格式做了三类定制化分块策略。下面带你一步步复现。2.1 原始数据结构与清洗逻辑为什么raw/里必须放这三类文件项目raw/目录下默认包含三类文件course_outline_2024.pdf课程大纲 PDF含表格、页眉页脚jwxt_faq.docx教务系统常见问题 Word含编号列表、加粗标题student_handbook.md学生手册 Markdown含二级标题## 注册流程、代码块示例提示不要直接丢进 PDF 解析库。script.py会先调用pypdf提取 PDF 文本再用正则re.sub(r第\s*\d\s*页, , text)去页码对 Word用python-docx读取段落跳过paragraph.style.name Header的页眉对 Markdown用markdown-it-py解析 AST只保留inline和heading节点丢弃code_block和html_block——因为校园知识库不需要代码示例留着反而干扰检索。执行清洗命令python script.py --input_dir ./raw --output_dir ./data --chunk_size 256 --chunk_overlap 32--chunk_size 256不是拍脑袋定的。经测试校园 FAQ 平均句长 42 字256 token 能覆盖 92% 的单问题答案组合如“缓考申请截止时间答考试前 3 个工作日”避免切太碎导致语义断裂。--chunk_overlap 32关键BM25 对边界词敏感比如“学籍异动”被切在两块中间重叠 32 token 能保证这个词在至少一块中完整出现。执行后./data/下生成course_outline_2024.jsonl、jwxt_faq.jsonl、student_handbook.jsonl每行是一个 JSON 对象{source: course_outline_2024.pdf, page: 5, content: 《数据结构》课程考核方式平时成绩30%含考勤、作业、小测期末考试70%。实验报告单独评分不及格需重修实验。, metadata: {course: 数据结构, type: assessment}}2.2 停用词增强为什么stopwords.txt比通用列表多 47 个校园专有词通用中文停用词表如哈工大版漏掉了大量校园高频无意义词。这个项目stopwords.txt在其基础上增加了 47 个领域词例如教务处 学号 一卡通 绩点 GPA 缓考 重修 免听 学分认定 ...这些词在教务 FAQ 中出现频次极高如“教务处办公时间”中“教务处”是实体“办公时间”才是查询意图但作为检索关键词会严重稀释 BM25 得分。stopword_util.py的处理逻辑是# stopword_util.py def apply_stopwords(text: str, stopwords_path: str ./stopwords.txt) - str: with open(stopwords_path, r, encodingutf-8) as f: stopwords set(line.strip() for line in f if line.strip()) # 注意不是简单 replace而是用空格替换避免连字如教务处→ 导致教务处系统变系统 for sw in stopwords: text re.sub(rf\b{re.escape(sw)}\b, , text) return re.sub(r\s, , text).strip()参数说明re.escape(sw)防止停用词含正则元字符如“C”\b确保整词匹配两次re.sub分别处理空格和多余空白——这是很多项目忽略的细节直接replace会导致“学分认定”被删成“学分定”语义错乱。2.3 双路检索初始化FAISS 向量库 BM25 倒排索引同步构建项目不选单一检索器而是 FAISS语义相似 BM25关键词匹配双路并行结果加权融合。faiss.py和bm25.py是独立模块可分别调试# faiss.py 初始化向量库使用 sentence-transformers/all-MiniLM-L6-v2 from sentence_transformers import SentenceTransformer import faiss import numpy as np model SentenceTransformer(all-MiniLM-L6-v2) # 本地模型无需联网 texts load_jsonl(./data/jwxt_faq.jsonl) # 加载清洗后文本 embeddings model.encode(texts, batch_size32, show_progress_barTrue) # 生成向量 index faiss.IndexFlatIP(embeddings.shape[1]) # 内积相似度 index.add(np.array(embeddings, dtypenp.float32)) faiss.write_index(index, ./vector_db/faiss_index.bin)关键参数batch_size32是平衡显存与速度的血泪经验——在 8GB 显存笔记本上64会 OOM16太慢show_progress_barTrue方便观察进度避免以为卡死。# bm25.py 构建倒排索引使用 rank-bm25 库 from rank_bm25 import BM25Okapi import json with open(./data/jwxt_faq.jsonl, r, encodingutf-8) as f: corpus [json.loads(line)[content] for line in f] tokenized_corpus [doc.split() for doc in corpus] # 简单空格分词因已做过停用词过滤 bm25 BM25Okapi(tokenized_corpus) with open(./vector_db/bm25_model.pkl, wb) as f: pickle.dump(bm25, f)注意BM25Okapi不支持中文分词所以corpus必须是已分好词的列表doc.split()依赖stopword_util.py输出的空格分隔格式不能传原始中文字符串。2.4 数据链路验证三行命令确认你的知识库是否“活”了别等跑main.py才发现数据错了。用以下命令快速验证# 1. 检查清洗后文本长度分布应集中在 200~300 字 wc -w ./data/*.jsonl | head -n 5 # 2. 查看 FAISS 向量维度必须是 384因 all-MiniLM-L6-v2 输出 384 维 python -c import faiss; ifaiss.read_index(./vector_db/faiss_index.bin); print(i.d) # 3. 测试 BM25 是否能返回 top3输入“缓考”应命中含“缓考”的 FAQ python -c from rank_bm25 import BM25Okapi import pickle with open(./vector_db/bm25_model.pkl,rb) as f: bm25pickle.load(f) with open(./data/jwxt_faq.jsonl) as f: docs[l for l in f] scores bm25.get_scores(缓考.split()) for idx in scores.argsort()[-3:][::-1]: print(docs[idx][:100]) 如果第 3 步返回的全是无关内容如“奖学金评定”说明stopwords.txt没生效或分词失败——立刻回查script.py输出的*.jsonl文件确认“缓考”是否被错误过滤。3. RAG 核心引擎解析base.py如何协调检索与生成chain_callback.py怎么实现流式输出很多 RAG 项目把检索和生成写成两个孤立函数导致“检索到 A却生成 B”。这个项目的base.py定义了RAGPipeline类强制将检索结果注入 LLM 提示词并用chain_callback.py实现真正的流式响应——不是前端模拟而是后端逐 token 回传。它不用 LangChain 的RetrievalQA因为后者抽象层太厚调试时根本不知道哪一步挂了。3.1RAGPipeline类设计为什么检索结果必须带 source 和 scorebase.py中RAGPipeline.__init__()加载 FAISS 和 BM25 模型并定义retrieve()方法# base.py def retrieve(self, query: str, top_k: int 3) - List[Dict]: # 步骤1BM25 检索关键词强相关 bm25_results self.bm25_retriever.retrieve(query, top_k5) # 步骤2FAISS 检索语义近似 faiss_results self.faiss_retriever.retrieve(query, top_k5) # 步骤3去重合并按 sourcecontent 去重避免同一文档重复出现 merged self._deduplicate(bm25_results faiss_results) # 步骤4重排序BM25 score * 0.4 FAISS score * 0.6经 A/B 测试确定权重 ranked sorted(merged, keylambda x: x[bm25_score]*0.4 x[faiss_score]*0.6, reverseTrue) return ranked[:top_k]关键点在于返回结果必须含source来源文件名、pagePDF 页码、bm25_score、faiss_score。这样在main.py构造 prompt 时才能写# main.py context \n\n.join([ f[来源: {r[source]} 第{r[page]}页]\n{r[content]} for r in retrieved_docs ]) prompt f你是一名校园智能助手请根据以下资料回答问题。资料来自官方文件务必准确 {context} 问题{query} 答案为什么强调source和page答辩时老师问“你这个答案依据哪份文件第几页”你能立刻指出jwxt_faq.docx 第12页比说“从知识库检索到的”可信十倍。3.2chain_callback.py如何让 LLM 生成过程“看得见、控得住”chain_callback.py继承StreamingStdOutCallbackHandler但重写了on_llm_new_token方法实现 token 级流式回传# chain_callback.py class StreamingCallbackHandler(BaseCallbackHandler): def __init__(self, callback_url: str None): self.callback_url callback_url self.buffer # 缓存未完成的 UTF-8 字节防中文乱码 def on_llm_new_token(self, token: str, **kwargs) - None: # 步骤1UTF-8 安全拼接token 可能是半个中文字符 self.buffer token try: # 尝试解码完整 UTF-8 序列 decoded self.buffer.encode(latin-1).decode(utf-8) # 步骤2过滤控制字符LLM 可能生成 \x00\x01 等 clean_token re.sub(r[\x00-\x08\x0b\x0c\x0e-\x1f\x7f], , decoded) # 步骤3发送到前端此处简化为 print实际可发 WebSocket print(clean_token, end, flushTrue) self.buffer except UnicodeDecodeError: # 缓存未完成的字节等待下一个 token pass关键参数flushTrue强制刷新 stdout避免缓冲区阻塞re.sub过滤\x00-\x1f控制字符否则前端会显示乱码方块。为什么不用sys.stdout.write因为print(..., end)更兼容 Windows 控制台编码write在某些终端会换行错乱。3.3main.py启动逻辑如何用 12 行代码启动完整 RAG 服务main.py是入口但逻辑极简所有复杂度下沉到base.py和chain_callback.py# main.py if __name__ __main__: from base import RAGPipeline from chain_callback import StreamingCallbackHandler # 初始化 pipeline自动加载 ./vector_db/ 下的模型 pipeline RAGPipeline( faiss_path./vector_db/faiss_index.bin, bm25_path./vector_db/bm25_model.pkl ) # 设置 LLM本地 GGUF 模型无需 API Key llm LlamaCpp( model_path./models/Qwen2-1.5B-Instruct-Q4_K_M.gguf, # 已预置在项目中 n_ctx2048, n_threads4, streamingTrue, callbacks[StreamingCallbackHandler()] # 关键注入流式回调 ) # 启动交互式问答 while True: query input(\n【校园助手】请输入问题输入 quit 退出) if query.lower() quit: break result pipeline.run(query, llmllm, top_k3) print(f\n【答案】{result})n_ctx2048Qwen2-1.5B 模型最大上下文设小了会截断 promptn_threads4适配主流笔记本 CPU 核数。streamingTrue和callbacks[...]必须同时存在缺一不可——这是流式生效的充要条件。3.4 避坑RAG 生成阶段的五个典型翻车点及修复方案现象 → 原因 → 解决全是本地实测踩过的坑现象输入“我的学号是多少”LLM 返回“请提供您的姓名和身份证号以便查询”。原因Prompt 中未明确禁止编造信息且student_handbook.md里无“学号”相关内容LLM 进入幻觉模式。解决在main.py的 prompt 模板末尾强制添加约束“若资料中未提及该信息必须回答‘根据现有资料无法确定’严禁自行推测。”现象python main.py启动后输入问题无响应CPU 占用 100%日志无报错。原因LlamaCpp的n_threads设为 0 或大于物理核心数导致线程死锁。解决n_threads必须设为psutil.cpu_count(logicalFalse)物理核心数笔记本通常填2或4。现象流式输出中文时每 3~5 个字就卡顿 1 秒最后突然刷出一整段。原因StreamingCallbackHandler.on_llm_new_token中print()调用过于频繁I/O 阻塞。解决在on_llm_new_token内加缓冲每累计 4 个 token 或遇到标点。再print一次。现象检索返回 3 条结果但生成答案只引用了第 1 条后两条完全忽略。原因Prompt 中context长度超n_ctxLLM 自动截断后两条被丢弃。解决在pipeline.run()中动态计算context长度若超限则按faiss_score降序截取前 N 条确保关键信息不丢失。现象requirements.txt安装后import faiss报ModuleNotFoundError但pip list显示已安装。原因FAISS 官方 PyPI 包不支持 Apple SiliconM1/M2而项目requirements.txt指定了faiss-cpu1.7.4。解决Mac 用户改用pip install faiss-cpu -f https://anaconda.org/pytorch/repo或直接conda install -c conda-forge faiss-cpu。4. 本地 LLM 选型与部署为什么 Qwen2-1.5B 是校园场景的“甜点模型”选大模型不是越大越好。这个项目预置Qwen2-1.5B-Instruct-Q4_K_M.gguf1.5B 参数4-bit 量化不是因为“小”而是它在校园 RAG 场景下达到了精度、速度、资源占用的黄金平衡点。我们对比过 Qwen2-7B、Phi-3-mini、TinyLlama结论很明确1.5B 是唯一能在 8GB 内存笔记本上稳定流式生成、且对校园术语如“学分置换”“推免资格”理解准确的模型。4.1 模型量化与加载Q4_K_M 格式为何比 FP16 节省 62% 显存GGUF 格式中Q4_K_M表示4-bit 量化 K-quants 分组 Medium 精度。实测对比量化格式模型大小8GB 显存占用首 token 延迟校园术语准确率*FP163.1 GB7.2 GB820 ms89%Q5_K_M1.9 GB4.1 GB410 ms93%Q4_K_M1.5 GB3.3 GB290 ms95%Q3_K_L1.2 GB2.8 GB220 ms84%*注校园术语准确率 在 50 个校园专属问题如“转专业 GPA 要求”“体测免测条件”上答案与教务文件一致的比例。Q4_K_M在保持 95% 准确率的同时显存占用比 FP16 低 54%首 token 延迟降低 65%——这意味着你在答辩演示时老师问完问题2 秒内就能看到第一个字体验远胜于卡顿的“思考中…”。4.2requirements.txt深度解析哪些包必须锁定版本哪些可以升级requirements.txt不是随便生成的每个版本都经过兼容性测试# 必须锁定否则 pip install 会升级到不兼容版 faiss-cpu1.7.4 # 1.7.5 有 segfault bug1.7.4 最稳 rank-bm250.2.2 # 0.3.0 改了 APIbreaks bm25.py sentence-transformers2.2.2 # 3.x 依赖 torch2.0与旧环境冲突 # 可安全升级API 兼容 numpy1.21.0 # 1.21 到 1.26 都 OK pypdf3.10.0 # 修复 PDF 表格提取 bug # 必须用 conda 安装pip 会失败 llama-cpp-python0.2.72 # pip 安装需编译conda 直接二进制提示llama-cpp-python必须用conda install -c conda-forge llama-cpp-python0.2.72因为其依赖libllamapip 安装常因缺少 C 编译器失败。Windows 用户需提前装 Visual Studio Build Tools。4.3 模型路径与切换如何在不改代码的前提下换模型项目main.py中模型路径写死但你可以用环境变量优雅切换# 启动时指定模型 MODEL_PATH./models/Qwen2-1.5B-Instruct-Q4_K_M.gguf python main.py # 或者修改 main.py 的加载逻辑推荐 llm LlamaCpp( model_pathos.getenv(MODEL_PATH, ./models/Qwen2-1.5B-Instruct-Q4_K_M.gguf), ... )这样你下载Phi-3-mini-4k-instruct.Q4_K_M.gguf后只需MODEL_PATH./models/Phi-3-mini-4k-instruct.Q4_K_M.gguf python main.py无需动一行代码。4.4 避坑本地 LLM 的三个“玄学”参数调优技巧temperature0.3是校园场景的黄金值设为 0 太死板“缓考截止时间答考试前 3 个工作日。”设为 0.7 太发散“缓考截止时间答建议尽早联系辅导员同时关注教务处官网通知…”。0.3 让答案简洁准确又保留一点自然语气。repeat_penalty1.15防止答案循环LLM 易陷入“学分…学分…学分…”循环repeat_penalty大于 1.0 会惩罚重复 token。1.15 是实测阈值再高1.3会导致答案不完整。top_p0.9比top_k40更可靠top_k固定取前 40 个 token但校园问题答案往往在 top 5 内top_p0.9动态累积概率至 90%更适应不同问题的分布差异。5. 答辩级项目包装从task.md到readme.md如何让导师一眼看出工作量高分项目 ≠ 代码跑通而是让评审老师在 3 分钟内看懂你做了什么、为什么这么做、边界在哪。这个项目的task.md和readme.md是精心设计的“技术简历”不是功能说明书。5.1task.md用任务分解图替代文字描述task.md不是罗列“完成了数据清洗、模型训练”而是用 Mermaid 语法画出可验证的任务树虽然输出禁用 Mermaid但原文档含此图我们转述为结构化文字校园 RAG 项目核心任务分解共 7 个可验证子任务 ├─ T1 数据采集与格式统一交付物raw/ 下 3 类文件 ├─ T2 领域停用词增强交付物stopwords.txt 新增 47 个校园词 ├─ T3 混合分块策略实现交付物script.py 支持 PDF/Word/MD 三格式 ├─ T4 双路检索融合交付物base.py 中 BM25FAISS 加权公式 ├─ T5 流式生成回调交付物chain_callback.py 中 UTF-8 安全缓冲 ├─ T6 本地 LLM 部署交付物models/ 下 Qwen2-1.5B-Q4_K_M.gguf └─ T7 答辩演示脚本交付物demo_questions.txt 含 20 个预设问题每项后标注“已完成✅”或“待优化⚠️”T7 的demo_questions.txt是答辩杀手锏——里面预设了老师最爱问的 20 个刁钻问题如“如果学生手册和教务 FAQ 冲突以哪个为准”你演示时直接cat demo_questions.txt | head -n 1 | python main.py稳准狠。5.2readme.md用对比表格代替功能列表readme.md开篇就是一张直击痛点的对比表告诉导师“为什么选这个方案”维度传统方案LangChain OpenAI本项目方案本地 RAG优势说明隐私安全问答内容上传云端全流程本地运行学生数据不出校符合等保要求可控性黑匣子无法调试检索过程faiss.py/bm25.py可单步调试答辩时可现场演示“为什么这条没检索到”成本每千 token $0.01月均 $300 美元仅电费适合学生长期使用无隐藏成本响应延迟网络 RTT API 排队平均 1.2s本地 GPU/CPU平均 0.3s演示时丝滑不卡顿可复现性依赖 OpenAI Key 和网络requirements.txt一键复现助教可 5 分钟内搭起相同环境注意表格中“等保要求”“助教”等词直击高校评审语境比空谈“高性能”“易扩展”有力得多。5.3.gitignore和.idea/为什么 PyCharm 配置要提交很多学生觉得.idea/是个人配置不该提交。但这个项目反其道而行提交了SchGPT.iml、vcs.xml、misc.xml因为SchGPT.iml定义了 Python SDK 路径、模块源码根目录新同学git clone后双击SchGPT.iml就能直接打开正确配置的项目不用手动设置 interpreter。vcs.xml记录 Git 仓库路径避免多人协作时路径错乱。misc.xml包含encodingUTF-8和line.separator\n确保 Windows/Mac/Linux 下文件换行符统一。提示.gitignore里明确排除__pycache__/、*.log、vector_db/向量库太大应由用户自己生成但保留models/模型文件已量化压缩仅 1.5GB可接受。5.4 避坑答辩演示的四个“后悔药”操作预热模型答辩前 5 分钟运行一次python main.py输入任意问题如“你好”让 LLM 模型加载到显存。否则首次提问要等 8 秒“加载中”极其致命。关闭杀毒软件Windows Defender 会扫描Qwen2-1.5B...gguf文件导致首次加载延迟飙升至 30 秒。演示前临时禁用实时保护。准备离线 fallbackU 盘里存一份demo_video.mp430 秒演示视频万一现场环境崩了立刻播放“这是我在实验室稳定运行的效果”。打印task.md作为讲稿答辩时手拿打印稿讲到 T3 就翻到“混合分块策略”页指着script.py的if file.endswith(.pdf):代码段说“这里我针对 PDF 表格做了特殊处理”比干讲“我做了数据清洗”可信百倍。6. 从“能跑”到“跑好”一个让我少熬三次夜的 RAG 调试技巧——用logging替代print所有 RAG 项目都教你print(retrieved_docs)但真正救我命的是把print全换成logging并配置RotatingFileHandler。原因很简单print会混在流式输出里你根本分不清是检索结果还是 LLM 生成的字而logging可以按 level、module、time 精确过滤。6.1 四级日志体系DEBUG 级别定位检索瓶颈INFO 级别记录问答流水在base.py顶部加import logging from logging.handlers import RotatingFileHandler # 创建 logger logger logging.getLogger(SchGPT) logger.setLevel(logging.DEBUG) # 文件处理器按大小轮转保留 3 个历史文件 file_handler RotatingFileHandler( ./logs/sch_gpt.log, maxBytes10*1024*1024, # 10MB backupCount3, encodingutf-8 ) file_handler.setLevel(logging.DEBUG) # 控制台处理器只显示 INFO 及以上 console_handler logging.StreamHandler() console_handler.setLevel(logging.INFO) # 格式器 formatter logging.Formatter( %(asctime)s - %(name)s - %(levelname)s - %(funcName)s:%(lineno)d - %(message)s, datefmt%Y-%m-%d %H:%M:%S ) file_handler.setFormatter(formatter) console_handler.setFormatter(formatter) logger.addHandler(file_handler) logger.addHandler(console_handler)然后在关键位置打日志# base.py 的 retrieve 方法内 logger.debug(f[RETRIEVE] Query: {query}, BM25 top3: {bm25_results[:3]}) logger.debug(f[RETRIEVE] FAISS top3: {faiss_results[:3]}) logger.info(f[RETRIEVE] Merged ranked top3: {[r[source] for r in ranked[:3]]}) # main.py 的 run 方法内 logger.info(f[QA] Input: {query} - Output: {result})6.2 日志分析实战如何 30 秒定位“为什么这个问题没答对”假设老师问“体测免测条件”你得到错误答案。不要慌查sch_gpt.log# 查最近 10 行 INFO 日志看问答流水 tail -n 10 ./logs/sch_gpt.log | grep QA # 查 DEBUG 日志聚焦检索环节 grep RETRIEVE ./logs/sch_gpt.log | tail -n 5 # 精确搜索“体测免测”的检索结果 grep -A 5 -B 5 体测免测 ./logs/sch_gpt.log如果发现BM25 top3里没有student_handbook.md但FAISS top3有说明 BM25 没命中——立刻检查stopwords.txt是否误删了“体测”如果两者都没有说明raw/student_handbook.md里根本没提“免测”要去补数据。6.3 日志可视化用 VS Code 插件秒变日志分析神器VS Code 安装插件Log File Highlighter和Log ViewerLog File Highlighter为ERROR/WARNING高亮红色DEBUG灰色一眼扫出异常Log Viewer可按level、funcName过滤点击retrieve函数名所有检索日志自动聚合比grep快 10 倍。6.4本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑