バトルカードと競合分析 — 技術で勝つ戦略を組み立てる
「ソウタさん、ミライテックの案件、ベイクオフになりました」
Slack に飛び込んできたメッセージを見て、ソウタは思わず椅子から身を乗り出した。ミライテックは従業員 8,000 人を超える大手製造業だ。AI による品質検査の自動化を検討しており、Arclight AI にとって今期最大の案件だった。
「ベイクオフ? つまり他社と比較されるってことですか」
カイがビデオ通話をつないできた。
「そう。競合は NeuralWorks と DataForge の 2 社。3 社で技術評価を受けて、最終的に 1 社に絞られる。2 週間後にそれぞれ技術デモをやる」
ソウタの表情が曇る。NeuralWorks は資金力のある大手で、DataForge は製造業での導入実績が豊富だ。
「正直、厳しい戦いですね……」
「厳しいのは事実だ。でも、準備次第で勝率は大きく変わる。今日はバトルカードの作り方を教えよう」
バトルカードとは何か
バトルカードとは、競合との比較情報を 1 枚のカードに凝縮した営業・技術支援ツールだ。FDE にとって、これは単なる営業資料ではない。技術的な優位性を構造化し、顧客の前で自信を持って語るための「作戦書」だ。
INFO
バトルカードの効果は数字で証明されている。利用者の 71% が勝率の改善を報告し、競合状況での改善率は 93% が 20% 以上と回答している。バトルカードは営業支援ツールの中で最も ROI が高い資産とされる。
「71% が勝率改善って、本当ですか?」
「本当だ。ただし、ちゃんと作ればの話だよ。テンプレートを埋めるだけじゃダメだ。技術者の視点で、本質的な差別化ポイントを抽出する必要がある」
バトルカードの 8 セクション構成
カイはホワイトボードにバトルカードの構造を描いた。
「大きく分けると 8 セクションだが、まずはこの 5 カテゴリで構造を掴もう」
各セクションの役割
| セクション | 内容 | 誰が使うか |
|---|---|---|
| 概要 | 競合の企業情報・ポジション | 全員 |
| 勝因・敗因 | 過去に勝った/負けた理由 | FDE・営業 |
| 機能比較 | 機能ごとの優劣マトリクス | FDE |
| 反論対処 | よくある反論とその対応 | FDE・営業 |
| トラップ質問 | 競合に不利になる質問 | FDE |
| クイックディスミス | 短い一言で競合を位置づける | 営業 |
| 価格情報 | 競合の価格体系 | 営業 |
| 攻撃・防御戦術 | 攻めと守りの具体的な手法 | FDE |
WARNING
バトルカードは社外秘だ。顧客に直接見せるものではない。あくまでチーム内で使う準備資料であり、顧客の前では自然な会話として情報を伝える。
FIA フレームワーク — 競合主張の構造化
「バトルカードに書く内容は、感覚じゃなくフレームワークで構造化する。FIA を使おう」
カイが説明する。
Fact-Impact-Act
- Fact(事実): 検証可能な客観的事実
- Impact(影響): その事実が顧客にどう影響するか
- Act(行動): FDE としてどう行動するか
NeuralWorks に対する FIA の例
ソウタはカイの指導のもと、NeuralWorks に対するバトルカードエントリを作り始めた。
| 要素 | 内容 |
|---|---|
| Fact | NeuralWorks のモデル推論は GPU 専用で、CPU フォールバックがない |
| Impact | 工場のエッジ環境では GPU が使えない場合がある。推論が止まると検査ラインが停止する |
| Act | Arclight AI の CPU/GPU 自動切替デモを見せる。エッジ環境の安定性を強調する |
| 要素 | 内容 |
|---|---|
| Fact | NeuralWorks は API ベースのみで、オンプレミス対応していない |
| Impact | 製造業のセキュリティ要件で、品質検査データを外部に送れない場合がある |
| Act | Arclight AI のオンプレミス / ハイブリッド構成のリファレンスアーキテクチャを提示する |
「事実だけ伝えても相手には刺さらない。『だからあなたにとってこう困る』まで繋げて、『だから私たちはこうします』で閉じる」
Know-Say-Show フレームワーク
「FIA はバトルカードの中身を構造化するものだ。次は、実際の会話でどう使うかの話だ」
Know(知る)— 内部で把握しておく情報
顧客には直接言わないが、チームで共有しておくべき情報だ。
- NeuralWorks の直近の資金調達額と投資家の期待
- DataForge が製造業 A 社で導入に 18 ヶ月かかった事実
- 競合の技術スタック(Python/TensorFlow vs Arclight の Rust/ONNX)
- 競合の解約率や顧客満足度の情報
Say(伝える)— 顧客に伝えるメッセージ
「競合を直接攻撃するんじゃない。自社の強みとして伝えるんだ」
❌ 「NeuralWorks は GPU がないと動きません」
✅ 「Arclight AI はエッジ環境でも安定動作するよう、CPU/GPU 自動切替を標準搭載しています」
❌ 「DataForge は導入に 1 年以上かかります」
✅ 「Arclight AI は PoC から本番稼働まで平均 3 ヶ月で、専任の FDE が伴走します」
Show(見せる)— デモや証拠で示す
- エッジデバイス上でのリアルタイム推論デモ
- 既存顧客の導入タイムライン(匿名化済み)
- ベンチマーク結果(推論速度、精度、リソース消費)
INFO
Say で主張し、Show で証明するのが鉄則だ。「速いです」と言うだけでなく、目の前でベンチマークを走らせる。FDE の技術力が最も活きる瞬間だ。
Winning / Battling / Losing ゾーン分析
「次に、競合ごとにどこで勝てて、どこが五分五分で、どこで負けるかを整理しよう」
各ゾーンの戦略
Winning Zone(勝てる領域):
- ここを評価基準の中心に据える
- デモで重点的に見せる
- 顧客の課題とこの領域を結びつける
Battling Zone(五分五分の領域):
- 差別化ポイントを探す
- テクニカルな深掘りで微差を見せる
- 顧客固有の要件で有利に持ち込む
Losing Zone(負ける領域):
- 評価基準から外すか、重要度を下げる
- 代替手段やロードマップで補う
- 「ブランドより実績」のように視点を変える
「勝てるところで戦い、五分のところで差をつけ、負けるところは土俵を変える。これが基本戦略だ」
Win/Loss 分析 — なぜ勝ち、なぜ負けたか
「ソウタ、過去のベイクオフの勝敗記録はあるか?」
「営業チームが Salesforce に記録していますが、『価格で負けた』とか『関係性で勝った』みたいな大雑把なものですね」
「それが問題だ」
WARNING
セラーの 60% が敗因を誤って認識しているという調査結果がある。営業担当は「価格で負けた」と思いがちだが、実際には技術評価の段階で差がついていることが多い。
構造化された Win/Loss 分析の方法
ポイントは、営業チームだけでなく顧客にもインタビューすることだ。
| 分析対象 | 質問例 |
|---|---|
| 意思決定基準 | 最終的にどの基準で選びましたか? |
| 技術評価 | 技術デモで最も印象に残った点は? |
| 信頼性 | ベンダーの信頼性をどう評価しましたか? |
| リスク | 採用にあたって最大のリスクは何でしたか? |
| 競合比較 | 他社と比べて優れていた/劣っていた点は? |
「勝ちからも負けからも学ぶ。でも負けからの方が 10 倍学べる」
技術評価での競合ポジショニング
評価基準を設計する
「ミライテックが独自に評価基準を作る前に、こちらから提案するんだ」
ソウタは驚いた。
「評価基準をこっちから出すんですか?」
「もちろんだ。顧客は AI の技術評価に慣れていない場合が多い。こちらが『こういう観点で比較すると公平です』と提案すれば、感謝されるし、自社の強みが反映された基準になる」
Arclight AI が提案する評価基準
# 技術評価基準の構造化
class EvaluationCriteria
CATEGORIES = {
performance: { label: '推論性能', weight: 25,
items: %w[リアルタイム推論速度 バッチスループット CPU/GPU両対応 エッジ動作] },
integration: { label: '統合容易性', weight: 20,
items: %w[REST_API対応 既存システム連携 オンプレ/クラウド選択 パイプライン構築] },
reliability: { label: '信頼性', weight: 20,
items: %w[SLA保証 フェイルオーバー モデル監視 ロールバック] },
support: { label: '導入支援', weight: 20,
items: %w[PoC期間 専任技術者 トレーニング ドキュメント] },
cost: { label: 'コスト', weight: 15,
items: %w[初期費用 ランニングコスト スケーリング費用 隠れコスト] }
}.freeze
endINFO
評価基準の重み付けが鍵だ。Arclight AI が強い「推論性能」と「導入支援」の配点を高くし、ブランド知名度のような負ける領域は基準に入れない。これは不正ではなく、顧客にとって本当に重要な観点を提案しているだけだ。
テクニカルプルーフポイント
ソウタは、各評価基準に対する「証拠」を準備した。
| 主張 | 証拠タイプ | 具体的な証拠 |
|---|---|---|
| CPU 環境で 50ms 以下の推論速度 | ベンチマーク | ONNX Runtime + 量子化モデルの計測結果 |
| PoC から本番まで平均 3 ヶ月 | 導入事例 | 製造業 B 社のタイムライン(匿名化済み) |
| オンプレミス完全閉域運用 | アーキテクチャ | エアギャップ構成のリファレンス図 |
Rails で構築する競合インテリジェンスシステム
「バトルカードを個人の知識にしておくのはもったいない。チーム全体で共有・更新できるシステムを作ろう」
ソウタは Rails で社内用の競合インテリジェンスシステムを構築することにした。
データモデル
# app/models/competitor.rb
class Competitor < ApplicationRecord
has_many :battle_cards, dependent: :destroy
has_many :win_loss_records, dependent: :destroy
validates :name, presence: true, uniqueness: true
enum :threat_level, { low: 0, medium: 1, high: 2, critical: 3 }
scope :active, -> { where(active: true) }
scope :by_threat, -> { order(threat_level: :desc) }
def win_rate
total = win_loss_records.decided.count
return 0 if total.zero?
(win_loss_records.won.count.to_f / total * 100).round(1)
end
end
# app/models/battle_card.rb
class BattleCard < ApplicationRecord
belongs_to :competitor
belongs_to :author, class_name: 'User'
has_many :sections, class_name: 'BattleCardSection',
dependent: :destroy
validates :title, presence: true
validates :version, presence: true
enum :status, { draft: 0, review: 1, approved: 2, archived: 3 }
scope :current, -> { approved.order(version: :desc).limit(1) }
def complete?
BattleCardSection::TYPES.all? { |t| sections.exists?(section_type: t) }
end
end
# app/models/battle_card_section.rb
class BattleCardSection < ApplicationRecord
belongs_to :battle_card
TYPES = %w[
overview win_lose_reasons feature_comparison
objection_handling trap_questions quick_dismiss
pricing_intel attack_defense_tactics
].freeze
validates :section_type, presence: true, inclusion: { in: TYPES }
validates :content, presence: true
end
# app/models/win_loss_record.rb
class WinLossRecord < ApplicationRecord
belongs_to :competitor
belongs_to :account_executive, class_name: 'User'
belongs_to :fde, class_name: 'User', optional: true
validates :deal_name, presence: true
validates :deal_size, numericality: { greater_than: 0 }
enum :outcome, { won: 0, lost: 1, no_decision: 2 }
enum :loss_reason, {
price: 0, features: 1, integration: 2,
relationship: 3, brand: 4, technical: 5
}, prefix: true
scope :decided, -> { where(outcome: %i[won lost]) }
endWin/Loss パターン分析サービス
# app/services/win_loss_analyzer.rb
class WinLossAnalyzer
def initialize(competitor:, period: 12.months)
@competitor = competitor
@period = period
end
def analyze
records = WinLossRecord.where(competitor: @competitor)
.where('closed_at > ?', @period.ago).decided
return {} if records.empty?
{
total: records.count,
win_rate: (records.won.count.to_f / records.count * 100).round(1),
top_loss_reason: top_reason(records.lost),
trend: monthly_trend(records),
recommendation: recommend(records)
}
end
private
def top_reason(losses)
return nil if losses.empty?
losses.group(:loss_reason).count.max_by { |_, v| v }&.first
end
def monthly_trend(records)
records.group_by { |r| r.closed_at.beginning_of_month }
.sort_by(&:first)
.last(6)
.map { |m, rs| { month: m.strftime('%Y-%m'), deals: rs.size } }
end
def recommend(records)
win_rate = records.won.count.to_f / records.count * 100
return 'バトルカードの全面見直しが必要' if win_rate < 40
top = top_reason(records.lost)
top ? "#{top} への対策を強化せよ" : '現状維持'
end
endコントローラ
# app/controllers/battle_cards_controller.rb
class BattleCardsController < ApplicationController
before_action :authenticate_user!
before_action :set_competitor
def show
@battle_card = @competitor.battle_cards.current.first!
@sections = @battle_card.sections.order(:position)
@analysis = WinLossAnalyzer.new(competitor: @competitor).analyze
end
def create
@battle_card = @competitor.battle_cards.build(battle_card_params)
@battle_card.author = current_user
if @battle_card.save
redirect_to competitor_battle_card_path(@competitor, @battle_card),
notice: 'バトルカードを作成しました'
else
render :new, status: :unprocessable_entity
end
end
def search
@results = BattleCard.approved
.joins(:sections)
.where('battle_card_sections.content LIKE ?', "%#{params[:q]}%")
.distinct
end
private
def set_competitor = Competitor.find(params[:competitor_id])
def battle_card_params
params.require(:battle_card).permit(:title, :version, :status, :notes)
end
endAWS DynamoDB によるバトルカードストレージ
「社内 Rails アプリは小規模チーム向けだ。でもエンタープライズ規模になると、リアルタイム更新と高速検索が必要になる」
カイが AWS のアーキテクチャを提案した。
テーブル設計と CRUD
DynamoDB のシングルテーブル設計を採用する。PK に COMPETITOR#<id>、SK に CARD#<version> を使い、GSI で全バトルカードの横断検索を可能にする。
# lib/aws/dynamo_battle_card.rb
require 'aws-sdk-dynamodb'
class DynamoBattleCard
TABLE_NAME = 'battle_cards'
def initialize
@client = Aws::DynamoDB::Client.new(
region: ENV.fetch('AWS_REGION', 'ap-northeast-1')
)
end
def put_card(competitor_id:, version:, sections:, author:)
@client.put_item(
table_name: TABLE_NAME,
item: {
'pk' => "COMPETITOR##{competitor_id}",
'sk' => "CARD##{version}",
'gsi1pk' => 'CARD',
'gsi1sk' => "#{competitor_id}##{version}",
'sections' => sections,
'author' => author,
'updated_at' => Time.current.iso8601
}
)
end
def cards_for_competitor(competitor_id)
@client.query(
table_name: TABLE_NAME,
key_condition_expression: 'pk = :pk AND begins_with(sk, :prefix)',
expression_attribute_values: {
':pk' => "COMPETITOR##{competitor_id}",
':prefix' => 'CARD#'
},
scan_index_forward: false
).items
end
endDynamoDB Streams による通知
DynamoDB Streams を有効にし、Lambda でバトルカードの更新を検知して SNS 経由でチームに通知する。
# lib/aws/battle_card_stream_handler.rb
require 'aws-sdk-sns'
class BattleCardStreamHandler
def self.process(event:, context:)
sns = Aws::SNS::Client.new
topic_arn = ENV.fetch('BATTLE_CARD_TOPIC_ARN')
event['Records'].each do |record|
next unless record['eventName'] == 'MODIFY'
new_image = record['dynamodb']['NewImage']
competitor = new_image.dig('pk', 'S')&.delete_prefix('COMPETITOR#')
sns.publish(
topic_arn: topic_arn,
subject: "バトルカード更新: #{competitor}",
message: "#{new_image.dig('author', 'S')} がバトルカードを更新しました。"
)
end
end
endINFO
DynamoDB Streams + Lambda + SNS の組み合わせにより、バトルカードが更新されると即座にチーム全体に通知が飛ぶ。ベイクオフ直前の最新情報共有に威力を発揮する。
ベイクオフ当日 — バトルカードの実戦投入
2 週間後、ミライテックの会議室。ソウタは Arclight AI の技術デモを担当した。
ミライテックの CTO が最初に質問した。
「御社のモデルは、GPU がない現場でも動くのですか?」
ソウタはバトルカードの トラップ質問 セクションを思い出した。実はこの質問こそ、Arclight AI が仕掛けた土俵だった。事前に提案した評価基準の中に「エッジ環境での動作」を含めておいたのだ。
「はい。Arclight AI は ONNX Runtime による CPU 推論を標準でサポートしています。実際にお見せします」
ソウタはノート PC で、GPU なしの環境でリアルタイム推論のデモを走らせた。推論速度は 42ms。ミライテックのエンジニアたちが身を乗り出した。
Know-Say-Show の Show だ。
「NeuralWorks さんも候補ですが、エッジ対応はどうなんでしょう」と CTO が呟いた。
ソウタは競合を直接攻撃しなかった。バトルカードの 反論対処 セクションにあった通り、自社の強みとして語った。
「Arclight AI は、クラウドとエッジのハイブリッド構成をリファレンスアーキテクチャとして提供しています。工場のネットワーク状況に関係なく、検査ラインを止めない設計です」
デモ終了後、ミライテックの技術チームからの質問は 1 時間以上続いた。ソウタはバトルカードに書いた FIA の構造で、すべての質問に「事実 → 影響 → 行動」の流れで答えた。
3 日後、カイから連絡が来た。
「ソウタ、ミライテックから連絡があった。Arclight AI に決まったよ」
「本当ですか!」
「決め手は 2 つ。エッジ環境での実動デモと、FDE による導入支援体制。まさにバトルカードで Winning Zone に設定した 2 つだ」
ソウタは深く息を吐いた。準備が勝利を生んだのだ。
まとめ — FDE は技術と戦略の交差点に立つ
カイが最後に語った。
「FDE の仕事は、コードを書くことでも、デモをすることでもない。プロダクトの技術的価値を、顧客の文脈で証明することだ」
バトルカードは、その証明を構造化するツールだ。
- FIA で競合の弱点を事実ベースで整理する
- Know-Say-Show で会話の準備をする
- Winning/Battling/Losing でどこで戦うか決める
- Win/Loss 分析 で継続的に精度を上げる
「技術力だけでは勝てない。戦略だけでも勝てない。両方を持っている FDE だから、ベイクオフで勝てるんだ」
ソウタは次のベイクオフに向けて、Win/Loss レコードにミライテックの勝因を記録し始めた。今日の勝利が、明日のバトルカードを強くする。