高度なRAGの解放:引用と帰属
このセッションについて
大規模言語モデル(LLM)により、私たちはAIと簡単に「チャット」できるようになりました。最近人気が高まっている、人気かつ高性能なアプローチの1つが検索拡張生成(RAG)です。RAGアプリは、MilvusやZilliz Cloudのようなベクトルデータベースを使用して、LLMの上にあなたのデータを注入することで機能します。
シンプルなRAGに加えて、アトリビューションや引用は一般的に求められる機能強化です。アトリビューションと引用は、回答がコーパス内のどこから来ているのかを説明します。このセッションでは、MilvusとLlamaIndexを使用して、RAGアプリにアトリビューションと引用を追加する方法を見ていきます。
扱うトピック:
- なぜ引用付きの検索拡張生成を行うのか?
- 引用付きのRAGをどのように構築するのか?
- これはあなたのLLMアプリにとって何を意味するのか?
本日のセッション「Advanced Rag Citations and Attributions」を紹介します。そしてゲストスピーカーである私の同僚、Yuin Tang Yu Eugene は、ここ Zillows のデベロッパーアドボケイトです。彼はソフトウェアエンジニアとしてのバックグラウンドを持ち、Amazon で auto ML に取り組んでいました。コンピューターサイエンス、統計学、神経科学を学び、I E E E、big Data などのカンファレンスで研究論文を発表しています。彼はタピオカティー、家族と過ごす時間、水辺にいることが好きです。本日はご参加いただきありがとうございます、Eugene、ようこそ。
ええと、こんにちは皆さん。Emily、紹介ありがとうございます。ええと、今日は rag における引用と帰属について皆さんとお話しできることを本当に楽しみにしています。これは実際、ここ数か月で私が多くの議論を目にしているものです。ですので、これに関するものを構築したり、これに取り組んだりすることは本当に刺激的でした。
ええと、私の名前は Tang です。ええと、Emily が言ったように、私は Zillow のデベロッパーアドボケイトです。ここにスキャンできる QR コードを載せています。ええと、この QR コードをスキャンすると、LinkedIn に移動して、そこで私とつながることができます。ええと、私のバックグラウンドは機械学習です。Zillow に来る前は、CV と自然言語処理に取り組んでいました。
そして、ここで私が行っていることのほとんどは、検索拡張生成、ええと、アプリケーションの構築に注力することです。ですので、引用と帰属に加えて、一般的な l l m アプリについて質問があれば、ぜひ q and a に投稿してください。今日は、ええと、引用についてほんのいくつかのことを取り上げます。まず、なぜ引用が重要なのかから始めます。引用と帰属というこのユースケースの動機づけを行います。
ええと、それから、引用エンジンをどのように構築できるかに入っていきます。このサブセクションでは、引用エンジンのプロセスの部分をある程度取り上げます。そして、引用エンジンに何が含まれるかについては、引用エンジンの各要素をより多く取り上げることになります。そして最後に F a Q がいくつかあり、主に、ええと、ベクトルデータベースについてです。ええと、これは取り上げることもできますし、取り上げないこともできます。ええと、というのもセクション3の後には、引用エンジンの概念実証におけるコードがどのように見えるかを理解できるように、一緒に見ていくコード例もあるからです。では、なぜ引用が重要なのでしょうか?セクション1、これが最初に知っておくべきことです。
ええと、基本的に、引用が重要なのは、chat, G B T やその他の大規模言語モデルにはハルシネーションの問題があるからです。ニュースに注意を払っていたなら、ええと、chat bt の利用に関する興味深いニュースをいくつか見たことがあるでしょう。業界の内外、学術界、さらには法廷でもです。そして、ええと、今年の初め、これは8月か7月だったと思いますが、ええと、ある弁護士が法廷で Chade を使い、架空の判例を引用しました。そして、これは「裁判官が制裁を検討している」と言っていますが、実際には最近、彼らはすでにこの件で問題になっているのを見たとかなり確信しています。ええと、それから、ご存じのように、ええと、人々は学術界でも Chad GT をたくさん使っています。
特に多くの学部生だと思いますが、ええと、Chad BT を使って論文を書き、そして論文を引用しています。そして、たまたま Chad G B T に行って、「ねえ、ええと、例えば、わからないけど、古代ローマに関する論文が10本必要なんだ」と伝えると、そうですね、それは、論文をいくつか作り上げ、その一部は本物で、一部は作り物になります。ですから、これは問題です。ええと、そして大規模言語モデルが、このように物事をでっち上げてしまうハルシネーション問題を抱える理由は、それらがニューラルネットワークであり、ニューラルネットワークは実際には高度な統計的手法にすぎないからです。ですので、裏側で何が起きているのかを理解するために、引用に入る前にここで立ち止まり、ニューラルネットワークを深掘りして、何が起きているのか、そしてなぜそれらにこのハルシネーション問題があるのかを理解していきます。
それでは、基本的なニューラルネットワークの紹介から始めましょう。これは1960年代か1970年代か、そのあたりから存在しています。ええと、そして本質的に、ここで皆さんに理解してほしいのは、何らかの入力の集合を受け取るということです。この場合、入力は、まあ、3つあります。そしてこれらは通常、数値です。
つまりこれは3次元ベクトルのようなものが入力だということです、いいですか?そしてそれが何らかの形でマッピングされます。いくつかの変換が行われ、いくつかの関数が動いて、あれこれして。そして出力が得られます。そしてその出力は、何らかの、通常は何らかの分類になります。必ずしも分類であるとは限りません。
別の予測である場合もあります。ええと、そして典型的には、ニューラルネットワーク、ただし典型的にはニューラルネットワークは分類を行います。ええと、つまり基本的なニューラルネットワークについて知っておくべきことは基本的にこれだけで、何らかの数値を入力として受け取り、何らかの処理を行い、それから何かを出力として返すということです。そして、ニューラルネットワークの研究がさらに進むにつれて、特定の種類のニューラルネットワークは、ええと、テキストに非常にうまく機能し、特定の種類のニューラルネットワークは画像や、ええと、グラフ、あるいは表形式データなどに非常にうまく機能することがわかってきました。つまり、異なる種類のデータには、異なる種類のニューラルネットワークがよりよく機能するということです。
そしてテキストデータに特化すると、リカレントニューラルネットワークがあります。これは、ええと、テキストデータにうまく機能します。なぜテキストデータにうまく機能するかというと、時間に沿って入力を追跡できるようにしてくれるからです。つまり、何らかの文脈を追跡できるようにしてくれます。そしてここにあるこの画像は、リカレントニューラルネットワークがどのようなものかを示す典型的なアーキテクチャ図です。この画像から理解してほしいこと、あるいはこの画像から得てほしいことは、本質的には、それぞれの入力と出力のような、ええと、組み合わせが自分自身にループバックしているということです。
そしてそれがシーケンスを追跡する方法であり、ええと、時間に沿って単語やトークン、入力を追跡する方法です。そしてこの図では、X minus XT minus one XT XT plus one というものが見えます。これが示そうとしているのは、入力時刻 t において、直近の入力からの情報がまだいくらか残っているということです。つまり本質的に、これによって入力に沿って文脈のスライディングウィンドウのようなものを作ることができます。しかし、まあ、これには2つの問題、あるいは複数の問題がありますが、次のアーキテクチャであるトランスフォーマーアーキテクチャによってリカレントニューラルネットワーク上で主に解決しようとする2つの問題は、このような、ええと、アーキテクチャでは時間が経つにつれて文脈を失ってしまうということです、そうですよね?スライディングウィンドウがあります。
そして加えて、同じ数の、シーケンスからシーケンスへの変換を行う必要があり、そのシーケンスは同じ長さでなければなりません。トランスフォーマーは、そのシーケンスからシーケンスへの翻訳を一時停止することをある程度可能にし、さらに文脈も一時停止して、その文脈を私たちが隠れ状態と呼ぶものに保存することを可能にします。つまりトランスフォーマーは、エンコーダ、デコーダ、隠れ状態、追加の入力から構成されています。そしてこの追加の入力は通常、自己注意と呼ばれるものです。ええと、これは行列であり、この隠れ状態も行列です、そうですよね?つまり、単なるたくさんのベクトルです、そうですよね?そして追加の入力である自己注意も、単なるたくさんのベクトルです。
そのように考えてください。ええと、つまり本質的に入力、エンコーダが行うことは、エンコーダが「ほら、これは、まあ、何であれ、ええと、テキスト入力からの入力です」と言うことです。そして私たちが行うのは、それを何らかの計算に通し、入力の現在の文脈と、入力の現在のトークンについて教えてくれる隠れ、ええと、ベクトルを生成することです。それはどこにあるのか?そして入力の現在の状態です。つまり基本的に、入力で何が起こっているのか、その全体の状態を追跡するのです。
そして、これは時間をかけて行われ、これを行うことで、本質的にグローバルなコンテキストとフィードフォワードのコンテキスト、そしてデコーダの両方を扱えるようになります。デコーダが行うことは、このコンテキストを受け取り、ええと、このコンテキストを受け取り、あなたが持っているこの隠れ状態、つまり入力のコンテキストを受け取ることです。それには、たとえばトークンや、現在位置などが含まれます。そして追加の入力も受け取ります。これは自己注意行列であり、これらを組み合わせて、それから出力を生成します。
そして通常、この出力が何かというと、そうですね、つまりトークンがどこにあるかをコンテキストに取り込みます。したがって通常、この出力は次のトークンは何か、というものになります。そしてそれこそが G P T が行っていることです。つまり G P T は実際にはデコーダのみのアーキテクチャです。自己注意があり、このような完全なフィードフォワードニューラルネットワークのようなものがありますが、実際には多数のデコーダブロックなのです。つまり本質的に何をしているかというと、その状態を受け取り、次の単語を生成するまで状態を変換し続けているのです。
そしてこの例では、ニワトリが横切って歩いた。実際に起きていることは、G P T が、よし、文の中でニワトリが道路を横切って歩く、と言うということです。ですから、ここで覚えておいてほしいのは、G P T が、ええと、G P T が行うことは、次のトークンがどこにあるかと、現在の状態、つまり入力の現在のコンテキストの両方を知っていることを活用するということです。そしてそれを使って次のトークン、または次の出力を作成します。つまり Chad g p t が幻覚を起こす理由は、一連の単語やトークンを予測するように設定されているからであり、直接一致ではないからです。
それはあいまい一致ではなく、検索エンジンでもありません。それは一連の単語を予測するように設定された高度な統計的手法です。わかりましたか?では、これで何が起こっているのか、たとえば、何というか、tragedy, BT がこれを行うということ、ではどうやって、どうやって、どうやって、どうやってここから抜け出すのか?この幻覚にどう対処するのか?ということが少し理解できたところで、これにはいくつかの要素があります。そして、その要素の一つは、本質的に、自分の知識を vaverify する、または検証する方法を持つ必要があるということです。このデータはどこから来ているのか?そこで引用が出てきますよね。つまり引用によって、「これがこのデータを見つけた場所です」と言えるようになります。
そしてこの基本的なプロセス、この最初のステップは、基本的に自分のデータを LLM の上に注入することです。これは rag であり、基本的な rag retrieve、生成へのログインであり、LLM の上にデータを持つということです。この基本的なプロセスでは、ナレッジベース、ええと通常はテキスト、画像、動画、何であれ、それをニューラルネットワーク、つまりディープラーニングモデルに入れます。データの種類ごとに異なるモデルでなければなりません。画像データにテキストモデルを使わないでください。ええと、それをネットワークに入れ、ネットワークの最後の層を切り落とし、最後から2番目の層から出力を取得します。そしてそれがベクトル埋め込みです。つまりそこでベクトルを取得し、それをベクトルデータベースに保存します。
そしてそれが基本的に、引用と帰属付きで LMSs の上にデータを注入する方法です。ここに追加のステップを加えます。ベクトルを保存するだけでなく、テキストのチャンクも必ず保存するようにします。ええと、それについてはすぐに話します。まずここで話したいのは、それにつながるものとして、この意味的類似性とは何か、ということです。なぜベクトルを保存するのか?何の意味があるのか?どうやって、ベクトルを保存することが、記事を引用し、適切な場所で適切な情報を見つけるのに役立つのか?そこで、意味的類似性と呼ばれるものを取り上げ、ベクトルがどのようにして似た意味を持つものを見つけられるのかを理解しましょう。
つまりこの例で見てほしいのは、基本的にこれらの単語、queen、king woman、man をベクトル化し、それらに対して少し数学的な計算を行うということです。つまりベクトル化、意味的類似性というのは、基本的に、テキストのようなあらゆる非構造化データを取り、それに対して何らかの数学的処理を行うということです。では queen、ええと、queen minus woman から始めます、いいですか?私の画像がこれを隠しているのですが、ええと、これから示すのは queen minus woman plus man is equal to king ということです。では queen minus woman から始めます。これは 0.
3 comma, 0. 9, minus 0. 3,comma 0. 4. そしてこれは zero comma 0.
5 です、そうですよね?ここでわかるのは、queen と woman は X 軸上で同じ値を持っているということです。これが、あるいはすみません、x の値、最初の次元において、基本的に意味しているのは、これら2つの単語はその次元に沿ってほぼ同じ意味を持っているということです。そしてここで気づくもう一つのことは、queen と king、そして woman とman は、第2次元で同じだけ異なっているということです。そこから推測できるのは、これらの単語は意味において似たような意味、あるいは似たような差異を持っているということです。ですから、このような計算 queen minus woman を行うと、zero comm, 0.
5 になります。この、ええと、ベクトルが表しているのは、基本的に queen とwoman という単語の違いです。ですから queen と woman の差を取り、それに man を加えると、その 0. 5, common 0. 2 によって、最終的に 0.
5, common 0. 7 になり、偶然にもそれは king でもあります。つまり queen と woman の差を man に足すと king になるのです。したがって、ここで基本的に示しているのは単語に対する数学です。似ている単語は、足したり引いたりすることで、同じような意味を持つ他の単語を作ることができます。これが要点です。ベクトルによって単語に対して数学ができるようになります。
いいですか?ではここで、類似性検索はどのようなものに見えるのでしょうか?ここまで、ステップ1と2をずっと話してきましたよね?つまり、この非構造化データを取得し、それをベクトルに変換し、それをベクトル埋め込みに入れました。引用を追跡できるように、それに追加する必要がある何らかのテキストがあると言い、それをベクトルデータベースに格納しました。次に何が起こるのでしょうか?これはどのように役立つのでしょうか?これらすべてが揃ったら、ユーザーが来てクエリを実行し、ユーザーが「Hey, um, ローマの、ええと、知りたいんだけど、あの、ローマの滅亡について知りたい。ローマの、ローマ帝国の滅亡について知りたい。よくわからないけど。
ええと、それについて教えて」と言うとします。いいですか?そして、そのクエリを言うと、それをベクトル化し、そのクエリを取得して大規模言語モデルに送り、「Hey, これを見つける必要があります」と言います。そしてベクトルデータベースに行き、「よし、私たちのテキスト、私たちの文書の中で、ローマの滅亡に最も近いものを見つけよう」と言います。つまりそれは中に入って、「よし、自分がやるのは、ローマの滅亡の最近傍を見つけることだ。ああ、ほら、ええと、ユリウス・カエサルの暗殺、内戦、その他もろもろ」といった具合に探します。
いいですか、これが返す内容で、こちらが引用された文書です。こちらが、つまり、この文書はどこで見つかったのか?それは、たとえば、この教科書で見つけたとか、あるいは、この、何であれ、ということです。ええと、もしかすると Wikipedia で見つけたかもしれません。多くの学校は「Wikipedia を引用するな」と言うのは知っていますが、実際には悪い情報源ではないと思います。ええと、でも基本的には、それがどこで見つかったのかを教えてくれます。
つまり、どちらかを設定できます。たとえば、Aとして、これは信頼できるソースであり、私はそれを信頼する、またはBとして、これは信頼できないソースであり、私はそれを信頼する、というようにです。もしかすると、The Onionで情報を見つけて、「ねえ、なぜそれがそもそも私のデータベースに入っているの?」となるかもしれません。つまり、それは不要です。そこから取り除きましょう。なので、ええと、引用はデータがどこから来たのかを示してくれます。そして引用と典型的な類似検索の違いは、基本的に、これらのテキストをベクトルデータベースに追加して、クエリしたときにソースが返ってくるようにする、ということです。ええと、ここでの違いは、つまり、私がしたかったのは、ベクトルデータベースの中でデータがどのように見えるのかを少し見てみることでした。
これについては多くの質問を受けます。つまり、あなたのベクトルデータベースのデータはどのように見えるのか、ということです。ですから、任意のblobストレージやno SQLデータベースと同じように、J S O N形式のメタデータがあります。ここでの違いは、本当にこの埋め込みを見るという点です。そしてこの埋め込みは、使用できる一種のキーです。つまり埋め込みは近似最近傍キーであり、実際にベクトルデータベースはこれによってクエリされます。そしてここで丸で囲んだものは、この中で私がparagraphと呼んでいるものです。
これは実際に、私が最近取り組んでいるプロジェクトからのデータのスクリーンショットです。そして抽出されたparagraphは、「we defined an anomaly as follows」です。そこには段落の残りの部分は含まれていません。ですが、ええと、引用の部分でここで本質的に指摘したいのは、そこにテキストの段落が含まれているということです。つまり、それが引用用のデータがどのように見えるか、という感じです。
そして通常、引用を行う必要がない場合、またはZoom attributionがない場合、このテキストデータを保存する必要はありません。ベクトルデータベースに必要なメタデータだけを保存すればよいのです。わかりましたか?では、引用エンジンには何が入るのでしょうか?いま私は、この引用エンジンがどのように機能するのか、内部のベクトルデータベースで何が起きているのか、実際にどのように関連ドキュメントを引き出すのか、その例は何か、について話しました。これには何が入るのでしょうか?引用エンジンは、ええと、ragスタックの一部であり、L L Mアプリケーションフレームワークの一部です。ええと、そして本質的にここで私たちが行うのは、ええと、このフレームワークをC V Pフレームワークとして定義することです。私たちはそれをC V P、Chad、G B T、またはその他の大規模言語モデル、vissのようなベクトルデータベース、そしてprompt is codeと呼んでいます。
そして本質的に、これを、あなたが考えることができる、考え方としては、ええと、プロセッサ、ええと、C P Uとして考えられます。それがchat、G B Tであり、これはすべての計算的なことを行います。また、それをGPU Uの計算負荷の高い作業として考えることもできます。そして次にストレージがあります。つまり、データをどこかに保存しておく必要があり、それがベクトルデータベースです、そうですよね?つまりこれはあなたのハードドライブ、ええと、romなどになります。そしてあなたのprompt is codeは、本質的にはプロンプトを使って、あなた、C P U、そしてストレージの間をインターフェースするものです。
では、このスタックのどこに引用が位置するのでしょうか?引用は、ベクトルデータベースとprompt as codeのところに位置します。ですから、プロジェクトをどのように構成しているかによって、ええと、あなたのベクトルデータベースは、コードを自動的にアップロードする対象である場合もあれば、そうでない場合もあります。あるいは、フレームワークを使ってアップロードするものかもしれません。ええと、すみません、コードをアップロードするのではなく、データをアップロードするものです。あるいは、フレームワークを使ってデータをアップロードする対象かもしれません。ですので、それはprompt as codeの一部として位置づけることができます。たとえばAIエージェントなどがいて、あなたのベクトルデータベースにデータをアップロードしている場合、それにプロンプトで「ねえ、実際のテキストやソースなども含めたいです」と指示できます。つまり、それがそのように行う一つの方法です。
ただし、これはベクトルデータベース上で直接行うこともできます。つまり、ええと、ベクトルデータベースに入って、「ねえ、保存したいフィールドの1つはこのテキストフィールドです」と指定するだけです。そしてこれは、データを保存する直前にも関わってくることですよね。つまり、データに対して行う必要のある前処理がいくつかあるということです。その中には、データを適切なチャンクに分割するようなことが含まれます。ええと、私が最近いろいろ試しているのは、どうやって適切なサイズのチャンクを見つけるのか、ということです。良いクロスオーバーとは何か。ええと、チャンクにとって良いオーバーラップとは何か。そして実際、これは難しい問題で、ええと、業界の誰もまだ、あるいは学術界でさえも、強力な解決策を見つけられていません。ええと、ただこれは、やらなければならないことであり、実験して、データをどのように正しくチャンク化するかを見つけなければならないことです。そして、チャンク化されたデータができたら、それをどのように保存するのか。つまり、すべてのチャンクデータが同じドキュメントなどにマッピングされるようにする、ということです。
ここが引用の位置づけです。そして次に行うのは、ええと、私が非常に、非常にシンプルな引用エンジンを構築したサンプルノートブックを見ていくことです。いいですか?これはノートブックにアクセスするためにスキャンできるQRコードです。ええと、チャットにもリンクを投下します。ええと、ただ、スマホでこれをスキャンして、今後使うためなどにリンクをどこかに保存しておきたい場合は、そうしてもらえればと思います。10秒、15秒くらい時間を取ってから、ええと、ノートブックを開きます。
いいですか?おっと。はい、これがノートブックです。全画面に戻りましょう。これを全画面にします。とてもいいですね。
はい。はい。これが、ええと、引用エンジン用に使っているノートブックです。そして基本的にここで行うのは、ええと、最後にこの引用付きのレスポンスのようなものが得られるのがわかると思います。そして私たちがやることは、いくつかのデータをスクレイピングして、そのデータをベクトルストアに入れ、それから、次に L L M を使い、それをベクトルストアの上に載せて、ええと、それで引用コントロールを作るということです。
いいですか?ここではこのすべてのものを、ええと、コメントアウトしています。なぜなら、これはすでに実行済みだからです。これは、マルチドキュメントクエリエンジン用のデータが入っていたのと同じフォルダにあります。ええと、もし、ええと、その回に参加していたなら、このデータも持っているはずです。もしなければ、そのリンクも投下します。あ、そうだ、これのリンクをチャットに投下すると言いましたね。
これら両方のリンクを取得して、チャットに入れます。少し待ってください。これは、これに沿って進められるようにするためのもので、それから、ええと、もう1つもすぐに投下します。これがもう1つです。つまり、これら両方が、ええと、このスクレイピングを行います。
ええと、基本的にここで行うのは、都市のリストを取得するだけで、好きな都市を選べます。私は Toronto、Seattle、SF、Chicago、Boston、dc、ええと、Cambridge、Houston を選びました。そして Wikipedia に行き、Wikipedia に ping します。これは Wikipedia の a p i で、特に凝ったことは何もありません。ええと、そしてこれは、あなたがその、Webスクレイピングに興味があるのでなければ、重要なことでもありません。
ええと、それから、ここに降りてきて、ええと、OpenAI キーを取得します。つまり、OpenAI を使うなら、dot m を読み込んでから OpenAI キーを取得します。ええと、次に LAMA Index からいろいろなものをインポートします。なので、この部分は重要です。まず、OpenAI とやり取りする方法をインポートする必要があります。そして、citation query engine をインポートする必要があります。実際には自分自身の citation query、citation query engine を作成することもできます。しかしこの例では、LAMA Index のものを使います。そしてもちろん、Vector store index も必要になります。
これは、Vector store を、ええと、シンプルなディレクトリリーダーにつなぐためのものです。つまり、これは data ディレクトリからデータを読み込みます。スクレイピングしたら、ええと、storage context、これによって vus への参照を渡し回すことができます。ええと、ストレージからインデックスをロードします。これによってストレージからインデックスをロードできます。実際、ここでこれを使っているかはちょっとわかりません。
ええと、それから service context によって大規模言語モデルを渡し回すことができます。そして LAMA index が viss にアクセスできるように、Llama Index 版の Viss Vector Source が必要になります。それから Viss light のデフォルトサーバーを取得します。ええと、それを起動します。ええと、このときは 2. 2 point 11 を使っていましたが、今は 2.
3 0. 0 です。ええと、同じインターフェースです。ああ、なのでそのやり取りに変更はありません。ええと、それから私がやるのは、基本的には Vector store への接続を開くことです、このベクトルストアを、ええと、Llama Index で扱うために。
そしてこの接続に citations という名前を付けて、ローカルホストで動かすようにします。それで、Hey。Hey、Eugene、遮ってすみません。エディタをズームインしてもらうことはできますか?はい。これがすごく小さくて見づらいということをいつも忘れてしまいます。
はい。これで良くなりましたか?良くなりました。Okay。ええと、いいですね。では、もう一度かなり手短に説明します。
皆さんがこれを見られたかわからないので。ええと、これは OpenAI とやり取りする方法です。これは citation query engine の、ええと、機能で、LAMA Index によって提供されています。これは Vector store からインデックスを作成する方法です。これは、ええと、ディレクトリからデータを読み込む方法です。
これは、ええと、この場合 Vector database にデータを保存する方法を渡し回すためのものです。これはインデックスをロードする方法です。これは L L M を渡し回す方法です。そしてこれは LAMA Index と一緒に使う Viss Vector store そのものです。そしてこれも、viss Light のデフォルトサーバーです。
これを起動して、それから Viss Vector store を作成します。なので、このコレクションを citations と呼ぶことにしました。これは local host で、それから default server を呼んでポートをリッスンさせます。ええと、ここで service context を作成します。そして基本的に必要なのは、G P T 3. 5 turbo を取得することです。ええと、ここでは自分に合う大規模言語モデルを何でも選んでください。
ただ OpenAI は、デフォルトで LAMA Index と Lane Chain の両方と簡単に動作します。なので、この場合は G PT 3. 5 を使います。ええと、それから、ええと、storage context を取得します。そして本質的にここでやりたいことは、storage context を持ち、先ほど作成したこの vector storage をロードすることです。それから directory reader を使ってデータをロードします。
ええと、これは上のほうで Wikipedia からスクレイピングしたデータです。それからインデックスを作成します。つまりインデックスを作成し、以前に、ええと、スクレイピングしたこれらのドキュメントを持っていて、それを変換し、それから使用する大規模言語モデルと、ええと、使用する vector database を渡します。それから query engine を作成します。つまり、ええと、ここで本質的にやっていることは、citation query engineobject を呼び出すだけです。そしてこれが何をするかというと、内部的に LAMA index に対して、情報を取得するときに、ソースがどこかを知りたい、と伝えるものを作成します。
つまりこれがそれです。これは、たとえば、prompt is code slash のような、つまり、CVP スタックにおけるインターフェース部分のようなものの一部です。なのでこれに渡すのは、使用したい index、ええと、それから similarity top case です。つまり本質的にこれは、Vector database から欲しい上位の応答は何か、ということです。ここでは例として三つと言うだけにします。そしてこれは、つまり、引用の粒度はどれくらいか、ということです。この例では 512 文字と言い、それから単に、ええと、Seattle と Houston のどちらの空港が大きいですか?と言います。すると、まあ、云々かんぬん、と答えてくれます。
そして、ノードが欲しければ、もっと多くの情報が出力されます。なので、ええと、Houston に関するこの情報がどこから来ているのかを見ることができます。それは、こう、いろいろなもののリストで、Houston に関するこのセクションのようなものです。というわけで、はい、基本的には、クエリエンジンに何が含まれるのか、そして llama index を使って独自のシンプルな例をどのように構築できるのか、そしてなぜそれらが重要なのか、ということです。はい。ではここで、質問を受け付けたいと思います。
ありがとう、Egen。参加者の質問が入ってくるのを待つ間にリマインダーです。皆さん、画面下部の q and a ツールを使ってください。ええと、あなたがこれに、ええと、少しの間、取り組んできたことは知っています。気になっているのですが、この問題を構築する、あるいは解決する上で、最も難しかった部分は何でしたか?ええと、この問題を解決することですか?この問題を解決することですか?はい、実は、プレゼンの最後で言っていたように、効果的な引用エンジンを作る上で最も難しい部分は、実はチャンク分割を正しく行うことだと思います。つまり、実際にはデータの前処理です。
ええと、これは本当に厄介です。なぜなら、それは、こう、AI ML の分野の中でもあまり明確に定義されておらず、あまり解決されていない領域だからです。ええと、でもそれは引用にとって非常に重要なことです。なぜなら、正しいコンテキストであるコンテキストを取得できるようにしたいし、それを適切なコンテキストサイズのウィンドウで取得したいからです。ええと、そこが難しい部分の一部でした。ええと、それに加えて、私はこれの別バージョンをいくつか作りました。これは、ええと、これは llama index 上で動くバージョンでした。
これをやりましたし、vis だけで構築した別のバージョンも作りました。ええと、その場合、実際にはチャンク分割はもっと厄介でした。ええと、こちらは少なくともドキュメントを自動でチャンク分割してくれました。ええと、でも別の難しい部分は、何を保存し、どう保存するかを選ぶことかもしれません。たとえば、単に、ええと、テキストだけを保存したいわけではありません。このテキストをどこで見つけたのか、ええと、あるいは著者は誰なのか、いつ公開されたのか、そういったことも保存したいわけです。
ですから、こうした多くのことは、ええと、実際にインデックス自体を構築することよりも、より多くの前処理や思考、設計プロセスを必要とします。Jeremiah、ええと、新しいデータを追加するのはどれくらい難しいですか?ドキュメントを追加するたびにベクトルを再生成する必要がありますか、それともベクトルを増分的に追加できますか?この質問についてはもう少し情報が必要です。ええと、では。ええと、私は、私は、私は、私は、理解していません。ええと、私には、そして間違っていたら q and a で教えてください、私には、1つのベクトルがデータ全体を表しているという概念を持っているように見えます。
新しいデータを追加するには、そのベクトルに追加する必要がある、と。というのも、ドキュメントを追加するたびにベクトルを再生成する、というところからそう受け取っているからです。実際には、ベクトルは毎回同じ次元で、ええと、こうしたニューラルネットワークによって生成されます。つまり、ベクトルは実際には、入力ドキュメントに対するニューラルネットワークのこの出力層なのです。たとえば、文を追加するたびに、このネットワークに文を与えると、4次元ベクトルが得られます。段落を与えると、別の4次元ベクトルが得られます。
ええと、なのでベクトルは変わりませんし、ベクトルに追加するわけでもありません。そして新しいデータの追加はとても簡単です。言うことはただ、やあ、これが新しいデータです。embedding を生成して、というだけです。ええと、再生成する必要はありません。一度生成するだけでよく、その後それをベクトルデータベースに保存できます。
トークンに値を割り当てる方法をもう一度説明してもらえますか?ええと、はい、実はこの質問を見て、私は、正直よく理解できていません。というのも、トークンに値を割り当てることはないからです。なので、その質問をした方、もし可能であれば、もう少し明確にしていただけるとありがたいです。もう一度取り上げてみます。はい。この引用アプローチは、本質的には l m に該当箇所を引用するようプロンプトしているだけですか?読み取っている部分から該当箇所を引用するよう l m にプロンプトしているだけです。
ええと、いいえ。実際には、この引用アプローチが行うのは、「ねえ、出典を見つけて」と指示することです。そしてご存じのとおり、LMS にはこの幻覚の問題があります。なので実際にはこれは、「出典をデータベースに保存しておき、その出典を取得するときに、その出典をどこから得たのか、そしてその出典が何なのかを含めよう」とするものです。つまり、L lmm に対して、どこから読んでいるのかを引用するよう単にプロンプトしているわけではありません。なぜなら l l m は読まないからです。l l m はただ単語を生成するだけです。読んでいるわけではありません。l l m による読解は行われていません。ええと、〜について。ああ、うんうん。
わかりました。ソース1について、具体的にソースとは何ですか?この、ええと、私が提示した例では、提示していませんでした。ソースから Houston だとわかります。Houston と書いてあるからです。ええと、ただ私はそれに、Houston は見えますが、ええと、その、何て言うんでしたっけ、リンクを提供するようには求めていませんでした。あなたが何を作ったのか不明確です。あなたは citation query engine を使っていて、何を作ったのかという点で、どういうわけかメッセージが伝わっていません。
ええと、citation query engine はこの一部のようなものです。つまり、query engines は大規模言語モデルアプリケーションの一部です。本質的にそれらが行うのは、アプリケーションがデータベースにクエリを送る方法を制御することです。したがって citation query engine は、より大きな大規模言語モデルアプリケーションの一部であり、それがここで作ったものです。これは大規模言語モデルを活用するアプリケーションです。
私たちはデータベースを組み込み、自分たちの個人データを組み込みました。この場合、自分たちの個人データは、ええと、Wikipedia ファイルです。ええと、はい、つまり、それが基本的に citation engines で、大規模言語モデルアプリケーションの一部です。ええと、その方がより明確な説明ですね。ベクトルを生成するときに他のコンテンツは考慮されない、という理解で正しいですか?その通りです。ええと、これはどこか別の citation query engine を使うという話ですか、それとも自分たちで構築すべきですか?わかりました。
あのですね、これは、この例を使うべきではなかったということが私には明確になってきました。そして実際には、単に生の例を作るべきでした。ええと、自分自身の citation query example を構築できます。この citation query engine は単に、私が LAMA Index から持ってきたものです。なぜなら私はそのフレームワークが好きで、彼らがこの引用関連のことを、ええと、本質的に実装しやすくしてくれているのが好きだからです。ええと、ただし外部で構築された citation query engine を使う必要はありません。本質的にこれでやる必要があるのは、a、ええと、自分の、ええと、ソースデータを保存することを忘れないこと、そして b、クエリを実行するときにソースデータを見たいと宣言することです。
つまり citation query engine には実際には2つの要素があります。つまり、このものはチャンク化も処理します。なのでデータのチャンク化も処理する必要があります。ええと、ただ要素はほんのいくつかしかなく、自分で構築できます。別のものを使う必要はありません。私は単に LAMA Index のこのものを使っただけです。彼らのフレームワークが好きで、クールだと思うからです。
ええと、ツリーベースのドキュメント構造、DOM ツリーや親子孫のようなものを想定して、より具体的な引用とコンテキストを可能にするためのチャンク化戦略のおすすめはありますか?ええ、はい、実は、うーん、これは必ずしもチャンク化に関することではありませんが、ツリーベースのドキュメント構造という点では、うーん、私はナレッジグラフで何かに取り組んでいて、ええと、ベクトルデータベースの上にナレッジグラフを置くというものです。実際に、それを行っているお客様がいて、OriginTrail が、vis の上にナレッジグラフを置いています。うーん、ここでおすすめするチャンク化戦略、または戦略は、実際にはノードのメタデータをベクトルデータベースへのエントリに保持することです。たとえば、ノードにはおそらく親、左の子、右の子、あるいは、子、まあ何でも、といった何らかのメタデータがあるでしょう。うーん、あるいは孫かもしれません。その関係を追跡しているかどうかはわかりませんが。
必須ではありませんが、できるとは思います。うーん、つまりノードはメタデータの中にこれらの一部を持つことになります。そして基本的にやりたいことは、これらをエントリに確実に入れることです。そうすれば、エントリのクエリ結果が返ってきたときに、たとえばクエリを行って、「ああ、これが返ってきたエントリだ」とわかった場合、そこには、うーん、情報として、ええと、これはテキストで、これは子で、これはこの親ノードの子ノードだ、ということが含まれています。そうすると何ができるかというと、では、まあ、このテキストの一部があります。実際には、情報についてもっとコンテキストが必要なら、親ノードも戻ってクエリできますよね?うーん、そうですね、そういったものについてやりたいことは、チャンク同士をリンクする方法と、うーん、それらを引用する方法を持つことです。
ええと、あなたが設定したクラスには主要な部分、L l m とソースドキュメントがあります。後者がベクトル化されます。L l m はブラックボックスです。では、クエリの出力にソースとしてドキュメントをどう接続するのですか?プロンプト応答を使って、すべてのドキュメントベクトルで類似検索をしているのですか?うーん、こういったアプリケーションの動作としては、クエリを与える、つまり送信すると、そのクエリが、こう、あなたが、あなたが、わかりますか?ええと、あなたが、つまり自然言語で質問すると、実際に裏側で起こるのは、自然言語で尋ねたこの質問、たとえば「シアトルとヒューストンのどちらが大きい空港を持っていますか」が、クエリ、または一連のクエリ、またはクエリの集合に変換され、基本的には「Seattle Airport」「Houston airport」そして「size」と言うようなものになります。つまり、自然言語の質問を取り込んでいるわけです。
L l M の役割は、あなたの自然言語の質問を受け取り、その質問を理解する、あるいはその質問をクエリに分解し、そのクエリに対してベクトルストアに問い合わせられるようにすることです。そしてそれがドキュメントベクトルに対して類似検索を行う方法です。ですから、それは、プロンプト応答の部分、部分であなたが言っていることに近いと思います。うーん、ただ、ドキュメントをソースとして接続する方法は、ドキュメントを入れて、ドキュメントをベクトル化する、ということです。ベクトル化されたドキュメントがあり、それらをベクトルデータベースに入れ、それからベクトルデータベースに対して、その、その、その質問でクエリします。そこに L l M の役割が関わってきます。そして最後に、それをこのような応答に変換するだけです。
そして応答が得られたら、「この情報はどこから得たのか?」と言います。よし、この情報を取得しましょう。なので、だいたいそういう仕組みです。チャットにもう一つ質問があります。プログラムはトークンにどのように値を割り当てるのですか?各単語/トークンに対して、言語モデルが持っているものと同じトークン値を割り当てるのですか?ああ、あなたの、ああ、音声が戻りました。すみません、音声が一瞬途切れました。
ああ、ええと、わかりました。うーん、私、私はこの質問が何を意味しているのか理解するのが本当に難しくて、本当に苦労しています。うーん、その、ええと、私たちのプログラムのどの時点でも、tokens に値を割り当てることはありません。ええと、tokens は、うーん、tokens は、ええと、あ、わかりますか? ここで、私は、私はこれについてのビジュアルがあります。はい、どうぞ。
この例では、tokens はこれらの単語ですが、実際には、この例は非常に単純化された例です。実際には tokens は、あなたのネットワークが言語の単一の buildingblock として定義した単語または単語の一部です。たとえば、the はおそらく単一の token ですが、chicken はおそらく 2 つの tokens です。おそらくこれは ChiN とか chi みたいなものだと言っているのだと思います、よくわかりません。そして walked もおそらく 2 つの tokens です。
おそらく walk、duh、そして、この ed token は過去形を意味します、と言っています。そしてこの walk は、ええと、動詞のようなもので、そうするとそれらを p*****s して、walked は過去形の walking だと言う、まあ、そんな感じです。ええと、across は 1 つの token かもしれません。ええと、the、the は、もう一度言うと、おそらく 1 つの token で、road はおそらく 1 つの token です。
なので token は、tokenization は、実際にはかなり複雑なプロセスです。うーん、本質的な仕組みとしては、大量のデータを language model に流し込むと、それが「おい、このすべてのデータから見ると、これは単一のもの、これらの別々の単語の最小の building block として識別できる単一の building block のようだ」と言うわけです。なので、スペース、ピリオド、句読点も、しばしば tokens です。うーん、そしてこの質問を終えるために、ええと、同じものを割り当てるのか? いいえ、すべての language model が同じ tokenization を持っているわけではありません。わかりました。
私は、あなたと似たユースケースに取り組んでいます。knowledge graph の vertices を VUSs に埋め込み、citations を含む応答が必要な rag app で使うというものです。は。はい。chunking strategy のアドバイスありがとうございます。スケーリングしながら Novus をより効率的に使う方法について、他にアドバイスはありますか?child references と metadata を含む tree based embeddings にどの indexing algorithm を使うべきか、何か推奨はありますか?ちなみに、私はその tree そのものは embed しません。
tree は完全に、あなたの metadata の中に存在すべきで、embed するのは text や images、何であれそれだけです。うーん、そしてスケーリングしながら viss をより効率的に使うには、うーん、まあ、viss は実際には非常に簡単にスケールできるように作られています。うーん、ここは私がただ、ほら、viss をあなたに宣伝する部分になります。でも Viss には、こうした 3 つの関心の分離があって、indexing、data ingestion、querying を分離しています。なので、すでにこの infrastructure がそこにあるため、本当に気にする必要があるのは Kubernetes pods とか、それらを接続すること、そして「いつ 2 つ目の pod を立ち上げるのか?」ということです。それを行うには、主に monitoring であり、主にあなたの use case を知り、あなたの app がどのように使われているかを知ることです。それは本当に、vector databases とはあまり、あまり関係がありません。
うーん、なのでそこでおそらくやりたいことは、まあ、ただ、それは、load balancing に近いものになります。ええと、もう 1 つできることは、もしあなたが「もう Kubernetes を扱いたくない。DevOps をやりたくない。これを scale させたくない」という段階に到達したら、私たちの sales team に連絡してください。喜んで話をしてくれるはずです。うーん、stored citation data のために vis で RO view を共有していただけますか? 私、それは、それはこれです。たぶん、うーん、あなたが別の意味で言っているのでない限り、まあ、これは、つまり、これらは j ss o n form で、これを tabular data と考えることもできると思います。
うーん、でもこれは、これはおそらく、tabular data における row は同じ IDs が何度も何度も並んだものになる、ということですよね? ええと、でもこれは本質的にあなたの data がどのように見えるか、1 つの entry がどのように見えるかです。うーん、U S A にはいくつの hidden states がありますか? あ、あ、冗談です。わかりました。users として、natural language inputs はかなり荒れることがあり、いくつかの keywords から非常に descriptive な instruction や question まで幅がありますが、有用な information を引き戻すものにそれらを手なずけるための推奨事項はありますか。誰、ええと、私は、私はこの質問について追加の、ええと、information が欲しいです。
非常に幅広いものを持っているあなたのユーザーが誰なのか、そしてそれがなぜ有用な情報を引き出すことにつながらない可能性があるのかを知りたいです。ええと、通常、私は、これは社内で使用しているのであれば、たぶん何らかのプロンプトエンジニアリングをしたくなると思います。それは単に、たとえば「ねえ、毎回、いくつかのルールを設ける、いくつかのルールを設けるんだよ」というようなもので、たとえば「ねえ、何かを探したいときは毎回、この文を含めるとか、この一連の単語を含めるとか、このリンクを含めるとか、そういうことをする」といった感じです。ええと、外部ユーザーがいる場合は、ええと、つまり、その場合は、あなたは、あなたは、どうしようもない状況にいるということです。ええと、どのインデックスを使うべきかについて何かおすすめはありますか?ああ、はい、あなたのナレッジグラフのユースケースについてですね?ええと、それはどれだけかによります。つまり、すべてのインデックス、インデックスの違いは主にトレードオフにすぎません。ですから、必要なものが、ええと、精度、速度、メモリの観点で何かによります。
たとえば、本当に高い精度が必要で、速度を気にせず、メモリについては問わないのであれば、フラットインデックスを使えばよいです。本当に高い精度が必要で、速度を重視し、メモリを気にしないのであれば、H N S W を使うことになります。これは最も人気のあるものです。ええと、速度を非常に重視し、精度はそれほど気にせず、メモリを重視するのであれば、スカラー量子化やプロダクト量子化のような何らかの量子化を、ええと、I V F と組み合わせて使ってください。ええと、スカラー量子化は、そうですね、あるいはプロダクト量子化というのは、スカラー量子化よりもメモリを重視するということを意味します。ええと、はい、つまりすべては必要なトレードオフ次第です。チャットであなた宛てにもう一つ質問があります、Jun。
LLM やベクトルデータベースを入れ替えるのはどれくらい簡単ですか?ええと、例として、Falcon l l m や Pine Cone db を使う場合です。ええと、他のベクトルデータベースについてはわかりません。言えるのは、ローカルでホストできる限り、LLM を使うものを入れ替えるのはそれほど難しくないということです。そしてインターフェースを理解している限り、L L M を使って、それらを入れたり出したりするだけでできます。必要なのは、ええと、L L M とのインターフェースの方法を変えることだけです。しかし通常、L L M でしていることは、それをフレームワークに入れることだけなので、通常は出し入れするのが非常に簡単です。ええと、すべてのベクトルデータベースが同じインターフェースを持っているわけではないことは知っています。ですから、たぶん、そうですね、インターフェースの違いが何かを学んでおきたいと思うでしょう。ええと、それらを切り替えられるようにしたいのであれば。
ええと、そうですね、それが、それが、基本的に私の、そうですね、それは、それほど難しくはありません。ただすべてのインターフェースを学ぶ必要があるだけです。聴衆からさらに質問を待っている間に、あなたは、あなたが FAQ をいくつか用意していたのは知っていますが、それを一通り見ていきますか?はい。では、何を、サイドモードに戻って、では、ああ、ここでこの最後の質問に答えましょう。ええと、ソースは完全に正確なのか、つまり、その、プロンプトの応答が本当にソースとして提示されたドキュメントから引用されているという保証があるのか、という意味ですか?私は、ええと、そうですね、それは本当に良い質問です。
私は、はい、と言いたいですが、繰り返しになりますが、そうですね、ええと、大規模言語モデルはニューラルネットワークです。つまり高度な統計的手法です。そして、ソースを与えたからといって、場合によっては、それが可能ではないということにはなりません。たぶん 0. 1% のケースでは、間違った答えを返してしまうことがあります。ええと、しかしこれは非常に起こりにくいと言えるでしょう。ええと、そして実際には、l l M に正しくプロンプトを与えれば、それをほぼ完全に取り除くことができるはずです。
ええと、でもソフトウェアに完璧というものはありません。それはまた、ソースを知ることと、そのソース自体の正確性との境界をどこで理解するか、という別の興味深い点にもつながると思います。つまり、The Onion と、たとえば AP との違いというか、その間には大きな幅があります。ですから、引用や出典表示は、このような幻覚的な誤情報の一部に対抗する助けになるということを、私たちは引き続き覚えておく必要があると思います。ええと、ただし、それが元のソース自体の中に存在する場合もあるということを忘れてはいけません。
はい。ええと、はい、すべてのソースが同じレベルの信頼性を持っているわけではありません。私が用意している FAQ は主にベクターデータベースに関するものです。というのも、これは私が主に話している内容だからです。だからこそ、これについて多くの質問を受けます。
ええと、引用や出典表示を使うべきでない場合にも当てはまると言っておきます。ええと、ただ本当に「使うべきでない」ユースケースは、たとえば「データがどこから来たかは気にしない。ただチャットボットを使えるようにしたいだけだ」という場合です。その場合は、使わなくていいですし、必要ありません。それは、理由もなく余計な作業を増やすだけです。
ええと、ベクターデータベースを使いたくない場合は、キー・バリュー型のデータしかない場合です。つまり、大量のキー・バリュー型データを扱っているなら、ええと、類似性は必要ありません。ですから過剰です。ええと、わかりました。それから、CSV ファイルや PDF に関する話をよく見かけます。特にベクトル化に関してです。
ええと、CSV や PDF に対応したモデルの選択肢はあまり多くないようです。そしてベクトル化の課題は、埋め込みやベクトル化しようとしているデータと同じ種類のデータで学習されたモデルが必要だということです。ですから、CSV や P D F データで学習されたモデルはあまり多くありません。ええと、そのため、これらを使ったベクトル化は難しいです。これらについて私が提案するのは、CSV を各行ごとに完全な文に変換してみること、そして PDF をテキストに変換し、それをチャンクに分割して、両方をテキストとして保存することです。
ええと、最後に、ときどき質問されるのがハイブリッド検索です。ハイブリッド検索とは、構造化データと非構造化データをどのように一緒に検索するか、というものです。そして Novus では、フィルターと呼ばれるものを通じてこれを行えます。たとえば、「公開日が 2023 年 8 月 1 日以降のものを検索する」といった指定ができます。そんな感じです。はい、これらが私が通常受ける FAQ です。そしてチャットがもう少しありますね。ああ、わかりました。
いえ、ありませんね。わかりました。ええと、いいですね。これでこのセクションについて私が用意している内容はほぼすべてです。Eugene への追加の質問があれば、これが最後の機会です。
そうでなければ、セッションを締めくくります。もう 1 分ほどお待ちします。ええと、その間に、Eugene、この本当に素晴らしいセッションと、私たちに順を追って説明してくださったことに感謝します。ええと、聴衆からの質問に対して、かなりじっくりと考える時間を取れたことは、このプレゼンテーションの非常に力強い部分だったと思います。そして本日私たちと時間を過ごしてくださった皆さんに、本当に感謝しています。ハイブリッド検索について、もう 1 つ来ているようです。
フィルター対象にするためのメタデータを追加する方法はありますか?はい。ええと、実際、ハイブリッド検索では、ええと、その、QR コードをちょっと移動します。ハイブリッド検索では、ええと、それはメタデータ上で行われます。実際、ハイブリッド検索でできるほぼ唯一のことは、ええと、メタデータでフィルタリングすることです。
ええと、そしてこの話題が出ているので、ここでちょっと面白い小話をします。Vis はビットマスクを適用することでこのハイブリッド検索を実行します。つまり、「これを検索してからフィルターする」とか、「先にフィルターしてから検索する」といったものではありません。フィルターをビットマスクに変換することで、実際には検索とフィルタリングを同時に行うことができます。とても面白いです。つまり、それによって、ええと、基本的に、ええと、クエリ時間を大幅に短縮できるのです。
はい、速いです。基本的には線形時間だからですよね?だから本当にすごいです。私は、わあ、という感じでした。それを学んだとき、ただ、ああ、これは本当に面白いな、と思いました。では。
今日のセッションの最後の質問はこれだと思います。ええと、先ほどお伝えしたように、今日のセッションは録画されていますので、リプレイへのリンクをお送りします。ええと、Ian、本当にありがとうございました。素晴らしかったです。よかったです。
はい。ありがとうございます。

Join the Webinar
Loading...
Meet the Speaker
Join the session for live Q&A with the speaker

Yujian Tang
Developer Advocate at Zilliz
Yujian Tang is a Developer Advocate at Zilliz. He has a background as a software engineer working on AutoML at Amazon. Yujian studied Computer Science, Statistics, and Neuroscience with research papers published to conferences including IEEE Big Data. He enjoys drinking bubble tea, spending time with family, and being near water.


