ข้ามไปที่เนื้อหา

Tools

ระบบ tool ช่วยให้เอเจนต์ทำ action นอกเหนือจากการสร้างข้อความได้ -- การคำนวณ, การค้นหา memory, การอ่านไฟล์ และการเรียกโมเดลย่อย Tool ใช้การออกแบบแบบ spec-driven พร้อม dispatch engine กลาง และรองรับรูปแบบ function-calling ของ OpenAI

สถาปัตยกรรม

Agent  -->  Engine (with tool defs)  -->  tool_calls response  -->  ToolExecutor  -->  Tool.execute()
  ^                                                                                          |
  |                                                                                          v
  +-------------------------------  ToolResult  <--------------------------------------------+

BaseTool ABC

Tool ทั้งหมด implement abstract base class BaseTool

from abc import ABC, abstractmethod
from openjarvis.tools._stubs import ToolSpec
from openjarvis.core.types import ToolResult

class BaseTool(ABC):
    tool_id: str

    @property
    @abstractmethod
    def spec(self) -> ToolSpec:
        """Return the tool specification."""

    @abstractmethod
    def execute(self, **params) -> ToolResult:
        """Execute the tool with the given parameters."""

    def to_openai_function(self) -> dict:
        """Convert to OpenAI function-calling format."""

Method to_openai_function() มีมาให้จาก base class และแปลง spec ของ tool เป็นรูปแบบที่ API ที่เข้ากันได้กับ OpenAI คาดหวัง:

{
  "type": "function",
  "function": {
    "name": "calculator",
    "description": "Evaluate a mathematical expression safely.",
    "parameters": {
      "type": "object",
      "properties": {
        "expression": {
          "type": "string",
          "description": "Math expression to evaluate"
        }
      },
      "required": ["expression"]
    }
  }
}

ToolSpec

Dataclass ToolSpec อธิบาย interface และลักษณะของ tool

ฟิลด์ ชนิด ค่าเริ่มต้น คำอธิบาย
name str -- Identifier ของ tool แบบไม่ซ้ำกัน
description str -- คำอธิบายที่มนุษย์อ่านได้ (ส่งให้โมเดล)
parameters dict[str, Any] {} JSON Schema สำหรับพารามิเตอร์ของ tool
category str "" หมวดหมู่ของ tool (เช่น math, memory, reasoning)
cost_estimate float 0.0 ต้นทุนโดยประมาณต่อการเรียกใช้
latency_estimate float 0.0 Latency โดยประมาณต่อการเรียกใช้
requires_confirmation bool False Tool ต้องการการยืนยันจากผู้ใช้หรือไม่
metadata dict[str, Any] {} Metadata เพิ่มเติม

ToolResult

Dataclass ToolResult เก็บผลลัพธ์ของการรัน tool

ฟิลด์ ชนิด ค่าเริ่มต้น คำอธิบาย
tool_name str -- ชื่อของ tool ที่ถูกเรียก
content str -- ผลลัพธ์ของ tool (ข้อความ)
success bool True การรันสำเร็จหรือไม่
usage dict[str, Any] {} การใช้ token (สำหรับ LLM tool)
cost_usd float 0.0 ต้นทุนจริงของการเรียกใช้
latency_seconds float 0.0 Latency ของการรันที่วัดได้
metadata dict[str, Any] {} Metadata เพิ่มเติม

ToolExecutor

ToolExecutor คือ dispatch engine กลางสำหรับการเรียก tool มันจัดการชุด instance ของ tool, parse argument แบบ JSON, วัด latency ของการรัน และ เผยแพร่ event บน event bus

from openjarvis.tools._stubs import ToolExecutor

executor = ToolExecutor(tools=[calculator, think_tool], bus=event_bus)

# Get OpenAI-format tool definitions
openai_tools = executor.get_openai_tools()

# Execute a tool call
from openjarvis.core.types import ToolCall
tc = ToolCall(id="call_1", name="calculator", arguments='{"expression": "2+2"}')
result = executor.execute(tc)
print(result.content)  # "4"

