gpt-oss:20BでMCPを試してみた【LangChain+Ollama】

お疲れ様です。

今回はgpt-oss:20Bを使ってMCPサーバを利用した返答生成を試してみます。

コードは過去にGeminiのAPIを使って作成したものを、langchain-ollamaを使ったものに変更したのみにはなりますが…。 最後にGeminiと簡単に比較した内容を載せたいと思います。
GeminiとLangChainでMCPを使った時の記事は以下。MCPサーバについてや事前準備については以下を確認してください。

fallpoke-tech.hatenadiary.jp



実装

ソースコードはこちらにあります。 以前RAGを試したときのリポジトリと同じものに実装しています。 このうち、MCPを使った実装はchat/generate_response_mcp.pyにあります。

github.com

実際のコードは以下です。 UIをStreamlitで作っているのでチャットの履歴がst.session_state.messagesに入っています。

注意点として、モデルの読み込みはChatOllama()を使うようにしてください。 RAGではOllamaLLMを使っていたのですが、こちらはMCPサーバを使うためのツールが使えません。
【参考】
github.com

def response_generator_mcp() -> Generator:
    """AIが作成した返答をstreamで返す関数
    """    
    response = asyncio.run(create_gemini_mcp_response(st.session_state.messages))
    for word in response.split():
        yield word + " "
        time.sleep(0.05)


# AIの返答を作成
async def create_gemini_mcp_response(
    messages: List[Dict[str, str]]
) -> str:        
    # モデルを準備
    llm = ChatOllama(model='gpt-oss:20b')
    
    # プロンプトを設定
    prompt = PromptTemplate.from_template(MCP_PROMPT)
    
    # 直前のユーザの入力を取得
    user_input = messages[-1]["content"]
    
    # MCPサーバの設定を読み込み
    with open(MCP_CONFIG_PATH, mode="r") as f:
        mcp_config = json.load(f)
    
    # ツール化
    mcp_client = MultiServerMCPClient(mcp_config["mcpServers"])
    tools = await mcp_client.get_tools()
    
    # エージェントを用意
    agent = create_tool_calling_agent(llm, tools, prompt)
    executor = AgentExecutor(agent=agent, tools=tools)
    
    # 返答を取得
    response = await executor.ainvoke({"question": user_input})
    
    # 返答を成形(makrddown -> HTML)
    response = Markdown().convert(response["output"])
    
    return response

出力結果

上記で実装したコードを使って出力した結果が以下になります。 使用したMCPサーバはWebサイトのコンテンツを取得するfetchです。

質問文:

次のサイトを参照してエレファントカシマシの2000年代の活動をまとめてください。
https://www.elephantkashimashi.com/biography/

gpt-oss_output1

gpt-oss_output2

1ページに収まらなかったのでスクリーンショット2枚になっていますが、サイトから情報取得して綺麗にまとめてくれています。 ただ、出力に時間がかかるのは気になりました。(今回の場合5分程度)

Geminiでの出力結果(比較用)

最後にGeminiでの出力結果です。モデルはgemini-2.0-flashです。

gemini_output

得られた情報を箇条書き的に羅列して表示してくれています。 出力の時間もそれほどかからない印象でした。