メインコンテンツまでスキップ

AI functions

会話中に呼び出せるカスタム backend logic で AI agent を拡張します。

なぜ AI Functions を使うのか

AI agent は、単に質問に答えるだけでは不十分です。注文状況を調べたり、database を更新したり、domain-specific な計算を実行したり、external API を呼び出したりする必要があります。model は、それらを単独で行う方法を知りません。

AI functions がなければ、agent は model がすでに知っていることに制限されます。AI functions があれば、会話に応じて agent は 언제でも backend code を呼び出せます。

Backend code
// Backend: define the function
@aiFunction<{ shipName: string }>(
'指定された船に乗っている海賊の一覧を返します。ユーザーが船の乗組員について尋ねたときに呼び出してください。',
[{ name: 'shipName', description: '船の名前', type: 'string', required: true }],
)
async listPiratesOnShip(params: { shipName: string }): Promise<string> {
// Your custom logic: query a database, call an API, run a calculation, etc.
const { shipName } = params;
const crew = await this.lookupCrew(shipName);
return crew.join(', ');
}
Client code
// Frontend: pass the function to the agent and ask a question
const response = await squid
.ai()
.agent('pirate-agent')
.ask('Who is on the Black Pearl?', {
functions: ['listPiratesOnShip'],
});

Functions は、リクエストごとに渡す代わりに、Agent Studio または setAgentOptionInPath を使って agent に恒久的に追加することもできます。

agent は function の description を読み、いつ呼び出すべきかを判断し、その結果を response に組み込みます。

Overview

AI functions は、@aiFunction で decorate された Squid Service 内の method です。これらを AI agent にアタッチすると、agent は function の description と user prompt に基づいて会話中にそれらを呼び出せるようになります。

AI functions を使うタイミング

Use CaseRecommendation
Agent が custom server-side logic を呼び出す必要があるAI function
Agent が接続された database に query または write する必要があるdatabase connector を使用するか、custom query logic には AI function を使用
Agent が接続された service(例: CRM、calendar、API)にアクセスする必要があるconnected integration を使用
Agent が MCP 経由で external tools に接続する必要があるMCP を使用
Agent が upload された document を検索する必要があるKnowledge Bases を使用

仕組み

  1. SquidService を継承した class 内で method を @aiFunction で decorate します
  2. function を名前で agent にアタッチします(SDK または console の Agent Studio 経由)
  3. user が message を送ると、agent は prompt に対して function の description を評価します
  4. agent が function が relevant だと判断すると、AI が生成した parameter 値で function を呼び出します
  5. function は backend 上で実行され、string の result を返します
  6. agent はその result を response に組み込みます

Quick Start

Prerequisites

  • squid init で初期化された Squid backend project
  • NPM からインストールされた @squidcloud/backend package
  • 作成済みの AI agent

Step 1: AI function を作成する

Squid Service に @aiFunction decorator を付けた method を追加します。

Backend code
import { SquidService, aiFunction } from '@squidcloud/backend';

export class AiService extends SquidService {
@aiFunction<{ city: string }>('指定された都市の現在の天気を返します。ユーザーが天気について尋ねたときに呼び出してください。', [{ name: 'city', description: '都市名', type: 'string', required: true }])
async getWeather(params: { city: string }): Promise<string> {
const { city } = params;
// Replace with your actual weather API call
return `The weather in ${city} is 72°F and sunny.`;
}
}

Step 2: backend を deploy する

local development では、次を実行します。

squid start

cloud に deploy する方法については、deploying your backend を参照してください。

deploy 後、この function は console の Agent Studio の Abilities に表示されます。

Step 3: function を使って agent を呼び出す

Client code
const response = await squid
.ai()
.agent('my-agent')
.ask("What's the weather in Tokyo?", {
functions: ['getWeather'],
});
console.log(response);

agent は user が天気について尋ねたことを認識し、{ city: "Tokyo" } を使って getWeather を呼び出し、その結果を response に含めます。

setAgentOptionInPath を使って function を agent に恒久的に追加することもできるため、毎回のリクエストで渡す必要はありません。

Client code
await squid.ai().agent('my-agent').setAgentOptionInPath('functions', ['getWeather']);

// Now the agent always has access to getWeather
const response = await squid.ai().agent('my-agent').ask("What's the weather in Tokyo?");

Core Concepts

@aiFunction decorator

この decorator は、必須の引数を 2 つ受け取ります。

  1. description (string): agent にこの function をいつ呼び出すべきかを伝えます。曖昧な label ではなく、明確な instruction として書いてください。
  2. params (array): function を呼び出すときに agent が渡すべき parameter を定義します。
Backend code
@aiFunction<{ productId: string; quantity: number }>(
'商品の在庫数量を更新します。ユーザーが inventory を調整したいときに呼び出してください。',
[
{ name: 'productId', description: '商品 ID', type: 'string', required: true },
{ name: 'quantity', description: '加算する量(減算する場合は負の値)', type: 'number', required: true },
],
)
async updateStock(params: { productId: string; quantity: number }): Promise<string> {
// ...
}

または、decorator に単一の options object を渡すこともできます。