ขั้นตอนการรัน

  1. Parse argument: สตริง JSON arguments จาก ToolCall ถูก deserialize
  2. เผยแพร่ event เริ่มต้น: TOOL_CALL_START ถูกส่งบน event bus พร้อมชื่อ tool และ argument
  3. รัน: method execute() ของ tool ถูกเรียกพร้อมพารามิเตอร์ที่ parse แล้ว
  4. วัด latency: เวลาที่ใช้รันถูกบันทึกไว้ใน result.latency_seconds
  5. เผยแพร่ event จบ: TOOL_CALL_END ถูกส่งพร้อมสถานะความสำเร็จและ latency
  6. คืนผลลัพธ์: ToolResult ถูกคืนให้ผู้เรียก

หากชื่อ tool ไม่รู้จัก จะคืน ToolResult พร้อม success=False หากการ parse JSON ล้มเหลวหรือ tool สร้าง exception error จะถูกจับและคืนเป็น ToolResult ที่ล้มเหลว

Method

Method คืนค่า คำอธิบาย
execute(tool_call) ToolResult Parse argument, dispatch, วัดผล, ส่ง event
available_tools() list[ToolSpec] คืน spec สำหรับ tool ที่ลงทะเบียนไว้ทั้งหมด
get_openai_tools() list[dict] คืน tool ในรูปแบบ function ของ OpenAI

build_tool_descriptions()

ฟังก์ชัน build_tool_descriptions() เป็น แหล่งความจริงเดียว (single source of truth) สำหรับการสร้างคำอธิบาย tool แบบเสริมข้อมูล ที่ใช้ใน system prompt ของเอเจนต์ เอเจนต์แบบ text ทั้งหมด (NativeReActAgent, NativeOpenHandsAgent, RLMAgent, OrchestratorAgent ในโหมด structured) ใช้ฟังก์ชันนี้เพื่อสร้างส่วน tool ในรูปแบบ Markdown

พารามิเตอร์

พารามิเตอร์ ชนิด ค่าเริ่มต้น คำอธิบาย
tools list[BaseTool] -- รายการ instance ของ tool ที่จะอธิบาย
include_category bool True รวมบรรทัด Category: หรือไม่
include_cost bool False รวมบรรทัดประมาณต้นทุนและ latency หรือไม่

การใช้งาน

from openjarvis.tools._stubs import build_tool_descriptions
from openjarvis.tools.calculator import CalculatorTool
from openjarvis.tools.think import ThinkTool

tools = [CalculatorTool(), ThinkTool()]
desc = build_tool_descriptions(tools)
print(desc)
# ### calculator
# Evaluate a mathematical expression safely.
# Category: math
# Parameters:
#   - expression (string, required): Math expression to evaluate
#
# ### think
# Reasoning scratchpad ...

เอเจนต์ที่ใช้ Builder นี้

  • NativeReActAgent -- แทรกคำอธิบายเข้าไปใน system prompt ของ ReAct
  • NativeOpenHandsAgent -- แทรกคำอธิบายเข้าไปใน system prompt ของ CodeAct
  • RLMAgent -- เพิ่มหมวด ## Available Tools เข้าไปใน system prompt ของ REPL
  • OrchestratorAgent (โหมด structured) -- ส่ง tools= ให้ build_system_prompt() ซึ่งมอบหมายให้ builder นี้

สรุป Tool ในตัว

Tool ในตัวทั้งหมดลงทะเบียนผ่าน @ToolRegistry.register() และใช้งานได้ด้วย ชื่อ ทั้งจากเอเจนต์และ CLI

