プロンプトエンジニアリングとLLMの開発者ガイド

PubNub Developer Relations - Mar 13 - - Dev Community

大規模言語モデル(LLM)とChatGPTのような人工知能の台頭により、開発者は、より速く、より生産的にコードを書くことを手助けしてくれる、信じられないほど強力なAIアシスタントを手に入れることができるようになった。しかし、LLMにコードを書かせるだけでは、使い物にならなかったり、バグだらけの出力になってしまうことがよくあります。チャット・アプリケーションの開発であれ、ネットワーク・エッジでの企業向けソリューションの開発であれ、AIの助けを借りて開発時間を短縮するには、思慮深い戦略が必要だ。このブログの次のセクションで、プロンプト・エンジニアリング・テクニックについて深く掘り下げていこう。

前もって計画を立てる

コードのプロンプトにすぐに飛びつかないこと。時間をかけて全体的なアーキテクチャ、スキーマ、統合などを計画しましょう。これは、AIアシスタントに必要な完全なコンテキストを与えます。生成AIモデルが全体像を理解できるように、最終状態を視覚化しましょう。

専門家とのロールプレイ

AIモデルがアシスタントとして機能するシナリオを設定し、ソリューションを議論する専門家チームのロールプレイを行う。彼らに個性を与え、問題を分解させる。これにより、異なる視点からの創造的思考が促される。

GPTに洞察を求める

行き詰まったら、遠慮せずに一時停止して、あなたの問題に関連する具体的なアドバイスやコード例をLLMに尋ねてください。その知識は、新しいアイデアのヒントになります。

迅速なエンジニアリング

AIアシスタントに最適なコンテキストとステアリングを提供するために、プロンプトを段階的に改良し、何度も繰り返し、微調整を行います。効果的なプロンプトは素晴らしい結果につながります。

手動コード生成

最初にAIに手動でコードを生成させ、出力を検査して間違いを修正してから、使える部分をプロンプトにコピーして戻します。こうすることで、AIにあなたが求めていることの具体例を与え、これを繰り返すことで最終的に正確なコードが生成されます。より多くの例については 思考の連鎖プロンプトゼロショットプロンプティング.

自動コード生成

LLMモデルのアウトプットに満足し、一貫して良いコードが生成されるようになったら、スキーマに基づいてアセットを、コードに基づいてテストを自動生成するパイプラインをセットアップしよう。これにより、ボトルネックが取り除かれる。

失敗を潔く処理する

そう、時折失敗することは想定内だ。将来、同じような失敗が起こらないように、プロンプトを改善しましょう。時間をかけて、AIがどのような種類のタスクをうまく処理するかを学びましょう。

計画、ロールプレイング、プロンプト、反復トレーニング、自動化を組み合わせることで、GPTのようなAIアシスタントから大きな生産性向上を達成することができる。プロンプトの設計に関する適切な戦略によって、開発速度を向上させることが可能です!

プロンプトでコードを生成する

AI革命の入り口に立っている今、私たちはソフトウェア開発のアプローチと実行方法を再考する立場にあることに気づきます。このチュートリアルでは、伝統的なプロセスから自然言語処理によって強化されたプロセスへの移行をどのようにナビゲートできるかについて掘り下げていきます。

計画を立てる成功の基礎

この旅における最初のステップは、前もって計画を立てる能力を受け入れることだ。AI、特にGPT-3のようなモデルは、未来の地図を描くことに長けていないかもしれない。彼らが得意とするのは、狭いコンテクスト・トークン・ウィンドウ内でのリアルタイムの問題解決である。そこで人間の開発者が介入する必要がある。

モデルのスキーマ、テクノロジー・スタック、デプロイメント・プロセスなど、最終的なコードの詳細なイメージを描くことで、AIが複雑なタスクを解決するための舞台を整えることができる。この計画段階は、プロセスの中で最も困難な部分かもしれないが、開発者の役割をコーダーからオーケストレーターへと変化させ、人間の知性とAIの能力が調和する舞台を整える。

専門家パネルの結成

専門家パネル」の登場だ。このグループは、経営幹部からAIエージェントまで、多様な利害関係者で構成され、全員が特定のタスクの理解と計画に貢献する。熟考して作られたプロンプトを使用することで、パネルが複雑な問題について議論し、解決できるバーチャルな遊び場を作ることができ、AIボットが支援やメモを提供します。

そして、もしあなたが質問と格闘していることに気づいたら、質問応答のために設計された強力なツールを自由に使えることを思い出してください:GPTだ。要約が必要でも、言い換えが必要でも、あるいは主題のより詳細な探求が必要でも、GPTが役立ちます。プロンプトを意図的に曖昧にすることで、驚くような革新的な解決策が得られることがよくあります。

