繁中 ▾
取得 API 金鑰

Uncensored VideoSora 2 API:在影片管線中使用無審查文字

LangChain 代理式 AI 教學:搭配 OpenAI 相容 API API

此 LangChain 代理式 AI 教學將 LangChain 連接至 OpenAI 相容端點,綁定兩個工具,並執行可逐行閱讀的代理迴圈。每個程式碼片段都使用相同的 Base URL 與模型名稱 uncensored。

更新

機器手臂在工具方塊之間循環運作,說明 LangChain 代理程式呼叫工具

重點摘要

  • ChatOpenAI 運作方式不變:設定 base_url、api_key 與模型為 uncensored。
  • API 支援函式呼叫,因此 bind_tools 與預建代理程式均可運作。
  • 限制迴圈迭代次數並驗證工具參數;開放權重模型有時會出錯。
  • 執行並行代理程式時,完整金鑰需遵守 8 個並行請求的限制。

開始前你需要準備的事項

你需要 Python 3.10 或更新版本、API 金鑰與一些套件。金鑰來自 API 金鑰頁面:使用 Google 或電子郵件與密碼註冊,然後一鍵領取 $0.50 試用額度。試用金鑰允許 2 個並行請求與每分鐘 60 個請求,若一次只執行一個代理程式,這已足夠應付本文的所有內容。

pip install langchain-openai langchain-core langgraph
export API_KEY="paste-your-key-here"

API 提供 POST /v1/chat/completions 與 GET /v1/models 端點。LangChain 僅需第一個端點。該模型為單一開放權重模型,經調整以在合法成人使用情境下回答而不拒絕內容;由獨立供應商運行,並非任何模型廠商的官方 API。文件列出了標頭與限制,若需將其置於編輯器旁可參考。

各組件與 API 的對應關係

了解 LangChain 在網路上的行為很有幫助。HumanMessage 會變成 role 為 user 的訊息。AIMessage 會變成 assistant,若包含函式呼叫,則以 tool_calls 陣列出現在助手訊息中。ToolMessage 會變成 role 為 tool 並附帶對應的呼叫 ID。系統提示詞則以 role system 排在最前面。

這種對應關係對於除錯很重要。如果代理程式行為異常,請在每次呼叫前列印訊息列表,並像閱讀紀錄一樣閱讀它。你通常在一分鐘內就能發現問題:空的工具結果、不相符的呼叫 ID,或是歷史記錄變得太長。「代理式」這個詞可能讓這聽起來像魔法,但每個步驟都是一次普通的 chat completion 請求。

步驟 1:連接 ChatOpenAI

整個整合只需要三個參數。LangChain 會建立標準的 OpenAI 風格請求,因此伺服器無法區分差異。

import os
from langchain_openai import ChatOpenAI

llm = ChatOpenAI(
    model="uncensored",
    base_url="https://api.uncensoredvideo.cc/v1",
    api_key=os.environ["API_KEY"],
    temperature=0.7,
    max_retries=2,
)

print(llm.invoke("Name three beats of a heist scene, one line each.").content)

如果這印出三行,表示連線正常。如果出現 401,請檢查金鑰。如果出現 404,請檢查 URL 是否以 /v1 結尾且沒有額外路徑。max_retries 是一個用戶端選項,有助於處理帶有 Retry-After: 5 的暫時性 429 回應。

串流輸出的運作方式與你使用任何 OpenAI 模型時相同:呼叫 llm.stream(...) 並進行迭代。最後一個區塊會包含用量資訊,因此你可以記錄每次呼叫的 token 計數。

步驟 2:定義工具

代理程式是一個迴圈:模型閱讀對話,回答或要求工具,你的程式碼執行工具,然後結果回傳給模型。以下工具是純 Python 函式。它們故意設計得很無聊,因為重點在於觀察機制。

from langchain_core.tools import tool

@tool
def word_count(text: str) -> int:
    """Count the words in a piece of text."""
    return len(text.split())

@tool
def spoken_minutes(words: int, words_per_minute: int = 150) -> float:
    """Estimate how many minutes a script takes to read aloud."""
    return round(words / words_per_minute, 2)