หมวดหมู่ Registry Key คำอธิบาย
Reasoning think พื้นที่ร่างความคิดต้นทุนศูนย์สำหรับ chain-of-thought
Math calculator ตัวประเมินนิพจน์คณิตศาสตร์อย่างปลอดภัย (ast-based)
Code code_interpreter รันโค้ด Python ใน subprocess แบบ sandboxed
Code code_interpreter_docker รันโค้ด Python ใน Docker container แบบใช้แล้วทิ้ง
Code repl Python REPL แบบต่อเนื่อง คงสถานะข้ามการเรียก
Search web_search ค้นหาเว็บ คืนสรุปผลลัพธ์
File I/O file_read อ่านเนื้อหาไฟล์พร้อมการตรวจสอบความปลอดภัย
HTTP http_request ส่งคำขอ HTTP พร้อมการป้องกัน SSRF
Memory retrieval ค้นหา memory backend หาบริบทที่เกี่ยวข้อง
Memory memory_store เก็บเนื้อหาลง memory backend
Memory memory_retrieve ดึงเนื้อหาที่เกี่ยวข้องจาก memory backend
Memory memory_search ค้นหาแบบ full-text ข้าม memory ที่เก็บไว้
Memory memory_index Index ไฟล์หรือไดเรกทอรีเข้า memory backend
Inference llm มอบหมายคำถามย่อยให้ inference engine
Channel channel_send ส่งข้อความผ่าน channel (Telegram, Discord ฯลฯ)
Channel channel_list แสดงรายการ messaging channel ที่มี
Channel channel_status ตรวจสอบสถานะการเชื่อมต่อของ messaging channel
Scheduler schedule_task ตั้งเวลางานสำหรับรันในอนาคตหรือแบบเกิดซ้ำ
Scheduler list_scheduled_tasks แสดงรายการงานที่ตั้งเวลาไว้ทั้งหมด
Scheduler pause_scheduled_task หยุดงานที่ตั้งเวลาไว้ที่กำลัง active ชั่วคราว
Scheduler resume_scheduled_task ดำเนินงานที่หยุดไว้ต่อ
Scheduler cancel_scheduled_task ยกเลิกงานที่ตั้งเวลาไว้อย่างถาวร
Integration mcp_adapter เชื่อมต่อไปยังเซิร์ฟเวอร์ MCP tool ภายนอก (ดู External MCP Servers)

รายละเอียด Tool ในตัว

Calculator

Registry key: calculator | หมวดหมู่: math

ประเมินนิพจน์ทางคณิตศาสตร์อย่างปลอดภัยด้วยโมดูล ast ของ Python ไม่มีการ รันโค้ดตามอำเภอใจ -- อนุญาตเฉพาะ operation ที่อยู่ใน whitelist เท่านั้น

พารามิเตอร์:

พารามิเตอร์ ชนิด จำเป็น คำอธิบาย
expression string ใช่ นิพจน์คณิตศาสตร์ (เช่น "2+3*4", "sqrt(16)")

Operation ที่รองรับ:

หมวดหมู่ Operation
เลขคณิต +, -, *, /, // (หารปัดลง), % (mod), ** (ยกกำลัง)
ฟังก์ชัน abs, round, min, max, sqrt, log, log10, log2
ตรีโกณมิติ sin, cos, tan
ปัดเศษ ceil, floor
ค่าคงที่ pi, e

ตัวอย่าง:

from openjarvis.tools.calculator import CalculatorTool

calc = CalculatorTool()
result = calc.execute(expression="sqrt(144) + 3**2")
print(result.content)   # "21.0"
print(result.success)   # True

Think

Registry key: think | หมวดหมู่: reasoning

พื้นที่ร่างความคิดต้นทุนศูนย์ input จะถูก echo กลับมาเป็น output ทำให้โมเดล "คิดออกเสียง" ระหว่างลูปการเรียกใช้ tool ได้ สิ่งนี้เปิดใช้งาน chain-of-thought reasoning ภายในเวิร์กโฟลว์ของเอเจนต์

พารามิเตอร์:

พารามิเตอร์ ชนิด จำเป็น คำอธิบาย
thought string ใช่ กระบวนการให้เหตุผลหรือความคิด

ตัวอย่าง:

from openjarvis.tools.think import ThinkTool

think = ThinkTool()
result = think.execute(thought="Let me break this problem into steps...")
print(result.content)   # "Let me break this problem into steps..."
print(result.success)   # True

ต้นทุนและ Latency

