🤖 smolagents: agents that use your tools · smolagents: เอเจนต์ที่ใช้เครื่องมือของคุณ · smolagents:会用你工具的智能体

Three tutorials. Turn your own function into a tool an agent can choose. Meet the tools that come in the box. Then let one agent give orders to others. · สามบท เปลี่ยนฟังก์ชันของคุณให้เป็นเครื่องมือที่เอเจนต์เลือกใช้ได้ รู้จักเครื่องมือที่มีมาให้ แล้วให้เอเจนต์ตัวหนึ่งสั่งงานตัวอื่น · 三个教程:把你自己的函数变成智能体能挑的工具,认识内置的那些工具,再让一个智能体去指挥别的智能体。

🇬🇧 English

In the email lessons you wrote the tool loop by hand. Offer the menu. Read the choice. Run the function. Hand back the answer.

smolagents writes that loop for you. You bring the tools.

It also brings things you did not write. A step limit. A retry when the model answers badly. A final_answer tool, so the agent can say it is done. And agents that can hire other agents.

🇹🇭 ไทย

ในบทเรียนอีเมล คุณเขียนลูปเครื่องมือเอง เสนอเมนู อ่านคำตอบ เรียกฟังก์ชัน แล้วส่งผลกลับไป

smolagents เขียนลูปนั้นให้คุณ คุณแค่เอาเครื่องมือมา

มันยังให้สิ่งที่คุณไม่ได้เขียนด้วย ตัวจำกัดจำนวนรอบ การลองใหม่เมื่อโมเดลตอบไม่เข้าท่า เครื่องมือ final_answer ให้เอเจนต์บอกว่าเสร็จแล้ว และเอเจนต์ที่จ้างเอเจนต์อื่นได้

🇨🇳 中文

在邮件那几课里,工具循环是你自己写的:给出菜单、读取选择、运行函数、把结果交回去。

smolagents 替你写那个循环,你只要带上工具。

它还带来一些你没写的东西:步数上限、模型答得不好时的重试、一个让智能体宣布完成的 final_answer 工具,以及可以雇用其他智能体的智能体。

⌨️ TERMINAL · install it once

python -m pip install smolagents
ollama pull qwen2.5:14b   # a small model will not do, see below
AN AGENT NEEDS A MODEL THAT CAN FOLLOW ORDERS We ran the very same file twice, changing only the model. hermes3:8b never produced one usable tool call. It failed twenty times. It burned 26,733 input tokens, hit the step limit, and apologised. qwen2.5:14b answered correctly in two steps and 2,323 tokens. One model chats. The other works. เรารันไฟล์เดียวกันสองครั้ง เปลี่ยนแค่โมเดล hermes3:8b ไม่เคยสร้างการเรียกเครื่องมือที่ใช้ได้เลย ล้มเหลวยี่สิบครั้ง ใช้โทเคนขาเข้าไป 26,733 ชนเพดานจำนวนรอบ แล้วก็ขอโทษ ส่วน qwen2.5:14b ตอบถูกในสองรอบ ใช้ไป 2,323 โทเคน นี่คือความต่างระหว่างโมเดลที่คุยเก่ง กับโมเดลที่ทำงานได้ 我们把同一个文件跑了两次,只换了模型。hermes3:8b 一次可用的工具调用都没产生:失败二十次,烧掉 26,733 个输入 token,撞到步数上限,然后道歉。qwen2.5:14b 两步就答对了,只用 2,323 个 token。这就是会聊天的模型和能干活的模型之间的差别。
('Model', 'โมเดล', '模型')('Steps', 'จำนวนรอบ', '步数')('Input tokens', 'โทเคนขาเข้า', '输入 token')('Result', 'ผลลัพธ์', '结果')
hermes3:8b2026,733gave upยอมแพ้放弃了
qwen2.5:14b22,323correctถูกต้อง正确

1 🤖 Your first agent · เอเจนต์ตัวแรกของคุณ · 你的第一个智能体

🇬🇧 English

Here is a whole agent. The tool is a normal function with a decorator on top.

