Галоўная / Артыкулы

Лакальны AI-агент: мадэлі, памяць, сховішча і інтэрфейс

Пяць узроўняў стэка лакальнага AI-агента з параўнаннем Ollama, OpenClaw, Mem0 і Qdrant ці Chroma, а таксама выпраўленні для JSON у think-рэжыме і ціхіх неадпаведнасцей памернасці.

Выдавец: REACTAPP.TOP10 хв чытання2248 слоў

Крыніцы: Building Local AI Agents: A Practical Guide to Models, Memory, and Orchestration

Местны ўраджэнны агент AI захоўвае модэль на вашай сабе апаратыразыёвай базе, дзеяе за вас і перадае кантэкст з адной сесіі ў іншую, не выканаючы перадачу дадзэнняў да зовнішніх API. Базавы чатбот адпавядае і забывае. Агент можа выконваць калькуляціі па кількох кроках, выкарыстоўваць інструменты і накапліваць знанні з часам. Работа ў локальным рэжыме дае вам асістэнта без компромісаў у паводзе з прыватнасцю чы ўзнаковых платаў за кожны вызов, якія ёсць у хоставаных службах.

Для стварэння аднаго такога рашэння павінны разам працаваць пяць слоёў: слой LLM, які выканае інферэнс на вашай машыне, фрэймворк агента, які керуе дзеяннямі, слой памяці, які паўрабляе агента з часам, слой зберагчыка, які захоўвае зібраны контэнт, і слой інтэрфейсу, які падходзіць вашаму спосабу работы. Ніжэй для кожнага слою паказаны ўзнаковыя моменты, можлівыя компромісы і рэкамендацыі, ўсё гэта дапамагае скласці комплект, які падходзіць вашай сітуацыі.

Слоёў 1: модэль

Гэта ядро. Мадэль выклікае намерэння, генеруе код і выдзяляе структураваныя даны, ад калі якіх паводлі працюе рэштка сістэмы, а ўсё іншэ — цэлая сістэма, побудаваная на тым, што ядро можа робіць надзеяйна. Тры інструмента домінуюць у локальных вычысленнях.

Ollama — гэта простэйшы спосаб развязкі. Адной командай яго встановляюць, адной — завантажаюць мадэль, і васямкнуто ўтвараецца API, сумесны з OpenAI, на локальнай машыне. Ён караце модэлі, выбірае спосаб квантавання і настаўляе параметры кантэкстнага вікна без дадатковай настройкі. Ён не створаны для велікага трафіку і больш падходзіць як інструмент для персональнага асістэнта чым для распрацоўшчыка.

ollama pull qwen3:8b
ollama pull nomic-embed-text

llama.cpp знаходзіцца на аднам рэвэне ніжэй. Гэта двайчы-плюс-двойковы моцар, які безпасебна запускае квантаваныя мадэлі GGUF, без дэмона і без слоя HTTP. Яго мінімальны расход памяці робіць яго падходжым для перыферыйных прыстроў, такіх як Raspberry Pi чы сістэмы на базе Linux, дзе Ollama бы зайняў занадта многа памяці. Недзею ў яго ёсць відсутная вбудованая адзначка модэляў і неабходнасць ручнага налажвання.

vLLM — гэта варыянт для практычнага выкарыстоўвання. Ён выкорыстоўвае тэхнікі PagedAttention і непаўзлівага батчавання, якія вікорыстоўваюцца для адпаведнага працэсування дадзеных у хмарах. Калі вы обслужваеце многа корыстувачаў чы маеце вялікія патрэбныя прыемнікі, гэты варыянт будзе падходжым, хоць ён выкарыстоўвае адпаведную інфраструктуру GPU і мае лепшую здатнасць доўжэй працаваць, чым першыя два варыянты.

Для локальнага асістэнта адзінаго распрацоўшчыка Ollama ёсць розумным стандартам, тым болей што простасць важнейшая за працэздатнасць. Мадэль qwen3:8b заслуговае на увагу: яна дае надзеяны JSON для выканаўвання задумоў, пішчыць код чыста і помешчаецца ў 8 ГБ VRAM. Аднак трэба знаць адну особлівасць — яна загортае свой адказ у блакі <think>…</think> прычымо да справжніх даных, што паслабляе будзь-які JSON-парсер, які працуе з неапранутым адказам. Невялікі кэш, які у всіх месцах задае think: False, вырашае гэту проблему:

_orig_ollama_chat = ollama.chat
def _no_think_chat(*args, **kwargs):
    opts = kwargs.get("options") or {}
    if isinstance(opts, dict):
        opts.setdefault("think", False)
        kwargs["options"] = opts
    return _orig_ollama_chat(*args, **kwargs)
ollama.chat = _no_think_chat

Паколькі ў яго вікорыстоўваецца setdefault, аддзельныя корыстувачы все ж можаць знова увімкнуць рэжым “thinking”, калі гэта для іх неабходна. Для выкарыстоўвання JSON і генеравання коду ў паўтараючыхся працэсах інструменту, рэжым “thinking” прыносіць затрымкі без падышча ў якасці.

Слой 2: фрэймворк агента

Мадэль генеруе тэкст. Фрэймворк вяршыць прыняцтва рашэнняя пра тое, што робіць з гэтым тэкстам і што робіць далей, включаючы класыфікацыю намеру, маршрутызацыю і выкананне.

OpenClaw спачатку ўважаецца інструментам і працюе на рэвэрсіі файлавой сістэмы. Кожная дзеянне ўособліваеся камандай, якая надсылаецца да адпаведнай навыку, такой як стварэнне файла, запіс коду, ачынэнне папкі або запуск каманды шэлу. Вы пішаце SKILL.md, у яком указваеце назву навыку і спосаб яго адправкі, а фрэймворк займаецца маршрутызацыяй:

- -
name: local-ai-assistant
description: Local AI coding assistant with persistent memory
command-dispatch: tool
command-tool: exec
command-arg-mode: raw
-

Калі большая частка операцыяў — гэта праца з файламі (I/O), як у дапаможніку для програмавання, такая мадэль падходзіць ідэальна. Лініі command-dispatch: tool і command-tool: exec паведамляюць OpenClaw выканаць Python-скрыпты, калі запускаецца адпаведная спэцыяльнасць, тады праца з файламі праходзіць праз гэтую праметку. Яе меры — гэта тое, што яна не прызначана для дугіх ланцоў багатоэтапнага разумавання чы для коордынаціі калькольных агентаў.

LangGraph выкорыстоўвае працоўны падход. Вы задаёце явны граф станоў, у яком вузламі ёсць вызовы мадэляў чы дзеяння, а рэшткамі — пераходы, і праметка перадае стан между этапамі. Цена гэтага падходу — павышаная прадзеяльнасьць пад час праектавання: трэба з’ясаваць схему станоў і форму графа раней, чым працаваць з логікай бізнесу. Для простага выкарыстоўвання інструментаў гэта зайвая складнасьц, але для сложных багатоэтапных працэсаў гэта дазволяе маты запіс пра тое, што адбывалася на кожным этапе.

CrewAI знаходзіцца ў яшчэ вышэйшым рангу. Вы опісваеце агентаў з ўпадзімамі і задачамі, а таксама з апісаннямі, і гэтая платформа выклікае парадак адкрыцьця задач і взаімную связь межа агентамі. Гэта найшырэйшы шлях да рабочага пратотыпу з калькольніка агентаў, хоча абстракцыя ускладнюе дыягнастыку нештачакоў.

Як бы вы не выбралі, класыфікацыя намеру адбываецца першай для кожнага прыйнятага паведамлення. Спалучэнне класыфікаціі на адной з модэляў з альтэрнатываю на аснове рэгулярных выразаў дапамагае лепшая справляцца з нештачакамі, чым кожны з методаў околасці.

def detect_intent(message: str) -> dict:
    try:
        resp = ollama.chat(
            model=OLLAMA_CHAT_MODEL,
            messages=[{"role": "user", "content": INTENT_PROMPT.format(message=message)}],
            options={"temperature": 0, "num_predict": 1024},
        )
        return extract_json(resp["message"]["content"])
    except Exception:
        return keyword_intent_fallback(message)