Tool Think มีต้นทุนเป็นศูนย์และ latency เกือบเป็นศูนย์ เหมาะสำหรับการให้เหตุผลแบบมีโครงสร้างโดยไม่ใช้ทรัพยากรเพิ่มเติม

Retrieval

Registry key: retrieval | หมวดหมู่: memory

ค้นหา memory backend หาบริบทที่เกี่ยวข้อง และคืนผลลัพธ์ที่จัดรูปแบบพร้อมการ ระบุแหล่งที่มา

พารามิเตอร์:

พารามิเตอร์ ชนิด จำเป็น คำอธิบาย
query string ใช่ คำค้นหา
top_k integer ไม่ จำนวนผลลัพธ์ (ค่าเริ่มต้น: 5)

พารามิเตอร์ของ Constructor:

พารามิเตอร์ ชนิด ค่าเริ่มต้น คำอธิบาย
backend MemoryBackend None Memory backend ที่จะค้นหา
top_k int 5 จำนวนผลลัพธ์เริ่มต้น

ตัวอย่าง:

from openjarvis.tools.retrieval import RetrievalTool
from openjarvis.memory.sqlite import SQLiteMemory

backend = SQLiteMemory(db_path="./memory.db")
retrieval = RetrievalTool(backend=backend)
result = retrieval.execute(query="machine learning")
print(result.content)   # Formatted context with source tags

LLM

Registry key: llm | หมวดหมู่: inference

มอบหมายคำถามย่อยให้ inference engine มีประโยชน์สำหรับการสรุป, คำถามย่อย หรือการสร้างผลลัพธ์แบบมีโครงสร้างภายในเวิร์กโฟลว์ของเอเจนต์

พารามิเตอร์:

พารามิเตอร์ ชนิด จำเป็น คำอธิบาย
prompt string ใช่ Prompt ที่จะส่งไปยังโมเดล
system string ไม่ System message เสริมสำหรับบริบท

พารามิเตอร์ของ Constructor:

พารามิเตอร์ ชนิด ค่าเริ่มต้น คำอธิบาย
engine InferenceEngine None Inference engine ที่จะใช้
model str "" Identifier ของโมเดล

ตัวอย่าง:

from openjarvis.tools.llm_tool import LLMTool

llm = LLMTool(engine=my_engine, model="qwen3:8b")
result = llm.execute(
    prompt="Summarize: AI is transforming industries...",
    system="You are a concise summarizer.",
)
print(result.content)

FileRead

Registry key: file_read | หมวดหมู่: filesystem

อ่านเนื้อหาไฟล์พร้อมการตรวจสอบความปลอดภัย รองรับการจำกัดไดเรกทอรี (เสริม), ขีดจำกัดขนาดไฟล์ (สูงสุด 1 MB) และการจำกัดจำนวนบรรทัด

พารามิเตอร์:

พารามิเตอร์ ชนิด จำเป็น คำอธิบาย
path string ใช่ Path ของไฟล์ที่จะอ่าน
max_lines integer ไม่ จำนวนบรรทัดสูงสุดที่จะคืน (ค่าเริ่มต้น: ทั้งหมด)

พารามิเตอร์ของ Constructor:

พารามิเตอร์ ชนิด ค่าเริ่มต้น คำอธิบาย
allowed_dirs list[str] None จำกัดการเข้าถึงไฟล์เฉพาะไดเรกทอรีเหล่านี้

คุณสมบัติด้านความปลอดภัย:

  • ตรวจสอบ path เทียบกับไดเรกทอรีที่อนุญาต (เมื่อตั้งค่าไว้)
  • ขนาดไฟล์สูงสุด: 1 MB
  • ต้องเป็น encoding UTF-8 (ปฏิเสธไฟล์ binary)
  • ตรวจสอบการมีอยู่และประเภทไฟล์

ตัวอย่าง:

from openjarvis.tools.file_read import FileReadTool

reader = FileReadTool(allowed_dirs=["/home/user/projects"])
result = reader.execute(path="/home/user/projects/README.md", max_lines=50)
print(result.content)
print(result.metadata)  # {"path": "/home/user/projects/README.md", "size_bytes": 1234}

