AGI 与未来 AI

从零开始构建LLM代理和超越:全面指南

mm
Building LLM Agents for RAG from Scratch and Beyond: A Comprehensive Guide

像GPT-3、GPT-4和它们的开源对应物一样的LLM,经常难以获取最新的信息检索,并且有时会生成幻觉或不正确的信息。

检索增强生成(RAG)是一种将LLM的力量与外部知识检索相结合的技术。RAG允许我们将LLM的响应建立在事实、最新的信息上,从而显著提高AI生成内容的准确性和可靠性。

在这篇博客文章中,我们将探讨如何从零开始构建LLM代理,深入探讨RAG的架构、实现细节和高级技术。我们将涵盖从RAG基础到创建能够进行复杂推理和任务执行的复杂代理的一切。

在我们开始构建LLM代理之前,让我们了解什么是RAG以及为什么它很重要。

RAG,即检索增强生成,是一种将信息检索与文本生成相结合的混合方法。在RAG系统中:

  • 使用查询从知识库中检索相关文档。
  • 然后将这些文档与原始查询一起输入语言模型中。
  • 模型根据查询和检索到的信息生成响应。
RAG

RAG

这种方法有几个优点:

  • 提高准确性:通过将响应建立在检索到的信息上,RAG减少了幻觉并提高了事实准确性。
  • 最新信息:知识库可以定期更新,从而使系统能够访问当前信息。
  • 透明度:系统可以提供其信息的来源,增加信任并允许事实核查。

理解LLM代理

 

当你面临一个没有简单答案的问题时,你经常需要遵循几个步骤,认真思考,并记住你已经尝试过什么。LLM代理专门为此类语言模型应用中的情况而设计。它们结合了彻底的数据分析、战略规划、数据检索和从过去的行动中学习的能力来解决复杂的问题。

什么是LLM代理?

LLM代理是为创建需要顺序推理的复杂文本而设计的高级AI系统。它们可以预测、记住过去的对话,并使用不同的工具根据情况和所需的风格调整其响应。

考虑一个法律领域的问题,例如:“在加利福尼亚州,某种类型的合同违约可能会产生什么法律后果?”具有检索增强生成(RAG)系统的基本LLM可以从法律数据库中检索必要的信息。

对于更详细的场景:“在新的数据隐私法的背景下,公司面临什么样的常见法律挑战,法院如何处理这些问题?”这个问题比简单地查找事实更深入。它是关于理解新规则、它们对不同公司的影响以及法院的回应。LLM代理将把这个任务分解为子任务,例如检索最新的法律、分析历史案例、总结法律文件,并根据模式预测趋势。

LLM代理的组件

LLM代理通常由四个组件组成:

  1. 代理/大脑:处理和理解语言的核心语言模型。
  2. 规划:推理、分解任务和制定具体计划的能力。
  3. 记忆:保持过去交互记录并从中学习。
  4. 工具使用:集成各种资源以执行任务。

代理/大脑

LLM代理的核心是一个语言模型,根据其训练的海量数据处理和理解语言。您首先给它一个特定的提示,指导代理如何响应、使用哪些工具以及要实现的目标。您可以使用适合特定任务或交互的个性来定制代理,从而增强其性能。

记忆

记忆组件帮助LLM代理处理复杂任务,通过保持过去操作的记录。主要有两种类型的记忆:

  • 短期记忆:像记事本一样,跟踪正在进行的讨论。
  • 长期记忆:像日记一样,存储来自过去交互的信息,以便学习模式和做出更好的决定。

通过结合这些类型的记忆,代理可以提供更个性化的响应,并随着时间的推移记住用户的偏好,从而创建更连贯和相关的交互。

规划

规划使LLM代理能够推理、将任务分解为可管理的部分,并根据任务的进展调整计划。规划涉及两个主要阶段:

  • 计划制定:将任务分解为较小的子任务。
  • 计划反思:审查和评估计划的有效性,纳入反馈以完善策略。

像链式思维(CoT)和思维树(ToT)这样的方法有助于这种分解过程,允许代理探索不同路径来解决问题。

要更深入地了解AI代理的世界,包括它们当前的能力和潜力,请考虑阅读 “Auto-GPT & GPT-Engineer:今天领先的AI代理的深入指南”

设置环境

要构建我们的RAG代理,我们需要设置开发环境。我们将使用Python和几个关键库:

  • LangChain:用于编排我们的LLM和检索组件
  • Chroma:作为我们的向量存储用于文档嵌入
  • OpenAI的GPT模型:作为我们的基础LLM(如果需要,可以用开源模型替换)
  • FastAPI:用于创建一个简单的API来与我们的代理交互

让我们从设置环境开始:


<p># 创建一个新虚拟环境
python -m venv rag_agent_env
source rag_agent_env/bin/activate # 在Windows上,使用 `rag_agent_env\Scripts\activate`</p>

<p># 安装所需的包
pip install langchain chromadb openai fastapi uvicorn

