langchain 的 runnable 是通用计算流接口,llamaindex 的 queryengine 是专为文档问答封装的黑盒;前者需手动构建链,后者依赖 vectorstoreindex 预置流程。

LangChain 的 Runnable 和 LlamaIndex 的 QueryEngine 本质不是同类抽象
LangChain 的 Runnable 是通用计算流接口,能串任何函数、LLM 调用、工具或异步操作;LlamaIndex 的 QueryEngine 是专为“文档问答”封装的黑盒,输入 query,输出 response,内部固定走 retrieval → synthesis 流程。硬比“谁更好用”容易误判——你真需要的是 pipeline 可控性,还是开箱即用的 RAG 效果?
常见错误现象:ValueError: Cannot run QueryEngine without nodes 或 RunnableSequence 报 TypeError: object is not callable,往往是因为混淆了这两者的职责边界:前者要你亲手搭链,后者要你先喂够 VectorStoreIndex。
- 如果你在做多跳推理、混合调用外部 API + LLM + 数据库,
Runnable更直觉,但得自己 handle 错误传播和中间态缓存 - 如果你只做企业文档问答,且数据结构稳定(PDF/Markdown/Notion 导出),
QueryEngine的SubQuestionQueryEngine或HybridQueryEngine开箱就比手写Runnable链快 2–3 天 -
QueryEngine默认不暴露 retrieval 结果,想 debug 检索质量?得手动传callback_manager或 patchretrieve()方法;Runnable则天然支持每步invoke(..., config={"callbacks": [...]})
LlamaIndex 的 VectorStoreIndex 对 embedding 模型更敏感
LangChain 的 Chroma 或 FAISS vectorstore 接收的是预计算好的向量,embedding 模型换不换,不影响已有索引;但 LlamaIndex 的 VectorStoreIndex 在构建时会直接绑定 embedding model 实例,一旦 model 变(比如从 text-embedding-3-small 换成 gte-Qwen2),旧索引必须重建,否则检索结果完全失效。
使用场景:你正在迭代 embedding 模型,又不想每次重跑全量文档处理流水线?LangChain 的向量存储解耦更友好;LlamaIndex 则要求你在 ServiceContext 里显式冻结 embed_model,且不能跨版本混用 .json 索引文件。
立即学习“Python免费学习笔记(深入)”;
- 性能影响:LlamaIndex 默认用
hnswlib,10 万 chunk 下查询延迟比 LangChain+FAISS 低 15–20%,但内存占用高约 1.8 倍 - 兼容性坑:
VectorStoreIndex.from_vector_store(...)看似能复用外部向量库,实际仍会尝试调用原embed_model的get_text_embedding_batch,导致 schema 不匹配报错 - 小技巧:用
SimpleDirectoryReader加载时设filename_as_id=True,后续查不到结果时至少能快速定位是 embedding 还是分块问题
LangChain 的 AgentExecutor 和 LlamaIndex 的 ReActAgent 都依赖 prompt 工程,但失败信号完全不同
AgentExecutor 卡住时通常抛 OutputParserException 或无限循环在 Thought: ... Action: ... Observation: ...;ReActAgent 则静默返回空 response 或 fallback 到 default_response,连 error log 都不打——因为它的 output_parser 是硬编码在 ReActOutputParser 里的,没做异常透出。
参数差异:LangChain 允许你替换 agent_executor 的 output_parser 为自定义类,也能关掉 handle_parsing_errors 强制 crash;LlamaIndex 的 ReActAgent 只能通过 max_iterations 和 verbose=True 看中间 step,想改解析逻辑?得继承 ReActAgentWorker 重写 _get_response。
- 调试建议:对
AgentExecutor,加callbacks=[ConsoleCallbackHandler()];对ReActAgent,必须设callback_manager=CallbackManager([LlamaDebugHandler()])才能看到 tool call 输入输出 - 容易踩的坑:两者都默认用
gpt-4-turbo级 prompt template,但若换成本地Qwen2-7B,LangChain 可以直接换prompt参数,LlamaIndex 得重写整个ReActPrompt并注册进BasePromptTemplate
2026 年真实项目里,90% 的“选型纠结”其实来自数据管道而非框架本身
LangChain 的 DocumentLoader 和 LlamaIndex 的 BaseReader 都支持 PDF 解析,但 PyMuPDFReader(LlamaIndex)默认保留表格结构,PyPDFLoader(LangChain)默认丢弃;你如果靠 OCR 后的 PDF 做合同比对,这个差异会让召回率差 40% 以上。
真正卡住进度的,从来不是 QueryEngine 还是 Runnable,而是:unstructured 版本升级后 partition_pdf 返回字段名从 "text" 变成 "element_text",而你的 NodeParser 还在按老字段切分;或是 Chroma 升级到 v0.5 后 collection.get() 不再返回 metadatas 字段,LangChain 的 RetrievalQA 直接崩。
所以别花三天对比 API 设计哲学。先跑通一条最小路径:PDF → 分块 → embed → 存 → 检索 → 问答。哪一步断了,就盯死那层——是 loader 输出不对,还是 embedding batch size 超限,还是 vectorstore 的 metadata filter 语法写错了。框架只是胶水,胶水粘不住漏气的管道。










