当前位置: 首页 > ai >正文

【面试题】LangChain与LlamaIndex核心概念详解

在这里插入图片描述

1. 什么是LangChain?它的核心设计理念是什么?

LangChain是一个用于构建大语言模型应用的框架,它提供了模块化组件和工具链,帮助开发者将LLM与外部数据和系统连接起来。其核心理念是组件化链式编排——通过标准化接口将各种功能模块(模型、工具、数据源)连接成可复用的处理流程。

LangChain的设计遵循几个关键原则:

  • 组合性:所有组件实现统一接口,可以通过管道操作符(|)轻松组合
  • 数据感知:内置多种数据连接器,使LLM能够访问外部知识源
  • 代理能力:支持让LLM自主选择工具和决策的智能代理模式
  • 生产就绪:提供调试、监控、部署等生产环境所需功能

2. LangChain中的6个核心概念

Models (模型)

  • LLMs:基础文本生成模型(如GPT-3)
  • ChatModels:对话优化模型(如ChatGPT)
  • Embeddings:文本向量化模型
    所有模型都实现Runnable接口,支持统一调用方式。

Prompts (提示)

  • 模板化:支持变量插值的提示模板
  • 少量示例:支持在提示中包含示例样本
  • 动态构建:可根据对话历史动态构建提示

Indexes (索引)

  • 文档加载:从各种来源加载文档
  • 文本分割:将长文档分割为适当片段
  • 向量存储:将文本转换为向量并存储
  • 检索器:从索引中检索相关文档

Memory (记忆)

  • 对话历史:维护多轮对话状态
  • 多种形式:支持短期记忆、摘要记忆、实体记忆等
  • 可定制:可根据需要定制记忆存储策略

Chains (链)

  • 顺序链:线性执行多个步骤
  • 转换链:处理数据格式转换
  • 路由链:根据条件选择不同分支
  • LCEL:使用表达式语言声明式构建链

Agents (代理)

  • 工具使用:让LLM自主选择和使用工具
  • 推理循环:基于ReAct框架进行推理和行动
  • 多种类型:支持ReAct、Plan-and-execute等多种代理类型

3. 什么是LCEL?它有什么优势?请写一个简单的例子

LCEL(LangChain Expression Language)是LangChain的声明式API,用于构建和组合链。它的核心优势包括:

主要优势

  • 统一接口:所有组件实现Runnable接口
  • 自动并行:自动并行处理多个输入
  • 流式支持:原生支持流式输出
  • 错误处理:内置重试和回退机制
  • 易于调试:提供详细的执行追踪

简单示例

from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
from langchain_core.output_parsers import StrOutputParser# 创建翻译链
translation_chain = (ChatPromptTemplate.from_template("将以下文本翻译成{language}: {text}")| ChatOpenAI(model="gpt-3.5-turbo")| StrOutputParser()
)# 使用链
result = translation_chain.invoke({"text": "Hello, world!","language": "中文"
})
print(result)  # 输出: "你好,世界!"

高级示例(带错误处理):

from langchain_core.runnables import RunnableBranch# 创建带分支的链
branch_chain = RunnableBranch((lambda x: "你好" in x["text"], translation_chain),translation_chain
)# 只会调用翻译链一次
result = branch_chain.invoke({"text": "Hello, world!","language": "中文"
})

4. Agent的执行流程(使用ReAct框架举例)

ReAct框架让Agent通过"思考-行动-观察"循环解决问题:

执行流程

  1. 初始化:接收用户查询,初始化提示模板
  2. 思考:LLM分析当前情况,决定下一步行动
  3. 行动:选择合适工具并生成调用参数
  4. 观察:执行工具并获取结果
  5. 循环:重复2-4步直到解决问题
  6. 终止:输出最终答案

具体示例

用户: "旧金山昨天的最高温度是多少华氏度?"Agent思考: "我需要获取旧金山昨天的天气数据,应该使用天气API工具"
Agent行动: 调用WeatherAPI("San Francisco", "yesterday")
观察: "高温: 65°F, 低温: 52°F"Agent思考: "我已获得天气数据,可以直接回答用户问题"
Agent输出: "旧金山昨天的最高温度是65°F"

关键特点

  • 每一步的思考和行动都记录在对话历史中
  • 支持工具调用失败时的重试机制
  • 可设置最大迭代次数防止无限循环

5. 什么是RAG?如何在LangChain中实现一个基本的RAG流程?

RAG(Retrieval-Augmented Generation)通过检索外部知识增强生成能力,减少模型幻觉。

LangChain实现方案

from langchain_community.document_loaders import WebBaseLoader
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_openai import OpenAIEmbeddings, ChatOpenAI
from langchain_chroma import Chroma
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough# 1. 加载和预处理文档
loader = WebBaseLoader("https://example.com")
docs = loader.load()# 2. 分割文档
text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200
)
splits = text_splitter.split_documents(docs)# 3. 创建向量存储
embeddings = OpenAIEmbeddings()
vectorstore = Chroma.from_documents(splits, embeddings)
retriever = vectorstore.as_retriever()# 4. 创建RAG链
template = """使用以下上下文回答问题。如果不知道答案,请如实告知。
上下文: {context}
问题: {question}
答案:"""
prompt = ChatPromptTemplate.from_template(template)llm = ChatOpenAI(model="gpt-3.5-turbo")rag_chain = ({"context": retriever, "question": RunnablePassthrough()}| prompt| llm| StrOutputParser()
)# 5. 使用RAG链
result = rag_chain.invoke("这篇文章的主要内容是什么?")

