はじめに
ServiceNowのインシデントからElasticのAIエージェントを呼び出しの一例です。
インシデントに記録した内容を元に、必要に応じてAIエージェントにオブザーバービリティ分析してもらうことが実現できます。
ServiceNowは使い慣れてないのですがGeminiに教えてもらいながら試したので、最適な実装ではないかもしれませんがご了承ください。
SerivceNowのバージョンはZurichで実施しています。
コンポーネント間の流れ
インシデントの内容について、ElasticのAI Agentに調査をしてもらい、返ってきた結果を記録するというものです。
[ServiceNow Incident]
│
▼
[UI Action (Manual Trigger)]
│
▼
[ServiceNow Flow Designer (Subflow)]
│
▼
[ServiceNow Action (Integration Step)]
│
▼
[Elastic Workflow (Orchestration)]
│
▼
[Elastic AI Agent (Agent Builder)]
│
▼
[Elasticsearch Observability Data]
Elastic側の構成手順
Elastic Workflow
以下の定義のWorkflowを保存します。これのURLに含まれるWorkflow IDは後ほどServiceNowから呼び出すためにコピーしておいてください。
name: test_servicenow
enabled: true
triggers:
- type: manual
inputs:
- name: incident_number
type: string
required: true
- name: incident_sys_id
type: string
required: true
- name: short_description
type: string
required: true
- name: priority
type: string
required: true
steps:
- name: console
type: console
with:
message: "{{inputs.incident_number}} {{inputs.incident_sys_id}} {{inputs.priority}} {{inputs.short_description}}"
- name: check_with_ai_agent
type: ai.agent
with:
message: "Output in plain text format and **NO** markdown. Check index: kibana_sample_data_flights and get information of: {{ inputs.short_description }}"
- name: post_to_snow
type: http
with:
url: "https://<Your ServiceNow ID domain>/api/now/table/incident/{{ inputs.incident_sys_id }}"
method: PATCH
headers:
Authorization: "Basic <Your user:password base64>"
Content-Type: "application/json"
body: '{"work_notes": "{{ steps.check_with_ai_agent.output.message | replace: "\n", "\\n"}}"}'
上のBasicのキーはusername:passwordをbase64エンコードしたものをセットします。
今回はServiceNowのadminとそのパスワードでとりあえず実施。(Macならecho -n "admin:xxx" | base64の出力を利用)
ServiceNow側の構成手順
System Definition > Script Includes
// Script Include: ElasticKibanaHelper
// Scope: Global
// Client callable: false
var ElasticKibanaHelper = Class.create();
ElasticKibanaHelper.prototype = {
initialize: function() {
this.baseUrl = 'https://<xxx>.elastic.cloud';
this.apiKey = gs.getProperty('elastic.kibana.api_key', '');
this.timeout = 30000; // 30 seconds
},
/**
* Trigger a Kibana Workflow by ID.
*
* @param {String} workflowId - The Kibana workflow ID to run
* @param {Object} bodyParams - Optional JSON payload to send with the request
* @returns {Object} - { success: Boolean, status: Number, body: Object, error: String }
*/
runWorkflow: function(workflowId, bodyParams) {
if (!workflowId) {
return this._error('workflowId is required');
}
if (!this.apiKey) {
gs.error('ElasticKibanaHelper: elastic.kibana.api_key system property is not set');
return this._error('API key not configured. Set the elastic.kibana.api_key system property.');
}
var endpoint = this.baseUrl + '/api/workflows/workflow/' + workflowId + '/run';
var payload = JSON.stringify({
inputs: bodyParams || {}
});
try {
var request = new sn_ws.RESTMessageV2();
request.setEndpoint(endpoint);
request.setHttpMethod('POST');
// ── Authentication ──────────────────────────────────────────────
request.setRequestHeader('Authorization', 'ApiKey ' + this.apiKey);
// ── Standard headers ────────────────────────────────────────────
request.setRequestHeader('Content-Type', 'application/json');
request.setRequestHeader('kbn-xsrf', 'true'); // Required by Kibana REST API
// ── Body ────────────────────────────────────────────────────────
request.setRequestBody(payload);
// Timeout
request.setEccParameter('connect_timeout', this.timeout);
request.setEccParameter('read_timeout', this.timeout);
var response = request.execute();
var statusCode = response.getStatusCode();
var bodyText = response.getBody();
gs.info(
'ElasticKibanaHelper.runWorkflow | workflowId=' + workflowId +
' | status=' + statusCode
);
var parsedBody = {};
try { parsedBody = JSON.parse(bodyText); } catch(e) { parsedBody = { raw: bodyText }; }
if (statusCode >= 200 && statusCode < 300) {
return {
success: true,
status: statusCode,
body: parsedBody,
error: null
};
}
gs.error(
'ElasticKibanaHelper.runWorkflow: HTTP ' + statusCode +
' for workflowId=' + workflowId + ' | body=' + bodyText
);
return {
success: false,
status: statusCode,
body: parsedBody,
error: 'HTTP ' + statusCode + ': ' + (parsedBody.message || bodyText)
};
} catch(ex) {
gs.error('ElasticKibanaHelper.runWorkflow exception: ' + ex.message);
return this._error(ex.message);
}
},
// ── Private helpers ───────────────────────────────────────────────────────
_error: function(msg) {
return { success: false, status: null, body: null, error: msg };
},
type: 'ElasticKibanaHelper'
};
ServiceNow メニュー sys_properties.listからElasticの認証APIキー設定
Flow Designer (Workflow Studio) > Actions
Inputs
Scirpt - Input Variables
Script- Script
// Flow Designer Action Script Step
// Action name: Run Elastic Kibana Workflow
// Step name: Invoke Kibana Workflow API
//
// Inputs (mapped from Action Inputs above):
// inputs.workflow_id → String
// inputs.incident_number → String
// inputs.incident_sys_id → String
// inputs.short_description → String
// inputs.priority → String
//
// Outputs to set:
// outputs.success → Boolean
// outputs.response_status → Integer
// outputs.response_body → String
// outputs.error_message → String
(function execute(inputs, outputs) {
var helper = new ElasticKibanaHelper();
// Build the payload sent to Kibana
var payload = {
source: 'ServiceNow',
incident_number: inputs.incident_number || '',
incident_sys_id: inputs.incident_sys_id || '',
short_description: inputs.short_description || '',
priority: inputs.priority || '',
triggered_at: new GlideDateTime().getDisplayValue()
};
var result = helper.runWorkflow(inputs.workflow_id, payload);
// ── Map results to Action outputs ────────────────────────────────────────
outputs.success = result.success;
outputs.response_status = result.status ? String(result.status) : '';
outputs.response_body = result.body ? JSON.stringify(result.body) : '';
outputs.error_message = result.error ? result.error : '';
if (!result.success) {
// Surface the error in the flow execution log
gs.error(
'Run Elastic Kibana Workflow action failed | ' +
'incident=' + inputs.incident_number +
' | workflowId=' + inputs.workflow_id +
' | error=' + result.error
);
}
})(inputs, outputs);
Script- Output Variables
Flow Designer (Workflow Studio) > Subflows
実行するElastic WorkflowsのIDを固定で入れています。