smolagents reads that function to build the menu. It takes the name, the docstring, and the type hints. So those are not decoration. They are the contract.

Then you call agent.run() and watch it think.

🇹🇭 ไทย

นี่คือเอเจนต์ทั้งตัว เครื่องมือก็คือฟังก์ชันธรรมดาที่มีเดคอเรเตอร์อยู่ข้างบน

smolagents อ่านฟังก์ชันนั้นเพื่อสร้างเมนู มันเอาชื่อ docstring และ type hint ไปใช้ สิ่งเหล่านี้จึงไม่ใช่ของประดับ แต่เป็นสัญญา

จากนั้นก็เรียก agent.run() แล้วดูมันคิด

🇨🇳 中文

这就是一整个智能体。工具就是一个普通函数,上面加个装饰器。

smolagents 读这个函数来生成菜单:它取名字、docstring 和类型注解。所以这些不是装饰,而是契约。

然后调用 agent.run(),看它思考。

📄 NEW FILE · agent1.py

"""agent1.py — one tool, one agent, and it decides when to use it."""
import os

from smolagents import OpenAIServerModel, ToolCallingAgent, tool

# Where the model runs. These defaults use Ollama on this computer.
LLM_URL = os.environ.get("LLM_URL", "http://localhost:11434/v1")
LLM_MODEL = os.environ.get("LLM_MODEL", "qwen2.5:14b")

# The OpenAI client always sends a key. Ollama accepts any word.
LLM_KEY = os.environ.get("LLM_KEY", "ollama")

INGREDIENTS = [
    "2 chicken thighs",
    "1 cup coconut milk",
    "3 kaffir lime leaves",
    "2 tablespoons red curry paste",
    "1 tablespoon fish sauce",
]


@tool
def check_pantry(item: str) -> str:
    """Check if one ingredient is in the kitchen right now.

    Args:
        item: the name of one ingredient, like "coconut milk"
    """
    for ingredient in INGREDIENTS:
        if item.lower() in ingredient.lower():
            return "yes, you have: " + ingredient
    return "no, there is no " + item + " in the kitchen"


if __name__ == "__main__":
    # Ollama answers in OpenAI's format, so this class can drive it.
    llm = OpenAIServerModel(
        model_id=LLM_MODEL,
        api_base=LLM_URL,
        api_key=LLM_KEY,
    )

    agent = ToolCallingAgent(tools=[check_pantry], model=llm)
    answer = agent.run("Do I have any coconut milk?")
    print("\nANSWER:", answer)