Функцыя адказу пры некальканоснасці перадае тыповыя сцэны, калі мадэль вяртае некарэктны выхад. Калі функцыя размышлення выключана, а параметр тэпературы стоіць 0, большасць запыткаў обрабоўваецца па шляху модэлі, але самэўжо адказ пры некальканоснасці дапамагае агенту працаваць.

Слой 3: памяць

Памяць разлічвае агента, які прыстосоўваецца да вас, ад таго, які спрыятае кожнай размове як да першай. Агент выучае вашы прыемы, пярасклоненні і кантэкст праекта, і прыменяе іх без дадатковых паведамленняў.

Звычныя спосабы рашэння проблем знаходзяцца ў самай вікну кантэкста: PREFERENCES.md, які чытаецца пад час запуску, довга сістэмная просьба або файл CONTEXT.md. Усе яны маюць аднаковую слабасць — у вікну ўсе яны стыскаюцца пад дэйствам компактавання, обмежэнням колькасці токеноў і перзапускам сесіі. Аднае, чаго на самай працэ патрэбна агенту, — гэта памяць за межамі вікна, якая зберагаецца на довгачас, выкарыстоўваецца тады, калі гэта неабходна, і апдэйтаваецца праз змены фактов. Існуе тры распашчытыя падходы, якія задовольняюць разныя потрэбы.

Базаваны RAG — гэта найпашчырэйшы і найяксьпрыятнейшы варыянт для пачатківаўцаў. Дакументы або історыю размовы дзельнуюць на часткі, гэтыя часткі вбудовуюцца, а калі прыходзіць запіт, выкарыстоўваюцца найболей схожыя з ім варыянты. Для ўстановкі трэба мінімум зусіль. Яго слабасць заключаецца у тым, што памяць ператвараецца на купу дакументаў, без разліку на тое, якія з іх варта зберагчы на довгачас, а якія — толькі для тымчасовага выкарыстоўвання.

Памяць, прызначаная для пэўнай сесіі, напрыклад ConversationBufferMemory і ConversationSummaryMemory з LangChain, спакойвае ход дыялогу ў межах адной сесіі. Агент не забудзе тое, што вы сказалі пяць прыемоў назад, а статыстыкі запобегаюць перапоўненню спамяральнага окна. Аднак такая памяць не застаецца пасля перзапуску, і гэта ёсць основныя недагодзі для кансультанта-програміста.

Структураваная стойкая памэць, як у Mem0, спрыяе тлумачэнню памяці як дадзення першага класу, а не як сырога тэксту. У зьмену на слова-в слова, мадэль выдэляе окрэмыя факты, якія зберагаюцца ў базе дадзеных у вектарнай форме. Пры запытанні факты, якія маюць сэмантычнае супадзенне, вяртаюцца, нават калі новыя сообшчэння не вжываюць первісных выразоў. Збераганыя факты застаюцца актуальнымі между сэсіямі, можаць быць з’едыненыя, калі ўтвараюцца дуплікаты, і перапісваюцца, калі змянюецца рэальнасць. Mem0 падтрымляе локальныя мадэлі, таму лёгка ўз’язначыць яго з стаком, базаваным на Ollama.

Вядзімо развіццелю, які згадвае, што ўпадабляе ся да pytest. Звычная сістэма RAG зберагае сам сырой абзац. Структураваная сістэма выдэляе і зберагае саму прыязнь. Калі вы праз тыя ж часы запытаецеся пра функцыю з тэстамі, памяць вярнеў «пользоватэль прывяжаны да pytest», нават калі у сообшчэнні ніколі не было назвы фрэймворка для тэставання.

Ўстановка Mem0 у местной сэтапаванні Ollama выклікае кароткую настройку, якая наводзіць на вашу местную мадэль, местную мадэль упаковкі даных і хранальнік вектараў:

