AWS Summit Japan 2026に参加してきました。

こんにちは。グループ情報部の池田(@mashiike)です。

今年も06/25・06/26にAWS Summitが開催されました。
現地に行ったのは06/25だけでした。06/26はライブ配信を視聴するのにとどめました。

AWS Summit 2026 は、何となくエンジニアリング観点では、以下のような共通課題をクリアした年なんだなと感じました。

LLM/Agentの管理自体はエンジニアがやるので良いのだけど、
効率化したいその業務に関するスペシャリストは他にいて、
スペシャリスト自身でプロンプトの管理を出来るようにしたい。
そのような管理をすることで、更新サイクルを早くしてAIのタスク精度を向上させて、AIの活用促進を進めたい。

というところに課題を感じている人が多いようでした。 それに対して、

そんな課題に対して、我々は次のように解決を試みました。
 <<ここに具体的なアプローチ>>
このアプローチによって、プロンプトないし文脈情報のデプロイメントをLLM/Agentのデプロイメントと切り離しに成功しました。
その結果AI活用がとても進みました!

という発表が多かったように思います。
具体的なアプローチとしては、 LangfuseというOSSを導入 or 内製のパターンだったと思います。

今年は、上記のような課題をクリアすることで、生成AIないしAgentの活用が一気に進み、一定の成果を見いだせた年になったのではないでしょうか。
来年はどうなっちゃうんでしょうね。


もっと内容についても触れたいところですが…一旦それは置いといて。
実は去年このような記事を出しました。

techblog.kayac.com

そう、Elastic座布団 クッションの比較記事です。もちろん、今年もクッションはしっかりとゲットしてきました。

いつものクッション

会社のオフィスには、各年のクッションはちゃんと取っといてあります。
こうやって、並べてみますと、、、今年の分厚さは目立ちますね

さて、去年の記事では、モデル作って分析してました。モデルができてるということは、予測ができるということで、予測結果をみましょう。

github.com

去年では、3種類のモデルを出してましたが、2次関数系は明らかにオーバーフィッティングということで除外しまして、対数モデルと線形モデルで予測結果を図示してみました。
個人的には、「対数モデルじゃないか?」って思ってるので大体 51.6 ~ 72.0 mm の何処かに収まるのではと思っています。

さて実測してみましょう。先ずは去年のクッションを再計測

概ね同じ数値です。計測方法は去年と同じっぽいですね。では問題の2026年今年のクッションです。

74.7mm と大きく分厚いです。去年の対数モデルの予測(51.6〜72.0mm)は68%PIだったので、今年の実測はそこをちょっと超えてきました。
とはいえ95%PIの範囲には収まっているので、「対数モデルが外れた」というより「稀な側に振れた」くらいの話です。  

これを噛み砕くと、解釈は次の2通りくらいに分かれます。

  • 「対数モデルで厚さが推移しているが、今年のAWS Summit は予算が潤沢で、クッションの厚さが想定より厚かった」
  • 「線形モデルで厚さが推移していて、今年のAWS Summitのクッションも想定通りに厚かった」

クッションの厚さが線形で毎年増えてくなんて、さすがのAWSでも無理でしょ〜と思うので、多分対数モデルだとは思いますが、まだどちらも否定できないなと思っております。 来年のクッションの厚さがとても楽しみです。 2026年のクッションの実測ができたところで、来年の予測をしたいです。
最近のCodingAgentはすごいですね。予測を立ててと言うと、コードを書いてくれるのです。   

2027年の予測は次のようになってるそうです。

ちなみに僕個人の予想を言うと、これまで薄め→厚め→薄め→厚めと交互に来ているので、来年は伸びが鈍る「薄め」の年かなと思っています。対数モデルでもだいたい 76.8mm くらいなので、その辺りに収まるんじゃないかと予想しています。  

この予測を出したコードは以下のようになっています。  

#!/usr/bin/env python3
"""Predict 2027 cushion "before" thickness with linear and log models.

Refits linear (y = a*year + b) and log (y = a*log(year-2022) + b) models on
the 2023-2026 observations (incl. the measured 2026 = 74.7 mm), by least
squares and Bayesian inference (PyMC), and plots the 2027 prediction with
68% prediction-interval bars (observation noise included) for each model.
"""

from __future__ import annotations

import warnings

import matplotlib
import matplotlib.pyplot as plt
import numpy as np
import pymc as pm

