mcpField
V
virtual-agent

virtual-agent

github.com/serac-labsエージェントワークフロー7758 回インストール9 週間前に更新
リポジトリ

virtual-agent について

virtual-agentは、ServiceNowの会話型セルフサービス向けトピックやフローを設計するスキルです。NLU設定や会話ブロックに加え、Virtual Agentの会話を管理・テストするMCPツールを扱います。

主な機能

  1. 01トピックと会話ブロックの作成
  2. 02NLUのインテントとエンティティ設定
  3. 03クイック返信とトピック変数の追加
  4. 04インシデント作成とナレッジ記事検索
  5. 05会話のテストと有人担当者への転送

活用シーン

  1. 01パスワードリセットのセルフサービスフロー構築
  2. 02リクエストの有人担当者への転送
  3. 03チャットからのインシデント作成
  4. 04ユーザーの質問に合うナレッジ記事の検索

MCP 対応

Virtual Agentのトピック作成・検索、ブロック追加、メッセージ送信、会話履歴の取得、有人担当者への引き継ぎに使うMCPツールを説明します。

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/serac-labs/serac --skill virtual-agent

インストール後、Claude Code で/virtual-agentを入力して読み込まれたか確認します。

詳細

ServiceNow の Virtual Agent

Virtual Agent(VA)は、チャットインターフェースを通じたセルフサービス向けに、会話型 AI 機能を提供します。

Virtual Agent のアーキテクチャ

トピック構造
Topic: Password Reset
├── NLU Model
│   ├── Utterances: "reset my password", "forgot password"
│   └── Entities: application_name
├── Topic Blocks (Flow)
│   ├── Greeting
│   ├── Ask for Application
│   ├── Verify User
│   ├── Process Reset
│   └── Confirmation
└── Variables
    ├── user_email
    └── application
主要なテーブル
テーブル用途
sys_cs_topicトピックの定義
sys_cs_topic_block会話フローブロック
sys_cs_intentNLU インテント
sys_cs_utteranceトレーニングフレーズ
sys_cs_entityカスタムエンティティ

トピック

トピックの作成(ES5)
// Create Password Reset topic
var topic = new GlideRecord("sys_cs_topic")
topic.initialize()
topic.setValue("name", "Password Reset")
topic.setValue("description", "Help users reset their passwords")
topic.setValue("active", true)

// NLU configuration
topic.setValue("goal", "I want to reset my password")
topic.setValue("nlu_enabled", true)

// Category
topic.setValue("category", "IT Support")

var topicSysId = topic.insert()
トピック変数
// Add variable to topic
var variable = new GlideRecord("sys_cs_topic_variable")
variable.initialize()
variable.setValue("topic", topicSysId)
variable.setValue("name", "user_email")
variable.setValue("label", "Email Address")
variable.setValue("type", "string")
variable.setValue("mandatory", true)
variable.insert()

トピックブロック

ブロックの種類
種類用途例
Textメッセージを表示"それについてお手伝いできます!"
Prompt質問する"メールアドレスを教えてください。"
Scriptサーバーコードを実行ユーザーの検索、チケットの作成
Decision分岐ロジックVIP の場合は……
Link外部リンクポータルページを開く
Handoffエージェントへの転送ライブエージェントに接続する
Text ブロック
// Greeting block
var block = new GlideRecord("sys_cs_topic_block")
block.initialize()
block.setValue("topic", topicSysId)
block.setValue("name", "greeting")
block.setValue("type", "text")
block.setValue("order", 100)
block.setValue("message", "Hello! I can help you reset your password. Let me gather some information.")
block.insert()
Prompt ブロック
// Ask for email
var promptBlock = new GlideRecord("sys_cs_topic_block")
promptBlock.initialize()
promptBlock.setValue("topic", topicSysId)
promptBlock.setValue("name", "ask_email")
promptBlock.setValue("type", "prompt")
promptBlock.setValue("order", 200)
promptBlock.setValue("message", "What is your email address?")
promptBlock.setValue("variable_name", "user_email")
promptBlock.setValue("validation_type", "email")
promptBlock.insert()
Script ブロック(ES5)
// Script block to verify user
var scriptBlock = new GlideRecord("sys_cs_topic_block")
scriptBlock.initialize()
scriptBlock.setValue("topic", topicSysId)
scriptBlock.setValue("name", "verify_user")
scriptBlock.setValue("type", "script")
scriptBlock.setValue("order", 300)

