AGI

Bygging av LLM-agenter for RAG fra scratch og utover: En omfattende guide

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

LLM-er som GPT-3, GPT-4 og deres åpne kilde-konterparter kan noen ganger slite med oppdatert informasjonsøkning og generere hallucinasjoner eller feilaktig informasjon.

Retrieval-Augmented Generation (RAG) er en teknikk som kombinerer kraften til LLM-er med eksterne kunnskapsøkning. RAG lar oss grunnlegge LLM-svar i faktiske, oppdaterte opplysninger, og forbedrer nøyaktigheten og påliteligheten til AI-generert innhold.

I denne bloggposten vil vi utforske hvordan vi kan bygge LLM-agenter for RAG fra scratch, og dykke dypt inn i arkitekturen, implementeringsdetaljer og avanserte tekniker. Vi vil dekke alt fra grunnleggende RAG til å lage sofistikerte agenter som kan utføre komplekse oppgaver og tankeprosesser.

Før vi dykker inn i å bygge vår LLM-agent, la oss forstå hva RAG er og hvorfor det er viktig.

RAG, eller Retrieval-Augmented Generation, er en hybridtilnærming som kombinerer informasjonsøkning med tekstgenerering. I et RAG-system:

  • En spørring brukes til å hente relevante dokumenter fra en kunnskapsbase.
  • Disse dokumentene føres deretter inn i en språkmodell sammen med den opprinnelige spørringen.
  • Modellen genererer et svar basert på både spørringen og den hentede informasjonen.
RAG

RAG

Denne tilnærmingen har flere fordeler:

  • Forbedret nøyaktighet: Ved å grunnlegge svar i hentet informasjon, reduserer RAG hallucinasjoner og forbedrer faktisk nøyaktighet.
  • Oppdatert informasjon: Kunnskapsbasen kan oppdateres regelmessig, og lar systemet få tilgang til aktuell informasjon.
  • Gjennomsiktighet: Systemet kan angi kilder for sin informasjon, og øke tillit og mulighet for faktasjekking.

Forståelse av LLM-agenter

 

Når du møter et problem uten en enkel løsning, må du ofte følge flere trinn, tenke nøye og huske hva du allerede har prøvd. LLM-agenter er designet for nettopp slike situasjoner i språkmodell-applikasjoner. De kombinerer grundig dataanalyse, strategisk planlegging, datahenting og evnen til å lære fra tidligere handlinger for å løse komplekse problemer.

Hva er LLM-agenter?

LLM-agenter er avanserte AI-systemer designet for å lage kompleks tekst som krever sekvensiell resonnering. De kan tenke foran, huske tidligere samtaler og bruke ulike verktøy til å tilpasse svarene sine basert på situasjonen og stilen som trengs.

Overvei et spørsmål i det juridiske feltet som: “Hva er de potensielle juridiske utfallene av en bestemt type kontraktbrudd i California?” En grundig LLM med en RAG-system kan hente nødvendig informasjon fra juridiske databaser.

For en mer detaljert scenario: “I lys av nye datavernlovene, hva er de vanlige juridiske utfordringene selskaper møter, og hvordan har domstolene behandlet disse problemene?” Dette spørsmålet graver dypere enn bare å se opp fakta. Det handler om å forstå nye regler, deres innvirkning på ulike selskaper og domstolenes svar. En LLM-agent ville bryte denne oppgaven ned i underoppgaver, som å hente de nyeste lovene, analysere historiske saker, summerer juridiske dokumenter og forutsi trender basert på mønster.

Komponenter av LLM-agenter

LLM-agenter består vanligvis av fire komponenter:

  1. Agent/Hjerne: Den grunnleggende språkmodellen som behandler og forstår språk.
  2. Planlegging: Evnen til å resonere, bryte ned oppgaver og utvikle spesifikke planer.
  3. Hukommelse: Vedlikeholder poster over tidligere interaksjoner og lærer fra dem.
  4. Verktøybruk: Integrerer ulike ressurser for å utføre oppgaver.

Agent/Hjerne

I kjernen av en LLM-agent ligger en språkmodell som behandler og forstår språk basert på store mengder data den er trent på. Du starter med å gi den en bestemt prompt, og guiden agenten på hvordan den skal svare, hvilke verktøy den skal bruke og hvilke mål den skal nå. Du kan tilpasse agenten med en personlighet som er egnet for bestemte oppgaver eller interaksjoner, og forbedre dens ytelse.

Hukommelse

