2024/5/1 LangChain js で Gemini が文字化けする
するったらする
きになる
LangChain 側の steram の扱いが雑そうだが...
code:output
--- LangChain ---
## ������の諺:知恵と教訓の宝庫
喜んで!日本語の諺をいくつかご紹介します。
* **七転び八起き (ななころびやおき):** 七回転んでも八回起き上がる。 どんな困難にもめげずに立ち上がる精神を表す。
* **猿も木から落ちる (さるもきからおちる):** どんな達人でも失敗することがある。
* **石の上にも三年 (いしのうえにもさんねん):** 辛抱強く努力すれば、いつかは成功する。
* **蛙の子は蛙 (かえるのこはかえる):** 子は親に似る。
* **猫に小判 (ねこにこばん):** 価値のわからない人には、貴重なものでも無駄になる。
* **覆水盆に返らず (ふくすいぼんにかえらず):** 一度してしまったことは取り返しがつかない。
* **果報は寝て待て (かほうはねてまて):** 焦らず気長に待っていれば、幸運は訪れる。
* **知らぬが仏 (しらぬがほとけ):** 知らない方が幸せなこともある。
* **急がば回れ (いそがばまわれ):** 近道よりも遠回りした方が、結果的に早く着くことがある。
* **出る杭は打たれる (でるくいはうたれる):** 他人より目立つと、批判や攻撃を受けやすい。
これはほんの一部��す。日本の諺は���え切れないほどあり、それぞれに深い意味が込められています。
他に何か知りたいことはありますか?
--- Direct ---
## 日本の諺:知恵の宝庫
喜んで!日本語の諺をいくつかご紹介します。
* **七転び八起き (ななころびやおき):** 七回転んでも八回起き上がる。失敗しても諦めずに立ち上がる精神を表しています。
* **猿も木から落ちる (さるもきからおちる):** どんなに熟練した者でもミスをすることがあるという意味。
* **蛙の子は蛙 (かえるのこはかえる):** 子は親に似る、という意味。
* **猫に小判 (ねこにこばん):** 価値のわからない者に貴重なものを与えても無駄であることのたとえ。
* **覆水盆に返らず (ふくすいぼんにかえらず):** 一度してしまったことは取り返しがつかないことのたとえ。
* **三人寄れば文殊の知恵 (さんにんよればもんじゅのちえ):** 三人集まれば優れた知恵が生まれるという意味。
* **石の上にも三年 (いしのうえにもさんねん):** 辛抱強く努力すれば成功するという意味。
* **果報は寝て待て (かほうはねてまて):** 幸運は自然に訪れるものだから、焦らずに待つべきだという意味。
* **急がば回れ (いそがばまわれ):** 急いでいる時こそ、遠回りでも確実な方法を選ぶべきだという意味。
* **出る杭は打たれる (でるくいはうたれる):** 他人より秀でていると、非難や攻撃を受けやすいという意味。
他にもたくさんありますが、まずはこの辺りからいかがでしょうか?
なんかこのへんが雑な気がするが直接呼ぶのとそう変わらない気も
chunk ごとにログ書いても chunk の前後とは限らない?
限らないが chunk 後が化けてる事が多いそう
化けてないこともあるし chunk の切れ目から離れて化けてることもある...
とかで StringDecoder 挟めば直らないのかなあ
OpenAI とかでは発生しないのか気になる
1文字ずつstreamにやってきている & 観測範囲では起きてなさそう
ギリシャ語やロシア語での出力を指示しても発生する
vertexai 側の修正 PR 見る
コード追う
VertexAI → Google LLM (@langchain/google-gauth) → GoogleBaseLLM @langchain/google-common
invoke ここ
stream は LangChain 側か、 Runnable にある
*_streamIterator 呼ぶ
上で言っていたこの近辺であっている
chunkToString でレスポンスから取り出してる
この content や content[0].text がマルチバイト文字の区切りで切れてるなんてことあるのかねえ
どうやらそうっぽい
https://gyazo.com/80a3f751d80c0c6e32ddee2472e548b8
うーーんそんな雑なことない気がするのだが
直接 curl で SSE 受け取る感じでレスポンス見ると再現しない
code:run.sh
PROJECT_ID=pokutuna-playground
curl -X POST \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
-H "Content-Type: application/json; charset=utf-8" \
-d @- <<JSON \
{
"contents": {
"role": "user",
"parts": {
"text": "日本語のことわざをできるだけたくさん挙げて"
}
},
"generation_config": {
"temperature": 0.0,
"topP": 0,
"topK": 1
}
}
JSON
クライアントの都合かねえ
grpc なら起きるとか
buildAbstractedClient
the response body contains a stream of GenerateContentResponse instances.
これだと起きる
stream だと JSON 自体も途切れてそれが text の途中であることもある
GenerateContentResponse の配列が返ってきてる感じだけどなあ
改行2個区切りで1アイテム来たの意??
そしてこのオブジェクトごとに取り出すのはおかしくなくて、chunk ごとに decode してを文字列結合してるのがダメなんだろな、マルチバイト文字の途中で decode して push してしまっている
stream 読む側はバイト列として結合しつつオブジェクトができたら yield する
code:out.txt
,
{
"candidates": [
{
"content": {
"role": "model",
"parts": [
{
"text": "�
�
って�
�
ます。 \n\n**何か特定のテーマやシチュエーションに合った諺を知りたい場合は、遠慮なく聞いてください。** \n"
}
]
},
JsonStream が実体だなあ
ReadableJonStream は機能していない? デバッグログ仕込んでもダメ
でも new JsonStream してるところテストしかないんだよな...
これだなあ
appendBuffer の data を見ると [238, 191, 189] が追加されてる
Unicode replacement character U+FFFD
Buffer.toString() のデコードに失敗すると暗黙に REPLACEMENT CHARACTER を返す
誰が appendBuffer してるねん
langchain-google-gauth/src/auth.ts の NodeJsonStrema か
雑!!!!
これでいけそうだけどどうかなあ
code:patch.diff
diff --git a/libs/langchain-google-gauth/src/auth.ts b/libs/langchain-google-gauth/src/auth.ts
index 189c867a..9581dc54 100644
--- a/libs/langchain-google-gauth/src/auth.ts
+++ b/libs/langchain-google-gauth/src/auth.ts
@@ -12,8 +12,16 @@ class NodeJsonStream extends JsonStream {
constructor(data: Readable) {
super();
- data.on("data", (data) => this.appendBuffer(data.toString()));
- data.on("end", () => this.closeBuffer());
+ const decoder = new TextDecoder("utf-8");
+ data.on("data", (data) => {
+ const text = decoder.decode(data, { stream: true });
+ this.appendBuffer(text);
+ });
+ data.on("end", () => {
+ const rest = decoder.decode();
+ this.appendBuffer(rest);
+ this.closeBuffer();
+ });
}
}
手元では問題起きなくなった
しかしテストどう書くのだ...既存のやつで stream にどうこうしているやつあるか??
あるけど、ちょっと違うような...
GAuthClient のモックやりたくなさすぎ
テストのために NodeJsonStream を export するかねえ、index.ts には書いてないから公開はされないが...
API_KEY の認証のほうだと発生しないのか確認
起きなさそう
見る
Issue に書くこと
タイトル: Replacement Characters(�) appear in multibyte text output from Google VertexAI
マルチバイト文字を含む stream を受信する場合、chunk の切れ目 (readable.on('data', ...) される単位) が文字の途中である可能性があります
👋 は utf-8 で 0xF0 0x9F 0x91 0x8B ですが、chunk はどの間にも来る可能性があります
Node 環境において buffer.toString() は utf-8 を仮定してバイト列のデコードを試みますが、不正な場合サイレントに REPLACEMENT CHARACTER (U+FFFD) を出力します、これがこの文字化けの原因です
関連 Issue
以下の Issue で報告されているが SDK を更新しても解決していない
@google-cloud/vertexai を利用した場合も同様だが、以下で対処されている
システム情報
macOS
node v20.12.2
langchain versions
code:output
$ 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
やった...疲れた...
2024/5/7 リリースされた