WebSearch

Registry key: web_search | หมวดหมู่: search

ค้นหาเว็บและคืนสรุปผลลัพธ์ มีประโยชน์สำหรับคำถามที่ต้องการข้อมูลปัจจุบัน

พารามิเตอร์:

พารามิเตอร์ ชนิด จำเป็น คำอธิบาย
query string ใช่ สตริงคำค้นหา

CodeInterpreter

Registry key: code_interpreter | หมวดหมู่: code

รันโค้ด Python ใน sandbox และคืนผลลัพธ์ ใช้โดย NativeOpenHandsAgent สำหรับการรันแบบ CodeAct

พารามิเตอร์:

พารามิเตอร์ ชนิด จำเป็น คำอธิบาย
code string ใช่ โค้ด Python ที่จะรัน

Scheduler Tools

Scheduler tools เปิด operation ของ TaskScheduler เป็น tool ที่ค้นพบได้ผ่าน MCP ทำให้เอเจนต์สร้าง, จัดการ และตรวจสอบงานที่ตั้งเวลาไว้เชิงโปรแกรมได้ Scheduler tool ทั้งหมดอยู่ในหมวด scheduler และต้องมี instance ของ TaskScheduler ตั้งค่าไว้ในระบบ

Dependency ของ Scheduler

Scheduler tool ทำงานได้เฉพาะเมื่อมี TaskScheduler ต่อสายเข้ากับระบบ (ผ่าน SystemBuilder) หากไม่มี scheduler ตั้งค่าไว้ การเรียก scheduler tool ทั้งหมดจะคืนผลลัพธ์ success=False พร้อมข้อความอธิบายว่า scheduler ไม่พร้อมใช้งาน

schedule_task

Registry key: schedule_task | หมวดหมู่: scheduler

ตั้งเวลางานใหม่สำหรับรันในอนาคตหรือแบบเกิดซ้ำ

พารามิเตอร์:

พารามิเตอร์ ชนิด จำเป็น คำอธิบาย
prompt string ใช่ คำถามหรือ prompt ที่จะรันตามตารางเวลา
schedule_type string ใช่ หนึ่งใน "cron", "interval" หรือ "once"
schedule_value string ใช่ นิพจน์ cron, interval เป็นวินาที หรือ ISO 8601 datetime สำหรับรันครั้งเดียว
agent string ไม่ เอเจนต์ที่จะใช้รัน (ค่าเริ่มต้น: "simple")
tools string ไม่ ชื่อ tool สำหรับเอเจนต์ คั่นด้วยคอมมา (เช่น "calculator,think")

ตัวอย่างประเภทตารางเวลา:

schedule_type schedule_value ความหมาย
once "2026-03-01T09:00:00Z" รันครั้งเดียวที่เวลา UTC นั้น
interval "3600" รันทุก 3600 วินาที (1 ชั่วโมง)
cron "0 9 * * 1-5" รันที่ 09:00 UTC จันทร์–ศุกร์

คืนค่า: JSON ที่มี task_id, next_run (ISO 8601) และ status

ตัวอย่าง (ผ่านการเรียก tool ของเอเจนต์):

from openjarvis.scheduler.tools import ScheduleTaskTool
from openjarvis.scheduler.scheduler import TaskScheduler
from openjarvis.scheduler.store import SchedulerStore

store = SchedulerStore(db_path="~/.openjarvis/scheduler.db")
scheduler = TaskScheduler(store=store, system=jarvis_system)
scheduler.start()

tool = ScheduleTaskTool()
tool._scheduler = scheduler

result = tool.execute(
    prompt="Summarize the daily news",
    schedule_type="cron",
    schedule_value="0 8 * * *",
    agent="simple",
)
# result.content: '{"task_id": "a3f9b12c", "next_run": "2026-02-26T08:00:00+00:00", "status": "active"}'

list_scheduled_tasks

Registry key: list_scheduled_tasks | หมวดหมู่: scheduler

คืนงานที่ตั้งเวลาไว้ทั้งหมด กรองตามสถานะได้ตามต้องการ

