Практычныя прытамулкі: Усе, што патрэбна для проектавання агентнай памяці
Практычныя прыказкі: усе, што патрэбна для проектавання агентнай памяці: контракты, перакрычанняя тэсты і слоты для коду для команд, якія викорыстоўваюць гэты патэрн.
Наступныя прытамлівкі паказваюць практычны шлях для рэалізацыі концепцыі “All You Want For Agentic Memory Design”. Акцэнт ставяцца на кантракты, пераконтроўкі і месца для коду, які можна легка адменстрацыяваць, а не на мотывацыйныя аспекты. Калі працуеце на стадзіі агледжэння, спачатку запісайце кантракт: неабяжныя даны, сігнал успеху і тое, што выканаецца у разе частковай нявыполненасці. Такі список контроля дапамагае залічваць пазнейшыя змены ў кодзе. Храніце настройкі парадульна ад коду прыемлівкі. Файлы сераўнавання, сховішчы секрэтных дадзеных і флагі функцыйяў должны знаходзіцца ў аднам месцы, куда аператары можу працаваць без неабяжнага чытання всіх элементаў системы.
Спіс зместу
Этап структуры зместа працюе наяўней, калі яго спрыяваць як мерыемую паверхню. Запісаце адна ідеальная версія, адзін прыклад неудачы і прыметку па адвярненню перад расшырэнням масштаба. Дакументавайце як шлях успеху, так і шлях вяснавання разам. Перапрыбуткі, людзкія контралі і обработка некоректных паведамленняў є часткай продукту, а не наступным этапам дорабатка. Храніце стан графаў у простам і типаваным формате. Вкладзеныя блокі маскуюць, який вузел запісаў канкрэтны поле, і спакшуюць продовжэнне роботы пасля перарываў.
Агент продовжваў забываць
Агент постаўляў забываць, што роботу на певным этапе лепш всючы як меруюцую паверхню. Запісаўце адна «золатая» транскрыпцыю, адзін прыклад неудачы і прыметку па адкату перш чым расширваць масштабы. Валіце маленькія, тэставаныя елементы замест большых скрыптов. Калі якісьць крок не выходзіць, прычына неудачы павінна вказваць на адную адпаведальнасць, а не на заплутаны ланцюг задач. Рэзультаты графа павінны быць простымі та з адзінаковым типам. Вярстаны блокі маскуюць, який вузол запісаў канкрэтны поле, і спакойна працаваюць пасля перарываў.
Чаму «вікна контэкста» не функцыонуюць (і доследжэнне, якое гэта падтвердзіла)
Этап анаізу прычын неяўнасці кантэкстных вікнаў работае наяўней, калі яго спрыяваць як мерыемую паверхню. Зафіксуйце адна ідеальная транскрыпцыю, адзін прыклад неяўнасці і запіс пра адваротную дзеянне перш чым расширваць масштаб. Спрыяйце гэтаму этапу як кантракту между вхіднымі дадзеннямі і паўнастайшымі выходнымі рэзультатамі. Дайце назвы артыфактам, задаць критэрыя успеху і адмовіцца ад тыхняе частковай роботы без паведамлення. Храніце стан графа ў простым і типаванам формате. Вкладзеныя блокі маскуюць, який вузел запісаў кожны поле, і спакшуюць возз'яданне пасля перарываў. Этап анаізу прычын неяўнасці кантэкстных вікнаў работае наяўней, калі яго спрыяваць як мерыемую паверхню. Зафіксуйце адна ідеальная транскрыпцыя, адзін прыклад неяўнасці і запіс пра адваротную дзеянне перш чым расширваць масштаб. Храніце настройкі параду ўнутры коду аплікацыі. Файлы сяродавішча, хранільнікі секрэтных дадзенняў і флагі функций должны знаходзіцца ў аднам месцы, якое аператары можаць пераглядаць без неабходнасці чытання всего графа.
Короткатэрмінная проты даўгатэрмінная памяць: Асновны разлік
Для стадіі короткакалендарнай і дзейнаеўскай памяці неабходна перад змянай коду адзначыць вхідныя даны, абавесця крока і критэрыі завершэння. Аперацыяныя працавнікі павінны магчымае запускаць крок з вядомай точкі контролю, не падозрываючы схованы стан. Неабходна аддзекластыць як шлях успеху, так і шлях вяснавання. Перапрыбуткі, людзкія перакрыцці і обробка некоректных паведамленняў ёсць часткай продукту, а не пасляднім дапрацоўкам. Пры выкарыстоўванні грошэй чы змяне данных у працэсе виробніцтва неабходна людзкая апраўдка. Прыўязкі ў часе кампілявання не адпавядаюць пачатковай цэлесообразнасі продукту.
Як промышленасць дайшла да чатырох типаў памяці
Для этапа «Як індустрыя стала адзінай» неабходна прадзеявленая інфармацыя, адпраўнік крока і крэтыры завершэння перад змянай коду. Аперацыйныя працавнікі должны магчыма ўвайсці крок з вядомай точкі перапытку без неабясненняя схованага стану. Лепш выбіраць маленькія, тэставаныя елементы замест большых скрыптаў. Калі крок не выйшоў, прычына неудачы должна вказываць на адну конкрэтную адпраўнасць, а не на заплутаны процес. Неабходна людская апраўдка для тых крокаў, якія выкорыстоўваюць грошы або зміняюць даны праўдзівай роботы. Компіляцыйныя налашчэння не ўзроўнаўцуюцься з пачатковасцю бізнес-процэсаў.
Рашэнні ўзгаліб пра базу дадзенаў праўдзівай роботы: SQL, Vector чы Graph
Для стадіі SQL пры выніканні рашэнняў у продакшн-базе дадзеных неабходна прадыктуваць вхідныя даны, адпаведальнага за крок і крэтары завершэння пры змяне коду. Аперацыйныя працавнікі должны магчымае перайсці на выкананне кроку з вядомага пункта контролю, не спрабоўваючы здагадвацца пра схованы стан. Спрыяйце цій стадіі як даговору межаў вхідных даных і перакананых выходных рэзультатаў. Даць назвы артыфактам, прадыктуваць перакананні пра успех і адмовіцца ад тыхнявага частковага завершэння. Забезпечыце людскія апраўдкі для тых крокаў, якія выкарыстоўваюць грошы чысткі змянююць даны ў продакшне. Кампіляцыйныя налашчэння не ўзроўнаваны з абсягам выконання задач у бізнесе. Для стадіі SQL пры выніканні рашэнняў у продакшн-базе дадзеных неабходна прадыктуваць вхідныя даны, адпаведальнага за крок і крэтары завершэння пры змяне коду. Аперацыйныя працавнікі должны магчымае перайсці на выкананне кроку з вядомага пункта контролю, не спрабоўваючы здагадвацца пра схованы стан. Зберагачыце налашчэнні параду ад коду прыкладнення. Файлы сяродавішча, хранільнікі секрэтных дадзеных і флагі функцияў должны знаходзіцца ў аднам месцы, якое працавнікі можу аудытаваць без права на чытанне.
< p>Усё графа.Слой 1: Пам’ять-буфер зі стварэнням кантракта
Калі працуеце з етапам пам’яті-буфера Слоя 1, спачатку запісайце кантракт: неабяжлівыя вхідныя даны, сигнал успеху і тое, што выходзіць у разе частковага невыпання. Такі список контролю дапамагае заліцвачыць пазнейшыя змены коду. Документавайце як шлях успеху, так і шлях вярнення. Перапрыбуткі, людзкіе етапы перагляду та обробка некоректных паведамленняў ёсць частью продукту, а не пазнейшым дапрацоўкам. Стварайце контрольныя пункты пасля дорогіх крокаў. Функцыя вярнення не павінна занова ставіць плату за той самы вызыв LLM, калі аператар перапрыбуе пазнейшы вузел.
from collections import deque
from typing import List, Dict
class BufferMemory:
def __init__(self, max_turns: int = 10):
# Each turn = one user message + one assistant message
self.history: deque = deque(maxlen=max_turns * 2)
def add_message(self, role: str, content: str):
self.history.append({"role": role, "content": content})
def get_context(self) -> List[Dict]:
return list(self.history)
def token_estimate(self) -> int:
total_chars = sum(len(m["content"]) for m in self.history)
return total_chars // 4 # rough approximation
def clear(self):
self.history.clear()
import os
from collections import deque
from typing import List, Dict
from openai import OpenAI
class SummarizingBufferMemory:
def __init__(self, max_turns: int = 8, summary_batch: int = 4):
self.client = OpenAI(
base_url="https://openrouter.ai/api/v1",
api_key=os.environ["OPENROUTER_API_KEY"],
)
self.model = "deepseek/deepseek-v4-flash-0731"
self.recent: deque = deque(maxlen=max_turns * 2)
self.rolling_summary: str = ""
self.summary_batch = summary_batch
def add_message(self, role: str, content: str):
if len(self.recent) == self.recent.maxlen:
self._compress_oldest()
self.recent.append({"role": role, "content": content})
def _compress_oldest(self):
batch = [self.recent.popleft() for _ in range(min(self.summary_batch * 2, len(self.recent)))]
text = "\n".join(f"{m['role']}: {m['content']}" for m in batch)
response = self.client.chat.completions.create(
model=self.model,
max_tokens=300,
messages=[
{
"role": "system",
"content": "You compress conversation history. Reply with the summary only.",
},
{
"role": "user",
"content": (
"Summarize this conversation segment in 2-4 sentences. "
"Preserve any decisions made, constraints stated, and conclusions reached.\n\n"
f"{text}"
),
},
],
)
new_summary = response.choices[0].message.content.strip()
if self.rolling_summary:
self.rolling_summary = f"{self.rolling_summary} | {new_summary}"
else:
self.rolling_summary = new_summary
def get_context(self) -> List[Dict]:
context = []
if self.rolling_summary:
context.append({
"role": "system",
"content": f"[Prior conversation summary: {self.rolling_summary}]",
})
context.extend(list(self.recent))
return context
Слой 2: Эпізодычная пам’ять з перакананнем у достовернасці цитатаў
Калі працуеце з стадзіяй эпізодычнай памяці 2-го слоя, спачатку запісаце кантракт: неабяжлівыя даны, сигнал успеху і тое, што выходзіць пад частыя неудачы. Такі список пераканаецца дапамагае залічваць змяны ў кодзе чыста. Валіце маленькія, тэставаныя елементы замест большых скрыптов. Калі якісь крок не выйшае, неудача должна вказваць на адну адпаведальнасць, а не на заплутаны ланцюг задач. Зробіце перапактаванне пасля дорогіх крокаў. Функцыя адновлення не должна зноў ставіць плату за той самы вызов LLM, калі аператар прабуе зноў запрацаваць з пазнейшым вузлом.
import json
import sqlite3
from datetime import datetime, timedelta
from dataclasses import dataclass, field
@dataclass
class Episode:
task_type: str
user_query: str
outcome: str
tools_used: list
citations: list # source references for validation
duration_seconds: float
success: bool
session_id: str = ""
created_at: str = field(default_factory=lambda: datetime.utcnow().isoformat())
class EpisodicMemory:
EXPIRY_DAYS = 28 # GitHub Copilot's production default
def __init__(self, db_path: str = "episodes.db"):
self.conn = sqlite3.connect(db_path, check_same_thread=False)
self._init_schema()
def _init_schema(self):
self.conn.executescript("""
CREATE TABLE IF NOT EXISTS episodes (
id INTEGER PRIMARY KEY AUTOINCREMENT,
task_type TEXT NOT NULL,
user_query TEXT,
outcome TEXT,
tools_used TEXT,
citations TEXT,
duration_s REAL,
success INTEGER,
session_id TEXT,
created_at TEXT
);
CREATE INDEX IF NOT EXISTS idx_task_type ON episodes (task_type, success, created_at);
""")
self.conn.commit()
def record(self, ep: Episode):
self.conn.execute(
"""
INSERT INTO episodes
(task_type, user_query, outcome, tools_used, citations,
duration_s, success, session_id, created_at)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
""",
(
ep.task_type, ep.user_query, ep.outcome,
json.dumps(ep.tools_used), json.dumps(ep.citations),
ep.duration_seconds, int(ep.success),
ep.session_id, ep.created_at,
),
)
self.conn.commit()
def recall_similar(self, task_type: str, limit: int = 3) -> list[Episode]:
cutoff = (datetime.utcnow() - timedelta(days=self.EXPIRY_DAYS)).isoformat()
cursor = self.conn.execute(
"""
SELECT task_type, user_query, outcome, tools_used, citations,
duration_s, success, session_id, created_at
FROM episodes
WHERE task_type = ? AND success = 1 AND created_at > ?
ORDER BY created_at DESC
LIMIT ?
""",
(task_type, cutoff, limit),
)
return [
Episode(
task_type=r[0], user_query=r[1], outcome=r[2],
tools_used=json.loads(r[3]), citations=json.loads(r[4]),
duration_seconds=r[5], success=bool(r[6]),
session_id=r[7], created_at=r[8],
)
for r in cursor.fetchall()
]
def validate_citations(self, episode: Episode, validator_fn) -> bool:
"""
validator_fn(citation: str) -> bool
Check if cited sources are still valid (file exists, URL responds, etc.)
Return False if any citation fails; the episode should be discarded.
"""
return all(validator_fn(c) for c in episode.citations)
3-й слой: Сэмантычная памяць з гібрыдным пошукам Weaviate
Калі працуеце над стадзіяй 3-го слоя сэмантычнай памяці, спачатку запісаце кантракт: неабяжлівыя даннэ, сігнал успеху і тое, што выходзіць у разе частковага нявыпання. Такі список перакладоў заходзіць пазнейшыя змены коду ў правільным направленні. Спрэцьвачыце гэтую стадзію як кантракт межа даннэмі і перакананымі выходамі. Дайце назву рэзультатам, задаце критэрыя успеху і не падтрымвайце тыхню частковую рэалізацыю без паведамлення. Зробіце перапактаванне пасля дорогіх крокаў. Система вярнення не павінна зноў ставіць плату за той самы вызов LLM, калі аператар прабуе зноў выконаць пазнейшы вузел. Калі працуеце над стадзіяй 3-го слоя сэмантычнай памяці, спачатку запісаце кантракт: неабяжлівыя даннэ, сігнал успеху і тое, што выходзіць у разе частковага нявыпання. Такі список перакладоў заходзіць пазнейшыя змены коду ў правільным направленні. Зберагаце настройкі паза кодам прыемлівача. Файлы сераўнавання, хранільнікі секрэтных дадзеных і флагі функций павінны знаходзіцца ў адном месцы, куда аператары можаць аудытаваць іх, не чытаючы весь граф.
import uuid as uuid_lib
from datetime import datetime
import weaviate
from weaviate.classes.config import Configure, Property, DataType, VectorDistances
from weaviate.classes.query import MetadataQuery, HybridFusion, Filter
def embed(text: str) -> list[float]:
"""
Swap in any embedding source: OpenAI, Cohere, sentence-transformers, etc.
Returns a normalized float vector.
"""
from sentence_transformers import SentenceTransformer
_model = SentenceTransformer("all-MiniLM-L6-v2")
return _model.encode(text, normalize_embeddings=True).tolist()
class WeaviateSemanticMemory:
COLLECTION = "AgentMemory"
def __init__(self, host: str = "localhost", port: int = 8080):
self.client = weaviate.connect_to_local(host=host, port=port)
self._ensure_collection()
def _ensure_collection(self):
if self.client.collections.exists(self.COLLECTION):
return
self.client.collections.create(
name=self.COLLECTION,
# We provide our own vectors; no built-in vectorizer needed.
# Swap to Configure.Vectorizer.text2vec_openai() if you prefer managed embedding.
vectorizer_config=Configure.Vectorizer.none(),
vector_index_config=Configure.VectorIndex.hnsw(
distance_metric=VectorDistances.COSINE
),
properties=[
Property(name="content", data_type=DataType.TEXT),
Property(name="task_type", data_type=DataType.TEXT),
Property(name="source", data_type=DataType.TEXT),
Property(name="citations", data_type=DataType.TEXT),
Property(name="session_id", data_type=DataType.TEXT),
Property(name="confidence", data_type=DataType.NUMBER),
Property(name="created_at", data_type=DataType.TEXT),
],
)
def store(
self,
content: str,
task_type: str = "",
source: str = "agent",
citations: str = "",
session_id: str = "",
confidence: float = 1.0,
) -> str:
collection = self.client.collections.get(self.COLLECTION)
doc_id = str(uuid_lib.uuid4())
collection.data.insert(
properties={
"content": content,
"task_type": task_type,
"source": source,
"citations": citations,
"session_id": session_id,
"confidence": confidence,
"created_at": datetime.utcnow().isoformat(),
},
vector=embed(content),
uuid=doc_id,
)
return doc_id
def retrieve_hybrid(
self,
query: str,
n_results: int = 5,
min_confidence: float = 0.6,
task_type: str = None,
) -> list[dict]:
collection = self.client.collections.get(self.COLLECTION)
# Filter by confidence floor and optionally by task type
confidence_filter = Filter.by_property("confidence").greater_or_equal(min_confidence)
if task_type:
active_filter = (
Filter.by_property("task_type").equal(task_type) & confidence_filter
)
else:
active_filter = confidence_filter
results = collection.query.hybrid(
query=query,
vector=embed(query),
limit=n_results,
fusion_type=HybridFusion.RELATIVE_SCORE,
filters=active_filter,
return_metadata=MetadataQuery(score=True),
)
return [
{
"content": obj.properties["content"],
"score": obj.metadata.score,
"confidence": obj.properties.get("confidence", 1.0),
"source": obj.properties.get("source", ""),
"citations": obj.properties.get("citations", ""),
"uuid": str(obj.uuid),
}
for obj in results.objects
]
def update_confidence(self, doc_id: str, new_confidence: float):
collection = self.client.collections.get(self.COLLECTION)
collection.data.update(
uuid=doc_id,
properties={"confidence": new_confidence},
)
def close(self):
self.client.close()
Слой 4: Процедурная памяць і шаблон эвалюэцыі запроса
Этап працы Процедурной памяці Слоя 4 дае найкращыя рэзультаты, калі яго спрыяваць як вимерную плошчу. Запісаўце адна ідеальная версія, адзін прыклад неудачы і прыметку па адкату перш чым расширваць масштаб. Дакументаваўце як успішны, так і вярнучыся шляхы. Перапрыбуткі, людзкія контралі і обработка некоректных паведамленняў є часткай продукту, а не наступным этапам дорабачання. Задаўце ліміт токенав на кожны раунд і на кожную сесію. Інструменты-агенты агрэсывна расширваюць контекст; строгі ліміты не дазволяюць дэмам ператварыцца на неспакоўныя рахункі.
import json
import os
import re
from datetime import datetime, timedelta, timezone
from openai import OpenAI
MODEL = "deepseek/deepseek-v4-flash-0731"
client = OpenAI(
base_url="https://openrouter.ai/api/v1",
api_key=os.environ["OPENROUTER_API_KEY"],
)
class ProceduralMemory:
def __init__(self, rules_path: str = "procedural_rules.json"):
self.rules_path = rules_path
self.rules: list[dict] = self._load()
def _load(self) -> list[dict]:
try:
with open(self.rules_path) as f:
return json.load(f)
except FileNotFoundError:
return []
def add_rule(self, situation: str, action: str, reason: str, confidence: float = 1.0):
self.rules.append({
"situation": situation,
"action": action,
"reason": reason,
"confidence": float(confidence),
"added_at": datetime.now(timezone.utc).isoformat(),
"trigger_count": 0,
})
self._save()
def get_applicable_rules(self, context: str, min_confidence: float = 0.7) -> list[dict]:
relevant = []
ctx_lower = context.lower()
dirty = False
for rule in self.rules:
if rule.get("confidence", 1.0) < min_confidence:
continue
keywords = rule["situation"].lower().split()
if not keywords:
continue
hits = sum(1 for kw in keywords if kw in ctx_lower)
if hits >= max(1, len(keywords) // 3):
rule["trigger_count"] = rule.get("trigger_count", 0) + 1
relevant.append(rule)
dirty = True
if dirty:
self._save()
relevant.sort(key=lambda r: r.get("confidence", 1.0), reverse=True)
return relevant[:5]
def prune_stale(self, max_age_days: int = 60, min_triggers: int = 2):
cutoff = (datetime.now(timezone.utc) - timedelta(days=max_age_days)).isoformat()
self.rules = [
r for r in self.rules
if r.get("added_at", "") > cutoff or r.get("trigger_count", 0) >= min_triggers
]
self._save()
def _save(self):
tmp = f"{self.rules_path}.tmp"
with open(tmp, "w") as f:
json.dump(self.rules, f, indent=2)
os.replace(tmp, self.rules_path)
def _parse_json(text: str) -> dict:
text = text.strip()
fenced = re.search(r"```(?:json)?\s*(.*?)```", text, re.S)
if fenced:
text = fenced.group(1).strip()
return json.loads(text)
def extract_rule_from_failure(failure_trace: str, memory: ProceduralMemory):
response = client.chat.completions.create(
model=MODEL,
max_tokens=250,
response_format={"type": "json_object"},
messages=[
{
"role": "system",
"content": "You return only a JSON object. No prose, no code fences.",
},
{
"role": "user",
"content": (
"A task failed. Extract one behavioral rule to prevent this failure.\n"
"Return ONLY valid JSON with keys: situation, action, reason, "
"confidence (0.0-1.0)\n"
f"Failure trace:\n{failure_trace}"
),
},
],
)
try:
rule = _parse_json(response.choices[0].message.content)
except (json.JSONDecodeError, AttributeError, TypeError):
return None
if not all(k in rule for k in ("situation", "action", "reason")):
return None
memory.add_rule(
situation=str(rule["situation"]),
action=str(rule["action"]),
reason=str(rule["reason"]),
confidence=float(rule.get("confidence", 1.0)),
)
return rule
Спаяванне ў адно: Асінхронны менеджер памяці і проектаванне системы
Асінхронны ўзаемадзеянне элементаў працюе наякша, калі яго розглядаць як мерыемую структуру. Зафіксавайце адну ідеальную версію, адзін прыклад неудачы і запіс пра вярнэнне да пачатковага стану, перш чым расширваць масштабы. Валіце маленькія, тэставаныя елементы замест большых скрыптаў. Калі якісь крок не выйшоў, прычына неудачы павінна вказываць на адную конкрэтную адпаведальнасць, а не на заплутаную сэрію крокаў. Рэгулюйце стан графа так, каб ён быў простым і з адзінаковым типам дадзеных. Вярсткаваныя структуры маскуюць інфармацію пра тое, який вузел запісаў канкрэтны поле, і спакойваюць працу пасля перерываў.
import json
from concurrent.futures import ThreadPoolExecutor
from dataclasses import dataclass, field
@dataclass
class TaskResult:
task_type: str
query: str
outcome: str
tools_used: list
citations: list
duration_seconds: float
success: bool
new_facts: list[dict] = field(default_factory=list)
session_id: str = ""
class MemoryManager:
def __init__(
self,
weaviate_host: str = "localhost",
episodic_db: str = "episodes.db",
rules_path: str = "procedural_rules.json",
):
self.buffer = SummarizingBufferMemory(max_turns=8)
self.episodic = EpisodicMemory(db_path=episodic_db)
self.semantic = WeaviateSemanticMemory(host=weaviate_host)
self.procedural = ProceduralMemory(rules_path=rules_path)
self._pool = ThreadPoolExecutor(max_workers=2, thread_name_prefix="memory_write")
def build_context(self, query: str, task_type: str) -> list[dict]:
context: list[dict] = []
# Procedural rules first: they constrain behavior throughout the task
rules = self.procedural.get_applicable_rules(query)
if rules:
rules_text = "\n".join(
f"- When '{r['situation']}': {r['action']} (reason: {r['reason']})"
for r in rules
)
context.append({"role": "user", "content": f"[Behavioral rules:\n{rules_text}]"})
# Semantic facts: domain knowledge and past discoveries
facts = self.semantic.retrieve_hybrid(query, n_results=5, min_confidence=0.6)
if facts:
facts_text = "\n".join(f"- {f['content']}" for f in facts)
context.append({"role": "user", "content": f"[Relevant knowledge:\n{facts_text}]"})
# Past episodes: outcome templates for similar tasks
episodes = self.episodic.recall_similar(task_type, limit=3)
if episodes:
ep_text = "\n".join(
f"- Outcome: {e.outcome} (tools: {', '.join(e.tools_used)})"
for e in episodes
)
context.append({"role": "user", "content": f"[Past similar tasks:\n{ep_text}]"})
# Current conversation last: the model reads this most carefully
context.extend(self.buffer.get_context())
return context
def record_turn(self, role: str, content: str):
self.buffer.add_message(role, content)
def persist(self, result: TaskResult):
# Submit to thread pool and return immediately; never block the caller
self._pool.submit(self._persist_worker, result)
def _persist_worker(self, result: TaskResult):
ep = Episode(
task_type=result.task_type,
user_query=result.query,
outcome=result.outcome,
tools_used=result.tools_used,
citations=result.citations,
duration_seconds=result.duration_seconds,
success=result.success,
session_id=result.session_id,
)
self.episodic.record(ep)
for fact in result.new_facts:
self.semantic.store(**fact)
if not result.success:
extract_rule_from_failure(result.outcome, self.procedural)
def shutdown(self):
self._pool.shutdown(wait=True)
self.semantic.close()
Тры рашэнні, якія визначаюць вашу архітектуру
Тры ўзнімкі, якія апісваюць стадію, працуюць наяўней калі іх расследжваць як вимерную паверхню. Зафіксуйце адны ідеальны прыклад, адзін прыклад неудачы і запіс пра вярнэнне да пачатковага стану перш чым расширваць масштаб. Расследжвайце гэтую стадію як кантракт межа вхіднымі дадзеннямі і паверыжанымі выходнымі рэзультатамі. Дайце назвы артыфактам, задаць критэрыя успеху і не падзеўляйцеся частым, непূরным викананнем задач. Храніце стан графа ў простам і типаваным формате. Вкладзеныя блокі маскуюць інфармацыю пра тое, який вузел запісаў кожны поле, і спакоююць працэс пасля перарываў. Тры ўзнімкі, якія апісваюць стадію, працуюць наяўней калі іх расследжваць як вимерную паверхню. Зафіксуйце адны ідеальны прыклад, адзін прыклад неудачы і запіс пра вярнэнне да пачатковага стану перш чым расширваць масштаб. Храніце настройкі параду ад коду прыемліка. Файлы сераў, хранільнікі секрэтных дадзенняў і флагі функцыйяй должны знаходзіцца ў аднам месцы, куды аператары можаць аудытаваць іх без неабходнасці чытаць весь граф.
Отруўванне памяці: як выглядаюць атакі і як західцаць
Для запобежчання заражэнню памяці, перш чым зменшваць код, неабходна ясная вяскапленасць стадій, параметраў вхідных даных, адпаведальнага за кожны крок і крэтарыяў завершэння. Аперацыйныя працавнікі должны магчымае перайсці на гэты крок з вядомага пункта контролю, не спрабоўваючы здогадвацца пра схованы стан. Неабходна адразу задокументаваць як шлях успеху, так і шлях вясвабаджэння. Перапрыбуткі, людзкія пераказы і обработка некоректных паведамленняў є часткай продукту, а не етапамі далейшага доўнелення. Неабходна людзкая апрацоўка для тых крокаў, якія выкорыстоўваюць грошы або зміняюць даны праўдзівай роботы. Компіляцыйныя налашчэння не є гарантыяй повнай адпаведнасці продукту бізнес-трэбованням.
Практычныя рэкамендацыі
Для самага этапу рэкамендацыі неабходна ўзначыць вхідныя даны, адпаведальнага за крок і крэтырыя завершэння пры перадзеі коду. Аперацыйныя працавнікі должны магчыма ўвайсці крок з вядомага пункта контролю, не спрабоўваючы здагадвацца пра схованы стан. Лепш выбіраць маленькія, тэставаныя елементы замест большых скрыптаў. Калі крок не выйшоў, прычына неудачы павінна вказываць на адзін конкрэтны аспект, а не на заплутаны процес. Неабходна людская апраўда для тых крокаў, якія выкарыстоўваюць грошы чы зміняюць даны ў працэсе виробніцтва. Компіляцыйныя налашчэння не ўзначаюць павнае адпрацоўванне бізнес-процэса.
Давайте продовжым развівацца разам
У стадії «Давай продолжаем вучыцца» неабяжна прадзефінаваць вхідныя даны, адміністратара крока і крэтырыя для завершэння пры зміне коду. Аперацыйныя працавнікі должны магчымае запускаць крок з вядомай точкі контролю, не спрабоўваючы здогадвацца пра схованы стан. Спрыяйце цій стадіі як даговору межаў вхідных даных і перакананых выходных рэзультатаў. Даць назвы артыфактам, прадзефінаваць пераканання ў успеху і адмовіцца ад беззвучнага частковага завершэння. Забезпечыце людскія празборы для тых крокаў, якія витрачаюць грошы або зменяюць даны ў працэсе. Компіляцыйныя налашчанні не ўзроўнаваліся з повным завершэнням бізнес-процесаў. У стадії «Давай продолжаем вучыцца» неабяжна прадзефінаваць вхідныя даны, адміністратара крока і крэтырыя для завершэння пры зміне коду. Аперацыйныя працавнікі должны магчымае запускаць крок з вядомай точкі контролю, не спрабоўваючы здагадвацца пра схованы стан. Зберагачыце налашчанні парадульна ад коду прыкладнення. Файлы сераўіса, хранільнікі секрэтных данных і флагі функцыйяў должны знаходзіцца ў аднам месцы, якое працавнікі можуць аудытаваць, не чытаючы весь структураны карэнтны стан.
Іншыя корыстныя статті
Калі працюеце над этапам «Іншыя корыстныя статті», спачатку запісайце умовы контракту: неабяжлівыя данні, сігнал успеху і тое, што выходзіць у разе частковага невыпання. Такі список пераконтролю дапамагае заліцвачыць пазнейшыя змены ў кодзе. Документавайце як шлях успеху, так і шлях вярнення да нормы. Перапрыбуткі, людзкія контрольныя пункты і обработка некоректных паведамленняў є частью продукту, а не пазнейшым дапрацоўкам. Зробіце пераконтроль пасля дорогіх крокаў. Система вярнення не должна занова ставіць плату за той самы вызыв LLM, калі аператар перапрыбуе пазнейшы вузел.
Чек-ліст для эксплуатацыі
Для этапа «Чек-ліст для эксплуатацыі» перад зменай кодзе задаце данні, адпаведальную особу за крок і критэрыя завершэння. Аператары должны магчыма было перазапусціць крок з вядомага пераконтролю, не спрабоўваючы здагадвацца пра схованы стан.
Запісвайце часы выконання аперацый і косць токенаў чы роезыкаў праза функцыйнае рэзультат. Відразліва візуалізацыя косцаў запобегае неспакойным рахункам, калі парадок пераходзіць з дэмовай среды ў спяльнаныя среды.
Заставьце людзкія апраўды на лініях, якія витрачаюць грошы чы зменяюць данні ў працэсе. Падключэння пад час компілявання не ўзроўнаўцяеся з повнай адпаведнасцю бізнесу.
Напісце кароткі посібнік: як роўнаць клучы, як спрачысці чергу, як анулюваць пярэдню інтеграцыю.
Зберагайце настройкі парадзельна ад коду прыемліка. Файлы среды, хранільнікі секрэтных дадзеных і флагі функций должны знаходзіцца ў аднам месцы, куды аператары можаць адбавляць без неабходнасці чытання всей структуры.
Заставьце людзкія апраўды на лініях, якія витрачаюць грошы чы зменяюць данні ў працэсе. Падключэння пад час компілявання не ўзроўнаўцяеся з повнай адпаведнасцю бізнесу.
Перш чым запускать стэк, заморозьце версіі, зафіксавце «золаты» транскрыпты для критичных шляхоў і паказваце спосабы атрыбуціі. У спадзяльных средах неабходны ліміты частоты запуска, пераканання ў належнасці тэриторыі і чысткі власніка для ротацыі секрэтных дадзенняў. Валідную надзею на стабільнасць лепш за крэатыўныя, адзінразовыя дамахі.
Прыметка для пакету b038012e06fc: не кладзіце ключы прадаўцаў у репазітарый, задаце верхнюю межу токеноў на сесію і зберагачыце транскрыпты празаўсёды з фікстурамі для ацэнкі, каб пазнейшыя замены моделяў заставаліся порównаннімы.
Для прыметкі па забезпечэнню безпекі на стадыі 0 абмовіцеся вхіднымі дадзеннямі, власнікам крока і крэтарыям завершэння пры змене коду. Аперацыйныя системы павінны магчымае перзапуск крока з вядомай точкі контролю, не падозрываючы схованы стан. Спрыяйце цій стадыі як даговору межа вхіднымі дадзеннямі і перакананымі выходнымі рэзультатамі. Даце назвы артыфактам, абмовіцеся перакананнямі пра успех і адмовіцеся ад тых, хто завершае роботу часткова без паведамлення.
Дзеянне паўжасткі 0/804: звярніце увагу на час выканання, клас памылкі і колькасць викорыстоўваных токенаў для гэтага запісу, а пасля, на аднойчынныя крэтыры, а не на індывідуальныя прыклады, вырашыце, чы робіць змяну.
Калі працюеце над першым этапам запісу паўжасткі, спачатку запішыце контракт: неабходныя данні, сігнал успеху і тое, што выканаецца у разе частковай памылкі. Такі список контроля дапамагае заставіць пазнейшыя змяны коду чыстымі. Канфігурацыю трэба зберагаць параду ад коду прыемлівача. Файлы сераўнавання, хранільнікі секрэтных данных і флагі функцыйяў должны знаходзіцца ў аднам месцы, куда аператары можуць адбавіць аудыт без неабходнасці чытання всей структуры.
Дзеянне паўжасткі 1/804: звярніце увагу на час выканання, клас памылкі і колькасць викорыстоўваных токенаў для гэтага запісу, а пасля, на аднойчынныя крэтыры, а не на індывідуальныя прыклады, вырашыце, чы робіць змяну.
Этап 2 прыцеленняя на зміцнэнне работае найкраща, калі яго розглядаць як вимероўваную паверхню. Запісаце адна «золатая» транскрыпцыя, адин прыклад неудачы і запіс пра вярнэнне да пачатковага стану перш чым расширваць масштабы. Валіце маленькія, тэставаныя елементы замест большых скрыптов. Калі якісь крок не выйшае, прычына неудачы павінна вказываць на адную адпаведальнасць, а не на заплутаны процес.
Дзеянне прыцеленняя на зміцнэнне 2/804: вимеравайце час выканання, класію памылак і колькасць выкорыстоўваных токенав для гэтага запісу, а потым вырашайце, чы рашыцца застаўляць змяну, стварываючыся на адной фіксаванай сэтцы пытанняў, а не на анекдотах.
Для трэція ўрадзу пункту пра змецеленне неабходна ўскладніць вводныя даны, адпаведальную особу за кожны крок і критэрыя завершэння пры змены коду. Аператары должны магчымае перайсці на гэты крок з вядомага пункта контролю, не спрабоўваючы здогадвацца пра схованы стан. Запісвайце час выконання і вартасць токена або запыту паляглі разам з функцыйнальнымі рэзультатамі. Відразліва візуабільнасць вартасцей запобегае неспакоўным рахункам, калі процес пераходзіць з дэмовай среды ў спакульную.
Дзялейчык пра змецеленне 3/804: вы меравайце час выконання, класію адказоў і витраты токена для гэтага пункту, а потым вырашайце, чы робіць змену на аднойчы зафіксаванай сэтке пытанняў, а не на аднойчы інформацыі.
Калі працуеце над 4-й стадзіяю прыемкі з павышэння безпекі, спачатку запісайце угоду: неабяжлівыя данні, сігнал успеху і тое, што выходзіць пад частковы нявыплэн. Такі список контроля дапамагае заставіць пазнейшыя змены коду быць чыстымі.
Документавайце як шлях успеху, так і шлях вярнення. Перапрыбуткі, людзкіе контралі і обработка некоректных паведамленняў ёсць частью продукту, а не пазнейшым дапрацоўкам.
Дзялей 4/804 прыемкі з павышэння безпекі: вымерайце час выканання, класыя ошибакі і витрату токенав для гэтай прыемкі, а пасля выберайце, чы робіць змены на адной пазначанай сэткі пытанняў, а не на адной толькі прымітцы.
4-я стадзія прыемкі з павышэння безпекі работае лепей, калі яе спрыямаць як вымеральную паверхню. Зафіксуйце адна ідеальная транскрыпцыя, адзін прыклад нявыплэну і прыемку для абраткаў перад расшырэнням масштаба. Спрыяйце гэтай стадзіі як угоды межа даннімі і перакананымі выходамі. Дайце назвы артыфактам, задаць критэрыяі успеху і адмовіцеся ад тыхнай частковай, неканфірмаванай дапрацоўкі.
Дзеянне паўжчання 5/804: звярніце увагу на час выканання, класы паказакоў і витрату токенаў для гэтага запісу, а пасля, на аднойчынай базе фіксаванага набору пытанняў, а не на індывідуальных прыкладах, выявіце, чы рэшыцца застаўіць змяну.
Для 6-й стадзіі паўжчання неабходна перад змянай коду чытаць, калі будуць вводзіцца даны, хто ўпраўляе гэтым крокам і якія будуць критэрыяы завершэння. Аперацыйныя працавнікі павінны магчымае перадзванаць гэты крок з вядомага пункта контролю, не спрабоўваючы здагадвацца пра схованы стан. Конфігурацыю трэба зберагчы за межамі коду прыемленае. Файлы сяродавішча, хранільнікі секрэтных дадзенняў і флагі функцыйяй павінны знаходзіцца ў адном месцы, якое працавнікі можуць пераглядаць, не чытаючы весь код.
Дзеянне паўжчання 6/804: звярніце увагу на час выканання, класы паказакоў і витрату токенаў для гэтага запісу, а пасля, на аднойчынай базе фіксаванага набору пытанняў, а не на індывідуальных прыкладах, выявіце, чы рэшыцца застаўіць змяну.
Калі працуеце над 7-ю стадзіяй забезпечэння безпекі, спачатку запісайце умовы кантракта: неабяжлівыя даны, сігнал успеху і тое, што выходзіць на частым неудачам. Такі список контроля дапамагае залічваць пазнейшыя змены ў кодзе чыста і прозрачна. Валіце маленькія, тэставаныя елементы замест вялікіх скрыптав. Калі якась стадзія не выйшла, неудача должна вказваць на адну конкрэтную адпаведальнасць, а не на заплутаны ланцюг задач.
Дзеянне забезпечэння безпекі 7/804: замерайце час выканання, класію паканаў і колькасць токенаў, якія былі выкарыстоўваны для гэтай стадзіі, а пасля выберайце, чы робіць змены на адной основе фіксаванага набору пытанняў, а не на адной лячбе.
8-я стадзія забезпечэння безпекі працуе лепей, калі яе спрыямаць як меравальную плошчу. Запісайце адны ідеальны прыклад роботы, адзін кейс неудачы і прыказку па вярнэнню да пачатковага стану, прычым не расшырюючы сферу дзеяння. Запісвайце часы выканання і косць токенаў або запытак праза функцыйнае рэзультат. Відкрытая інформацыя пра косцы з’являецца перашкоду неспакою, калі процес пераходзіць з дэмавайшага режыма ў спяльныя среды.
Дзеянне паўжчання 8/804: звярніце увагу на час выканання, клас памылакі і колькасць выкорыстоўваных токенаў для гэтага запісу, а пасля, на аднойчынай базе фіксаванага набору пытанняў, а не на асобістых спазыраннях, выявіце, чы робіць змены.
Для 9-го этапу паўжчання неабходна перад змянай коду чытко визначыць вхідныя даны, адпаведальнага за крок і критэрыя завершэння. Аперацыйныя працавнікі должны магчымае перадзвануць крок з вядомай точкі контролю, не падозрываючы прыхованы стан. Неабходна адначасова задокументаваць шлях успеху і шлях вярнення. Перапрыбуткі, людзкія перакрыцця і обробка некоректных паведамленняў є часткай продукту, а не чымсь, што дадаецца пазней.
Дзеянне паўжчання 9/804: звярніце увагу на час выканання, клас памылакі і колькасць выкорыстоўваных токенаў для гэтага запісу, а пасля, на аднойчынай базе фіксаванага набору пытанняў, а не на асобістых спазыраннях, выявіце, чы робіць змены.
Калі працуеце над 10-ю стадзіяй ударожэння, спачатку запісайце контракт: неабяжлівыя данні, сігнал успеху і тое, што выходзіць у разе частковага неяксамоства. Такі список контроля дапамагае залічыць пазнейшыя змены коду адкрыта. Спрыятлівайце гэтую стадзію як контракт межа даннімі і перакананымі выходамі. Дайце назву артыкулам, задаце правіла пераканання успеху і адмовіцеся ад тыхоўскага частковага завершэння.
Дзеянні ўдарожэння 10/804: звярніце увагу на час выканання, класы памылак і витрату токенав для гэтай змены, а пасля вырашыце, чы робіць яе, стварыўшы фіксаваны набор пытанняў, а не на адной лічбе.
11-я стадзія ударожэння працюе лепей, калі яе спрыятлівваюць як меравальную плошчу. Запісайце адна ідеальная транскрыпцыя, адзін прыклад неяксамоства і змэту аб анулюванні, перш чым расширваць масштаб. Зберагайце настройкі параду ўнутры коду прыемленае. Файлы сяродавішча, хранільнікі секрэтных дадзенняў і флагі функций павінны знаходзіцца ў адном месцы, куды аператары можаць аудытаваць, не чытаючы весь граф.
Дзеянне паўжасткі 11/804: звярніце увагу на час выканання, класы памылак і колькасць выкорыстоўваных токенаў для гэтага запісу, а пасля, на аднойчынай базе фіксаванага набору пытанняў, а не на асобістых спазыраннях, выявіце, чы хацяце застаўіць змены.
Для 12-го этапу паўжасткі неабходна перад змянай коду чытко визначыць вхідныя даны, адпаведальнага за крок і критэрыя завершэння. Аперацыяныя працавнікі должны магчымае перадзваначыць крок з вядомай точкі контролю, не падозрываючы прыхованы стан. Лепш выбіраць маленькія, тэставаныя елементы замест большых скрыптов. Калі крок не выйшоў, прычына нехарактернага рэзультата должна вказываць на адну конкрэтную адпаведальнасць, а не на заплутаны процес.
Дзеянне паўжасткі 12/804: звярніце увагу на час выканання, класы памылак і колькасць выкорыстоўваных токенаў для гэтага запісу, а пасля, на аднойчынай базе фіксаванага набору пытанняў, а не на асобістых спазыраннях, выявіце, чы хацяце застаўіць змены.