Backend code
@aiFunction({
description: '商品の在庫数量を更新します。',
params: [
{ name: 'productId', description: '商品 ID', type: 'string', required: true },
{ name: 'quantity', description: '加算する量(減算する場合は負の値)', type: 'number', required: true },
],
})
async updateStock(params: { productId: string; quantity: number }): Promise<string> {
// ...
}

Parameter definitions

params array 内の各 parameter では、以下の field をサポートしています。

FieldTypeRequiredDescription
namestringYesparameter 名。function の params object 内の key と一致する必要があります
descriptionstringYesagent にどの値を渡すべきかを伝えます
typestringYesdata type: 'string', 'number', 'boolean' など
requiredbooleanYesagent がこの値を必ず渡す必要があるかどうか
enumany[]No値を許可された選択肢の集合に制限します

有効な値が特定の選択肢に限られる場合は、enum を使って値を制約してください。

Backend code
@aiFunction('document 内の section を保存します', [
{
name: 'sectionId',
type: 'string',
description: 'document 内で更新する section',
required: true,
enum: ['introduction', 'background', 'methodology', 'results', 'conclusion'],
},
{
name: 'content',
type: 'string',
description: 'section の内容',
required: true,
},
])
async saveSection(params: { sectionId: string; content: string }): Promise<string> {
const { sectionId, content } = params;
const docRef = this.squid.collection('documents').doc('my-doc');
await docRef.update({ [sectionId]: content });
return 'Section saved: ' + sectionId;
}

Return values

AI functions は、Promise<string>(TypeScript)または str(Python)を返す必要があります。agent はこの string を受け取り、それを使って response を組み立てます。明確で簡潔な result を返してください。

Backend code
// Good: returns useful information the agent can relay
return 'Order #1234 shipped on March 5. Tracking number: ABC123';

// Bad: returns raw JSON the agent has to interpret
return JSON.stringify(orderObject);

Attributes

Attributes を使うと、AI function を特定の connector type に紐付けることができ、その connector の built-in capabilities を独自の custom logic で拡張できます。その type の connector を agent に追加すると、connector の default behavior と一緒に function も自動的に含まれます。

たとえば、database connector だけでも agent は AI を使って data を query できます。しかし、agent に常に特定の方法で query させたい場合は、その connector type に attribute を持つ AI function を書くことができます。

Backend code
@aiFunction({
description: 'PostgreSQL database から customer の最近の注文を取得します',
params: [
{
name: 'customerEmail',
description: 'customer の email address',
type: 'string',
required: true,
},
],
attributes: {
integrationType: ['postgres'],
},
})
async getCustomerOrders(
{ customerEmail }: { customerEmail: string },
{ integrationId }: AiFunctionCallContextWithIntegration,
): Promise<string> {
// Custom query logic.
//
// Squid provides "Query with AI" where the agent can write the query and execute it to
// accomplish a task, but if you want it to consistently query in a certain way, you can write
// an AI Function that you can instruct it to call instead.
}

PostgreSQL connector を agent に追加すると、この function は自動的に含まれます。

注記

connector type に attribute された functions は、Agent Studio の AI Functions list には表示されません。agent への含め方は connector によって処理されます。

Categories

Categories を使うと、Agent Studio で AI functions をグループ化し、整理しやすくできます。

Backend code
@aiFunction({
description: 'Amazon の product listing から新しい user review をすべて取得します。',
params: [
{
name: 'productId',
description: 'Amazon 上の listing の ID。例: URL "https://www.amazon.com/dp/B094D3JGLT" に対する "B094D3JGLT"',
type: 'string',
required: true,
},
{
name: 'cutoffDate',
description: '締切日。この日付より新しい review のみを返します。ISO8601 format を使用してください。指定しない場合はすべての review を返します。',
type: 'string',
required: false,
},
],
categories: ['Data Gathering'],
})
async getProductReviews(
{ productId, cutoffDate }: { productId: string; cutoffDate?: string },
{ integrationId }: AiFunctionCallContextWithIntegration,
): Promise<string> {
// Your logic to gather the user reviews.
}

これにより、getProductReviewsAI Functions list 内で "Data Gathering" category の下に表示されます。複数の category を指定することもでき、その場合 function はそれぞれの category に表示されます。

Parameter 値の上書き

一部の agent では、AI に決めさせるのではなく、特定の parameter 値を固定したい場合があります。predefinedParameters を使うことで parameter を上書きできます。AI は上書きされた parameter の存在を認識せず、その値を設定することもできません。

たとえば、先ほどの saveSection function を使うと、introduction section だけを更新する agent を作成できます。

chat widget を使う場合:

Client code
<squid-chat-widget
...
squid-ai-agent-chat-options={{
functions: [{
name: 'saveSection',
predefinedParameters: { sectionId: 'introduction' }
}]
}}
...
>
</squid-chat-widget>

SDK を使う場合:

Client code
const result = await squid
.ai()
.agent('my-agent')
.ask('Save that content.', {
functions: [
{
name: 'saveSection',
predefinedParameters: { sectionId: 'introduction' },
},
],
});

