JA ▾
API キーを取得

LangChainでChatOpenAIを無検閲APIと連携

LangChainのChatOpenAIクラスは任意のOpenAI互換エンドポイントで動作するため、Base URL、API キー、モデル名のみを変更すればよいです。このページではPythonとNode.jsでのセットアップを示し、ストリーミング、ツール、小型エージェントへの構築を行います。

更新日:

チャットバブルをサーバーキューブに送り込むリンクされたリングのアイソメトリックチェーン、APIへのLangChain接続を表す

主要ポイント

  1. ChatOpenAIにはbase_url、api_key、モデルをuncensoredに設定する3つの設定が必要です。
  2. ストリーミング、ツール呼び出し、JSONモードはすべて標準的なLangChainインターフェースを介して動作します。
  3. 同時実行数を8に制限し、HTTP 429をリトライ処理して制限内に収めてください。
  4. 10ステップのエージェント実行は、1Mトークンあたり$0.15と$0.50で、1セント未満のコストで済みます。

短い答え:ChatOpenAIの3つの設定

chat open ai langchainを検索したなら、おそらくすでにChatOpenAIを使用しているLangChainプロジェクトがあり、異なるバックエンドに接続したいのでしょう。これは書き換えではなく設定変更です。このサイトのAPIはOpenAIチャット完了プロトコルをサポートしているため、LangChainはこれを他のOpenAIスタイルのサーバーと同様に扱います。

Base URL、API キー、モデルID uncensoredが必要です。まずパッケージをインストールしてください:

pip install -U langchain-openai langgraph

次にモデルオブジェクトを作成します:

import os
from langchain_openai import ChatOpenAI

llm = ChatOpenAI(
    model="uncensored",
    base_url="https://api.nofilteraichat.com/v1",
    api_key=os.environ["NOFILTER_API_KEY"],
    temperature=0.8,
)

reply = llm.invoke("Write a two-sentence villain monologue for a heist novel.")
print(reply.content)

これで統合は完了です。ChatOpenAIに依存するすべてのLangChain機能は、無検閲モデルに対して実行されます:チェーン、チャットモデルを呼び出すリトリーバー、出力パーサー、エージェントなど。まだAPI キーをお持ちでない場合は、API keyページでサインアップとワンクリックの無料トライアルクレジットについて説明しています。

API キーをコードから分離してください

API キーを環境変数に格納し、起動時に読み込んでください。LinuxまたはmacOSでは:

export NOFILTER_API_KEY="paste-your-key-here"

プロジェクト用に共有クライアントモジュール(例:llm.py)を作成し、モデルを1回だけ構築してエクスポートします。各チェーンは同じオブジェクトをインポートし、API キー、タイムアウト、温度の変更を1か所で行うだけで済みます。これにより、ツールステップ用の別の冷却インスタンスとクリエイティブライティング用の別の暖かいインスタンスを、同じエンドポイントに異なる設定で保持することも容易になります。

多くの人が陥る落とし穴があります:ChatOpenAIは環境変数OPENAI_API_KEYとOPENAI_API_BASEも読み取ります。他のプロジェクト用にこれらの変数が設定されている場合、不完全に設定されたオブジェクトがリクエストを間違ったサーバーに送信する可能性があります。上記のようにbase_urlとapi_keyを明示的に渡すことで、この曖昧さを解消できます。

LangChainなしでも接続を確認できます。modelsエンドポイントは単一のエントリを返すはずです:

curl https://api.nofilteraichat.com/v1/models \
  -H "Authorization: Bearer $NOFILTER_API_KEY"

これが動作するがLangChainが失敗する場合、問題はAPIキーではなくPython環境にあります。両方が401で失敗する場合、APIキーに不要なスペースや改行が含まれていないか確認してください。比較用の正確なリクエスト形式はクイックスタートに記載されています。

ストリーミングとトークンの使用

トークンが生成される際に表示されるチャットUIは使い勝手が良くなります。LangChainは.stream()を通じてこれを公開し、サーバーは内部でstream: trueが設定されている場合に標準的なSSEチャンクを送信します。

from langchain_openai import ChatOpenAI
import os

llm = ChatOpenAI(
    model="uncensored",
    base_url="https://api.nofilteraichat.com/v1",
    api_key=os.environ["NOFILTER_API_KEY"],
    stream_usage=True,
)

