بهترین راه فهمیدن عاملها، ساختن یکی است — و خبر خوب این است که عامل «حداقلی» با حدود صد خط کد ساخته میشود؛ نه فریمورک سنگین، نه زیرساخت خاص. در این آموزش یک عامل واقعی میسازیم: عاملِ «تحلیلگر فروش» که میتواند فایل CSV فروش را بخواند، سؤالهای آماری را با اجرای کد جواب دهد و گزارش بسازد. در پایان، همان چارچوب برای هر ابزار دیگری — دیتابیس، API داخلی، وب — قابل استفاده است.
طراحی: سه ابزار و یک حلقه
به عامل خودمان سه ابزار میدهیم: read_csv (خواندن فایل و دیدن ستونها)، run_python (اجرای کد پایتون روی داده و گرفتن خروجی) و write_report (ذخیرهی گزارش نهایی). عامل هدف را میگیرد، خودش برنامه میریزد، ابزارها را بهترتیب لازم صدا میزند، خروجی هر قدم را میبیند و تا تحویل گزارش جلو میرود. این همان حلقهی «فکر، اقدام، مشاهده» است که در مطلب عامل چگونه کار میکند تحلیلش کردیم.
قدم اول: اتصال به مدل
با API سازگار با OpenAI مایندبیس شروع میکنیم — همان کلاینت استاندارد، فقط آدرس و کلید متفاوت:
from openai import OpenAI
client = OpenAI(
base_url="https://api.mindbase.ir/v1",
api_key="YOUR_API_KEY",
)
MODEL = "glm-5.3"
قدم دوم: تعریف ابزارها
هر ابزار یک تابع پایتون واقعی است بهعلاوهی «توضیح رسمی» برای مدل. کیفیت همین توضیحها، کیفیت انتخاب ابزار توسط مدل را تعیین میکند — مبهمنویسی اینجا یعنی عاملِ گیج:
import pandas as pd
def read_csv(path):
df = pd.read_csv(path)
return f"ستونها: {list(df.columns)} | تعداد ردیف: {len(df)}\n{df.head(3).to_string()}"
def run_python(code):
import io, contextlib
buf = io.StringIO()
df = globals().get("_df")
try:
with contextlib.redirect_stdout(buf):
exec(code, {"df": df, "pd": pd})
out = buf.getvalue() or "(بدون خروجی)"
return out[:2000]
except Exception as e:
return f"خطا: {e}"
def write_report(text):
with open("report.md", "w", encoding="utf-8") as f:
f.write(text)
return "گزارش ذخیره شد: report.md"
TOOLS = [
{"type": "function", "function": {
"name": "read_csv",
"description": "فایل CSV را میخواند؛ ستونها، تعداد ردیف و سه ردیف اول را برمیگرداند. همیشه اول این را صدا بزن.",
"parameters": {"type": "object", "properties": {
"path": {"type": "string", "description": "مسیر فایل CSV"}}}}},
{"type": "function", "function": {
"name": "run_python",
"description": "کد پایتون اجرا میکند؛ دیتافریم با نام df در دسترس است. خروجی چاپشده برمیگردد. حداکثر ۲۰۰۰ کاراکتر چاپ کن.",
"parameters": {"type": "object", "properties": {
"code": {"type": "string", "description": "کد پایتون"}}}}},
{"type": "function", "function": {
"name": "write_report",
"description": "متن گزارش نهایی را در فایل ذخیره میکند. فقط وقتی تحلیل کامل است.",
"parameters": {"type": "object", "properties": {
"text": {"type": "string", "description": "متن کامل گزارش"}}}}},
]
قدم سوم: حلقهی اجرا
حالا قلب عامل: پیامها را به مدل میدهیم؛ اگر مدل «فراخوانی ابزار» خواست، اجرایش میکنیم و نتیجه را برمیگردانیم؛ این چرخه تا وقتی ادامه دارد که مدل پاسخ نهایی بدهد:
import json
def run_agent(goal, max_steps=15):
messages = [
{"role": "system", "content":
"تو تحلیلگر دادهی دقیقی. فقط از ابزارهای موجود استفاده کن. "
"قبل از نتیجهگیری همیشه اعداد را با run_python راستیآزمایی کن. "
"اگر داده برای پاسخ ناکافی است، صریح بگو چه چیزی کم است."},
{"role": "user", "content": goal},
]
dispatch = {"read_csv": read_csv, "run_python": run_python, "write_report": write_report}
for step in range(max_steps):
resp = client.chat.completions.create(
model=MODEL, messages=messages, tools=TOOLS)
msg = resp.choices[0].message
messages.append(msg)
if not msg.tool_calls:
return msg.content
for call in msg.tool_calls:
args = json.loads(call.function.arguments)
result = dispatch[call.function.name](**args)
messages.append({"role": "tool",
"tool_call_id": call.id,
"content": str(result)})
return "به سقف قدمها رسیدم؛ خلاصهی وضعیت: " + messages[-1]["content"]
print(run_agent("فایل sales.csv را تحلیل کن: مجموع فروش، پرفروشترین محصول، و روند سه ماه آخر؛ گزارش را ذخیره کن."))
چه اتفاقی در اجرا میافتد؟
عامل اول read_csv را صدا میزند تا شکل داده را ببیند؛ بعد با run_python محاسبات را یکییکی انجام و اعداد را چک میکند؛ اگر کدی خطا بدهد، پیام خطا را میبیند و کد را اصلاح میکند — همین حلقهی خطا/اصلاح است که عامل را از یک اسکریپت ثابت جدا میکند؛ در پایان گزارش را با write_report ذخیره میکند و برایتان خلاصه مینویسد. کل این مسیر شاید پنج تا ده فراخوانی ابزار باشد؛ هزینهاش با مدل مناسب چند صدم تومان است.
سه اصل ایمنی که از روز اول رعایت کنید
- سقف حلقه: پارامتر
max_stepsشوخی نیست؛ عامل بدون سقف میتواند حلقهی بیپایان بسازد و حساب را ببلعد. - حداقل اختیار: ابزار
run_pythonدر این مثال عمداً ساده و sandbox-شده است؛ در محیط واقعی، اجرای کد عامل را در محیط ایزوله و بدون دسترسی شبکه انجام دهید. - تأیید انسانی برای کارهای برگشتناپذیر: هر ابزاری که پول حرکت میدهد، ایمیل میفرستد یا چیزی حذف میکند، باید قبل از اجرا تأیید بگیرد — حتی وقتی همهچیز خوب کار میکند.
از اینجا به بعد
همین چارچوب قابل گسترش است: ابزارهای بیشتر (دیتابیس، وب، ایمیل)، حافظهی بینمأموریتی، و اتصال به ابزارهای استاندارد از طریق MCP بهجای نوشتن همهچیز از صفر. و برای کدنویسی، ابزارهای آماده مثل عاملهای کدنویس — موضوع مطلب بعدی این مجموعه — همین الگو را در مقیاس بزرگ پیاده کردهاند. کلید API را از پنل مایندبیس بگیرید و همین امروز عاملتان را اجرا کنید — با اعتبار هدیه، بدون هزینهی اولیه.