コードレビューからアドフラウド検出まで!AIが変えた私たちの日常

はじめに

こんにちは、更新が滞りすぎて本当にスミマセン、、。でも、めげません。

生成AIのブームがエンジニアの世界を席巻してから、一切更新がないのは逆にすごいなと思っている id:hokupod です。私は当社でシニアマネジャー兼スタッフエンジニアとして働いています。

近年、ChatGPTやGitHub Copilotなどの登場により、エンジニアの働き方が大きく変わりつつあります。コーディング支援やデバッグ、さらにはアイデア出しまで、生成AIの活用範囲は日々拡大しています。

この記事では、当社における生成AIの具体的な活用事例をご紹介します。実践的な活用方法とその効果について詳しく説明していきますので、ぜひ最後までお付き合いください。

生成AIがWebエンジニアに及ぼす影響

生成AIは、Webエンジニアの業務に大きな影響を与えています。特に、コストカットと質の向上の両面で顕著な効果が見られます。

  1. コード生成: 定型的なコードや基本的なアルゴリズムの実装を生成AIに任せることで、開発時間を大幅に短縮できます。これにより、エンジニアはより創造的な作業に集中できるようになりました。例えば、APIのボイラープレートコードやデータベース操作の基本的なクエリなどを素早く生成し、それをベースに微調整するだけで済むようになりました。

  2. コードレビュー: AIによる事前レビューにより、人間のレビュアーの負担が軽減され、より深い議論に時間を割けるようになりました。結果として、コードの品質向上につながっています。AIは一貫性のチェックやベストプラクティスの提案を行い、人間のレビュアーは設計の妥当性やビジネスロジックの正確性に集中できるようになりました。

生成AIは、私にとって単なる知識獲得のツール以上の存在となっています。不得意分野への挑戦や新しい領域への展開において、強力なサポート役として機能しています。例えば、技術報告書や開発ドキュメントの作成時に、生成AIを活用することで、より効率的に情報を整理し、わかりやすい文章を構成できるようになりました。複雑な技術概念を説明する際も、AIが適切な比喩や図解のアイデアを提案してくれるため、非技術者にも理解しやすいドキュメントを作成できるようになりました。

技術面では、プログラミングにおける実用的なツールとしても活用しています。特に、従来の文字列検索では対応が困難だった微妙な表現の違いを適切に処理できる点で、大きな価値を提供しています。これにより、より柔軟で効率的なコード検索や、自然言語によるコード生成が可能になりました。

このように、生成AIはWebエンジニアの業務効率を大幅に向上させ、より創造的で価値の高い仕事に注力できる環境を作り出しています。

Amazon Bedrock を活用した Dify 環境の全社展開

当社では Amazon Bedrock を使用して Dify 環境を構築し、全社展開を実施いたしました。Difyは生成AIアプリケーションを簡単に作成できるプラットフォームで、これにより社内での生成AI活用が飛躍的に進みました。

詳細については、当社サイトのコラムに掲載されているインタビュー記事をご覧ください。

https://bltinc.co.jp/recruiting/interview/qkj9vje1d5

社内浸透のための工夫

生成AIの導入にあたり、未経験者でも気軽に触れられる環境作りを心がけました。その一環として、「逆アキネイター」というゲームをチャット上で実装いたしました。このゲームは以下の特徴を持っています:

• 生成AIが特定のキャラクターを一人選定 • ユーザーが質問を通じてそのキャラクターを当てる • 「よつばと!のキャラクター」などユーザーの最初の発言でテーマが決定 • 生成AIがテーマに沿って情報を収集し回答

よつばと!のキャラクターを当てるゲーム
よつばと!のキャラクターを当てるゲーム、あっさり当たりました
この遊び感覚でのアプローチは大成功を収め、公開後にアクセスが一時倍増するなど、多くの社員の参加を得ることができました。なお、このゲーム形式は「みんなで推理」というコンセプトに影響を受けています。

この取り組みにより、生成AIに対する心理的障壁を下げることに成功し、社内での活用が促進されました。また、このゲームを通じて社員間のコミュニケーションも活性化され、予想以上の副次的効果も得られました。

逆アキネイターのプロンプトはこちら!

あなたは「逆アキネイター」というゲームのゲームマスターです。このゲームでは、あなたがユーザーの指定したテーマに基づいて秘密の対象を選び、プレイヤーがその対象を当てようとします。以下のルールに従ってゲームを進行してください:

1. ゲーム開始:
   - プレイヤーにゲームの説明をし、テーマを指定するよう促します。
   - プレイヤーが指定したテーマを確認します。
   - tavily_searchツールを使用して、指定されたテーマに関連する対象のリストを検索します。
   - 検索結果から無作為に1つの対象を選び、それを秘密の解答とします。
   - 選んだ対象について、可能な限り多くの情報(特徴、属性、関連情報など)を収集します。

