HUOXIU

AIアプリケーション開発の実践的な共有 - 基礎

出典: Bilibili Technology


「フロントエンド開発者から AI への移行: 最初の講義が始まりました!」


導入


あなたがフロントエンド開発者であり、AI 開発にも興味があるなら、おめでとうございます。チャンスが到来しました。

そうでなくても大丈夫です。AI アプリケーションの開発プロセスを理解するのに役立ちます。

この記事では、AI 開発の基礎から RAG、エージェント、プロセス オーケストレーションまでを解説し、企業内で AI プロジェクトを実装する方法を詳細に理解できるようにします。


基本


I. AIとの関わり方


通常、テキストを入力すると、AIモデルは大規模なモデル自体に基づいて応答します。これはほとんどの人が既に知っていることです。しかし、私たちが期待するコンテンツ、より具体的には個人情報に基づいてAIに応答させるにはどうすればよいでしょうか?

1. モデルのトレーニング
2. 微調整
3. プロンプトプロンプトワードプロジェクト
4. RAG検索の生成強化

モデルのトレーニング:

Huggingfaceからオープンソースモデルをダウンロードし、新しくリリースされたLlama 3 8Bバージョンなどのローカルにデプロイすることで、小規模なモデルではGPU要件が比較的低くなります。その後、大量のドキュメントを用いてモデルのトレーニングを完了できます。

モデルを小型化することでGPUコンピューティングリソースを削減できますが、そのコストは依然として一般企業にとって手の届かないものです。ハードウェアコストとモデル最適化のための人的コストに加え、モデルの陳腐化リスクも存在します。外部の大手企業が大きな動きを見せれば、学習済みモデルは陳腐化に直面するでしょう。しかし、AIは避けられないトレンドであるため、企業は防御戦略を採用し、まずAIを導入すべきです。モデルのアプリケーション層インターフェースはオープンソースコミュニティで標準化されており、開発・設計段階ではモデルと機能が分離されているため、いつでも置き換え可能です。

微調整:

多くの商用 AI サービス モデルはこの機能を提供しており、ユーザーは特定のアプリケーション シナリオに合わせて事前トレーニング済みのモデルを調整し、期待に応える出力結果を得ることができます。

例えば、社内に「プロジェクト」というコードネームの社内プロジェクトがあり、LLMモデルを用いて「プロジェクト」に関するドキュメントを自動生成したり、従業員からの問い合わせに回答したりしたいとします。しかし、事前学習済みのモデルは「プロジェクト」という用語をこれまで使用したことがないため、正確な情報を生成できません。このような場合、用語やコンテキストを追加することで、モデルによるこのトピックの理解を調整できます。

最後に、微調整は有料サービスです。将来的に別のモデルに切り替える場合、新しいモデルの特性や改善点に合わせて再度微調整を行う必要があります。これにも計算コストと時間コストが発生します。

プロンプトプロンプトワードプロジェクト:

これはおそらく、AI開発に不慣れな人がAIに期待通りに指示を実行させるために最初に用いる方法でしょう。例えば、モデルに可能な限り中国語で応答させるなどです。役割、経歴、スキル、出力スタイル、出力範囲を含む一連のプロンプトを用意し、各コミュニケーションのコンテキストに組み込む必要があります。

chat_model(Langchain用語)方式を使用する場合、システムプロンプトは常にメッセージ配列のキー0に保持されます。LLM(Langchain用語)方式を使用する場合、プロンプトと質問は各通信中にメッセージ文字列にラップされます。ここでは、chat_modelソリューションに基づいて開発する必要があります。

しかし、Promptを独自のプロジェクトに正式に統合しようとすると、最適化が非常に難しく、AIが要求通りに動作しない可能性があります。まとめると、Promptには以下の問題点があります。

1. 設計が難しい。モデルの出力がプロンプトに依存する場合、より良い出力を得るためにプロンプ​​トを絶えず調整しなければならないというループが発生する可能性があります。
2. 長さ制限:各通信メッセージは通常、プロンプト、nラウンド分のコンテキスト履歴、現在の質問で構成されます。これらのコンテンツの合計単語数は、1セッションの計算に必要なトークンコストの合計でもあります。プロンプトが長すぎると、AIが錯覚を起こしやすく、応答結果に影響を与える可能性があります。
3. Prompt では、社内のナレッジベースを使用してモデルがプライベート ドメイン クエリに応答できるようにするという問題が依然として解決できません。