LineWhat it does · ทำอะไร · 做什么
from smolagents import OpenAIServerModel, ToolCallingAgent, toolThree names. A door to a model, an agent, and the decorator.สามชื่อ ประตูไปหาโมเดล ตัวเอเจนต์ และเดคอเรเตอร์三个名字:通向模型的门、智能体,和那个装饰器。
@toolTurns the function below into something an agent can choose.เปลี่ยนฟังก์ชันข้างล่างให้เป็นสิ่งที่เอเจนต์เลือกใช้ได้把下面的函数变成智能体可以挑选的东西。
def check_pantry(item: str) -> str:Both type hints are required. smolagents refuses the tool without them.ต้องมี type hint ทั้งสองจุด ถ้าไม่มี smolagents จะไม่รับเครื่องมือนี้两个类型注解都是必须的。没有它们,smolagents 不接受这个工具。
item: the name of one ingredientThe Args: block is required too. This line becomes the argument's description.บล็อก Args: ก็จำเป็นเช่นกัน บรรทัดนี้จะกลายเป็นคำอธิบายของอาร์กิวเมนต์Args: 段落同样必须。这一行会变成参数的说明。
api_base=LLM_URL,Ollama speaks OpenAI's language on /v1. No extra library needed.Ollama พูดภาษาของ OpenAI ได้ที่ /v1 ไม่ต้องลงไลบรารีเพิ่มOllama 在 /v1 上也说 OpenAI 的语言,不用装别的库。
agent.run(...)One line. The loop, the retries and the stopping are all inside it.บรรทัดเดียว ทั้งลูป การลองใหม่ และการหยุด อยู่ข้างในนั้นหมด一行。循环、重试和停止,全在里面。
THE DOCSTRING IS NOW ENFORCED, NOT ADVISED On the email page the docstring was good manners. Here it is checked. We tried each mistake on purpose. No Args: block gives DocstringParsingException. A missing argument hint gives TypeHintParsingException. A missing return hint gives Tool return type not found. Write them and the errors never appear. ในหน้าอีเมล docstring เป็นเรื่องมารยาท แต่ที่นี่มันถูกตรวจ เราลองผิดทีละแบบโดยตั้งใจ ถ้าไม่มีบล็อก Args: จะได้ DocstringParsingException ถ้าขาด type hint ของอาร์กิวเมนต์ จะได้ TypeHintParsingException ถ้าขาด type hint ของค่าที่คืน จะได้ Tool return type not found เขียนให้ครบแล้วจะไม่เจอเลย 在邮件那一页,docstring 是礼貌;在这里,它会被检查。我们故意逐个试错:没有 Args: 段会得到 DocstringParsingException;参数缺类型注解会得到 TypeHintParsingException;返回值缺注解会得到 Tool return type not found。都写齐,就一个都不会出现。
YOUR TURN
  1. Install smolagents, then create agent1.py and run it.
  2. Check: it calls check_pantry, then final_answer. Two steps.
  3. Delete the Args: block. Run it and read the exception.
  4. Ask it about saffron instead. Watch it report the truth.
  5. Point LLM_URL at another machine if yours is slow.
  1. ติดตั้ง smolagents แล้วสร้าง agent1.py จากนั้นรัน
  2. ตรวจ: มันเรียก check_pantry แล้วตามด้วย final_answer สองรอบ
  3. ลองลบบล็อก Args: ออก แล้วรัน อ่านข้อผิดพลาดที่ได้
  4. ลองถามหาหญ้าฝรั่นแทน แล้วดูว่ามันรายงานตามจริง
  5. ถ้าเครื่องคุณช้า ให้ชี้ LLM_URL ไปที่เครื่องอื่น
  1. 安装 smolagents,新建 agent1.py 并运行。
  2. 检查:它先调用 check_pantry,再调用 final_answer。两步。
  3. 把 Args: 段删掉,运行一次,读那个异常。
  4. 改成问藏红花,看它如实回答。
  5. 如果你的机器慢,把 LLM_URL 指向另一台。

2 🧰 The tool ecosystem · ระบบนิเวศของเครื่องมือ · 工具生态

🇬🇧 English

A tool can come from three places. One agent can hold all three.

Write a function, for something small. Write a class, when the tool needs to remember something. Or take one that already exists.

This agent has one of each. The job needs all three.

🇹🇭 ไทย

เครื่องมือมาได้จากสามที่ และเอเจนต์ตัวเดียวถือได้ครบทั้งสามแบบ

เขียนเป็นฟังก์ชัน สำหรับงานเล็ก ๆ เขียนเป็นคลาส เมื่อเครื่องมือต้องจำอะไรบางอย่าง หรือหยิบตัวที่มีอยู่แล้วมาใช้

เอเจนต์ตัวนี้มีครบอย่างละหนึ่ง และมีงานที่ต้องใช้ทั้งสามอย่าง

🇨🇳 中文

工具可以来自三个地方,而一个智能体可以同时拿着这三种。

小事情就写成函数;工具需要记住东西时就写成类;或者直接用现成的。

这个智能体三种各有一个,任务也正好三个都要用上。

📄 NEW FILE · agent2.py

"""agent2.py — three kinds of tool, in one agent."""
import os
from pathlib import Path

from smolagents import (
    OpenAIServerModel,
    PythonInterpreterTool,
    Tool,
    ToolCallingAgent,
    tool,
)

LLM_URL = os.environ.get("LLM_URL", "http://localhost:11434/v1")
LLM_MODEL = os.environ.get("LLM_MODEL", "qwen2.5:14b")
LLM_KEY = os.environ.get("LLM_KEY", "ollama")

SHOP = Path("shopping.txt")