warnings.filterwarnings("ignore")
matplotlib.use("Agg")
plt.rcParams["font.family"] = "DejaVu Sans"

YEARS = np.array([2023, 2024, 2025, 2026], dtype=float)
BEFORE = np.array([20.9, 45.9, 50.0, 74.7], dtype=float)
YEAR_2027 = 2027.0

YEAR_CENTER = float(np.mean(YEARS))
years_c = YEARS - YEAR_CENTER
year_2027_c = YEAR_2027 - YEAR_CENTER

t_obs = YEARS - 2022.0
t_2027 = YEAR_2027 - 2022.0
log_t_obs = np.log(t_obs)
log_t_2027 = np.log(t_2027)

RNG = np.random.default_rng(42)


def fit_bayes_linear() -> np.ndarray:
    """Return posterior predictive samples of the 2027 measurement (linear)."""
    with pm.Model():
        alpha = pm.Normal("alpha", mu=float(np.mean(BEFORE)), sigma=50.0)
        beta = pm.Normal("beta", mu=0.0, sigma=50.0)
        sigma = pm.HalfNormal("sigma", sigma=10.0)
        mu = alpha + beta * years_c
        pm.Normal("y_obs", mu=mu, sigma=sigma, observed=BEFORE)
        trace = pm.sample(
            4000, tune=2000, chains=4,
            target_accept=0.95, random_seed=42, progressbar=False,
        )
    a = trace.posterior["alpha"].values.flatten()
    b = trace.posterior["beta"].values.flatten()
    sigma_post = trace.posterior["sigma"].values.flatten()
    mu_2027 = a + b * year_2027_c
    return RNG.normal(loc=mu_2027, scale=sigma_post)


def fit_bayes_log() -> np.ndarray:
    """Return posterior predictive samples of the 2027 measurement (log)."""
    with pm.Model():
        a = pm.Normal("a", mu=30.0, sigma=20.0)
        b = pm.Normal("b", mu=0.0, sigma=20.0)
        sigma = pm.HalfNormal("sigma", sigma=10.0)
        mu = a * log_t_obs + b
        pm.Normal("y_obs", mu=mu, sigma=sigma, observed=BEFORE)
        trace = pm.sample(
            4000, tune=2000, chains=4,
            target_accept=0.95, random_seed=42, progressbar=False,
        )
    a_post = trace.posterior["a"].values.flatten()
    b_post = trace.posterior["b"].values.flatten()
    sigma_post = trace.posterior["sigma"].values.flatten()
    mu_2027 = a_post * log_t_2027 + b_post
    return RNG.normal(loc=mu_2027, scale=sigma_post)


def main() -> None:
    coeffs_lin = np.polyfit(years_c, BEFORE, 1)
    coeffs_log = np.polyfit(log_t_obs, BEFORE, 1)
    pred_lin_ols = float(np.polyval(coeffs_lin, year_2027_c))
    pred_log_ols = float(np.polyval(coeffs_log, np.log(t_2027)))

    samples_lin = fit_bayes_linear()
    samples_log = fit_bayes_log()

    def stats(s: np.ndarray) -> tuple[float, float, float]:
        return (
            float(np.mean(s)),
            float(np.percentile(s, 16.0)),
            float(np.percentile(s, 84.0)),
        )

    mean_lin, lo_lin, hi_lin = stats(samples_lin)
    mean_log, lo_log, hi_log = stats(samples_log)

    print("=== 2027 'before' thickness prediction ===\n")
    print("Observed:")
    for yr, val in zip(YEARS, BEFORE):
        print(f"  {int(yr)}: {val:.1f} mm")
    print()
    print("Linear model:")
    print(f"  OLS prediction      : {pred_lin_ols:.1f} mm")
    print(f"  Bayes pred. (w/ noise): {mean_lin:.1f} mm  (68% PI: {lo_lin:.1f}-{hi_lin:.1f})")
    print("Log model:")
    print(f"  OLS prediction      : {pred_log_ols:.1f} mm")
    print(f"  Bayes pred. (w/ noise): {mean_log:.1f} mm  (68% PI: {lo_log:.1f}-{hi_log:.1f})")

    # ------------------------------------------------------------------
    # Plot
    # ------------------------------------------------------------------
    fig, ax = plt.subplots(figsize=(8, 6))

    ax.scatter(YEARS, BEFORE, s=90, zorder=5, color="black", label="Observed")

    t_plot = np.linspace(2023, 2027.3, 200)
    t_plot_c = t_plot - YEAR_CENTER
    t_plot_log = t_plot - 2022.0

    ax.plot(t_plot, np.polyval(coeffs_lin, t_plot_c),
            "--", color="steelblue", label="Linear fit")
    ax.plot(t_plot, np.polyval(coeffs_log, np.log(t_plot_log)),
            "--", color="seagreen", label="Log fit")

    ax.errorbar(
        2026.85, mean_lin, yerr=[[mean_lin - lo_lin], [hi_lin - mean_lin]],
        fmt="D", markersize=9, color="steelblue", capsize=7,
        label=f"Linear 2027: {mean_lin:.1f} (68% PI [{lo_lin:.1f}, {hi_lin:.1f}])",
    )
    ax.errorbar(
        2027.15, mean_log, yerr=[[mean_log - lo_log], [hi_log - mean_log]],
        fmt="D", markersize=9, color="seagreen", capsize=7,
        label=f"Log 2027: {mean_log:.1f} (68% PI [{lo_log:.1f}, {hi_log:.1f}])",
    )

    ax.set_xlim(2022.5, 2027.8)
    ax.set_xlabel("Year")
    ax.set_ylabel("Thickness (mm)")
    ax.set_title("AWS Summit Cushion 'before' Thickness — 2027 Prediction")
    ax.legend(fontsize=9, loc="upper left")
    ax.grid(True, alpha=0.3)

    plt.tight_layout()
    plt.savefig("images/prediction_before_2027.png", dpi=150, bbox_inches="tight")
    plt.close()
    print("\nSaved plot to images/prediction_before_2027.png")