现在,让我们创建一个名为rag_agent.py的新Python文件,并导入必要的库:


<p>from langchain.embeddings import OpenAIEmbeddings
from langchain.vectorstores import Chroma
from langchain.text_splitter import CharacterTextSplitter
from langchain.llms import OpenAI
from langchain.chains import RetrievalQA
from langchain.document_loaders import TextLoader
import os</p>

<p># 设置您的OpenAI API密钥
os.environ[&quot;OPENAI_API_KEY&quot;] = &quot;your-api-key-here&quot;</p>

构建一个简单的RAG系统

现在我们有了环境,让我们构建一个基本的RAG系统。我们将从创建一个知识库开始,然后使用它来回答查询。

步骤1:准备文档

首先,我们需要加载和准备我们的文档。假设我们有一个名为knowledge_base.txt的文本文件,其中包含一些关于AI和机器学习的信息。


<p># 加载文档
loader = TextLoader(&quot;knowledge_base.txt&quot;)
documents = loader.load()</p>

<p># 将文档分成块
text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=0)
texts = text_splitter.split_documents(documents)</p>

<p># 创建嵌入
embeddings = OpenAIEmbeddings()</p>

<p># 创建向量存储
vectorstore = Chroma.from_documents(texts, embeddings)</p>

步骤2:创建一个基于检索的问答链

现在我们有了向量存储,我们可以创建一个基于检索的问答链:


<p># 创建一个基于检索的问答链
qa = RetrievalQA.from_chain_type(llm=OpenAI(), chain_type=&quot;stuff&quot;, retriever=vectorstore.as_retriever())</p>

步骤3:查询系统

我们现在可以查询我们的RAG系统:


<p>query = &quot;机器学习的主要应用是什么?&quot;
result = qa.run(query)
print(result)

步骤4:创建LLM代理

虽然我们的简单RAG系统很有用,但它非常有限。让我们通过创建一个LLM代理来增强它,该代理可以执行更复杂的任务并推理检索到的信息。

LLM代理是一种可以使用工具并对要采取的操作做出决定的AI系统。我们将创建一个代理,不仅可以回答问题,还可以执行网络搜索和基本计算。

首先,让我们为我们的代理定义一些工具:


<p>from langchain.agents import Tool
from langchain.tools import DuckDuckGoSearchRun
from langchain.tools import BaseTool
from langchain.agents import initialize_agent
from langchain.agents import AgentType</p>

<p># 定义一个计算器工具
class CalculatorTool(BaseTool):
name = &quot;Calculator&quot;
description = &quot;用于需要回答数学问题时&quot;</p>

<p>def _run(self, query: str)
try:
return str(eval(query))
except:
return &quot;我无法计算该值。请确保输入的是有效的数学表达式。&quot;</p>

<p># 创建工具实例
search = DuckDuckGoSearchRun()
calculator = CalculatorTool()</p>

<p># 定义工具
tools = [Tool(name=&quot;Search&quot;, func=search.run, description=&quot;用于需要回答当前事件问题时&quot;),
Tool(name=&quot;RAG-QA&quot;, func=qa.run, description=&quot;用于需要回答AI和机器学习问题时&quot;),
Tool(name=&quot;Calculator&quot;, func=calculator._run, description=&quot;用于需要执行数学计算时&quot;)
]</p>

<p># 初始化代理
agent = initialize_agent(tools, OpenAI(temperature=0), agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, verbose=True
)</p>

现在我们有了一个代理,可以使用我们的RAG系统、执行网络搜索和执行计算。让我们测试它:


<p>result = agent.run(&quot;什么是监督学习和无监督学习的区别?另外,80的15%是多少?&quot;)
print(result)</p>

这个代理演示了LLM代理的一个关键优势:它们可以结合多个工具和推理步骤来回答复杂的查询。

使用高级RAG技术增强代理

虽然我们的当前RAG系统效果很好,但有一些高级技术可以用来增强其性能:

a) 使用DPR的语义搜索

我们可以实现DPR来实现更准确的语义搜索:


<p>from transformers import DPRQuestionEncoder, DPRContextEncoder</p>

<p>question_encoder = DPRQuestionEncoder.from_pretrained(&quot;facebook/dpr-question_encoder-single-nq-base&quot;)
context_encoder = DPRContextEncoder.from_pretrained(&quot;facebook/dpr-ctx_encoder-single-nq-base&quot;)</p>

<p># 编码通道的函数
def encode_passages(passages):
return context_encoder(passages, max_length=512, return_tensors=&quot;pt&quot;).pooler_output</p>

<p># 编码查询的函数
def encode_query(query):
return question_encoder(query, max_length=512, return_tensors=&quot;pt&quot;).pooler_output</p>

b) 查询扩展

我们可以使用查询扩展来提高检索性能:


<p>from transformers import T5ForConditionalGeneration, T5Tokenizer</p>

