用LLM构建可复现研究流水线:从文献调研到RAG知识库
用 LLM 做研究从“聊天问答”到“可复现研究流水线”在 Hacker News 的技术讨论区里经常能看到一个问题“How do you use LLMs for your research”这个问题看似简单实际问的是大语言模型在真实研究工作中到底应该放在哪个环节是当搜索引擎用还是当协作分析者用还是干脆只用来整理笔记。过去一年里我的答案发生了明显变化。最初我只是把 LLM 当成一个“能聊天的搜索框”后来逐渐发现研究工作和普通问答的最大区别在于研究需要可追溯、可复现、可验证。基于这个转变我把自己在文献调研、实验设计、代码辅助、论文写作和知识库维护这几个环节中使用 LLM 的完整方法整理了出来。这篇文章会给出具体工作流、提示词模板、环境配置、代码示例以及我在实际使用中踩过的坑。适合的读者有两类。一类是高校学生、科研人员和工程师想把论文阅读、实验代码、文献笔记这类工作交给 LLM 提效另一类是正在做 RAG、Agent 和 LLM 应用开发的开发者想找一个相对完整的“知识库 Agent”落地场景。1. 先理解 LLM 在研究工作中到底适合做什么1.1 研究者真正需要的不是“答案”而是“证据链”普通问答场景中用户问“什么是 Transformer”LLM 给出一个通顺解释就满足了。但研究场景完全不同。比如你问“LoRA 在低秩矩阵维度选择上有什么经验法则”如果模型只是给出一段流畅表达却没有说明这个结论来自哪篇论文、在哪个数据集上验证、实验设置的秩是多少、有没有对比 baseline那么这段回答对研究工作的价值就很低。研究的核心是证据链结论必须有来源来源必须能追溯到论文、代码、数据集或实验日志。这也是为什么很多研究者用了一段 LLM 之后觉得“它说得挺对但我不敢引用”。问题不在于 LLM 不能帮助研究而在于使用方式还停留在问答模式。正确思路是把 LLM 定位成“研究管线中的多个组件”每个组件只负责一环且每一环都保留原始材料。比如文献筛选环节LLM 负责从 100 篇论文中提取候选列表但它必须给出每篇论文的标题、DOI、摘要原文和筛选理由研究员再人工抽查。这样 LLM 就不是替代判断而是扩展处理范围判断权仍然在自己手里。1.2 研究工作流中适合 LLM 介入的五个环节根据我的实践LLM 在研究中的价值主要体现在五个环节文献调研与筛选从大量论文中快速抽取主题、方法、数据集、结论生成结构化对比表。论文阅读与摘要对单篇论文进行分段摘要、术语解释、数学推导补充和“反事实提问”。实验代码辅助生成 PyTorch 训练脚本、数据处理脚本、消融实验配置以及解释报错信息。写作与润色在作者自己完成论证逻辑的前提下帮助改写句式、统一术语、检查段落衔接。知识库维护把读过的论文、实验笔记、技术博客沉淀到本地知识库后续通过检索复用。这五个环节有一个共同特点它们都适合“批处理”和“结构化”不适合“一锤子买卖式问答”。换句话说LLM 在研究里最好的使用方式不是一次性对话而是把研究过程拆成多个可以重复执行的步骤。1.3 不要用 LLM 做研究中的哪些事情避免使用的场景同样重要。我不会让 LLM 决定研究选题因为选题需要领域嗅觉和文献积累不会让它生成实验结论因为结论必须来自真实实验数据不会让它直接生成引文条目因为 LLM 幻觉可能制造出不存在的文献也不会让它独立设计实验对照组这需要精确理解任务和数据集分布。这些边界不是保守而是对研究负责。LLM 是研究者能力的放大器不是研究责任的替代品。2. 搭建一个 LLM 研究环境本地推理与 API 的选型逻辑2.1 先明确需求再做选型不是所有环境都能用云端 API部署方式和模型选型都要看具体研究场景。如果处理的是公开论文、摘要和通用代码可以直接使用云端 API速度快模型能力强成本也可控。如果涉及未公开数据、内部实验结果、患者数据或企业隐私数据就必须考虑本地部署或私有化 API 网关。在常见项目中我建议按下面的方式判断场景推荐方式原因公开论文摘要、通用技术调研云端 API模型强、速度快、无需维护 GPU实验笔记、内部代码库、专利未公开内容本地模型或私有化部署数据不出内网合规风险低批量处理大量短文本先小样本验证再批量控制成本和幻觉率需要稳定复现的长期任务固定模型版本和温度参数保证结果可比较需要注意的是不要只看模型名还要看推理服务的参数设置、版本锁定方式和日志记录方式。研究环境里“这次结果和上次不一样”很容易导致整个验证过程失效。2.2 本地部署最小方案Ollama Python 示例如果选择本地部署推荐一个适合研究场景的最小技术栈Ollama 负责模型运行Python 通过 HTTP API 调用SQLite 保存结构化结果。整个链路不复杂但足够支撑起研究辅助工具。安装 Ollama 后先拉取一个可用的对话模型ollama pull qwen2.5:7b ollama pull llama3.1:8b拉取完成后使用下面的 Python 脚本验证本地推理环境import requests import json response requests.post( http://localhost:11434/api/generate, json{ model: qwen2.5:7b, prompt: 请用三句话总结这篇论文的贡献标题是《Attention Is All You Need》。, stream: False, options: { temperature: 0.2, top_p: 0.9, max_tokens: 512 } } ) data response.json() print(data[response])这个脚本的关键点有三个temperature 设置成 0.2用于摘要类任务减少随机性如果任务是头脑风暴或候选方案生成再调到 0.7 以上。stream 设为 False方便第一次调试避免流式输出把日志刷花。max_tokens 不能太小否则长摘要会被截断也不能太大否则一次请求耗时失控。本地部署的优势是数据可控、无限调用、离线可用代价是 GPU 显存有限7B 到 14B 级别的模型在复杂推理上不如云端大模型。所以我的实际策略是本地模型负责批量文本处理云端模型负责复杂推理和长上下文分析。2.3 环境变量与 API Key 管理不管用哪个云厂商的模型服务都要做到两件事API Key 不进代码库、模型版本和 base_url 显式配置。推荐使用 .env 文件管理配置# .env LLM_API_KEYyour_api_key_here LLM_BASE_URLhttps://api.example.com/v1 LLM_MODELgpt-4o-mini LLM_TEMPERATURE0.2然后在 Python 中通过 pydantic-settings 或 dotenv 加载from dotenv import load_dotenv import os load_dotenv() config { api_key: os.getenv(LLM_API_KEY), base_url: os.getenv(LLM_BASE_URL), model: os.getenv(LLM_MODEL), temperature: float(os.getenv(LLM_TEMPERATURE, 0.2)), }不要为了省事把 key 直接写在代码里。研究项目经常要分享代码Key 一旦进入 git 历史即使后面删掉也可能已经被别人拉取。3. 文献调研工作流用 LLM 批量筛选论文并生成结构化速览表3.1 从关键词到候选论文列表文献调研的第一步通常是从一个宽泛问题开始比如“基于大模型的代码生成研究中检索增强到底怎么和模型结合”。直接把这个宽泛问题丢给 LLM很容易得到一堆泛泛而谈的论文推荐其中还夹杂着幻觉出来的文献。更可控的做法分成两步。第一步用传统检索方式获取候选列表第二步再让 LLM 对候选列表做结构化处理。传统检索可以从这些入口开始Google Scholar 搜索关键词arXiv API 按标题、摘要检索Semantic Scholar API 获取引用数据已读论文的参考文献列表得到候选论文标题后交给 LLM 的任务不是“推荐相关论文”而是“根据我给出的论文标题和摘要整理成指定字段的结构化表格”。这样 LLM 的幻觉空间被大大压缩因为它只能基于输入内容输出。下面是一个通过 arXiv API 拉取候选论文的 Python 示例import urllib.parse import urllib.request import xml.etree.ElementTree as ET query urllib.parse.quote(retrieval augmented generation code generation) url fhttp://export.arxiv.org/api/query?search_queryall:{query}start0max_results10 with urllib.request.urlopen(url) as resp: data resp.read().decode(utf-8) ns {atom: http://www.w3.org/2005/Atom} root ET.fromstring(data) papers [] for entry in root.findall(atom:entry, ns): title entry.find(atom:title, ns).text.strip().replace(\n, ) summary entry.find(atom:summary, ns).text.strip().replace(\n, ) link entry.find(atom:id, ns).text papers.append({title: title, summary: summary, url: link}) print(len(papers))这一步的目标是把原始论文信息变成结构化输入为下一步 LLM 处理做准备。3.2 给 LLM 一个固定模板让输出可以直接入库获取论文原始信息后构造如下提示词要求 LLM 输出 JSON。关键在于强调必须基于给定摘要不允许补充外部知识。你是一个科研助理。请根据下面的论文列表输出 JSON 数组。 每篇论文需要包含 - title: 论文标题 - method: 方法的核心思想不超过 50 字 - dataset: 使用的数据集或实验场景如果没有则写 unknown - baseline: 对比的基线方法如果没有则写 unknown - result: 主要实验结论不超过 80 字 - limitation: 作者提到的局限或你从摘要中合理推断的局限不超过 50 字 - url: 原始链接 要求 1. 只能基于提供的摘要内容不能补充外部知识 2. 如果摘要中没有相关信息填写字符串 unknown 3. 不要输出除 JSON 之外的任何内容。 论文列表 {papers_json}把上一节得到的 papers 列表转成 JSON 传入就能得到结构化结果[ { title: Example Paper, method: 提出一种检索增强的代码生成框架, dataset: HumanEval, baseline: Codex, result: 在 HumanEval 上提升约 5 个百分点, limitation: 仅针对单函数粒度未验证长文件场景, url: http://arxiv.org/abs/xxxx } ]使用这种“固定模板输出”的价值在于不同时间跑同一批论文输出格式一致结果可以直接写入 SQLite、CSV 或 Notion 表格后续可以用脚本继续筛选而不需要反复回到对话里找内容。3.3 常见坑论文筛选阶段的幻觉来源在文献调研阶段最常遇到的问题有三个。第一个是要求 LLM “推荐论文”时生成不存在的文献。推荐做法是颠倒流程先由检索系统给出真实论文列表LLM 只负责整理和理解不负责生成参考文献条目。第二个是摘要中明明没有说明数据集LLM 却自作主张填了 “ImageNet”。解决办法是在提示词中强制规定信息缺失时填 unknown不要猜测。第三个是让 LLM 一次性处理超过上下文窗口的论文数量导致结果被截断或遗漏。解决办法是把论文分批处理每批 5 到 10 篇全部处理完后再合并。4. 深度阅读单篇论文让 LLM 从“总结者”变成“对话式解释器”4.1 分段摘要与术语解释读论文时直接让 LLM “帮我总结这篇论文”效果并不好因为对陌生领域来说总结通常只覆盖了最容易懂的部分难懂的方法细节仍然没解决。我推荐的做法是把论文按结构拆开处理一次只让 LLM 解释一个部分。比如把 Abstract、Method 中的公式、Experiment 表格分别输入。对 Method 部分可以用这样的提示词你是这个研究方向的资深审稿人。请用最容易理解的语言解释以下方法段落。 要求 1. 先指出该方法解决的核心问题 2. 再用“输入 - 处理 - 输出”的格式描述流程 3. 解释至少两个关键术语 4. 给出一个最小示例说明输入和输出长什么样 5. 如果段落包含数学公式用直白语言解释每个符号的含义。 原文 [粘贴论文段落]这个提示词的设计思路是不给 LLM 太宽泛的任务而是要求它从多个角度解释同一个段落。这样更容易发现它是否真的理解了或者只是在套话。4.2 反事实提问检验 LLM 是否真理解方法检验模型是否理解一个方法最好的方式不是让它复述而是让它回答“如果去掉某个模块会怎样”“如果修改某个超参数会怎样”。这种反事实提问对研究者自己也很有用能帮助想清楚实验中的变量关系。例如读完一篇对比学习论文后可以向 LLM 提问如果训练阶段去掉投影头projection head直接使用编码器输出的特征做对比损失模型效果会发生什么变化请从训练目标和特征空间两个角度分析。这类问题不一定需要模型给出绝对正确的答案而是通过它的回答帮助研究者发现之前忽略的机制。关键在于模型给出的任何推理都不能作为实验结论必须通过真实实验验证。4.3 常见坑上下文过大导致的错误把整篇 20 页论文一次性塞进 prompt经常出现两种问题上下文过长导致部分内容被截断模型把前面段落的信息错误迁移到后面段落。实际处理时建议按章节切割。一篇论文拆成 introduction、method、experiment、conclusion 四段分别阅读。如果使用支持超长上下文的模型仍然建议分段提问因为分段提问能让模型集中注意力回答质量明显更高。5. 把知识沉淀成 RAG 知识库Obsidian 与 LLM Wiki 的落地组合5.1 为什么要从“一次性对话”走向“知识库”研究过程中最浪费的事情是几个月前读过的论文、记过的实验细节、踩过的环境坑全部散落在不同对话窗口和文档里。等到真需要时想找却找不到或者只能凭记忆重新搜索。解决思路是把 LLM 的产出沉淀为结构化文档再通过 RAG 让这些文档变成可持续查询的知识库。简单说就是用向量数据库或支持全文检索的工具保存笔记后续问答时先检索相关笔记再让 LLM 基于检索结果回答。在个人知识库场景里Obsidian 加 Markdown 是一个非常合适的基础设施。所有笔记都是纯文本没有平台锁定可以通过双链组织论文、实验、代码之间的关系也能配合社区插件实现全文检索和向量化。我之前在项目里用过这样一个组合Obsidian 作为笔记编辑和浏览层Markdown 文件保存结构化的论文笔记向量化脚本把笔记写入本地向量库一个本地 Python CLI 完成“检索 LLM 回答”5.2 一个轻量 RAG 流程示例假设你已经把论文笔记整理成了 Markdown 文件下面是用 LangChain 搭建轻量检索问答的示例。from langchain_community.document_loaders import DirectoryLoader from langchain.text_splitter import RecursiveCharacterTextSplitter from langchain_community.embeddings import HuggingFaceEmbeddings from langchain_community.vectorstores import Chroma loader DirectoryLoader(notes/, glob**/*.md) docs loader.load() splitter RecursiveCharacterTextSplitter( chunk_size500, chunk_overlap50 ) chunks splitter.split_documents(docs) embedding HuggingFaceEmbeddings(model_nameBAAI/bge-small-zh-v1.5) vectorstore Chroma.from_documents(chunks, embedding) retriever vectorstore.as_retriever(search_kwargs{k: 4})检索器准备好之后提问流程是先检索出与问题最相关的 4 个片段再把片段和问题组合成 prompt交给 LLM 回答。关键点在于提示词中要说明“只能基于检索内容回答”这样可以减少幻觉。from langchain.chains import RetrievalQA from langchain_openai import ChatOpenAI llm ChatOpenAI( modelgpt-4o-mini, temperature0.1, openai_api_keyconfig[api_key], openai_api_baseconfig[base_url], ) qa RetrievalQA.from_chain_type( llmllm, retrieverretriever, chain_typestuff ) result qa.invoke(LoRA 中 rank 的选择对下游任务效果有什么影响) print(result[result])这个 RAG 流程适合个人知识库规模几百篇 Markdown 笔记完全够用。生产环境如果文档数量增长到几十万还需要引入增量索引、密度聚类、混合检索和评价集但核心思想不变先检索再回答。5.3 向量化是 RAG 最重要的环节很多 RAG 项目效果差问题出在向量化而不是大模型。常见的错法是把整篇论文作为一个向量结果检索时匹配精度极低或者没有做分块调优导致语义断裂。建议先做三件事确认 chunk_size 是否适合文档类型。学术论文适合 300 到 800 字的分块代码文档适合更小的块。确认文本清洗规则。Markdown 标题、链接、代码块是否被保留或剔除会直接影响向量语义。构建一个包含 10 到 30 条真实问题的评测集人工判断每条检索结果是否相关再迭代分块和 embedding 模型。不要在没有评测集的情况下盲目换 embedding 模型。模型 A 在某个公开基准上分数高不代表在你自己领域的数据上更准。5.4 常见坑RAG 检索到不相关片段时的表现当检索结果不相关时LLM 依然可能给出流畅答案这是 RAG 最隐蔽的坑。表面上看起来回答了实际上内容来自模型内部知识而不是笔记。排查方式很简单在返回结果中同时输出引用的原文片段人工检查“回答是否真的来自片段”。如果经常出现“检索片段完全不相关但回答很流畅”的情况优先检查分块大小和 embedding 模型是否匹配而不是检查 LLM 参数。更稳妥的提示词模板你是一个研究助理。请仅根据下面提供的资料回答问题。 资料 {context} 问题{question} 要求 1. 如果资料中找不到答案直接回答“资料中没有相关内容” 2. 不要使用资料之外的常识补充 3. 回答末尾列出你参考的资料文件名。6. 用 LLM 辅助实验代码从生成训练脚本到解释报错6.1 让 LLM 生成可配置的训练脚本写论文实验代码时经常需要针对不同数据集、不同模型写很多结构类似的脚本。完全手写浪费时间完全让 LLM 生成又容易失控。我的做法是先写好一个模板让 LLM 在模板基础上补全而不是从零生成。下面是一个最小 PyTorch 训练脚本模板import argparse import torch from torch import nn from torch.utils.data import DataLoader def parse_args(): parser argparse.ArgumentParser() parser.add_argument(--epochs, typeint, default10) parser.add_argument(--batch_size, typeint, default32) parser.add_argument(--lr, typefloat, default3e-4) parser.add_argument(--device, typestr, defaultcuda) return parser.parse_args() def main(): args parse_args() # TODO: 加载数据集 # TODO: 初始化模型 # TODO: 定义优化器和损失函数 # TODO: 训练循环 pass if __name__ __main__: main()把这个模板放到提示词中要求 LLM 完成数据加载、模型定义和训练循环。这样生成结果受模板约束不会被模型自由发挥到完全不可用。6.2 排错示例显存不足、野卡和数据未对齐用 LLM 辅助代码排错时给模型的上下文越接近真实日志效果越好。不要只复制一行错误消息要把完整堆栈、关键代码片段、输入数据的 shape 一并提供。例如常见错误 CUDA out of memory 的处理思路现象训练开始时出现 RuntimeError: CUDA out of memory。 环境显卡显存 8GBbatch_size32输入图片是 224x224模型是 ResNet50。 请列出可能导致显存不足的配置项并按排查优先级排序。这种问法能帮助研究者快速定位是 batch_size 太大是模型太大还是 DataLoader 的 num_workers 导致额外开销。实际排错时我会按下面的顺序检查输入数据 shape 是否正确是否意外创建了巨大的中间张量。batch_size 是否在当前显存限制范围内。优化器是否有主模型之外的额外状态。是否在不需要梯度时忘记使用 torch.no_grad()。是否有模型前向过程产生了未释放的计算图。这些内容本身也可以整理成笔记放进知识库后续遇到相同问题直接检索。6.3 常见坑LLM 生成代码不是“可直接运行”的代名词LLM 生成的实验代码经常存在三个问题数据集路径是假的模型与论文描述不一致训练循环缺少 eval 阶段。推荐处理方式是把生成代码当作“第一版草稿”必须完成以下检查后才能运行数据集的下载、缓存和预处理是否真实存在模型输入维度是否与数据维度匹配是否保存最佳 checkpoint而不是只保存最后一个评价指标是否在测试集上计算随机种子是否固定确保多次运行可比较尤其是随机种子实验代码不固定种子论文里的“提升 2 个百分点”很可能是随机波动而不是方法带来的提升。7. 从对话记录到论文写作LLM 在写作环节的正确位置7.1 LLM 能写句子但不能替你论证写作阶段最容易犯的错误是让 LLM 直接生成整段 Related Work 或 Method 描述。这样写出的文字缺少作者自己的判断和逻辑链而且一旦模型幻觉了某篇论文引用就成了大问题。我的用法是在论文结构确定之后让人工先把每段的“论点 论据 句子逻辑”写成提纲然后用 LLM 做这些事把口语化提纲改写成学术书面表达压缩冗长段落统一术语检查段落之间的过渡是否自然比如下面这个提示词下面是我的一段论文草稿请帮我做学术化润色不要增加新的技术内容不要新增参考文献不要改变句子顺序。 要求 1. 保持原意 2. 使用更正式、更简洁的学术表达 3. 如果段落中有重复表达合并 4. 直接输出润色后的段落。 草稿 [粘贴段落]这个提示词的关键是加了三道约束不增加新内容、不新增引用、不改变句子顺序。这样 LLM 的发挥空间被压缩到“语言表达”层面而不是“内容创作”层面。7.2 用 LLM 做术语一致性检查论文写作到后期经常出现术语不统一的问题比如一会儿写 “low-rank adaptation”一会儿写 “LoRA”一会儿写 “低秩适配”。人工检查容易遗漏可以交给 LLM 做一次术语一致性扫描。下面是一篇论文的多个段落。请找出我使用的核心术语检查是否存在同一概念使用不同术语的情况。 输出格式 - 概念概念解释 - 使用过的术语列表 - 推荐统一术语 论文段落 [粘贴内容]这项任务风险低即使模型判断不完全准确也能作为人工检查的起点。7.3 常见坑润色后引入错误LLM 润色可能引入两个问题一是把一个技术概念换成了自己发明的等价表达导致原文含义变化二是通过改写句子顺序改变了段落逻辑。防范方式有两个。第一润色后必须用 diff 工具对比原稿和修改稿逐条确认改动第二在提示词中禁止结构性和概念性修改只允许语言层面调整。8. 研究级 LLM 使用的评估方法如何确认“用 LLM 是真的有帮助”8.1 不要凭感觉判断质量建立小型评估集很多人在使用 LLM 辅助研究时靠“感觉回答不错”来判断质量。这种方式在简单问题上够用但在研究方法评估上完全不够。可以建立一个小型评估集。选取 20 到 30 个真实问题这些问题可以来自你实际研究过程中的提问覆盖文献理解、实验设计、代码排错、概念解释等类型。对每个问题保存三条信息问题原文LLM 的回答人工评分与评语评分维度建议分为相关性、准确性、可追溯性和可操作性四项每项 1 到 5 分。每两周评估一次观察不同模型、不同提示词方案的变化。8.2 评估清单从答案倒查引用研究场景中对 LLM 回答的评估必须把“可追溯性”作为核心指标。具体检查方式如下检查项通过标准事实是否有来源关键结论能对应到论文、文档或实验记录引用是否真实存在如果提到论文能在 arXiv 或出版社查到回答是否基于给定资料闭卷回答和开卷检索回答不要混淆是否区分推测与事实模型应明确标注“这是我的推断”结果是否可复现相同输入、相同参数下多次运行结果稳定如果这五个检查项大部分不通过说明当前答案不能进入研究流程只能当思路启发。8.3 常见坑把“流畅”当成“准确”大模型生成的答案天然通顺这一点会让不熟悉技术细节的人低估幻觉风险。在研究场景里越是流畅但不给来源的回答越要警惕。培养自己的检查习惯拿到一个回答先问“这个说法来自哪里”再去验证。验证方式包括在原文中检索关键句、查看模型是否列举了可定位的来源、自己复现一次计算。没有验证流程LLM 在研究里就会变成一个高风险的信息源。9. 生产级研究知识库从个人脚本到可维护系统9.1 学习环境与生产环境的差异本地跑一个检索问答脚本只是学习验证。真正要变成团队可用、长期维护的研究系统还需要考虑很多工程问题。学习环境里可以直接把一段 Markdown 一次性写入 Chroma生产环境需要一个增量更新的管道新论文入库时只处理新增部分。学习环境里可以忽略权限问题生产环境要区分私有实验数据和公开论文数据可能需要上不同的模型和不同的访问控制。学习环境里用一条 prompt 直接问答生产环境要加日志、版本、评测和回滚机制每次 prompt 模板改动都要记录防止“换了模板后结果变了”却查不到原因。9.2 给研究系统增加日志与版本控制研究系统的运行记录本身也是研究数据。建议在一开始就给每次 LLM 调用保存一份完整 JSON 日志记录以下字段{ timestamp: 2025-06-01T10:00:00Z, task: literature_review, model: gpt-4o-mini, temperature: 0.2, prompt_version: v3, input: , output: , latency_ms: 1234, token_count: 3456 }保存到本地后可以按 prompt_version 统计不同版本的输出质量也可以复盘某个错误结果到底是输入问题还是模型问题。这是把 LLM 应用从“试玩”升级到“研究工具”的关键一步。9.3 可复用清单研究系统上线前检查上线一个 LLM 辅助研究系统前至少完成以下检查是否所有外部依赖都锁定了版本API Key 是否已从代码仓库移除是否记录了每次请求的模型名、参数和输入输出是否设置最大 token 和请求超时是否对输出结果做了非法字符清洗是否建立小型评估集并测过基线是否保留原始论文整理结果而不是只保留模型输出摘要是否明确哪些任务允许 LLM 参与哪些任务禁止 LLM 参与是否有批量任务失败后的重试和告警机制是否有回滚方案比如 prompt 模板改动后如何回到上一版本10. 从 Andrej Karpathy 的“LLM Wiki”范式到个人知识库的扩展10.1 为什么个人知识库要面向“检索复用”而不是“堆存笔记”近一年里Andrej Karpathy 关于 LLM Wiki 的讨论受到很多开发者关注。核心思想是把知识以结构化文本形式保存下来让 LLM 在回答问题时基于已有笔记进行引用和推理而不是每次都从零生成。这个思想正好解决研究场景的痛点。研究笔记不是收藏夹不是摘抄本而是用来支撑下一次研究和下一次写作的素材库。笔记的价值取决于它被检索和复用的效率。10.2 从“论文笔记”到“实验日志”到“错误归档”的扩展个人知识库可以按数据类型划分成几个区域论文笔记每篇论文一个 Markdown 文件记录问题、方法、实验、局限。实验日志每次实验记录配置、指标、结论和可视化图。错误归档遇到的报错、原因、解决方式、预防建议。代码片段常用脚本、模板、prompt 模板、RAG 上游处理流程。把这些区域统一放入同一个向量库后续一个新问题时既可能检索到相关论文也可能检索到之前踩过的坑。这种跨类型检索正是 RAG 相对传统文件夹搜索的优势。10.3 不要盲目追求“全自动研究助手”当前很多文章会展示一个看起来很智能的 Agent 流程输入一个研究主题Agent 自动去搜索论文、读 PDF、生成报告。这种全自动流程在演示时效果很好但在真实研究中容易出问题。原因在于研究过程中的判断非常依赖领域知识而 Agent 缺少两个关键能力一是对不确定信息的识别和主动询问二是对领域内默认知识的理解。全自动流程一旦在某一步检索到错误论文后续所有步骤都会基于错误信息继续最终输出的报告可能很完整但核心结论是错的。更稳妥的模式是“半自动”LLM 负责处理结构化、批量、耗时的环节人工负责关键的判断和决策。比如筛选候选论文时LLM 可以生成结构化表格但最终选哪 20 篇精读仍然由人工决定。这不是保守而是对研究质量负责。11. 从零搭建一个“研究辅助 CLI”的完整示例11.1 设计目标把前面涉及的功能整合起来可以做一个非常简单的研究辅助 CLI。它支持三个子命令search用 arXiv API 搜索论文并调用 LLM 输出结构化 JSON。add-note把一篇 Markdown 笔记写入知识库。ask从知识库检索并回答问题。这样就把文献调研、知识沉淀、检索问答三个环节放到了一个统一工具里。11.2 项目结构research-cli/ main.py requirements.txt .env notes/ README.mdrequirements.txtrequests python-dotenv langchain langchain-community chromadb unstructured markdown11.3 search 子命令实现import argparse import json import urllib.parse import urllib.request import xml.etree.ElementTree as ET import requests ARXIV_API http://export.arxiv.org/api/query def fetch_arxiv_papers(query: str, max_results: int 10): params { search_query: fall:{query}, start: 0, max_results: max_results } url f{ARXIV_API}?{urllib.parse.urlencode(params)} with urllib.request.urlopen(url) as resp: data resp.read().decode(utf-8) ns {atom: http://www.w3.org/2005/Atom} root ET.fromstring(data) papers [] for entry in root.findall(atom:entry, ns): title entry.find(atom:title, ns).text.strip().replace(\n, ) summary entry.find(atom:summary, ns).text.strip().replace(\n, ) link entry.find(atom:id, ns).text papers.append({title: title, summary: summary, url: link}) return papers def summarize_papers(papers, api_key, base_url, model): prompt f请将以下论文列表整理为 JSON 数组。每项字段见说明。 要求只基于摘要不补充外部知识。 {papers} resp requests.post( f{base_url}/chat/completions, headers{Authorization: fBearer {api_key}}, json{ model: model, messages: [{role: user, content: prompt}], temperature: 0.2 } ) return resp.json()[choices][0][message][content] def main(): parser argparse.ArgumentParser() parser.add_argument(--query, requiredTrue) parser.add_argument(--max-results, typeint, default10) args parser.parse_args() papers fetch_arxiv_papers(args.query, args.max_results) result summarize_papers(papers, os.getenv(LLM_API_KEY), os.getenv(LLM_BASE_URL), os.getenv(LLM_MODEL)) print(result)这段代码把第 3 节的核心逻辑合并成了一个可执行的脚本。实际使用可能需要调整 base_url 的路径规则不同模型服务提供商的 /chat/completions 路径可能不同。11.4 ask 子命令实现def ask_question(question: str): from langchain_community.document_loaders import DirectoryLoader from langchain.text_splitter import RecursiveCharacterTextSplitter from langchain_community.embeddings import HuggingFaceEmbeddings from langchain_community.vectorstores import Chroma loader DirectoryLoader(notes/, glob**/*.md) docs loader.load() splitter RecursiveCharacterTextSplitter(chunk_size500, chunk_overlap50) chunks splitter.split_documents(docs) embedding HuggingFaceEmbeddings(model_nameBAAI/bge-small-zh-v1.5) vectorstore Chroma.from_documents(chunks, embedding) retriever vectorstore.as_retriever(search_kwargs{k: 4}) retrived retriever.get_relevant_documents(question) context \n\n.join([doc.page_content for doc in retrived]) prompt f请仅根据以下资料回答问题。资料中没有的内容直接说“资料中没有相关内容”。 资料 {context} 问题{question} resp requests.post( f{config[base_url]}/chat/completions, headers{Authorization: fBearer {config[api_key]}}, json{ model: config[model], messages: [{role: user, content: prompt}], temperature: 0.1 } ) answer resp.json()[choices][0][message][content] print(回答, answer) print(参考片段) for i, doc in enumerate(retrived): print(f[{i1}] {doc.page_content[:200]})注意 ask 命令每次运行时都会重新构建向量库个人笔记量小时没问题。笔记量增大后应改成向量库持久化加增量更新否则每次提问都要重新 embedding耗时太长。12. 常见问题排查从“回答不对”反推原因12.1 排查顺序优先级使用 LLM 做研究辅助时遇到“回答不对”或“效果差”建议按以下顺序排查问题是否清晰。提问是否明确指定了输入范围、输出格式和不能做的事。输入材料是否正确。是让模型读摘要还是读全文分块有没有截断关键信息。模型参数是否合适。temperature 是否过高max_tokens 是否截断top_p 是否异常。提示词是否约束了范围。是否允许模型补充外部知识是否允许自由发挥。知识库检索是否命中。RAG 场景中先检查检索到的片段是否相关再检查 LLM 回答。输出解析是否失败。JSON 输出是否有额外文字是否有转义问题。模型版本和 API 行为是否稳定。相同参数下结果差异是否影响判断。12.2 常见问题表问题现象可能原因检查方式处理建议LLM 推荐了不存在的论文模型在自由生成引用用搜索引擎验证论文是否存在更换流程先检索真实论文再让 LLM 整理结构化 JSON 输出不稳定prompt 未严格要求 JSON查看原始响应在输出前加“只输出 JSON”并使用解析兜底摘要结果过于泛泛输入是全文模型抓不住重点检查输入长度和切分按章节输入每章节单独提问RAG 回答与笔记无关检索片段不相关打印检索片段调整分块大小或换 embedding 模型运行两次结果不同temperature 设置过高或模型非确定性固定参数复测temperature 调低记录模型版本和参数本地模型回答质量差模型参数规模小对比云端模型本地模型做批量任务复杂推理用云端API 调用超时输入过长或模型推理慢检查日志耗时加超时重试必要时减少输入长度实验结果代码无法运行生成代码缺少真实路径或依赖检查代码细节人工审查代码后再运行不能直接提交 GPU 任务12.3 排查时最容易被忽略的环节很多人先怀疑模型能力但真实原因经常在更简单的地方输入材料本身有问题。比如把网页复制进 prompt 时带了大量无关导航文字比如 OCR 论文时公式被识别错误比如从 PDF 提取的文本丢失了表格结构。所以排查的第一步不是换更强的模型而是检查输入文本。先把输入打印出来人工看一眼确认模型收到的内容确实是研究中需要的内容。13. 最佳实践把 LLM 当成研究团队里的“初级研究员”来管理13.1 明确职责边界可以把 LLM 当成一个效率很高但需要监督的初级研究员给它分配任务时明确三点输入是什么、输出格式是什么、哪些事情绝对不要做。比如分配文献筛选任务时明确输入arXiv API 返回的 10 篇论文标题和摘要。 输出JSON 数组包含标题、方法、数据集、结论、局限。 不要做不要给论文打分排序不要推荐额外论文不要生成引用条目。13.2 建立 prompt 模板版本库研究项目中提示词本身是需要版本管理的资产。建议把常用 prompt 存成文件纳入 git 管理每次修改记录版本号。例如prompts/ literature_review_v1.md paper_explainer_v1.md paper_explainer_v2.md code_debug_v1.md rag_answer_v1.md这样当问题复现时可以定位到“当时的 prompt 和现在的 prompt 差别在哪里”而不是凭记忆猜测。13.3 明确人工复核点研究流程中至少要设置以下人工复核点文献筛选结果人工确认最终纳入精读的论文列表从论文段落中提取的 Method 描述人工确认与原文一致LLM 生成的实验代码人工 review 后再运行润色后的论文段落人工逐句检查是否改变原意任何引用文献必须回到原始来源确认如果这些复核点被跳过LLM 就从一个辅助工具变成了黑盒决策器这在研究里是危险的。13.4 面向长期维护的建议长期使用 LLM 做研究还要注意三点第一关注新模型和新技术但不要频繁切换。每次切换模型都要重新跑一遍小型评估集确认没有引入新的质量回退。第二注意 Token 成本。批量处理大量文本时先在小样本上验证质量和成本再全量执行避免一次任务烧掉大量额度。第三做好原始数据备份。LLM 的摘要、整理、结构化输出都是派生数据原始论文和原始实验记录必须单独保存不能只依赖模型输出。14. 推荐的学习路径与下一步实践方向如果刚接触 LLM 辅助研究我的建议是按下面的顺序推进第一阶段直接使用对话式 LLM 阅读论文但每次提问都要求模型给出结构和约束比如“基于这段摘要使用 JSON 输出论文方法、数据集、局限”。第二阶段搭建本地环境用 Ollama 或 API 完成批量文献摘要把所有结果保存为结构化笔记。第三阶段引入 RAG 知识库把论文笔记、实验日志和代码片段统一检索养成“回答必带参考”的习惯。第四阶段为一个具体研究主题搭建“检索 摘要 问答 写作辅助”的完整工作流并用小型评估集持续监控质量。再往后可以探索更复杂的 Agent 场景比如把论文检索、实验代码生成、结果报告整合成一个半自动流程。但每一步都要明确人工智能的边界和人工复核点否则工具越复杂错误越难发现。真正有价值的研究工具不是那些看起来“全自动”的系统而是能让人在更短时间里做出更好判断的系统。LLM 在这条路上的最大贡献是帮研究者从繁琐的文献处理、代码调试和文本润色中解放出来把注意力放回到科学问题本身。