if __name__ == "__main__":
    main()

まとめ

今年もAWS Summit 2026に参加し、無事にクッションをゲットできました。    そして、前年のモデルでの予測と実際のクッションの比較を行い、「今年のは分厚いな」という最初に持ったときの感覚を数値としても確認できました。
昨年に比べると人が2倍くらい増えていたような気がしています。
内容は、去年に引き続いて生成AIやAgentに関する話がとても多かったです。去年は「生成AIを導入し始めました」「Agentを試してみました」という発表が多い印象でしたが、今年は「Agentを導入した結果こういう成果がありました、その過程でこんな課題がありました」という、より実践・運用フェーズの話が増えていました。
冒頭で感じた「プロンプトや文脈情報のデプロイをLLM/Agentのデプロイと切り離す」という共通課題も、まさにそうした運用の深まりの中から生まれてきたものなんだと思います。
来年は一体どうなるのかと、セッションの内容とクッションの厚さという2重の意味で楽しみに待っていたいと思います。

カヤックでは、カンファレンスに積極的に参加するエンジニアも募集しています!

dbt のリネージを BigQuery Graph で調べられるようにしてみる

こんにちは、グループ情報部の@mashiikeです。
2026年4月9日に、BigQuery の新機能「BigQuery Graph」が Preview になりました。

cloud.google.com

BigQuery Graph は、BigQuery 上のテーブルデータをグラフとしてモデリングし、ISO GQL 標準に準拠した Graph Query Language で分析できる機能です。
ノードとエッジのテーブルさえ用意すれば CREATE PROPERTY GRAPH でグラフが定義でき、GQL で関係性を辿れるようになります。

身近なグラフデータと言えば、dbt のリネージグラフだなと思い、PoC としてパッケージを書いてみました。

github.com

dbt のリネージ情報について

dbt をお使いの方はご存知だと思いますが、dbt は compile 時にプロジェクト全体の DAG(有向非巡回グラフ)の情報を持っています。
Jinja のコンテキスト変数 graph.nodesgraph.sources を通じて、どのモデルがどのソースやモデルに依存しているかが全てわかります。

最近は MCP で BigQuery へアクセスできるので、リネージの情報が BigQuery 上にあれば、わざわざ Claude 等にリポジトリを渡さなくても依存関係を調べられて便利そうですよね。

仕組み

dbt-bigquery-lineage-sync は、2つのコンポーネントで構成されています。

nodes と edges のモデル

github.com

github.com

nodes と edges というモデルを dbt build すると、dbt の manifest にあるリネージ情報をマクロで参照して BigQuery に incremental model として保存します。
profile_name ごとに分けて保存しているのは、dbt で複数環境に分けて開発する場合は profile_name で環境を分けることが多いためです。