// Server-side script (ES5 only!)
scriptBlock.setValue(
  "script",
  "(function execute(inputs, outputs) {\n" +
    "    var email = inputs.user_email;\n" +
    '    var user = new GlideRecord("sys_user");\n' +
    '    user.addQuery("email", email);\n' +
    "    user.query();\n" +
    "    \n" +
    "    if (user.next()) {\n" +
    "        outputs.user_found = true;\n" +
    '        outputs.user_name = user.getValue("name");\n' +
    "        outputs.user_sys_id = user.getUniqueValue();\n" +
    "    } else {\n" +
    "        outputs.user_found = false;\n" +
    "    }\n" +
    "})(inputs, outputs);",
)
scriptBlock.insert()
Decision ブロック
// Decision based on user found
var decisionBlock = new GlideRecord("sys_cs_topic_block")
decisionBlock.initialize()
decisionBlock.setValue("topic", topicSysId)
decisionBlock.setValue("name", "check_user")
decisionBlock.setValue("type", "decision")
decisionBlock.setValue("order", 400)

// Decision branches configured separately
decisionBlock.insert()

// Add decision branches
var branch1 = new GlideRecord("sys_cs_topic_block_branch")
branch1.initialize()
branch1.setValue("block", decisionBlock.getUniqueValue())
branch1.setValue("condition", "user_found == true")
branch1.setValue("next_block", processResetBlockSysId)
branch1.insert()

var branch2 = new GlideRecord("sys_cs_topic_block_branch")
branch2.initialize()
branch2.setValue("block", decisionBlock.getUniqueValue())
branch2.setValue("condition", "user_found == false")
branch2.setValue("next_block", userNotFoundBlockSysId)
branch2.insert()
Handoff ブロック
// Transfer to live agent
var handoffBlock = new GlideRecord("sys_cs_topic_block")
handoffBlock.initialize()
handoffBlock.setValue("topic", topicSysId)
handoffBlock.setValue("name", "transfer_agent")
handoffBlock.setValue("type", "handoff")
handoffBlock.setValue("order", 900)
handoffBlock.setValue("message", "Let me connect you with a live agent who can help further.")
handoffBlock.setValue("queue", liveSupportQueueSysId)
handoffBlock.insert()

NLU トレーニング

発話の追加
// Add training utterances for intent
function addUtterance(topicId, text) {
  var utt = new GlideRecord("sys_cs_utterance")
  utt.initialize()
  utt.setValue("topic", topicId)
  utt.setValue("utterance", text)
  utt.insert()
}

// Training phrases for password reset
addUtterance(topicSysId, "reset my password")
addUtterance(topicSysId, "I forgot my password")
addUtterance(topicSysId, "change my password")
addUtterance(topicSysId, "password not working")
addUtterance(topicSysId, "can't log in")
addUtterance(topicSysId, "locked out of my account")
addUtterance(topicSysId, "need to reset password for @application")
カスタムエンティティ
// Create custom entity for applications
var entity = new GlideRecord("sys_cs_entity")
entity.initialize()
entity.setValue("name", "application_name")
entity.setValue("description", "Enterprise application names")
entity.setValue("type", "list")
entity.insert()

// Add entity values
var values = ["SAP", "Salesforce", "Workday", "ServiceNow", "Email"]
for (var i = 0; i < values.length; i++) {
  var val = new GlideRecord("sys_cs_entity_value")
  val.initialize()
  val.setValue("entity", entity.getUniqueValue())
  val.setValue("value", values[i])
  val.setValue("synonyms", "") // comma-separated synonyms
  val.insert()
}

クイック返信

