Uygulamanızın AI özelliklerinin temelinde, üretken model istekleri yer alır. Ancak nadiren kullanıcı girişini alıp modele ileterek ve model çıktısını kullanıcıya geri göstermeniz nadirdir. Genellikle model çağrısına eşlik etmesi gereken işlem öncesi ve sonrası adımlar bulunur. Örneğin:
- Model çağrısıyla gönderilecek bağlamsal bilgiler alınıyor.
- Kullanıcının geçerli oturumunun (ör. bir sohbet uygulamasında) geçmişini alma.
- Kullanıcı girişini başka bir modele aktarılmaya uygun şekilde yeniden biçimlendirmek için bir model kullanma.
- Bir model çıktısını kullanıcıya sunmadan önce "güvenliğini" değerlendirme.
- Birkaç modelin çıktısını birleştirmek.
Bu iş akışının her adımı, AI ile ilgili herhangi bir görevin başarıya ulaşması için birlikte çalışmalıdır.
Genkit'te birbiriyle sıkı bağlantılı bu mantığı, akış adı verilen bir yapıyı kullanarak temsil edersiniz. Akışlar, tıpkı işlevler gibi normal Go kodu kullanılarak yazılır ancak bu akışlar, yapay zeka özelliklerinin geliştirilmesini kolaylaştırmayı amaçlayan ek özellikler ekler:
- Tür güvenliği: Hem statik hem de çalışma zamanı türü kontrolü sağlayan giriş ve çıkış şemaları.
- Geliştirici kullanıcı arayüzüyle entegrasyon: Geliştirici kullanıcı arayüzünü kullanarak hata ayıklama akışları, uygulama kodunuzdan bağımsız olarak yapılır. Geliştirici kullanıcı arayüzünde, akışın her adımı için akışları çalıştırabilir ve izleri görüntüleyebilirsiniz.
- Basitleştirilmiş dağıtım: Akışları, bir web uygulaması barındırabilen herhangi bir platformu kullanarak doğrudan web API uç noktaları olarak dağıtın.
Genkit'in akışları hafif ve göze batmaz. Ayrıca uygulamanızı belirli bir soyutlamaya uymaya zorlamaz. Akışın tüm mantığı standart Go'da yazılır ve bir akışın içindeki kodun akışa duyarlı olması gerekmez.
Akışları tanımlama ve arama
Akış, en basit haliyle bir fonksiyonu sarmalar. Aşağıdaki örnekte Generate()
çağrısı yapan bir işlev gösterilmektedir:
menuSuggestionFlow := genkit.DefineFlow(g, "menuSuggestionFlow",
func(ctx context.Context, theme string) (string, error) {
resp, err := genkit.Generate(ctx, g,
ai.WithPrompt("Invent a menu item for a %s themed restaurant.", theme),
)
if err != nil {
return "", err
}
return resp.Text(), nil
})
Sadece genkit.Generate()
çağrılarınızı bu şekilde sarmalayarak birtakım işlevler eklersiniz: Bu sayede Genkit CLI'dan ve geliştirici kullanıcı arayüzünden akışı çalıştırabilirsiniz. Ayrıca, Genkit'in dağıtım ve gözlemlenebilirlik gibi bazı özellikleri için bu şarttır (sonraki bölümlerde bu konular ele alınacaktır).
Giriş ve çıkış şemaları
Genkit akışlarının doğrudan model API çağırmaya kıyasla en önemli avantajlarından biri, hem giriş hem de çıkışların tür güvenliğidir. Akışları tanımlarken, tıpkı genkit.Generate()
çağrısının çıkış şemasına benzer şekilde şemaları tanımlayabilirsiniz. Ancak, genkit.Generate()
işlevinin aksine, bir giriş şeması da belirtebilirsiniz.
Bir dizeyi girdi olarak alan ve nesne çıkışı yapan bir akışı tanımlayan son örneği aşağıda görebilirsiniz:
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),
)
})
Bir akış şemasının, akış içindeki genkit.Generate()
çağrılarının şemasıyla uyumlu olması gerekmediğini unutmayın (aslında bir akış genkit.Generate()
çağrılarını bile içermeyebilir). genkit.GenerateData()
çağrısı yapan ancak akışın döndürdüğü basit bir dizeyi biçimlendirmek için yapılandırılmış çıkışı kullanan örneğin bir varyasyonunu aşağıda görebilirsiniz. MenuItem
parametresini tür parametresi olarak nasıl ilettiğimize dikkat edin. Bu, WithOutputType()
seçeneğini ileterek yanıt olarak ilgili türde bir değer almaya eşdeğerdir.
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
})
Telefon araması akışları
Bir akışı tanımladıktan sonra, Go kodunuzdan çağırabilirsiniz:
item, err := menuSuggestionFlow.Run(ctx, "bistro")
Akış bağımsız değişkeni giriş şemasına uygun olmalıdır.
Bir çıkış şeması tanımladıysanız akış yanıtı buna uygun olacaktır. Örneğin, çıkış şemasını MenuItem
olarak ayarlarsanız akış çıkışı kendi özelliklerini içerir:
item, err := menuSuggestionFlow.Run(ctx, "bistro")
if err != nil {
log.Fatal(err)
}
log.Println(item.DishName)
log.Println(item.Description)
Akış akışları
Akışlar, genkit.Generate()
ürününün akış arayüzüne benzer bir arayüz kullanarak yayın desteği sunar. Akışınız büyük miktarda çıktı oluşturduğunda akış faydalıdır. Çünkü sonucu kullanıcıya üretilirken sunabilirsiniz. Bu da uygulamanızın algılanan yanıt verme süresini iyileştirir. Bilindik bir örnek olarak, sohbet tabanlı LLM arayüzleri genellikle yanıtları, oluşturuldukları anda kullanıcıya akış olarak sunar.
Aşağıda, akışı destekleyen bir akış örneği verilmiştir:
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]
öğesindeki string
türü, akış akışlarınızın değer türünü belirtir. Bunun dönüş türü ile aynı türde olması gerekmez. Döndürme türü, akışın tam çıkışının türüdür (bu örnekte Menu
).
Bu örnekte, akış tarafından yayınlanan değerler, akışın içindeki genkit.Generate()
çağrısı tarafından yayınlanan değerlerle doğrudan bağlantılıdır.
Çoğu zaman böyle olması gerekmez. Geri çağırmayı kullanarak, akışınız için uygun sıklıkta değer akışı ekleyebilirsiniz.
Görüşme akışları
Akış akışları, menuSuggestionFlow.Run(ctx, "bistro")
ile akış olmayan akışlar gibi çalıştırılabilir veya akış olarak yayınlanabilir:
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)
}
}
Akışları komut satırından çalıştırma
Genkit CLI aracını kullanarak komut satırından akış çalıştırabilirsiniz:
genkit flow:run menuSuggestionFlow '"French"'
Akış akışları için -s
işaretini ekleyerek akış çıkışını konsola yazdırabilirsiniz:
genkit flow:run menuSuggestionFlow '"French"' -s
Komut satırından akış çalıştırmak, bir akışı test etmek veya geçici olarak (örneğin, vektör veritabanınıza doküman besleyen bir akış çalıştırmak) gereken görevleri gerçekleştiren akışları çalıştırmak için yararlıdır.
Hata ayıklama akışları
AI mantığını bir akış içinde kapsamanın avantajlarından biri, Genkit geliştirici kullanıcı arayüzünü kullanarak akışı uygulamanızdan bağımsız olarak test edip hata ayıklayabilmenizdir.
Geliştirici kullanıcı arayüzü, mantık tamamlanmış olsa bile Go uygulamasının çalışmaya devam etmesini temel alır. Yeni başlıyorsanız ve Genkit daha kapsamlı bir uygulamanın parçası değilse select {}
uygulamasını son satır olarak main()
ekleyin. Böylece uygulamanın kullanıcı arayüzünde incelenmesini önleyebilirsiniz.
Geliştirici kullanıcı arayüzünü başlatmak için proje dizininizden aşağıdaki komutu çalıştırın:
genkit start -- go run .
Geliştirici arayüzünün Çalıştır sekmesinden projenizde tanımlanan akışlardan herhangi birini çalıştırabilirsiniz:
Bir akış çalıştırdıktan sonra, İzlemeyi görüntüle'yi tıklayarak veya İncele sekmesine bakarak akış çağrısı izini inceleyebilirsiniz.
Akışları dağıtma
Akışlarınızı doğrudan, uygulama istemcilerinizden arama yapmaya hazır olan web API uç noktaları olarak dağıtabilirsiniz. Dağıtım, diğer sayfalarda ayrıntılı olarak açıklanmıştır. Ancak bu bölümde dağıtım seçeneklerinize kısa genel bakış sunulmaktadır.
net/http
Sunucusu
Bir akışı Cloud Run gibi herhangi bir Go barındırma platformunu kullanarak dağıtmak için akışınızı DefineFlow()
kullanarak tanımlayın ve sağlanan akış işleyiciyle bir net/http
sunucusu başlatın:
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()
, sunucuyu başlatan ve yerel geliştirmeyi kolaylaştırmak için kesinti sinyallerini yakalamak dahil olmak üzere sunucuyu başlatan ve yaşam döngüsünü yöneten isteğe bağlı bir yardımcı işlevdir. Ancak kendi yönteminizi de kullanabilirsiniz.
Kod tabanınızda tanımlanan tüm akışları sunmak için ListFlows()
işlevini kullanabilirsiniz:
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 isteği olan bir akış uç noktasını aşağıdaki şekilde çağırabilirsiniz:
curl -X POST "http://localhost:3400/menuSuggestionFlow" \
-H "Content-Type: application/json" -d '{"data": "banana"}'
Diğer sunucu çerçeveleri
Akışlarınızı dağıtmak için diğer sunucu çerçevelerini de kullanabilirsiniz. Örneğin, Gin'i yalnızca birkaç satırla kullanabilirsiniz:
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"))
Belirli platformlara dağıtım hakkında bilgi edinmek için Cloud Run ile Genkit sayfasını inceleyin.