优化技巧

  • 使用更好的嵌入模型提高检索质量
  • 调整chunk_size和chunk_overlap参数
  • 添加重排序步骤提高相关性
  • 使用多查询生成增强检索

6. LlamaIndex的核心价值与LangChain的主要区别

LlamaIndex核心价值
专注于数据连接层,提供高效的文档索引和检索能力,特别擅长:

  • 复杂文档解析(PDF、Word等)
  • 高级索引结构(向量、树形、关键词等)
  • 智能查询优化和重写
  • 开箱即用的RAG解决方案

与LangChain的主要区别

方面LlamaIndexLangChain
定位数据连接和检索专家通用应用编排框架
核心功能文档索引和查询链式工作流和代理
抽象层级更高层,更专注更底层,更灵活
使用难度学习曲线较平缓学习曲线较陡峭
典型用例文档问答、知识检索复杂代理、多步工作流

如何选择

  • 需要快速构建文档问答系统 → LlamaIndex
  • 需要复杂逻辑和工具使用 → LangChain
  • 大型项目 → 结合使用(LlamaIndex处理数据,LangChain处理逻辑)

7. LlamaIndex中的核心组件

Nodes (节点)

文档的基本单元,包含文本内容和元数据:

from llama_index.core.schema import TextNodenode = TextNode(text="文档内容",metadata={"source": "document.pdf", "page": 1}
)

Indexes (索引)

多种索引类型适应不同场景:

  • VectorStoreIndex:向量索引,适合语义搜索
  • SummaryIndex:摘要索引,适合整体分析
  • TreeIndex:树形索引,适合层次结构
  • KeywordTableIndex:关键词索引,适合精确匹配

Engines (引擎)

处理查询的核心组件:

  • Retrievers:从索引中检索相关节点
  • Query Engines:处理完整查询流程
  • Response Synthesizers:生成最终答案

使用示例

from llama_index.core import VectorStoreIndex# 创建索引
index = VectorStoreIndex.from_documents(documents)# 创建查询引擎
query_engine = index.as_query_engine()# 执行查询
response = query_engine.query("你的问题")

8. LlamaIndex的高级查询/检索模式

1. 子问题分解

将复杂问题分解为多个子问题:

from llama_index.core.query_engine import SubQuestionQueryEnginequery_engine = SubQuestionQueryEngine.from_defaults(query_engine_tools=[engine1, engine2]
)

2. 多步查询

支持多轮交互的复杂查询:

from llama_index.core.query_engine import MultiStepQueryEnginequery_engine = MultiStepQueryEngine(query_engine, num_steps=3
)

3. 混合检索

结合多种检索策略:

from llama_index.core import VectorStoreIndex, KeywordTableIndex
from llama_index.core.retrievers import QueryFusionRetrievervector_retriever = VectorStoreIndex.as_retriever()
keyword_retriever = KeywordTableIndex.as_retriever()fusion_retriever = QueryFusionRetriever([vector_retriever, keyword_retriever]
)

9. RAG中文档切分的重要性与策略

为什么文档切分重要

  • 影响检索精度:过大或过小的块都会降低相关性
  • 影响生成质量:提供不完整的上下文会导致错误答案
  • 影响性能:合理的块大小提高检索效率

常用切分策略

  1. 固定大小切分
from langchain_text_splitters import CharacterTextSplittersplitter = CharacterTextSplitter(chunk_size=1000,chunk_overlap=200
)
  1. 递归切分(推荐):
from langchain_text_splitters import RecursiveCharacterTextSplittersplitter = RecursiveCharacterTextSplitter(chunk_size=512,chunk_overlap=50
)
  1. 语义切分
from langchain_experimental.text_splitter import SemanticChunkersplitter = SemanticChunker(OpenAIEmbeddings())

最佳实践

  • 一般文档:500-1000字符的块大小,10-20%重叠
  • 技术文档:较小的块大小(200-500字符)
  • 对话记录:按对话轮次切分
  • 代码文档:按函数或类切分

10. 评估和提升RAG应用效果

评估指标

  • 检索质量:命中率、MRR、NDCG
  • 生成质量:事实准确性、相关性、流畅性
  • 端到端指标:答案相关性、有用性评分

提升策略

检索阶段优化

# 1. 优化检索器
retriever = vectorstore.as_retriever(search_type="mmr",  # 使用最大边际相关性search_kwargs={"k": 5, "fetch_k": 20}
)# 2. 添加重排序
from langchain.retrievers import ContextualCompressionRetriever
from langchain_cohere import CohereRerankcompressor = CohereRerank()
compression_retriever = ContextualCompressionRetriever(base_compressor=compressor,base_retriever=retriever
)