2. ゲーム進行:
   - プレイヤーからの質問を待ちます。
   - プレイヤーの質問に対し、収集した情報に基づいて「はい」「多分そう、部分的にそう」「多分違う、部分的に違う」「いいえ」「わかりません」のいずれかで回答します。他に何も言ってはいけません。
   - プレイヤーの質問の回数が15回を越えない限りはヒントを与えないでください。
   - 情報が不足している場合は、ddgo_searchツールを使用して追加情報を収集します。「わかりません」と返す前に対象についての情報収集は必ずしてください。正確な情報を得るために秘密の解答を伏せずに検索クエリに含めても構いません。ただしツールから返ってきた内容をプレイヤーに伝えてはいけません。
   - 各回答の後、残りの質問回数を伝えます。

3. 情報管理:
   - プレイヤーの質問と自分の回答を記録し、矛盾が生じないようにします。
   - 新しく得た情報は、後の質問に備えて記憶します。

4. ゲーム終了条件:
   - プレイヤーが正解の対象を言い当てた場合。間違えていた場合は、解答を言わず継続します
   - 質問回数が20回に達した場合

5. ゲーム終了時:
   - 正解の場合:「おめでとうございます!正解です!」と祝福します。
   - 不正解の場合:「残念でした。正解は[対象名]でした。」と伝えます。
   - 秘密の対象についての詳細情報を共有し、ゲームの振り返りを行います。

6. その他の注意事項:
   - プレイヤーの質問が不明確な場合は、明確化を求めます。
   - ヒントが必要そうな場合は、控えめなヒントを提供することができます。
   - 常に友好的かつ励ましの態度を保ちます。
   - テーマに応じて適切な難易度を維持するよう努めます。
   - 秘密の解答は、ゲームの終了条件を満たすまで絶対に口にしてはいけません。絶対にです。

開発部門の導入事例

開発部門での生成AI活用について、主にCodeRabbitの導入事例と開発効率化の取り組みをご紹介します。

生産性向上のための取り組み

CodeRabbitの活用

CodeRabbitは、GitHubのプルリクエストに対して人間の代わりにコードレビューを実施し、JavaScriptなどのスタイルチェックも同時に行います。人間のレビュアーとは異なる幅広い観点からの指摘が得られる点が特に評価されています。

CodeRabbitの活用により、レビュー時間の短縮はもちろんのこと、チームになかった新しい視点でのレビューが可能になりました。例えば、セキュリティの観点やパフォーマンスの最適化など、人間のレビュアーが見落としがちな点も指摘されるようになりました。

また以下の機能が継続的に追加され、日々CodeRabbit自身もカイゼンされているのが好印象です。

  • 学習機能:誤ったレビュー内容への指摘を学習し、レビュー品質を改善
  • レポート機能:
    • 日次のプルリクエスト提出状況の通知
    • スプリント単位での承認済みプルリクエストのサマリーをSlackへ通知

CodeRabbit が指摘を受け学習をしている様子
CodeRabbit が指摘を受け学習をしている様子

Slack次世代プラットフォームでのアプリ開発

OpenAI社のAPIを活用し、Slack上でのコミュニケーションを要約できるアプリケーションを開発しました。Slack次世代プラットフォームの制約上、Denoのライブラリのみが使用可能であり、OpenAIのAPIを選択しています。

本開発では「生成AIをパーサーとして活用する」というコンセプトで取り組みました。生成AIのパーサーとしての活用とは、自然言語を解析して構造化されたJSONデータに変換することを指します。また、人間が日常的に使用する曖昧な期間表現(「昨日」「先週」など)を具体的な期間に変換する機能も実装しました。本機能の実装には、比較的軽量な gpt-4o-mini モデルを採用しています。

アプリケーションの処理フローは以下の通りです。

  1. ユーザーがSlackアプリにメンションを付けて要約を依頼
  2. Slackアプリのワークフローが起動
  3. 投稿内容を解析し、要約対象期間を特定
  4. Slack APIで該当期間の投稿を取得
  5. 取得した投稿内容の要約を生成
  6. 要約結果をユーザーに返信

Slack アプリからの要約の投稿(よわりんコンシェルジュフォームかわいい)
Slack アプリからの要約の投稿(コンシェルジュフォームのよわりんアイコンかわいい)

技術的特徴として、gpt-4o-mini の Structured Outputs 機能を活用し、ユーザーの入力を効率的にJSON形式に変換しています。これにより、要約期間の開始日時、終了日時への分割などの構造化や、プログラムでの取り扱いが容易になりました。また、期間指定の変換以外にも、様々な変換処理への応用が期待できます。