INGREDIENTS = [
    "2 chicken thighs",
    "1 cup coconut milk",
    "1 tablespoon fish sauce",
]


# 1. The quick kind: a function with a decorator.
@tool
def add_to_shopping_list(item: str) -> str:
    """Add one thing to the shopping list.

    Args:
        item: the name of one ingredient
    """
    with SHOP.open("a", encoding="utf-8") as shopping:
        shopping.write(item + "\n")
    return "added " + item


# 2. The fuller kind: a class, for a tool that needs to remember something.
class PantryTool(Tool):
    """A tool that keeps its own data, instead of reading a global."""

    name = "check_pantry"
    description = "Check if one ingredient is in the kitchen right now."
    inputs = {"item": {"type": "string", "description": "One ingredient name."}}
    output_type = "string"

    def __init__(self, ingredients):
        super().__init__()
        self.ingredients = ingredients

    def forward(self, item: str) -> str:
        for ingredient in self.ingredients:
            if item.lower() in ingredient.lower():
                return "yes, you have: " + ingredient
        return "no, there is no " + item


if __name__ == "__main__":
    llm = OpenAIServerModel(
        model_id=LLM_MODEL,
        api_base=LLM_URL,
        api_key=LLM_KEY,
    )

    agent = ToolCallingAgent(
        tools=[
            PantryTool(INGREDIENTS),    # your class
            add_to_shopping_list,       # your function
            PythonInterpreterTool(),    # one that came with smolagents
        ],
        model=llm,
    )
    answer = agent.run(
        "Check if I have green curry paste. If I do not, add it to the shopping "
        "list. Then work out how many grams are in 2.5 cups of coconut milk, "
        "using 240 grams per cup."
    )
    print("\nANSWER:", answer)
LineWhat it does · ทำอะไร · 做什么
@tool def add_to_shopping_list(item: str) -> str:The quick kind. Good for anything that fits in one function.แบบเร็ว เหมาะกับอะไรก็ตามที่เขียนจบในฟังก์ชันเดียว快的那种。凡是一个函数能装下的都合适。
class PantryTool(Tool):The fuller kind. Use it when the tool needs data of its own.แบบเต็ม ใช้เมื่อเครื่องมือต้องมีข้อมูลของตัวเอง完整的那种。工具需要自己的数据时用它。
name = ... description = ... inputs = ...The class writes by hand what the decorator worked out for you.คลาสเขียนสิ่งที่เดคอเรเตอร์คิดให้คุณ ออกมาด้วยมือ装饰器帮你推导出的东西,类里要手写出来。
def forward(self, item: str) -> str:The work goes in forward, not in __call__.งานอยู่ใน forward ไม่ใช่ __call__活儿写在 forward 里,不是 __call__。
PythonInterpreterTool()One that came with smolagents. It lets the model do arithmetic properly.ตัวที่มากับ smolagents มันให้โมเดลคำนวณเลขได้อย่างถูกต้องsmolagents 自带的一个。它让模型能正经地算数。
PantryTool(INGREDIENTS)The class is built with its data. The function reads a global instead.คลาสถูกสร้างพร้อมข้อมูลของมัน ส่วนฟังก์ชันไปอ่านตัวแปรส่วนกลางแทน类是带着数据被创建的;函数则是去读一个全局变量。

🇬🇧 English

These come with smolagents. Import and use, no writing needed.

🇹🇭 ไทย

ตัวเหล่านี้มากับ smolagents แค่ import แล้วใช้ ไม่ต้องเขียนเอง

🇨🇳 中文

下面这些是 smolagents 自带的。import 进来就能用,不用自己写。