強化された RAG 検索生成:

RAG は初心者にとっては少し抽象的かもしれないので、Langchain の図を使用して説明しましょう。

1. まず、ベクトルストレージを埋め込みます。

内部ドキュメントからコンテンツを抽出した後、それをチャンクに分割し、段落配列(チャンク)に変換します。これらのチャンクは、より大きなモデルの埋め込みインターフェースに渡され、浮動小数点数を返します。このプロセスは埋め込みと呼ばれます。最後に、浮動小数点数をElasticsearchやFaissなどのベクトルライブラリに保存します。



2. 次はコンテンツの想起です。

質問を入力として受け取り、まずモデル埋め込みを使用してそれをベクター データに変換し、次にドキュメント ライブラリで類似性検索を実行して類似度の高いデータを呼び出し、それをより大きなモデルにフィードして要約し、最後にユーザーに返します。



上記がRAGプロセス全体です。RAGは非常に技術的に要求の厳しい作業であり、上記のプロセスではRAGの複雑さを全て説明することはできません。製品の発売後も、私たちはRAGの品質向上に絶えず取り組んでいます。使いやすくするのは簡単ですが、完璧に仕上げるのは非常に困難です。

現在のソリューションと実際のオンライン パフォーマンスについては、後ほど社内ナレッジ ベースについて説明するときに説明します。

別の記事で見た引用文に共感できます。


RAGは、埋め込み、単語のセグメンテーションとチャンキング、検索リコール(類似性マッチング)、チャットシステム、ReActとPromptの最適化、そして最後にLLM(ローカルレベルモデル)とのインタラクションなど、幅広い側面を伴います。プロセス全体は技術的に非常に複雑です。優れたLLMを使用している場合、大規模なモデル部分についてはあまり心配する必要はありません。しかし、これらのステップのいずれかで1を達成できない場合(例:0.9、0.7など)、最終結果はこれらの小数点の積になる可能性があります。

https://mp.weixin.qq.com/s/WjiOrJHt8nSW5OGe2x4BAg


II. エージェント


前のセクションでは、主にAIによるテキストコンテンツの配信に焦点を当てました。では、AIが作業の配信を完了できるようにするにはどうすればよいでしょうか?

作業報告中に AI エージェントの機能をデモンストレーションするために以下の画像を使用すると非常に魅力的だと思いませんか?


(QCon プレゼンテーションからの画像)


現在、エージェントを実装するには主に 2 つの方法があります。

ReAct自己推論

数ショットのプロンプト + 思考 + 行動 + 観察

ツール、推論、計画を含むプロンプト構造を構築することにより、モデルはプロンプトとの対話を通じて内部的に反復および調整を行い、適切なツールを選択したり、より優れた出力を生成したりします。