<p>model = T5ForConditionalGeneration.from_pretrained(&quot;t5-small&quot;)
tokenizer = T5Tokenizer.from_pretrained(&quot;t5-small&quot;)</p>

<p>def expand_query(query):
input_text = f&quot;expand query: {query}&quot;
input_ids = tokenizer.encode(input_text, return_tensors=&quot;pt&quot;)
outputs = model.generate(input_ids, max_length=50, num_return_sequences=3)
expanded_queries = [tokenizer.decode(output, skip_special_tokens=True) for output in outputs]
return expanded_queries</p>

c) 迭代精化

我们可以实现一个迭代精化过程,其中代理可以提出后续问题来澄清或扩展其初始检索:


<p>def iterative_retrieval(initial_query, max_iterations=3):
query = initial_query
for _ in range(max_iterations):
result = qa.run(query)
clarification = agent.run(f&quot;基于此结果:&#039;{result}&#039;,我应该提出什么后续问题来获取更多具体信息?&quot;)
if clarification.lower().strip() == &quot;none&quot;:
break
query = clarification
return result</p>

# 在您的代理过程中使用此函数

实现多代理系统

为了处理更复杂的任务,我们可以实现一个多代理系统,其中不同的代理专门从事不同的领域。以下是一个简单的例子:


<p>class SpecialistAgent:
def __init__(self, name, tools):
self.name = name
self.agent = initialize_agent(tools, OpenAI(temperature=0), agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, verbose=True)</p>

<p>def run(self, query):
return self.agent.run(query)</p>

<p># 创建专家代理
research_agent = SpecialistAgent(&quot;Research&quot;, [Tool(name=&quot;RAG-QA&quot;, func=qa.run, description=&quot;用于AI和ML问题&quot;)])
math_agent = SpecialistAgent(&quot;Math&quot;, [Tool(name=&quot;Calculator&quot;, func=calculator._run, description=&quot;用于计算&quot;)])
general_agent = SpecialistAgent(&quot;General&quot;, [Tool(name=&quot;Search&quot;, func=search.run, description=&quot;用于一般查询&quot;)])</p>

<p>class Coordinator:
def __init__(self, agents):
self.agents = agents</p>

<p>def run(self, query):
# 确定要使用哪个代理
if &quot;calculate&quot; in query.lower() or any(op in query for op in [&#039;+&#039;, &#039;-&#039;, &#039;*&#039;, &#039;/&#039;]):
return self.agents[&#039;Math&#039;].run(query)
elif any(term in query.lower() for term in [&#039;ai&#039;, &#039;machine learning&#039;, &#039;deep learning&#039;]):
return self.agents[&#039;Research&#039;].run(query)
else:
return self.agents[&#039;General&#039;].run(query)</p>

<p>coordinator = Coordinator({&#039;Research&#039;: research_agent, &#039;Math&#039;: math_agent, &#039;General&#039;: general_agent})</p>

<p># 测试多代理系统
result = coordinator.run(&quot;什么是CNN和RNN之间的区别?另外,120的25%是多少?&quot;)
print(result)</p>

这个多代理系统允许专门化,并且可以更有效地处理更广泛的查询。

评估和优化RAG代理

为了确保我们的RAG代理表现良好,我们需要实施评估指标和优化技术:

a) 相关性评估

我们可以使用BLEU、ROUGE或BERTScore等指标来评估检索文档的相关性:


<p>from bert_score import score</p>

<p>def evaluate_relevance(query, retrieved_doc, generated_answer):
P, R, F1 = score([generated_answer], [retrieved_doc], lang=&quot;en&quot;)
return F1.mean().item()</p>

b) 答案质量评估

我们可以使用人工评估或自动评估指标来评估答案质量:


<p>from nltk.translate.bleu_score import sentence_bleu</p>

<p>def evaluate_answer_quality(reference_answer, generated_answer):
return sentence_bleu([reference_answer.split()], generated_answer.split())</p>

<p># 使用此函数来评估您的代理的响应

未来方向和挑战

当我们展望RAG代理的未来时,出现了几个令人兴奋的方向和挑战:

a) 多模态RAG:将RAG扩展到包含图像、音频和视频数据。

b) 联邦RAG:在分布式、隐私保护的知识库中实现RAG。

c) 持续学习:开发方法,使RAG代理能够更新其知识库和模型。

d) 道德考虑:解决RAG系统中的偏见、公平性和透明度问题。

e) 可扩展性:优化RAG以适应大规模、实时应用。

结论

从零开始构建LLM代理是一个复杂但有价值的过程。我们涵盖了RAG的基础、实现、创建LLM代理、使用高级技术增强代理、探索多代理系统以及讨论评估和优化策略。

我已经沉浸在了令人着迷的机器学习和深度学习世界中五年了。我的热情和专业知识让我为超过50个不同的软件工程项目做出了贡献,特别关注AI/ML。我的持续的好奇心也让我对自然语言处理产生了兴趣,这是一个我渴望进一步探索的领域。