Podcast - Backyard Hatena
TechTalk - Google Cloud Born Digital Summit
ぽ靴な缶
ブログに書きたいと思いつつ書いてない話の供養です Google Open Source Peer Bonus Award 頂きました Dataform へのコントリビュートで貰った、2023 年末の話... Majestouch Xacro M10SP 良い 自作に手を出したくないが分割キーボードは欲しい、このマクロキーの配置は良くめっちゃ使ってる はてなインターン 2024 で AI に関する講義をした 時流にあわせて AI の話をする、歴史っぽい話から、ベンチマーク鵜呑みにするなよという話 東京大学松尾・岩澤研「大規模言語モデル2024」の公開講義を受講した 最終課題は受講生同士でバトルするコンペ、3000人?中、一般8位&コントリビューション3位になった、これはちゃんと書きたい Modern App Summit '25 基調講演で話した Google Cloud イベントの基調講演中の 10 分枠で発表した、短いし楽かと思いきや自分のトークを聞きに来てない聴衆に話すのは難しい、ふわっとした話になって反省 もっと細かく書きたいとは思っています。思ってはいる。
ぽ靴な缶
AI と一緒に作った。このようなテーマ。 pokutuna.vscode-gnome2like-theme marketplace.visualstudio.com このテーマは Emacs の color-theme.el に含まれる color-theme-gnome2 を起源とした配色です。 故郷 学生の頃、2008 年あたりにから Emacs を使い始め、仕事でも長く Emacs を使っていたけど、TypeScript の書く体験の良さから徐々に VSCode の比率が上がっていったり Live Share でペアプロをする必要が出たりして、今では VSCode がメインエディタになってしまった。今ではほぼ Emacs を起動していないが、Emacs を故郷《ふるさと》にように思っている。 当時 Emacs では color-theme.el の color-theme-gnome2 を愛用していた。 emacsmirror/color-theme-modern より引用 この Dark でも Light でもない緑ベースのテーマの中で、あらゆるプログラミング活動を行っていたよな。 この配色が好きで VSCode に持っていきたいと思っていたが、指定する色数が多く腰が重かった。 Emacs に比べると VSCode テーマで指定しなきゃいけない色数はめちゃくちゃ多く、過去のメモによると 2019 年ごろにもトライして飽きている。せっかくコーディングエージェントが流行っているので改めてやってみようと思い立って実装した。 Roo Code と sonnet 3.7 と gemini-2.0-pro-exp (書いてる時は 2.5 出てなかった) に指示を出すと、あれよあれよとできていき、完成度 70% ぐらいまですぐ行けた。 今や VSCode がメインエディタとなって久しいが、Emacs 時代にずーーっと愛用していた color-theme.el の gnome2 テーマを Roo Code と一緒に VSCode に再現している、整っていくにつれ懐かしさで泣きそう pic.twitter.com/BSRclQTgRb — pokutuna (@pokutuna) 2025年3月2日 とはいえここからが長く、UI 上の指定が足りないところや syntax highlight のトークンごとの指定、一貫性に欠ける部分を修正していく必要があった。 仕事しながら2週間ぐらい使って不満があらかた消えたので、公開することにした。 こちらからどうぞ。 GNOME2-like Theme - Visual Studio Marketplace 黒すぎず白すぎず、目に優しいユニークで好ましいテーマですね。 作業中に使っている都合で Cline/Roo でもそれなりの見た目です。 badge.background や badge.foreground を token 数とか出てるパネルに使うのは違うんじゃないかと思うが、バッジとしてもパネルとしても違和感ない色に着地させる。 RooCode 当初はベタ移植を考えていて color-theme.el 全部 VSCode に持ってきたら面白いんじゃないかと考えたけど、VSCode の UI に合わせて色数をだいぶ補う必要があり、思い入れのないテーマの色を変に AI で補って完成させても誰も嬉しくないだろなぁとやめた。自分が愛用していた gnome2 のみを、色を補ったりアレンジした点もあるので -like suffix をつけ公開することにした。これはこれでウィンドウマネージャの GNOME 側に失礼な気もしなくはないが、そこは color-theme.el 時代からそうだということで。 半ばこの類の緑色がアイデンティティ化していて、このブログのテーマもそうだし、キャラエディットできる系だと緑を入れちゃうんだよな。覚えやすい ■#008080 を使いがち。 AC6 ノウハウ VSCode カラーテーマ JSON の色部分を消して、テンプレートとして埋めてくださいと指示する Emacs の色名は hex とのマッピングを csv で与えるとよい pokutuna/vscode-gnome2like-theme@main - resources/colornames.csv color-theme.el 巨大なので必要な部分だけ切って与える、GPL なので派生著作物も GPL にする テーマ = VSCode 拡張の開発は Debugger で行うのだが、テーマ JSON そのままは拡張だと思ってくれないので以下を .vscode/launch.json に置くとよい { "version": "0.2.0", "configurations": [ { "name": "Extension", "type": "extensionHost", "request": "launch", "args": [ "--extensionDevelopmentPath=${workspaceFolder}" ] } ] } UI から色の設定名を特定するには Theme Color | Visual Studio Code Extension API をじっくり見る VSCode 中の Developer Tools を開いて var() や Computed から辿る シンタックスハイライトにおいて特定の言語に依存したトークンの記述は最小限にしたいのでそう指示する & ある程度できたら置き換えさせる ストア公開用のスクショを取るためのスクリプトも AI に書いてもらった ユーザディレクトリ切り替えていい感じにできない? と頼むと Portable mode を使いつつ、開発中のテーマに symlink 張って開いてサンプルコードを開くスクリプトを書いてもらえた これは自分で作るとちょっと面倒くさかっただろうなと思う、これを実行してウィンドウ分割してコード並べてスクショ撮るのが俺の仕事 pokutuna/vscode-gnome2like-theme@main - resources/samples/setup_screenshot.sh AIエディタCursor完全ガイド ―やりたいことを伝えるだけでできる新世代プログラミング― 作者:木下雄一朗 オーム社 Amazon Cursor完全入門 エンジニア&Webクリエイターの生産性がアップするAIコードエディターの操り方 作者:リブロワークス インプレス Amazon
ぽ靴な缶
この記事は はてなエンジニアアドベントカレンダー 2024 5 日目の記事です。 昨日は id:susisu さんの Data types à la carte in TypeScript でした。 本人が「アクセス増えたと思ったら別の記事で、全然読まれてない...」と言っていたので「いきなりフランス語で難しそうやからね」と伝えました。本文は日本語なので、みなさんも読んで下さい。 今日は最近見て面白かったコードの紹介です。 ChatGPT が流行って以来、アプリでストリームのレスポンスをよく見るようになりました。 LLM によるテキスト生成はわりと時間がかかる処理で、もしすべて生成し終えてからレスポンスするとユーザーを待たせてしまうからでしょう。テキストがちょっとずつ表示される UI は昔からあるものですが、LLM を使ったアプリケーションが出てきて以来、演出としてではなく実用としてよく見られるようになったと思います。 各社が提供している LLM の API を利用する場合も、大抵ストリームでレスポンスを受け取る方法も提供されています。また自然文の生成だけでなく、指定したスキーマを埋めて JSON で構造化されたデータを返してくれる機能があります。アプリケーションに組み込みやすくて重宝しますね。 では LangChain で JSON のレスポンスストリームを読んでいる様子を見てください これは Gemini API のレスポンスを JsonOutputParser に渡していて、チャンクを受信するたびにパース結果を出力しています。 JsonOutputParser え!?!? 今みた!?!? もっとわかりやすく1文字ずつバッファに書き込んでいってパースさせてみましょう。 1文字ずつ おわかりいただけだろうか... まだリテラルが終わっていない段階でパースされた値が得られているのを... stream: {"name": "p parsed: {"name": "p"} ↑ この段階で name の値が p としてパースされてる!! stream: {"name": "pokutuna", "age": 1 parsed: {"name": "pokutuna", "age": 1} ↑ age: 1 の瞬間がある!! stream: { ... "food": ["tonka parsed: { ... "food": ["tonka"]} ↑ まだ Array 閉じてないのに!! JSON ストリームの読み込みは、いろいろなライブラリで実装されています。 例えば、NDJSON に対して行ごとにオブジェクトを受け取れるものや、JSON Path で値をひっかけるもの、SAX-like な特定のトークンが来たらコールバックを受け取るもの (もう SAX という響きが懐かしいぞ)など。 でも LangChain のこのパターンを見るのは始めてで、なにそれ!? と思ってコードを見に行きました。 この動作はこの parse_partial_json で実装されています。 github.com 文字列の開始のダブルクオートや、Object や Array の開きカッコなど、開始トークンが来るたびに、対応する閉じトークンを積んでいって、最後に reverse してくっつけて補完して json.loads しています。なかなか勢いのある実装。 内容を正確にパースをするという観点からは許されるか怪しい、レスポンスを途中までしか受け取ってないからといって、お小遣い3円の瞬間があっていいのか? しかし { "message": "長いテキスト長いテキスト長いテキスト長いテキスト... のような文字列の終わりを待ってずっと値を使えないなら、レスポンスをストリームすることで本来得たいユーザを待たせない体験が得られません。 実装も富豪的で、全体のパースを試して失敗したら1文字ずつ読んでカッコ等を積んでいく、ダメなら末尾を捨てていって試す、と何回 json.loads するつもりなのか。 これは JsonOutputParser 全体で、自然文中に JSON が含まれるレスポンス はい、指示に従って JSON で回答します。 ```json {"hoge": "fuga", ... みたいな出力もパースできるようにするためですね。 大抵「ストリームで JSON を処理したい」というと、超巨大なログを扱うとか、一度にメモリに読み込みたくないとか、実行時のリソースに意識があります。しかし LangChain のこの実装はユーザを待たせないため、途中でもいいから値を返す、Object や Array だけでなく、文字列や数値すら途中で返してしまう、AI との会話文ストリームからも取り出す、というのが面白いですね。そんなちょっとした観光名所でした。 途中の stream.py はこれ stream.py · GitHub この記事は はてなエンジニアアドベントカレンダー 2024 5 日目の記事です。 id:miki_bene さんです!! { entries.forEach(entry => { if (entry.isIntersecting) { typeText(); } else { clearTimeout(animationId); } }); }); observer.observe(element);
ぽ靴な缶
はてな 生成AI×新規事業 の挑戦 〜生成AIを学びながら技術とチームを磨いた事業立ち上げの道のり〜 - connpass speakerdeck.com 何の因果か新規事業立ち上げ & AI 担当みたいな仕事をしております。 話題で分類するとなるとトピックモデルか? と思うけど、Vertex AI の Embedding API に task_type="CLUSTERING" を見つけ、クラスタリングでそこそこのものが出たのでそれで行くことに。改善の余地は様々ありますがとにかく HDBSCAN の性質に助けられた機能だったなと思います。 密度ベースのクラスタリング 異なる密度レベルのクラスタ得られる クラスタ形状の変化に柔軟 階層構造得られる ハイパラ調整がほぼ要らない 都合が良すぎる。 メイン図 手法の図
Checked other resources I added a very descriptive title to this issue. I searched the LangChain.js documentation with the integrated search. I used the GitHub search to find a similar question and didn't find it. I am sure that this is a bug in LangChain.js rather than my code. The bug is not resolved by updating to the latest stable version of LangChain (or the specific integration package). Example Code Make the model output long texts containing multibyte characters as a stream. import { VertexAI } from "@langchain/google-vertexai"; // Set your project ID and pass the credentials according to the doc. // https://js.langchain.com/docs/integrations/llms/google_vertex_ai const project = "YOUR_PROJECT_ID"; const langchainModel = new VertexAI({ model: "gemini-1.5-pro-preview-0409", location: "us-central1", authOptions: { projectId: project }, }); // EN: List as many Japanese proverbs as possible. const prompt = "日本のことわざをできるだけたくさん挙げて"; for await (const chunk of await langchainModel.stream(prompt)) { process.stdout.write(chunk); } Error Message and Stack Trace (if applicable) (No errors or stack traces occur) Output Example: Includes Replacement Characters (�) ## ������������:知恵の宝庫 日本のことわざは、長い歴史の中で培われた知恵や教訓が詰まった、短い言葉の宝庫で������いくつかご紹介しますね。 **人生・教訓** * **井の中の蛙大海を知らず** (I no naka no kawazu taikai wo shirazu): 狭い世界しか知らない者のたとえ。 * **石の上にも三年** (Ishi no ue ni mo san nen): ������強く努力すれば成功する。 * **案ずるより産むが易し** (Anzuru yori umu ga yasushi): 心配するよりも行動した方が良い。 * **転�������������** (Korobanu saki no tsue): 前もって準備をすることの大切さ。 * **失敗は成功のもと** (Shippai wa seikou no moto): 失敗から学ぶことで成功�������る。 **人���関係** * **類は友を呼ぶ** (Rui wa tomo wo yobu): 似た者同士が仲良くなる。 * **情けは人の為ならず** (Nasake wa hito no tame narazu): 人に親切にすることは巡り巡��て自分に良いことが返ってくる。 * **人の振り見て我が振り直せ** (Hito no furi mite waga furi naose): 他人の行動を見て自分の行動を反省する。 * **出る杭は打たれる** (Deru kui wa utareru): 他人より目���つ��叩かれる。 * **三人寄れば文殊の知恵** (Sannin yoreba monju no chie): みんなで知恵を出し合えば良い考えが浮かぶ。 ... Description This issue occurs when requesting outputs from the model in languages that include multibyte characters, such as Japanese, Chinese, Russian, Greek, and various other languages, or in texts that include emojis 😎. This issue occurs due to the handling of streams containing multibyte characters and the behavior of buffer.toString() method in Node. langchainjs/libs/langchain-google-gauth/src/auth.ts Line 15 in a1ed4fe data.on("data", (data) => this.appendBuffer(data.toString())); When receiving a stream containing multibyte characters, the point at which a chunk (readable.on('data', ...) is executed) is may be in the middle of a character’s byte sequence. For instance, the emoji "👋" is represented in UTF-8 as 0xF0 0x9F 0x91 0x8B. The callback might be executed after only 0xF0 0x9F has been received. buffer.toString() attempts to decode byte sequences assuming UTF-8 encoding. If the bytes are invalid, it does not throw an error, instead silently outputs a REPLACEMENT CHARACTER (�). https://nodejs.org/api/buffer.html#buffers-and-character-encodings To resolve this, use TextDecoder with the stream option. https://developer.mozilla.org/en-US/docs/Web/API/TextDecoder/decode Related Issues The issue has been reported below, but it persists even in the latest version. #4113 The same issue occurred when using Google Cloud's client libraries instead of LangChain, but it has been fixed. googleapis/nodejs-vertexai#78 googleapis/nodejs-vertexai#86 I will send a Pull Request later, but I am not familiar with this codebase, and there are many google-related packages under libs/ which I have not grasped enough. Any advice would be appreciated. System Info macOS node v20.12.2 langchain versions $ npm list --depth=1 | grep langchain ├─┬ @langchain/community@0.0.54 │ ├── @langchain/core@0.1.61 │ ├── @langchain/openai@0.0.28 ├─┬ @langchain/google-vertexai@0.0.12 │ ├── @langchain/core@0.1.61 deduped │ └── @langchain/google-gauth@0.0.12 ├─┬ langchain@0.1.36 │ ├── @langchain/community@0.0.54 deduped │ ├── @langchain/core@0.1.61 deduped │ ├── @langchain/openai@0.0.28 deduped │ ├── @langchain/textsplitters@0.0.0 │ ├── langchainhub@0.0.8
Fixes #6501 I have fixed this issue similarly to #5286. The approach is the same, but we need to use components that work in the Browser environment instead of Node. I previously fixed the same issue for @langchain/google-vertexai in #5285. Although I don't use @langchain/google-vertexai-web myself, I've also fixed this package as it was requested in the issue.
Checked other resources I added a very descriptive title to this issue. I searched the LangChain.js documentation with the integrated search. I used the GitHub search to find a similar question and didn't find it. I am sure that this is a bug in LangChain.js rather than my code. The bug is not resolved by updating to the latest stable version of LangChain (or the specific integration package). Example Code Make the model output long texts containing multibyte characters as a stream. import { VertexAI } from "@langchain/google-vertexai-web"; const langchainModel = new VertexAI({ model: "gemini-1.5-pro-001", location: "us-central1", }); // EN: List as many Japanese proverbs as possible. const prompt = "日本のことわざをできるだけたくさん挙げて"; const stream = await langchainModel.stream(prompt); const reader = stream.getReader(); let buf = ""; while (true) { const { done, value } = await reader.read(); if (done) break; buf += value; } console.log(buf); This code can be executed by creating a service account key from the Google Cloud Console and running it with the following command: $ GOOGLE_WEB_CREDENTIALS=$(cat ./key.json) npx tsx sample.ts Error Message and Stack Trace (if applicable) (No errors or stack traces occur) Output Example: Includes Replacement Characters (�) ## ���本の諺 (ことわざ) - できるだけたくさん! **一般的な知������������** * 石の上にも三年 (いしのうえにもさんねん) - Perseverance will pay off. * 七転び八起き (ななころびやおき) - Fall seven times, stand up eight. * 継続は力なり (けいぞくはちからなり) - Persistence is power. * 急がば回れ (い��がばまわれ) - Haste makes waste. * 井の中の蛙大海を知らず (いのなかのかわずたいかいをしらず) - A frog in a well knows nothing of the great ocean. * 良���は���に苦し (りょうやくはくちにくい) - Good medicine tastes bitter. * 猿も木から落ちる (さるもきからおちる) - Even monkeys fall from trees. * 転石苔を生ぜず (てんせきこけをしょうぜず) - A rolling stone gathers no moss. * 覆水盆に返らず (ふくすいぼんにかえらず) - Spilled water will not return to the tray. * 後生の祭り (ごしょうの�����り) - Too late for regrets. * 習うより慣れろ (ならうよりなれろ) - Experience is the best teacher. * 鉄は熱いうちに打て (てつはあついうちにうて) - Strike while the iron is hot. ... Description This is the same issue as #5285. While #5285 is about @langchain/google-vertexai, this issue also occurs in @langchain/google-vertexai-web. The problem occurs when a stream chunk is cut in the middle of a multibyte character. For detailed reasons, please refer to #5285. I will submit a Pull Request with the fix shortly. System Info macOS node v20.12.2 langchain versions $ npm list --depth=1 | grep langchain ├─┬ @langchain/google-vertexai-web@0.0.25 │ ├── @langchain/core@0.2.23 │ └── @langchain/google-webauth@0.0.25 ├─┬ @langchain/google-vertexai@0.0.25 │ ├── @langchain/core@0.2.23 deduped │ └── @langchain/google-gauth@0.0.25 ├─┬ langchain@0.2.15 │ ├── UNMET OPTIONAL DEPENDENCY @langchain/anthropic@* │ ├── UNMET OPTIONAL DEPENDENCY @langchain/aws@* │ ├── UNMET OPTIONAL DEPENDENCY @langchain/cohere@* │ ├── UNMET OPTIONAL DEPENDENCY @langchain/community@* │ ├── @langchain/core@0.2.23 deduped │ ├── UNMET OPTIONAL DEPENDENCY @langchain/google-genai@* │ ├── @langchain/google-vertexai@0.0.25 deduped │ ├── UNMET OPTIONAL DEPENDENCY @langchain/groq@* │ ├── UNMET OPTIONAL DEPENDENCY @langchain/mistralai@* │ ├── UNMET OPTIONAL DEPENDENCY @langchain/ollama@* │ ├── @langchain/openai@0.2.6 │ ├── @langchain/textsplitters@0.0.3
Environment KFP SDK version: kfp==2.0.0b16 All dependencies version: kfp==2.0.0b16 kfp-pipeline-spec==0.2.2 kfp-server-api==2.0.0b1 Steps to reproduce When running the code snippet below the following error is raised: kfp.components.types.type_utils.InconsistentTypeException: Incompatible argument passed to the input 'val_a' of component 'add': Argument type 'STRING' is incompatible with the input type 'NUMBER_INTEGER' @dsl.component() def add(val_a: int, val_b: int) -> int: return val_a + val_b @dsl.pipeline() def model_training_pipeline() -> None: with dsl.ParallelFor( items=[{"a": 1, "b": 10}, {"a": 2, "b": 20}], parallelism=1 ) as item: task = add(val_a=item.a, val_b=item.b) compiler.Compiler().compile( pipeline_func=model_training_pipeline, package_path="/app/pipeline.yaml" ) Expected result According to the ParallelFor documentation, the code sample above should compile without errors. The add component should receive the values of the dictionaries as integer arguments. Materials and Reference The code snippet below is a modification of the code snippet above, changing the add component to accept string arguments. @dsl.component() def add(val_a: str, val_b: str) -> int: return int(val_a) + int(val_b) @dsl.pipeline() def model_training_pipeline() -> None: with dsl.ParallelFor( items=[{"a": 1, "b": 10}, {"a": 2, "b": 20}], parallelism=1 ) as item: task = add(val_a=item.a, val_b=item.b) compiler.Compiler().compile( pipeline_func=model_training_pipeline, package_path="/app/pipeline.yaml" ) The pipeline compiles without errors with this modification, however it fails to run in Google Vertex Pipelines. The add component doesn't even run and throws the following error in the UI: Failed to evaluate the expression with error: INVALID_ARGUMENT: Failed to parseJson from string.; Failed to evaluate the parameter_expression_selector. As the component's code is not even executed, it seems that the problem occurs when executing the DAG. Here is the content of the pipeline.yaml that was compiled. # PIPELINE DEFINITION # Name: model-training-pipeline components: comp-add: executorLabel: exec-add inputDefinitions: parameters: val_a: parameterType: STRING val_b: parameterType: STRING outputDefinitions: parameters: Output: parameterType: NUMBER_INTEGER comp-for-loop-2: dag: tasks: add: cachingOptions: enableCache: true componentRef: name: comp-add inputs: parameters: val_a: componentInputParameter: pipelinechannel--loop-item-param-1 parameterExpressionSelector: parseJson(string_value)["a"] val_b: componentInputParameter: pipelinechannel--loop-item-param-1 parameterExpressionSelector: parseJson(string_value)["b"] taskInfo: name: add inputDefinitions: parameters: pipelinechannel--loop-item-param-1: parameterType: STRUCT deploymentSpec: executors: exec-add: container: args: - --executor_input - '{{$}}' - --function_to_execute - add command: - sh - -c - "\nif ! [ -x \"$(command -v pip)\" ]; then\n python3 -m ensurepip ||\ \ python3 -m ensurepip --user || apt-get install python3-pip\nfi\n\nPIP_DISABLE_PIP_VERSION_CHECK=1\ \ python3 -m pip install --quiet --no-warn-script-location 'kfp==2.0.0-beta.16'\ \ && \"$0\" \"$@\"\n" - sh - -ec - 'program_path=$(mktemp -d) printf "%s" "$0" > "$program_path/ephemeral_component.py" python3 -m kfp.components.executor_main --component_module_path "$program_path/ephemeral_component.py" "$@" ' - "\nimport kfp\nfrom kfp import dsl\nfrom kfp.dsl import *\nfrom typing import\ \ *\n\ndef add(val_a: str, val_b: str) -> int:\n return int(val_a) +\ \ int(val_b)\n\n" image: python:3.7 pipelineInfo: name: model-training-pipeline root: dag: tasks: for-loop-2: componentRef: name: comp-for-loop-2 iteratorPolicy: parallelismLimit: 1 parameterIterator: itemInput: pipelinechannel--loop-item-param-1 items: raw: '[{"a": 1, "b": 10}, {"a": 2, "b": 20}]' taskInfo: name: for-loop-2 schemaVersion: 2.1.0 sdkVersion: kfp-2.0.0-beta.16 Impacted by this bug? Give it a 👍.