1. 项目概述当Gemini 3.5 Pro遇上两大编排框架最近在折腾大模型应用开发的朋友估计都绕不开两个名字LangChain和LlamaIndex。它们就像是AI应用开发领域的“瑞士军刀”和“专业导航仪”各有各的擅长领域。与此同时Google的Gemini 3.5 Pro模型以其强大的多模态能力和在代码、推理任务上的出色表现成为了许多开发者在构建复杂应用时的新宠。但问题来了当你想把Gemini 3.5 Pro这颗强大的“大脑”接入到你的项目中时是选择生态庞大、组件丰富的LangChain还是选择专精于RAG检索增强生成、对数据索引有深度优化的LlamaIndex呢这个选择直接关系到后续的开发效率、系统性能和维护成本。我最近正好在两个不同的项目里分别用LangChain和LlamaIndex接入了Gemini 3.5 Pro完成了一些从简单对话到复杂文档问答的应用。整个过程下来感触颇深。这不仅仅是调用一个API那么简单它涉及到框架的设计哲学、对工作流的抽象方式、以及在你遇到坑时哪个框架能更快地帮你填上。这篇文章我就以一个一线开发者的视角来详细拆解一下这两种接入方式的异同、各自的优劣以及在不同场景下该如何选择。我会尽量抛开那些官方的、教科书式的对比多聊聊实际编码、调试、部署时遇到的真实情况和我的选择逻辑。2. 核心框架设计哲学与定位差异在深入代码之前我们必须先理解这两个框架的根本不同。这决定了它们处理问题的方式也直接影响了我们接入Gemini时的体验。2.1 LangChain以“链”为核心的通用型编排器你可以把LangChain想象成一个高度模块化的乐高工厂。它的核心设计思想是“链”Chain。任何复杂的大模型应用都被拆解成一系列可组合的“环节”Links比如调用模型、检索信息、处理输出、执行工具等。LangChain提供了海量的标准化“乐高积木”组件并定义了清晰的接口让你可以通过“链”把这些积木以任意顺序和逻辑组装起来构建出从简单到极其复杂的AI工作流。它的优势在于通用性和灵活性。无论是构建一个简单的聊天机器人还是一个需要调用数据库、搜索引擎、代码解释器、并具备记忆能力的多智能体Agent系统LangChain都有相应的组件和设计模式来支持。它的生态极其繁荣社区贡献了数以千计的集成工具、模板和第三方扩展。当你使用LangChain接入Gemini时你不仅仅是在调用一个模型你是在将一个强大的LLM嵌入到一个预设的、可无限扩展的自动化流水线中。注意这种强大灵活性带来的一个副作用是“初期的认知负担”。新手面对LangChain众多的概念Chain, Agent, Tool, Memory, Retrieval等和更底层的API时可能会感到无从下手。你需要花时间理解它的抽象层次。2.2 LlamaIndex以“数据”为中心的RAG专家与LangChain的“通用编排”定位不同LlamaIndex从诞生起就带着鲜明的使命成为连接私有数据与大模型的最佳桥梁。它的核心不是“链”而是“索引”Index。LlamaIndex将全部精力聚焦在RAG管道的“R”检索部分致力于解决如何高效地加载、解析、索引你的私有数据文档、数据库、API等并在查询时为LLM提供最相关、最精准的上下文。它的设计哲学是专精和开箱即用。对于RAG应用LlamaIndex提供了一套更高层、更声明式的API。你不需要像在LangChain里那样手动组装检索器、文本分割器、向量数据库连接器在LlamaIndex中你通常只需要定义数据源、选择索引类型如向量索引、摘要索引、树状索引等然后进行查询框架内部帮你处理了大部分繁琐的细节。它对多种数据格式的支持非常友好并且内置了复杂的检索策略比如混合检索、重排序等。因此当你主要目标是构建一个高质量的文档问答、知识库聊天机器人时LlamaIndex往往能让你用更少的代码更快地达到一个效果不错的基线。它的学习曲线在RAG领域相对平缓。2.3 哲学差异对接入的影响这种根本性的差异直接体现在我们接入Gemini 3.5 Pro的代码和思路上在LangChain中ChatGoogleGenerativeAI或GoogleGenerativeAI只是一个强大的“LLM组件”。你需要思考的是如何将它与你链条中的其他组件如提示模板、输出解析器、记忆模块、工具连接起来。你的代码结构围绕“工作流的构建”展开。在LlamaIndex中Gemini 3.5 Pro被配置为一个“LLM后端”。你的核心工作是定义和优化你的数据索引。你的代码结构围绕“数据的加载与查询”展开。框架更关心如何用最好的方式将你的数据“喂”给Gemini。理解这一点是做出正确技术选型的第一步。接下来我们就进入实战环节看看具体代码怎么写。3. 环境准备与基础接入实战无论选择哪个框架第一步都是准备好环境和基础的模型调用。这里我会展示最精简的接入代码并对比其中的异同。3.1 通用前置步骤安装与密钥配置首先你需要一个Gemini API密钥。前往Google AI Studio即可免费申请目前有较为充裕的免费额度非常适合开发和测试。安装必要的Python包# 如果你打算两个框架都尝试可以一次性安装 pip install langchain langchain-google-genai llama-index llama-index-llms-google # 或者按需安装 # 仅LangChain: pip install langchain langchain-google-genai # 仅LlamaIndex: pip install llama-index llama-index-llms-google将你的API密钥设置为环境变量这是安全且通用的做法# 在终端中设置临时 export GOOGLE_API_KEYyour_api_key_here # 或者在Python代码中设置不推荐用于生产 import os os.environ[GOOGLE_API_KEY] your_api_key_here3.2 LangChain 基础接入将Gemini作为组件在LangChain中我们通常使用langchain-google-genai这个官方集成包。接入非常简单核心是创建一个LLM实例。from langchain_google_genai import ChatGoogleGenerativeAI from langchain_core.messages import HumanMessage # 1. 创建ChatGoogleGenerativeAI实例 # 这里使用的是Gemini 1.5 Pro如需Gemini 2.0 Flash或其他模型修改model参数即可 llm ChatGoogleGenerativeAI( modelgemini-1.5-pro-latest, # 或 gemini-1.5-flash-latest 获取更快响应 temperature0.7, # 控制创造性0-1越高越随机 max_output_tokens1024, # 限制最大输出长度 convert_system_message_to_humanTrue # 处理系统消息的兼容性选项 ) # 2. 直接调用流式输出 print(LangChain 直接调用流式:) for chunk in llm.stream(请用一句话介绍你自己。): print(chunk.content, end, flushTrue) # 3. 使用LangChain的消息格式调用 messages [ HumanMessage(content谁是《三体》的作者) ] response llm.invoke(messages) print(f\n\nLangChain 消息调用:\n{response.content})代码解读与注意事项ChatGoogleGenerativeAI类是对应Gemini聊天模型的封装。如果你需要进行纯文本补全虽然Gemini主打聊天也有GoogleGenerativeAI类但前者更通用。temperature和max_output_tokens是关键参数需要根据你的应用场景调整。做创意写作可以调高temperature做事实问答则调低。convert_system_message_to_humanTrue是一个重要的兼容性参数。因为Gemini的API原生对“系统消息”的支持方式与OpenAI不同这个参数能确保LangChain格式的系统消息被正确转换。这是初期容易踩的坑如果发现系统指令不生效首先检查这个参数。3.3 LlamaIndex 基础接入将Gemini配置为后端在LlamaIndex中模型的配置通常与索引的创建和查询绑定得更紧密。我们首先需要配置一个“LLM”对象。from llama_index.llms.google import Gemini from llama_index.core import Settings # 1. 创建Gemini LLM实例 llm Gemini( modelmodels/gemini-1.5-pro-latest, # LlamaIndex中模型路径格式略有不同 temperature0.7, max_tokens1024, ) # 2. 将LLM设置为全局默认设置推荐方式 Settings.llm llm # 你也可以同时设置嵌入模型例如使用Gemini的嵌入模型或OpenAI的 # Settings.embed_model ... # 3. 直接调用LLM非流式 print(LlamaIndex 直接调用:) response llm.complete(请用一句话介绍你自己。) print(response.text) # 4. 使用聊天接口 from llama_index.core.llms import ChatMessage messages [ ChatMessage(roleuser, content谁是《三体》的作者) ] chat_response llm.chat(messages) print(f\nLlamaIndex 聊天调用:\n{chat_response.message.content})代码解读与注意事项LlamaIndex的Gemini类来自llama_index.llms.google其参数与LangChain版本大同小异。一个关键区别是模型名称的格式LlamaIndex中通常使用models/gemini-1.5-pro-latest这种完整路径这与Google AI Studio的格式一致。而LangChain的langchain-google-genai做了一层简化。Settings.llm llm这行代码非常重要。它将该LLM实例设置为全局默认。这意味着之后你创建的任何索引或查询引擎如果没有显式指定LLM都会自动使用这个Gemini实例。这简化了配置但也需要注意避免全局状态的意外修改。LlamaIndex同样支持流式响应通过stream_complete或stream_chat方法即可。基础接入对比小结 在简单的模型调用层面两者都非常直观几乎不分伯仲。LangChain的接口更接近“标准”的聊天LLM抽象而LlamaIndex通过Settings全局配置的方式在与自身索引系统集成时显得更便捷。真正的分水岭在我们开始构建实际应用时才会显现。4. 进阶应用对比构建一个文档问答系统让我们用一个更实际的场景来对比构建一个基于本地PDF文档的问答系统。这是RAG的经典用例。4.1 使用LangChain构建RAG流水线在LangChain中你需要像组装管道一样明确地定义每一个步骤。from langchain_google_genai import ChatGoogleGenerativeAI, GoogleGenerativeAIEmbeddings from langchain_community.document_loaders import PyPDFLoader from langchain_text_splitters import RecursiveCharacterTextSplitter from langchain_chroma import Chroma from langchain.chains import RetrievalQA from langchain.prompts import PromptTemplate # 1. 加载文档 loader PyPDFLoader(./your_document.pdf) documents loader.load() # 2. 分割文本 text_splitter RecursiveCharacterTextSplitter( chunk_size1000, # 每个块的大小 chunk_overlap200 # 块之间的重叠避免上下文断裂 ) texts text_splitter.split_documents(documents) # 3. 创建向量存储使用Gemini的嵌入模型 embeddings GoogleGenerativeAIEmbeddings(modelmodels/embedding-001) vectorstore Chroma.from_documents( documentstexts, embeddingembeddings, persist_directory./chroma_db # 可选持久化存储 ) # 4. 创建检索器 retriever vectorstore.as_retriever( search_typesimilarity, # 相似度搜索 search_kwargs{k: 4} # 返回最相关的4个块 ) # 5. 定义自定义提示模板 prompt_template 请根据以下上下文信息回答问题。如果你不知道答案就说你不知道不要编造答案。 上下文 {context} 问题{question} 请给出详细、准确的回答 PROMPT PromptTemplate( templateprompt_template, input_variables[context, question] ) # 6. 创建LLM实例 llm ChatGoogleGenerativeAI(modelgemini-1.5-pro-latest, temperature0.1) # 7. 组装成检索问答链 qa_chain RetrievalQA.from_chain_type( llmllm, chain_typestuff, # 最简单的方式将所有检索到的上下文塞进提示词 retrieverretriever, chain_type_kwargs{prompt: PROMPT}, # 使用自定义提示 return_source_documentsTrue # 返回源文档便于调试 ) # 8. 进行查询 query 文档中提到的核心挑战是什么 result qa_chain.invoke({query: query}) print(f答案{result[result]}) print(f\n来源文档前2个) for i, doc in enumerate(result[source_documents][:2]): print(f[{i1}] {doc.page_content[:200]}...)LangChain RAG实操心得显式控制你能清晰地看到并控制流水线的每一个环节加载器、分割器、嵌入模型、向量库、检索器、提示模板、LLM。这带来了极大的灵活性和调试便利。例如你可以轻松地将文本分割器从RecursiveCharacterTextSplitter换成TokenTextSplitter或者把向量数据库从Chroma换成Pinecone。链的多样性chain_type参数支持“stuff”、“map_reduce”、“refine”、“map_rerank”等多种模式用于处理长上下文。“stuff”最简单但如果检索到的文档总长度超过模型上下文窗口就需要用“map_reduce”等更复杂的方法。你需要根据文档长度和精度要求主动选择这是LangChain灵活性的体现也意味着更多的决策点。调试友好通过return_source_documentsTrue你可以直接看到模型做出回答所依据的原文片段这对于评估RAG效果、调整检索参数如chunk_size,k值至关重要。4.2 使用LlamaIndex构建RAG流水线在LlamaIndex中同样的功能代码会更加简洁和声明式。from llama_index.llms.google import Gemini from llama_index.embeddings.google import GoogleTextEmbedding from llama_index.core import VectorStoreIndex, SimpleDirectoryReader, Settings from llama_index.core.node_parser import SentenceSplitter # 1. 配置全局LLM和Embedding模型 Settings.llm Gemini(modelmodels/gemini-1.5-pro-latest, temperature0.1) Settings.embed_model GoogleTextEmbedding(modelmodels/embedding-001) # 配置文本分割器 Settings.text_splitter SentenceSplitter(chunk_size1000, chunk_overlap200) # 2. 加载数据并创建索引一步到位 documents SimpleDirectoryReader(input_dir./data).load_data() # 假设PDF在./data目录下 index VectorStoreIndex.from_documents( documents, show_progressTrue # 显示创建进度 ) # 可选持久化索引 index.storage_context.persist(persist_dir./llama_index_storage) # 3. 创建查询引擎 query_engine index.as_query_engine( similarity_top_k4, # 检索前4个相似节点 response_modecompact # 响应模式类似于“stuff” ) # 4. 进行查询 query 文档中提到的核心挑战是什么 response query_engine.query(query) print(f答案{response.response}) # 5. 获取并查看来源节点 print(f\n来源节点前2个) for i, node in enumerate(response.source_nodes[:2]): print(f[{i1}] {node.text[:200]}...)LlamaIndex RAG实操心得开箱即用与高抽象最直观的感受是代码量少。VectorStoreIndex.from_documents()这一行代码在背后帮你完成了文档加载根据文件类型自动选择、文本分割、嵌入生成、向量索引构建等一系列操作。你通过Settings进行全局配置框架负责协调。内置的智能处理LlamaIndex的Node概念比LangChain的Document更丰富。一个Document可以被解析成多个Node并且节点之间可以保留层次关系父节点、子节点。这对于处理结构复杂的文档如带有标题、章节的论文非常有利其内置的检索器可以利用这种结构进行更精准的检索。响应模式response_mode“compact”模式对应LangChain的“stuff”。LlamaIndex还提供了“refine”,“tree_summarize”等高级模式。关键在于这些模式在LlamaIndex中通常是作为查询引擎的一个参数而不是在创建链时就需要决定的“类型”感觉上更贴近“查询时优化”。存储上下文StorageContextLlamaIndex对索引的持久化和加载有更原生的支持storage_context.persist()和load_index_from_storage()用起来非常顺手。4.3 深度对比与选型建议通过上面的例子我们可以总结出更细致的对比特性维度LangChainLlamaIndex选型建议设计理念通用工作流编排框架数据连接与RAG专家框架LangChain适合构建复杂、多步骤、涉及外部工具或自定义逻辑的AI应用如智能体。LlamaIndex适合以数据检索为核心、追求快速搭建和高质量检索效果的RAG应用。学习曲线较陡峭概念多需理解底层组件在RAG领域相对平缓API更高层如果你是RAG新手想快速看到一个可用的文档问答DemoLlamaIndex更容易上手。如果你想深入理解RAG的每一个环节或有非标准需求LangChain更合适。代码控制粒度细粒度。你可以替换、定制流水线中的任意一个组件。粗粒度。框架封装了“最佳实践”管道定制需要通过覆盖组件或使用底层API。需要极致优化或特殊处理流程时选LangChain认可框架默认设计且想提升开发速度时选LlamaIndex。生态系统极其庞大。集成无数工具、数据库、内存方案等社区活跃。聚焦而深入。在数据连接器、索引结构、检索策略上非常专业。项目需要集成大量外部工具如Slack、GitHub、各种API时LangChain的生态是巨大优势。项目数据源复杂Notion、Confluence、数据库或需要高级检索时LlamaIndex可能更专业。调试与透明度高。可以轻松插入回调、检查中间步骤结果。中。高级抽象有时会隐藏细节但通过response.source_nodes等仍可调试。当应用出现问题时LangChain的细粒度流水线让你能更快定位是加载、分割、检索还是生成环节出了问题。我的个人经验原型验证阶段我倾向于使用LlamaIndex。它能让我在几十分钟内就把一堆杂乱的技术文档、会议纪要丢进去做出一个能回答基本问题的聊天机器人快速验证想法和数据的可行性。生产系统构建阶段随着需求复杂化比如需要对话历史、需要根据答案触发特定工具、需要复杂的后处理逻辑我会转向LangChain。它的模块化设计让我能像搭积木一样逐步构建起一个健壮、可维护的系统架构。例如我可以很方便地加入ConversationBufferMemory来让机器人拥有记忆或者用AgentExecutor来让它学会使用计算器、搜索网络。混合使用这完全可行你可以用LlamaIndex来构建高效、专业的数据索引和检索层然后将检索到的结果节点作为输入传递给一个由LangChain构建的、功能更复杂的处理与生成链或智能体。这结合了两者的优势。5. 高级特性与避坑指南在实际使用中还有一些高级功能和常见“坑点”值得分享。5.1 流式输出与异步支持两者都对流式输出和异步操作有良好支持。LangChain流式输出llm ChatGoogleGenerativeAI(modelgemini-1.5-pro-latest, streamingTrue) chain prompt | llm # 使用LCEL语法创建链 for chunk in chain.stream({question: 讲一个故事}): print(chunk.content, end, flushTrue)LlamaIndex流式输出query_engine index.as_query_engine(streamingTrue) streaming_response query_engine.query(讲一个故事) streaming_response.print_response_stream()异步调用对于构建高并发API服务至关重要。两者都支持ainvoke,astream,acomplete,achat等异步方法。在FastAPI或Django异步视图中使用异步接口可以显著提升吞吐量。5.2 提示工程与系统消息如何给Gemini设定角色和指令两者处理方式不同。在LangChain中你可以使用SystemMessage但务必记得设置convert_system_message_to_humanTrue或者更推荐地使用HumanMessagePromptTemplate来模拟系统指令。from langchain_core.prompts import ChatPromptTemplate from langchain_core.messages import SystemMessage # 方式1使用SystemMessage需配合convert_system_message_to_human prompt ChatPromptTemplate.from_messages([ SystemMessage(content你是一个专业的科技文章翻译助手。), (human, 请将以下英文翻译成中文{text}) ]) # 方式2更稳妥的方式将系统指令放在第一条人类消息中 prompt ChatPromptTemplate.from_messages([ (human, 你是一个专业的科技文章翻译助手。请将以下英文翻译成中文{text}) ])在LlamaIndex中你可以在创建查询引擎时通过text_qa_template或refine_template来注入系统指令这些模板是PromptTemplate对象。from llama_index.core import PromptTemplate qa_template PromptTemplate( 你是一位资深法律顾问请根据以下法律条文上下文用严谨的专业语言回答问题。 上下文 {context_str} 问题{query_str} 答案 ) query_engine index.as_query_engine(text_qa_templateqa_template)5.3 常见问题与排查错误API密钥未设置或无效现象google.api_core.exceptions.PermissionDenied: 403 ... API key not valid...解决确保GOOGLE_API_KEY环境变量已正确设置且未过期。在代码开头用print(os.getenv(GOOGLE_API_KEY))检查。错误模型名称错误或区域限制现象google.api_core.exceptions.InvalidArgument: 400 ... Model ‘gemini-pro’ is not supported...解决使用正确的模型名称。对于Gemini 1.5 ProLangChain用“gemini-1.5-pro-latest”LlamaIndex用“models/gemini-1.5-pro-latest”。同时确认该模型在你的区域可用。问题响应速度慢排查首先确认是否是网络问题。其次对于文本任务可以尝试切换到“gemini-1.5-flash-latest”模型它在保持较好能力的同时速度更快、成本更低。检查你的提示词是否过于冗长或检索返回的上下文k值是否过大。问题RAG答案质量不高胡编乱造排查这是RAG系统的核心挑战。首先检查你的检索质量。打印出source_documents或source_nodes看返回的文本片段是否真的与问题相关。如果不相关需要调整文本分割chunk_size可能不合适。太小会丢失上下文太大会引入噪声。尝试500-1500之间的值。检索策略尝试不同的search_type如“mmr”最大边际相关性来兼顾相关性和多样性或调整similarity_top_k。嵌入模型确保使用了合适的嵌入模型。对于中文text-embedding-004或专门的多语言模型可能比默认的更好。提示词优化在提示词中明确指令“严格根据上下文回答不知道就说不知道”。LangChain特定系统指令不生效解决确保在初始化ChatGoogleGenerativeAI时设置了convert_system_message_to_humanTrue。或者避免使用SystemMessage直接将指令放在第一条人类消息中。经过这几个项目的实战我个人最大的体会是没有绝对的“更好”只有“更合适”。LangChain和LlamaIndex都是极其优秀的框架它们代表了构建LLM应用的两种不同但互补的范式。我的建议是不妨两个都上手试一试用同一个简单的项目比如给你自己的简历PDF做个问答机器人分别实现一遍。这个过程本身就能让你深刻理解它们各自的抽象层次和设计美学从而为你未来更复杂的项目做出最明智的技术选型。