এআই ওয়ার্কফ্লো সংজ্ঞায়িত করা

আপনার অ্যাপের AI বৈশিষ্ট্যগুলির মূল হল জেনারেটিভ মডেল অনুরোধ, কিন্তু এটি বিরল যে আপনি কেবল ব্যবহারকারীর ইনপুট নিতে পারেন, এটি মডেলে পাস করতে পারেন এবং ব্যবহারকারীর কাছে মডেল আউটপুটটি প্রদর্শন করতে পারেন। সাধারণত, মডেল কলের সাথে অবশ্যই প্রি- এবং পোস্ট-প্রসেসিং ধাপ রয়েছে। যেমন:

  • মডেল কলের সাথে পাঠানোর জন্য প্রাসঙ্গিক তথ্য পুনরুদ্ধার করা হচ্ছে।
  • ব্যবহারকারীর বর্তমান সেশনের ইতিহাস পুনরুদ্ধার করা, উদাহরণস্বরূপ একটি চ্যাট অ্যাপে।
  • একটি মডেল ব্যবহার করে ব্যবহারকারীর ইনপুটকে এমনভাবে পুনরায় ফর্ম্যাট করা যা অন্য মডেলে পাস করার জন্য উপযুক্ত।
  • ব্যবহারকারীর কাছে উপস্থাপন করার আগে একটি মডেলের আউটপুটের "নিরাপত্তা" মূল্যায়ন করা।
  • বেশ কয়েকটি মডেলের আউটপুট একত্রিত করা।

এআই-সম্পর্কিত যেকোনো কাজ সফল হওয়ার জন্য এই কর্মপ্রবাহের প্রতিটি ধাপে একসঙ্গে কাজ করতে হবে।

জেনকিটে, আপনি একটি প্রবাহ নামক একটি নির্মাণ ব্যবহার করে এই শক্তভাবে-সংযুক্ত যুক্তি উপস্থাপন করেন। ফ্লোগুলি সাধারণ গো কোড ব্যবহার করে ফাংশনের মতোই লেখা হয়, তবে তারা এআই বৈশিষ্ট্যগুলির বিকাশ সহজ করার উদ্দেশ্যে অতিরিক্ত ক্ষমতা যুক্ত করে:

  • টাইপ নিরাপত্তা : ইনপুট এবং আউটপুট স্কিমা, যা স্ট্যাটিক এবং রানটাইম উভয় প্রকার চেকিং প্রদান করে।
  • বিকাশকারী UI এর সাথে একীকরণ : বিকাশকারী UI ব্যবহার করে আপনার অ্যাপ্লিকেশন কোড থেকে স্বাধীনভাবে ডিবাগ প্রবাহিত হয়। বিকাশকারী UI-তে, আপনি প্রবাহ চালাতে পারেন এবং প্রবাহের প্রতিটি ধাপের জন্য ট্রেস দেখতে পারেন।
  • সরলীকৃত স্থাপনা : কোনো ওয়েব অ্যাপ হোস্ট করতে পারে এমন যেকোনো প্ল্যাটফর্ম ব্যবহার করে সরাসরি ওয়েব API এন্ডপয়েন্ট হিসেবে প্রবাহ স্থাপন করুন।

Genkit এর প্রবাহগুলি হালকা এবং নিরবচ্ছিন্ন, এবং আপনার অ্যাপকে কোনো নির্দিষ্ট বিমূর্ততা মেনে চলতে বাধ্য করবেন না। প্রবাহের সমস্ত যুক্তি স্ট্যান্ডার্ড গো-তে লেখা আছে এবং প্রবাহের ভিতরের কোডের প্রবাহ-সচেতন হওয়ার প্রয়োজন নেই।

সংজ্ঞায়িত এবং কলিং প্রবাহ

এর সহজতম আকারে, একটি প্রবাহ কেবল একটি ফাংশনকে মোড়ানো হয়। নিম্নলিখিত উদাহরণটি একটি ফাংশনকে মোড়ক করে যা GenerateData() কল করে:

menuSuggestionFlow := genkit.DefineFlow(g, "menuSuggestionFlow",
    func(ctx context.Context, theme string) (string, error) {
        resp, err := genkit.GenerateData(ctx, g,
            ai.WithPrompt("Invent a menu item for a %s themed restaurant.", theme),
        )
        if err != nil {
            return "", err
        }

        return resp.Text(), nil
    })

শুধু আপনার genkit.Generate() কলগুলিকে এইভাবে মোড়ানোর মাধ্যমে, আপনি কিছু কার্যকারিতা যোগ করুন: এটি করার ফলে আপনি Genkit CLI এবং বিকাশকারী UI থেকে প্রবাহ চালাতে পারবেন, এবং স্থাপনা এবং পর্যবেক্ষণযোগ্যতা সহ জেনকিটের বেশ কয়েকটি বৈশিষ্ট্যের জন্য প্রয়োজন (পরবর্তী বিভাগগুলি এই বিষয়গুলি নিয়ে আলোচনা করবে)৷

