0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Opik LLM監視と分析ツールを使ってみた

Posted at

背景

日本でオープンソースのLLM監視と分析ツールだったらLangfuseがほぼ一強の状況だけど、海外にはいくつかのツールがあります。その中にあまり日本で知られていないOpikというツールを使ってみたいと思います。

概要

Comet発のOpik:

image.png

近代のオープンソースツールと同じく、SaaSとセルフホスト型もあって、セルフホストの方法がやや複雑だけど、LLMの中身を全部監視するので、セキュリティ要件的にSaaS使えないケースが多いでしょう。

一般的なユースケースが懸念なくカバーされています。

  • ログトレース
  • コスト追跡
  • データセット管理
  • プロンプト管理
  • エージェント評価
  • ガードレール
  • MCP

また、対応するLLMも非常に多くて、この部分一番安心感があります。

Screenshot from 2025-10-12 00-57-55.png
(サポートLLMの一部)

使ってみる

ログトレース

早速使ってみて、まず簡単なプロンプトでテストします。

import os
import dotenv

from opik.integrations.openai import track_openai
from openai import OpenAI

dotenv.load_dotenv()

openai_client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
openai_client = track_openai(openai_client)

response = openai_client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[{"role": "user", "content": "What is the capital of France?"}]
)

print(response.choices[0].message.content)

ツール上で結果を見てみます。

test11.png

test12.png

UI的にわかりやすくて、知りたい情報も揃っています。

LangGraph連携

上記あくまで簡単な例で、実際のユースケースは多くの場合がLangGraphなどエージェントを構築して使うので、こちらでLangGraph連携の場合でどうなるかを試します。

import opik
import dotenv

from langgraph.graph import StateGraph, END
from typing import TypedDict, Optional

dotenv.load_dotenv()
opik.configure(use_local=False)

# Define the graph state
class GraphState(TypedDict):
    question: Optional[str] = None
    classification: Optional[str] = None
    response: Optional[str] = None

# Create the node functions
def classify(question: str) -> str:
    return "greeting" if question.startswith("Hello") else "search"

def classify_input_node(state):
    question = state.get("question", "").strip()
    classification = classify(question)
    return {"classification": classification}

def handle_greeting_node(state):
    return {"response": "Hello! How can I help you today?"}

def handle_search_node(state):
    question = state.get("question", "").strip()
    search_result = f"Search result for '{question}'"
    return {"response": search_result}

# Create the workflow
workflow = StateGraph(GraphState)
workflow.add_node("classify_input", classify_input_node)
workflow.add_node("handle_greeting", handle_greeting_node)
workflow.add_node("handle_search", handle_search_node)

# Add conditional routing
def decide_next_node(state):
    return (
        "handle_greeting"
        if state.get("classification") == "greeting"
        else "handle_search"
    )

workflow.add_conditional_edges(
    "classify_input",
    decide_next_node,
    {"handle_greeting": "handle_greeting", "handle_search": "handle_search"},
)

workflow.set_entry_point("classify_input")
workflow.add_edge("handle_greeting", END)
workflow.add_edge("handle_search", END)

app = workflow.compile()

from opik.integrations.langchain import OpikTracer

# Create the OpikTracer with graph visualization
tracer = OpikTracer(graph=app.get_graph(xray=True))

# Execute the workflow
inputs = {"question": "Hello, how are you?"}
result = app.invoke(inputs, config={"callbacks": [tracer]})
print(result)

test31.png

ソースコードを見ると長くてわかりにくいけど、実行結果の画面を見るとわかりやすくて、デバッグの時にこれがあると非常に協力になります。

プロンプト管理

せっかくなので、もう1個重要な機能を試していきます。

プロンプトの追加はソースコード上でできます。その結果は画面上で確認できます。

import opik
import dotenv

dotenv.load_dotenv()
opik.configure(use_local=False)

PROMPT_TEXT = "Rewrite the following text: {{text}}"

prompt = opik.Prompt(
    name="prompt-summary",
    prompt=PROMPT_TEXT,
    metadata={"environment": "production"}
)

print(prompt.prompt)

print(prompt.format(text="Hello, world!"))

test41.png

test51.png

ツールの画面を見ると、バーションで複数のプロンプトを管理することができます。またメタデータの設定でバーション以外の属性で管理することもできます。

もちろん追加したプロンプトの管理と確認はソースコード上でもできます。

import opik

client = opik.Opik()

history = client.get_prompt_history(name="prompt-summary")
for version in history:
    print(version.commit, version.prompt)

で、その出力結果は:

803efbf8 Rewrite the following text: {{text}}
fefb23c4 Write a summary of the following text: {{text}}

サマリー

  • 使い方は簡単で、ラッパーだけで完結、高度な細かい制御の場合はローレベルSDKもある
  • 機能アップデートが頻繁、ちゃんと本番利用できえうver 1.Xになっている
  • 日本でのコミュニティーがないので(GitHubに14kの星があっても)、Langfuseと比べるとやはり少し微妙
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?