В этом руководстве мы покажем вам, как создать продвинутого агента искусственного интеллекта, который не только общается, но и запоминает. Мы начнём с нуля и продемонстрируем, как объединить легковесную 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. Какие методы используются для адаптации ответов агента к стилю пользователя?
Для адаптации ответов к стилю пользователя агент использует прошлые предпочтения и адаптирует учебные рекомендации в настоящем. Это делает взаимодействия контекстуальными и развивающимися, делая агента более личным и интеллектуальным с каждым обменом.