Погледајте видео лекцију: Осигуравање AI агената криптографским рачунима
(Видео лекције и минијатура ће бити додати од стране Microsoft тима за садржај након спајања, у складу са узорком лекција 14 / 15.)
У овој лекцији ћемо покрити:
Након завршетка ове лекције, знаћете како да:
Замислите да сте распоредили AI агента за Contoso Travel. Агент чита захтеве корисника, позива API за летове да потражи опције и резервише места уместо корисника. Прошлог квартала, агент је обрадио 50.000 резервација.
Данас долази ревизор. Поставља једноставно питање: “Покажи ми шта је твој агент радио.”
Предате му своје лог фајлове. Ревизор их погледа и поставља теже питање: “Како знам да ови записи нису измењени?”
Ово је проблем ревизног трага. Већина распоређивања агената данас се ослања на:
Ниједан од ових не може одговорити на питање ревизора без да се ревизор ослони на некога (вас, провајдера облака, добavljaча базе података). За интерну употребу, тај ниво поверења је често прихватљив. За регулисане задатке (финансије, здравство, све под оквиром EU AI закона), није.
Криптографски рачуни решавају овај проблем тако што свака радња агента може бити независно проверена. Ревизор не мора да вам верује. Потребан му је само ваш јавни кључ и сам рачун.
Рачун је JSON објекат који записује шта је агент урадио, са потписом дигиталног потписа.
flowchart LR
A[Агенс позива алат] --> B[Направи податке рачуна]
B --> C[Канонизуј JSON RFC 8785]
C --> E[Ed25519 потпиши канонске бајтове]
E --> F[Рачун са потписом]
F --> G[Ревизор проверa офлајн]
G --> H{Да ли је потпис важећи?}
H -- yes --> I[Доказ заштите од промена]
H -- no --> J[Рачун одбијен]
Минимални рачун изгледа овако:
{
"type": "agent.tool_call.v1",
"agent_id": "contoso-travel-bot",
"tool_name": "lookup_flights",
"tool_args_hash": "sha256:a3f9c1...",
"result_hash": "sha256:7b2e1d...",
"policy_id": "contoso-travel-policy-v3",
"timestamp": "2026-04-25T14:30:00Z",
"sequence": 47,
"previous_receipt_hash": "sha256:9d4e6a...",
"signature": {
"alg": "EdDSA",
"sig": "c5af83...",
"public_key": "8f3b2c..."
}
}
Три особине обављају посао:
Потпис. Рачун потписује агентова капија користећи Ed25519 приватни кључ. Било ко са одговарајућим јавним кључем може проћи проверу потписа офлајн. Манипулација било којим пољем онемогућава потпис.
Канонско кодирање. Пре потписивања рачун се серијализује користећи JSON Canonicalization Scheme (JCS, RFC 8785). Ово осигурава да две имплементације које производе исту логичку поруку уједначено производе идентичан батч излаз. Без канонализације, различити JSON серијализатори би производили различите потписе за исти садржај.
Хеш ланац. Поље previous_receipt_hash повезује сваки рачун са претходним. Уклањање или мењање редоследа рачуна прекида сваки рачун који долази након њега. Манипулација постаје видљива на нивоу ланца чак и ако се појединачни потписи заобиђу.
Заједно, ове особине дају три гаранције:
Не треба вам посебна библиотека за производњу рачуна. Криптографске примитиве су широко доступне и логика је само неколико десетина линија Python кода.
Практични задаци у code_samples/18-signed-receipts.ipynb објашњавају цео ток. Сажетак:
import json
import hashlib
import base64
from nacl import signing
from jcs import canonicalize # RFC 8785 канонски JSON
def b64url_nopad(data: bytes) -> str:
return base64.urlsafe_b64encode(data).decode("ascii").rstrip("=")
def sha256_canonical(obj) -> str:
"""SHA-256 of a Python object's JCS-canonical JSON form."""
return f"sha256:{hashlib.sha256(canonicalize(obj)).hexdigest()}"
# Генериши или учитај кључ за потписивање (у продукцији, чувај у „кеј валту“)
signing_key = signing.SigningKey.generate()
verify_key = signing_key.verify_key
# Креирај садржај рачуна (још без потписа)
tool_args = {"origin": "SYD", "destination": "LAX"}
tool_result = [{"flight": "QF11", "price": 1850, "stops": 0}]
payload = {
"type": "agent.tool_call.v1",
"agent_id": "contoso-travel-bot",
"tool_name": "lookup_flights",
"tool_args_hash": sha256_canonical(tool_args),
"result_hash": sha256_canonical(tool_result),
"policy_id": "contoso-travel-policy-v3",
"timestamp": "2026-04-25T14:30:00Z",
"sequence": 0,
"previous_receipt_hash": None,
}
# Канонизуј и директно потпиши JCS бајтове. PureEdDSA унутрашње хеширање.
canonical_bytes = canonicalize(payload)
signature_bytes = signing_key.sign(canonical_bytes).signature
# Додати структурисани објекат потписа.
receipt = {
**payload,
"signature": {
"alg": "EdDSA",
"sig": b64url_nopad(signature_bytes),
"public_key": b64url_nopad(bytes(verify_key)),
},
}
То је цела цевоводна линија за потписивање. Задаци у свесци воде вас кроз сваки корак.
Верификација је обрнути поступак:
import base64
import hashlib
from nacl import signing
from nacl.exceptions import BadSignatureError
from jcs import canonicalize
def b64url_decode(s: str) -> bytes:
padding = "=" * ((4 - len(s) % 4) % 4)
return base64.urlsafe_b64decode(s + padding)
def verify_receipt(receipt: dict) -> bool:
# Потпис је структурирани објекат: {"alg", "sig", "public_key"}.
sig_obj = receipt.get("signature")
if not sig_obj or sig_obj.get("alg") != "EdDSA":
return False
# Реконструишите податке који су заправо потписани (све осим потписа).
payload = {k: v for k, v in receipt.items() if k != "signature"}
canonical_bytes = canonicalize(payload)
try:
verify_key = signing.VerifyKey(b64url_decode(sig_obj["public_key"]))
verify_key.verify(canonical_bytes, b64url_decode(sig_obj["sig"]))
return True
except BadSignatureError:
return False
Ова функција узима рачун и враћа True ако је потпис валидан, у супротном False. Без позива на мрежу, без зависности од сервиса, без потребе за поверљивом трећом страном.
Да видите детекцију манипулације у акцији, свеска води кроз:
tool_args_hash.Ово је практичан доказ да су рачуни видљиви за манипулацију: свака измена, ма колико мала, срушaва потпис.
Један потписани рачун штити једну радњу. Ланац рачуна штити низ радњи.
flowchart LR
R0[Рачун 0<br/>генеза] --> R1[Рачун 1]
R1 --> R2[Рачун 2]
R2 --> R3[Рачун 3]
R1 -. previous_receipt_hash .-> R0
R2 -. previous_receipt_hash .-> R1
R3 -. previous_receipt_hash .-> R2
Сваки рачун бележи хеш претходног. Да би уклонио рачун 2 неприметно, нападач би морао или:
previous_receipt_hash у рачуну 3 (што квари потпис рачуна 3), ИЛИАко је приватни кључ у хардверском сигурносном модулу и ако објављујете јавни кључ уз сваки рачун, ниједан напад није могућ без откривања.
Свеска показује:
previous_receipt_hash сваког рачуна одговара стварном хешу претходног.Ово је начин да направите ревизни траг који спољни ревизор може проверити без поверења у вас.
Ово је најважнији део ове лекције. Рачуни су моћни, али је њихова моћ ограничена.
Рачуни доказују три ствари:
Рачуни НЕ доказују:
policy_id стварно процењена, или да би допустила ову радњу уколико је проверена. Рачун бележи оно што је тврдњено, не оно што је спроведено.Ова граница је важна из два разлога:
Честа грешка је претпоставка да “ако имамо рачуне” значи “ако смо вођени.” Не значи. Рачуни су основа. Управљање је систем који градите на тој основи.
Тачка 3 горе заслужује свој одељак: рачун каже “овај кључ је потписао овај садржај,” никад “човек је одобрио ову радњу.” За радње високе ризичности (повраћаји, брисања, трансфери новца) оквири управљања све више захтевају управо ту изостављену изјаву, која се може произвести истим примитивима које сте већ изградили у овој лекцији.
Следећа свеска code_samples/human-authorization-receipts.ipynb додаје другу врсту рачуна, human.approval.v1, у истом обиму као рачуни из ове лекције (типизовани подаци потписани Ed25519 преко њихових канонских JCS бајтова, са signature објектом ван потписаних бајтова). Именовани одобравач потписује целу канонску радњу и њен дигест пре извршења; рачун радње агента носи исти дигест радње и parent_approval_ref, receipt_hash одобрења, исту конвенцију као и previous_receipt_hash у ланцу који сте изградили горе. Једна verify_chain функција проверава оба артефакта под одвојеним регистрима фиксираних кључева (кључеви одобравача против кључева агента), тако да имамо делимичан код али не и заједничку ауторитет.
Особина која се добија, прецизно изражена: човек је одобрио ову тачну радњу и агент је извршио управо ту одобрeну радњу. Фиксири у свесци који одбијају су оно што ову особину чини стварном а не само тврдњом:
Свако одбијање има јасан разлог, тако да ревизор који чита одбијање може уочити да ли је власт постала застарела или је извршена радња промењена. Правило које свеска учи: потписано одобрење само по себи није ауторитет. Ауторитет постоји само ако оба рачуна и даље везују исту канонску радњу у време извршења. Рачун људске сагласности је образовни састав дефинисан овом лекцијом, а не тип рачуна дефинисан у draft-farley-acta-signed-receipts.
Python код у овој лекцији је намерно минималан да бисте могли прочитати сваки ред и тачно разумети шта се дешава. У производњи, имате две опције:
Радите директно на криптографским примитивима. 50 редова које сте видели горе је довољно за многе случајеве. PyNaCl (Ed25519) и пакет jcs (канонски JSON) су добро одржаване и ревидиране библиотеке.
Користите библиотеку за рачуне у производњи. Неколико open-source пројеката имплементира исти образац са додатним карактеристикама (ротирање кључева, групна провера, дистрибуција JWK сета, интеграција са политичким механизмима):
draft-farley-acta-signed-receipts, ревизија 02). Образац за ову лекцију је равни образовни рачун који се разликује од јединственог коверта {payload, signature} из драфта и није представљен као конформна имплементација. Драфт објављује заједнички скуп за тестирање усаглашености (agent-governance-testvectors) за имплементације које циљају његов wire формaт.protect-mcp (npm) и @veritasacta/verify (npm) пружају Node-имплементацију за потписивање рачуна и офлајн верификацију, намењену за омотавање било ког MCP сервера са трајним ревизним трагом, укључујући и ток који чека потпис у којем паузирана радња емитује одобрење везано за дигест радње (WebAuthn подршка у десктоп току), исти образац одобрења као у свесци за људску ауторизацију изнад.pip install nobulex) пружа исти Ed25519 + JCS образац потписивања у Python-у са интеграцијама за LangChain и CrewAI, укључујући објављене векторе за међусобну валидацију и мапирање за усаглашеност доприносио OWASP PR #2210.Одлука између писања сопственог решења и коришћења библиотеке слична је одлуци између писања сопствене JWT библиотеке и коришћења тестиране: обе опције су разумне; библиотека штеди време и смањује ограничења ревизије; прилагођено решење тражи да разумете сваки примитив. Ова лекција учи вашу властиту имплементацију како бисте стекли основу за било који избор.
Тестирајте своје разумевање пре него што пређете на практичну вежбу.
1. Рачун је потписан приватним Ed25519 кључем агента. Ревизор има само јавни кључ. Може ли ревизор проверити рачун офлајн?
2. Нападач мења поље policy_id у рачуну да би тврдио да га је регулисала блажa политика. Потпис је био над оригиналним садржајем. Шта се дешава током провере?
3. Зашто примка садржи tool_args_hash и result_hash уместо необрађених аргумената и резултата?
4. Поље previous_receipt_hash повезује сваку примку са својим претходником. Ако нападач тихо избрише једну примку из средине ланца, шта постаје неважеће?
5. Примка се успешно верификује. Да ли то доказује да је агентова акција била исправна, звучна или у складу са политиком?
Отворите code_samples/18-signed-receipts.ipynb и завршите сва четири одељка:
Изазов 1: проширите шему примке додатним пољем по свом избору (на пример, ID захтева за праћење), ажурирајте канонску логику потписивања да га укључује и потврдите да примка и даље пролази кроз верификацију. Затим измените поље након потписивања и уверите се да верификација не успева. Ово вам помаже да разумете како сваки бајт канонског кодирања доприноси потпису.
Изазов 2: Хеширајте две примке SHA-256 заједно (конкатенирајте њихове канонске бајтове у детерминисаном редоследу) и уградите резултујући дигест као ново поље на трећој примци пре потписивања. Проверите да све три примке и даље пролазе верификацију. Управо сте направили доказ укључености у једном кораку: било коју ко поседује трећу примку може доказати да су прве две постојале у тренутку потписа, без потребе да открива њихов садржај. Ово је образац који се користи за примке селективног откривања у великом обиму (Merkle обавезе, RFC 6962).
Криптографске примке пружају AI агентима ревизорски траг који је:
Нису замена за проверу улаза, примену политика или инфраструктуру идентитета. Они су основа за те слојеве. Када распоређујете агенте у регулисане радне оптерећења, мултиорганизационе токове рада или окружења у којима се не може претпоставити да ће вас будући ревизор веровати, примке су начин да ревизорски траг буде поуздан.
Најважнија порука: примке доказују ко је шта рекао и када. Не доказују да је оно што је речено тачно или исправно. Држите ту разлику чврсто. То је разлика између искреног система порекла и обмањујућег.
Када будете спремни да пређете из ове лекције у распоређивање агената са потписаним примкама у реалном окружењу:
https://your-org.example.com/.well-known/agent-keys.json.Придружите се Microsoft Foundry Discord да упознате друге ученике, похађате канцеларијске сате и добијете одговоре на ваша питања о AI агенатима.
Ова лекција покрива потписивање једне примке и ланце са хешевима. Исте примитиве сачињавају неколико напреднијих образаца које можете срести како ваша управљачка позиција сазрева:
authorization_*) и после извршења (result_*) са независним потписима; корисно када одлуку о овлашћењу и посматрани резултат доносе различити актери или у различито време. Ово додатно се саставља на образац примки из ове лекције.result_hash. Стварни садржаји често су богатији од резултата једног позива алата: разлози пре одлуке (предвиђање модела, разматране опције, докази и њихова потпуна скала, ризични положај, ланац одговорности, исход контролне капије) могу бити унутар садржаја, запечаћени једном примком. Ово чува формат примке минималним, а шеме садржаја еволуирају по доменима.signature.alg може носити ML-DSA-65 (стандард НИСТ-а за постквантни потпис) кад буде потребно миграцију. Планирајте период транзиције када ће примке бити двоструко потписане.Изјава о одрицању одговорности: Овај документ је преведен коришћењем услуге за аутоматски превод Co-op Translator. Иако тежимо тачности, имајте у виду да аутоматски преводи могу садржати грешке или нетачности. Оригинални документ на његовом изворном језику треба сматрати ауторитативним извором. За критичне информације препоручује се професионални људски превод. Нисмо одговорни за било каква неспоразума или погрешна тумачења која произилазе из коришћења овог превода.