сводка по 0x00
MAI-UI — это пользовательский интерфейс, который позволяет использовать интерфейс MAI-UI. 重塑人机 режим взаимодействия 的Базовый интеллектуальный пользовательский интерфейс (GUI)“, 和首轃星辰的思路 очень похожи, поэтому мы можем распечатать доказательства друг друга.
Информация пользовательского интерфейса MAI следующая:
https://arxiv.org/pdf/2512.22047
https://github.com/Tongyi-MAI/MAI-UI
Два класса основных агентов MAI-UI следующие: Эти два класса агентов:
| Агент | документ | задача | соглашение о выпуске продукции |
|---|---|---|---|
| MAIGroundingAgent | src/mai_grounding_agent.py | Позиционирование элемента пользовательского интерфейса (单步) | |
| MAIUINavigationAgent | src/mai_navigation_agent.py | Поддержка графического интерфейса пользователя, поддержка Ask_user и mcp_call. |
0x01 ប្រ្រ្រ្រេ
Три характеристики проекта MAI-UI заключаются в следующем.
1.1 Особенности1
Форма1: 三套电影电视词 发动最新Форма агента: заземление / 纯навигация / Ask_user + улучшенная навигация MCP
src/prompt.py также поддерживает:
- MAI_MOBILE_SYS_PROMPT_GROUNDING 一 и позиционирование элемента
- MAI_MOBILE_SYS_PROMPT — стандартная навигация.
- MAI_MOBILE_SYS_PROMPT_ASK_USER_MCP 一在действия навигации集里南加交电影специальные инструменты:
- Ask_user (вопрос): 打回去打回去
- mcp_call(инструмент,args):调门门MCP工作(如高德navigator)花全设计端做不能设计

значение:
- Это «Взаимодействие пользователя с агентом + рост MCP». подскажите 下解遏以作设计集。
- Правильная конфигурация нового инструмента интерактивного класса — это схема 改prompt.py+parse_tagged_text, а не другой класс агента.
1.2 особенности2
Значение 2: 归一化координата космического корабля SCALE_FACTOR = 999 + протокол вывода тега XML (вызов функции 而非).
- src/mai_grounding_agent.py и src/mai_naivigation_agent.py
999; модель навсегда выводится[0,999]区门公字, client按手机截图(W,H)反归一化. - Результатом является не вызов функции OpenAI, а XML в необработанных текстовых тегах:
- Заземление:
… {“координата”:[x,y]} - Навигация:
. {JSON} (Совместимость с моделью мышления) - 解析器:parse_grounding_response、parse_tagged_text,电视结果剧ValueError。
- Заземление:

значение:
- Размер экрана: не требуется подсказка, размер экрана;
- Можно использовать DashScope, поскольку это только анализ чистого текста, не полагающийся на какую-либо структуру вызова инструментов;
- Стоимость: стоимость доставки должна быть гарантирована клиентом самостоятельно.
1.3 Особенности 3
Особенность 3: Сетевой интерфейс + клиентский интерфейс TrajMemory, Сетевой интерфейс с сообщениями:
- BaseAgent одновременно хранит traj_memory: TrajMemory, каждый TrajStep: изображение и скриншот_байты: байты
- MAIUINaivigationAgent._build_messages() и runtime_conf[“history_n”] 把最作 N 步的“ 截国+门面回社“重电影多轮диалог пользователя/помощника再发给vLLM一一一vLLM端雝炊最么
- save_traj()/load_traj() 走bytes,可被电影化/回放/做话明离线analysis。
- Тело запроса Stept (независимое, без состояния) выглядит следующим образом:

значение:
- 可回放、可语是、可断点画跑—save_traj出dict、load_traj第回,简线replay, не требует木最要期最要期
- Поддержка VLLM для масштабирования параллельных носителей до 512-дюймовый алюминиевый корпус с ручным управлением;
- Стоимость: 每步N张图都要重传, пропускная способность — стоимость предварительного заполнения;
1.4 Заключение
Уникальной особенностью проекта MAI-UI является не сама модель, а этот набор клиентских контрактов: независимый от разрешения, несвязанный, несвязанный сам по себе, этот набор клиентских соглашений: независимый от разрешения, не связанный, не связанный с самим собой, протокол тегов XML (с развязкой внутренней части) + многодневный перевыпуск без состояния (развязка с длиной истории) + тройная подсказка разблокировки заземления/навигации/ask_user+MCP
电影时间一一一方法任么可于可以都时间设四条线走, 全容去改模度度赛
0x02 Подсказка
2.1 Код дисплея
Ниже приведен предлагаемый код слова.
MAI_MOBILE_SYS_PROMPT
MAI_MOBILE_SYS_PROMPT = """You are a GUI agent. You are given a task and your action history, with screenshots. You need to perform the next action to complete the task.
## Output Format
For each function call, return the thinking process in tags, and a json object with function name and arguments within XML tags:
```
...
{"name": "mobile_use", "arguments": }
```
## Action Space
{"action": "click", "coordinate": [x, y]}
{"action": "long_press", "coordinate": [x, y]}
{"action": "type", "text": ""}
{"action": "swipe", "direction": "up or down or left or right", "coordinate": [x, y]} # "coordinate" is optional. Use the "coordinate" if you want to swipe a specific UI element.
{"action": "open", "text": "app_name"}
{"action": "drag", "start_coordinate": [x1, y1], "end_coordinate": [x2, y2]}
{"action": "system_button", "button": "button_name"} # Options: back, home, menu, enter
{"action": "wait"}
{"action": "terminate", "status": "success or fail"}
{"action": "answer", "text": "xxx"} # Use escape characters \\', \\", and \\n in text part to ensure we can parse the text in normal python string format.
## Note
- Write a small plan and finally summarize your next action (with its target element) in one sentence in part.
- Available Apps: `["Camera","Chrome","Clock","Contacts","Dialer","Files","Settings","Markor","Tasks","Simple Draw Pro","Simple Gallery Pro","Simple SMS Messenger","Audio Recorder","Pro Expense","Broccoli APP","OSMand","VLC","Joplin","Retro Music","OpenTracks","Simple Calendar Pro"]`.
You should use the `open` action to open the app as possible as you can, because it is the fast way to open the app.
- You must follow the Action Space strictly, and return the correct json object within and XML tags.
""".strip()
MAI_MOBILE_SYS_PROMPT_NO_THINKING
MAI_MOBILE_SYS_PROMPT_NO_THINKING = """You are a GUI agent. You are given a task and your action history, with screenshots. You need to perform the next action to complete the task.
## Output Format
For each function call, return a json object with function name and arguments within XML tags:
```
{"name": "mobile_use", "arguments": }
```
## Action Space
{"action": "click", "coordinate": [x, y]}
{"action": "long_press", "coordinate": [x, y]}
{"action": "type", "text": ""}
{"action": "swipe", "direction": "up or down or left or right", "coordinate": [x, y]} # "coordinate" is optional. Use the "coordinate" if you want to swipe a specific UI element.
{"action": "open", "text": "app_name"}
{"action": "drag", "start_coordinate": [x1, y1], "end_coordinate": [x2, y2]}
{"action": "system_button", "button": "button_name"} # Options: back, home, menu, enter
{"action": "wait"}
{"action": "terminate", "status": "success or fail"}
{"action": "answer", "text": "xxx"} # Use escape characters \\', \\", and \\n in text part to ensure we can parse the text in normal python string format.
## Note
- Available Apps: `["Camera","Chrome","Clock","Contacts","Dialer","Files","Settings","Markor","Tasks","Simple Draw Pro","Simple Gallery Pro","Simple SMS Messenger","Audio Recorder","Pro Expense","Broccoli APP","OSMand","VLC","Joplin","Retro Music","OpenTracks","Simple Calendar Pro"]`.
You should use the `open` action to open the app as possible as you can, because it is the fast way to open the app.
- You must follow the Action Space strictly, and return the correct json object within and XML tags.
""".strip()
MAI_MOBILE_SYS_PROMPT_ASK_USER_MCP
# Placeholder prompts for future features
MAI_MOBILE_SYS_PROMPT_ASK_USER_MCP = Template(
"""You are a GUI agent. You are given a task and your action history, with screenshots. You need to perform the next action to complete the task.
## Output Format
For each function call, return the thinking process in tags, and a json object with function name and arguments within XML tags:
```
...
{"name": "mobile_use", "arguments": }
```
## Action Space
{"action": "click", "coordinate": [x, y]}
{"action": "long_press", "coordinate": [x, y]}
{"action": "type", "text": ""}
{"action": "swipe", "direction": "up or down or left or right", "coordinate": [x, y]} # "coordinate" is optional. Use the "coordinate" if you want to swipe a specific UI element.
{"action": "open", "text": "app_name"}
{"action": "drag", "start_coordinate": [x1, y1], "end_coordinate": [x2, y2]}
{"action": "system_button", "button": "button_name"} # Options: back, home, menu, enter
{"action": "wait"}
{"action": "terminate", "status": "success or fail"}
{"action": "answer", "text": "xxx"} # Use escape characters \\', \\", and \\n in text part to ensure we can parse the text in normal python string format.
{"action": "ask_user", "text": "xxx"} # you can ask user for more information to complete the task.
{"action": "double_click", "coordinate": [x, y]}
{% if tools -%}
## MCP Tools
You are also provided with MCP tools, you can use them to complete the task.
{{ tools }}
If you want to use MCP tools, you must output as the following format:
```
...
{"name": , "arguments": }
```
{% endif -%}
## Note
- Available Apps: `["Contacts", "Settings", "Clock", "Maps", "Chrome", "Calendar", "files", "Gallery", "Taodian", "Mattermost", "Mastodon", "Mail", "SMS", "Camera"]`.
- Write a small plan and finally summarize your next action (with its target element) in one sentence in part.
""".strip()
)
MAI_MOBILE_SYS_PROMPT_GROUNDING
MAI_MOBILE_SYS_PROMPT_GROUNDING = """
You are a GUI grounding agent.
## Task
Given a screenshot and the user's grounding instruction. Your task is to accurately locate a UI element based on the user's instructions.
First, you should carefully examine the screenshot and analyze the user's instructions, translate the user's instruction into a effective reasoning process, and then provide the final coordinate.
## Output Format
Return a json object with a reasoning process in tags, a [x,y] format coordinate within XML tags:
...
{"coordinate": [x,y]}
""".strip()
2.2 Мобильная система отображает разницу
только MAI_MOBILE_SYS_PROMPT_ASK_USER_MCP Шаблон поддерживает интеграцию инструмента MCP, включая динамическую вставку реализации условного синтаксиса Jinja2, другие подсказки и функцию CP.
| Запрос идентификатора | основные виды использования | думающий тег | Космическая операция | специальная функция |
|---|---|---|---|---|
| MAI_MOBILE_SYS_PROMPT | Стандартный прокси-сервер с графическим интерфейсом | “ должен | Нажмите/长按/ввод/скольжение и т. д. | 无 |
| MAI_MOBILE_SYS_PROMPT_NO_THINKING | быстрый ответ | нет тега мысли | 同上 | Перестаньте думать, верните JSON напрямую. |
| MAI_MOBILE_SYS_PROMPT_ASK_USER_MCP | шаблон+запрос пользователя | необязательный | 同上 | Ask_user、Double_click、Шаблон Jinja2、Набор инструментов MCP |
| MAI_MOBILE_SYS_PROMPT_GROUNDING | Специальное позиционирование | “ | Только элементы распознавания | выход [x,y] координаты, нет команды операции |
2.3 различных инструмента для сборки
Только функция MCP MAI_MOBILE_SYS_PROMPT_ASK_USER_MCP Слой шаблона интегрирован, остальная часть версии требует подключения внешнего моста.
вывод 0x03
3.1 разница в формате вывода
非 Версия MCP (MAI_MOBILE_SYS_PROMPT)
-
единый формат: Все операции пройдены
mobile_useфункция вызова -
фиксированная структура: Пакет операций с графическим интерфейсом
argumentsполе -
пример:
... {"name":"mobile_use","arguments": }
Версия MCP (MAI_MOBILE_SYS_PROMPT_ASK_USER_MCP)
-
двойной формат: Поддержка стандартного графического интерфейса и инструментов MCP.
-
формат, указанный инструментом:MCP 工作电影使用电视安全安全名可以
name -
пример:
... {"name": ,"arguments": }
Следующий код показывает выходные данные LLM, преобразованные в структурированный вывод.
def parse_action_to_structure_output(text: str) -> Dict[str, Any]:
"""
Parse model output text into structured action format.
Args:
text: Raw model output containing thinking and tool_call tags.
Returns:
Dictionary with keys:
- "thinking": The model's reasoning process
- "action_json": Parsed action with normalized coordinates
Note:
Coordinates are normalized to [0, 1] range by dividing by SCALE_FACTOR.
"""
text = text.strip()
results = parse_tagged_text(text)
thinking = results["thinking"]
tool_call = results["tool_call"]
action = tool_call["arguments"]
# Normalize coordinates from SCALE_FACTOR range to [0, 1]
if "coordinate" in action:
coordinates = action["coordinate"]
if len(coordinates) == 2:
point_x, point_y = coordinates
elif len(coordinates) == 4:
x1, y1, x2, y2 = coordinates
point_x = (x1 + x2) / 2
point_y = (y1 + y2) / 2
else:
raise ValueError(
f"Invalid coordinate format: expected 2 or 4 values, got {len(coordinates)}"
)
point_x = point_x / SCALE_FACTOR
point_y = point_y / SCALE_FACTOR
action["coordinate"] = [point_x, point_y]
return {
"thinking": thinking,
"action_json": action,
}
3.2 разница в функциональном объеме
Версия без MCP
- ограниченная операция: Только предопределенные операции графического интерфейса (нажатие, слайд, ввод и т. д.)
- Исключительно мобильное оборудование: 上注 интерактивный интерфейс с сенсорным экраном.
- фиксированное пространство действий: Невозможно расширить новый тип операции.
версия MCP
- Развернуть операцию: Работа с графическим интерфейсом пользователя, поддержка инструментов MCP.
- системная функция: вы можете выполнять сложную работу системы с помощью инструмента MCP.
- динамическая функция: В соответствии с диапазоном функций динамического расширения инструмента конфигурации.
3.3 Фактический сценарий применения
Стандартная операция с графическим интерфейсом
- MCP 版线中标准 GUI и функция mobile_use
- 与非 MCP 电影 поведение в основном такое же
Инструмент MCP называется
- 需方法 MCP 工作时,使用工作名称的实施定利名
- Может выполнять сложные задачи (конфигурация системы, обработка данных и т. д.)
Обработка в реализации кода
В классе MAIUIMobileAgent:
- 若 self.tools 非空, используйте шаблон MAI_MOBILE_SYS_PROMPT_ASK_USER_MCP;
- Путем рендеринга (tools=tools_str)
- Используйте MAI_MOBILE_SYS_PROMPT.
Коды следующие:
@property
def system_prompt(self) -> str:
"""
Generate the system prompt based on available MCP tools.
Returns:
System prompt string, with MCP tools section if tools are configured.
"""
if self.tools:
tools_str = "\n".join(
[json.dumps(tool, ensure_ascii=False) for tool in self.tools]
)
return MAI_MOBILE_SYS_PROMPT_ASK_USER_MCP.render(tools=tools_str)
return MAI_MOBILE_SYS_PROMPT
Версия MCP обеспечивает более гибкие возможности работы, позволяя интеллектуальному телу переключаться между стандартными операциями с графическим интерфейсом и инструментами MCP, тем самым выполняя более сложные задачи; Версия без MCP обеспечивает работу мобильного интерфейса.
0x04 MAIUINaivigationAgent
MAIUINaivigationAgent(电视端Навигатор с графическим интерфейсом) Это «базовый модуль» всего MAI-GUI — он инкапсулирует основные возможности инициализации LLM, управления контекстом интерфейса истории, построения мультимодальных сообщений и т. д., особенно для основных возможностей динамической интеграции, автоматического проектирования сцен, а также на основе инструкций по задачам и снимков экрана многошагового интерфейса истории он может создавать стандартизированную стандартизированную модель LLM, обеспечивая унифицированную основу ввода для действий последующего поколения.
4.1 Основные функции
Основная логика MAIUINaivigationAgent следующая: инициализация (конфигурация + LLM-клиент) → предварительная обработка изображения (история + текущий формат скриншота) → построение сообщения (按改法报报多模态内容)), весь процесс структурирован для обеспечения стандартизированного, структурированного ввода.
| Функции | конкретное объяснение |
|---|---|
| 推视在电影电影电影 | поддержка конфигурацииhistory_nПараметр (по умолчанию 3) автоматически принимает самый последний снимок экрана интерфейса N步 в качестве исторического контекста, сохраняя при этом ключевую дорожку операции и избегая контекста.history_n-1条在线截图 + текущий снимок экрана, точно контролировать длину контекста |
| Совместимость с несколькими форматами изображений. | _prepare_imagesМетод поддерживает поток байтов, изображение PIL и т. д. Несколько входных форматов изображений, автоматически преобразуемых в формат изображения RGB PIL, что решает проблему совместимости различных снимков экрана из разных источников, подходит для снимков экрана мобильных устройств в различных сценариях. |
| Возможность сборки инструмента MCP | При инициализации поддерживайте импорт списка инструментов MCP, для последующего LLM используйте инструмент MCP (如电影设计数用). Расширенный интерфейс предварительной версии, совместимый с экологией протокола MCP. |
| Стандартизированное построение сообщений | _build_messagesФиксированный логический метод построения «системные подсказки→команда пользователя→скриншот истории + ответ истории→текущий снимок экрана», строго соответствует мультимодальному формату ввода LLM, гарантируется различная длина истории, формат ввода длины, длина. |
| легко настраиваемый | Поддержка настраиваемой температуры, top_k, top_p и т. д. Параметры LLM, а также длина контекста истории (history_n) могут настраивать конфигурацию в соответствии с различными задачами мобильных конечных устройств. |
4.2 определение
Определение MAIUINaivigationAgent следующее:
class MAIUINaivigationAgent(BaseAgent):
"""
Mobile automation agent using vision-language models.
This agent processes screenshots and natural language instructions to
generate GUI actions for mobile device automation.
Attributes:
llm_base_url: Base URL for the LLM API endpoint.
model_name: Name of the model to use for predictions.
runtime_conf: Configuration dictionary for runtime parameters.
history_n: Number of history steps to include in context.
"""
def __init__(
self,
llm_base_url: str,
model_name: str,
runtime_conf: Optional[Dict[str, Any]] = None,
tools: Optional[List[Dict[str, Any]]] = None,
):
"""
Initialize the MAIMobileAgent.
Args:
llm_base_url: Base URL for the LLM API endpoint.
model_name: Name of the model to use.
runtime_conf: Optional configuration dictionary with keys:
- history_n: Number of history images to include (default: 3)
- max_pixels: Maximum pixels for image processing
- min_pixels: Minimum pixels for image processing
- temperature: Sampling temperature (default: 0.0)
- top_k: Top-k sampling parameter (default: -1)
- top_p: Top-p sampling parameter (default: 1.0)
- max_tokens: Maximum tokens in response (default: 2048)
tools: Optional list of MCP tool definitions. Each tool should be a dict
with 'name', 'description', and 'parameters' keys.
"""
super().__init__()
# Store MCP tools
self.tools = tools or []
# Set default configuration
default_conf = {
"history_n": 3,
"temperature": 0.0,
"top_k": -1,
"top_p": 1.0,
"max_tokens": 2048,
}
self.runtime_conf = {**default_conf, **(runtime_conf or {})}
self.llm_base_url = llm_base_url
self.model_name = model_name
self.llm = OpenAI(
base_url=self.llm_base_url,
api_key="empty",
)
# Extract frequently used config values
self.temperature = self.runtime_conf["temperature"]
self.top_k = self.runtime_conf["top_k"]
self.top_p = self.runtime_conf["top_p"]
self.max_tokens = self.runtime_conf["max_tokens"]
self.history_n = self.runtime_conf["history_n"]
4.3 Создайте образ
Функция _prepare_images используется для создания изображений.
def _prepare_images(self, screenshot_bytes: bytes) -> List[Image.Image]:
"""
Prepare image list including history and current screenshot.
Args:
screenshot_bytes: Current screenshot as bytes.
Returns:
List of PIL Images (history + current).
"""
# Calculate how many history images to include
if len(self.history_images) > 0:
max_history = min(len(self.history_images), self.history_n - 1)
recent_history = self.history_images[-max_history:] if max_history > 0 else []
else:
recent_history = []
# Add current image bytes
recent_history.append(screenshot_bytes)
# Normalize input type
if isinstance(recent_history, bytes):
recent_history = [recent_history]
elif isinstance(recent_history, np.ndarray):
recent_history = list(recent_history)
elif not isinstance(recent_history, list):
raise TypeError(f"Unidentified images type: {type(recent_history)}")
# Convert all images to PIL format
images = []
for image in recent_history:
if isinstance(image, bytes):
image = Image.open(BytesIO(image))
elif isinstance(image, Image.Image):
pass
else:
raise TypeError(f"Expected bytes or PIL Image, got {type(image)}")
if image.mode != "RGB":
image = image.convert("RGB")
images.append(image)
return images
4.4 Построение текста
def _build_messages(
self,
instruction: str,
images: List[Image.Image],
) -> List[Dict[str, Any]]:
"""
Build the message list for the LLM API call.
Args:
instruction: Task instruction from user.
images: List of prepared images.
Returns:
List of message dictionaries for the API.
"""
messages = [
{
"role": "system",
"content": [{"type": "text", "text": self.system_prompt}],
},
{
"role": "user",
"content": [{"type": "text", "text": instruction}],
},
]
image_num = 0
history_responses = self.history_responses
if len(history_responses) > 0:
for history_idx, history_response in enumerate(history_responses):
# Only include images for recent history (last history_n responses)
if history_idx + self.history_n >= len(history_responses):
# Add image before the assistant response
if image_num < len(images) - 1:
cur_image = images[image_num]
encoded_string = pil_to_base64(cur_image)
messages.append({
"role": "user",
"content": [{
"type": "image_url",
"image_url": {"url": f"data:image/png;base64,{encoded_string}"},
}],
})
image_num += 1
messages.append({
"role": "assistant",
"content": [{"type": "text", "text": history_response}],
})
# Add current image (last one in images list)
if image_num < len(images):
cur_image = images[image_num]
encoded_string = pil_to_base64(cur_image)
messages.append({
"role": "user",
"content": [{
"type": "image_url",
"image_url": {"url": f"data:image/png;base64,{encoded_string}"},
}],
})
else:
# No history, just add the current image
cur_image = images[0]
encoded_string = pil_to_base64(cur_image)
messages.append({
"role": "user",
"content": [{
"type": "image_url",
"image_url": {"url": f"data:image/png;base64,{encoded_string}"},
}],
})
return messages
4.5 процессы
Схема цикла MAIUINaivigationAgent выглядит следующим образом:

специальное действие:
- спросить_пользователя(вопрос) → пауза,把问题返还经电影(电视-云设计里电影电影)
- mcp_call(tool,args) → вызов внешних инструментов MCP
- завершение () задачи
Также смотрите ниже:
4.6.
основная функция
предсказывает интеллектуальный MAI-GUI电影电影与设计 генерировать модуль,是 «Мозг принятия решений» графического пользовательского интерфейса агента, основное решение «в соответствии с командой задачи и текущим состоянием интерфейса, генерирует проблему с текущим состоянием интерфейса, отличным от модуля позиционирования одного чистого элемента».
прогнозирует, что основная функция состоит в получении инструкций по задаче (如 «полный вход в приложение»), а текущая информационная карта наблюдения интерфейса становится дополнительным безбарьерным деревом), вызывая большую языковую модель для создания и анализа следующего шага для выполнения последовательности действий графического интерфейса (如 щелчок, слайд, ввод и т. д.), одновременно записывая полную траекторию задачи (траектория), в то же время записывая полную траекторию задачи (траектория), является основным звеном агента графического интерфейса «на основе решения о состоянии интерфейса». операция».
прогнозирование процесса потока: обработка ввода → построение сообщения → вызов LLM → ответный анализ → запись последовательности → вывод результатов, полный поток ненормальной обработки, гарантированное действие 戨作生戨作生戨作生果вывод, полный поток ненормальной обработки,
основные функции
| Функции | конкретное объяснение |
|---|---|
| Послужной список задач | встроенный traj_memory Модуль трековой памяти, на каждом этапе операции может сохраняться снимок экрана, модель ответа, действие после анализа, анализ процесса и т. д. полный объем информации, поддержка отслеживания задач, отладки и воспроизведения. |
| 多维度 вид ввода интерфейса | В то же время он получает снимки экрана (визуальную информацию) и беспрепятственное дерево (информацию о структуре пользовательского интерфейса) по сравнению с чистым визуальным вводом, более точное понимание структуры интерфейса, подходящее для сложных сцен графического интерфейса. |
| 鲁棒的 LLM 设计与解析 | ① Встроенный третий API 重试手机, захват и печать ненормальной информации стека, повышение стабильности вызова, ②стандартный ответ модели 解析 thinking+ action_json(设计化设计), обеспечить единый выходной формат |
| долгосрочная цель | При первом вызове команда задачи будет сохранена в дорожке памяти как долгосрочная цель, избегайте следующих шагов. |
| Удобный просмотр журнала | Для сообщений, содержащих изображенияmask_image_urls_for_logging), оба сохраняют журнал полным и избегают кодирования Base64, отладки. |
процесс
он предсказывает процесс следующим образом