ইনপুট এবং আউটপুট স্কিমা

Genkit ফ্লোতে সরাসরি একটি মডেল API কল করার সবচেয়ে গুরুত্বপূর্ণ সুবিধাগুলির মধ্যে একটি হল ইনপুট এবং আউটপুট উভয়ের ধরনের নিরাপত্তা। প্রবাহ সংজ্ঞায়িত করার সময়, আপনি স্কিমাগুলিকে সংজ্ঞায়িত করতে পারেন, যেমন আপনি একটি genkit.Generate() কলের আউটপুট স্কিমা সংজ্ঞায়িত করেন; যাইহোক, genkit.Generate() এর বিপরীতে, আপনি একটি ইনপুট স্কিমাও নির্দিষ্ট করতে পারেন।

এখানে শেষ উদাহরণের একটি পরিমার্জন রয়েছে, যা একটি প্রবাহকে সংজ্ঞায়িত করে যা একটি স্ট্রিংকে ইনপুট হিসাবে নেয় এবং একটি বস্তুকে আউটপুট করে:

type MenuItem struct {
    Name        string `json:"name"`
    Description string `json:"description"`
}

menuSuggestionFlow := genkit.DefineFlow(g, "menuSuggestionFlow",
    func(ctx context.Context, theme string) (MenuItem, error) {
        return genkit.GenerateData[MenuItem](ctx, g,
            ai.WithPrompt("Invent a menu item for a %s themed restaurant.", theme),
        )
    })

মনে রাখবেন যে একটি প্রবাহের স্কিমা অগত্যা genkit.Generate() কলগুলি (আসলে, একটি ফ্লোতে genkit.Generate() কল নাও থাকতে পারে)। এখানে উদাহরণের একটি ভিন্নতা রয়েছে যা genkit.Generate() এ একটি স্কিমা পাস করে, কিন্তু একটি সাধারণ স্ট্রিং ফর্ম্যাট করতে কাঠামোগত আউটপুট ব্যবহার করে, যা প্রবাহটি ফেরত দেয়।

type MenuItem struct {
    Name        string `json:"name"`
    Description string `json:"description"`
}

menuSuggestionMarkdownFlow := genkit.DefineFlow(g, "menuSuggestionMarkdownFlow",
    func(ctx context.Context, theme string) (string, error) {
        item, _, err := genkit.GenerateData[MenuItem](ctx, g,
            ai.WithPrompt("Invent a menu item for a %s themed restaurant.", theme),
        )
        if err != nil {
            return "", err
        }

        return fmt.Sprintf("**%s**: %s", item.Name, item.Description), nil
    })

কলিং প্রবাহ

একবার আপনি একটি প্রবাহ সংজ্ঞায়িত করলে, আপনি এটিকে আপনার Go কোড থেকে কল করতে পারেন:

item, err := menuSuggestionFlow.Run(ctx, "bistro")

প্রবাহের যুক্তি অবশ্যই ইনপুট স্কিমার সাথে সঙ্গতিপূর্ণ হতে হবে।

আপনি যদি একটি আউটপুট স্কিমা সংজ্ঞায়িত করেন তবে প্রবাহ প্রতিক্রিয়া এটির সাথে সামঞ্জস্যপূর্ণ হবে। উদাহরণস্বরূপ, আপনি যদি MenuItem এ আউটপুট স্কিমা সেট করেন, তাহলে প্রবাহ আউটপুটে এর বৈশিষ্ট্য থাকবে:

item, err := menuSuggestionFlow.Run(ctx, "bistro")
if err != nil {
    log.Fatal(err)
}

log.Println(item.DishName)
log.Println(item.Description)

স্ট্রিমিং প্রবাহ

ফ্লোস genkit.Generate() এর স্ট্রিমিং ইন্টারফেসের মতো একটি ইন্টারফেস ব্যবহার করে স্ট্রিমিং সমর্থন করে। আপনার প্রবাহ যখন প্রচুর পরিমাণে আউটপুট জেনারেট করে তখন স্ট্রিমিং উপযোগী হয়, কারণ আপনি ব্যবহারকারীর কাছে আউটপুটটি উত্পন্ন হওয়ার সাথে সাথে উপস্থাপন করতে পারেন, যা আপনার অ্যাপের অনুভূত প্রতিক্রিয়াশীলতাকে উন্নত করে। একটি পরিচিত উদাহরণ হিসাবে, চ্যাট-ভিত্তিক LLM ইন্টারফেসগুলি প্রায়শই ব্যবহারকারীর কাছে তাদের প্রতিক্রিয়াগুলি তৈরি করার সাথে সাথে স্ট্রিম করে।