create_or_replace_lineage_graph マクロ

github.com

nodes と edges を保存するだけでも有用ですが、create_or_replace_lineage_graph マクロを使うことで Property Graph を定義でき、今回の Preview 機能である GQL を使ってリネージを調べられるようになります。

使い方

セットアップ

packages.yml に追加して dbt deps するだけです。

packages:
  - git: "https://github.com/mashiike/dbt-bigquery-lineage-sync"
    revision: v0.0.0

テーブルの作成とグラフの定義

# 1. ノードとエッジのテーブルを作成
dbt build --select dbt_bigquery_lineage_sync

# 2. Property Graph を作成
dbt run-operation create_or_replace_lineage_graph

これだけです。2段階なのは、Property Graph の DDL が dbt の標準的な materialization ではないため run-operation で実行する必要があるからです。

GQL で調べてみる

グラフができたら、GQL でリネージを調べてみましょう。

モデルの一覧を出す:

GRAPH `infra-dev-281205.dbt_lineage`.`graph`
  MATCH (n:DbtNode)
  WHERE n.resource_type = "model"
  RETURN n.name, n.materialized
  ORDER BY n.name

特定モデルの直接の上流を調べる:

GRAPH `infra-dev-281205.dbt_lineage`.`graph`
  MATCH (upstream:DbtNode)-[e:DependsOn]->(downstream:DbtNode)
  WHERE downstream.name = "orders"
  RETURN upstream.name, upstream.resource_type

3ホップ先まで辿る:

GRAPH `infra-dev-281205.dbt_lineage`.`graph`
  MATCH (src:DbtNode)-[:DependsOn]->{1,3}(dst:DbtNode)
  WHERE dst.name = "customers" AND dst.resource_type = "model"
  RETURN src.name, src.resource_type

この -[:DependsOn]->{1,3} という書き方で「1〜3ホップの範囲で DependsOn エッジを辿る」という意味になります。

「このソースを変更したら影響範囲どこまで?」みたいな問いに、SQL の延長でサクッと答えが出せるのはなかなか便利です。

ノートブックで可視化する:

BigQuery Studio のノートブックでは %%bigquery --graph マジックコマンドを使うと、GQL の結果をグラフとして可視化できます。

%%bigquery --graph
GRAPH `infra-dev-281205.dbt_lineage`.`graph`
  MATCH
    p = ((src:DbtNode)-[:DependsOn]->(dst:DbtNode))
  WHERE dst.name = "customers"
  RETURN TO_JSON(p) AS path

docs.cloud.google.com

この GRAPH 構文を人間が覚える必要があるのか?

GQL のクエリ例をいくつか紹介しましたが、正直なところこの構文を人間が毎回書くのかというと微妙なところです。
冒頭で「MCP で BigQuery にアクセスできるなら便利そう」と書きましたが、MCP Toolbox for Databases を使えば Claude Code から BigQuery に直接アクセスできます。

docs.cloud.google.com

.mcp.json に以下のように設定するだけです。

{
  "mcpServers": {
    "bigquery": {
      "command": ".bin/toolbox",
      "args": [
        "--prebuilt",
        "bigquery",
        "--stdio"
      ],
      "env": {
        "BIGQUERY_PROJECT": "${BIGQUERY_PROJECT}"
      }
    }
  }
}

さらに、リポジトリにはサンプルの Claude Code スキルも用意しています。

github.com

このスキルを入れておけば、「customers モデルのリネージを可視化してほしい」と聞くだけで GQL を組み立てて実行してくれます。

人間が GRAPH 構文を覚える必要はありません。

まとめ

BigQuery Graph が Preview になったので、dbt のリネージ情報を Property Graph として載せて GQL で調べられるようにする PoC パッケージを作ってみました。
やってみた感想としては、BigQuery Graph と dbt のリネージは相性が良いです。
「このソースを変えたら影響範囲は?」「このモデルの上流3段を辿りたい」みたいなクエリが、BigQuery の中だけで SQL の延長として書けるのは楽です。
グラフデータベースを別途用意する必要がないのも嬉しいですね。

まだ PoC なので粗い部分はありますが、興味のある方はリポジトリを試してみてください。
BigQuery Graph がGAになるのが楽しみです。

カヤックでは、データパイプラインを調べるのが好きなエンジニアも募集しています!

Generated with Claude Code