('Tool', 'เครื่องมือ', '工具')('What it does', 'ทำอะไร', '做什么')('Needs', 'ต้องมี', '需要')
PythonInterpreterToolRuns Python the model wroteรันโค้ด Python ที่โมเดลเขียน运行模型写的 Pythonnothingไม่ต้องมีอะไร什么都不用
FinalAnswerToolLets the agent stopให้เอเจนต์หยุดได้让智能体停下来added for youถูกเพิ่มให้อัตโนมัติ自动加上
WebSearchToolSearches the webค้นเว็บ搜索网页the internetอินเทอร์เน็ต网络
VisitWebpageToolReads one page as textอ่านหน้าเว็บหนึ่งหน้าเป็นข้อความ把一个网页读成文字the internetอินเทอร์เน็ต网络
WikipediaSearchToolLooks something upค้นข้อมูลอ้างอิง查资料the internetอินเทอร์เน็ต网络
GoogleSearchToolSearch, through a paid keyค้นหา ผ่านคีย์แบบเสียเงิน搜索,需付费密钥a SerpAPI keyคีย์ SerpAPISerpAPI 密钥
SpeechToTextToolTurns speech into wordsเปลี่ยนเสียงพูดเป็นข้อความ把语音变成文字a downloadต้องดาวน์โหลด要下载
UserInputToolStops and asks youหยุดแล้วถามคุณ停下来问你a personต้องมีคน要有人
THE PYTHON TOOL RUNS CODE THE MODEL WROTE PythonInterpreterTool is how an agent does maths without inventing an answer. Ours worked out 2.5 cups at 240 grams and got 600, which is right. But it is still code you did not read. A model wrote it. It runs on your machine. smolagents limits what it can import. Do not widen that list to make an error go away. PythonInterpreterTool คือวิธีที่เอเจนต์คำนวณเลขได้โดยไม่ต้องมั่วคำตอบ ของเราคำนวณ 2.5 ถ้วย ถ้วยละ 240 กรัม ได้ 600 ซึ่งถูกต้อง แต่มันก็ยังเป็นโค้ดที่คุณไม่ได้อ่าน เขียนโดยโมเดล และรันบนเครื่องของคุณ smolagents จำกัดว่ามัน import อะไรได้บ้าง อย่าไปขยายรายการนั้นเพียงเพื่อให้ error หายไป PythonInterpreterTool 让智能体算数时不用瞎编答案。我们这次算 2.5 杯、每杯 240 克,得到 600,是对的。但那仍然是你没读过的代码,由模型写的,跑在你的机器上。smolagents 限制了它能 import 什么。别为了让报错消失就去放宽那个名单。
A TOOL THAT APPENDS WILL APPEND TWICE One run called add_to_shopping_list three times with the same item. The file came out holding green curry paste, three times over. The agent was not broken. The tool was. It appends whatever it is handed, every time it is asked. An agent retries. Make the tool safe to call twice. Let the tool read the file first, and skip what is there. มีรันหนึ่งเรียก add_to_shopping_list สามครั้งด้วยของชิ้นเดียวกัน ไฟล์จึงมีพริกแกงเขียวหวานสามบรรทัด เอเจนต์ไม่ได้พัง แต่เครื่องมือต่างหากที่พัง มันต่อท้ายทุกอย่างที่ได้รับ ทุกครั้งที่ถูกเรียก เอเจนต์ลองใหม่เสมอ เครื่องมือที่เรียกซ้ำได้อย่างปลอดภัยจึงมีค่ากว่าพรอมป์ตที่ขอร้องไม่ให้เรียกซ้ำ ให้เครื่องมืออ่านไฟล์ก่อน แล้วข้ามสิ่งที่มีอยู่แล้ว 有一次运行把 add_to_shopping_list 用同一个东西调了三遍,文件里就出现了三行绿咖喱酱。坏的不是智能体,是工具。它每次被调用,就把拿到的东西原样追加一次。智能体是会重试的。一个可以安全调用两次的工具,胜过一句请求它别重试的提示词。让工具先读一下文件,已经有的就跳过。
YOUR TURN
  1. Create agent2.py and run it.
  2. Check: the maths comes out at 600 grams.
  3. Ours used all three tools once, and wrote shopping.txt. Another run did the maths and forgot the shopping.
  4. Give PantryTool a different kitchen string and rerun.
  5. Swap PythonInterpreterTool out and ask the maths question again.
  1. สร้าง agent2.py แล้วรัน
  2. ตรวจ: ผลคำนวณต้องได้ 600 กรัม
  3. ของเราใช้เครื่องมือครบทั้งสามครั้งหนึ่ง และเขียนไฟล์ shopping.txt อีกรันหนึ่งคิดเลขแล้วลืมเรื่องซื้อของ
  4. ลองใส่ข้อความครัวอีกชุดให้ PantryTool แล้วรันใหม่
  5. ลองเอา PythonInterpreterTool ออก แล้วถามโจทย์เลขเดิมอีกครั้ง
  1. 新建 agent2.py 并运行。
  2. 检查:算出来是 600 克。
  3. 我们有一次三种工具都用了,也写了 shopping.txt。另一次只算了数,把买东西忘了。
  4. 给 PantryTool 换一份厨房清单再跑一次。
  5. 把 PythonInterpreterTool 去掉,再问一次那道算术题。

