先说个常被问到的问题LangChain 和 LlamaIndex这两个开源框架到底有什么本质区别我该用哪一个这问题我在好几个项目群里都见人反复问过每次的回答其实都不太一样——因为答案取决于你手里的事情是什么。如果你正打算做知识库问答、文档对话或者要搭一个带流程控制的 AI 应用这篇文章就是给你写的。我不会像官方文档那样面面俱到只挑我在实际项目里选型时真正踩过、验证过的差异点来讲争取一次把“怎么选”这件事说透。1. 一条主线先分清谁是编排器、谁是检索器1.1 框架定位完全不同很多人第一次看到这两个框架第一反应是“这不都是 LLM 的封装吗随便选一个不就行了”。真不是。你得先看到两者的出发点完全不同LangChain 的核心词是“编排”它假设你的 AI 应用是一个流程用户输入进来可能要查知识库、调外部工具、让模型推理、再把结果返回。它提供的是链条、Agent、状态管理、工具注册这一整套流程控制能力。LlamaIndex 的核心词是“索引”它假设你要面对一批文档或者数据源核心问题是如何把数据准备好、切分好、索引好然后让模型在回答问题的时候真正“查到”相关的内容。这个差异不是细节差异而是世界观差异。LangChain 想让你觉得“所有 AI 应用都可以被我编排起来”LlamaIndex 想让你觉得“所有数据都可以被我索引起来”。当你拿着做知识库问答的需求去选框架时这两条路线都会“看起来能用”但深入到细节你会发现它在为你解决不同的问题。1.2 用“你要解决什么问题”倒推选择我自己的选型方法很简单先别管框架热不热回答三个问题你的核心需求是“让模型有条理地调用多个能力”还是“让模型从大量资料里找到准确答案”你的数据量是几十个小文档还是几千个混杂着表格、图片、PDF 的庞杂资料你需要深度定制每一步流程还是希望开箱即用地把数据灌进去就出效果如果第一个问题偏前者LangChain 更顺手如果偏后者LlamaIndex 更省心。第二个和第三个问题则决定你最终注定要付出多少定制成本。为什么我会说“注定”因为实践中大多数项目并不会落在其中一个框架的纯享区。知识库问答往往会用到外部工具的补全、流程上的条件判断业务自动化流程也免不了从一堆文档里抽数据。所以“先选主框架再补上另一个框架的能力”才是成熟团队实际在走的路这一点我放在后面第 6 章详细说。2. LangChain 的核心优势把“流程”玩明白2.1 链式编排与状态管理LangChain 最深入人心的概念就是“链”。我第一次用它的LCELLangChain Expression Language写表达式时印象最深的是整个链像流水线一样可以组合拆解每个环节是一个Runnable你可以随便把RunnableParallel、RunnablePassthrough这些节点拼起来形成一个可观测的数据流。这种设计解决了一个很实际的问题在很多业务场景里模型输出并不是最终结果它只是一个中间产物。比如你要做一个客户工单分类加摘要的系统流程可能是先判断工单类型再按类型调用不同的处理逻辑最后生成摘要并推送到某个系统。用 LCEL 写逻辑非常直观from langchain_core.runnables import RunnableLambda, RunnablePassthrough from langchain.prompts import ChatPromptTemplate from langchain_openai import ChatOpenAI llm ChatOpenAI(modelyour-model, api_keyyour-api-key) classify_prompt ChatPromptTemplate.from_template( 请将下面的工单分类为网络故障/账号问题/账单问题/其他。\n工单内容{content} ) summarize_prompt ChatPromptTemplate.from_template( 请用两句话总结这个工单的处理要点。\n工单内容{content} ) chain ( RunnablePassthrough.assign( categoryclassify_prompt | llm, summarysummarize_prompt | llm, ) | RunnableLambda(lambda x: { content: x[content], category: x[category], summary: x[summary], needs_manual: x[category] in [账单问题, 其他], }) ) result chain.invoke({content: 我登录不上账号显示密码错误几次后就被锁住了。})这种写法最大的好处是可以把每一步的输入输出都追踪到。调invoke之后中间结果在对象里一目了然。调试的时候你能明确看到是哪一层出了问题是分类提示词不行还是摘要模型输出太啰嗦——这在复杂流程里能节省大量排查时间。2.2 Agent 与工具调用的自由度LangChain 的另一个招牌能力是 Agent。Agent 本质上是让模型自己“决定”接下来调用哪个工具、要不要继续执行。这听起来很炫但我的实际体验是Agent 适合“工具边界清晰、容错率高”的场景不适合业务严谨的流程。举例来说你给 Agent 挂了三个工具查天气、查航班、查酒店。用户说“帮我安排后天的出差顺便查下那边的天气”Agent 会自己决定依次调用哪些工具然后把结果拼给你。这在 Loosely 的场景里很实用因为你没法提前穷尽所有对话路径。不过要注意Agent 的自由度是一把双刃剑。模型一旦在工具调用上脑补了一个并不存在的参数或者连续调用同一个工具陷入死循环你的应用就卡住了。我在生产环境里通常会给 Agent 加上清晰的工具描述和参数 schema再在外层设定最大迭代次数必要的时候还要做一个简单的“投票机制”——让另一个模型检查 Agent 的调用记录是否合理不合理就打回重来。LangChain 允许你做这些外层定制这是它流程优势的体现。2.3 生态集成一个写满适配器的工具箱还有一个不能忽视的点是集成生态。LangChain 已经有了大量现成的集成组件从各种向量数据库、各种模型服务到各种外部 API基本都能找到封装好的类。这个“连接器”优势在项目要对接多个系统的时候特别明显。比如你既要把数据存到某个向量库又要调用外部审批 API还想把时间线推到某个协作工具LangChain 的集成层能减少很多胶水代码。它不是最好的检索工具也不是最好的 UI 框架但它像一个中间层让你不用分别去学每一个系统的 SDK 细节。但集成多也意味着封装深出了问题要往下钻好几层。我的经验是遇到问题先查它封装那层 SDK 的版本很多时候是版本不匹配导致的“诡异报错”跟你的业务逻辑没关系。3. LlamaIndex 的核心优势把“检索”做到极致3.1 数据接入从小文件到数万文档LlamaIndex 给我的第一感觉是它对“文档”的理解非常认真。它提供了很细的Document和Node抽象一个Document可以对应一个文件、一个网页、一段数据库记录而真正参与检索的粒度是Node——也就是切分之后的文本块。它的数据加载器Loaders特别多PDF、Word、Markdown、结构化表格、网页都能接。印象最深的是处理一个混合了大量 PDF 和表格的项目我用 LlamaIndex 的加载器把数据接进来再配合它的MetadataExtractor自动抽取文档标题、页码、章节信息后面做来源溯源就非常轻松。这里的经验是与其手动写一堆解析逻辑不如先在 LlamaIndex 里找有没有现成的 Loader它的社区已经把很多脏活干完了。3.2 检索质量的可控可调做知识库问答最怕的就是“答非所问”。LlamaIndex 在提升检索精度上给了很多参数和模块特别是这两点值得关注第一是切分策略。同一个文档切得太碎会丢失上下文切得太大又会混入无关信息。我通常会把chunk_size设在 256 到 512 之间重叠部分设在 10% 到 20%再根据文档类型做调整。代码文档和小节明显的文章适合小块切分长篇论述适合大块。node_parser是控制这一层的关键类它支持按句子、按段落、按固定 token 数等多种模式。我曾经为了追求效果对不同目录的文档用了不同的切分策略然后统一构建索引。LlamaIndex 允许你把这些不同策略的节点混在一个索引里这种灵活性在 LangChain 里要做不少额外工作。第二是混合检索与重排。LlamaIndex 支持把多个查询引擎组合起来比如关键词检索和向量检索并行再用一个reranker对两路结果统一打分排序。这块是我认为 LlamaIndex 最值钱的地方。直观地说向量检索擅长语义相近但用词不同的情况关键词检索擅长匹配专有名词、编号这类精确信息。两者一结合覆盖率明显提升。from llama_index.core import SimpleDirectoryReader, VectorStoreIndex from llama_index.core.node_parser import SentenceSplitter from llama_index.core.query_engine import RetrieverQueryEngine # 读取文档 docs SimpleDirectoryReader(./data/pdfs).load_data() # 设定切分策略 parser SentenceSplitter(chunk_size384, chunk_overlap48) nodes parser.get_nodes_from_documents(docs) # 构建索引 index VectorStoreIndex(nodes, show_progressTrue) # 查询引擎 query_engine index.as_query_engine( similarity_top_k8, response_modetree_summarize, ) response query_engine.query(今年第一季度的营收情况怎么样)不要小看response_mode这个参数。默认的compact模式是把检索到的内容塞进上下文让模型回答够用但不精细tree_summarize模式会分步聚合多段信息更擅长综合分散在不同文档里的答案refine模式则适合在已有答案的基础上增量修正。根据问题类型换response_mode比调模型温度更立竿见影。3.3 索引与查询引擎的层次感LlamaIndex 的索引类型不止向量索引一种。它还有摘要索引、关键词索引、知识图谱索引各有各的适用场景。我实际用过知识图谱索引来处理一段强关联的实体关系数据效果确实比纯向量检索更符合预期因为查询可以直接沿着关系跳转而不是靠向量距离去猜。它把“检索”和“生成”拆成了两个层次Retriever负责拿候选内容ResponseSynthesizer负责把内容组织成回答QueryEngine把两者包在一起而你几乎可以在每一层插入自定义逻辑。这种分层的思路让做 RAG 的人感觉自己不是在用框架而是在搭一套检索系统。需求简单时用默认配置需求复杂时层层替换组件这种克制感是 LlamaIndex 设计上比较成熟的体现。4. 适用场景一张表看清各自的地盘4.1 场景一多步骤业务自动化如果你要构建的是“多工具协作 状态流转”的业务自动化系统比如客服工单处理、内容生产流水线、自动化审批助手LangChain 是首选。原因很简单它把“流程”当成一等公民链条、并行分支、条件分支、Agent 循环这些能力都是现成的。举个具体例子。我有一个模拟项目用户提交产品需求文档系统需要先解析文档关键信息再自动生成一份风险评估报告最后根据风险等级走不同的通知流程。用 LangChain 做每个环节都可以拆成一个 Runnable模块之间靠数据传递出问题能单独替换某一环。LlamaIndex 也能做但它更关心“文档进了索引之后怎么查”而不是“多个任务怎么协调”你会需要自己写更多流程控制代码。4.2 场景二企业知识库问答反过来如果你的核心任务就是“喂一批资料让用户问问题答案要准、要可溯源”LlamaIndex 更合适。它的加载器、节点切分、混合检索、重排、引用溯源这些能力恰恰命中知识库问答的每一个痛点。特别是“引用溯源”这件事很多团队容易低估它的重要性。企业内部知识库问答回答里如果没有来源页码或者原文引用根本没人敢信。LlamaIndex 的节点天然保留文档来源信息返回结果时可以方便地映射回原始段落省了我在 LangChain 里手动维护文档来源的工作。4.3 场景三数据分析与文档洞察还有一种常见场景是“对一批文档做完形填空式分析”比如从财报里提取指标、从合同里找关键条款。这种情况下两个框架都能用但体验不同。LlamaIndex 的优势在于它可以直接加载结构化表格并支持对多文档做聚合分析。LangChain 的优势在于你可以把“读取文件—提取信息—写入表格—发送提醒”串成一个完整自动化流程。我的选型建议是如果分析结果是给人看的LlamaIndex如果分析结果要流向下一个业务环节LangChain。4.4 场景四原型快速验证想做 POC 或者参加黑客松我会优先用 LlamaIndex。因为它开箱即用的程度更高导入文档、构建索引、拉起查询引擎几行代码就能看到效果。LangChain 需要你先理解链、工具、模型、解析器这一堆概念虽然它的默认递归也能工作但总觉得中间隔着一层迷雾。偏好 LangChain 的情况是你已经预判到这个原型未来一定会长得很大、很复杂需要引入多少工具和流程那早点在 LangChain 里搭骨架更明智免得后期从 LlamaIndex 迁移过来还要重写一遍业务逻辑。5. 上手实测同一个问答需求两个框架分别怎么写5.1 LangChain 实现一个简单 RAG这里我用一个“从公司制度文档里问答”的需求做实验。LangChain 的标准做法是加载文档、切分、存向量库、检索、组装提示词、生成答案。from langchain_community.document_loaders import DirectoryLoader from langchain.text_splitter import RecursiveCharacterTextSplitter from langchain_openai import OpenAIEmbeddings, ChatOpenAI from langchain_community.vectorstores import FAISS from langchain.chains import create_retrieval_chain from langchain.chains.combine_documents import create_stuff_documents_chain from langchain_core.prompts import ChatPromptTemplate loader DirectoryLoader(./data/pdfs, glob*.pdf) docs loader.load() splitter RecursiveCharacterTextSplitter(chunk_size512, chunk_overlap64) chunks splitter.split_documents(docs) embeddings OpenAIEmbeddings(modelyour-embedding-model, api_keyyour-api-key) vectorstore FAISS.from_documents(chunks, embeddings) llm ChatOpenAI(modelyour-model, api_keyyour-api-key, temperature0) prompt ChatPromptTemplate.from_template( 请基于以下资料回答问题\n{context}\n问题{input} ) doc_chain create_stuff_documents_chain(llm, prompt) retrieval_chain create_retrieval_chain(vectorstore.as_retriever(search_kwargs{k: 6}), doc_chain) answer retrieval_chain.invoke({input: 新员工的试用期是多久}) print(answer[answer])整体逻辑清楚但你能看出来从加载器、切分器、向量库到检索链每一层都要自己拼。好处是每一层都能换缺点是“每一层都得懂”。如果只是做一次性的小问答这套流程略重但如果你本来就要搭自动化流程这套结构就顺势变成整个应用的主干。5.2 LlamaIndex 实现同样的 RAG同样一个需求LlamaIndex 写法更紧凑from llama_index.core import SimpleDirectoryReader from llama_index.core.node_parser import SentenceSplitter from llama_index.core import VectorStoreIndex from llama_index.llms.openai import OpenAI docs SimpleDirectoryReader(./data/pdfs).load_data() parser SentenceSplitter(chunk_size512, chunk_overlap64) nodes parser.get_nodes_from_documents(docs) index VectorStoreIndex(nodes, show_progressTrue) query_engine index.as_query_engine( llmOpenAI(modelyour-model, api_keyyour-api-key, temperature0), similarity_top_k6, response_modecompact, ) resp query_engine.query(新员工的试用期是多久) print(resp.response)代码量少了将近一半而且默认配置已经能给出一个可用结果。这也是为什么“快速验证”场景我更推荐它。但如果你后续要在这个系统里加“判断试用期是否通过”的审批流LlamaIndex 就没有 LangChain 那种链式的原生支持了你得自己在外部拼逻辑。5.3 从代码看选型思路把两段代码放在一起你就能直观感受那件事LangChain 是“流程框架 检索能力”LlamaIndex 是“检索框架 流程能力”。它们都在往对方的地盘渗透但核心气质没有变。我的个人选型公式是项目里有明显的多步骤业务逻辑、需要调用多个外部系统 → 主选 LangChain检索部分可以用 LlamaIndex 的检索器补强。项目核心是文档问答、知识库内信息抽取 → 主选 LlamaIndex涉及复杂工具调用时再引入 LangChain 的 Agent 能力。项目是原型或内部小工具 → 优先 LlamaIndex简单直接除非你确定它马上要变成大型系统。6. 常见问题与避坑实录6.1 别在 LangChain 里手搓一堆链去做复杂 RAG我踩过最深的坑是在 LangChain 里试图用手工组合 Chain 的方式去实现复杂的多路召回、重排、反馈循环结果链越摞越长中间每个环节的输入输出都是自定义字典最后没人能维护。后来我把检索这块拆出来直接用 LlamaIndex 做检索LangChain 只负责外层编排代码瞬间清爽了很多。这件事给我的教训是不要在框架不擅长的地方硬刚。LangChain 可以写 RAGLlamaIndex 可以写流程但“可以”和“舒服”是两回事。模块边界设成“LangChain 管流程、LlamaIndex 管检索”之后两边都回到了舒适区。6.2 LlamaIndex 自定义能力有一定学习门槛LlamaIndex 开箱即用但它的自定义点非常多初始接触时容易被概念弄晕。Document、Node、Index、Retriever、QueryEngine、ResponseSynthesizer、NodeParser这一堆概念之间的依赖关系不看几个源码容易混淆。我的建议是从一个最小 demo 入手然后把as_query_engine()换成retriever synthesizer手动组合一遍。这个过程能帮你理解它内部到底发生了什么。一旦理解了这个层次后面换索引、换检索器、换合成策略都是顺藤摸瓜的事。6.3 版本更新频繁示例代码容易过期LangChain 和 LlamaIndex 都在快速迭代接口变化非常频繁。我自己就遇到过上个月还正常运行的导入下个月升级小版本就报“module not found”。这种问题不是你的锅但很浪费精力。经验措施有三条。一是锁定版本号项目里把主版本号写稳不要随手升级。二是别迷信网上剪贴板里的老代码凡是跑不通的先检查当前版本的核心文档。三是善用官方文档的“版本迁移指南”虽然追着看很费时间但比你去项目源码里考古高效得多。6.4 混用才是很多项目的最终形态我在前面提到的模块边界方案其实已经是我在两三个项目里验证过的模式。具体做法是主应用用 LangChain 搭建负责 Agent、工具、外部系统交互知识库部分不以 LangChain 的VectorStoreRetriever为终点而是用 LlamaIndex 单独维护一套索引和查询服务通过内部接口暴露给 LangChain 调用。这样做的好处很明显检索效果由 LlamaIndex 持续优化业务流程由 LangChain 稳定编排两边可以独立升级不会因为一方的接口变动把另一方带崩。代价是要多写一层接口封装但长期维护起来非常值得。注意不要在一开始就追求终极架构。先用一个框架把业务跑通当某个环节明显“使不上劲”时再引入另一个框架补位。架构是为业务服务的不是用来展示技术审美的。最后分享一个我的习惯每次做完选型我都会在项目里留一页“为什么这么选”的记录写上当时对比过的方案、关键权衡和预期风险。不是因为记性好而是因为过几个月再看你大概率会忘记当初为什么没选另一个框架。选型不是一锤子买卖它只是给后续迭代定了一个起点。真正让项目成功的还是你在选定框架之后对它特性的把握和对坑位的熟悉程度。希望这篇对比能帮你跳过一些我当初绕过的弯路。