AIエージェントとは、生成AIの発展によって登場した新たなAIサービスで、AIが文字通りエージェントのように特定の業務を代替してくれるSaaSの発展形です。AIマーケター、AI採用担当者、AIセールスのように職種・業界ごとに特化したAIエージェントが登場しています。
予実管理AIエージェントとは、経営企画や各事業部の総括的な役割など予実管理、計画策定を行なっている部門の業務を代替するAIエージェントです。弊社は、ビジネスにおいて人が最も時間をかけている業務はエクセル作業だと捉えています。これまでもセールス・マーケティング領域のCRMやクラウド会計サービスなど様々な領域のSaaSが登場し、徐々にエクセル作業がSaaSに置き換えられてきています。しかし、いまだにエクセルを使っている企業がほとんどで、その中でも計数管理の領域は各社で原価と販管費の考え方、勘定科目、管理したいKPIが異なるので、SaaS化が難しく、エクセルが残っているのではないかと思います。
弊社は、SaaSでは解決が難しかった計数管理の領域、中でも予実管理にフォーカスして解決できるAIエージェントサービスを開発しています。
具体的には、下記の3つに絞って機能開発を行なっています。
①予実管理シート作成の自動化
②BIツールでの可視化グラフ作成の自動化
③見込数値の予測・作成の自動化
PLの予実管理、キャッシュフローの予実管理、事業部別のKPI管理、販売計画、マーケティング計画など様々な予実管理シートを簡単な指示を与えるだけでエクセル、スプレッドシート等で作成してくれる機能を開発しています。
わざわざAIで自動化する必要あるのかと思われる方もいるかもしれませんが、エクセルやスプレッドシートは自由度が高いが故に、BIツールへのデータ連携や、統合シート(例えば、各事業部のPLを統合して全社PLを作成するなど)を作成する際に、データ型やフォーマットが連携可能な形になっておらず、担当者が手作業で統合するなんてことがよく起きています。
・セル結合が使われているシートがある
・項目の位置が揃っていない
・データ型が揃っていない
・勘定科目のドリルダウン、階層が揃っていない
・シートを統合する際に必要な統合キーとなるものがない
など上記のような要素を気にしながら各シートを整備していく作業はシステム開発におけるデータベース構築に近いものがあり、整合性がとれたシートを作成したり、統合しやすいように修正を行うところに生成AIを使用しています。
1:AIに作成したいシートについての指示を与える。
例えば、A事業、B事業、C事業の3つがある会社の統合PLの予実管理シートを作りたい場合は、「A事業、B事業、C事業の3つの事業がある場合の統合PLの予実管理シートのたたき台をスプレッドシートで作成してください。」という指示(プロンプト)を行うと、以下のようなスプレッドシートが作成されます。
2:AIが作成したシートに自身で行列を追加し必要な項目を揃える。四則演算など必要に応じて関数も埋め込む。
各社によって、必要な勘定科目、ドリルダウンも変わってくると思いますので、直接スプレッドシートを編集して修正を行います。自由に行の追加や関数の使用が可能です。
3:AIに別シートに送りたいデータの指示を与える。
例えば、A事業のPL予実管理シートから特定のデータを統合PLに送りたい場合は、「統合PLシート内に別シートから特定のIDのデータだけをインポートするようにして欲しい。インポートは自動ではなくボタンをクリックしたら実行されるようにしたい。」という指示を行うと、以下のようなGoogle App Scriptが書き込まれ、インポートボタンが表示されます。
function importData() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const menuSheet = ss.getSheetByName('menu');
const fileId = menuSheet.getRange('A2').getValue();
const sheetName = menuSheet.getRange('B2').getValue();
try {
const sourceSpreadsheet = SpreadsheetApp.openById(fileId);
const sourceSheet = sourceSpreadsheet.getSheetByName(sheetName);
if (!sourceSheet) {
SpreadsheetApp.getUi().alert('対象シートが見つかりません');
return;
}
const response = SpreadsheetApp.getUi().alert('インポートを開始しても良いですか?', SpreadsheetApp.getUi().ButtonSet.YES_NO);
if (response !== SpreadsheetApp.getUi().Button.YES) {
return;
}
// ステータス表示用のHTMLを作成
const html = HtmlService.createHtmlOutput('<p>インポート実行中です</p>')
.setWidth(300)
.setHeight(80);
SpreadsheetApp.getUi().showSidebar(html);
const targetSheet = ss.getSheetByName('月次');
const sourceData = sourceSheet.getRange('A2:AL' + sourceSheet.getLastRow()).getValues();
const targetData = targetSheet.getRange('A2:AL' + targetSheet.getLastRow()).getValues();
for (let i = 0; i < sourceData.length; i++) {
if (sourceData[i][0] !== '') {
const targetIndex = targetData.findIndex(row => row[0] === sourceData[i][0]);
if (targetIndex !== -1) {
for (let j = 2; j < sourceData[i].length; j++) {
targetSheet.getRange(targetIndex + 2, j + 1).setValue(sourceData[i][j]);
}
}
}
}
// サイドバーは自動的には閉じないので、完了後にアラートを表示
SpreadsheetApp.getUi().alert('インポートが完了しました');
} catch (error) {
console.error('Error:', error);
SpreadsheetApp.getUi().alert('エラーが発生しました: ' + error.message);
}
}
エクセルやスプレッドシートだけでは見づらいので、表やグラフにして可視化したい場合も、予実管理AIエージェントがサポートしてくれます。
エクセルの場合はPowerBIに、スプレッドシートの場合はLooker Studioに可視化を行ってくれます。
例えば、以下の統合PLシートで「売上高、売上総利益、営業利益について予実比較を確認できるダッシュボードを作成してください。期間は、4月から3月までの月別で表示し、棒グラフは累積表示でお願いします。」と指示を与えると、まずはスプレッドシート側でLooker Studioに連携するデータの成形を行います。
function onEdit(e) {
var sheet = e.source.getActiveSheet();
if (sheet.getName() === '月次') {
updateLSPlanAndActual();
}
}
function updateLSPlanAndActual() {
updateLSPlan();
updateLSActual();
}
function updateLSPlan() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var monthlySheet = ss.getSheetByName('月次');
var lsPlanSheet = ss.getSheetByName('LS計画');
// Get data from 月次 sheet
var headers = monthlySheet.getRange('C1:AL1').getValues()[0];
var data = monthlySheet.getRange('B2:AL').getValues();
// Initialize an array to store the transposed and filtered data
var result = [];
// Add the first row with headers
var firstRow = ['計画'];
for (var j = 0; j < headers.length; j++) {
if (/.*計画.*/.test(headers[j])) {
firstRow.push(headers[j]);
}
}
result.push(firstRow);
// Add the data rows
for (var i = 0; i < data.length; i++) {
var row = data[i];
var newRow = [row[0]]; // Start with the value from column B (e.g., 2024年4月 計画)
for (var j = 1; j < row.length; j++) { // Skip the first column (already added)
if (/.*計画.*/.test(headers[j - 1])) {
newRow.push(row[j]);
}
}
result.push(newRow);
}
// Transpose result to match the structure of LS計画 sheet
var transposedResult = transpose(result);
// Clear the LS計画 sheet before setting new values
lsPlanSheet.clear();
// Set the transposed and filtered data to LS計画 sheet
lsPlanSheet.getRange(1, 1, transposedResult.length, transposedResult[0].length).setValues(transposedResult);
// Convert text dates to actual dates in LS計画 sheet
var dateRange = lsPlanSheet.getRange('A2:A' + (transposedResult.length));
var dateValues = dateRange.getValues();
for (var i = 0; i < dateValues.length; i++) {
var dateText = dateValues[i][0];
var date = convertTextToDate(dateText, '計画');
if (date) {
dateValues[i][0] = date;
}
}
dateRange.setValues(dateValues);
}
function updateLSActual() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var monthlySheet = ss.getSheetByName('月次');
var lsActualSheet = ss.getSheetByName('LS実績');
// Get data from 月次 sheet
var headers = monthlySheet.getRange('C1:AL1').getValues()[0];
var data = monthlySheet.getRange('B2:AL').getValues();
// Initialize an array to store the transposed and filtered data
var result = [];
// Add the first row with headers
var firstRow = ['実績'];
for (var j = 0; j < headers.length; j++) {
if (/.*実績.*/.test(headers[j])) {
firstRow.push(headers[j]);
}
}
result.push(firstRow);
// Add the data rows
for (var i = 0; i < data.length; i++) {
var row = data[i];
var newRow = [row[0]]; // Start with the value from column B (e.g., 2024年4月 実績)
for (var j = 1; j < row.length; j++) { // Skip the first column (already added)
if (/.*実績.*/.test(headers[j - 1])) {
newRow.push(row[j]);
}
}
result.push(newRow);
}
// Transpose result to match the structure of LS実績 sheet
var transposedResult = transpose(result);
// Clear the LS実績 sheet before setting new values
lsActualSheet.clear();
// Set the transposed and filtered data to LS実績 sheet
lsActualSheet.getRange(1, 1, transposedResult.length, transposedResult[0].length).setValues(transposedResult);
// Add the header '実績' to cell A1
lsActualSheet.getRange('A1').setValue('実績');
// Convert text dates to actual dates in LS実績 sheet
var dateRange = lsActualSheet.getRange('A2:A' + (transposedResult.length));
var dateValues = dateRange.getValues();
for (var i = 0; i < dateValues.length; i++) {
var dateText = dateValues[i][0];
var date = convertTextToDate(dateText, '実績');
if (date) {
dateValues[i][0] = date;
}
}
dateRange.setValues(dateValues);
}
function transpose(matrix) {
return matrix[0].map((col, i) => matrix.map(row => row[i]));
}
function convertTextToDate(dateText, type) {
var datePattern = new RegExp('(\\d{4})年(\\d{1,2})月 ' + type);
var match = datePattern.exec(dateText);
if (match) {
var year = parseInt(match[1], 10);
var month = parseInt(match[2], 10) - 1; // JavaScript Date months are 0-based
return new Date(year, month, 1);
}
return null;
}
BIツールは簡単にエクセルやスプレッドシート、CSVファイルなどをインポートできますが、正しくインポートしないと見たいグラフを作成することができません。そのため、データベースやBIの知識がなくてもBIへのデータ連携を実現できるのが予実管理AIエージェントの2つ目の価値になります。
その後、Looker Studio上にグラフ作成を行います。テーマや色、フォントなどは仮で作成されますので、細かく修正やカスタマイズを行いたい場合は、自由に変更することができます。
最後に、予実管理においては四半期ごとなど定期的に計画の数値を各事業部に見直してもらう作業を行うことが多いですが、ここの見込数値の精度が悪いと全社の予算達成に大きな影響が出て、上場企業では決算の下方修正など株価にもインパクトのある話になってしまうかと思います。
そこで、見込数値作成の精度を少しでも上げるためにAIが直前四半期の実績データや過去の実績データなどを参考に、見込数値を予測してくれる機能を開発しております。
また、過去データからは読み取れない要因がある場合は、それも含めてAIに指示を出していただく形になります。(見込数値の予測精度は過去データの量やビジネスモデルによって変わってきます)
「下期の見込数値を予測し、作成してください。下期は、第二四半期で大型案件の期ずれがあるため、10月は1,000万円の売上上振れ要因がありますが、パイプラインの案件数が少ないので、11月以降は30%程度ずつ案件数を下方修正する必要がありそうです。案件単価は当初の計画通りとします。」と指示を出すと見込数値が見直されます。
弊社サービスでサンプルとして作成したスプレッドシートや、Looker Studioはこちらにまとめております。
スプレッドシート
Looker Studio
まだ開発中なので、どこまで期待通りのものが作成できるかは課題があるのですが、エクセル、スプレッドシートでの予実管理、計数管理に課題を抱えている場合は、お気軽にご相談ください。