例えば:













 { "messages": [ { "role": "system", "content": "アシスタントはOpenAIによってトレーニングされた大規模な言語モデルです。\n\nアシスタントは、簡単な質問に答えることから、幅広いトピックに関する詳細な説明や議論を提供することまで、幅広いタスクを支援できるように設計されています。言語モデルとして、アシスタントは受け取った入力に基づいて人間のようなテキストを生成することができ、自然な会話に参加し、話題に関連性のある一貫性のある応答を提供することができます。\n\nアシスタントは常に学習と改善を続け、その機能は常に進化しています。大量のテキストを処理・理解することができ、この知識を使用して、幅広い質問に対して正確で有益な応答を提供することができます。さらに、アシスタントは受け取った入力に基づいて独自のテキストを生成することができるため、幅広いトピックに関する議論に参加したり、説明や記述を提供したりすることができます。\n\n全体として、アシスタントは幅広いタスクを支援し、幅広いトピックに関する貴重な洞察と情報を提供できる強力なシステムです。特定の質問についてサポートが必要な場合や、特定のトピックについて会話をしたい場合は、アシスタントがお手伝いします。ただし、何よりもまず、すべての回答は「回答フォーマットの指示」の形式に準拠する必要があります。 }, { "role": "user", "content": "ツール\n------\nアシスタントは、元のユーザーの質問に答えるのに役立つ可能性のある情報を検索するツールを使用するようにユーザーに依頼できます。ユーザーが使用できるツールは次のとおりです。\n\ninfo-tool: https://info.bilibili.co/ から1つ以上のURLを介してコンテンツを取得する必要がある場合に便利です。入力は、\"ドメイン https://info.bilibili.co/pages/viewpage.action を持つ1つ以上の有効なURL(URLにはpageIdパラメータを含める必要があります)\"の後に\"要約する必要がある情報、または要約を取得するために必要な情報\"の形式で、カンマ区切りのリストにする必要があります。\n\n応答形式の指示\n----------------------------\n\n有効なJSONオブジェクトを含むJSONマークダウンコードスニペットを、次の2つの形式のいずれかで出力します。\n\n**オプション1:**\nユーザーがツール。\n次のスキーマでフォーマットされたMarkdownコードスニペット:\n\n```json\n{\n \"action\": string, // 実行するアクション。[info-tool]のいずれかである必要があります\n \"action_input\": string // アクションへの入力。文字列化されたオブジェクトの場合もあります。\n}\n```\n\n**オプション #2:**\n人間に直接会話形式で応答する場合は、こちらを使用します。次のスキーマでフォーマットされたMarkdownコードスニペット:\n\n``json\n{\n \"action\": \"Final Answer\",\n \"action_input\": string // 返したいものをここに記述し、有効なjson改行文字を使用してください。\n}\n```\n\nどちらのオプションでも、常に前後のMarkdownコードスニペット区切り文字を含めることを忘れないでください(\"```json\"で始まり、 \"```\")!\n\n\nユーザーの入力\n--------------------\nユーザーの入力は次のとおりです (1 つのアクションのみを含む JSON BLOB のマークダウン コード スニペットで応答し、他には何も応答しないでください):\n\nhttps://info.bilibili.co/pages/viewpage.action?pageId=849684529\nこの記事の内容" } ]} 


モデルにツールを用いた問題解決能力があることを伝えるために、プロンプトを使用し、各ツールの紹介と入力が必要なパラメータを提供します。最後に、モデルが毎回マークダウンコード形式でレスポンスを返すように要求します。そして、返されたJSONスキーマをエージェントプロセスで使用し、ツールを呼び出すか最終回答を使用するかを判断します。

ツール呼び出しプロキシの相互作用

ReAct によってコンテキストが長くなりすぎることは明らかであり、これにより、モデルが数回の反復後にマークダウン コード形式でコンテンツを返す可能性が高くなり、最終的にエージェントが停止する可能性があります。

ツールコールの登場により、この問題は解決されます。プロンプト内の非構造化ツールの説明を構造化されたAPIフィールドに変換することで、プロンプトのコンテキストの長さが短縮され、制御が容易になります。

例えば:



































 // POST /chat/completions{ ... "tools": [ { "type": "function", "function": { "name": "info-tool", "description": "pageId で 1 つ以上の xxxx ウェブサイトを開き、ユーザー要件を完了してください", "parameters": { "type": "object", "properties": { "pageId": { "type": "number", "description": "URL の pageId を入力してください。複数のページはコンマで区切ってください" }, "task": { "type": "string", "description": "要件を説明してください" } }, "required": [ "pageId", "task" ], "additionalProperties": false, "$schema": "http://json-schema.org/draft-07/schema#" } } }, ...その他のツール ], ...} 


この時点で、モデルは構造化された方法で、使用するツールも示します。

















 // API レスポンス{ ... "tool_calls": [ { "index": 0, "id": "info-tool:0", "type": "function", "function": { "name": "info-tool", "arguments": "{\n \"task\": \"ページ コンテンツの取得\",\n \"pageId\": 845030990\n}" } } ] ...} 


III. 開発の枠組み


次に、私たちが選択した技術フレームワークを紹介し、その長所と短所について説明します。

ランチェイン

LangchainはAIに関する多くの記事で言及されており、多くのオープンソースフレームワークと比較されています。Langchainは商用モデルとオープンソースモデルを統合し、言語モデルベースのアプリケーションの開発、統合、展開を簡素化するための包括的なツールと機能を提供します。

- コンポーネント化:言語モデルを利用するための抽象化レイヤーと、各抽象化レイヤーの実装セットを提供します。コンポーネントはモジュール化されており、LangChainフレームワークの他の部分の使用の有無にかかわらず、簡単に使用できます。
- 既製のチェーン: 特定の高レベルタスクを実行するために使用されるコンポーネントの構造化されたコレクション。

簡単に言えば、さまざまなモデルやコンポーネントに対して統一された入力および出力仕様を提供します。

チェーンは [プロンプト、モデル、ツール、メモリ (履歴セッション)、OutputParser] を受け入れることができ、複数のモデルをネストして、前のモデルの出力を次の PromptTemplate の入力として使用することもできます。

現在、公式サイトでは Python と Node.js の 2 つの言語のバージョンが提供されています。

フローワイズ

LangchainをベースとしたAIプロセスオーケストレーションシステムは、Node.jsをメイン言語として採用しています。Langchain内の各モデルクラスとコンポーネントクラスに対し、視覚的なローコードコンポーネントを提供しています。キャンバス上でコンポーネントをドラッグ&ドロップするだけで、AIデリバリープロセス全体を構築できます。コンポーネントには、Chain、Prompt、Agent Tool、Chat Moduleなどがあります。

Dify も同様のソリューションであり、マルチモデル統合、RAG、タスク オーケストレーションを含む製品化されたソリューションの完全なスイートを提供します。

Flowwiseは、ソリューションを提供する必要最低限​​の家のようなものですが、製品化には依然としてカスタム開発が必要です。Flowwiseを理解することで、Langchain開発の効率が大幅に向上します。Difyは、高級ヴィラのようなものです。ほとんどの機能は既に製品化されており、モデルのAPIカプセル化を独自に維持しており、主要言語はPythonです。

Flowwise のパッケージの紹介:

- サーバー: Express、CRUD、コンポーネント ライブラリ内でインスタンスの実行を完了します。
- コンポーネント: JavaScript。Langchain クラスの視覚化とローコード実装を提供します。
- UI: React、AI ワークフロー オーケストレーションのキャンバス、およびいくつかのメンテナンス ページ。

以下は、エージェントを介してAIが使用するツールを決定するオーケストレーションのデモです。ツール呼び出し機能により適したよう、エージェントコンポーネントを再開発しました。Bili Agentのメインプロセス内で、このコンポーネントは関連ツールの利用を担当します。



部分的なコード例

















































 import { AgentExecutor } from 'langchain/agents' // ツールの構成情報をモデルインターフェース内のツールの構造化フィールドに変換します // インターフェース仕様が整合されているため、formatToOpenAITool 関数を直接使用できます const modelWithTools = model.bind({ tools: [...tools.map((tool: any) => formatToOpenAITool(tool))]}) // 順番に組み合わせます const runnableAgent = RunnableSequence.from([ // ユーザーの指示、モデルメッセージ内の tool_calls をフォーマットすることによって取得された ToolMessage、およびコンテキストチャット履歴が含まれます // これらはすべて prompt に入力されます { [inputKey]: (i: { input: string; steps: AgentStep[] }) => i.input, agent_scratchpad: (i: { input: string; steps: ToolsAgentStep[] }) => formatToolAgentSteps(i.steps), [memoryKey]: async (_: { input: string; steps: AgentStep[] }) => { const messages = (await memory.getChatMessages(flowObj?.sessionId, true, chatHistory)) as BaseMessage[] return messages ?? [] } }, prompt, modelWithTools, new OpenAIToolsAgentOutputParser()]) const executor = AgentExecutor.fromAgentAndTools({ agent: runnableAgent, tools, returnIntermediateSteps: true, maxIterations: 5}) executor.invoke({input: '明日の日付は何ですか?'}) ​​// tool_callsの例 { "tool_calls": [ { "index": 0, "id": "GetDate:0", "type": "function", "function": { "name": "GetDate", "arguments": "{\n \"task\": \"Get tomorrow's date\"\n}" } } ]} 


最後に、エージェント構成を通じて、モデルは一般ドメイン、プライベート ドメイン、またはツール プラグインでチャットすることを自由に選択できます。



これで基礎セクションは終了です。なぜフロントエンド開発者を称賛することから始めたのか、お分かりいただけたでしょうか。そう、上記で説明したテクノロジースタック全体は、フロントエンド開発分野から生まれたものです。

次の記事では、プロジェクトの適用という観点から、製品化されたAIプラットフォームに必要なソリューションについてご紹介します。また、ローコードやクラウド機能といった他のフロントエンド分野の技術についてもご紹介します。


-終わり-

著者 | Zerooo