本開発を通じて、生成AIを活用したシステム開発の新たな可能性を見出すことができました。特に、自然言語処理と構造化データの橋渡しとしての生成AIの活用は、今後のアプリケーション開発において重要な役割を果たすと考えています。

このアプリは、日々の業務の効率化に大きく貢献しています。例えば、前日や前週の作業内容を忘れてしまった際に、このアプリを使って簡単に思い出すことができます。また、朝に定期的に要約をボットが投稿するようになっており、これをチーム全員で確認するという新しい習慣が生まれました。この習慣により、チーム内のコミュニケーションが活性化し、作業の進捗や課題の共有がスムーズになりました。

最後に、Structured Outputs および要約期間の変換についての重要な処理の概要を以下に示します。これはイメージとしてご覧ください:

// 構造化された出力の型を定義
const OutputSchema = z.object({
  conversation: z.string().describe("会話の内容の説明"),
  isSummaryRequest: z.boolean().describe("要約の依頼であるかどうか"),
  summaryStartTime: z.string().describe(
    "要約期間の開始時刻 (YYYY-MM-DDTHH:mm:ss)",
  ),
  summaryEndTime: z.string().describe(
    "要約期間の終了時刻 (YYYY-MM-DDTHH:mm:ss)",
  ),
});
type OutputType = z.infer<typeof OutputSchema>;
// LLM では現在時刻を持っていないため、現在時刻をプロンプトに渡す
const currentTime = new Date().toISOString();
const prompt = `現在時刻は ${currentTime} です。
以下のSlackメッセージを解析し、以下の形式のJSONデータとして返してください:
{
  "conversation": "会話の内容の説明",
  "isSummaryRequest": true/false,
  "summaryStartTime": "YYYY-MM-DDTHH:mm:ss",
  "summaryEndTime": "YYYY-MM-DDTHH:mm:ss"
}
メッセージ: ${inputs.text}`;
const openai = new OpenAI({
  apiKey: OPENAI_API_KEY,
  baseURL: OPENAI_BASE_URL,
  organization: null,
  project: null,
});
const timeoutPromise = new Promise((_, reject) =>
  setTimeout(() => reject(new Error("Request timeout")), 30000)
);
const response = await Promise.race([
  openai.chat.completions.create({
    model: "gpt-4o-mini",
    messages: [{ role: "user", content: prompt }],
    temperature: 0,
    response_format: { type: "json_object" }, //Structured Outputs の指定
  }),
  timeoutPromise,
]) as ChatCompletion;
const result = JSON.parse(
  response.choices[0].message.content,
) as OutputType;
console.log("Analysis result:", result);

この開発を通じて、生成AIを単なる文章生成ツールではなく、柔軟なデータ処理システムとして活用する新たな可能性を見出すことができました。

(番外編) 個人で使用しているメッセージ整形ツール

ご興味ございましたら、開いてください Slackなどでメッセージを送信する際、文章が整わないことがしばしばあります。また、文章を整えるのにかなりの時間を要することがあり、何らかの方法で時間短縮できないかと考えていました。

そこで、AIツールを活用したメッセージ整形ツールを実装しました。具体的には、Neovimのプラグインである CodeCompanion を利用しています。

このツールでは、選択した文章を自動的に書き直し、元の文章との差分(Diff)が表示されます。その動作を確認いただけるよう、GIFアニメーションを用意いたしました。

CodeCompanion によるテキストの整形

参考として、私が使用している CodeCompanion の設定ファイル(抜粋)を以下に添付いたします。