এখানে একটি প্রবাহের একটি উদাহরণ যা স্ট্রিমিং সমর্থন করে:

type Menu struct {
    Theme  string     `json:"theme"`
    Items  []MenuItem `json:"items"`
}

type MenuItem struct {
    Name        string `json:"name"`
    Description string `json:"description"`
}

menuSuggestionFlow := genkit.DefineStreamingFlow(g, "menuSuggestionFlow",
    func(ctx context.Context, theme string, callback core.StreamCallback[string]) (Menu, error) {
        item, _, err := genkit.GenerateData[MenuItem](ctx, g,
            ai.WithPrompt("Invent a menu item for a %s themed restaurant.", theme),
            ai.WithStreaming(func(ctx context.Context, chunk *ai.ModelResponseChunk) error {
                // Here, you could process the chunk in some way before sending it to
                // the output stream using StreamCallback. In this example, we output
                // the text of the chunk, unmodified.
                return callback(ctx, chunk.Text())
            }),
        )
        if err != nil {
            return nil, err
        }

        return Menu{
            Theme: theme,
            Items: []MenuItem{item},
        }, nil
    })

StreamCallback[string] -এ string টাইপ আপনার ফ্লো স্ট্রীমের মানগুলির ধরন নির্দিষ্ট করে। এটি অগত্যা রিটার্ন টাইপের মতো একই ধরণের হতে হবে না, যা প্রবাহের সম্পূর্ণ আউটপুটের ধরন (এই উদাহরণে Menu )।

এই উদাহরণে, প্রবাহ দ্বারা প্রবাহিত মানগুলি সরাসরি genkit.Generate() কল দ্বারা প্রবাহিত মানের সাথে মিলিত হয়। যদিও এটি প্রায়শই হয়, এটি হওয়ার দরকার নেই: আপনি যতবার আপনার প্রবাহের জন্য উপযোগী ততবার কলব্যাক ব্যবহার করে স্ট্রীমে মানগুলি আউটপুট করতে পারেন।

কলিং স্ট্রিমিং প্রবাহ

স্ট্রিমিং ফ্লোগুলি menuSuggestionFlow.Run(ctx, "bistro") সহ নন-স্ট্রিমিং প্রবাহের মতো চালানো যেতে পারে বা সেগুলি স্ট্রিম করা যেতে পারে:

streamCh, err := menuSuggestionFlow.Stream(ctx, "bistro")
if err != nil {
    log.Fatal(err)
}

for result := range streamCh {
    if result.Err != nil {
        log.Fatal("Stream error: %v", result.Err)
    }
    if result.Done {
        log.Printf("Menu with %s theme:\n", result.Output.Theme)
        for item := range result.Output.Items {
            log.Println(" - %s: %s", item.Name, item.Description)
        }
    } else {
        log.Println("Stream chunk:", result.Stream)
    }
}

কমান্ড লাইন থেকে চলমান প্রবাহ

আপনি Genkit CLI টুল ব্যবহার করে কমান্ড লাইন থেকে প্রবাহ চালাতে পারেন:

genkit flow:run menuSuggestionFlow '"French"'

স্ট্রিমিং প্রবাহের জন্য, আপনি -s পতাকা যোগ করে কনসোলে স্ট্রিমিং আউটপুট মুদ্রণ করতে পারেন:

genkit flow:run menuSuggestionFlow '"French"' -s

কমান্ড লাইন থেকে একটি প্রবাহ চালানো একটি ফ্লো পরীক্ষা করার জন্য, বা অ্যাডহক ভিত্তিতে প্রয়োজনীয় কাজগুলি সঞ্চালন করার জন্য প্রবাহ চালানোর জন্য দরকারী - উদাহরণস্বরূপ, একটি প্রবাহ চালানোর জন্য যা আপনার ভেক্টর ডাটাবেসে একটি নথি প্রবেশ করে৷

ডিবাগিং প্রবাহ

একটি প্রবাহের মধ্যে AI লজিককে এনক্যাপসুলেট করার সুবিধাগুলির মধ্যে একটি হল যে আপনি Genkit বিকাশকারী UI ব্যবহার করে আপনার অ্যাপ থেকে স্বাধীনভাবে ফ্লো পরীক্ষা এবং ডিবাগ করতে পারেন।

ডেভেলপার UI নির্ভর করে Go অ্যাপটি চলতে চলতে, এমনকি লজিক সম্পূর্ণ হয়ে গেলেও। আপনি যদি এইমাত্র শুরু করছেন এবং Genkit একটি বৃহত্তর অ্যাপের অংশ না হয়, তাহলে অ্যাপটিকে বন্ধ হওয়া থেকে আটকাতে main() এর শেষ লাইন হিসাবে select {} যোগ করুন যাতে আপনি এটি UI-তে পরিদর্শন করতে পারেন।