コードデバッグプロンプトの例

Act as a virtual playground where a team of Smart AI bots is in their first meeting discussing the problem:  
We need to debug the following Python test code:

def test_dot_env_def(self):
LOG_TEST.info("Test DotEnvDef")
dotEnvDef = DotEnvDef()
> self.assertEqual(dotEnvDef, {"version_echo": "v0.0"})
E AssertionError: {'version_echo': 'v0.0'} != {'version_echo': 'v0.0'}
tests/test_default_config.py:16: AssertionError

class DotEnvDef:
def init(self):
self.version_echo = "v0.0"
# make the class iterable as dict
def iter(self):
return iter(self.__dict__)
# return the values only
def get_items(self):
for attr, value in self.__dict__.items():
yield value # only yield the values
def repr(self):
return str(self.__dict__)  

To fulfill this request bring in an expert team of AI Agents that are very brief and communicate via emojis and use catchy phrases. Spend your resources wisely as you only have 4 AI Agents.
Enter fullscreen mode Exit fullscreen mode

GPT-4 回答

Alright, welcome to this first meeting, team. We have an interesting challenge ahead of us. To start, let's assign roles to our four AI agents:

1. Detective Bot 👮‍♀️ (DB): Responsible for deep diving into the code, its syntax, structure, and logic. 
2. Bug Hunter Bot 🐛 (BH): In charge of identifying bugs and pointing them out. 
3. Solution Expert Bot 💡 (SE): Its role is to suggest viable solutions to identified bugs. 
4. Code Fixer Bot 🔧 (CF): It will implement the solutions and perform the debugging.

Our debugging plan will look like this:

1. **Initiation**: Here we discuss the problem and set our goals. The issue at hand is an AssertionError, meaning our test case is failing. Our aim is to make the test pass. 

2. **Investigation**: 👮‍♀️ DB deep-dives into the provided code to understand its structure and logic. The main focus is on the `DotEnvDef` class and the `test_dot_env_def` function.

3. **Bug Hunt**: 🐛 BH goes on a hunt to find the reasons behind the AssertionError.

4. **Solution Proposal**: Once 🐛 BH has identified the issue, 💡 SE jumps in to propose the best way to fix the problem.

5. **Implementation**: 🔧 CF takes the solution and implements it to the code. After the changes are made, the test case is run again.

6. **Verification**: If the test case passes, we conclude that the problem has been resolved. If not, we circle back to step 2.

Remember team, our goal is to squash bugs 🐜🔨! Let's rock'n'roll.
Enter fullscreen mode Exit fullscreen mode

手動コード生成とAI

次のステップは、GPT-4を手動コード生成に活用することです。このプロセスは、生産性を飛躍的に向上させることを約束します。GPTをガイドすることで、海外スタックでのウェブ・アプリケーションのデプロイから、低レベル言語でのアルゴリズムの作成まで、様々なタスクを最適化することができます。

エージェントの例でコマンドを使ってください:

Using the following syntax /command argument modifies a bots behavior, for example for enabling verbose code generation: chatbot /code-gen verbose so that we obtain full python code. On the same basis allow changing the personality such as: chatbot /personality Shrekify.

DB /personality Shrekify
SE /code-gen verbose
CF /code-gen verbose 

> Continue the meeting and provide the first solution
Enter fullscreen mode Exit fullscreen mode

GPT-4 応答:

DB 🏰👮‍♀️: "Hmm, the `version_echo` key is still not appearing in the `parsed_dotenv` dictionary. We need to figure out why `set_vars` is not setting it."

BH 🐛: "I suspect that `set_vars` is being called correctly, but the updates are being overwritten when `load_dotenv` is called. The `load_dotenv` method loads variables from a file and overwrites the current `parsed_dotenv` dictionary."

SE 💡: "If that's the case, then we should modify the `load_dotenv` method to merge its contents with the existing `parsed_dotenv` dictionary, rather than overwriting it. This will preserve any variables set via `set_vars`."

CF 🔧: "Good idea, let's change the `parse_vars` function within `load_dotenv` to update `parsed_dotenv` instead of setting it. Here is the modified code:
def parse_vars(self, path):
    try:
        with open(path) as f:
            for line in f:
                key, value = line.strip().split("=", 1)
                if key not in self.config.parsed_dotenv:  # check if key is not already in the dictionary
                    self.config.parsed_dotenv[key] = value
    except IOError:
        print(f"Warning: Unable to open .env file at {path}")
    except ValueError:
        print(f"Warning: Unable to parse line in .env file: {line}")