agent が指定できるのは content parameter のみです。sectionId は常に 'introduction' になります。

AI functions に context を渡す

AI が生成した params に加えて、context object を使って独自の値を AI functions に渡すこともできます。これは、document ID、user preferences、security に関わる値のように、AI が制御すべきでない data に便利です。

context には 2 つの scope があります。

  • agentContext: agent が行うすべての AI function call に渡されます。ctx.agentContext からアクセスします。
  • functionContext: 特定の function にのみ渡されます。ctx.functionContext からアクセスします。

Example

先ほどの saveSection function をさらに発展させてみましょう。document ID を agent level で設定し、保存前に content から internal codename を redact したいとします。

Backend code
import { SquidService, aiFunction, AiFunctionCallContext } from '@squidcloud/backend';

const SECTION_IDS = ['introduction', 'background', 'methodology', 'results', 'conclusion'] as const;
type SectionId = (typeof SECTION_IDS)[number];

interface DocumentIdAgentContext {
documentId: string;
}

interface RedactionFunctionContext {
codenameList: string[];
}

class DocumentService extends SquidService {
@aiFunction('document 内の section を保存します', [
{
name: 'sectionId',
type: 'string',
description: 'document 内で更新する section',
required: true,
enum: [...SECTION_IDS],
},
{
name: 'content',
type: 'string',
description: 'section の内容',
required: true,
},
])
async saveSection({ sectionId, content }: { sectionId: SectionId; content: string }, ctx: AiFunctionCallContext<RedactionFunctionContext, DocumentIdAgentContext>): Promise<string> {
const docRef = this.squid.collection('documents').doc(ctx.agentContext.documentId);
let censoredContent = content;
for (const censorWord of ctx.functionContext.codenameList) {
censoredContent = censoredContent.replaceAll(censorWord, 'REDACTED');
}
await docRef.update({ [sectionId]: censoredContent });
return 'Section saved: ' + sectionId;
}
}

これらの context 値は、client 側から chat widget を通して渡せます。

Client code
<squid-chat-widget
...
squid-ai-agent-chat-options={{
agentContext: { documentId: "document_controlled_by_this_agent" },
functions: [{
name: 'saveSection',
context: { codenameList: ['LITANIA', 'LEOPARD'] }
}]
}}
...
>
</squid-chat-widget>

または SDK を使う場合:

Client code
const result = await squid
.ai()
.agent('my-agent')
.ask('I want the "results" section to be "LITANIA has determined the answer to be 42".', {
agentContext: { documentId: 'document_controlled_by_this_agent' },
functions: [
{
name: 'saveSection',
context: { codenameList: ['LITANIA', 'LEOPARD'] },
},
],
});

この場合、保存される content には "REDACTED has determined the answer to be 42" が含まれます。これは "LITANIA" が codename list に含まれているためです。

Error Handling

AI function が error を throw すると、agent はその error message を受け取り、それを user に伝えたり、次にどう進めるかを判断したりできます。明確で説明的な error を throw してください。

Backend code
@aiFunction<{ orderId: string }>(
'注文の status を調べます。',
[{ name: 'orderId', description: '注文 ID', type: 'string', required: true }],
)
async getOrderStatus(params: { orderId: string }): Promise<string> {
const { orderId } = params;
const order = await this.squid.collection('orders').doc(orderId).snapshot();
if (!order) {
throw new Error(`Order ${orderId} not found`);
}
return `Order ${orderId}: ${order.status}, shipped ${order.shippedDate}`;
}

Common issues

IssueCauseSolution
Function がまったく呼び出されないdescription が user prompt と一致していないいつ function を呼び出すべきかを明確に記述するよう description を書き直す
間違った parameter 値が渡されるparameter description が曖昧より具体的な description を追加し、enum を使って値を制約する
Agent が function を見つけられないfunctions option に function 名が渡されていないask call で function 名を渡すか、Agent Studio で追加する
Agent Studio に function が表示されないfunction が cloud に deploy されていないsquid deploy で backend を deploy する

Best Practices

明確な description を書く

description は、agent が function を正しく呼び出せるかどうかを左右する最も重要な要素です。agent にいつ使うべきかを正確に伝える instruction として書いてください。

Good: 'Returns the shipping status and tracking number for an order. Call when the user asks about order status, delivery, or tracking.'

Bad: 'Gets order info'

Parameter を慎重に設計する

  • function がその値なしでは動作できない場合にのみ required: true を使う
  • 有効な値が決まっている場合は enum を設定する
  • parameter description には、どの format を使うべきかが分かるように書く(例: "ISO8601 date", "email address")

Return value は情報が伝わるものにする

agent はあなたの return string を使って response を組み立てます。raw data structure ではなく、人が読める情報を返してください。

Input を validate する

AI が parameter 値を生成する場合でも、function 内で必ず validate してください。AI は予期しない値を生成することがあります。

Backend code
async updateQuantity(params: { quantity: number }): Promise<string> {
const { quantity } = params;
if (!Number.isFinite(quantity) || quantity < 0) {
throw new Error('Quantity must be a non-negative number');
}
// ...
return 'Quantity updated';
}

Next Steps