বিকাশকারী UI শুরু করতে, আপনার প্রকল্প ডিরেক্টরি থেকে নিম্নলিখিত কমান্ডটি চালান:

genkit start -- go run .

বিকাশকারী UI এর রান ট্যাব থেকে, আপনি আপনার প্রকল্পে সংজ্ঞায়িত যে কোনও প্রবাহ চালাতে পারেন:

ফ্লো রানার স্ক্রিনশট

আপনি একটি ফ্লো চালানোর পরে, আপনি ভিউ ট্রেস ক্লিক করে বা পরিদর্শন ট্যাবটি দেখে ফ্লো ইনভোকেশনের একটি ট্রেস পরিদর্শন করতে পারেন।

প্রবাহ স্থাপন

আপনি আপনার অ্যাপ ক্লায়েন্টদের থেকে কল করার জন্য প্রস্তুত, ওয়েব API এন্ডপয়েন্ট হিসাবে সরাসরি আপনার প্রবাহ স্থাপন করতে পারেন। স্থাপনার বিষয়ে অন্যান্য কয়েকটি পৃষ্ঠায় বিস্তারিত আলোচনা করা হয়েছে, তবে এই বিভাগটি আপনার স্থাপনার বিকল্পগুলির সংক্ষিপ্ত বিবরণ দেয়।

net/http সার্ভার

ক্লাউড রানের মতো যেকোনো Go হোস্টিং প্ল্যাটফর্ম ব্যবহার করে একটি ফ্লো স্থাপন করতে, DefineFlow() ব্যবহার করে আপনার ফ্লো সংজ্ঞায়িত করুন এবং প্রদত্ত ফ্লো হ্যান্ডলারের সাথে একটি net/http সার্ভার শুরু করুন:

import (
    "context"
    "log"
    "net/http"

    "github.com/firebase/genkit/go/genkit"
    "github.com/firebase/genkit/go/plugins/googlegenai"
    "github.com/firebase/genkit/go/plugins/server"
)

func main() {
    ctx := context.Background()

    g, err := genkit.Init(ctx, genkit.WithPlugins(&googlegenai.GoogleAI{}))
    if err != nil {
      log.Fatal(err)
    }

    menuSuggestionFlow := genkit.DefineFlow(g, "menuSuggestionFlow",
        func(ctx context.Context, theme string) (MenuItem, error) {
            // Flow implementation...
        })

    mux := http.NewServeMux()
    mux.HandleFunc("POST /menuSuggestionFlow", genkit.Handler(menuSuggestionFlow))
    log.Fatal(server.Start(ctx, "127.0.0.1:3400", mux))
}

server.Start() হল একটি ঐচ্ছিক সাহায্যকারী ফাংশন যা সার্ভার শুরু করে এবং স্থানীয় উন্নয়ন সহজ করতে বাধা সংকেত ক্যাপচার সহ এর জীবনচক্র পরিচালনা করে, তবে আপনি আপনার নিজস্ব পদ্ধতি ব্যবহার করতে পারেন।

আপনার কোডবেসে সংজ্ঞায়িত সমস্ত প্রবাহ পরিবেশন করতে, আপনি ListFlows() ব্যবহার করতে পারেন :

mux := http.NewServeMux()
for _, flow := range genkit.ListFlows(g) {
    mux.HandleFunc("POST /"+flow.Name(), genkit.Handler(flow))
}
log.Fatal(server.Start(ctx, "127.0.0.1:3400", mux))

আপনি নিম্নরূপ একটি POST অনুরোধ সহ একটি ফ্লো এন্ডপয়েন্ট কল করতে পারেন:

curl -X POST "http://localhost:3400/menuSuggestionFlow" \
    -H "Content-Type: application/json" -d '{"data": "banana"}'

অন্যান্য সার্ভার ফ্রেমওয়ার্ক

আপনি আপনার প্রবাহ স্থাপন করতে অন্যান্য সার্ভার ফ্রেমওয়ার্ক ব্যবহার করতে পারেন। উদাহরণস্বরূপ, আপনি মাত্র কয়েকটি লাইনের সাথে জিন ব্যবহার করতে পারেন:

router := gin.Default()
for _, flow := range genkit.ListFlows(g) {
    router.POST("/"+flow.Name(), func(c *gin.Context) {
        genkit.Handler(flow)(c.Writer, c.Request)
    })
}
log.Fatal(router.Run(":3400"))

নির্দিষ্ট প্ল্যাটফর্মে স্থাপনের তথ্যের জন্য, ক্লাউড রানের সাথে জেনকিট দেখুন।