3 👥 Agents that manage agents · เอเจนต์ที่จัดการเอเจนต์ · 管理智能体的智能体

🇬🇧 English

An agent can hold other agents, the way it holds tools.

Give an agent a name and a description. Another agent can then call it. Pass it in managed_agents. That is all multi-agent means.

Notice who holds what. The worker only answers questions. The manager keeps the tool that changes a file.

🇹🇭 ไทย

เอเจนต์ถือเอเจนต์ตัวอื่นได้ เหมือนที่มันถือเครื่องมือ

ให้ name และ description กับเอเจนต์ตัวหนึ่ง มันก็กลายเป็นสิ่งที่เอเจนต์อีกตัวเรียกใช้ได้ แล้วส่งมันเข้าไปใน managed_agents multi-agent มีความหมายแค่นั้น

สังเกตว่าใครถืออะไร ลูกน้องแค่ตอบคำถาม ส่วนผู้จัดการเก็บเครื่องมือที่เปลี่ยนไฟล์ไว้กับตัว

🇨🇳 中文

一个智能体可以持有别的智能体,就像持有工具一样。

给一个智能体加上 name 和 description,它就成了别的智能体能调用的东西,再把它放进 managed_agents。所谓多智能体,就这么多。

注意谁拿着什么:工人只回答问题,会改文件的工具留在经理手里。

📄 NEW FILE · agent3.py

"""agent3.py — a manager with one worker, and one clear reason to have it."""
import os
from pathlib import Path

from smolagents import OpenAIServerModel, ToolCallingAgent, tool

LLM_URL = os.environ.get("LLM_URL", "http://localhost:11434/v1")
LLM_MODEL = os.environ.get("LLM_MODEL", "qwen2.5:14b")
LLM_KEY = os.environ.get("LLM_KEY", "ollama")

SHOP = Path("shopping.txt")

INGREDIENTS = [
    "2 chicken thighs",
    "1 cup coconut milk",
    "3 kaffir lime leaves",
    "2 tablespoons red curry paste",
    "1 tablespoon fish sauce",
]


@tool
def check_pantry(item: str) -> str:
    """Check if one ingredient is in the kitchen right now.

    Args:
        item: the name of one ingredient, like "coconut milk"
    """
    for ingredient in INGREDIENTS:
        if item.lower() in ingredient.lower():
            return "yes, you have: " + ingredient
    return "no, there is no " + item + " in the kitchen"


@tool
def recipe_needs(dish: str) -> str:
    """List the ingredients a dish needs.

    Args:
        dish: the name of a dish, like "green curry"
    """
    book = {
        "green curry": "green curry paste, coconut milk, chicken",
        "red curry": "red curry paste, coconut milk, chicken",
    }
    return book.get(dish.lower(), "that dish is not in the book")


@tool
def add_to_shopping_list(item: str) -> str:
    """Add one missing ingredient to the shopping list.

    Args:
        item: the name of one ingredient
    """
    with SHOP.open("a", encoding="utf-8") as shopping:
        shopping.write(item + "\n")
    return "added " + item


