nikkie-ftnextの日記

イベントレポートや読書メモを発信

#技術書典 21にて頒布される #エンジニアニメ Anthology Tech Book第4弾に主キーについて寄稿しています

ピンポンパンポーン
みなさんに 大事なお知らせです

目次

しゅきしゅきソングならぬ

IWSFでの劇的な体験から、主キーについての小話が爆誕しました!

エンジニアニメ Anthology Tech Bookとnikkie

今回の呼びかけ

11/23(月・祝)当日は私は売り子はしてませんが、あ34をよろしくお願いします!
(入口近くなんでしょうか?)

過去の寄稿

GPT-6.1 Sol(中)にしゅきQRコードを無茶振り

私の原稿にYouTube動画へのQRコードを用意したい。再生してもらいやすくするため
QRコードはPythonのライブラリを使って作るつもり
工夫として「しゅき」という文字のシルエットでQRコードにできたらいいなと思う。渡した画像に合わせてQRコードを作れるというのをみたことがある。「しゅき」はSlackのカスタムemojiみたいに領域をマックスに使う感じで

想定を超えるQRコードを作ってきました。
これでしゅきしゅきソングへ飛べます!

スクリプトはこちら
https://gist.github.com/ftnext/e8d3a796d2beae50369bfbff7339ba2a

  1. 「しゅ/き」の元画像を作る
  2. 文字に似たQRコードを作る
  3. 文字が見えやすい版も作る
  4. 読み取りを検証する

終わりに

11/23の技術書典21、エンジニアニメ(あ34)の合同誌をよろしくお願いしまぁす!
この記事では自分の書いた分のみ紹介しましたが、第4弾もす ん ご い ですよ(公式アカウント発信をお楽しみに)

P.S. 11/11にもエンジニアニメ!

Astralがuvと型チェッカtyを実験的に連携。inline script metadata付きのPythonスクリプトをtyの恩恵を受けながら実装できます!

はじめに

inline script metadataはいいぞ。nikkie (UUID 28fb3f96-a221-462c-93bd-567b431715b9) です。

Pythonで激推ししている技術ですが、そんなinline script metadata界隈に私の目からすると大きな動きがありました!

目次

PEP 723 – Inline script metadata

inline script metadataはuvやhatchがサポートしていて、Pythonスクリプトに特殊なコメント(metadata)を書くことで、スクリプト実行時にmetadataに沿った仮想環境が用意されます。

# /// script
# requires-python = ">=3.13"
# dependencies = [
#     "httpx2",
#     "rich",
# ]
# ///

PyCon JP 2024で話し、ことあるごとに推している技術です(私の発表資料のサンプルコードに頻繁に登場しています)

書き慣れたPythonスクリプトが仮想環境管理不要で実装・実行でき、私にとってはシェルスクリプトより多くを表現できるので大変重宝しています。

ヘビーユースしていますが、uvたちが管理する仮想環境に開発者から触りづらいため、エディタの補完の恩恵は受けられずにいました。
こんな工夫をしてみたり

そこに今回のuv-ty連携の登場です!

「Bringing uv and ty together」

Astral1製のPythonプロジェクト管理ツールuvと、型チェッカtyを実験的に統合!

  • uv check --script example.pyでinline script metadataに沿った環境をuvが用意し、そこを見てtyが型チェックします2
  • VS Codeのty拡張でもサポート! tyのサポートを受けながらinline script metadata付きのスクリプトを実装できます

後者が私にとって待望の機能です!3
.vscode/settings.jsonを書いて
https://docs.astral.sh/ty/reference/editor-settings/#experimentaluseuv

{
    "ty.experimental.useUv": "on"
}

後者の動作イメージはこちらの動画(download.mp4)をどうぞ

どのように実現している?

Support for PEP 723 scripts and the uv check command requires uv 0.12.3 or later, and ty 0.0.76 or later.(「Bringing uv and ty together」)

秘密はuv workspace metadata。
--scriptと--sync指定で、inline script metadataに沿った環境を用意してそのパスを返します。

uv 0.12.3で--quiet指定でもJSONを返すように調整(これをtyから指定しています)。
https://github.com/astral-sh/uv/releases/tag/0.12.3