时序图
Процедура: Пользователь ⇔ Агент ⇔ vLLM (навигация по сценарию) следующим образом:
要点:
- 每步都把去生 History_n张截图图像塞进messages(无服务端电影电视,vLLM是无电视牄;завершения чата;
- Ask_user/mcp_call может быть установлен в Tool_call, сам агент не имеет побочных эффектов,
- Путь ведения журнала в формате base64 или в формате Mask_image_urls_for_logging 下载的 [IMAGE_DATA]。

код
def predict(
self,
instruction: str,
obs: Dict[str, Any],
**kwargs: Any,
) -> Tuple[str, Dict[str, Any]]:
"""
Predict the next action based on the current observation.
Args:
instruction: Task instruction/goal.
obs: Current observation containing:
- screenshot: PIL Image or bytes of current screen
- accessibility_tree: Optional accessibility tree data
**kwargs: Additional arguments including:
- extra_info: Optional extra context string
Returns:
Tuple of (prediction_text, action_dict) where:
- prediction_text: Raw model response or error message
- action_dict: Parsed action dictionary
"""
# Set task goal if not already set
if not self.traj_memory.task_goal:
self.traj_memory.task_goal = instruction
# Process screenshot
screenshot_pil = obs["screenshot"]
screenshot_bytes = safe_pil_to_bytes(screenshot_pil)
# Prepare images
images = self._prepare_images(screenshot_bytes)
# Build messages
messages = self._build_messages(instruction, images)
# Make API call with retry logic
max_retries = 3
prediction = None
action_json = None
for attempt in range(max_retries):
try:
messages_print = mask_image_urls_for_logging(messages)
print(f"Messages (attempt {attempt + 1}):\n{messages_print}")
response = self.llm.chat.completions.create(
model=self.model_name,
messages=messages,
max_tokens=self.max_tokens,
temperature=self.temperature,
top_p=self.top_p,
frequency_penalty=0.0,
presence_penalty=0.0,
extra_body={"repetition_penalty": 1.0, "top_k": self.top_k},
seed=42,
)
prediction = response.choices[0].message.content.strip()
print(f"Raw response:\n{prediction}")
# Parse response
parsed_response = parse_action_to_structure_output(prediction)
thinking = parsed_response["thinking"]
action_json = parsed_response["action_json"]
print(f"Parsed response:\n{parsed_response}")
break
except Exception as e:
print(f"Error on attempt {attempt + 1}: {e}")
traceback.print_exc()
prediction = None
action_json = None
# Return error if all retries failed
if prediction is None or action_json is None:
print("Max retry attempts reached, returning error flag.")
return "llm client error", {"action": None}
# Create and store trajectory step
traj_step = TrajStep(
screenshot=screenshot_pil,
accessibility_tree=obs.get("accessibility_tree"),
prediction=prediction,
action=action_json,
conclusion="",
thought=thinking,
step_index=len(self.traj_memory.steps),
agent_type="MAIMobileAgent",
model_name=self.model_name,
screenshot_bytes=screenshot_bytes,
structured_action={"action_json": action_json},
)
self.traj_memory.steps.append(traj_step)
return prediction, action_json
4,7 треков
Структура данных TrajMemory/TrajStep

派生电影
派生电影(BaseAgent上海@property,избегайте внешних прямых ссылок)шаги) следующим образом:

путь последовательности
BaseAgent.save_traj() → {
"task_goal", "task_id",
"steps": [
{ screenshot_bytes, accessibility_tree, prediction,
action, conclusion, thought,
step_index, agent_type, model_name }, ...
]
}
△ 注意:save 时只输出 screenshot_bytes,丢弃 PIL.Image 对象
△ structured_action 字段不在 save_traj 输出里(只在内存中使用)
BaseAgent.load_traj(traj_memory) →直接覆盖self.traj_memory
(需要外部自行从dict重建TrajMemory)
要点:
- Снимок экрана(PIL)+screenshot_bytes(bytes)双份会存:电影走PIL、电影化/ 网络走 bytes,不要可电影一一一
- мышление
,действие ,是解析器parse_tagged_text和端落点; предсказание存接术未解析的电影,便于回放与отладка, 不要用解析后名生国际; - save_traj与TrajStep Поле не полностью идентично (structured_action не экспортируется), новое поле при двойной синхронизации не экспортируется
код
@dataclass
class TrajStep:
"""
Represents a single step in an agent's trajectory.
Attributes:
screenshot: PIL Image of the screen at this step.
accessibility_tree: Accessibility tree data for the screen.
prediction: Raw model prediction/response.
action: Parsed action dictionary.
conclusion: Conclusion or summary of the step.
thought: Model's reasoning/thinking process.
step_index: Index of this step in the trajectory.
agent_type: Type of agent that produced this step.
model_name: Name of the model used.
screenshot_bytes: Original screenshot as bytes (for compatibility).
structured_action: Structured action with metadata.
"""
screenshot: Image.Image
accessibility_tree: Optional[Dict[str, Any]]
prediction: str
action: Dict[str, Any]
conclusion: str
thought: str
step_index: int
agent_type: str
model_name: str
screenshot_bytes: Optional[bytes] = None
structured_action: Optional[Dict[str, Any]] = None
@dataclass
class TrajMemory:
"""
Container for a complete trajectory of agent steps.
Attributes:
task_goal: The goal/instruction for this trajectory.
task_id: Unique identifier for the task.
steps: List of trajectory steps.
"""
task_goal: str
task_id: str
steps: List[TrajStep] = field(default_factory=list)
0x05 MAIGroundingAgent
MAIGroundingAgent — этоНа основе визуально-языковой модели (VLM) и интеллекта позиционирования с графическим интерфейсом (агент заземления),Код представляет собой «модуль визуального позиционирования» графического пользовательского интерфейса агента, основное решение: «Проблема, которую необходимо решить», – графический интерфейс агента реализует интерфейс, понимающий основные ссылки.
Основная функция MAIGroundingAgent — получение команд на естественном языке (如 «нажмите кнопку входа») и скриншота интерфейса графического пользовательского интерфейса с использованием API большой языковой модели для анализа команды, идентификации целевого элемента пользовательского интерфейса и вывода стандартизированных координат элемента (归一化). [0,1] 电影), для GUI Agent 的 последующая операция (如щелчок、ввод) обеспечивает возможность точного позиционирования элемента 定彍能力 GUI Agent 昍能力 ——环述普”看懂设计” основной модуль。
Последовательность действий MAIGroundingAgent выглядит следующим образом: предварительная обработка входных данных → построение сообщения → вызов LLM → ответный анализ → вывод результатов, полный поток охватывает аномальную обработку, обеспечивает доступность.
5.1 Основные функции
| Функции | конкретное объяснение |
|---|---|
| Множественная обработка ввода | В то же время он получает команды на естественном языке (текст) и снимки экрана интерфейса (изображения), совместимые со сценариями интерактивного визуального графического интерфейса + двуязычного ввода. |
| Стандартизация логики | фиксированный вывод модели анализа (推理过程)和 (小是), обеспечивает унификацию выходной структуры; автоматическая координата 归一化(除以 SCALE_FACTOR), 歌錨 унификация; автоматическая координата 归一化(除以 SCALE_FACTOR), 歌錅率逍不不 |
| 鲁棒性 дизайн | ① Встроенный третий API 重语机场,可以网络 / 电视时间时间;② Совместим с изображения格容图片格容图片格容图像增在墨臺漏(臺漏(踴时时间; RGB), тип ввода (поддержка PIL-изображения/байтового изображения); ③ Завершить ненормальный захват, вернуться при неудача攇明硯流) |
| Можно настроить | Поддержка параметризации LLM (температура/top_k/top_p/max_tokens и т. д.) может быть основана на модели режима настройки сцены (генерация модели 生整). |
| чистый поток закрыт | От «обработки ввода → построения нескольких моделей сообщений → вызова LLM → анализа ответа → возврата стандартизированных результатов» для формирования полного цикла выходные данные также включают модель процесса и конечные координаты, удобные для отладки и отслеживания. |
5.2 определение
MAIGroundingAgent следующим образом.
class MAIGroundingAgent:
"""
GUI grounding agent using vision-language models.
This agent processes a screenshot and natural language instruction to
locate a specific UI element and return its coordinates.
Attributes:
llm_base_url: Base URL for the LLM API endpoint.
model_name: Name of the model to use for predictions.
runtime_conf: Configuration dictionary for runtime parameters.
"""
def __init__(
self,
llm_base_url: str,
model_name: str,
runtime_conf: Optional[Dict[str, Any]] = None,
):
"""
Initialize the MAIGroundingAgent.
Args:
llm_base_url: Base URL for the LLM API endpoint.
model_name: Name of the model to use.
runtime_conf: Optional configuration dictionary with keys:
- max_pixels: Maximum pixels for image processing
- min_pixels: Minimum pixels for image processing
- temperature: Sampling temperature (default: 0.0)
- top_k: Top-k sampling parameter (default: -1)
- top_p: Top-p sampling parameter (default: 1.0)
- max_tokens: Maximum tokens in response (default: 2048)
"""
# Set default configuration
default_conf = {
"temperature": 0.0,
"top_k": -1,
"top_p": 1.0,
"max_tokens": 2048,
}
self.runtime_conf = {**default_conf, **(runtime_conf or {})}
self.llm_base_url = llm_base_url
self.model_name = model_name
self.llm = OpenAI(
base_url=self.llm_base_url,
api_key="empty",
)
# Extract frequently used config values
self.temperature = self.runtime_conf["temperature"]
self.top_k = self.runtime_conf["top_k"]
self.top_p = self.runtime_conf["top_p"]
self.max_tokens = self.runtime_conf["max_tokens"]
5.3 поток данных
Заземляющий агент 单步 设计图图新:

Вы также можете увидеть следующее:

5.4.
@property
def system_prompt(self) -> str:
"""Return the system prompt for grounding tasks."""
return MAI_MOBILE_SYS_PROMPT_GROUNDING
def _build_messages(
self,
instruction: str,
image: Image.Image,
) -> list:
"""
Build the message list for the LLM API call.
Args:
instruction: Grounding instruction from user.
image: PIL Image of the screenshot.
magic_prompt: Whether to use the magic prompt format.
Returns:
List of message dictionaries for the API.
"""
encoded_string = pil_to_base64(image)
messages = [
{
"role": "system",
"content": [
{
"type": "text",
"text": self.system_prompt,
}
],
}
]
messages.append(
{
"role": "user",
"content": [
{
"type": "text",
"text": instruction + "\n",
},
{
"type": "image_url",
"image_url": {
"url": f"data:image/png;base64,{encoded_string}"
},
},
],
}
)
return messages
def predict(
self,
instruction: str,
image: Union[Image.Image, bytes],
**kwargs: Any,
) -> Tuple[str, Dict[str, Any]]:
"""
Predict the coordinate of the UI element based on the instruction.
Args:
instruction: Grounding instruction describing the UI element to locate.
image: PIL Image or bytes of the screenshot.
**kwargs: Additional arguments (unused).
Returns:
Tuple of (prediction_text, result_dict) where:
- prediction_text: Raw model response or error message
- result_dict: Dictionary containing:
- "thinking": Model's reasoning process
- "coordinate": Normalized [x, y] coordinate
"""
# Convert bytes to PIL Image if necessary
if isinstance(image, bytes):
image = Image.open(BytesIO(image))
if image.mode != "RGB":
image = image.convert("RGB")
# Build messages
messages = self._build_messages(instruction, image)
# Make API call with retry logic
max_retries = 3
prediction = None
result = None
for attempt in range(max_retries):
try:
response = self.llm.chat.completions.create(
model=self.model_name,
messages=messages,
max_tokens=self.max_tokens,
temperature=self.temperature,
top_p=self.top_p,
frequency_penalty=0.0,
presence_penalty=0.0,
extra_body={"repetition_penalty": 1.0, "top_k": self.top_k},
seed=42,
)
prediction = response.choices[0].message.content.strip()
print(f"Raw response:\n{prediction}")
# Parse response
result = parse_grounding_response(prediction)
print(f"Parsed result:\n{result}")
break
except Exception as e:
print(f"Error on attempt {attempt + 1}: {e}")
prediction = None
result = None
# Return error if all retries failed
if prediction is None or result is None:
print("Max retry attempts reached, returning error flag.")
return "llm client error", {"thinking": None, "coordinate": None}
return prediction, result
5.5 анализ
def parse_grounding_response(text: str) -> Dict[str, Any]:
"""
Parse model output text containing grounding_think and answer tags.
Args:
text: Raw model output containing and tags.
Returns:
Dictionary with keys:
- "thinking": The model's reasoning process
- "coordinate": Normalized [x, y] coordinate
Raises:
ValueError: If parsing fails or JSON is invalid.
"""
text = text.strip()
result: Dict[str, Any] = {
"thinking": None,
"coordinate": None,
}
# Extract thinking content
think_pattern = r"(.*?) "
think_match = re.search(think_pattern, text, re.DOTALL)
if think_match:
result["thinking"] = think_match.group(1).strip()
# Extract answer content
answer_pattern = r"(.*?) "
answer_match = re.search(answer_pattern, text, re.DOTALL)
if answer_match:
answer_text = answer_match.group(1).strip()
try:
answer_json = json.loads(answer_text)
coordinates = answer_json.get("coordinate", [])
if len(coordinates) == 2:
# Normalize coordinates from SCALE_FACTOR range to [0, 1]
point_x = coordinates[0] / SCALE_FACTOR
point_y = coordinates[1] / SCALE_FACTOR
result["coordinate"] = [point_x, point_y]
else:
raise ValueError(
f"Invalid coordinate format: expected 2 values, got {len(coordinates)}"
)
except json.JSONDecodeError as e:
raise ValueError(f"Invalid JSON in answer: {e}")
return result
0xEE реклама
Продолжить рекламу второй книги.

ссылка 0xFF
从豆包手机谈起:端上电影的明景与进行起
阿里发布MAI-UI,一个“活”在在能电影全能AI动动!美国真能全电视了?