Home Assistant大语言模型API
Home Assistant可以与大语言模型(LLMs)进行交互。通过向大语言模型公开Home Assistant API,大语言模型可以获取数据或控制Home Assistant,从而更好地辅助用户。Home Assistant带有一个内置的大语言模型API,但自定义集成可以注册自己的API以提供更高级的功能。
内置辅助API
Home Assistant有一个内置API,它向大语言模型公开了辅助API。此API允许大语言模型通过意图与Home Assistant交互,并且可以通过注册意图进行扩展。
辅助API等同于内置对话代理也可访问的功能和公开实体。不能执行管理任务。
支持大语言模型API
大语言模型API需要在你的集成中的两个地方进行集成。用户需要能够配置应使用哪个API,并且在与大语言模型交互时,应将API提供的工具传递给大语言模型。
选项流程
所选的API应存储在配置项选项中。它应包含对API ID的字符串引用。如果未选择API,则必须省略该键。
在你的选项流程中,你应该向用户提供一个选择器,让他们选择应使用哪个API。
from types import MappingProxyType
from homeassistant.const import CONF_LLM_HASS_API
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers import llm
from homeassistant.helpers.selector import (
SelectOptionDict,
SelectSelector,
SelectSelectorConfig,
)
@callback
def async_get_options_schema(
hass: HomeAssistant,
options: MappingProxyType[str, Any],
) -> vol.Schema:
"""返回选项模式。"""
apis: list[SelectOptionDict] = [
SelectOptionDict(
label="无控制",
value="none",
)
]
apis.extend(
SelectOptionDict(
label=api.name,
value=api.id,
)
for api in llm.async_get_apis(hass)
)
return vol.Schema(
{
vol.Optional(
CONF_LLM_HASS_API,
description={"suggested_value": options.get(CONF_LLM_HASS_API)},
default="none",
): SelectSelector(SelectSelectorConfig(options=apis)),
}
)
在处理选项时,如果用户选择了“none”,请确保在存储选项之前删除该键。
if user_input[CONF_LLM_HASS_API] == "none":
user_input.pop(CONF_LLM_HASS_API)
return self.async_create_entry(title="", data=user_input)
获取工具
与大语言模型交互时,你应该从所选的API中获取工具,并将它们与API提供的额外提示一起传递给大语言模型。
from homeassistant.const import CONF_LLM_HASS_API
from homeassistant.core import HomeAssistant, callback
from homeassistant.components import conversation
from homeassistant.helpers import intent, llm
class MyConversationEntity(conversation.ConversationEntity):
def __init__(self, entry: ConfigEntry) -> None:
"""初始化代理。"""
self.entry = entry
...
async def async_process(
self, user_input: conversation.ConversationInput
) -> conversation.ConversationResult:
"""处理用户输入。"""
intent_response = intent.IntentResponse(language=user_input.language)
llm_api: llm.API | None = None
tools: list[dict[str, Any]] | None = None
if self.entry.options.get(CONF_LLM_HASS_API):
try:
llm_api = await llm.async_get_api(
self.hass,
self.entry.options[CONF_LLM_HASS_API],
llm.LLMContext(
platform=DOMAIN,
context=user_input.context,
user_prompt=user_input.text,
language=user_input.language,
assistant=conversation.DOMAIN,
device_id=user_input.device_id,
),
)
except HomeAssistantError as err:
LOGGER.error("获取大语言模型API时出错: %s", err)
intent_response.async_set_error(
intent.IntentResponseErrorCode.UNKNOWN,
f"准备大语言模型API时出错: {err}",
)
return conversation.ConversationResult(
response=intent_response, conversation_id=user_input.conversation_id
)
tools = [
_format_tool(tool) # TODO按照你的大语言模型期望的格式格式化工具
for tool in llm_api.tools
]
if llm_api:
api_prompt = llm_api.api_prompt
else:
api_prompt = llm.async_render_no_api_prompt(self.hass)
prompt = "\n".join((user_prompt, api_prompt))
# 与大语言模型交互并传递工具
request = user_input.text
for _iteration in range(10):
response =... # 向大语言模型发送请求并获取响应,包括工具
if not response.tool_call:
break
LOGGER.debug(
"工具调用: %s(%s)",
response.tool_call.function.name,
response.tool_call.function.arguments,
)
tool_input = llm.ToolInput(
tool_name=response.tool_call.function.name,
tool_args=json.loads(response.tool_call.function.arguments),
)
try:
tool_response = await llm_api.async_call_tool(tool_input)
except (HomeAssistantError, vol.Invalid) as e:
tool_response = {"error": type(e).__name__}
if str(e):
tool_response["error_text"] = str(e)
LOGGER.debug("工具响应: %s", tool_response)
response = tool_response
最佳实践
如果你的对话实体允许用户使用 conversation_id
维护对话历史,请确保为每次交互重新生成提示,并在为后续命令传递的历史中覆盖它。这允许用户始终能够查询家庭的最新状态。
创建自己的API
要创建自己的API,你需要创建一个继承自 API
的类并实现 async_get_tools
方法。async_get_tools
方法应该返回一个 Tool
对象列表,这些对象表示你希望向大语言模型公开的功能。
工具
llm.Tool
类表示可以由大语言模型调用的工具。
from homeassistant.core import HomeAssistant
from homeassistant.helper import llm
from homeassistant.util import dt as dt_util
from homeassistant.util.json import JsonObjectType
class TimeTool(llm.Tool):
"""获取当前时间的工具。"""
name = "GetTime"
description: "返回当前时间。"
# 可选。输入参数的voluptuous模式。
parameters = vol.Schema({
vol.Optional('timezone'): str,
})
async def async_call(
self, hass: HomeAssistant, tool_input: ToolInput, llm_context: LLMContext
) -> JsonObjectType:
"""调用工具。"""
if "timezone" in tool_input.tool_args:
tzinfo = dt_util.get_time_zone(tool_input.tool_args["timezone"])
else:
tzinfo = dt_util.DEFAULT_TIME_ZONE
return dt_util.now(tzinfo).isoformat()
llm.Tool
类具有以下属性:
名称 | 类型 | 描述 |
---|---|---|
name | 字符串 | 工具的名称。必需。 |
description | 字符串 | 工具的描述,帮助大语言模型理解何时以及如何调用它。可选但建议提供。 |
parameters | vol.Schema | 参数的voluptuous模式。默认为 vol.Schema() |
llm.Tool
类具有以下方法:
async_call
:当被大语言模型调用时执行工具的实际操作。这必须是一个异步方法。其参数是 hass
和 llm.ToolInput
的一个实例。响应数据必须是一个字典,并且可以序列化为JSON homeassistant.util.json.JsonObjectType
。错误必须作为 HomeAssistantError
异常(或其子类)抛出。响应数据不应包含用于错误处理的错误代码。
ToolInput
具有以下属性:
名称 | 类型 | 描述 |
---|---|---|
tool_name | 字符串 | 正在调用的工具的名称 |
tool_args | 字典 | 大语言模型提供的参数。参数使用 parameters 模式进行转换和验证。 |
platform | 字符串 | 使用该工具的对话代理的DOMAIN |
context | Context | 对话的 homeassistant.core.Context |
user_prompt | 字符串 | 发起工具调用的原始文本输入 |
language | 字符串 | 对话代理的语言,或“*”表示任何语言 |
assistant | 字符串 | 用于控制公开实体的助手名称。目前,仅支持 conversation 。 |
device_id | 字符串 | 用户发起对话的设备的设备ID |
API
API对象允许创建API实例。一个API实例表示将提供给大语言模型的一组工具。
from homeassistant.core import HomeAssistant
from homeassistant.helper import llm
from homeassistant.util import dt as dt_util
from homeassistant.util.json import JsonObjectType
class MyAPI(API):
"""我自己的大语言模型API。"""
def __init__(self, hass: HomeAssistant) -> None:
"""初始化类。"""
super().__init__(
hass=hass,
id="my_unique_key",
name="我自己的API",
)
async def async_get_api_instance(self, llm_context: LLMContext) -> APIInstance:
"""返回API的实例。"""
return APIInstance(
api=self,
api_prompt="调用工具从Home Assistant获取数据。",
llm_context=llm_context,
tools=[TimeTool()],
)
async def async_setup_api(hass: HomeAssistant) -> None:
"""在Home Assistant中注册API。"""
llm.async_register_api(hass, MyAPI())
llm.API
类具有以下属性:
名称 | 类型 | 描述 |
---|---|---|
id | 字符串 | API的唯一标识符。必需。 |
name | 字符串 | API的名称。必需。 |
llm.APIInstance
类具有以下属性:
名称 | 类型 | 描述 |
---|---|---|
api | API | API对象。必需。 |
api_prompt | 字符串 | 关于如何使用大语言模型工具的大语言模型指令。必需。 |
llm_context | LLMContext | 工具调用的上下文。必需。 |
tools | list[Tool] | 此API中可用的工具。必需。 |
总结
本文档主要介绍了Home Assistant与大语言模型交互的相关内容,包括内置辅助API及其功能,支持大语言模型API时在集成中的选项流程(涉及API选择的存储与展示给用户)和获取工具传递给大语言模型的操作,以及创建自己API的方法(需创建继承自 API
的类并实现 async_get_tools
方法),同时详细阐述了工具(Tool
类的属性和方法)和API(API
类及 APIInstance
类的属性)相关的概念与要求,为开发者在Home Assistant中集成大语言模型功能提供了全面的指导和规范。