All > System Definitions > UI Actions
(function() {
try {
var inputs = {};
// Set "current" to the "Name" defined in the Subflow Input (e.g., incident_record)
inputs['incident_record'] = current;
// Test with "synchronous execution" that is guaranteed to work
// * Be sure to use the Internal Name copied from the Subflow Properties for 'global.xxx'
var result = sn_fd.FlowAPI.executeSubflow('global.from_button_trigger_elastic_investigation', inputs);
// For synchronous execution, you can directly retrieve information from the returned object
gs.addInfoMessage('Executed Subflow');
} catch (ex) {
// Force display of the error type and details
var errorDetail = (ex.message) ? ex.message : ex.toString();
gs.addErrorMessage('[Debug] Error details: ' + errorDetail);
// Also output detailed information to the system log (sys_log)
gs.error('Subflow Debug: ' + errorDetail);
}
// Keep the current screen
action.setRedirectURL(current);
})();
動作テスト!
ServiceNow - Incident作成してください。
-
Execute data investigation in Elastic AIのボタンが右上にあること。 - Short descriptionがElasticのAI Agentへの調査依頼内容になる。
一度Incident保存してから、また開いてボタンを実行します。
IncidentにElasticのAIエージェントから結果が返ってくることを確認

おわり
AIエージェントがない時代ではこのような連携を行っても返せるデータは限定的でした。しかし今はAIエージェントで色々な分析を行ってもらって人が読みやすい形で返してくれるので、インシデント管理にも使いやすくなったと思います。