Preserve JSON output from uv workspace metadata --quiet while suppressing diagnostics (#20991)

またtyは0.0.76で準備が整いました!4

Check direct dependencies in PEP 723 scripts (#28136)

Refresh uv project metadata in the background (#27933)

Synchronize PEP 723 script environments in the language server (#27619)

(PR #27619 は上でdownload.mp4を紹介したプルリクエストです)

uvとtyをまさしく連携させて実現しています。
uvってinline script metadataで作った仮想環境のパスを返せるんですね。

終わりに

Astralが打ち出したuv-tyの連携を取り上げました。
inline script metadataを使ったPythonスクリプトがグッと書きやすくなります!
Astral自体はRuffも含めて持っている3つのツールを連携させていく考えのようです。

個人的にはuv workspace metadata --scriptが収穫でした。
ty以外の型チェッカにも渡せるってことでは?(緩く宿題事項)


  1. OpenAIに買収されています↩
  2. マシンにインストール済みのtyは環境変数TYで指定できます。 https://docs.astral.sh/uv/reference/environment/#ty↩
  3. 画像はDevin Desktopにty拡張を入れたものですが、Devin Pyrightと競合してしまっているので、お手元と違ったらごめんなさい(pull requestの方の動画を確認ください)↩
  4. 今回知ったのですが、tyへの機能拡張はRuffのリポジトリで実施されています↩

macOSのメニューバーに常駐するLLMアプリ、Llamaをお試し。LFM3を例にチャットしたり、OpenAI互換APIを叩いたり

Hugging Faceの新作、Llamaを導入しました(この記事では0.46.1を動かしています)。
https://llama.app/

目次

Llama

※MetaのLLM、Llamaとは別です。ググラビリティが低いよ〜
https://huggingface.co/meta-llama

macOSのメニューバーに常駐し、ローカルでLLMを動かすアプリです。

冒頭の動画より

  • モデルの候補をクリックしてダウンロード
  • ダウンロードするだけで、チャットがローカルPCのブラウザで動かせます
  • OpenAIのChat にcompletions API互換のAPIも生えます

READMEの「How it works」

If you have llama.cpp installed, Llama uses it. Otherwise, it installs a prebuilt binary for your Mac.

You can install any GGUF model from Hugging Face,

llama.cppを使っているんですね。
実際私の環境にもllamaコマンドが生えてました。

LFM3をダウンロードするだけで動かせた!

www.liquid.ai

メニューバーのLlamaから、ブラウザでモデルを確認。
https://llama.app/models/lfm-3-omni
Q4_K_M(1.10 GB)1をダウンロードしただけです。

サクサク動きます!(LFM3が小さいからだと思います)

ローカルのAPIもお試し

過去に触ったOpenAI CLI2を、ローカルのChat completions互換APIに向けてみます3。

% openai --version
openai version 1.38.0
% OPENAI_BASE_URL=http://localhost:9931/v1 OPENAI_API_KEY=dummy openai chat:completions create --model ggml-org/LFM3-Omni-2B-GGUF:Q4_K_M --message '{role: user, content: "こんにちは"}'
Choices:
  1.
    Finish reason: stop
    Index: 0
    Message:
      Role: assistant
      Content: こんにちは! こんにちは! どういたしまして。何かお手伝いできることはありますか?
Created: 1793538618
Model: ggml-org/LFM3-Omni-2B-GGUF:Q4_K_M
System fingerprint: b11941-19ff817fb
Object: chat.completion
Usage:
  Completion tokens: 22
  Prompt tokens: 11
  Total tokens: 33
  Prompt tokens details:
    Cached tokens: 0
ID: chatcmpl-Hym8HQc9evG2nn3WEV7aTBx28WtHMvdC
Timings:
  Cache n: 0
  Prompt n: 11
  Prompt ms: 733.741
  Prompt per token ms: 66.70372727272728
  Prompt per second: 14.991665996584626
  Predicted n: 22
  Predicted ms: 296.38
  Predicted per token ms: 14.113333333333333
  Predicted per second: 70.85498346717053

過去記事のように要約もできます!
メニューバーからContext lengthを初期値の4kから32kに上げました。

% markitdown --version  # uv tool installしています
markitdown 0.1.9
% markitdown https://www.liquid.ai/blog/lfm3 -o lfm3-article.md
% OPENAI_BASE_URL=http://localhost:9931/v1 OPENAI_API_KEY=dummy openai chat:completions create --model ggml-org/LFM3-Omni-2B-GGUF:Q4_K_M --message '{role: system, content: "日本語で300字で要約してください"}' --message '{role: user, content: "@lfm3-article.md"}'

終わりに

Llama、簡単に使えて好感触です。
これまではOllamaをもふもふしていましたが、LFM3が軽いモデルだからか、今回触ってLlamaの可能性を感じました。

(Twitterに上げた画像をこちらにも。OGP用でもあります)


  1. Show smaller quantizationsのトグルを有効にしています↩
  2. ↩
  3. 管理しているmiseからバージョンを上げてみたのですが、バージョン表示は1.38.0のままでした。出力形式がJSONでなくなったような(未切り分け)↩

11/4(水)のお昼にFindyさんのオンライン勉強会にて、2026年のPython環境構築について、uvにどこまで任せるか話します #python_findy

ばーん!

目次

Python環境構築を、もう一度考える ~uvに任せていいのはどこまで?~

11/4(水)のお昼開催です。

findy.connpass.com

つながるアウトプット

今年は7月にFindyさんにインタビュー記事を掲載いただきました。
Findyさんのインタビューにて、uvに至るPythonパッケージ管理ツールの変遷を好きに語りました - nikkie-ftnextの日記

また8月に同様の話題を別の切り口でPyCon JP 2026で話しました。
インタビュー実施とPyCon JP 2026のプロポーザル募集期間が重なっていたのですが、3月のPythonAsia1のあたりから私が考えているテーマなんですよね。

なお、PyCon JPの発表は、Findyさんのブログでも紹介いただいています。
聞きに来て下さり、ありがとうございます!

こういったご縁からこのたび主演公演の機会をいただきました。
インタビュー記事やPyCon JPの発表資料につながる前段のところを多めに話そうと絶賛準備中です。
ふだんPythonではない方や、インタビューや発表資料を見てもよくわからなかったという方、お昼のラジオとして一部だけでもお耳を傾けていただけたら嬉しいです。

証明書の件など、PyCon JPからのアップデートも多少盛り込もうと画策しています。お楽しみに


  1. ↩

Rustのmain関数の中でResultに?を使ったときに怒られるの、なんでだろう?(E0277)

はじめに

ああああああああああああああ!!!!!!!!!!!nikkie (UUID 28fb3f96-a221-462c-93bd-567b431715b9) です。

エミリーちゃんの主演公演を機に、自作PythonパッケージをRustで書き直しています1(ここ怪文書注意)。
今回はResultの理解を深めました。

目次

main()でResultに?すると怒られる

例としてHTTPクライアントureqを試します。
https://docs.rs/ureq/latest/ureq/

% cargo --version
cargo 1.99.1 (5f94df478 2026-08-27)
% rustc --version
rustc 1.99.1 (58cf8f9c3 2026-10-13)
% cargo new hello-ureq
% cd hello-ureq
% cargo add ureq

サンプルコードをmain.rsのmain()に貼ると
(Devin Desktop 3.11.228のrust-analyzer 0.3.3097あたりです2)

ここでコンパイラが何を言っているのか理解することにしました。

?はErrをreturnしている

The Rust Programming Languageにドンピシャな解説がありました。

日本語版で「エラー委譲のショートカット: ?演算子」を見ていきます

エラー委譲とはエラーのreturnです。

    // リスト9-6の抜粋
    let username_file_result = File::open("hello.txt");
    let mut username_file = match username_file_result {
        Ok(file) => file,
        Err(e) => return Err(e),  // エラー委譲
    };

これを短く書くのが?です!

    let mut username_file = File::open("hello.txt")?;

Result値の直後に置かれた?は、リスト9-6でResult値を処理するために定義したmatch式とほぼ同じように動作します。

Resultの値がOkなら、Okの中身がこの式から返ってきて、プログラムは継続します。
値がErrなら、 returnキーワードを使ったかのように関数全体からErrが返ってくるので、エラー値は呼び出し元のコードに委譲されます。

(「ほぼ同じ」であり、違いについても解説されています)

main()関数の返り値に?の使用と互換性がなかった

「?演算子が使用できる場所」より

リスト9-10で、?を使用する対象の値の型と戻り値の型に互換性がないmain関数で、 ?演算子を使用した場合に得られるエラーを見てみましょう:

use std::fs::File;

fn main() {
    let greeting_file = File::open("hello.txt")?;
}

これ、私が書いて怒られていたureqのコードと同じなんですよね

?演算子はFile::openによって返されるResult値を確認して対処しますが、このmain関数はResultではなく()の戻り値型を持っています。

main()関数の返り値の型の問題と気づいて、なぜ直るのかも得心しました(これまではAI補完を採用したら直ったので何も分かってませんでした...)

fn main() -> Result<(), Box<dyn std::error::Error>>{  // 型を書く
    let body: String = ureq::get("http://example.com")
        .header("Example-Header", "header value")
        .call()?
        .body_mut()
        .read_to_string()?;
    println!("{}", body);
    Ok(())  // Okのケースの返り値を示す
}

今のところは、Boxは「任意の種類のエラー」を意味するものと理解してください。

終わりに

RustのResultの?の理解が深まりました。
Errをreturnするを短く書いているので、関数の返り値の型でそれを示す必要がある!

Swiftで初めて(オプショナルチェーンの)?に触れていた3のですが、RustのResultの?はそれと同じと誤解していました。
あえてドキュメントを訪れたことでピンポイントな解説と出会え、一歩以上先へ踏み出せました!


  1. ↩
  2. Devin Desktopはアップデートが速く、また拡張も自動でアップデートされるので、バージョン番号は参考程度にお願いします↩
  3. いにしえのスライド:https://www.slideshare.net/slideshow/ss-67821847/67821847↩

ADK Community Call (October 2026) ライブ参加メモ

はじめに

㊗️アイうた5周年!nikkie (UUID 28fb3f96-a221-462c-93bd-567b431715b9) です。

10/29(木)AM1:30〜2:30(JST)に行われたADK Community Callで知った事項を残します。
睡魔と戦いながら参加しました(翌日あるので途中離脱)。

9月の参加はこちら

目次

アジェンダ

予告のメールより
https://groups.google.com/g/adk-community/c/jSpzT9NdW60

  • ModelConsultTool (Mid-Task Escalation): Keep bulk execution fast and cheap on Gemini Flash while consulting Gemini Pro as an advisor only on tricky edge cases
  • Skill Lifecycle Management: Prevent context bloat and leftover tools in long sessions with new BOUNDED (LRU), EPHEMERAL, and on-demand unload_skill modes.
  • Classifier API & Jev (~170ms Agent Decisions): Route workflows and gate high-risk tool calls 4–12x faster than standard LLM prompts, featuring a live side-by-side browser agent demo.
  • How Gemini 4 Argon Sped Up ADK by 40%: What happened when we gave Argon one /goal prompt and our .agents/skills review rules

ADK Community Callはアーカイブのplaylistがあるので、少し待てば公開されると思います(でも9月がまだ入ってないような...)

ModelConsultTool

v2.11.0で追加

ModelConsultTool: Let an agent consult another model mid-task, capped by per-turn and per-session budgets. See the unit guide for more details. (84cc99a)

adk-python内のunit guide
https://github.com/google/adk-python/blob/v2.13.0/docs/guides/tools/model_consult/model_consult_tool/index.md

サンプルより1

root_agent = Agent(
    name='order_support_agent',
    description='Handles customer order returns, warranty defect bulletins, and loyalty refund policies.',
    instruction=_TASK_INSTRUCTION,
    tools=[
        get_order,
        get_customer_profile,
        issue_refund,
        ModelConsultTool(  # 🈁
            max_uses=2,
            session_max_uses=5,
            thinking_level='high',
        ),
    ],
)

Skill Lifecycle Management

ADKはv1.25.0でAgent Skillsをサポートしていますが、v2.10.0でそのコンテキスト管理(Lifecycle Management)を追加!

Skills: Control resource usage and tool persistence dynamically using new ephemeral lifecycles and active skill limits (experimental; enable with ADK_ENABLE_SKILL_LIFECYCLE=1). (43b73e4)

ガイドからControl how long skills stay active

The PERSISTENT mode is the default. The skill stays active for the rest of the session.

The BOUNDED mode works like PERSISTENT, except that at most max_active_skills bounded skills can be active for an agent at once.

The EPHEMERAL mode keeps the skill active for the rest of the turn that loaded it and releases it when the next turn begins.

toolset = SkillToolset(
    skills=skills,  # your own list of skills
    lifecycle_config=SkillLifecycleConfig(
        default_mode=SkillLifecycleMode.BOUNDED,
        max_active_skills=3,
        skill_overrides={"incident-report": SkillLifecycleMode.EPHEMERAL},
    ),
)

skill(特定の専門知識)をコンテキストに入れたまま何十ターンも連れ回すのか? その必要がない場合の選択肢が入ったのは個人的に好感触です。

Classifier API & Jev

大バズりのSystem One ModelにもADKは飛びついていきます!(v2.13.0)

Classifiers: Route workflows with TypeSafe's Jev models via the new TypesafeClassifier and ClassifierNode. Jev returns calibrated probabilities in a single forward pass, much faster than an LLM. See the unit guide for more details. (ddf8c55, e8c4bac)

unit guideは2つ

サンプルも2つ

(1) ADK Workflow Classifier Routing Sample

Jevでない例です

classifier = LlmClassifier(model="gemini-3.5-flash")

triage = ClassifierNode(
    name="triage",
    classifier=classifier,
    question=Choice(
        instructions="Which team should handle this support ticket?",
        criteria={
            "billing": "Invoices, refunds, or subscription charges",
            "technical": "Bugs, errors, outages, or API problems",
            "general": "Product questions and anything else",
        },
    ),
    answer_key="triage_answer",
)

(2) Classifier Tool Gate Sample

before_tool_callbackに渡す関数でLlmClassifierを使います。
https://github.com/google/adk-python/blob/v2.13.0/contributing/samples/hitl/classifier_tool_gate/tool_gate.py#L50

Before each tool call, the callback asks classifier a Binary question about the call. If the probability of true is at or above threshold, the call is blocked, or held until the user confirms it.

コーディングエージェントのauto mode(代理で承認モード)がADKのエージェントで実現できていそうです。

How Gemini 4 Argon Sped Up ADK by 40%

v2.12.0でArgonによる改善が入っています

Performance: Cut time to first model request by 40% in long sessions. (1754b3e)

コミットメッセージ抜粋

                                         before    after
first model request after 50 turns *      64 ms    36 ms   -43%
first model request after 150 turns *    200 ms   122 ms   -39%

adk-pythonにはAgent Skillsが整備されており、
https://github.com/google/adk-python/tree/main/.agents/skills
Argonにそれらを装備してうまくいったという報告です。

With .agents/skills in the repo and /goal mode active, Argon ran unattended for 11 hours overnight (Figure 3).(Googleブログより)

終わりに

10月のADK Community Callで知った情報を書き出しました。
ModelConsultTool、SkillLifecycleConfig、LlmClassifier、これらを使うことでこれまでできなかったエージェントの開発ができそうと可能性を感じています。

そしてこの記事では取り上げきれませんでしたが、実は他にもリリースがあります(YouTubeアーカイブ出てくれ!)

2026年10月28日(水)のリリース

はじめに

あの母にしてこの子あり nikkie (UUID 28fb3f96-a221-462c-93bd-567b431715b9) です。

毎週水曜のリリース報告エントリです1。

目次

flake8-llm-sunset 0.0.8

https://pypi.org/project/flake8-llm-sunset/0.0.8/

「モデルの廃止日が近いよ」と検出するリンタです。
現在はGoogleのモデル(Geminiたち)のみ対応しています。
前回:2026年10月21日(水)のリリース - nikkie-ftnextの日記

ドキュメントの変更に追従しました。
画像モデルが2026-06-30付けで廃止と記載されています。

こんなに細かい変更をなぜ取り込めたかというと、実装の自動化を進めているからです。

今週のリリースは以上です

終わりに

今週は脆弱性を追いかけており(Brotli2、そしてeMudhra3)、リリースは小粒です

来週は1年前、二階堂千鶴さんでした。楽しかった、Grand bal masqué!


  1. 始めたきっかけは765プロです(頭ミリオン) 2025年4月2日(水)のリリース - nikkie-ftnextの日記↩
  2. ↩
  3. 一連の記事の末に ↩