tools = [word_count, spoken_minutes]

docstring 與型別提示會成為模型所見的工具描述與結構。撰寫時請假想你在向同事交代任務。模糊的 docstring是代理程式選錯工具的最常見原因。如果你為影片撰寫腳本,相同的模式可擴展至查詢分鏡腳本或檢查長度預算的工具,此主題詳見於 Sora 2 腳本產生器頁面。

步驟 3:手動執行代理迴圈

預建輔助函式隱藏了迴圈。自己寫一次會讓之後的除錯更容易。

from langchain_core.messages import HumanMessage, ToolMessage

by_name = {t.name: t for t in tools}
llm_tools = llm.bind_tools(tools)

messages = [HumanMessage(
    "Here is a draft: 'The vault door hums. Nina counts to three, "
    "then cuts the power.' How many words is it, and how long is it read aloud?"
)]

for step in range(6):
    ai = llm_tools.invoke(messages)
    messages.append(ai)
    if not ai.tool_calls:
        break
    for call in ai.tool_calls:
        result = by_name[call["name"]].invoke(call["args"])
        messages.append(ToolMessage(content=str(result), tool_call_id=call["id"]))

print(messages[-1].content)

有三個細節很重要。range(6) 限制可防止混淆的模型無限迴圈,並限制你的支出。tool_call_id 必須與它回答的呼叫相符。模型可以在一次回覆中要求多個工具,這就是為什麼內層迴圈處理列表的原因。

在底層,請求攜帶 tools 陣列,回覆攜帶 tool_calls,結果以 role: "tool" 的訊息形式回傳。你可以使用 tool_choice 強制指定特定工具,LangChain 將其作為 bind_tools 的參數提供。

步驟 4:使用預建的 LangGraph 代理程式

一旦手動迴圈變得合理,預建代理程式可以節省程式碼行數。它接受相同的模型與相同的工具。

import os
from langchain_openai import ChatOpenAI
from langgraph.prebuilt import create_react_agent

llm = ChatOpenAI(
    model="uncensored",
    base_url="https://api.uncensoredvideo.cc/v1",
    api_key=os.environ["API_KEY"],
)

agent = create_react_agent(llm, tools)
out = agent.invoke({"messages": [("user", "How long is a 450 word script read aloud?")]})
print(out["messages"][-1].content)

LangChain 與 LangGraph 在版本之間會更改其 API,某些輔助函式已被重新命名或移動。如果匯入失敗,請檢查目前的 LangChain 文件以取得等效的代理程式建構子。連接部分,即帶有 Base URL 的 ChatOpenAI,保持不變。

選擇迴圈與圖形

手寫迴圈足以讓代理程式從少數工具中選擇並停止。它易於閱讀、易於記錄且沒有框架帶來的意外。當你需要依賴狀態的分支時,請轉向 LangGraph:一個將工作送回再次處理的審查步驟、在執行危險工具前的人類核准,或多個將結果傳遞給彼此的專門子代理程式。

無論你選擇什麼,請保持每個節點小巧並賦予單一任務。輸出簡短 JSON 編號清單的規劃節點、執行工具的執行節點,以及產生最終文字的撰寫節點,比一個巨大的提示詞更容易測試。它們也讓你使用不同的 temperature:規劃與工具使用時較低,撰寫步驟時較高。由於每個節點都是一次正常的 chat completion 呼叫,相同的金鑰、URL 與模型名稱可服務所有節點,成本只是呼叫的總和。

最後一個習慣:列印累計 token 總量。在示範中看起來便宜的代理程式,在凌亂的真實任務中可能會花費十倍的金額,而每個回應上的用量資訊會在第一次執行時顯示出來,以免在餘額上出現意外。

記憶體、測試與結構化輸出

上述迴圈在腳本結束時會遺忘所有內容。最簡單的記憶方式是訊息列表本身:在使用者輪次之間保留它,附加每個新問題,並在變長時修剪最舊的訊息。對於長時間會話,請以模型撰寫的簡短摘要取代舊訊息。由於輸入按 token 計費,500-token 的摘要在成本與焦點上皆優於 20,000 token 的原始歷史記錄。