def main():
    """One worker, and a manager that keeps the writing to itself."""
    # One model, shared by both agents. Ollama answers in OpenAI's format.
    llm = OpenAIServerModel(
        model_id=LLM_MODEL,
        api_base=LLM_URL,
        api_key=LLM_KEY,
    )

    # Only this agent holds check_pantry. The manager has to ask it.
    kitchen = ToolCallingAgent(
        tools=[check_pantry],
        model=llm,
        name="kitchen_agent",
        description=(
            "Answers whether the kitchen has an ingredient. "
            "Ask about one ingredient at a time."
        ),
        max_steps=4,
    )

    # The manager keeps the writing tool, so only it changes the file.
    manager = ToolCallingAgent(
        tools=[recipe_needs, add_to_shopping_list],
        model=llm,
        managed_agents=[kitchen],
        max_steps=12,
    )

    answer = manager.run(
        "I want to cook green curry. Call recipe_needs once. "
        "Then ask kitchen_agent about each ingredient, one at a time. "
        "Call add_to_shopping_list yourself for each one the kitchen lacks."
    )

    print("\nANSWER:", answer)
    # The file is the truth. An agent saying it added something is not.
    written = SHOP.read_text(encoding="utf-8").split() if SHOP.exists() else []
    print("shopping.txt holds:", written)


if __name__ == "__main__":
    main()