พารามิเตอร์:

พารามิเตอร์ ชนิด จำเป็น คำอธิบาย
status string ไม่ กรองตามสถานะ: "active", "paused", "completed", "cancelled"

คืนค่า: JSON array ของ object งาน

pause_scheduled_task

Registry key: pause_scheduled_task | หมวดหมู่: scheduler

หยุดงานที่ตั้งเวลาไว้ที่กำลัง active ชั่วคราว งานยังคงอยู่และดำเนินต่อได้ ภายหลัง

พารามิเตอร์:

พารามิเตอร์ ชนิด จำเป็น คำอธิบาย
task_id string ใช่ ID ของงานที่จะหยุด

resume_scheduled_task

Registry key: resume_scheduled_task | หมวดหมู่: scheduler

ดำเนินงานที่หยุดไว้ต่อ เวลา next_run จะถูกคำนวณใหม่จากเวลาปัจจุบัน

พารามิเตอร์:

พารามิเตอร์ ชนิด จำเป็น คำอธิบาย
task_id string ใช่ ID ของงานที่จะดำเนินต่อ

cancel_scheduled_task

Registry key: cancel_scheduled_task | หมวดหมู่: scheduler

ยกเลิกงานอย่างถาวร (ตั้งสถานะเป็น "cancelled" และล้าง next_run) งานที่ ยกเลิกแล้วจะไม่รันอีก

พารามิเตอร์:

พารามิเตอร์ ชนิด จำเป็น คำอธิบาย
task_id string ใช่ ID ของงานที่จะยกเลิก

การลงทะเบียน Tool

Tool ลงทะเบียนผ่าน decorator @ToolRegistry.register() ทำให้ค้นพบได้ด้วยชื่อ ตอน runtime

from openjarvis.core.registry import ToolRegistry
from openjarvis.tools._stubs import BaseTool, ToolSpec
from openjarvis.core.types import ToolResult


@ToolRegistry.register("my_tool")
class MyTool(BaseTool):
    tool_id = "my_tool"

    @property
    def spec(self) -> ToolSpec:
        return ToolSpec(
            name="my_tool",
            description="A custom tool that does something useful.",
            parameters={
                "type": "object",
                "properties": {
                    "input": {
                        "type": "string",
                        "description": "The input to process.",
                    },
                },
                "required": ["input"],
            },
            category="custom",
        )

    def execute(self, **params) -> ToolResult:
        value = params.get("input", "")
        return ToolResult(
            tool_name="my_tool",
            content=f"Processed: {value}",
            success=True,
        )

หลังลงทะเบียนแล้ว ใช้ tool กับเอเจนต์ได้:

jarvis ask --agent orchestrator --tools my_tool "Process this data"

การใช้ Tool กับเอเจนต์

ผ่าน CLI

Tool ระบุเป็นรายการคั่นด้วยคอมมาผ่าน flag --tools ต้องเลือกเอเจนต์ (มักเป็น orchestrator):

# Single tool
jarvis ask --agent orchestrator --tools calculator "What is 15% of 340?"

# Multiple tools
jarvis ask --agent orchestrator --tools calculator,think "Solve: 2x + 5 = 13"

# All available tools (list them)
jarvis ask --agent orchestrator --tools calculator,think,retrieval,file_read "..."

ผ่าน Python SDK

Tool ส่งเป็นรายการสตริงชื่อ:

from openjarvis import Jarvis

j = Jarvis()

# Use calculator and think tools
result = j.ask_full(
    "What is the area of a circle with radius 7?",
    agent="orchestrator",
    tools=["calculator", "think"],
)

for tr in result["tool_results"]:
    print(f"  {tr['tool_name']}: {tr['content']} (success={tr['success']})")

j.close()

SDK จะสร้าง instance ของ tool พร้อม dependency ที่เหมาะสมให้โดยอัตโนมัติ ตัวอย่างเช่น tool retrieval จะได้รับ memory backend ที่ตั้งค่าไว้ และ tool llm จะได้รับ engine และโมเดลที่ใช้งานอยู่