Практычныя нататкі: як насамрэч працуе спецыфікацыя ARD
Практычны разбор тэмы «спецыфікацыя Agentic Resource Discovery (ARD) знутры»: кантракты, праверкі і гатовыя фрагменты кода для каманд, якія ўкараняюць гэты падыход.
Крыніцы: Inside ARD: How the Agentic Resource Discovery Spec Actually Works
Наступныя прыміткі паказваюць практычны шлях для розумэння “Inside ARD: How the Agentic Resource Discovery Spec Actually Works”. Акцэнт ставіцца на контракты, пераконтроўванні і месца для коду, а не на мотывацыйныя аспекты. Калі працуеце над стадзіяй агледжэння, спачатку запісайце контракт: неабяжныя даны, сігнал успеху і тое, што выканаецца у разе частковага невыпалення. Такі спіс дапамагае заліцвачыць пазнейшыя змены ў кодзе. Документавайце як шлях успеху, так і шлях вярнення да нормы. Перапрыбуткі, людзкія контралі і обработка некорэктных паведамленняў ёсць часткай продукту, а не пазнейшым дапрацоўкам.
Проблема, яку рашае ARD
Проблема ARD лепша ў тым, калі яе спрыяваць як меркаваную паверхню. Зафіксавайце адны «золаты» прыклад працы, адну справу з бягам і прыміткі па варыянты рэшэння прычыны бягу, перш чым расшырваць масштабы. Валіце маленькія, тэставаныя елементы замест большых скрыптов. Калі якісь крок не выйшае, прычына бягу павінна вказываць на адную адпаведальнасць, а не на заплутаны ланцюг задач. Рэзультаты працы графа павінны быць простымі і з адначытаемым тыпам. Вярнутыя структуры дадзеных маскуюць інфармацыю пра тое, які вузел запісаў канкрэтны поле, і спакоююць продовжэнне працы пасля перэрываў.
Ментальная мадэль: апісацыя, прасканаванне, пошук, вызов
Ментальная мадэль, якая апісвае стадыю, працуе найкрашча, калі яе расследжваць як вімерную паверхню. Запісаўце адна «золатая» транскрыпцыю, адзін прыклад неудачы і запіс пра вярнэнне да пачатковага стану перш чым расшырваць масштабы. Расследжвайце гэтую стадыю як кантракт межа вхіднымі дадзеннямі і паверыжанымі выходнымі рэзультатамі. Даўце назвы артыфактам, задаце крытэрыя успеху і адмовіцеся ад тыхоўскага частковага завершэння. Задаце бюджэт токенав на кожны рунг і на кожную сесію. Інструменты-агенты агрэсывна расшырваюць кантэкст; строгія ліміты не дазволяюць дэмам ператварыцца на неспакоўныя рахункі.
Апісваўце рэсурса: маніфест ai-catalog.json
Этап апібарацыі рэсурса працуе наяўней, калі яго спрыяваць як вімерную паверхню. Зберагачыце адны ідэальны прыклад работы, адзін прыклад неудачы і запіс пра вярнэнне да пачатковага стану перад расшырэнням масштаба. Запісвайце часы выканання і косты токеноў або запытак па боку ад функцыйнальных рэзультатаў. Візуабельнасць костаў з самага пачатку запобегае неспакойным рахункам, калі працэс пераходзіць з дэмаверсіі ў спяльныя асяроддзя. Храніце стан графа ў простам і тыпаваным фармаце. Вярнутыя структуры дакументаў маскуюць інфармацыю пра тое, які вузел запісаў кожны поле, і спакшваюць продыржанне выканання пасля перарываў. Этап апібарацыі рэсурса працуе наяўней, калі яго спрыяваць як вімерную паверхню. Зберагачыце адны ідэальны прыклад работы, адзін прыклад неудачы і запіс пра вярнэнне да пачатковага стану перад расшырэнням масштаба. Дакументавайце як успешны, так і вярнучыся шляхі працы. Перапрыбуткі, людзкія контрольныя пункты і обработка некорэктных паведамленняў ёсць часткай продукту, а не чымсь, што дадаецца пазней.
https://yourdomain.com/.well-known/ai-catalog.json
{
"specVersion": "1.0",
"host": {
"displayName": "Northwind Labs",
"identifier": "northwindlabs.dev"
},
"entries": [
{
"identifier": "urn:ai:northwindlabs.dev:tools:pdf-table-extractor",
"displayName": "PDF Table Extractor",
"type": "application/mcp-server+json",
"url": "https://tools.northwindlabs.dev/pdf-extractor/mcp.json",
"description": "Extracts structured tables from scanned or digital
PDFs into CSV or JSON.",
"representativeQueries": [
"pull the line-item table out of this invoice PDF",
"convert the tables in this scanned report into a spreadsheet"
]
}
]
}
Ідэнтыфікатор: чаму ідэнтыфікат выглядае як URN
Для з’ясавання прычыны проблемы на стадыўцы ідэнтыфікацыі неабходна пазначыць вхідныя даны, адпаведальнага за крок і крытэрыя завершэння пры перадзначэнні коду. Аперацыйныя працавнікі должны магчыма ўвайсці крок з вядомай точкі контролю, не прабуючы спадарожваць схованы стан. Валідзіце маленькія, тэставаныя елементы замест большых скрыптов. Калі крок не выконваецца, прычына нехаўкаю павінна вказываць на адну конкрэтную адпаведальнасць, а не на заплутаны ланцюг задач. Заставьце людзей апраўдваць тыя крокі, якія ведуць да вітрачання грошаў або зміны дадзэнняў у працоўным рэжыме. Компіляцыйныя налаштаванні не ёсць гарантыяй полнай адпрацоўкі задач.
API: пошук, аналіз і просты спіс
Для этапы адаптавання API-знаходжэння неабяцкова практычна вызначэнне параметраў, адпаведальнага за крок, і крэтарыяў завершэння працы перад зменым коду. Аператары должны магчымае пераўстаць выкананне кроку з вядомага пункта контролю, не спрабоўваючы здагадвацца пра схованы стан. Спрыяйце цій этапы як даговору межа параметрамі і перакананымі рэзультатамі. Дайце назву файлам, вызначыце крэтарыі успеху і не прымайце частковае завершэння без паведамлення. Забяжыце людзкія апраўданні для тых крокаў, якія выкарыстоўваюць грошы або зміняюць даныя у працэўным рэжыме. Компіляцыйныя налашчэнні не ўзроўнаваны з абсягам бізнес-працы.
{
"query": {
"text": "I need to digitize an invoice's line items",
"filter": {
"type": ["application/mcp-server+json"]
}
},
"pageSize": 5
}
Федэрацыя: рэестры, якія спілкуюцца межа сабой
Для рэгістраў Федэрацыі, якіе вярбуюцца з стэйджам, неабходна перад змянай коду апрацаваць параметры вхідных дадзеных, адпаведальнага за крок і крэтарыя выходу. Аператары должны магчымае перайсці на выкананне кроку з вядомага пункта контролю, не спрабоўваючы здагадвацца пра схованы стан. Запісвайце час выканання і вартасць токенаў або запытак палягліва да рэзультатаў функцыянальнай працы. Візуабельнасць вартасцей з самага пачатку запобегае неспакойным рахункам, калі працэс пераходзіць з дэмавайнага рэжыма ў спадзеленыя сераўеры. Заставіце людскую аправу на тых кроках, якія выкарыстоўваюць грошы або зміняюць даны ў працэсе віробніцтва. Праця ў час компілявання не ёсць адпаведнай для пачатку рэальной бізнес-працы. Для рэгістраў Федэрацыі, якіе вярбуюцца з стэйджам, неабходна перад змянай коду апрацаваць параметры вхідных дадзеных, адпаведальнага за крок і крэтарыя выходу. Аператары должны магчымае перайсці на выкананне кроку з вядомага пункта контролю, не спрабоўваючы здагадвацца пра схованы стан. Дакументавайце як шлях успеху, так і шлях вярнення да нормальнага стану. Перапрыбуткі, людскія контрольныя пункты і обработка некорэктных запытак ўскладневаюць продукт, а не яго частка.
Для паветраціі.
Дзе гэта насправды падключаецца да чатбота
Калі працуеце над этапам «Дзе гэта насправды падключаецца», спачатку запісайце умовы: неабяжлівыя даныя, сігнал успеху і тое, што выходзіць у разе частковага нявыпання. Такі спіс контроля дапамагае заліцвачваць пазнейшыя змены ў кодзе. Валіце маленькія, тэставаныя елементы замест большых скрыптов. Калі якісь крок не выйшоў, прычына нявыпання павінна вказываць на адну конкрэтную адпаведальнасць, а не на заплутаны ланцужок задач. Ствараюце контрольныя пункты пасля дорогіх крокаў. Сістэма вярнення не павінна зноў ставіць плату за той самы вызов LLM, калі аператар прабуе зноў выконаць пазнейшы вузел.
Стварэнне ў рэальных умовах: рэалізацыя ARD у працэсе на Snowflake
Калі працюеце над стадзіяй «Стварэнне рэальна», спачатку запісайце контракт: неабяжлівыя даныя, сігнал успеху і тое, што выходзіць у разе частковага нявыпання. Такі спіс пераконтроўкаў дапамагае заліцвачыць змяны ў кодзе. Спрыймайце гэтую стадзію як контракт межа данымі і перакананымі выходамі. Дайце назву рэзультатам, задаць тэсты на успех і адмовіцеся ад мовчанкавага частковага завершэння. Зробіце пераконтроўку пасля дорогіх крокаў. Програма не должна занова выклікаць той самы калл LLM, калі аператар прабуе зноў запрацаваць з пазнейшым вузлам.
┌─────────────────────────────────────────────────────────────┐
│ Streamlit UI Layer │
│ (Serves /.well-known/ai-catalog.json + search interface) │
├─────────────────────────────────────────────────────────────┤
│ API Procedures Layer │
│ ARD_SEARCH │ ARD_LIST_AGENTS │ ARD_EXPLORE │ ARD_GATE │
├─────────────────────────────────────────────────────────────┤
│ Semantic Ranking Layer │
│ Python UDF: TF-IDF + Cosine Similarity (scikit-learn) │
├─────────────────────────────────────────────────────────────┤
│ Registry Layer │
│ ARD_REGISTRY_ENTRIES table + ARD_AUDIT_LOG │
├─────────────────────────────────────────────────────────────┤
│ Ingestion Layer │
│ ARD_INGEST_MANIFEST (parse JSON → populate registry) │
├─────────────────────────────────────────────────────────────┤
│ Generation Layer │
│ ARD_MANIFEST_GENERATOR (DESCRIBE AGENT → ai-catalog.json) │
└─────────────────────────────────────────────────────────────┘
Слою 1: Аўтаматычнае стварэнне маніфеста з жывых агентаў
Калі працуеце над стадзіяй автагенеравання на роўні 1, спачатку запісайце «контракт»: неабходныя даны, сігнал успеху і тое, што выходзіць у разе частковага невыпання. Такі спіс перакладоў заходзіць пазнейшыя змены коду ў правільным напрамку. Запісвайце часы выканання і кост токенаў або запытаў праза функцыйнае рэзультат. Відкрытыя даны пра косцы з’являюцца перашкоду неспакоўным рахункам, калі працэс пераходзіць з дэмаверсіі ў спакульнаныя сераўсы. Зробіце контрольную пазнаку пасля дорогіх крокаў. Функцыя вярнення не павінна знову нараховваць косты той самай вызову LLM, калі аператар прабуюць зноў запрацаваць пазнейшы вузол. Калі працуеце над стадзіяй автагенеравання на роўні 1, спачатку запісайце «контракт»: неабходныя даны, сігнал успеху і тое, што выходзіць у разе частковага невыпання. Такі спіс перакладоў заходзіць пазнейшыя змены коду ў правільным напрамку. Дакументавайце як «шчаслівы» шлях, так і шлях вярнення да нормальнасці. Прабуванні зноў, людзкія контролы і обработка некорэктных паведамленняў ёсць часткай продукту, а не пазнейшым дапрацоўкам.
SHOW AGENTS IN SCHEMA ANALYTICS.AGENTS;
{
"specVersion": "1.0",
"host": {
"displayName": "Snowflake Analytics Platform",
"identifier": "analytics.snowflake-demo.com"
},
"entries": [
{
"identifier": "urn:ai:analytics.snowflake-demo.com:analytics:finance-agent",
"displayName": "Finance Agent",
"type": "application/vnd.snowflake.cortex-agent+json",
"url": "https://zkumjrw-uib48895.snowflakecomputing.com/api/v2/cortex/agents/...",
"description": "Finance AI analyst with expertise in ASC 606...",
"tags": ["finance", "revenue", "ASC-606", "ARR", "bookings"],
"capabilities": ["text-to-sql", "metric-disambiguation"],
"representativeQueries": [
"What was our recognized revenue last quarter?",
"Show me ARR trend over the past 12 months"
],
"trustManifest": {
"identity": {"type": "domain-verified", "domain": "analytics.snowflake-demo.com"},
"attestations": [
{"type": "RBAC-governed", "detail": "FINANCE_AGENT_ROLE required"}
]
}
}
]
}
Слой 2: Адаптаванне да вышукаўнага рэестру
Этап адаптавання да вышукаўнага рэестру на Слое 2 работае найкрашча, калі яго розглядаць як вімерную паверхню. Зберагачыце адна ідэальная транскрыпція, адзін прыклад неудачы і запіс пра вярнэнне да пачатковага стану, перш чым расшырваць масштаб. Валіце малыя, тэставаныя елементы замест большых скрыптов. Калі якісь крок не выйшае, прычына неудачы павінна вказываць на адную адпаведальнасць, а не на заплутаны ланцюг задач. Рэзерваваць стан графа ў простам і тыпізаваным фармаце. Вкладныя блокі маскуюць інфармацыю пра тое, які вузел запісаў канкрэтны поле, і спакоююць працу пасля перэрываў.
ARD_REGISTRY_ENTRIES
├── IDENTIFIER (URN, unique)
├── DISPLAY_NAME
├── TYPE (IANA media type)
├── URL
├── DESCRIPTION
├── TAGS (ARRAY)
├── CAPABILITIES (ARRAY)
├── REPRESENTATIVE_QUERIES (ARRAY)
├── TRUST_MANIFEST (VARIANT)
├── SEARCH_TEXT (lower-cased concatenation of description + queries + tags)
├── STATUS ('ACTIVE' | 'STALE' | 'REMOVED')
└── Timestamps (INGESTED_AT, LAST_VERIFIED_AT, UPDATED_AT)
Слой 3: Семантычнае вышукванне — падход з Python UDF
Этап семантычнага пошуку на роўні 3 працюе найэфектывней, калі яго розглядаць як мерыемую паверхню. Зафіксавайце адна ідэальная транскрыпцыя, адзін прыклад неудачы і запіс пра вярнэнне да пачатковага стану перш чым расшырваць масштабы. Разглядзайце гэты этап як кантракт межа вхіднымі данымі і паверыжанымі выходнымі рэзультатамі. Дайце назвы артыфактам, задаць крытэрыя успеху і адмовіцеся ад тыхоўскага частковага завершэння. Закрэпіце інтэрпрэтара і файл з правамі на выкарыстоўванне падметаў прытым, як што навчаце цыкл. Адхіленне межа лептапам і сістэмай CI ёсць найчастэйшым тыхоўскім нарушэнням пад час дэманстрацый API.
CREATE OR REPLACE FUNCTION ANALYTICS.AGENTS.ARD_SEMANTIC_RANK(
query_text VARCHAR,
candidates ARRAY
)
RETURNS ARRAY
LANGUAGE PYTHON
RUNTIME_VERSION = '3.11'
PACKAGES = ('scikit-learn', 'numpy')
HANDLER = 'rank_candidates'
AS
$
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity
def rank_candidates(query_text, candidates):
if not candidates or not query_text:
return []
identifiers = [c['identifier'] for c in candidates]
texts = [c.get('search_text', '') for c in candidates]
all_texts = [query_text.lower()] + [t.lower() for t in texts]
vectorizer = TfidfVectorizer(
ngram_range=(1, 3),
max_features=5000,
stop_words='english',
sublinear_tf=True
)
try:
tfidf_matrix = vectorizer.fit_transform(all_texts)
except ValueError:
return [{'identifier': id, 'score': 0} for id in identifiers]
similarities = cosine_similarity(tfidf_matrix[0:1], tfidf_matrix[1:])[0]
results = [
{'identifier': id, 'score': round(float(sim) * 100, 1)}
for id, sim in zip(identifiers, similarities)
]
results.sort(key=lambda x: x['score'], reverse=True)
return results
$;
Роўень 4: Брама вызыву — RBAC пры выкананні
У роўні 4 стадыя вызывання працюе найэфектывней, калі яе розглядаць як вімерную паверхню. Зафіксуйце адны ідэальны прыклад працы, адзін прыклад неудачы і запіс пра відкатанне раней, чым расшыруваць масштабы. Запісвайце часы выканання і вартасьць токеноў чы апыткаў па боку ад функцыйнальных рэзультатаў. Візуабельнасьць вартасцей з самага пачатку запобегае неспакойным рахункам, калі працэс пераходзіць з дэмовай асяроддзя ў спакульную. Храніце стан графа у простам і тыпаваным фармаце. Вкладзеныя блокі маскуюць інфармацыю пра тое, які вузел запісаў які поле, і спакштуюць продовжэнне працы пасля перэрываў. У роўні 4 стадыя вызывання працюе найэфектывней, калі яе розглядаць як вімерную паверхню. Зафіксуйце адны ідэальны прыклад працы, адзін прыклад неудачы і запіс пра відкатанне раней, чым расшыруваць масштабы. Документавайце як шлях успеху, так і шлях вяснавання проблем. Перапрыбуткі, людзкі контроль і обработка некорэктных паведамленняў ёсць часткай продукту, а не етапамі далейшай оптымаўзаціі.
CALL ARD_INVOCATION_GATE(
'urn:ai:analytics.snowflake-demo.com:analytics:finance-agent',
'ACCOUNTADMIN'
)
-- Returns: {"authorized": true, "agentFqn": "ANALYTICS.AGENTS.FINANCE_AGENT", ...}
CALL ARD_INVOCATION_GATE(
'urn:ai:analytics.snowflake-demo.com:analytics:finance-agent',
'PUBLIC'
)
-- Returns: {"authorized": false, "reason": "Role PUBLIC lacks FINANCE_AGENT_ROLE grant."}
Роўень 5: Сервер маніфеста Streamlit
Для этапу Layer 5 The Streamlit неабяжна прадзецьваваць вхідныя даны, адпаведнага адпаведальнага за крок і крэтыяры выходу пры зміне коду. Аператары должны магчымаць перзапуск кроку з вядомай точкі контролю, не падозрываючы схованы стан. Лепш выбіраць маленькія, тэставаныя елементы замест большых скрыптов. Калі крок не выйшае, прычына неудачы должна вказываць на адзіну адпаведальнасць, а не на заплутаны працэс. Заставіць людзкую апраўду на тых этапах, дзе відбываецца выдатак грошэй або зміняюцыся даны для працы. Працэўнае падключэнне не ёсць гарантыяй полнайсткі бізнес-процэса.
manifest = get_manifest()
st.code(json.dumps(manifest, indent=2), language="json")
st.download_button("Download", json.dumps(manifest, indent=2), "ai-catalog.json")
query = st.text_input("Query", placeholder="I need to analyze quarterly revenue")
cap_filter = st.selectbox("Capability", [None, "text-to-sql", "multi-tool-routing"])
if st.button("Search"):
results = search_registry(query, filters)
for entry in results["results"]:
st.expander(f"{entry['displayName']} — Score: {entry['score']}")
stats = get_registry_stats()
# Shows: 4 entries, 18 tags across 4 agents, 3 capability types
Layer 6: Полны комплект для тэставання
Для этапу «Канцэн-до-канцэн» на роўні 6 неабходна перад змянай коду вызначыць вхідныя даны, адпаведальнага за крок і крытэрыя завершэння. Аператары должны магчымае запускіць крок з вядомай точкі контролю, не падозрываючы прыхованы стан. Спрыяйце цэму этапу як кантракту межа вхіднымі данымі і перакананымі выходнымі рэзультатамі. Даўце назвы артыфактам, вызначыце перакананні успеху і адмовіцеся ад беззвучнага частковага завершэння. Аўтэнтыфікуйцеся на воратах і паўтарна автарызуйцеся на роўні дадзенняў. Толькі токэн-носіцель не ёсцца межай арэнды.
Test 1: MANIFEST_GENERATION
→ Calls ARD_MANIFEST_GENERATOR(), asserts specVersion = "1.0"
and entries array is non-empty
Test 2: MANIFEST_INGESTION
→ Calls ARD_INGEST_MANIFEST(manifest), asserts status = "SUCCESS"
and entries_ingested > 0
Test 3: SEARCH_FINANCE_QUERY
→ Searches "What was our revenue last quarter?"
→ Asserts top result identifier contains "finance"
Test 4: SEARCH_CHURN_QUERY
→ Searches "Which customers are likely to churn?"
→ Asserts top result identifier contains "cs"
Test 5: SEARCH_WITH_FILTER
→ Searches "pipeline forecast" with capabilities filter ["text-to-sql"]
→ Asserts results > 0 (filter applied correctly)
Test 6: LIST_AGENTS
→ Calls ARD_LIST_AGENTS(1, 10)
→ Asserts pagination.totalEntries > 0
Test 7: EXPLORE_FACETS
→ Calls ARD_EXPLORE()
→ Asserts facets.tags is not null and totalEntries > 0
Test 8: GATE_AUTHORIZED
→ Calls ARD_INVOCATION_GATE(finance URN, "ACCOUNTADMIN")
→ Asserts authorized = true
Test 9: GATE_UNAUTHORIZED
→ Calls ARD_INVOCATION_GATE(finance URN, "PUBLIC")
→ Asserts authorized = false
Test 10: HEALTH_CHECK
→ Calls ARD_HEALTH_CHECK()
→ Asserts status = "COMPLETE"
{
"summary": {
"total_tests": 10,
"passed": 10,
"failed": 0,
"success_rate": "100.0%"
},
"tests": [...],
"timestamp": "2026-06-18T..."
}
Захоўка прыладоў у працэсе: што ламаецца і як мы гэта вылечылі
Для ўжошчэння працы сістэмы у рэжыме продакшн, на стадыўцы аналізу таго, што можа зламацца, неабходна прадзефінаваць вхідныя даны, адпаведальную особу за кожны крок і крэтыніяты для завершэння працы перад зменыма коду. Аператары должны магчымаць перзапуск крока з вядомай точкі контролю, не спрабоўваючы здагадвацца пра схованы стан. Запісвайце час выканання і вартасьць токенаў або запытак праза функцыйнае рэзультат. Відкрытая візуабілізацыя вартасцей запобегае неспакоўным рахункам, калі сістэма пераходзіць з дэмовай асяроддзя ў спакульнаныя сераўы. Заставьце людзкую апрацоўку для тых крокаў, якія выкалічваюць грошы або зменяюць даны ў рэжыме продакшн. Працэс кампілявання не ёсць гарантыяю полнай адпаведнасьці продукту бізнес-трэбованням. Для ўжошчэння працы сістэмы у рэжыме продакшн, на стадыўцы аналізу таго, што можа зламацца, неабходна прадзефінаваць вхідныя даны, адпаведальную особу за кожны крок і крэтыніяты для завершэння працы перад зменыма коду. Аператары должны магчымаць перзапуск крока з вядомай точкі контролю, не спрабоўваючы здагадвацца пра схованы стан. Документавайце як «шчаслівы» шлях, так і шлях вяснавання проблем. Перапрыбуткі, людзкія контрольныя пункты і обработка некорэктных запытак ўскладневаюць частку продукту, а не яе частка.
Для падчыркавання.
Сервер маніфеста Streamlit — аднаслужэнне ARD праз HTTP
Калі працуеце над стадзіяй сервера маніфеста Streamlit, спачатку запісайце умовы: неабяжлівыя даныя, сігнал успеху і тое, што выканаецца у разе частковага невыпалення. Такі спіс контроля дапамагае заліцвачыць змяны ў кодзе. Валіце маленькія, тэставаныя елементы замест большых скрыптов. Калі якісь крок не выйшае, прычына невыпалення павінна вказываць на адную адпаведальнасць, а не на заплутаны ланцюг задач. Зробіце контрольную точку пасля дорогіх крокаў. Програма для продакцыявання не павінна зноў выклікаць той самы календар LLM, калі аператар пракушае пазнейшы вузел.
Розгортанне
Калі працюеце на стадыі развяроцьбы, спачатку запісайце угоду: неабяжлівыя даныя, сігнал успеху і тое, што выходзіць у разе частковага нявыпання. Такі спіс пераконтроўкаў дапамагае заліцвачыць пазнейшыя змены ў кодзе. Спрыймайце гэтую стадыю як угоду межа данымі і перакананымі выходамі. Дайце назву артыфактам, задаць правілы пераканання успеху і адмовіцеся ад тыхоўскага частковага завершэння. Зробіце пераконтроўку пасля дорогіх крокаў. Програма не должна зноў выкарыстоўваць той самы вызов LLM, калі аператар прабуе зноў запрацаваць пазнейшы вузел.
CREATE STAGE IF NOT EXISTS ANALYTICS.AGENTS.STREAMLIT_STAGE
ENCRYPTION = (TYPE = 'SNOWFLAKE_SSE');
-- Upload source (via COPY INTO from temp table)
COPY INTO @ANALYTICS.AGENTS.STREAMLIT_STAGE/ard_manifest_app/streamlit_app.py
FROM (SELECT content FROM _STREAMLIT_SRC)
FILE_FORMAT = (TYPE = CSV COMPRESSION = NONE ...)
SINGLE = TRUE OVERWRITE = TRUE;
CREATE OR REPLACE STREAMLIT ANALYTICS.AGENTS.ARD_MANIFEST_SERVER
ROOT_LOCATION = '@ANALYTICS.AGENTS.STREAMLIT_STAGE/ard_manifest_app'
MAIN_FILE = '/streamlit_app.py'
QUERY_WAREHOUSE = COMPUTE_WH;
Полны код Streamlit
Калі працуеце з выключным стадыям коду Streamlit, спачатку запісайце умовы вікорыстання: неабяжлівыя даны, сігнал успеху і тое, што выходзіць у разе частковага нявыпання задачы. Такі спіс дапамагае заліцварваць можлівыя змены ў кодзе. Запісывайце час выканання і кост токена або запіту разам з рэзультатамі функцыянальнай працы. Відразлівасць костаў з самага пачатку запобегае неспакойным рахункам, калі праця пераходзіць з дэмаверсіі ў спакульнаныя сераўы. Стварайце контрольны пункт пасля дорогіх крокаў. Функцыя вярнення не должна зноў нараховваць косты той самай вызову LLM, калі аператар прабуюць зноў выконаць пазнейшы вузел.
import streamlit as st
import json
from snowflake.snowpark.context import get_active_session
st.set_page_config(page_title="ARD Manifest Server", layout="wide")
session = get_active_session()
@st.cache_data(ttl=300)
def get_manifest():
result = session.sql("CALL ANALYTICS.AGENTS.ARD_MANIFEST_GENERATOR()").collect()
return json.loads(result[0][0])
@st.cache_data(ttl=300)
def search_registry(query, filters=None):
safe_query = query.replace("'", "''")
if filters:
filter_json = json.dumps(filters).replace("'", "''")
sql = f"CALL ANALYTICS.AGENTS.ARD_SEARCH('{safe_query}', PARSE_JSON('{filter_json}'))"
else:
sql = f"CALL ANALYTICS.AGENTS.ARD_SEARCH('{safe_query}')"
result = session.sql(sql).collect()
return json.loads(result[0][0])
@st.cache_data(ttl=300)
def get_registry_stats():
result = session.sql("CALL ANALYTICS.AGENTS.ARD_EXPLORE()").collect()
return json.loads(result[0][0])
tab1, tab2, tab3, tab4 = st.tabs([
"ai-catalog.json", "Search", "Explorer", "API Docs"
])
Табліца 1: Необработаны маніфест
Калі працуеце з роўнем «Tab 1 The raw stage», спачатку запішыце умовы кантракту: неабходныя даны, сігнал успеху і тое, што выходзіць пад частым нявыпаннем задачы. Такі спіс контроля дапамагае залічваць змяны ў кодзе чыста.
with tab1:
st.markdown("## /.well-known/ai-catalog.json")
manifest = get_manifest()
c1, c2, c3 = st.columns(3)
c1.metric("Spec Version", manifest.get("specVersion", "?"))
c2.metric("Host", manifest.get("host", {}).get("identifier", "?"))
c3.metric("Entries", len(manifest.get("entries", [])))
st.code(json.dumps(manifest, indent=2), language="json")
st.download_button(
"Download ai-catalog.json",
json.dumps(manifest, indent=2),
"ai-catalog.json",
"application/json"
)
Tab 2: Інтэрактыўны семантычны пошук
Калі працюеце над інтэрактыўным семантычным этапам Tab 2, спачатку запісайце угоду: неабходныя даны, сігнал успеху і тое, што выходзіць пад частым неудачам. Такі спіс пераканае ў тым, што пазнейшыя змены коду будуць чыстымі. Документавайце як шлях успеху, так і шлях вярнення. Перапрыбуткі, людзкі контроль і обработка некорэктных паведамленняў ёсць часткай продукту, а не пазнейшым дапрацоўкам. Зробіце пераканаючы пункт пасля дорогіх крокаў. Сістэма вярнення не должна зноў ставіць плату за той самы вызов LLM, калі аператар перапрыбуе пазнейшы вузел.
with tab2:
st.markdown("## POST /search")
query = st.text_input("Query", placeholder="e.g., I need to analyze quarterly revenue")
cap_filter = st.selectbox("Capability", [None, "text-to-sql", "multi-tool-routing"])
if st.button("Search", type="primary") and query:
filters = {"capabilities": [cap_filter]} if cap_filter else None
results = search_registry(query, filters)
st.markdown(f"### {results['resultCount']} results")
st.caption(f"Method: {results.get('method', 'keyword')}")
for i, entry in enumerate(results.get("results", [])):
with st.expander(f"#{i+1} {entry['displayName']} — Score: {entry['score']}"):
st.markdown(f"**ID:** `{entry['identifier']}`")
st.markdown(f"**URL:** `{entry.get('url', 'N/A')}`")
st.markdown(f"**Tags:** {', '.join(entry.get('tags', []))}")
st.markdown(f"**Capabilities:** {', '.join(entry.get('capabilities', []))}")
if entry.get("representativeQueries"):
for q in entry["representativeQueries"]:
st.markdown(f"- _{q}_")
Tab 3: Разглед з рознымі аспектамі
Калі працюеце на стадыі фасетаванага аналізу Tab 3, спачатку запісайце умовы працы: неабяжлівыя даны, сігнал успеху і тое, што выходзіць пад частыя неудачы. Такі спіс контроля дапамагае заліцвачыць змяны ў кодзе. Валіце маленькія, тэставаныя елементы замест большых скрыптов. Калі якісь крок не выйшае, неудача должна вказваць на адну конкрэтную адпаведальнасць, а не на заплутаны ланцюг задач. Зробіце перапактаванне пасля дорогіх крокаў. Програма не должна зноў ставіць плату за той самы вызов LLM, калі аператар праказвае празбор наступнага вузла.
with tab3:
st.markdown("## POST /explore")
stats = get_registry_stats()
st.metric("Active Entries", stats.get("totalEntries", 0))
e1, e2, e3 = st.columns(3)
with e1:
st.markdown("### Types")
for f in stats.get("facets", {}).get("type", []):
st.markdown(f"- `{f['value']}` ({f['count']})")
with e2:
st.markdown("### Tags")
for f in stats.get("facets", {}).get("tags", []):
st.markdown(f"- `{f['value']}` ({f['count']})")
with e3:
st.markdown("### Capabilities")
for f in stats.get("facets", {}).get("capabilities", []):
st.markdown(f"- `{f['value']}` ({f['count']})")
Tab 4: Апавяданне API
Калі працюеце над стадзіяй рэферэнсу API Tab 4, спачатку запішыце умовы кантракту: неабяжлівыя даныя, сігнал успеху і тое, што выходзіць у разе частковага нявыпання. Такі чэк-ліст дапамагае захаваць чыстасць пазнейшых змян у кодзе. Спрыятліваце гэтую стадзію як кантракт межа данымі і пераканаленымі выходнымі данымі. Даць назвы элементам, задаць правіла пераканалення і не прыймаць часткова завершэнне без паведамлення. Зрабіце чэкпоінт пасля дорогіх крокаў. Сістэма вярнення не павінна зноў выклікаць той самы калл LLM, калі аператар прабуе зноў выконаць пазнейшы элемент.
with tab4:
st.markdown("""
| ARD Endpoint | Procedure | Description |
|---|---|---|
| `GET /.well-known/ai-catalog.json` | `ARD_MANIFEST_GENERATOR()` | Live manifest |
| `POST /search` | `ARD_SEARCH(query, filters)` | Semantic search |
| `POST /explore` | `ARD_EXPLORE()` | Faceted browse |
| `GET /agents` | `ARD_LIST_AGENTS(page, size)` | Paginated list |
| Gate | `ARD_INVOCATION_GATE(urn, role)` | RBAC check |
Scoring: TF-IDF + cosine similarity (scikit-learn), 0-100 scale.
Identity: urn:ai:<domain>:<namespace>:<agent-name>
""")
Адчынэнне дапрыемлівасці да прыкладнага програму
Калі працуеце над стадзіяй «Адрыханне да прыемленае», спачатку запісайце умовы вікорыстоўвання: неабходныя даныя, сігнал успеху і тое, што выходзіць на частыя неудачы. Такі спіс дапамагае заліцваліваць пазнейшыя змены ў кодзе. Запісвайце час выканання і вартасьць токена або запытку праза функцыйнае рэзультат. Відразлівая вартасьць з самага пачатку запобегае неспакоўным рахункам, калі працэс пераходзіць з дэмаверсіі ў спяльныя сераўры. Зробіце перапытку пасля дорогіх крокаў. Сістэма не должна зноў нарахоўваць плата за той самы вызов LLM, калі аператар праканае пазнейшы вузел. Калі працуеце над стадзіяй «Адрыханне да прыемленае», спачатку запісайце умовы вікорыстоўвання: неабходныя даныя, сігнал успеху і тое, што выходзіць на частыя неудачы. Такі спіс дапамагае заліцваліваць пазнейшыя змены ў кодзе. Дакументавайце як успішны, так і варыянт вярнення да нормальнага стану. Пракананні, людзкія контролі і обработка некорэктных паведамленняў ёсць часткай продукту, а не дадатковым элементам пасляўпрацоўкі.
Рэзультаты жывых тэстаў
Этап аналізу рэзультатаў жывых тэстаў працюе наякшым чынам, калі яго спрыятаць як меравальную плошчу. Зафіксавайце адны ідэальны прыклад працы, адзін прыклад неудачы і запіс пра вярнэнне да попераднего стану, перш чым расшырваць масштабы тэстаў. Валідзіце маленькія, тэставаныя елементы замест большых скрыптаў. Калі які-небудзь крок не выйшаў, прычына неудачы павінна вказваць на адну конкрэтную адпаведальнасць, а не на заплутаны ланцуг задач. Рэзультаты графаў павінны быць простымі і з адзінаковым тыпам дадзеных. Вярсткаваныя структуры дадзеных маскуюць інфармацыю пра тое, які вузел запісаў канкрэтны поле, і спакойваюць працу пасля перарываў.
Пошук: «Вам трэба аналізаваць нашы квартальныя доходы»
Пошук, які трэба адгрупаваць, працуе наяўней калі яго спрыяваць як мерыемую паверхню. Зафіксавайце адны ідэальны прыклад, адзін прыклад неудачы і запіс пра вярнэнне да пачатковага стану перш чым расшырваць масштабы. Спрыявайце гэтым этапам як кантракту межа вхіднымі данымі і перакананымі выходнымі рэзультатамі. Даўце назвы артыфактам, задаць крытэрыя успеху і адмовіцеся ад тыхоўскага частковага завершэння. Храніце стан графа як плоскі і з адначынным тыпам. Вярстакаваныя блокі маскуюць, які вузел запісаў кожны поле, і спакшваюць продажы пасля перарываў.
Results: 2 found | Method: tfidf-cosine-similarity
#1 Finance Agent — Score: 3.5
ID: urn:ai:analytics.snowflake-demo.com:analytics:finance-agent
Tags: finance, revenue, ASC-606, ARR, bookings
Capabilities: text-to-sql, metric-disambiguation#2 Executive Agent — Score: 1.5
ID: urn:ai:analytics.snowflake-demo.com:analytics:executive-agent
Tags: executive, cross-domain, orchestrator, KPI
Capabilities: text-to-sql, metric-disambiguation, multi-tool-routing
Пошук: «Калькі кляўэнтав, верагодна, пакінуць службу?»
Пошук кліянтав, які знаходзяцца на певным этапе, найэфектывней працюе, калі яго расследжваць як вімерную велічыну. Запісайце адзін удачны прыклад, адзін прыклад неудачы і прыметкі па поверненню да пярвоначальнага стану пры розшырэнні масштаба. Запісвайце часы выканання і косты токеноў або запытак праза функцыйнае рэзультат. Відразлівае прадставленне костаў з’являецца рана, чым утвараюцца неспакойныя рахункі, калі працэс пераходзіць з дэмовай асяроддзя ў спяльныя сераўеры. Храніце стан графа простым і з адначытаемымі данымі. Вкладаныя блокі маскуюць інфармацыю пра тое, які вузел запісаў канкрэтны поле, і спакшваюць продовжэнне працы пасля перэрываў.
Results: 1 found | Method: tfidf-cosine-similarity
#1 CS Agent — Score: 10.5
ID: urn:ai:analytics.snowflake-demo.com:analytics:cs-agent
Tags: customer-success, health-score, churn, NPS, CSAT
Пошук: “pipeline forecast” з можлівасцю фільтрацыі=[“text-to-sql”]
Прогназ праграмы пошуку з ўсіма етапамі працюе найэфектывней, калі яго розглядаць як вімерную паверхню. Зберагачыце адна ідэальная транскрыпція, адзін прыклад неудачы і запіс пра вярнэнне да пачатковага стану перш чым расшырваць масштабы. Храніце настройкі парадульна ад коду прыемліка. Файлы сераўнавальной асяроддзя, хранільнікі секрэтных даных і флагі функцыйяў должны знаходзіцца ў аднам месцы, куды аператары можаць адбавляць контроль без неабяжнага чытання всіх дадзеных. Храніце стан графа ў простам і тыпаваным фармаце. Вярнутыя блокі дадзеных маскуюць інфармацыю пра тое, які вузел запісаў канкрэтны поле, і спакоююць продаж чытання пасля перэрываў.
Results: 2 found (filtered from 4 total)
#1 Sales Agent — Score: 8.2
#2 Finance Agent — Score: 2.1
Фасеты эксплорэра
Фасеты механізму Explorer працююць наякнайэфектывней, калі іх розглядаць як вімерную паверхню. Запісаўце адна «золатая» транскрыпцыя, адын прыклад неудачы і запіс пра відкатанне раней, чым расшырваце дыяпазон. Дакументаваць трэба як шлях успеху, так і шлях вярнення да стану нормы. Перапрыбуткі, людзкія контрольныя пункты і обработка некорэктных паведамленняў ёсць часткай продукту, а не етапамі далейшай доўнелівання. Храніце стан графа як просты і з адначытаемымі данымі. Вкладаныя структуры дадзеных маскуюць інфармацыю пра тое, які вузел запісаў кожна поль і спакоююць продовжэнне выканання пасля перэрываў.
Total Active Entries: 4
Types:
- application/vnd.snowflake.cortex-agent+json (4)
Tags (18 total):
- bookings (2), finance (1), revenue (1), ASC-606 (1), ARR (1),
sales (1), pipeline (1), forecast (1), win-rate (1),
customer-success (1), health-score (1), churn (1), NPS (1),
CSAT (1), executive (1), cross-domain (1), orchestrator (1), KPI (1)
Capabilities:
- text-to-sql (7), metric-disambiguation (7), multi-tool-routing (1)
Тэст контрольнага пункта вызывання
Этап тэставання вората Invocation работае наяўней, калі яго спрыяваць як мерыемую паверхню. Запісаце адна «золатая» версія рэзультата, адын прыклад неудачы і прыметку па вярнэнню да пачатковага стану пры расшырэнні масштаба. Валіце маленькія, тэставаныя елементы замест большых скрыптов. Калі якісь крок не выйшае, прычына неудачы павінна вказываць на адную адпаведальнасць, а не на заплутаны ланцюг задач. Рэзультаты графа павінны быць простымі і з адначыя тыпамі дадзеных. Вкладаныя структуры дадзеных маскуюць інфармацыю пра тое, які вузел запісаў канкрэтны поле, і спакоююць працу пасля перэрываў.
CALL ARD_INVOCATION_GATE('urn:ai:...finance-agent', 'ACCOUNTADMIN')
→ {"authorized": true, "reason": "Role ACCOUNTADMIN is authorized..."}
CALL ARD_INVOCATION_GATE('urn:ai:...finance-agent', 'PUBLIC')
→ {"authorized": false, "reason": "Role PUBLIC lacks FINANCE_AGENT_ROLE grant."}
Слой манітарынгу
Этап слоя манітарынгу працюе наяўней, калі яго спрыяваць як мерымае паверхне. Запісайце адну ідэальную транскрыпцыю, адзін прыклад неудачы і запіску пра вярнэнне да пачатковага стану перш чым расшырваць сферу дзеяння. Спрыяйце гэтам этапу як кантракту межа вхіднымі данымі і перакананымі выходнымі рэзультатамі. Дайце назвы артыфактам, задаце крытэрыя успеху і адмовіцеся ад тыхоўскага частковага завершэння. Зберагачыце стан графа ў простам і тыпаванам фармаце. Вкладзеныя блокі маскуюць, які вузел запісаў канкрэтны поле, і спакшуюць возобнавленне працы пасля перэрываў.
Што гэта значыць на практыцы
Практычна значыць, што этап «Што гэта значыць» працуе найкрашча, калі яго розглядаюць як вімерную паверхню. Зафіксуйце адны ідэальны прыклад, адзін прыклад неудачы і запіс пра вярнэнне да пачатковага стану перад расшырэнням масштаба. Запісвайце часы выканання і косты токеноў або запытак па боку ад функцыйнальных рэзультатаў. Візуабельнасць костаў з самага пачатку запобегае неспакойным рахункам, калі працэс пераходзіць з дэмаверсіі ў спяльныя асяроддзя. Разважайце стан графа простым і з адзінаковым тыпам дадзеных. Вкладаныя блокі маскуюць інфармацыю пра тое, які вузел запісаў кожны поле, і спакшуюць продовжэнне працы пасля перарываў. Практычна значыць, што этап «Што гэта значыць» працуе найкрашча, калі яго розглядаюць як вімерную паверхню. Зафіксуйце адны ідэальны прыклад, адзін прыклад неудачы і запіс пра вярнэнне да пачатковага стану перад расшырэнням масштаба. Дакументавайце як шлях успеху, так і шлях вярнэння да нормальнага стану адночасна. Перапрыбуткі, людзкія контрольны пункты і обработка некорэктных паведамленняў ёсць часткай продукту, а не чымсь, што дадаецца пазней.
"I need to analyze our quarterly revenue figures"
Finance Agent — Score: 15.8
Executive Agent — Score: 3.5
Sales Agent — Score: 3.2
Інструменты для рэалізавальнікаў
Для этапы «Адыяванні для рэалізавальнікаў» неабходна прадзефінаваць вхідныя даны, адпаведальную особу за крок і крытэрыя завершэння пры зміне коду. Аперацыйныя працавнікі должны магчымае перайсці на выкананне кроку з вядомага пункта контролю, не спрабоўваючы з’ясаваць схованы стан. Лепш выбіраць маленькія, тэставаныя елементы замест большых скрыптов. Калі крок не выканаецца, прычына неудачы должна вказываць на адну конкрэтную адпаведальнасць, а не на заплутаны працэс. Автэнтыфікуйцеся на в’язку і паўторна автарызуйцеся на роўні дадзенняў. Толькі токэн-носіцель не ёсць межай адпаведальнасці.
Што далей
У стадыі «Што далей?» неабяжна прадзеўніць вхідныя даны, адпаведальную особу за крок і крытэрыя завершэння перад змінайом коду. Аперацыяныя працавнікі павінны магчымае перадзеўжваць крок з вядомага пункту контролю, не спрабоўваючы здагадвацца пра схованы стан. Спрацавляйце гэтую стадыю як кантракт межа вхіднымі данымі і падтверджанымі выходнымі рэзультатамі. Даўце назвы артыфактам, прадзеўніць перагляды успеху і адмовіцеся ад тыхнай частковай завершэння без паведамлення. Заставьце людзкія апраўданні для тых крокаў, якія выкарыстоўваюць грошы або зміняюць даны для працы. Компіляцыйныя налашчэнні не ўзроўнаўцяюцца з павнайстковасцю бізнес-процэсаў.
Пачатак работы
У стадыі «Пачатак» неабяжна ўзначыць вхідныя даны, адпаведальнага за крок і крэтыры завершэння пры змяне коду. Аперацыйныя працавнікі должны магчымае запускаць крок з вядомай точкі контролю, не спрабоўваючы здагадвацца пра схованы стан. Запісваць час выканання і вартасць токена або запыту разам з функцыйнальнымі рэзултатамі. Візуабельная інформацыя пра вартасці з самага пачатку запобегае неспакоўным рахункам, калі працэс пераходзіць з дэмовай асяроддзя ў спяльнаныя сераўеры. Прызначыць людскія апраўдкі для тых крокаў, якія вітрачаюць грошы або зменяюць даны у працэсе. Компіляцыйныя налаштаванні не ўзначаюць повнасці продукту з точкі зору бізнеса. У стадыі «Пачатак» неабяжна ўзначыць вхідныя даны, адпаведальнага за крок і крэтыры завершэння пры змяне коду. Аперацыйныя працавнікі должны магчымае запускаць крок з вядомай точкі контролю, не спрабоўваючы здагадвацца пра схованы стан. Адначасова задокументаваць шлях успеху і шлях вярнення. Перапрыбуткі, людскія апраўдкі і апрацоўка некорэктных паведамленняў ёсць часткай продукту, а не елементамі, якія дадаюцца пазней.
git clone https://github.com/satish/ard-registry.git
cd ard-registry
-- In Snowsight, execute these SQL files in order:
sql/01_infrastructure.sql -- Creates stage, tables, audit log
sql/02_manifest_generator.sql -- Reads agent metadata → ARD manifest
sql/03_ingest.sql -- Parses manifest → searchable registry
sql/04_semantic_rank.sql -- Python UDF (TF-IDF + cosine similarity)
sql/05_search.sql -- Semantic search endpoint
sql/06_list_and_explore.sql -- List + explore endpoints
sql/07_invocation_gate.sql -- RBAC authorization gate
sql/08_monitoring.sql -- Scheduled refresh + health check
sql/10_e2e_test.sql -- Test harness-- Then ingest and verify:
EXECUTE IMMEDIATE $
DECLARE v_manifest VARIANT; v_result VARIANT;
BEGIN
CALL ANALYTICS.AGENTS.ARD_MANIFEST_GENERATOR() INTO v_manifest;
CALL ANALYTICS.AGENTS.ARD_INGEST_MANIFEST(:v_manifest) INTO v_result;
RETURN :v_result;
END;
$;CALL ANALYTICS.AGENTS.ARD_END_TO_END_TEST();
-- Expected: 10/10 PASS (100%)
Чэк-ліст аператыўнай працы
На этапы чэк-ліста аператыўнай працы неабходна праказаць вхідныя даны, адпаведальную особу за кожны крок і крэтыніяя зняцья з працы пры змены коду. Аператары должны магчыма было перзапусціць крок з вядомай точкі контролю, не спрабоўваючы здагадвацца пра схованы стан.
Конфігурацыю трэба зберагчы за межамі коду прыкладнення. Файлы сераўнавання, хранільнікі секрэтных дадзеных і флагі функцыйяў должны знаходзіцца ў аднам месцы, якое аператары можаць пераглядаць, не чытачы ўсю структуру.
Неабходна праўаваць людзкую апраўду для тых канектацый, якія выкарыстоўваюць грошы або зміняюць даны ў працэсе віробніцтва. Праўаванне ў часе компілявання не ёсць падтверджэннем полныя адпаведнасці продукту выклікам.
Напісці короткі посібнік: як роўнаць клучы, як спрачыслаць чэргу, як анулюваць пярэдніе дадзеныя.
Дакументаваць як шлях успеху, так і шлях вяснавання. Перапрыбуткі, людзкія контрольныя пункты і обработка некорэктных дадзеных ўжо ёсць часткай продукту, а не чымсь, што дадаецца пазней.
Неабяжна людская празначэнне для тых элементаў, якія выдвайуць грошы або зменяюць даныя праработкі. Працаванне ў часе компілявання не абяжаецца пачынкамі бізнес-процэсаў.
Перш чым пераводзіць стэк, заморажуйце версіі, зафіксавайце «золаты» транскрыпты для крытычных ліній працы і паказвайце крокі для адвярнення змян. У спадзеленых срэдах неабходны ліміты частоты, перакананні ў правах на вікорыстоўванне і чысты власнік для ротацыі секрэтных даных. Валіце надзейнасць працы над крэатывнымі, адзінразовымі дамах.
Запіс для ba61be007942: не кладзіце ключы прадаўцоў у рэпазітарый, задаце верхнюю межу токенаў на кожную сесію і зберагаце транскрыпты праз адно з фіксатараў eval, каб пазнейшыя замены модэляў заставаліся парабяльнымі.