from mem0 import Memory
config = {
    "llm": {
        "provider": "ollama",
        "config": {"model": "qwen3:8b", "ollama_base_url": "http://localhost:11434"},
    },
    "embedder": {
        "provider": "ollama",
        "config": {"model": "nomic-embed-text", "ollama_base_url": "http://localhost:11434"},
    },
    "vector_store": {
        "provider": "qdrant",
        "config": {"host": "localhost", "port": 6333, "embedding_model_dims": 768},
    },
}
memory = Memory.from_config(config)
memory.add("I always use type hints and pytest", user_id="dev")
results = memory.search("write a utility function", user_id="dev")

llm блакет направляе Mem0 да qwen3:8b для выкарыстоўвання фактов, ператвараючы неапранутаяе паведамленне на аддзельныя зберажаныя прывычкі заместо слова ў слова. embedder блакет выкарыстоўвае nomic-embed-text для вектарызаціі гэтых фактов пад час запісу і для уключэння запытаў пад час выкарыстоўвання, а memory.search() пасля таго выкарыстоўвае значэння для пошуку, а не ключавыя словы.

Недаастаткова ацэнаваная паліптатацыя для будзь-якага падходу да памяці — гэта фільтрацыя таго, што ідзе у зберажанне, прытым як толькі ўжо пачынаецца запіс. Лёгкі класыфікатор, які працуе перад кожным запісам, дапамагае падтрымаць чыстасцю памяці і высокую якосць выкарыстоўвання інфармацыі:

def _is_worth_storing(self, user_message: str) -> bool:
    response = ollama.chat(
        model=OLLAMA_CHAT_MODEL,
        messages=[{"role": "user", "content": SMART_MEMORY_PROMPT.format(
            user_message=user_message
        )}],
        options={"temperature": 0, "num_predict": 512},
    )
    data = self._extract_json_robust(response["message"]["content"])
    return bool(data.get("worth_storing", False))

Якісны прыклады розблакоўваюць мадэль:

HIGH-VALUE (worth storing):
- "I prefer TypeScript over JavaScript"
- "I use pytest, never unittest"
- "Always use Google-style docstrings"

LOW-VALUE (discard):
- "What does enumerate() do?"
- "Write a retry decorator"
- "Thanks"

Калі не выкасціваць фільтр, база вектарных дадзеных паступова заполняецца запытамі, які вікорыстоўваюцца толькі адной раз, што пагоршвае якасць пошуку.

Слой 4: зберагчык

Слой памяці вяршыць, што трэба запам’ятаваць, а зберагчык — гэта месца, дзе гэтыя даныя зберагаюцца на дыску.

FAISS — гэта бібліятэка, якая працуе ў межах працэса: быстрая, добра працаваная і не выкарыстоўвае спецыяльных інфраструктурных рэшэнняў. Яе можна адключыць да вашага працэса на Python і запускаць у памяці, або ж серыялізаваць на дыск. Яе абмежэння стосуюцца функцыянальнасці: для зберагчыка неабходны явныя вызовы функцый серыялізацыі, а таксама няма HTTP API чы ўбудованага механізму рэплікацыі. Гэта падходзяжае для науковых працэсаў і пакетных завадзяў, але не падходзіць для довгачасовага асістэнта, які часта перзапускаецца.

Chroma — гэта працявае як найпростэйшая база даных для векторыв, яку можа обраты розробнік. Яна почынаецца як локальній працэс Python або працюе вбудовано у ваш власній код, автоматычно зберываючы даныя у локальну дырэкторыю.

pip install chromadb

Тыясячы фактов, якія зберагаюцца ў персональнам асістэнце, цалкам падпадаюць пад можлівасці Chroma. Ён абсалютна пазбавляе апатрэбы інфраструктуры, але фільтрацыя ў яго ёсць болей обмежанай, чым у Qdrant.

Qdrant працуе як справжняя служба з полнымі API REST і gRPC, фільтрацыёю пакетаў дадзеных і вектарамі з іменамі. Ён прызначаны для выкарыстоўвання ў сістэмах з мільйонамі вектараў і адночаснымі запытамі. Дадзеныя атрымуюцца на дыск натычна, і ён перазлучаецца пасля перзапуску Docker без спецыяльных заходаў:

# Qdrant via Docker
docker run -d - name qdrant-local -p 6333:6333 \
-v $(pwd)/qdrant_storage:/qdrant/storage qdrant/qdrant

Адзін элемент настройкі прычынюе проблемы без явных сігналаў: размер пазначэння ў настройках хранілішча вектароў павінен абоўсюды падходзіць да размеру выхідных даных вашага модэлю пазначэння. Напрыклад, модэль nomic-embed-text стварае вектары размерам 768. Калі змяніце модэль пазначэння, не адкорэктаваўшы гэты параметр, вставкі не будуць выкананы без явных памылак.

"vector_store": {
    "provider": "qdrant",
    "config": {
        "collection_name": "coding_assistant",
        "host": "localhost",
        "port": 6333,
        "embedding_model_dims": 768,  # must match your embedding model exactly
    },
}

Калі вы хочаце заменіць Docker, Chroma ўсё тое ж сама аплявацыя: проста зменіце прадастальніка vector_store у настройкach, а рэшта стака застанецца такім жа.

Слой 5: інтэрфейс

Найзовнішы слой вялічынае спосаб, якім вы вясьледзіце з агентам, і правы выбор залежыць ад таго, дзе ён знаходзіцца у вашай рабочай практыцы.

  • Веб-Інтэрфейс. Найбольш гнучкі варыянт. Ён працуе ў браузеры, адрасавае маркдаун, выдэляе код і секцыі, якія можна складзіць, і працуе на будзь-якай операцыйной сістэме без неабыходнасці інсталявання. Памагчык для програмавання можа паказаць тэкушчы файл, створэны код і стан памяці агента на аднай экране.
  • CLI. Тэрмінальны асістэнт вбудовуўся ў робочы працэс шэлу, перадае выхідны даныя іншым інструментам і не стварае додатковага візуальнага навантажэння. Для швыраго пошуку, операцый з файламі і автоматызаваных задач гэта найкрашчы варыянт.
  • Плагін IDE. Асістэнт у VS Code або JetBrains працюе разам з файлам, які вы рэдагуўаеце, ведае, які файл ачынены, і пропонуе змяны безпосерэдна ў файле. Патрэбна падтрымка API расшырэнняў і назіранне за апдэйтамі IDE, што ёсць корыстным для ўседзёнага інструменту команды.
  • Програмы для чату, такія як Slack, Discord або Telegram. Яны падходзяць для спілкування, калі асістэнт трэба доступны з розных прыстроў у командзе. Іх не можна вікорыстаць для перагляду коду чы рэдагавання файлаў, але яны паслягаюць для запытанняў, перагляду статусу і простых запросаў.
  • Як варыянты взаімаюцца межу сабою

    Кожны слой абсалютвае сваіх суседзей. Мадэль выбірае фармат API, які выкарыстоўвае фрэймворк, падход да памяці вялічыць, які тып зберагача неабходны, а інтэрфейс вялічыць, насколькі важна фарматаванне выходных дадзеных.

    Для локальнага асістэнта для кодавання адзінога распрацоўшчыка такі стак мінімізуе перашкоды, заўсёды залікаючы кожны слой заменяймым:

    Interface: Web UI on localhost
    │
    Framework: OpenClaw - tool-dispatch, SKILL.md routing
    │
    LLM: Ollama for qwen3:8b
    (think mode disabled for JSON reliability)
    │
    Memory: Structured persistent memory with value filtering
    Embeddings via nomic-embed-text
    │
    Storage: Chroma (zero infrastructure) or Qdrant (more robust)
    

    Паколькі кожны слой можа быць заменены незалежна, спачатку выберыце простэйшы варыянт на кожным рэвэлі і апгрэдавайце яго па меры падыходжання патрэбаў. Пераход з Chroma на Qdrant або з Ollama на vLLM не выклікае неабходнасці перзначання чаго-небудзь вышэй або ніжэй. Калі якійсь слой заслуговае на ранню інвестыцыю, то цэй будзе памяць. Скромны локальны модэль з добра спраектаваным слоем стойкай памяці надзеянна перамагае большы модэль, які кожную сесію пачынае з нуля.