自訂工具

進階工具設計模式和最佳實踐。

學習為 Lens OS Agent 設計強健且高效的工具執行器的進階模式。

工具設計模式

1. 搜尋 + 顯示模式

搜尋資料,然後產生顯示頁面:

搜尋和顯示模式
// Tool 1: Search
product_search: {
  description: "Search products",
  // ...
  execute: async (params) => {
    const results = await searchProducts(params.query);
    return {
      success: true,
      result: { results, message: `Found ${results.length} products` },
    };
  },
},

// Tool 2: Generate page
generate_page: {
  description: "Generate page from search results",
  whenToUse: "IMPORTANT: Must complete product_search first before calling this",
  schema: {
    title: { type: "string", required: true },
    productIds: { type: "array", required: true },
  },
  execute: async (params) => {
    const pageUrl = await generatePage(params);
    return {
      success: true,
      result: { pageUrl, message: `Page generated: ${pageUrl}` },
    };
  },
},

2. 讀取 + 寫入模式

查詢然後更新模式:

讀取和寫入模式
user_orders: {
  description: "Query or update user orders",
  schema: {
    action: {
      type: "string",
      required: true,
      description: '"get" to query | "update" to modify | "cancel" to cancel',
    },
    orderId: { type: "string", required: false },
    updates: { type: "object", required: false },
  },
  execute: async (params, context) => {
    switch (params.action) {
      case "get":
        return await getOrders(context?.userId);
      case "update":
        return await updateOrder(params.orderId, params.updates);
      case "cancel":
        return await cancelOrder(params.orderId);
    }
  },
},

錯誤處理

優雅降級

後援處理
execute: async (params) => {
  try {
    const result = await primaryMethod(params);
    return { success: true, result };
  } catch (primaryError) {
    console.error("Primary method failed:", primaryError);

    try {
      // Fallback
      const fallback = await fallbackMethod(params);
      return {
        success: true,
        result: {
          ...fallback,
          message: "使用後援方法取得",
        },
      };
    } catch (fallbackError) {
      return {
        success: false,
        error: "服務暫時無法使用,請稍後再試",
      };
    }
  }
},

使用者友善的錯誤訊息

驗證和錯誤
execute: async (params) => {
  if (!params.query?.trim()) {
    return { success: false, error: "請輸入搜尋關鍵字" };
  }

  if (params.query.length > 100) {
    return { success: false, error: "關鍵字過長,請縮短" };
  }

  // ...
},

Context 使用

存取使用者資訊

使用 Context
execute: async (params, context) => {
  const userId = context?.userId;

  if (!userId) {
    return { success: false, error: "請先登入" };
  }

  // Use userId to query user-specific data
  const orders = await getOrdersByUser(userId);
  return { success: true, result: orders };
},

效能提示

快取

實作快取
const cache = new Map<string, { data: any; timestamp: number }>();
const CACHE_TTL = 5 * 60 * 1000; // 5 分鐘

execute: async (params) => {
  const cacheKey = JSON.stringify(params);
  const cached = cache.get(cacheKey);

  if (cached && Date.now() - cached.timestamp < CACHE_TTL) {
    return { success: true, result: cached.data };
  }

  const result = await expensiveOperation(params);
  cache.set(cacheKey, { data: result, timestamp: Date.now() });

  return { success: true, result };
},

平行執行

平行查詢
execute: async (params) => {
  // Execute multiple queries in parallel
  const [products, categories, reviews] = await Promise.all([
    searchProducts(params.query),
    getCategories(),
    getTopReviews(params.query),
  ]);

  return {
    success: true,
    result: { products, categories, reviews },
  };
},

測試工具

本地測試

test-tools.ts
// 直接引入你定義的 tools 物件
const tools = { /* 你的工具定義 */ };

async function test() {

  // Test product_search
  const result = await tools.product_search.execute(
    { query: "TypeScript", topK: 5 },
    { userId: "test-user", sessionId: "test-session" }
  );

  console.log("Result:", JSON.stringify(result, null, 2));
}

test();
執行測試
bun test-tools.ts

Tip

在部署前務必在本地測試你的工具,以確保它們能夠優雅地處理邊界情況和錯誤。