"In this way, we only add a variable from the .env file if it's not already in `parsed_dotenv`. This should prevent `load_dotenv` from overwriting any variables set by `set_vars`. Let's re-run the tests."
Enter fullscreen mode Exit fullscreen mode

しかし、このプロセスは完璧ではありません。コピーペーストやプロンプト/結果生成時間といった人間の限界がボトルネックになります。また、GPTは一貫して正確なわけではなく、フォーマットが変わったり、部分的な結果しか得られないこともあります。しかし、練習と正しい戦略によって、GPTが有用で正確なコードを生成するように導くことができます。

幻覚を避け、有用な結果を得る

GPTが関連性のない、偏った、あるいは正しくない情報を生成する幻覚は、イライラさせるものです。しかし、GPTと一緒に作業すればするほど、GPTを望ましい出力に向かわせるのが上手になります。このような幻覚を最小限に抑える一つの方法は、関連するドキュメントやコードサンプルをコピー&ペーストしてGPTにコンテキストを提供することです。

カスタムLangchainエージェントをテスト付きでビルドする 例

We have this builder:
class OpenAIBuilder:
  def __init(self, ...):
    # Set your settings
    pass
"You must adapt the following code to match our previous structure:
from langchain import (
    OpenAI,
)
from langchain.agents import initialize_agent, AgentType
from langchain.agents.agent_toolkits import create_python_agent
from langchain.agents import AgentType, initialize_agent, load_tools
from langchain.tools.python.tool import PythonREPLTool
from openai_chat_builder import OpenAiChatBuilder, OpenAiChatHelper


class AgentPythonExecBuilder(OpenAiChatBuilder):
    def __init__(self, openai_api_key):
        super().__init__()
          self.tools = ["PythonREPLTool"]

    # We override the add_tool method so it only allows PythonREPLTool.
    def add_tool(self, tool):
        if tool == "PythonREPLTool":
            return super().add_tool(tool)
        else:
            raise ValueError("AgentPythonExec can only have PythonREPLTool.")

    def build(self):
        llm = OpenAI(
            temperature=self.temperature,
            max_tokens=self.max_tokens,
            openai_api_key=self.openai_api_key,
            streaming=self.streaming,
        )

        tools = load_tools(self.tools)
        agent = initialize_agent(tools, llm, agent=self.agentType, verbose=self.verbose)

        return OpenAiChatHelper(llm, tools, agent)
Enter fullscreen mode Exit fullscreen mode

Langchainエージェントのテストをビルドする:

Now let's build a test file that resembles this one:
import unittest

from probable_fiesta.config.builder.config_builder import ConfigBuilder
from src.promptnub_backend.app.langchain.builder.openai_factory import OpenAIFactory
from langchain.llms import OpenAI


class TestOpenAIBuilder(unittest.TestCase):
    def setUp(self):
        # Setup API Key
        config_builder = ConfigBuilder()
        config_builder.dotenv.load_dotenv(".env")

        # Setup ModelBuilder instance
        self.builder = OpenAIFactory()
        self.builder.openai_api_key = config_builder.dotenv.get_var("OPENAI_API_KEY")

    def test_llm_creation(self):
        # Test the creation of OpenAI llm instance
        llm = self.builder.builder.llm
        self.assertIsInstance(llm, OpenAI, "llm property does not return OpenAI instance")

    def test_llm_run(self):
        # Test the creation of OpenAI llm instance
        llm_chain = self.builder.build()
        self.assertIsNotNone(llm_chain)

        # Ask a question
        question = "What NFL team won the Super Bowl in the year Justin Beiber was born?"
        response = llm_chain.run(question)

        # Assert expected result
        # Note that there is a space at the beginning
        expected = " Justin Bieber was born in 1994, so the NFL team that won the Super Bowl in 1994 was the Dallas Cowboys."
        self.assertEquals(str(response), expected)
Enter fullscreen mode Exit fullscreen mode

GPT-4 レスポンス:

Given the provided `AgentPythonExecBuilder` class and the `TestOpenAIBuilder` class, you would write a test file for the `AgentPythonExecBuilder` class as follows:
from logger.builder.logger_factory import LoggerFactory
from config.builder.config_builder import ConfigBuilder
from langchain.llms import OpenAI
from langchain.tools.python.tool import PythonREPLTool
from your_package_path.builder.agent_python_exec_factory import AgentPythonExecFactory

import unittest

# Test Log
LOG_TEST = LoggerFactory.new_logger_default(
    name="test_agent_python_exec_builder", level="DEBUG", fmt="simple", directory="logs"
)