final = None
for chunk in llm.stream("Describe a rainy harbour town in four sentences."):
    print(chunk.content, end="", flush=True)
    final = chunk if final is None else final + chunk

print()
print(final.usage_metadata)

stream_usage=Trueを指定すると、ストリームの最後にAPIが送信する最後のチャンクに入力トークン数と出力トークン数が含まれます。これらの数値を保持してください。エージェントが実際にどれくらいコストがかかるかを確認する最も安価な方法です。また、以下のコストセクションでこれらを使用しています。

覚えておくべき点があります:ストリーミングリクエストはストリーミングが終了するまで同時実行数のスロットを保持します。ストリーミングを閉じずに放棄すると、そのスロットが予想よりも長く占有されます。

Node と TypeScript

JavaScriptパッケージでは、オプション名がわずかに異なります。ベースURLはconfiguration内に指定します。

npm install @langchain/openai @langchain/core
import { ChatOpenAI } from "@langchain/openai";

const llm = new ChatOpenAI({
  model: "uncensored",
  apiKey: process.env.NOFILTER_API_KEY,
  configuration: { baseURL: "https://api.nofilteraichat.com/v1" },
  temperature: 0.8,
});

const res = await llm.invoke("Give me three names for a smuggler's ship.");
console.log(res.content);

レスポンスのTypeScript型は通常のLangChainメッセージクラスであるため、res.contentやres.usage_metadataを読み込む既存のコードはそのまま動作します。サーバールート内でこれを実行する場合は、リクエストごとにモデルを作成するのではなく、モジュールスコープで1回だけモデルを構築してください。これにより、呼び出しごとに新しいHTTPクライアントが作成されず、同時実行数の管理が容易になります。

.stream()、.bindTools()、.withStructuredOutput()など、他のすべてはPythonと同じように動作します。温度、top_p、ストップシーケンス、シード、ペナルティオプションはモデルに渡されるため、他のOpenAIスタイルのバックエンドと同様にコンストラクタで設定できます。

ツール呼び出しと小型エージェント

APIはツール呼び出しをサポートしています:toolsとtool_choiceフィールド、ストリーミングされたtool_calls、およびrole: "tool"メッセージとして返されるツール結果です。LangGraphのビルド済みエージェントはまさにこのループを使用します。以下は1つのツールを持つエージェントです:

import os
from langchain_core.tools import tool
from langchain_openai import ChatOpenAI
from langgraph.prebuilt import create_react_agent

@tool
def roll_dice(sides: int) -> int:
    """Roll a die with the given number of sides."""
    import random
    return random.randint(1, sides)

llm = ChatOpenAI(
    model="uncensored",
    base_url="https://api.nofilteraichat.com/v1",
    api_key=os.environ["NOFILTER_API_KEY"],
)

agent = create_react_agent(llm, [roll_dice])
out = agent.invoke(
    {"messages": [("user", "Roll a twenty-sided die twice and tell me the total.")]}
)
print(out["messages"][-1].content)

オープンウェイトモデルでのツール使用はホストされたフラッグシップモデルよりも予測が難しいため、テスト対象として扱ってください。ツール説明は平易な言葉で記述し、引数スキーマを小さく保ち、有効な引数を生成する必要があるエージェントステップではtemperatureを低く(0.2〜0.4)設定してください。呼び出しが不正な形式で返された場合、LangChainはそれを無効なツール呼び出しとして表示し、より明確な説明でリトライすると通常修正できます。

エージェントループを制限してください。LangGraphには再帰制限があり、許容できる範囲の数値に設定してください。エージェントが永遠にツールを呼び出せる場合、悪いプロンプトによりキーボードから離れている間にクレジットを使い果たす可能性があります。10〜15ステップの制限はほとんどのタスクにとって適切なデフォルトであり、エージェントを呼び出す際に設定で渡すことができます。

JSON モード

JSONモードはresponse_formatを通じて利用可能です。LangChainではJSONモードメソッドでリクエストし、プロンプト内のキーに名前を付けてください:

from pydantic import BaseModel
from langchain_openai import ChatOpenAI
import os

class Character(BaseModel):
    name: str
    role: str
    secret: str

