تازه رسیدی؟ اول مسیر قبلی رو در دو دقیقه مرور کن
لازم نیست همهٔ مقالهها رو همین الان بخونی. هر کارت یک یادآوری یکجملهای داره؛ اگر مفهومش برات جدیده، کلیک کن. اگر قبلاً خوندی، از روش رد شو.
اصلاً ایجنت یعنی چی؟
چتبات فقط جواب میده؛ ایجنت میتونه برای رسیدن به هدف، مرحله و ابزار انتخاب کنه.
مرور خیلی سادهٔ کل مسیر ← LANGCHAINمدل چطور ابزار صدا میزنه؟
LangChain مدل، پرامپت و ابزارها رو به یک حلقهٔ قابلاستفاده وصل میکنه.
راهنمای LangChain ← LANGGRAPHکار چطور مکث میکنه و ادامه میده؟
LangGraph مسیر و state رو نگه میداره تا وسط کار توقف، بررسی و ادامه ممکن باشه.
راهنمای LangGraph ← REAL EXAMPLEیک نمونهٔ پیشرفته چه شکلیه؟
The Eye نشان میده یک ایجنت آنچین چطور پیشنهاد میده ولی اختیار نهایی بیرونش میمونه.
نمونهٔ کاملتر را ببین ← CLOUDایجنت آمادهٔ ابری
اگر هنوز هیچ تجربهای نداری، اول یک کار ساده رو به یک ایجنت آماده بده.
اولین تسک ابری ← ON YOUR COMPUTERایجنت روی کامپیوتر خودت
همان کار را با مدل روی دستگاهت امتحان کن تا فرق هزینه، سرعت و حریم خصوصی را حس کنی.
اولین تجربهٔ آفلاین ←قبلیها قطعات لگو رو معرفی کردن. اینجا برای اولین بار همشون رو روی میز میچینیم و یک ماشین کوچیکِ قابلاجرا میسازیم.
آخر کار دقیقاً چی داری؟
درخواست رو میخونه و یک عملیات ساختاریافته پیشنهاد میده.
مبلغ یا مقصد خارج از policy قبل از تأیید آدم بلاک میشه.
LangGraph state رو نگه میداره تا تو approve یا reject کنی.
agent به seed یا private key دسترسی پیدا نمیکنه.
بدون دستگاه، رابط یک Ledger App رو روی کامپیوتر میبینی.
مطمئن میشی درخواست خطرناک واقعاً متوقف میشه.
نقشهٔ پروژه قبل از کدنویسی
تأیید آدم نباید اجازه بده policy سخت دور زده بشه. اگر سقف مبلغ ۰٫۰۱ است، حتی آدم هم از داخل همین flow نمیتونه درخواست ۱ واحدی را «همینطوری» رد کند و جلو ببرد؛ باید policy جداگانه تغییر کند.
قبل از شروع چی نصب کنیم؟
Python 3.11 یا جدیدتر
کد پروژه با Python اجرا میشه. بعد از نصب، در ترمینال python3 --version رو بزن.
Ollama برای مدل رایگان روی کامپیوتر
مسیر اصلی مقاله رایگان و local است. اگر سیستم ضعیفه، میتونی بعداً adapter مدل رو با یک API ابری عوض کنی.
Docker فقط برای بخش Speculos
برای ساخت خود agent لازم نیست. وقتی رسیدیم به emulator، نصبش میکنیم.
اول پروژه رو با node ساختگیِ پیشنهاد اجرا کن یا از API ابری استفاده کن. بخش policy، human review و signer boundary به مدل بزرگ احتیاج ندارن؛ مهمترین یادگیری مقاله همین قسمتهاست.
قدم یک: پوشه و محیط پروژه
mkdir first-guarded-agent cd first-guarded-agent python3 -m venv .venv source .venv/bin/activate # Windows: .venv\Scripts\activate pip install langgraph langchain langchain-ollama pydantic python-dotenv
بعد یک مدل کوچک در Ollama آماده کن. اسم مدل رو میتونی براساس سختافزارت عوض کنی:
ollama run qwen3:4b
قدم دو: مدل فقط یک Proposal میسازه
اولین قانون معماری: مدل هیچ تابعی برای «ارسال» یا «امضا» نمیبینه. خروجیاش فقط یک فرم پیشنهاده.
import os
from typing import TypedDict
from pydantic import BaseModel, Field
from langchain_ollama import ChatOllama
from langgraph.graph import StateGraph, START, END
from langgraph.checkpoint.memory import InMemorySaver
from langgraph.types import interrupt, Command
class TransferProposal(BaseModel):
asset: str = Field(description="demo asset symbol")
amount: float = Field(gt=0)
destination: str
reason: str
class AgentState(TypedDict, total=False):
request: str
proposal: dict
policy: dict
approved: bool
result: str
model = ChatOllama(
model=os.getenv("OLLAMA_MODEL", "qwen3:4b"),
temperature=0,
)
proposal_model = model.with_structured_output(TransferProposal)
def propose(state: AgentState):
proposal = proposal_model.invoke(
"Create a DEMO transfer proposal only. "
"Never claim that anything was executed. Request: " + state["request"]
)
return {"proposal": proposal.model_dump()}بهجای اینکه مدل یک پاراگراف شلخته بده، مجبورش میکنیم چهار خانهٔ مشخص رو پر کنه: دارایی، مبلغ، مقصد و دلیل.
قدم سه: policy قبل از آدم تصمیم میگیره
تو این تمرین فقط دو مقصد آزمایشی مجازن و سقف مبلغ هم ۰٫۰۱ است. اگر درخواست با یکی از این قانونها جور درنیاد، مسیر همونجا تموم میشه.
MAX_AMOUNT = 0.01
ALLOWLIST = {"demo-alice", "demo-bob"}
def policy_check(state: AgentState):
p = state["proposal"]
reasons = []
if p["amount"] > MAX_AMOUNT:
reasons.append("amount is above the hard limit")
if p["destination"] not in ALLOWLIST:
reasons.append("destination is not allowlisted")
return {
"policy": {
"allowed": not reasons,
"reasons": reasons,
}
}
def after_policy(state: AgentState):
return "review" if state["policy"]["allowed"] else "blocked"
def blocked(state: AgentState):
return {"result": "REJECTED BY POLICY: " + ", ".join(state["policy"]["reasons"])}قدم چهار: LangGraph وسط کار مکث میکنه
interrupt() پیشنهاد رو بیرون میفرسته و state رو نگه میداره. همون thread_id باعث میشه ادامهٔ کار دقیقاً به اجرای قبلی برگرده.
def human_review(state: AgentState):
decision = interrupt({
"question": "Do you approve this demo proposal?",
"proposal": state["proposal"],
"allowed_decisions": ["approve", "reject"],
})
return {"approved": decision == "approve"}
def signer_boundary(state: AgentState):
if not state["policy"]["allowed"]:
return {"result": "REJECTED: policy cannot be bypassed"}
if not state.get("approved"):
return {"result": "REJECTED BY HUMAN"}
# No seed, private key or transaction broadcast exists in this tutorial.
# This adapter is where demo / Speculos / real hardware would be selected.
mode = os.getenv("SIGNER_MODE", "demo")
return {"result": f"APPROVED; handed to {mode} signer boundary (no broadcast)"}قدم پنج: گراف رو به هم وصل کن
builder = StateGraph(AgentState)
builder.add_node("propose", propose)
builder.add_node("policy", policy_check)
builder.add_node("blocked", blocked)
builder.add_node("review", human_review)
builder.add_node("signer", signer_boundary)
builder.add_edge(START, "propose")
builder.add_edge("propose", "policy")
builder.add_conditional_edges(
"policy",
after_policy,
{"review": "review", "blocked": "blocked"},
)
builder.add_edge("blocked", END)
builder.add_edge("review", "signer")
builder.add_edge("signer", END)
graph = builder.compile(checkpointer=InMemorySaver())
config = {"configurable": {"thread_id": "demo-1"}}
first = graph.invoke({
"request": "Send 0.005 DEMO to demo-alice for lunch"
}, config=config)
if "__interrupt__" in first:
print(first["__interrupt__"])
answer = input("Type approve or reject: ").strip().lower()
final = graph.invoke(Command(resume=answer), config=config)
print(final["result"])
else:
print(first["result"])فایل رو ذخیره کن و اجرا بگیر:
SIGNER_MODE=demo python agent.py
قدم شش: Speculos دقیقاً کجای داستانه؟
Speculos پروژهٔ رسمی Ledger برای اجرای Ledger Apps روی کامپیوتره. یعنی میتونی UI و رفتار یک اپ سازگار رو بدون دستگاه ببینی و تست کنی.
Speculos طبق مستندات خودش Secure Element، جداسازی سیستمعامل و تمام رفتارهای دستگاه واقعی رو تضمین نمیکنه. پس برای آموزش و تست خوبه؛ برای نگهداری دارایی یا ادعای امنیت سختافزاری نه.
برای شروع رسمی، مخزن و Quickstart خود Ledger رو دنبال کن. مسیر پایه معمولاً این شکله:
git clone https://github.com/LedgerHQ/speculos.git cd speculos python3 -m venv .venv source .venv/bin/activate pip install . ./speculos.py apps/boil.elf # then open http://127.0.0.1:5000
Speculos خودش «یک کیف پول آماده» نیست؛ مثل یک کنسول بازیه که برای اجرا به بازی نیاز داره. فایل .elf همان Ledger Appیه که داخل emulator اجرا میشه.
در پروژهٔ ما، تابع signer_boundary جای اتصال adapter است. فعلاً فقط اعلام میکنه پیشنهاد به مرز رسیده. برای اتصال واقعی باید:
| مرحله | در نسخهٔ آموزشی | در نسخهٔ واقعیتر |
|---|---|---|
| پیشنهاد agent | JSON آزمایشی | تراکنش decodeشده و قابلنمایش |
| Policy | سقف مبلغ + allowlist | session scope، expiry، nonce و budget |
| Human review | approve/reject در ترمینال | نمایش واضح مقصد، مبلغ و معنی عملیات |
| Speculos | تمرین UI یک Ledger App | APDU adapter سازگار با همان app |
| Hardware | نداریم | کلید داخل دستگاه و تأیید روی secure screen |
| Broadcast | عمداً خاموش | بعد از امضای معتبر و کنترل replay |
چهار تستی که حتماً باید انجام بدی
باید به signer boundary برسه، ولی در این آموزش هیچ تراکنشی broadcast نمیشه.
باید قبل از human review رد بشه؛ آدم نباید مسیر bypass داشته باشه.
حتی اگر متن درخواست قانعکننده بود، policy باید مستقل ردش کنه.
باید با نتیجهٔ REJECTED BY HUMAN تمام بشه و signer صدا نخوره.
تابع propose رو موقتاً طوری تغییر بده که همیشه مبلغ ۹۹۹ بسازه. اگر معماری درست باشه، policy بدون توجه به مدل یا پرامپت، درخواست رو متوقف میکنه.
چیزی که ساختیم «کیف پول» نیست؛ یک مرز درست برای agent است
مدل پیشنهاد میده. LangGraph مسیر و توقف رو نگه میداره. policy اجازهٔ عبور رو محدود میکنه. آدم تصمیم میگیره. signer بیرون از runtime ایجنت میمونه. Speculos هم کمک میکنه تجربهٔ یک Ledger App رو تمرین کنی—نه اینکه امنیت سختافزار واقعی رو جعل کنی.
منابع رسمی و بهروز
LangGraph Interrupts — pause, checkpoint and resume LangChain Human-in-the-loop middleware LedgerHQ Speculos — official repository, setup and limitations Speculos Quickstart — Linux, macOS and Windows Ollama Quickstart — local model setupدیسکلیمر: این پروژه برای یادگیری معماری و تست با دادهٔ ساختگیه. seed phrase، private key، دارایی واقعی یا تراکنش واقعی واردش نکن. Speculos جای Secure Element یا دستگاه واقعی نیست. بخشهایی از آمادهسازی و تصویرسازی این راهنما با کمک ایجنت هوش مصنوعی انجام شده.