borderless / ui /agent /graph /llm.py
spagestic's picture
switched to qwen
71a7158
Raw
History Blame Contribute Delete
4.03 kB
# ui/agent/graph/llm.py
from __future__ import annotations
import os
from dataclasses import dataclass, field
from typing import Any
from huggingface_hub import InferenceClient
from langchain_core.messages import AIMessage
from langchain_core.runnables import RunnableConfig
from langchain_openai import ChatOpenAI
from ..completion import complete_turn
from ..config import INFERENCE_MODE, MODEL_ID, local_inference_enabled
from ..messages import api_turn_to_ai_message, langchain_messages_to_api
HF_ROUTER_BASE_URL = "https://router.huggingface.co/v1"
def _resolve_hf_token(configurable: dict[str, Any]) -> str:
oauth_token = str(configurable.get("hf_token") or "").strip()
if oauth_token:
return oauth_token
return os.environ.get("HF_TOKEN", "").strip()
@dataclass
class HubInferenceChatModel:
"""LangGraph-compatible wrapper around huggingface_hub InferenceClient."""
hf_token: str
max_tokens: int = 1800
temperature: float = 0.35
top_p: float = 0.9
tools: list[dict[str, Any]] = field(default_factory=list)
def bind_tools(self, tools: list[dict[str, Any]]) -> HubInferenceChatModel:
return HubInferenceChatModel(
hf_token=self.hf_token,
max_tokens=self.max_tokens,
temperature=self.temperature,
top_p=self.top_p,
tools=list(tools),
)
def invoke(self, messages: list[Any]) -> AIMessage:
client = InferenceClient(api_key=self.hf_token, model=MODEL_ID)
api_messages = langchain_messages_to_api(messages)
content, reasoning, tool_calls = complete_turn(
client,
api_messages,
max_tokens=self.max_tokens,
temperature=self.temperature,
top_p=self.top_p,
tools=self.tools or None,
)
return api_turn_to_ai_message(content, reasoning, tool_calls)
@dataclass
class MiniCPMChatModel:
max_tokens: int = 1800
temperature: float = 0.35
top_p: float = 0.9
tools: list[dict[str, Any]] = field(default_factory=list)
def bind_tools(self, tools: list[dict[str, Any]]) -> MiniCPMChatModel:
return MiniCPMChatModel(
max_tokens=self.max_tokens,
temperature=self.temperature,
top_p=self.top_p,
tools=list(tools),
)
def invoke(self, messages: list[Any]) -> AIMessage:
from ..minicpm.model import chat_complete
return chat_complete(
messages,
tools=self.tools or None,
max_tokens=self.max_tokens,
temperature=self.temperature,
top_p=self.top_p,
)
def build_llm(
config: RunnableConfig,
**overrides: Any,
) -> HubInferenceChatModel | MiniCPMChatModel | ChatOpenAI:
"""Build a chat model from the per-request configurable values."""
configurable = config.get("configurable", {})
max_tokens = int(overrides.pop("max_tokens", configurable.get("max_tokens", 1800)))
temperature = float(
overrides.pop("temperature", configurable.get("temperature", 0.35))
)
top_p = float(overrides.pop("top_p", configurable.get("top_p", 0.9)))
hf_token = _resolve_hf_token(configurable)
if local_inference_enabled():
return MiniCPMChatModel(
max_tokens=max_tokens,
temperature=temperature,
top_p=top_p,
)
if INFERENCE_MODE == "router":
params: dict[str, Any] = {
"model": MODEL_ID,
"api_key": hf_token,
"base_url": HF_ROUTER_BASE_URL,
"max_tokens": max_tokens,
"temperature": temperature,
"top_p": top_p,
}
params.update(overrides)
return ChatOpenAI(**params)
return HubInferenceChatModel(
hf_token=hf_token,
max_tokens=max_tokens,
temperature=temperature,
top_p=top_p,
)