require("codecompanion").setup({
  opts = {
    language = "Japanese",
  },
  display = {
    chat = {
      render_headers = false,
    },
  },
  strategies = {
    chat = {
      adapter = "anthropic",
      slash_commands = {
        ["file"] = {
          opts = {
            -- ref: https://github.com/olimorris/codecompanion.nvim/discussions/276
            provider = "telescope",
          },
        },
      },
    },
    inline = {
      adapter = "anthropic",
    },
    agent = {
      adapter = "anthropic",
    },
  },
  prompt_library = {
    ["Communicatable Message"] = {
      strategy = "inline",
      description = "Create Communicatable Message",
      opts = {
        placement = "replace",
        short_name = "cm",
        auto_submit = true,
        is_slash_cmd = true,
        is_default = true,
        adapter = {
          name = "anthropic",
        }
      },
      prompts = {
        {
          role = "system",
          content = function(context)
            return "You are a professional communication editor.\n"
              .. "Following the guidelines below, please organize my text to make it more readable and provide it in a form that can be used as is. Please output the final text in the same language as the message.\n"
              .. "\n"
              .. "If there are sentences where the subject is unclear, please place placeholders where the subject should be.\n"
              .. "\n"
              .. "1. Structure\n"
              .. "- One main topic per paragraph\n"
              .. "- Maintain logical flow\n"
              .. "- Use appropriate conjunctions\n"
              .. "\n"
              .. "2. Clarity\n"
              .. "- Use concise and direct expressions\n"
              .. "- Employ specific wording\n"
              .. "- Eliminate ambiguous expressions\n"
              .. "\n"
              .. "3. Readability\n"
              .. "- Proper placement of punctuation\n"
              .. "- Separate into paragraphs as needed\n"
              .. "- Use bullet points when appropriate\n"
              .. "\n"
              .. "4. Tone\n"
              .. "- Use appropriate honorifics and politeness according to the situation\n"
              .. "- Express positivity and forward-thinking\n"
              .. "- Maintain sincerity and consistency\n"
              .. "\n"
              .. "5. Conclusion\n"
              .. "- Clarify claims and key points\n"
              .. "- Provide action proposals or inquiries as necessary\n"
          end,
        },
        {
          role = "user",
          content = function(context)
            local text = require("codecompanion.helpers.actions").get_code(context.start_line, context.end_line)
            return "Based on the above guidelines, please organize the following text so that it can be used as is.\n"
              .. "```\n" .. text .. "```\n"
          end,
        },
      },
    },
  },
})

このツールにより、メッセージ作成の効率が大幅に向上し、コミュニケーションの質の向上にも寄与しています。

アフィリエイトサービスプロバイダーとしての取り組み

アドフラウド検出

アドフラウドとは、アフィリエイトサービスにおける不正成果のことを指し、サービス運営における重要な課題となっています。私たちは、特定のパターンを認識させることでアドフラウドを検出できるのではないかと考え、検証を進めてまいりました。

検証プロセスでは、他社の事例を参考にアドフラウドのパターンを作成し、不正の可能性がある成果を特定する手法を採用しました。この取り組みにより、高い精度でパターンを認識することに成功しました。

ただし、現状では課題も残されています。単純なパターンマッチングだけでは不正の特定が困難であり、各アフィリエイトプログラムの特性を考慮した学習が必要であることが判明しました。幸いにも、検証開始時から使用している生成AIモデルの性能は大幅に向上しており、この課題に対しても継続的に取り組んでいます。

アドフラウドを事前に検出し防止することができれば、開発者の立場からも損失を抑制する形での利益貢献が可能となります。

まとめ

生成AIの導入は、当社の業務プロセスに大きな変革をもたらしています。本記事で紹介した様々な事例から、生成AIが単なるツール以上の存在となり、我々の業務の質と効率を大きく向上させる可能性を秘めていることが明らかになりました。

主な成果として、CodeRabbitによる開発効率の向上、Slack上での要約アプリによるコミュニケーションの活性化、さらにはアドフラウド検出など新たな領域への挑戦が挙げられます。特に、生成AIをパーサーとして活用する試みは、今後のアプリケーション開発に新たな可能性を開くものと期待しています。

一方で、生成AIの出力の信頼性やアドフラウド検出の精度向上など、克服すべき課題も明らかになりました。これらの課題に対しては、AIと人間の協力を前提とした新しいアプローチの開発や、より特化型のAIモデルの導入を検討しています。

今後は、以下のステップを重点的に進めていく予定です:

  1. アドフラウド検出システムの改善と精度向上: AIと人間の協力を前提とした新しい検出方法の開発を進めます。また、RAG(Retrieval-Augmented Generation)技術の導入を検討し、大規模な履歴データや専門知識を効果的に活用することで、検出精度の向上を目指します。

  2. 業務特性に合わせたAIソリューションの開発: カスタムAIモデルの開発だけでなく、RAGを活用した知識ベースの構築も視野に入れています。これにより、社内の専門知識や過去の事例を効果的に活用し、より正確で文脈に応じた出力を得ることができると期待しています。

  3. 定期的なAI活用事例共有会の開催: 各部署でのAI活用事例を定期的に共有し、成功事例だけでなく課題や失敗事例も含めて議論します。これにより、より効果的なAI活用方法を模索し、組織全体でのAI活用レベルの向上を図ります。

生成AI技術は日々進化しており、その可能性を最大限に引き出すためには、継続的な学習と改善が不可欠です。我々は、AIと人間の協力関係をさらに深め、より高度な問題解決や業務効率化を実現していきたいと考えています。

最後に、生成AIに興味のあるエンジニアの皆さん、私たちと一緒にAIの力を活かした新しい未来を創造していきませんか? 皆さんのアイデアと情熱をお待ちしています。