測試代理程式主要是檢查可觀察的行為。將 temperature 設為 0 或傳遞固定的 seed,API 會將其傳遞,使運行更具可重複性。然後撰寫一些你知道應該呼叫哪個工具的測試問題,並在訊息列表中斷言工具名稱與參數,而不是答案的確切措辭。在提示詞或工具描述每次更改後執行這些測試。更改 docstring可能會改變模型選擇的工具,而測試是發現問題最便宜的方式。

為每次運行記錄三件事:步驟數、帶有參數的工具呼叫以及 token 用量。當運行出錯時,這三行告訴你模型是否選擇錯誤、工具是否失敗,或迴圈是否耗盡步驟。

結構化輸出與 JSON 模式

代理程式通常需要回傳資料而非文字。API 透過 response_format: {"type":"json_object"} 支援 JSON 模式。在 LangChain 中,你可以使用 llm.bind(response_format={"type": "json_object"}) 要求它。在提示詞中告訴模型答案必須是 JSON 物件,並命名你預期的鍵,然後解析字串並使用 Pydantic 驗證它。不要相信解析步驟總是會成功;將其包裝在重試中,並將錯誤文字回傳給模型一次。

常見陷阱與解決方法

  • 工具參數錯誤。 開放權重模型有時會在你宣告為整數的地方傳送字串。驗證參數,從工具回傳短錯誤訊息,讓模型在下一步自行修正。
  • 失控迴圈。 始終限制迭代次數。在開發期間記錄每個步驟。
  • 並行代理程式。 完整金鑰允許 8 個並行請求。如果你執行批次,請在 llm.batch 上設定 config={"max_concurrency": 4} 以保留緩衝空間。超過限制會回傳 429 與程式碼 concurrency;超過每分鐘 300 個請求會回傳 rate_limited。
  • 串流輸出加上工具。 串流請求會保留其並行槽位直到串流結束,因此在試用金鑰的串流處理常式中不要開始新的呼叫。
  • 歷史記錄增長。 每個步驟都會重新傳送完整的訊息列表。上下文視窗為 100,000 token,但你在每次呼叫時都要為輸入付費。

代理程式運行的成本

取一個執行任務需進行 4 次模型呼叫的簡單代理程式,平均提示詞為 3,000 token,每次呼叫輸出 200 token。輸入:4 x 3,000 = 12,000 token,即 12,000 x $0.15 / 1,000,000 = $0.0018。輸出:4 x 200 = 800 token,即 $0.0004。一次執行成本為 $0.0022,因此 1,000 次執行成本為 $2.20。$0.50 的免費試用額度可涵蓋約 227 次此類執行。失敗或被拒絕的請求不會計費,且預付額度永不失效。請見定價以了解儲值金額與獎金。本網站僅接受加密貨幣,TRC20 上的 USDT 或 Base 上的 USDC。

問答

LangChain 需要為此 API 進行特殊整合嗎?

不需要。langchain-openai 的 ChatOpenAI 類別接受 base_url,因此你只需將其指向 API 並使用模型 uncensored 即可。無需自訂包裝函式。

API 支援代理程式的工具呼叫嗎?

是的。它接受工具與 tool_choice,回傳 tool_calls(串流輸出時亦然),並將結果以 role 為 tool 的訊息形式回傳。

為什麼我的代理程式會因 429 錯誤而停止?

你觸發了請求速率或並行限制。完整金鑰允許 8 個並行請求與每分鐘 300 個請求。降低 max_concurrency 或等待 Retry-After 期間。

我可以使用 LangGraph 取代普通的迴圈嗎?

可以。LangGraph 的預先建構代理程式會使用相同的 ChatOpenAI 物件與相同的工具列表,因此連線程式碼不會改變。

只差一張表單,即可取得金鑰

建立帳號、複製金鑰、更改Base URL。這就是整個設定過程。

取得 API 金鑰