生成阶段优化

# 1. 优化提示模板
template = """请基于以下上下文回答问题。如果上下文不包含答案,请说"我不知道"。上下文:{context}问题:{question}请以友好、专业的语气回答,并在必要时引用上下文。"""

端到端优化

# 添加验证步骤
def validate_answer(response):if "我不知道" in response or "不确定" in response:return "抱歉,我无法从提供的资料中找到答案。"return responsefinal_chain = rag_chain | validate_answer

11. ReAct框架与自定义Tool实现

ReAct框架详解

ReAct通过"思考-行动-观察"循环让LLM解决复杂问题:

循环步骤

  1. 思考:分析当前状况,决定下一步
  2. 行动:选择工具并生成参数
  3. 观察:执行工具并获取结果
  4. 重复:直到问题解决或达到最大迭代

优势

  • 减少幻觉:通过工具验证假设
  • 提高透明度:显示完整推理过程
  • 增强能力:突破LLM的知识限制

自定义Tool实现

安全实现示例

from langchain.tools import BaseTool
from pydantic import BaseModel, Field
import requestsclass WeatherInput(BaseModel):location: str = Field(description="城市名称")date: str = Field(description="日期,如'今天'、'明天'")class WeatherTool(BaseTool):name = "weather_api"description = "获取指定城市和日期的天气信息"args_schema = WeatherInputdef _run(self, location: str, date: str) -> str:"""调用天气API"""try:# 这里使用模拟API调用# 实际应用中应使用真实的天气APIif date == "今天":return f"{location}今天天气晴朗,25°C"elif date == "明天":return f"{location}明天多云转晴,23°C"else:return "仅支持查询今天或明天的天气"except Exception as e:return f"获取天气信息失败: {str(e)}"async def _arun(self, location: str, date: str) -> str:return self._run(location, date)# 使用工具
tool = WeatherTool()
result = tool.run("北京", "今天")
print(result)  # 输出: "北京今天天气晴朗,25°C"

安全最佳实践

  1. 输入验证:使用Pydantic模型验证参数
  2. 错误处理:妥善处理异常,避免暴露内部信息
  3. 权限控制:限制工具访问权限
  4. 日志记录:记录所有工具调用情况

在Agent中使用工具

from langchain.agents import initialize_agent
from langchain.agents import AgentTypetools = [WeatherTool()]
agent = initialize_agent(tools,llm,agent=AgentType.STRUCTURED_CHAT_ZERO_SHOT_REACT_DESCRIPTION,verbose=True
)result = agent.run("北京今天天气怎么样?")

通过这样的实现,可以创建安全、可靠的自定义工具,大大扩展Agent的能力范围。

http://www.xdnf.cn/news/19884.html

相关文章:

  • 聚焦GISBox矢量服务:数据管理、数据库连接与框架预览全攻略
  • 分布式电源接入电网进行潮流计算
  • Linux笔记---UDP套接字实战:简易聊天室
  • 服务器不支持node.js16以上版本安装?用Docker轻松部署Node.js 20+环境运行Strapi项目
  • 新规则,新游戏:AI时代下的战略重构与商业实践
  • 安全领域必须关注每年发布一次“最危险的25种软件弱点”清单 —— CWE Top 25(内附2024 CWE Top 25清单详情)
  • Boost搜索引擎 数据清洗与去标签(1)
  • 【OpenHarmony文件管理子系统】文件访问接口mod_fs解析
  • ECMAScript(2)核心语法课件(Node.js/React 环境)
  • uniapp的上拉加载H5和小程序
  • PDF.AI-与你的PDF文档对话
  • C++虚函数虚析构函数纯虚函数的使用说明和理解
  • redisson延迟队列报错Sync methods can‘t be invoked from async_rx_reactive listeners
  • 快速排序算法详解
  • 【mysql】SQL自连接实战:查询温度升高的日期
  • 三维多相机光场扫描:打造元宇宙时代的“数字自我”
  • React学习教程,从入门到精通, React 嵌套组件语法知识点(10)
  • 公司机密视频泄露频发?如何让机密视频只在公司内部播放
  • 数据采集机器人哪家好?2025 年实测推荐:千里聆 RPA 凭什么成企业首选?
  • 机器人智能控制领域技术路线
  • 嵌入式 - 硬件:51单片机(3)uart串口
  • 【Java EE进阶 --- SpringBoot】Spring IoC
  • 鸿蒙:从图库选择图片并上传到服务器
  • 什么情况下会用到ConcurrentSkipListMap
  • 【系统架构设计(15)】软件架构设计一:软件架构概念与基于架构的软件开发
  • PDF Reader 编辑阅读工具(Mac中文)
  • Linux 常用命令全解析:从入门到实战的必备指南
  • TypeScript 增强功能大纲 (相对于 ECMAScript)
  • 如何轻松地将联系人从 Mac 同步到 iPhone
  • SQLmap 完整使用指南:环境搭建 + 命令详解 + 实操案例