Hukommelseskomponenten hjelper LLM-agenter med å håndtere komplekse oppgaver ved å vedlikeholde en post over tidligere handlinger. Det finnes to hovedtyper hukommelse:

  • Korttidsminne: Fungerer som en notisblokk, og holder styr på pågående samtaler.
  • Langtidsminne: Fungerer som en dagbok, og lagrer informasjon fra tidligere interaksjoner for å lære mønster og ta bedre beslutninger.

Ved å blande disse typene hukommelse, kan agenten tilby mer tilpassede svar og huske brukerpreferanser over tid, og skape en mer sammenhengende og relevant interaksjon.

Planlegging

Planlegging aktiverer LLM-agenter til å resonere, bryte ned oppgaver i håndterbare deler og tilpasse planer etterhvert som oppgavene utvikler seg. Planlegging involverer to hovedfaser:

  • Planformulering: Bryter ned en oppgave i mindre underoppgaver.
  • Planrefleksjon: Gjennomgår og vurderer planens effektivitet, og inkorporerer tilbakemeldinger for å finjustere strategier.

Metoder som Chain of Thought (CoT) og Tree of Thought (ToT) hjelper i denne nedbrytningsprosessen, og lar agenter utforske ulike stier for å løse et problem.

For å dykke dyptere inn i verden av AI-agenter, inkludert deres nåværende evner og potensiale, kan du lese “Auto-GPT & GPT-Engineer: En dybdeguide til dagens ledende AI-agenter”

Oppsett av miljøet

For å bygge vår RAG-agent, må vi oppsette vår utviklingsmiljø. Vi vil bruke Python og flere nøkkelbiblioteker:

  • LangChain: For å orkestrere vår LLM- og hentingkomponenter
  • Chroma: Som vår vektorlagring for dokument-embeddings
  • OpenAI’s GPT-modeller: Som vår grunnleggende LLM (du kan erstatte dette med en åpen kilde-modell hvis du ønsker)
  • FastAPI: For å lage en enkel API for å interagere med vår agent

La oss starte med å oppsette vår miljø:


<p># Opprett en ny virtuell miljø
python -m venv rag_agent_env
source rag_agent_env/bin/activate # På Windows, bruk `rag_agent_env\Scripts\activate`</p>

<p># Installer nødvendige pakker
pip install langchain chromadb openai fastapi uvicorn

Na kan vi opprette en ny Python-fil kalt rag_agent.py og importere de nødvendige bibliotekene:


<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># Sett din OpenAI-API-nøkkel
os.environ[&quot;OPENAI_API_KEY&quot;] = &quot;din-api-nøkkel-her&quot;</p>

Bygging av et enkelt RAG-system

Na som vi har oppsatt vår miljø, la oss bygge et enkelt RAG-system. Vi vil starte med å opprette en kunnskapsbase fra en samling dokumenter, og deretter bruke denne til å svare på spørsmål.

Trinn 1: Forbered dokumentene

Først må vi laste og forberede våre dokumenter. For dette eksemplet, la oss anta at vi har en tekstfil kalt knowledge_base.txt med noen informasjon om AI og maskinlæring.


<p># Last dokumentet
loader = TextLoader(&quot;knowledge_base.txt&quot;)
documents = loader.load()</p>

<p># Del dokumentene inn i blokker
text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=0)
texts = text_splitter.split_documents(documents)</p>

<p># Opprett embeddings
embeddings = OpenAIEmbeddings()</p>

<p># Opprett en vektorlagring
vectorstore = Chroma.from_documents(texts, embeddings)</p>

Trinn 2: Opprett en henting-basert QA-kjede

Na som vi har vår vektorlagring, kan vi opprette en henting-basert QA-kjede:


<p># Opprett en henting-basert QA-kjede
qa = RetrievalQA.from_chain_type(llm=OpenAI(), chain_type=&quot;stuff&quot;, retriever=vectorstore.as_retriever())</p>

Trinn 3: Spør systemet

Vi kan nå spørre vår RAG-system:


<p>spørsmål = &quot;Hva er de viktigste anvendelsene av maskinlæring?&quot;
resultat = qa.run(spørsmål)
print(resultat)

Trinn 4: Opprett en LLM-agent

Mens vårt enkle RAG-system er nyttig, er det ganske begrenset. La oss forbedre det ved å opprette en LLM-agent som kan utføre mer komplekse oppgaver og resonere om informasjonen den henter.

En LLM-agent er et AI-system som kan bruke verktøy og ta beslutninger om hvilke handlinger den skal utføre. Vi vil opprette en agent som ikke bare kan svare på spørsmål, men også utføre nett-søk og grunnleggende beregninger.

Først la oss definere noen verktøy for vår agent:


<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># Definer en regneark-verktøy
class CalculatorTool(BaseTool):
navn = &quot;Regneark&quot;
beskrivelse = &quot;Nyttig for når du må svare på spørsmål om matematikk&quot;</p>

<p>def _run(self, spørsmål: str)
try:
return str(eval(spørsmål))
except:
return &quot;Jeg kunne ikke beregne det. Vennligst sikre at din input er en gyldig matematisk uttrykk.&quot;</p>

<p># Opprett verktøy-eksempler
søk = DuckDuckGoSearchRun()
regneark = CalculatorTool()</p>

<p># Definer verktøyene
verktøy = [Tool(navn=&quot;Søk&quot;, func=søk.run, beskrivelse=&quot;Nyttig for når du må svare på spørsmål om nåværende hendelser&quot;),
Tool(navn=&quot;RAG-QA&quot;, func=qa.run, beskrivelse=&quot;Nyttig for når du må svare på spørsmål om AI og maskinlæring&quot;),
Tool(navn=&quot;Regneark&quot;, func=regneark._run, beskrivelse=&quot;Nyttig for når du må utføre matematiske beregninger&quot;)
]</p>

<p># Initialiser agenten
agent = initialize_agent(verktøy, OpenAI(temperature=0), agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, verbose=True
)</p>

Na har vi en agent som kan bruke vårt RAG-system, utføre nett-søk og utføre beregninger. La oss teste den:


<p>resultat = agent.run(&quot;Hva er forskjellen på overvåket og uovervåket læring? Og hva er 15% av 80?&quot;)
print(resultat)</p>

Denne agenten demonstrerer en viktig fordel med LLM-agenter: de kan kombinere flere verktøy og resonnerings-trinn for å svare på komplekse spørsmål.

Forbedring av agenten med avanserte RAG-teknikker

Mens vårt nåværende RAG-system fungerer bra, er det flere avanserte tekniker vi kan bruke til å forbedre dens ytelse:

a) Semantisk søk med Dense Passage Retrieval (DPR)

I stedet for å bruke enkle embedding-basert søkning, kan vi implementere DPR for mer nøyaktig semantisk søk:


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

<p>spørsmål_encoder = DPRQuestionEncoder.from_pretrained(&quot;facebook/dpr-question_encoder-single-nq-base&quot;)
kontekst_encoder = DPRContextEncoder.from_pretrained(&quot;facebook/dpr-ctx_encoder-single-nq-base&quot;)</p>

<p># Funksjon for å kode passasjer
def kode_passasjer(passasjer):
return kontekst_encoder(passasjer, max_length=512, return_tensors=&quot;pt&quot;).pooler_output</p>

<p># Funksjon for å kode spørsmål
def kode_spørsmål(spørsmål):
return spørsmål_encoder(spørsmål, max_length=512, return_tensors=&quot;pt&quot;).pooler_output</p>

b) Spørsmål-utvidelse

Vi kan bruke spørsmål-utvidelse til å forbedre søkningsytelsen:


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

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

<p>def utvide_spørsmål(spørsmål):
input_tekst = f&quot;utvide spørsmål: {spørsmål}&quot;
input_ids = tokenizer.encode(input_tekst, return_tensors=&quot;pt&quot;)
outputs = modell.generate(input_ids, max_length=50, num_return_sequences=3)
utvidede_spørsmål = [tokenizer.decode(output, skip_special_tokens=True) for output in outputs]
return utvidede_spørsmål</p>

c) Iterativ forfining

Vi kan implementere en iterativ forfiningsprosess hvor agenten kan stille følgespørsmål for å klargjøre eller utvide på sitt opprinnelige søk:


<p>def iterativ_søkning(innledende_spørsmål, maks_iterasjoner=3):
spørsmål = innledende_spørsmål
for _ in range(maks_iterasjoner):
resultat = qa.run(spørsmål)
klargjøring = agent.run(f&quot;Basert på dette resultatet: &#039;{resultat}&#039;, hva følgespørsmål bør jeg stille for å få mer spesifikk informasjon?&quot;)
if klargjøring.lower().strip() == &quot;none&quot;:
break
spørsmål = klargjøring
return resultat</p>

# Bruk denne i din agent-prosess

Implementering av et multi-agent-system

For å håndtere mer komplekse oppgaver, kan vi implementere et multi-agent-system hvor ulike agenter spesialiserer seg i ulike områder. Her er et enkelt eksempel:


<p>class SpesialistAgent:
def __init__(self, navn, verktøy):
self.navn = navn
self.agent = initialize_agent(verktøy, OpenAI(temperature=0), agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, verbose=True)</p>

<p>def run(self, spørsmål):
return self.agent.run(spørsmål)</p>

<p># Opprett spesialist-agenter
forsknings_agent = SpesialistAgent(&quot;Forskning&quot;, [Tool(navn=&quot;RAG-QA&quot;, func=qa.run, beskrivelse=&quot;For AI- og ML-spørsmål&quot;)])
matematikk_agent = SpesialistAgent(&quot;Matematikk&quot;, [Tool(navn=&quot;Regneark&quot;, func=regneark._run, beskrivelse=&quot;For beregninger&quot;)])
generell_agent = SpesialistAgent(&quot;Generell&quot;, [Tool(navn=&quot;Søk&quot;, func=søk.run, beskrivelse=&quot;For generelle spørsmål&quot;)])</p>

<p>class Koordinator:
def __init__(self, agenter):
self.agenter = agenter</p>

<p>def run(self, spørsmål):
# Bestemm hvilken agent som skal brukes
if &quot;beregne&quot; in spørsmål.lower() or any(op in spørsmål for op in [&#039;+&#039;, &#039;-&#039;, &#039;*&#039;, &#039;/&#039;]):
return self.agenter[&#039;Matematikk&#039;].run(spørsmål)
elif any(termer in spørsmål.lower() for termer in [&#039;ai&#039;, &#039;maskinlæring&#039;, &#039;dyplæring&#039;]):
return self.agenter[&#039;Forskning&#039;].run(spørsmål)
else:
return self.agenter[&#039;Generell&#039;].run(spørsmål)</p>

<p>koordinator = Koordinator({&#039;Forskning&#039;: forskins_agent, &#039;Matematikk&#039;: matematikk_agent, &#039;Generell&#039;: generell_agent})</p>

<p># Test multi-agent-systemet
resultat = koordinator.run(&quot;Hva er forskjellen på CNN og RNN? Og beregn 25% av 120.&quot;)
print(resultat)</p>

Dette multi-agent-systemet lar oss spesialisere og håndtere en bredere rekke av spørsmål mer effektivt.

Evaluering og optimalisering av RAG-agenter

For å sikre at vår RAG-agent fungerer bra, må vi implementere evaluering-metrikker og optimaliseringsteknikker:

a) Relevans-evaluering

Vi kan bruke metrikker som BLEU, ROUGE eller BERTScore til å evaluere relevansen av hentede dokumenter:


<p>from bert_score import score</p>

<p>def evaluere_relevans(spørsmål, hentet_dokument, generert_svar):
P, R, F1 = score([generert_svar], [hentet_dokument], lang=&quot;en&quot;)
return F1.mean().item()</p>

b) Svar-kvalitets-evaluering

Vi kan bruke menneskelig evaluering eller automatiske metrikker til å vurdere svar-kvaliteten:


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

<p>def evaluere_svar_kvalitet(referanse_svar, generert_svar):
return sentence_bleu([referanse_svar.split()], generert_svar.split())</p>

<p># Bruk denne til å evaluere din agent-svar

Fremtidige retninger og utfordringer

Mens vi ser fremover mot fremtiden for RAG-agenter, finnes det flere spennende retninger og utfordringer:

a) Multi-modal RAG: Utvide RAG til å inkludere bilde-, lyd- og video-data.

b) Federeret RAG: Implementere RAG på tvers av distribuerte, privat-preserverende kunnskapsbaserte systemer.

c) Kontinuerlig læring: Utvikle metoder for RAG-agenter til å oppdatere sine kunnskapsbaserte systemer og modeller over tid.

d) Etiske overveielser: Behandle bias, rettferdighet og gjennomsiktighet i RAG-systemer.

e) Skalbarhet: Optimalisere RAG for store, sanntids-applikasjoner.

Konklusjon

Bygging av LLM-agenter for RAG fra scratch er en kompleks, men belønning prosess. Vi har dekket grunnleggende RAG, implementert et enkelt system, opprettet en LLM-agent, forbedret den med avanserte tekniker, utforsket multi-agent-systemer og diskutert evaluering og optimaliseringsteknikker.

Jeg har brukt de siste fem årene på å dykke ned i den fasiniserende verden av Maskinlæring og Dypt Læring. Min lidenskap og ekspertise har ledet meg til å bidra til over 50 ulike programvareprosjekter, med særlig fokus på AI/ML. Min pågående nysgjørhet har også trukket meg mot Naturlig Språkbehandling, et felt jeg er ivrig etter å utforske videre.