
はじめに
doda システムアーキテクト部の齋藤です。 私たちの組織における AI エージェントの開発と活用事例をご紹介します。
課題
doda はいくつかのシステムで構成されていますが、多くの機能は Java, Tomcat を EC2 で動かしています。 現在は複数のプロジェクトが動いており、テスト環境が当記事の記載時点においては 10 環境ほどあります。
この 10 環境分の Tomcat を 1 台の EC2 で動かしているため、時々 OOME などのエラーが発生して停止してしまいます。 エラーが発生するたび、 サーバーにログインし、ログを確認して再起動などをしていました。
そこで、この問題の対処に AI エージェントを使うことにしました。
対応方法
今回の課題以外にもテスト環境で発生する問題はいくつかありました。
そのため、チャットで AI と会話をしながら、テスト環境で起こるさまざまな問題を解決するアプローチが良いと私は考えました。
UIを作る
ということで、まずはチャットの UI を作ります。
このような画面ですが、この画面自体も AI に作成してもらいました。(この画面自体も AI エージェントに Sonnet3.5 で作ってもらっています。若干チープな印象ですが、テスト用なので気にしていません)

この画面は Next.js で作って ECS で稼働させています。
APIを作る
送信をクリックしたときに Bedrock とつないで利用するツールを判断させる API を作りました。
簡略化のため、会話の履歴はフロント側に持たせてしまっています。
const systemPrompt = `あなたは生成AIでdodaの開発環境をメンテナンスする xxx です。
dodaの開発環境をユーザーの要望に応じて管理してください。
===
dodaの開発環境は以下の構成用になっています。
(省略しますがサーバの構成やIPアドレスなどの情報を記載します)
===
以降がユーザーからのチャットになります。
`;
export async function POST(req: NextRequest) {
try {
const { messages } = await req.json();
const newMessages = [
{
role: 'user',
content: [
{ type: 'text', text: systemPrompt + messages[0].content[0].text },
],
},
...messages.slice(1),
];
const beforeMessageSize = newMessages.length;
while (true) {
if (loopCount >= 10) {
break;
}
const params = {
modelId: 'anthropic.claude-3-5-sonnet-20240620-v1:0',
contentType: 'application/json',
accept: 'application/json',
body: JSON.stringify({
anthropic_version: 'bedrock-2023-05-31',
max_tokens: 8192,
messages: newMessages,
tools: tools.tools.map((tool) => {
return {
name: tool.name,
description: tool.description,
input_schema: tool.inputSchema,
};
}),
}),
};
const command = new InvokeModelCommand(params);
const response = await bedrockClient.send(command);
const responseBody = JSON.parse(new TextDecoder().decode(response.body));
// ここはツール呼び出し処理だが一旦省略
if (!isToolUse) {
break;
}
loopCount++;
}
return NextResponse.json(newMessages.slice(beforeMessageSize));
} catch (error) {
console.error('Error:', error);
return NextResponse.json(
{ error: '通信に失敗しました。' },
{ status: 500 }
);
}
}
MCPを作る
Tomcat を再起動するためのツールを MCP Server で用意します。
内部のツールではなく MCP サーバーにしているのは、今後の拡張性を意識しているためです。こちらは後述します。
Next.js の APIルート で提供するため、vercel/mcp-adapter を利用しています。
const secretsManager = new SecretsManager({
region: 'ap-northeast-1',
});
const handler = createMcpHandler(
(server) => {
server.tool(
'tomcat_restart',
'Tomcatを再起動する',
{
host: z.string().describe('再起動対象サーバのIPアドレスを指定する'),
component: z.enum(['aaaa'/* システム名を列挙 */])
.describe(`再起動対象のシステムを指定する。
(システムの簡単な説明)
`),
env: z
.enum(['st' /* テスト環境を列挙 */])
.describe('対象の環境を指定する'),
},
async ({ host, component, env }) => {
// ここに再起動の処理を記載する
return {
content: [
{
type: 'text',
text: message,
},
],
_meta: {
isError,
},
};
}
);
},
{},
{ basePath: '/api' }
);
export { handler as GET, handler as POST, handler as DELETE };
APIからMCPを呼び出す
先ほど作成した API から MCP を呼び出します。
tools の作成
const mcpClient = new Client({
name: 'xxx',
version: '1.0.0',
});
const transport = new StreamableHTTPClientTransport(
new URL('/api/mcp', baseURL)
);
await mcpClient.connect(transport);
const tools = await mcpClient.listTools();
tool の呼び出し
// bedrockの呼び出し結果取得
const responseBody = JSON.parse(new TextDecoder().decode(response.body));
let isToolUse = false;
for (const content of responseBody.content) {
newMessages.push({
role: 'assistant',
content: [content],
});
if (content.type === 'tool_use') {
isToolUse = true;
const result: any = await mcpClient.callTool({
name: content.name,
arguments: content.input,
});
newMessages.push({
role: 'user',
content: [
{
type: 'tool_result',
tool_use_id: content.id,
content: result.content[0].text,
},
],
});
}
// 以下省略
結果
以下の画面が実行結果の例です。
このように日本語で環境の再起動ができるようになったことで、サーバーに入らなくても Tomcat の再起動ができるようになりました。

今後の拡張
今後は以下の拡張を進めていく予定です。
1. Slack などから呼び出せるようにする。
今回はチャット用の UI を用意しましたが、Slack などから呼び出すようにすることでさらに簡単に実行できるようにしたり、他の人の呼び出しが確認できる状態にしていきたいです。
2. MCP の追加
開発環境で起こるさまざまな課題の多くをチャットで解決できるようにしていきたいと考えています。
ログの確認からその原因調査、DB のデータ確認のようなさまざまな作業を生成 AI に任せられるようになると考えています。
さらには本番環境で発生した障害なども、チャットで解決できるようにして、より doda の品質や開発効率を上げていきたいと考えています。
コードなど実際のものから一部変更して記載しています。

齋藤 悠太 Yuta Saito
プロダクト開発統括部 dodaシステムアーキテクト部 dodaマイクロサービスグループ マネジャー
SIerや事業会社業務での開発を経験し、2020年9月にパーソルキャリアに入社。現在はdodaサイト開発に携わっている。好きな技術領域はJava、Spring、AWS。
※2025年8月時点の情報です。