LineWhat it does · ทำอะไร · 做什么
name="kitchen_agent",Without a name it cannot be called. This is the name the manager types.ถ้าไม่มีชื่อ ก็เรียกมันไม่ได้ นี่คือชื่อที่ผู้จัดการจะพิมพ์没有名字就没法被调用。这就是经理会写的那个名字。
description=(The manager reads this to decide when to ask. It is a job advert.ผู้จัดการอ่านบรรทัดนี้เพื่อตัดสินใจว่าจะถามเมื่อไหร่ มันคือประกาศรับสมัครงาน经理读这句来决定什么时候找它。这是一则招聘启事。
max_steps=4,A worker that cannot stop is a bill. Give every agent a ceiling.ลูกน้องที่หยุดไม่เป็นคือค่าใช้จ่าย ให้เพดานกับเอเจนต์ทุกตัว停不下来的工人就是账单。给每个智能体一个上限。
managed_agents=[kitchen],The whole of multi-agent, in one argument.ทั้งหมดของ multi-agent อยู่ในอาร์กิวเมนต์เดียว多智能体的全部,就在这一个参数里。
tools=[recipe_needs, add_to_shopping_list],The manager keeps the writing. The next box says why that matters.ผู้จัดการเก็บงานเขียนไฟล์ไว้เอง กล่องถัดไปจะบอกว่าทำไมถึงสำคัญ写文件留给经理自己。下一个框会说为什么这很重要。
written = SHOP.read_text(...)Read the file at the end. Believe that, and not the summary.อ่านไฟล์ตอนจบ เชื่อไฟล์ ไม่ใช่เชื่อบทสรุป最后读一下文件。信它,别信总结。
WE BUILT THIS WRONG FIRST, TWICE Our first try gave the shopping list its own agent. It reported Successfully added green curry paste. The file did not exist. It had called no tool at all. Our second try produced a Thai word where the syntax belongs. It put two calls in one blob, and the parser refused it. Fifteen steps, 54,573 input tokens, nothing written. The fix was to stop wrapping one tool in an agent. Delegate the question. Keep the action. ครั้งแรกเราให้รายการซื้อของไปอยู่กับเอเจนต์อีกตัว มันรายงานว่า Successfully added green curry paste แต่ไฟล์ไม่มีอยู่จริง มันไม่ได้เรียกเครื่องมือเลยสักครั้ง ครั้งที่สอง โมเดลเขียนคำภาษาไทยลงไปตรงที่ควรเป็นรูปแบบการเรียกเครื่องมือ และรวมสองคำสั่งไว้ในก้อนเดียว ตัวแปลงจึงปฏิเสธ สิบห้ารอบ โทเคนขาเข้า 54,573 และไม่มีอะไรถูกเขียน ทางแก้คือเลิกเอาเครื่องมือชิ้นเดียวไปห่อเป็นเอเจนต์ มอบหมายคำถาม แต่เก็บการลงมือไว้เอง 我们第一次把购物清单交给了另一个智能体。它报告 Successfully added green curry paste,而文件根本不存在——它一个工具都没调用。第二次,模型在该写工具调用格式的地方写了一个泰文词,还把两个调用塞进一个块里,解析器直接拒收:十五步,54,573 个输入 token,什么都没写。修法是别再拿一个工具去包一个智能体。把问题交出去,把动作留下来。
IT CAN BE RIGHT IN WORDS AND WRONG IN DEEDS The working version delegated three times and wrote the file. Its answer was correct: You have everything except the green curry paste. But the file held green curry paste and coconut milk. The kitchen has coconut milk. It summarised correctly and acted wrongly, in one run. A later run got the file exactly right, and stopped mid-sentence instead. Two runs, two different shapes of wrong. That is why the last line of the program reads the file. เวอร์ชันที่ใช้งานได้มอบหมายงานสามครั้ง และเขียนไฟล์สำเร็จ คำตอบก็ถูก You have everything except the green curry paste แต่ในไฟล์มีทั้งพริกแกงเขียวหวานและกะทิ ทั้งที่ในครัวมีกะทิอยู่แล้ว มันสรุปถูก แต่ลงมือผิด ในการรันครั้งเดียวกัน อีกรันหนึ่งเขียนไฟล์ถูกเป๊ะ แต่หยุดกลางประโยคแทน สองรัน ผิดคนละแบบ นี่คือเหตุผลที่บรรทัดสุดท้ายของโปรแกรมต้องอ่านไฟล์ 能用的那一版委派了三次,也确实写了文件。它的回答是对的:You have everything except the green curry paste。但文件里有绿咖喱酱和椰奶,而厨房里是有椰奶的。同一次运行里,它总结对了,却做错了。后来一次文件写得完全正确,却在句子中间停住。两次运行,两种不同的错。这就是程序最后一行要去读文件的原因。
YOUR TURN
  1. Create agent3.py and run it.
  2. Check: it calls kitchen_agent, then writes the file itself.
  3. Open shopping.txt. Did it add anything the kitchen already has?
  4. Ours added coconut milk by mistake. Yours may differ.
  5. Give the worker add_to_shopping_list instead. Watch it get worse.
  6. Count the model calls. One task, two agents, many turns.
  1. สร้าง agent3.py แล้วรัน
  2. ตรวจ: มันเรียก kitchen_agent แล้วเขียนไฟล์ด้วยตัวเอง
  3. เปิด shopping.txt ดู มันเพิ่มของที่ครัวมีอยู่แล้วหรือเปล่า
  4. ของเราเผลอเพิ่มกะทิเข้าไป ของคุณอาจต่างออกไป
  5. ลองให้ลูกน้องถือ add_to_shopping_list แทน แล้วดูว่าแย่ลงอย่างไร
  6. ลองนับจำนวนครั้งที่เรียกโมเดล งานเดียว สองเอเจนต์ หลายรอบ
  1. 新建 agent3.py 并运行。
  2. 检查:它调用 kitchen_agent,然后自己写文件。
  3. 打开 shopping.txt,它有没有加上厨房本来就有的东西?
  4. 我们这次误加了椰奶。你的可能不同。
  5. 把 add_to_shopping_list 改给工人拿,看它怎么变得更糟。
  6. 数数调用了几次模型。一个任务,两个智能体,很多轮。

Fifteen lines, your own address, and an app password. That is the whole trick. · สิบห้าบรรทัด อีเมลของคุณเอง และ app password หนึ่งอัน เคล็ดลับมีแค่นี้ · 十五行代码、你自己的邮箱地址,加一个应用专用密码。诀窍就这些。

All five files on this page were run on 21 September 2026, on smolagents 1.26.0 against a local Ollama model reached through its OpenAI endpoint. agent1 answered in two steps. agent2 used a class tool, a function tool and the built-in python interpreter in one run, worked out 600 grams, and wrote shopping.txt. agent3 delegated three times and wrote the file itself. The failures on this page are real runs too, including the agent that reported success while calling no tool, and the run that summarised correctly while adding an ingredient the kitchen already had.