Hono を Cloudflare Workers で動かしつつ、Vercel AI SDK で出力した LLM 実行結果を LangSmith でトレーシングできるようにする
背景
LangChain のほうが AI フレームワークとして代表的だが、Web アプリケーション開発の DX に特化した実装になっているのが気になっていたので試しに AI SDK を使ってみた。 その中でトレーシングとして LangSmith を導入したかったので、その経緯をこの記事に残す。
Vercel が提供している LLM 実行のためのフレームワーク
LangSmith とは
LangChain が提供している LLMOps のための SaaS
実行したLLMの出力結果やプロンプトチューニング、データセット作成および評価ができ、本業の LLM 開発で欠かせないツールになっている
実装サンプル
本記事では、/stream を叩くと任意のプロンプトでOpenAIにリクエストが行われストリーミング形式でレスポンスが返ってくるAPIを例とする。
まず、Hono 公式の手順で構築した Cloudflare 用のテンプレートから、 ai sdk をインストールし、 src/index.ts を以下の実装にする。
# 任意のパッケージマネージャーから導入してね(サンプルでは Bun を使っているよ)
bun install ai
import { createOpenAI } from "@ai-sdk/openai";
import { streamText } from "ai";
import { Hono } from "hono";
import { stream } from "hono/streaming";
type Bindings = {
OPENAI_API_KEY: string;
};
const app = new Hono<{ Bindings: Bindings }>();
app.get("/stream", (c) => {
const openai = createOpenAI({
apiKey: c.env.OPENAI_API_KEY,
});
const { textStream } = streamText({
model: openai("gpt-4o-mini"),
prompt: "some prompt here",
});
return stream(c, async (stream) => {
for await (const text of textStream) {
await stream.write(text);
}
stream.close();
});
});
export default {
port: 3000,
fetch: app.fetch,
};
環境変数を Cloudflare から事前に設定しておく。ローカルで wrangler dev で実行する場合、.dev.vars に環境変数を定義する
OPENAI_API_KEY="API KEY HERE"
-N オプションで curl コマンドを叩くと、実際にストリーミング形式でLLM実行結果が取得できるか確認する
curl -N http://localhost:8787/stream
It seems like you’re asking for some prompts. Could you clarify what type of prompts you’re looking for? Are you interested in writing prompts, creative image generation prompts, coding prompts, or something else entirely? Let me know, and I’ll provide some suggestions tailored to your needs!
LangSmith / otel-cf-workers の導入
続いてLangSmithと otel-cf-workers を導入する
otel-cf-workers は、Cloudflare Workers 上で Otel をアプリケーションレベルで設定できるライブラリだ。
bun install @microlabs/otel-cf-workers langsmith
LangSmithでトレーシングできるようにする
export default していたオブジェクトをそのまま otel-cf-workers の instrument 関数に渡し、LangSmithの認証情報かつOtelの設定を入れる
import { createOpenAI } from "@ai-sdk/openai";
import { instrument } from "@microlabs/otel-cf-workers";
import { streamText } from "ai";
import { Hono } from "hono";
import { stream } from "hono/streaming";
import { Client } from "langsmith";
import { AISDKExporter } from "langsmith/vercel";
type Bindings = {
OPENAI_API_KEY: string;
LANGCHAIN_TRACING_V2: string;
LANGCHAIN_API_KEY: string;
LANGCHAIN_PROJECT: string;
LANGCHAIN_ENDPOINT: string;
};
const app = new Hono<{ Bindings: Bindings }>();
app.get("/stream", (c) => {
const openai = createOpenAI({
apiKey: c.env.OPENAI_API_KEY,
});
const { textStream } = streamText({
model: openai("gpt-4o-mini"),
prompt: "some prompt here",
experimental_telemetry: AISDKExporter.getSettings({
isEnabled: c.env.LANGCHAIN_TRACING_V2 === "true",
}),
});
return stream(c, async (stream) => {
for await (const text of textStream) {
await stream.write(text);
}
stream.close();
});
});
const fetchHandler = {
port: 3000,
fetch: app.fetch,
};
export default instrument(fetchHandler, (env) => ({
exporter: new AISDKExporter({
client: new Client({
// Batching is handled by OTEL by default, we need to
// disable LangSmith batch tracing to avoid losing traces
autoBatchTracing: false,
apiKey: env.LANGCHAIN_API_KEY,
apiUrl: env.LANGCHAIN_ENDPOINT,
}),
}),
service: { name: "ai-sdk-service" },
}));
併せて環境変数も更新する
OPENAI_API_KEY="OpenAI API Key"
LANGCHAIN_TRACING_V2=true
LANGCHAIN_API_KEY="LangSmith API Key "
LANGCHAIN_ENDPOINT="https://api.smith.langchain.com"
これで、LangSmith上にトレーシングできるようになる
懸念
把握している限りだと、LangSmithでProject名を指定するには環境変数 LANGCHAIN_PROJECT を指定することで変更できるが(しない場合default固定)、Cloudflare Workers では process.env が使えないためこの手法で Project 名指定することができないので、別途手段を考える必要がある