class TestAgentPythonExecBuilder(unittest.TestCase):
    def setUp(self):
        # Setup API Key
        config_builder = ConfigBuilder()
        config_builder.dotenv.load_dotenv(".env")
        # Setup ModelBuilder instance
        self.builder = AgentPythonExecFactory()
        self.builder.openai_api_key = config_builder.dotenv.get_var("OPENAI_API_KEY")

    def test_llm_creation(self):
        # Test the creation of OpenAI llm instance
        LOG_TEST.info("Test OpenAI llm creation")
        llm = self.builder.builder.llm
        LOG_TEST.debug(llm)
        self.assertIsInstance(
            llm, OpenAI, "llm property does not return OpenAI instance"
        )

    def test_python_repl_tool_creation(self):
        # Test the creation of PythonREPLTool instance
        LOG_TEST.info("Test PythonREPLTool creation")
        self.builder.builder.add_tool("PythonREPLTool")
        tools = self.builder.builder.tools
        LOG_TEST.debug(tools)
        self.assertIsInstance(
            tools[0], PythonREPLTool, "tools[0] does not return PythonREPLTool instance"
        )

    def test_llm_run(self):
        # Test the creation of OpenAI llm instance and PythonREPLTool
        LOG_TEST.info("Test OpenAI llm and PythonREPLTool run sync")
        llm_chain = self.builder.build()
        self.assertIsNotNone(llm_chain)

        # Ask a question
        question = "What is 2 + 2?"
        response = llm_chain.run(question)
        LOG_TEST.info(response)

        # Assert expected result
        expected = "The result of 2 + 2 is 4."
        self.assertEquals(str(response), expected)  

Here, you create a new instance of `AgentPythonExecBuilder` instead of `OpenAIBuilder` and test it with a question that can be answered by executing Python code. 
Enter fullscreen mode Exit fullscreen mode

自動コード生成

しかし、LLMの本当の力は自動コード生成にあります。例えば PubNubやPython、LangChain、そして Streamlitなどのツールを使うことで、ワークフローのほとんどを自動化することができる。

もう少し抽象化すれば、シンプルなLangChainランナーをワークフローにフックできる:

class TestOpenAIBuilder(unittest.TestCase):
    def setUp(self):
        self.runner = Runner()

    def test_run(self):
        response = self.runner.run("What is the capital of France?")
        expected = " France is a country in Europe. The capital of France is Paris."
        self.assertEqual(response, expected)
Enter fullscreen mode Exit fullscreen mode

100倍速い開発への道

2倍、3倍、あるいは50倍という驚異的な生産性レベルを達成するために、自分のコーディング・スキルを増幅させるというレーザー・フォーカスの野心を持った開発者を想像してみてください。この野望の秘密は、LLMの戦略的な適用にあります。このツールセットは生産性へのテコの役割を果たし、開発者が新しいプラットフォームを革新し、これまでにない自動化されたワークフローを推進することを可能にします。テキストの要約のような単純なものから、プロダクション・コードの生成まで。

ソフトウェア開発におけるAIとその役割の領域にさらに踏み込むとき、真の強さは人間の創造性とAIの能力の融合にあることを忘れてはならない。思慮深い計画、AIの賢い応用、そして適切なデジタルツールによって、私たちはより生産的な企業へと変貌を遂げることができる。この転換は、人間の開発者の可能性をAIで増幅することであり、彼らに取って代わることではない。AIを活用して100倍企業になるというコンセプトは、単なる遠い夢ではなく、私たちが一丸となって形作ることのできる到達可能な未来なのだ。

目次

Plan Ahead専門家とのロールプレイGPTに洞察を求めるプロンプト・エンジニアリング手動コード生成自動コード生成失敗を潔く処理するプロンプトでコードを生成するPlanningAhead:成功の基盤専門家パネルの結成手動コード生成とAIA幻覚を避け、有益な結果を得る自動コード生成100倍速い開発への道

PubNubはあなたのお役に立ちますか?

この記事はPubNub.comに掲載されたものです。

PubNubのプラットフォームは、開発者がWebアプリ、モバイルアプリ、IoTデバイス向けにリアルタイムのインタラクティブ機能を構築、提供、管理できるように支援します。

私たちのプラットフォームの基盤は、業界最大かつ最もスケーラブルなリアルタイムエッジメッセージングネットワークです。世界15か所以上で8億人の月間アクティブユーザーをサポートし、99.999%の信頼性を誇るため、停電や同時実行数の制限、トラフィックの急増による遅延の問題を心配する必要はありません。

PubNubを体験

ライブツアーをチェックして、5分以内にすべてのPubNub搭載アプリの背後にある本質的な概念を理解する

セットアップ

PubNubアカウントにサインアップすると、PubNubキーに無料ですぐにアクセスできます。

始める

PubNubのドキュメントは、ユースケースやSDKに関係なく、あなたを立ち上げ、実行することができます。

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .