В этом руководстве мы покажем вам, как создать продвинутого агента искусственного интеллекта, который не только общается, но и запоминает. Мы начнём с нуля и продемонстрируем, как объединить легковесную LLM, векторный поиск FAISS и механизм суммирования для создания как краткосрочной, так и долгосрочной памяти.
Установка необходимых библиотек
Мы начнём с установки основных библиотек и импорта всех необходимых модулей для нашего агента. Мы настроим среду, чтобы определить, используем ли мы GPU или CPU, что позволит нам эффективно запускать модель.
«`python
!pip -q install transformers accelerate bitsandbytes sentence-transformers faiss-cpu
import os, json, time, uuid, math, re
from datetime import datetime
import torch, faiss
from transformers import AutoModelForCausalLM, AutoTokenizer, pipeline, BitsAndBytesConfig
from sentence_transformers import SentenceTransformer
DEVICE = «cuda» if torch.cuda.is_available() else «cpu»
«`
Загрузка языковой модели
Мы определяем функцию для загрузки нашей языковой модели. Мы настраиваем её так, чтобы при наличии GPU использовать 4-битную квантизацию для повышения эффективности; в противном случае мы переходим на CPU с оптимизированными настройками. Это гарантирует, что мы сможем плавно генерировать текст независимо от оборудования, на котором мы работаем.
«`python
def loadllm(modelname=»TinyLlama/TinyLlama-1.1B-Chat-v1.0″):
try:
if DEVICE==»cuda»:
bnb=BitsAndBytesConfig(loadin4bit=True,bnb4bitcomputedtype=torch.bfloat16,bnb4bitquanttype=»nf4″)
tok=AutoTokenizer.frompretrained(modelname, use_fast=True)
mdl=AutoModelForCausalLM.frompretrained(modelname, quantizationconfig=bnb, devicemap=»auto»)
else:
tok=AutoTokenizer.frompretrained(modelname, use_fast=True)
mdl=AutoModelForCausalLM.frompretrained(modelname, torchdtype=torch.float16 if torch.cuda.isavailable() else torch.float32, lowcpumem_usage=True)
return pipeline(«text-generation», model=mdl, tokenizer=tok, device=0 if DEVICE==»cuda» else -1, do_sample=True)
except Exception as e:
raise RuntimeError(f»Failed to load LLM: {e}»)
«`
Класс VectorMemory
Мы создаём класс VectorMemory, который даёт нашему агенту долгосрочную память. Мы храним прошлые взаимодействия в виде вложений с помощью MiniLM и индексируем их с помощью FAISS, что позволяет нам искать и вспоминать соответствующую информацию позже. Каждая память сохраняется на диске, что позволяет агенту сохранять свою память между сеансами.
«`python
class VectorMemory:
def init(self, path=»/content/agent_memory.json», dim=384):
self.path=path; self.dim=dim; self.items=[]
self.embedder=SentenceTransformer(«sentence-transformers/all-MiniLM-L6-v2», device=DEVICE)
self.index=faiss.IndexFlatIP(dim)
if os.path.exists(path):
data=json.load(open(path))
self.items=data.get(«items»,[])
if self.items:
X=torch.tensor([x[«emb»] for x in self.items], dtype=torch.float32).numpy()
self.index.add(X)
def _emb(self, text):
v=self.embedder.encode([text], normalize_embeddings=True)[0]
return v.tolist()
def add(self, text, meta=None):
e=self._emb(text); self.index.add(torch.tensor([e]).numpy())
rec={«id»:str(uuid.uuid4()),»text»:text,»meta»:meta or {}, «emb»:e}
self.items.append(rec); self._save(); return rec[«id»]
def search(self, query, k=5, thresh=0.25):
if len(self.items)==0: return []
q=self.embedder.encode([query], normalize_embeddings=True)
D,I=self.index.search(q, min(k, len(self.items)))
out=[]
for d,i in zip(D[0],I[0]):
if i==-1: continue
if d>=thresh: out.append((d,self.items[i]))
return out
def _save(self):
slim=[{k:v for k,v in it.items()} for it in self.items]
json.dump({«items»:slim}, open(self.path,»w»), indent=2)
«`
Класс MemoryAgent
Мы объединяем всё в класс MemoryAgent. Мы проектируем агента для генерации ответов с учётом контекста, дистилляции важных фактов в долгосрочную память и периодического суммирования разговоров для управления краткосрочным контекстом. С такой настройкой мы создаём помощника, который запоминает, вспоминает и адаптируется к нашему взаимодействию с ним.
«`python
class MemoryAgent:
def init(self):
self.llm=load_llm()
self.mem=VectorMemory()
self.turns=[]
self.summary=»»
self.max_turns=10
def gen(self, prompt, maxnew_tokens=256, temp=0.7):
out=self.llm(prompt, maxnewtokens=maxnewtokens, temperature=temp, topp=0.95, numreturnsequences=1, padtokenid=self.llm.tokenizer.eostokenid)[0][«generatedtext»]
return out[len(prompt):].strip() if out.startswith(prompt) else out.strip()
def chatprompt(self, user, memory_context):
convo=»\n».join([f»{r.upper()}: {t}» for r,t in self.turns[-8:]])
sys=f»System: {SYSGUIDE}\nTime: {nowiso()}\n\n»
mem = f»MEMORY (relevant excerpts):\n{memorycontext}\n\n» if memorycontext else «»
summ=f»CONTEXT SUMMARY:\n{self.summary}\n\n» if self.summary else «»
return sys+mem+summ+convo+f»\nUSER: {user}\nASSISTANT:»
def distilland_store(self, user):
try:
raw=self.gen(DISTILLPROMPT(user), maxnewtokens=120, temp=0.1)
js=strip_json(raw)
if js:
obj=json.loads(js)
if obj.get(«save») and obj.get(«memory»):
self.mem.add(obj[«memory»], {«ts»:now_iso(),»source»:»distilled»})
return True, obj[«memory»]
except Exception: pass
if re.search(r»\b(my name is|call me|I like|deadline|due|email|phone|working on|prefer|timezone|birthday|goal|exam)\b», user, flags=re.I):
m=f»User said: {clamp(user,120)}»
self.mem.add(m, {«ts»:now_iso(),»source»:»heuristic»})
return True, m
return False, «»
def maybesummarize(self):
if len(self.turns)>self.max_turns:
convo=»\n».join([f»{r}: {t}» for r,t in self.turns])
s=self.gen(SUMMARIZEPROMPT(clamp(convo, 3500)), maxnewtokens=180, temp=0.2)
self.summary=s; self.turns=self.turns[-4:]
def recall(self, query, k=5):
hits=self.mem.search(query, k=k)
return «\n».join([f»- ({d:.2f}) {h[‘text’]} [meta={h[‘meta’]}]» for d,h in hits])
def ask(self, user):
self.turns.append((«user», user))
saved, memline = self.distilland_store(user)
mem_ctx=self.recall(user, k=6)
prompt=self.chatprompt(user, mem_ctx)
reply=self._gen(prompt)
self.turns.append((«assistant», reply))
self.maybesummarize()
status=f» memory_saved: {saved}; » + (f»note: {memline}» if saved else «note: -«)
print(f»\nUSER: {user}\nASSISTANT: {reply}\n{status}»)
return reply
«`
Мы создаём нашего MemoryAgent и сразу же проверяем его с помощью нескольких сообщений, чтобы заполнить долговременную память и проверить возможность вызова. Мы подтверждаем, что он запоминает наше предпочтительное имя и год экзамена, адаптирует ответы к нашему лаконичному стилю и использует прошлые предпочтения (агентские RAG, однофайловые Colab) для адаптации учебных рекомендаций в настоящем.
В заключение мы видим, как это мощно, когда мы наделяем нашего ИИ-агента способностью запоминать. Теперь у нас есть агент, который хранит ключевые детали, вспоминает их, когда это необходимо, и суммирует разговоры, чтобы оставаться эффективным. Этот подход делает наши взаимодействия контекстуальными и развивающимися, делая агента более личным и интеллектуальным с каждым обменом.
1. Какие основные компоненты используются для создания продвинутого агента искусственного интеллекта с памятью?
В статье описывается создание продвинутого агента ИИ с использованием легковесной языковой модели (LLM), векторного поиска FAISS и механизма суммирования. Эти компоненты позволяют агенту не только общаться, но и запоминать информацию.
2. Какие преимущества даёт использование 4-битной квантизации при загрузке языковой модели?
При наличии GPU используется 4-битная квантизация для повышения эффективности работы модели. Это позволяет плавно генерировать текст независимо от оборудования, на котором работает модель. Такой подход оптимизирует использование ресурсов и улучшает производительность.
3. Как класс VectorMemory обеспечивает долгосрочную память агенту?
Класс VectorMemory хранит прошлые взаимодействия в виде вложений с помощью MiniLM и индексирует их с помощью FAISS. Это позволяет агенту искать и вспоминать соответствующую информацию позже. Каждая память сохраняется на диске, что позволяет агенту сохранять свою память между сеансами.
4. Какие функции выполняет класс MemoryAgent?
Класс MemoryAgent объединяет все компоненты в единую систему. Он генерирует ответы с учётом контекста, дистиллирует важные факты в долгосрочную память и периодически суммирует разговоры для управления краткосрочным контекстом. С такой настройкой создаётся помощник, который запоминает, вспоминает и адаптируется к взаимодействию с пользователем.
5. Какие методы используются для адаптации ответов агента к стилю пользователя?
Для адаптации ответов к стилю пользователя агент использует прошлые предпочтения и адаптирует учебные рекомендации в настоящем. Это делает взаимодействия контекстуальными и развивающимися, делая агента более личным и интеллектуальным с каждым обменом.