llm = ChatOpenAI(
    model="uncensored",
    base_url="https://api.nofilteraichat.com/v1",
    api_key=os.environ["NOFILTER_API_KEY"],
)
structured = llm.with_structured_output(Character, method="json_mode")
print(structured.invoke(
    "Return JSON with keys name, role and secret for a noir detective."
))

レート制限、リトライ、コスト

フルキーは8つの同時リクエストと1分あたり300リクエストを許可します。トライアルキーは2と60を許可します。いずれかを超過すると、APIはHTTP 429とエラーコードを返します:1分あたりのリクエストにはrate_limited、同時実行数の超過にはconcurrency。一時的な過負荷も429を返し、Retry-After: 5ヘッダーを含みます。

LangChain はこれに対応するための 2 つのノブを提供します。モデルの max_retries はバックオフ付きで失敗した呼び出しをリトライし、実行設定の max_concurrency は並列バッチ処理の上限を設けます:

llm = ChatOpenAI(
    model="uncensored",
    base_url="https://api.nofilteraichat.com/v1",
    api_key=os.environ["NOFILTER_API_KEY"],
    max_retries=4,
    timeout=120,
)

answers = llm.batch(
    ["Prompt one", "Prompt two", "Prompt three", "Prompt four"],
    config={"max_concurrency": 6},
)

フルキーで max_concurrency を 6 に設定すると、2 番目のプロセス用の余裕が生まれます。各エージェントステップは個別のリクエストであり、ストリーミング中のステップはストリーミングが終了するまでスロットを占有することに注意してください。

エージェントランのコスト

料金は1M入力トークンあたり$0.15、1M出力トークンあたり$0.50です。エージェントステップで3,000トークンの履歴、ツール、指示を送信し、モデルが500トークンを書き出すと仮定します。入力のコストは3,000 × $0.15 / 1,000,000 = $0.00045です。出力のコストは500 × $0.50 / 1,000,000 = $0.00025です。1ステップは$0.0007です。10ステップの実行は$0.007で、1,000回のそのような実行は$7.00かかります。

エージェントはステップごとに増大する履歴を再送信するため、入力トークンが支配的になります。古いツール出力を削除することが最も安価な最適化です。失敗または拒否されたリクエストは課金されません。チャージとボーナスの詳細は 価格ページ に記載されています。

よくある問題

  • すべての呼び出しで404エラー。ベースURLは/v1で終わる必要があり、/chat/completionsを含めてはいけません。LangChainはパスを自身で付加します。
  • モデルが見つかりません。 唯一のモデルIDはuncensoredです。gpt-4oなどの名前は機能しません。
  • コンテキストエラー。 コンテキストウィンドウはプロンプトと完了を合わせて100,000トークンです。長い検索チェーンはこれを超過する可能性があります。送信する前に要約またはトリミングしてください。
  • リクエストが大きすぎます。 ボディの制限は8 MBで、プロンプトに文書全体を詰め込む場合に重要です。
  • 埋め込みが失敗します。 このAPIはテキストチャットのみです。埋め込みモデルは別のプロバイダに保持し、生成にはこのエンドポイントを使用してください。

同じパターンは他のフレームワークやチャットフロントエンドでも機能します。より多くのクライアントについては統合ガイドをご覧ください。何か特殊なケースがある場合は、サポートページが最初の着手点となります。

質問と回答

カスタムベースURLでChatOpenAIを使用できますか?

はい。base_url(Nodeではconfiguration内のbaseURL)、API キー、モデルuncensoredを渡してください。OpenAIチャットプロトコルに従っていれば、LangChainはどのサーバーが応答しても気にしません。

LangChainのストリーミングはこのAPIで動作しますか?

はい。APIはSSEでストリーミングし、最後に使用量を送信するため、.stream()とastream()が動作し、stream_usage=Trueでトークン数を確認できます。

LangChainの埋め込みやベクトルストアをこれと併用できますか?

埋め込みには対応していません。APIには埋め込み用のエンドポイントがないため、検索には別の埋め込みソースを使用し、取得したテキストをこのエンドポイントに送信して生成を行ってください。

レート制限に達するとどうなりますか?

HTTP 429(コード: rate_limited または concurrency)が返されます。ChatOpenAI で max_retries を設定し、フルキーの場合は max_concurrency を 8 以下に制限してください。

キーはフォーム 1 つで手に入ります

アカウントを作成し、キーをコピーし、ベースURLを変更します。これでセットアップは完了です。

API キーを取得