這篇要介紹的是另一個 Effect 官方的套件 @effect/ai ,這個套件可以幫助你使用 AI ,同時你的程式不需要知道不同家 AI 的 sdk 之間的不同,只需要使用他們訂出來的統一的介面即可,就像是 Vercel 的 ai sdk 那樣,讓我們一起來看怎麼使用吧
這篇的範例程式在 https://github.com/DanSnow/ithelp-2025-ironman-sample-codes/tree/main/ai-demo
在 @effect/ai
中,我們可以用 LanguageModel.generateText
來跟 AI 對話
import { LanguageModel } from '@effect/ai'
const sayHello = Effect.fn('sayHello')(function* () {
const response = yield* LanguageModel.generateText({
prompt: 'Hi',
})
console.log(response.text)
})
不過我們還沒有設定要用哪家的模型,設定的方法就是使用 Effect 的 service ,這邊我們使用 Google 的模型
import { GoogleClient, GoogleLanguageModel } from '@effect/ai-google'
import { FetchHttpClient } from '@effect/platform'
import { Layer, pipe, Redacted } from 'effect'
// 選擇使用 gemini 2.0 flash
const Gemini20 = GoogleLanguageModel.model('gemini-2.0-flash')
// 從 env 取得 base url 跟 api key ,你可能不需要設定 base url 而讓它用預設的
const Google = GoogleClient.layer({
apiUrl: env.GOOGLE_BASE_URL,
// Redacted 可以避免 API key 被意外的 log 出來
apiKey: Redacted.make(env.GOOGLE_API_KEY),
})
const AILive = pipe(
Gemini20,
Layer.provide(Google),
Layer.provide(FetchHttpClient.layer)
)
最後我們將 service 提供給我們的程式
pipe(
sayHello(),
Effect.provide(AILive),
Effect.runPromise
)
就這樣,你完成了一個跟 AI 對話的程式,在上面的範例中,你應該注意到,不只是用哪家的服務是個 service ,同時使用哪個模型也是個 service ,這讓你可以從程式的外部控制使用的模型
使用 AI 時,除了單純的文字輸出,很常時候你會需要 AI 當你的程式的大腦,幫你做一些判斷,如果這時 AI 可以自由的輸出任何文字的話,相信你的程式會非常難處理,這時候我們就要請 AI 輸出格式化的資料,並且我們可以讓 Effect 幫我們驗證這個資料
首先,我們先定義我的資料的 schema
const SentimentSchema = Schema.Struct({
sentiment: Schema.Literal('neutral', 'negative', 'positive'),
})
再來,我們使用 LanguageModel.generateObject
,並將定義好的 schema 傳入,請 AI 產生格式化的輸出
const sentimentDetect = Effect.fn('sentimentDetect')(function* (text: string) {
const response = yield* LanguageModel.generateObject({
prompt: `Classify the text into neutral, negative or positive: ${text}`,
schema: SentimentSchema,
})
console.log(response.value)
})
最後我們就可以來使用
pipe(
sentimentDetect('I think the food is okay'),
Effect.provide(AILive),
Effect.runPromise
)
這篇裡展示了 Effect 裡怎麼跟 AI 串接,不過 Effect 的 @effect/ai
還在發展中,支援度可能不是那麼的好,之後我們再來看看發展的如何吧,按照預定,下一篇就是結語了