underthesea v9.3.0以降の二面性: ベトナム語NLPライブラリと依存ゼロのエージェント基盤
Underthesea - AI Assistant
ひと目でわかる
- これは何?
- undertheseaは長らくベトナム語の単語分割器として知られてきたが、v9.3.0でエージェント機能を、v9.5.0でA2Aサーバを追加した。標準ライブラリだけでLLM APIを叩く設計と、その代償を整理する。
- 誰に向いている?
- 既存のベトナム語パイプラインを持ち、そこにエージェント機能を足したいチームには、pip install underthesea 一発で両方が同じ依存ツリーに入る点が実用的だ。逆に、OpenAI SDKのエコシステムに乗ったストリーミングや構造化出力、ベンダー固有の新機能をすぐ使いたい場合、stdlib実装のurllibベースという設計は足かせになる。
- 商用利用できる?
- できます。Apache-2.0 は寛容なライセンスで、著作権表示とライセンス表示を残せば、使用・改変・販売が可能です。
- 今もメンテナンスされている?
- されています。最後のコミットは 1 日前です。
- 何の言語で書かれている?
- 主に Python です(GitHub の言語統計による)。
回答はプロジェクトの GitHub データ(最終同期:2026年9月15日)と当サイトの分析に基づくもので、法的助言ではありません。
オープンソース詳細解説
単語分割器からエージェント基盤へ、パッケージ名が同じまま何が変わったか
undertheseaはもともとベトナム語の自然言語処理モジュール群で、トピックにもword-segmenterが残っている。READMEの見出しは現在「Open-source Agentic AI Toolkit」で、v9.3.0以降はエージェント機能を同梱する構成に変わった。つまり利用者がpip install undertheseaで得るものは、ベトナム語処理とAIエージェントの両方である。この同居は便利さの一方で、関心の分離という観点では判断が要る。ベトナム語の分かち書きだけが目的のチームは、エージェント関連のコードとトレース出力も一緒にインストールされることになる。トレースは既定で有効で、~/.underthesea/traces/に書き出される仕様だ。ライブラリを組み込む側のアプリケーションが、知らないうちにホームディレクトリへファイルを増やす挙動になる。
LLM()が環境変数からプロバイダを自動判定する仕組みと、その曖昧さ
エージェントの中心はAgentとLLMという2つの名前だ。Agentはname、provider、tools、instructionを受け取る。providerにはOpenAI、AzureOpenAI、Anthropic、Geminiの各クラスを明示的に渡すことも、LLM()を渡して環境変数から自動判定させることもできる。READMEが挙げる環境変数はOPENAI_API_KEY、AZURE_OPENAI_API_KEYとAZURE_OPENAI_ENDPOINT、ANTHROPIC_API_KEY、GOOGLE_API_KEYの4系統である。自動判定は開発機では楽だが、複数のAPIキーが同時に設定された環境ではどれが選ばれるかがREADMEからは読み取れない。本番のコンテナではLLM()に頼らず、プロバイダクラスを明示してapi_keyを設定管理側から注入するほうが事故が少ない。README自身も各プロバイダを「Anthropic SDKのパターンに従う独自クラス」と位置づけており、明示指定が想定された使い方だと読める。
外部依存ゼロのHTTP実装が意味するもの
READMEで最も強い主張は、Python標準ライブラリのurllibとjsonだけでLLM APIと通信し、openai、anthropic、google-genaiの各パッケージを必要としないという点だ。依存の衝突に悩む環境、たとえば社内の制限されたpipミラーしか使えない現場では、この設計は導入の障壁を下げる。ただし代償もある。各ベンダーSDKが提供する自動リトライ、レート制限のハンドリング、トークン使用量の集計、構造化出力のヘルパーは、ここでは自前で扱うことになる。トレース出力にtokensの数値が出ているのは、レスポンスからusageを読んで記録しているという意味で、リトライ制御までは読み取れない。プロバイダ側のAPI仕様が変わったとき、追随はundertheseaのリリースを待つことになる。SDKなら利用者側のバージョン更新で済む変更が、ここではライブラリ更新に依存する。
default_toolsの12個と、shell・python execを渡すという判断
既定ツールとしてcalculator、datetime、web search、wikipedia、file I/O、shell、python execを含む12個が用意されている。default_toolsをそのままAgentに渡せば、計算や調査のデモはすぐ動く。問題はshellとpython execの存在だ。READMEの例ではdefault_toolsを無条件に渡しているが、これをそのまま公開エンドポイントの背後に置くのは危険である。v9.5.0のserve()はエージェントをA2AプロトコルでHTTPに露出させる。つまりdefault_toolsを付けたエージェントをserve()すれば、到達可能な相手がシェルとPython実行に触れる経路ができる。READMEにはツールの許可リストや実行サンドボックスについての記述がない。ツール呼び出しの安全性は利用側の責務であり、この点はドキュメントが薄いと感じる。組み込みツールは必要なものだけをTool()で個別に渡すほうがよい。
トレースは既定で有効、無効化は環境変数1つ
すべてのエージェント呼び出しは自動的に~/.underthesea/traces/へ記録される。無効化はUNDERTHESEA_TRACE_DISABLED=1を設定する。記録内容は生成呼び出しの回数、モデル名、所要ミリ秒、トークン数の推移、ツール呼び出しの内訳で、READMEの出力例ではtrace IDごとにJSONファイルが1つ生成される。LangfuseTracerを使えばlangfuseパッケージ経由で外部に送ることもでき、@traceデコレータで任意の関数を子スパンとして入れ子にできる。ローカルJSONは手軽だが、複数プロセスで動かすと書き込み先が同じディレクトリになり、保持期間やローテーションの仕組みはREADMEからは確認できない。長期運用ではLangfuseTracer側に寄せるか、少なくとも出力先の肥大化を自分で監視する必要がある。
Sessionによる長時間タスクの分割と、progress_fileの位置づけ
Sessionはエージェントの文脈をリセットしながら複数セッションにまたがってタスクを進める仕組みで、Anthropicのハーネスに関する記事のパターンに従うとREADMEは説明している。create_taskでタスクと手順のリストを与え、run_until_complete(max_sessions=5)で上限付きのループを回す。進捗はprogress_file、例ではprogress.jsonに書き出される。コンテキストを毎回捨ててファイル経由で引き継ぐ設計なので、セッションをまたいだ状態はこのJSONが唯一の正と読める。スキーマや排他制御についての記述はなく、同じprogress_fileを複数プロセスが共有した場合の挙動は不明である。長時間バッチを1プロセスで回す分には素直だが、並列化を考えるなら自分でファイルを分ける設計が要る。
A2AサーバはASGIアプリとして出す、フレームワーク非依存の選択
v9.5.0で追加されたserve()は、エージェントをJSON-RPCのmessage/streamでHTTP+SSEに露出させる。ベースインストールにWebフレームワークの依存はなく、uvicornとstarletteとhttpxはunderthesea[agent-server]というextraで入れる。serve(agent, port=8000, path="/a2a/math", ui=True)とすると、/a2a/math/uiのチャットUI、/a2a/math/.well-known/agent-card.jsonのAgentCard、/a2a/mathへのPOSTの3つが生える。独自ルーティングや別のASGIサーバに載せたい場合はmake_app()で生のASGI callableを取り出し、uvicornまたはhypercornのmodule:appとして起動する。ここで注意したいのは、serve()が開発用の便利関数であり、本番のプロセス管理や認証についてREADMEが何も述べていないことだ。AgentCardを公開するということは、エージェントの存在と能力を外部に知らせる行為でもある。
代替としてのLangChain、あるいは素のSDKとの違い
同じ用途でよく比較されるのはLangChain系のエージェントフレームワークである。違いは抽象化の層の厚さにある。LangChainはプロバイダ差異を多数のインテグレーションパッケージで吸収し、ツール、メモリ、リトライ、コールバックを共通インタフェースで提供する。undertheseaは逆に、プロバイダごとのクラスを並べ、通信をurllibに落とし、依存を最小に保つ。どちらが優れているかではなく、何を固定するかの違いだ。LangChainを選ぶと依存ツリーとバージョン追従のコストを負う代わりに、豊富な既製部品とコミュニティの知見が使える。undertheseaを選ぶと依存は軽いが、リトライや構造化出力の類は自分で書く。もう一つの現実的な選択は、openaiやanthropicの公式SDKを直接使うことである。その場合、ベトナム語処理が必要ならundertheseaをNLPライブラリとしてだけ使い、エージェント部分はSDKに任せる併用が成り立つ。
メンテナンスとライセンス、更新頻度から見えること
ライセンスはApache-2.0で、特許条項を含む寛容なライセンスとして知られる。派生物の配布時にライセンス表示と変更点の明示が求められる点は、社内ツールに組み込んで再配布する場合に関わる。法的判断はここでは扱わない。メンテナンス面では、リリースが2026年4月から5月にかけてv9.3.0、v9.4.0、v9.5.0と短期間に並び、最終プッシュは2026年9月である。エージェント機能は追加から日が浅く、APIの形が今後動く可能性は相応にある。プロバイダクラスの引数名やserve()のシグネチャに依存したコードを書くなら、バージョンを固定してアップグレード時に差分を確認する運用が要る。Python対応は3.10から3.14までとREADMEは記載しており、3.9以前は対象外である。
編集部の結論
既存のベトナム語パイプラインを持ち、そこにエージェント機能を足したいチームには、pip install underthesea 一発で両方が同じ依存ツリーに入る点が実用的だ。逆に、OpenAI SDKのエコシステムに乗ったストリーミングや構造化出力、ベンダー固有の新機能をすぐ使いたい場合、stdlib実装のurllibベースという設計は足かせになる。導入前に確認すべきは、agent-server extraを入れた状態でserve()が返すASGIアプリを、自分のuvicornまたはhypercornのバージョンで実際に起動できるかどうかだ。READMEの例はuvicorn module:appとhypercorn module:appの2行しか示しておらず、ワーカ数やタイムアウトの指針は書かれていない。
コミュニティノート