クイック返信の設定
// Add quick reply options to prompt
var promptWithReplies = new GlideRecord("sys_cs_topic_block")
promptWithReplies.initialize()
promptWithReplies.setValue("topic", topicSysId)
promptWithReplies.setValue("name", "select_application")
promptWithReplies.setValue("type", "prompt")
promptWithReplies.setValue("order", 150)
promptWithReplies.setValue("message", "Which application do you need to reset?")
promptWithReplies.setValue("variable_name", "application")
promptWithReplies.setValue(
  "quick_replies",
  JSON.stringify([
    { label: "Email", value: "email" },
    { label: "SAP", value: "sap" },
    { label: "ServiceNow", value: "servicenow" },
    { label: "Other", value: "other" },
  ]),
)
promptWithReplies.insert()

統合アクション

VA からインシデントを作成する(ES5)
// Script block to create incident
var createIncidentScript =
  "(function execute(inputs, outputs) {\n" +
  '    var inc = new GlideRecord("incident");\n' +
  "    inc.initialize();\n" +
  '    inc.setValue("caller_id", inputs.user_sys_id);\n' +
  '    inc.setValue("short_description", "Password Reset Request: " + inputs.application);\n' +
  '    inc.setValue("description", "User requested password reset via Virtual Agent.");\n' +
  '    inc.setValue("category", "software");\n' +
  '    inc.setValue("subcategory", "password reset");\n' +
  '    inc.setValue("priority", 3);\n' +
  "    \n" +
  "    var sysId = inc.insert();\n" +
  "    \n" +
  '    outputs.incident_number = inc.getValue("number");\n' +
  "    outputs.incident_sys_id = sysId;\n" +
  "})(inputs, outputs);"
レコードの検索(ES5)
// Script to lookup knowledge articles
var lookupKBScript =
  "(function execute(inputs, outputs) {\n" +
  "    var query = inputs.user_question;\n" +
  "    var articles = [];\n" +
  "    \n" +
  '    var kb = new GlideRecord("kb_knowledge");\n' +
  '    kb.addQuery("workflow_state", "published");\n' +
  '    kb.addQuery("short_description", "CONTAINS", query);\n' +
  "    kb.setLimit(3);\n" +
  "    kb.query();\n" +
  "    \n" +
  "    while (kb.next()) {\n" +
  "        articles.push({\n" +
  '            number: kb.getValue("number"),\n' +
  '            title: kb.getValue("short_description"),\n' +
  "            sys_id: kb.getUniqueValue()\n" +
  "        });\n" +
  "    }\n" +
  "    \n" +
  "    outputs.articles = JSON.stringify(articles);\n" +
  "    outputs.article_count = articles.length;\n" +
  "})(inputs, outputs);"

MCP ツールの統合

利用可能な VA ツール
ツール用途
snow_create_va_topicトピックを作成する
snow_create_va_topic_block会話ブロックを追加する
snow_discover_va_topicsトピックを検索する
snow_send_va_message会話をテストする
snow_get_va_conversation会話履歴を取得する
snow_handoff_to_agentエージェントに転送する
ワークフローの例
// 1. Create topic
var topicId = await snow_create_va_topic({
  name: "IT Equipment Request",
  description: "Help users request new equipment",
  category: "IT Support",
})

// 2. Add greeting block
await snow_create_va_topic_block({
  topic: topicId,
  name: "greeting",
  type: "text",
  order: 100,
  message: "I can help you request new IT equipment!",
})

// 3. Add prompt block
await snow_create_va_topic_block({
  topic: topicId,
  name: "equipment_type",
  type: "prompt",
  order: 200,
  message: "What type of equipment do you need?",
  quick_replies: ["Laptop", "Monitor", "Keyboard", "Mouse"],
})

// 4. Test conversation
await snow_send_va_message({
  topic: topicId,
  message: "I need a new laptop",
})

ベストプラクティス

  1. 明確なインテント - トピックごとに目的を 1 つにします
  2. 充実したトレーニング - さまざまな発話を多数用意します
  3. 適切なフォールバック - 不明な入力に対応します
  4. クイック返信 - 入力の手間を減らします
  5. 確認 - アクションの前に確認します
  6. エージェントへの転送経路 - 常にエージェントへの転送を可能にします
  7. 十分なテスト - さまざまな会話経路をテストします
  8. ペルソナ - 一貫して親しみやすい口調を保ちます

コメント