代理处理器

Processor 是代理的关键组件,用于处理代理的核心逻辑以处理用户的请求。Processor 作为类实现在 ufo/agents/processors 文件夹中。每个代理在文件夹中都有自己的 Processor 类。

核心流程

一旦被调用,代理通过调用 process 方法,遵循 Processor 类中定义的一系列步骤来处理用户的请求。process 的工作流程如下:

步骤 描述 功能
1 打印步骤信息。 print_step_info
2 捕获应用程序的屏幕截图。 capture_screenshot
3 获取应用程序的控件信息。 get_control_info
4 获取 LLM 的提示消息。 get_prompt_message
5 从 LLM 生成响应。 get_response
6 更新步骤成本。 update_cost
7 解析 LLM 的响应。 parse_response
8 根据响应执行操作。 execute_action
9 更新内存和黑板。 update_memory
10 更新代理的状态。 update_status

在每个步骤中,Processor 通过按顺序调用相应的方法来执行必要的操作,从而处理用户的请求。

该过程可能会暂停。根据代理的逻辑和用户的请求,可以使用 resume 方法恢复该过程。

参考

下面是 Processor 类的基本结构

基类:ABC

会话的基础处理器。一个会话由多轮与用户的对话组成,以完成一个任务。在每一轮中,HostAgent 和 AppAgent 与用户和应用程序通过处理器进行交互。每个处理器负责处理用户请求,并在一个回合的一个步骤中更新 HostAgent 和 AppAgent。

初始化处理器。

参数
  • context (Context) –

    会话的上下文。

  • agent (BasicAgent) –

    执行处理器的代理。

源代码位于 agents/processors/basic.py
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
def __init__(self, agent: BasicAgent, context: Context) -> None:
    """
    Initialize the processor.
    :param context: The context of the session.
    :param agent: The agent who executes the processor.
    """

    self._context = context
    self._agent = agent

    self.photographer = PhotographerFacade()
    self.control_inspector = ControlInspectorFacade(BACKEND)

    self._prompt_message = None
    self._status = None
    self._response = None
    self._cost = 0
    self._control_label = None
    self._control_text = None
    self._response_json = {}
    self._memory_data = MemoryItem()
    self._question_list = []
    self._agent_status_manager = self.agent.status_manager
    self._is_resumed = False
    self._plan = None

    self._total_time_cost = 0
    self._time_cost = {}
    self._exeception_traceback = {}
    self._actions = ActionSequence()

actions 属性 可写

获取动作。

返回
  • ActionSequence

    动作。

agent 属性

获取代理。

返回
  • BasicAgent

    代理。

app_root 属性 可写

获取应用程序根目录。

返回
  • 字符串

    应用程序根目录。

application_process_name 属性 可写

获取应用程序进程名称。

返回
  • 字符串

    应用程序进程名称。

application_window property writable

获取活动窗口。

返回
  • UIAWrapper

    活动窗口。

context property

获取上下文。

返回
  • Context

    上下文。

control_label 属性 可写

获取控件标签。

返回
  • 字符串

    控件标签。

control_reannotate 属性 可写

获取控件重新标注。

返回
  • List[str]

    控件重新标注。

control_text 属性 可写

获取活动应用程序。

返回
  • 字符串

    活动应用程序。

cost 属性 可写

获取处理器的成本。

返回
  • float

    处理器的成本。

host_message 属性 可写

获取主机消息。

返回
  • List[str]

    主机消息。

log_path 属性

获取日志路径。

返回
  • 字符串

    日志路径。

logger 属性

获取日志记录器。

返回
  • 字符串

    日志记录器。

name 属性

获取处理器的名称。

返回
  • 字符串

    处理器的名称。

plan 属性 可写

获取代理的计划。

返回
  • 字符串

    计划。

prev_plan 属性

获取上一个计划。

返回
  • List[str]

    代理的上一个计划。

previous_subtasks 属性 可写

获取上一个子任务。

返回
  • List[str]

    上一个子任务。

question_list 属性 可写

获取问题列表。

返回
  • List[str]

    问题列表。

request 属性

获取请求。

返回
  • 字符串

    请求。

request_logger 属性

获取请求日志记录器。

返回
  • 字符串

    请求日志记录器。

round_cost 属性 可写

获取回合成本。

返回
  • float

    回合成本。

round_num 属性

获取回合数。

返回
  • int

    回合数。

round_step 属性 可写

获取回合步骤。

返回
  • int

    回合步骤。

round_subtask_amount 属性

获取回合子任务数量。

返回
  • int

    回合子任务数量。

session_cost 属性 可写

获取会话成本。

返回
  • float

    会话成本。

session_step 属性 可写

获取会话步骤。

返回
  • int

    会话步骤。

status 属性 可写

获取处理器的状态。

返回
  • 字符串

    处理器的状态。

subtask 属性 可写

获取子任务。

返回
  • 字符串

    子任务。

ui_tree_path 属性

获取 UI 树路径。

返回
  • 字符串

    UI 树路径。

add_to_memory(data_dict)

将数据添加到内存。

参数
  • data_dict (Dict[str, Any]) –

    要添加到内存的数据字典。

源代码位于 agents/processors/basic.py
293
294
295
296
297
298
def add_to_memory(self, data_dict: Dict[str, Any]) -> None:
    """
    Add the data to the memory.
    :param data_dict: The data dictionary to be added to the memory.
    """
    self._memory_data.add_values_from_dict(data_dict)

capture_screenshot() 抽象方法

捕获屏幕截图。

源代码位于 agents/processors/basic.py
231
232
233
234
235
236
@abstractmethod
def capture_screenshot(self) -> None:
    """
    Capture the screenshot.
    """
    pass

exception_capture(func) 类方法

用于捕获方法异常的装饰器。

参数
  • func

    要装饰的方法。

返回
  • 装饰后的方法。

源代码位于 agents/processors/basic.py
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
@classmethod
def exception_capture(cls, func):
    """
    Decorator to capture the exception of the method.
    :param func: The method to be decorated.
    :return: The decorated method.
    """

    @wraps(func)
    def wrapper(self, *args, **kwargs):
        try:
            func(self, *args, **kwargs)
        except Exception as e:
            self._exeception_traceback[func.__name__] = {
                "type": str(type(e).__name__),
                "message": str(e),
                "traceback": traceback.format_exc(),
            }

            utils.print_with_color(f"Error Occurs at {func.__name__}", "red")
            utils.print_with_color(
                self._exeception_traceback[func.__name__]["traceback"], "red"
            )
            if self._response is not None:
                utils.print_with_color("Response: ", "red")
                utils.print_with_color(self._response, "red")
            self._status = self._agent_status_manager.ERROR.value
            self.sync_memory()
            self.add_to_memory({"error": self._exeception_traceback})
            self.add_to_memory({"Status": self._status})
            self.log_save()

            raise StopIteration("Error occurred during step.")

    return wrapper

execute_action() 抽象方法

执行动作。

源代码位于 agents/processors/basic.py
266
267
268
269
270
271
@abstractmethod
def execute_action(self) -> None:
    """
    Execute the action.
    """
    pass

get_control_info() 抽象方法

获取控件信息。

源代码位于 agents/processors/basic.py
238
239
240
241
242
243
@abstractmethod
def get_control_info(self) -> None:
    """
    Get the control information.
    """
    pass

get_prompt_message() 抽象方法

获取提示消息。

源代码位于 agents/processors/basic.py
245
246
247
248
249
250
@abstractmethod
def get_prompt_message(self) -> None:
    """
    Get the prompt message.
    """
    pass

get_response() 抽象方法

从 LLM 获取响应。

源代码位于 agents/processors/basic.py
252
253
254
255
256
257
@abstractmethod
def get_response(self) -> None:
    """
    Get the response from the LLM.
    """
    pass

is_application_closed()

检查应用程序是否已关闭。

返回
  • 布尔值

    表示应用程序是否已关闭的布尔值。

源代码位于 agents/processors/basic.py
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
def is_application_closed(self) -> bool:
    """
    Check if the application is closed.
    :return: The boolean value indicating if the application is closed.
    """

    if self.application_window is None:

        return True

    try:
        self.application_window.is_enabled()
        return False
    except:
        return True

is_confirm()

检查进程是否确认。

返回
  • 布尔值

    表示进程是否确认的布尔值。

源代码位于 agents/processors/basic.py
732
733
734
735
736
737
738
739
740
def is_confirm(self) -> bool:
    """
    Check if the process is confirm.
    :return: The boolean value indicating if the process is confirm.
    """

    self.agent.status = self.status

    return self.status == self._agent_status_manager.CONFIRM.value

is_error()

检查进程是否处于错误状态。

返回
  • 布尔值

    表示进程是否处于错误状态的布尔值。

源代码位于 agents/processors/basic.py
700
701
702
703
704
705
706
707
def is_error(self) -> bool:
    """
    Check if the process is in error.
    :return: The boolean value indicating if the process is in error.
    """

    self.agent.status = self.status
    return self.status == self._agent_status_manager.ERROR.value

is_paused()

检查进程是否已暂停。

返回
  • 布尔值

    表示进程是否已暂停的布尔值。

源代码位于 agents/processors/basic.py
709
710
711
712
713
714
715
716
717
718
719
720
def is_paused(self) -> bool:
    """
    Check if the process is paused.
    :return: The boolean value indicating if the process is paused.
    """

    self.agent.status = self.status

    return (
        self.status == self._agent_status_manager.PENDING.value
        or self.status == self._agent_status_manager.CONFIRM.value
    )

is_pending()

检查进程是否正在等待。

返回
  • 布尔值

    表示进程是否正在等待的布尔值。

源代码位于 agents/processors/basic.py
722
723
724
725
726
727
728
729
730
def is_pending(self) -> bool:
    """
    Check if the process is pending.
    :return: The boolean value indicating if the process is pending.
    """

    self.agent.status = self.status

    return self.status == self._agent_status_manager.PENDING.value

log(response_json)

设置会话结果并记录结果。result:会话结果。response_json:响应 JSON。返回:响应 JSON。

源代码位于 agents/processors/basic.py
758
759
760
761
762
763
764
765
766
def log(self, response_json: Dict[str, Any]) -> None:
    """
    Set the result of the session, and log the result.
    result: The result of the session.
    response_json: The response json.
    return: The response json.
    """

    self.logger.info(json.dumps(response_json))

log_save()

保存日志。

源代码位于 agents/processors/basic.py
300
301
302
303
304
305
306
307
308
def log_save(self) -> None:
    """
    Save the log.
    """

    self._memory_data.add_values_from_dict(
        {"total_time_cost": self._total_time_cost}
    )
    self.log(self._memory_data.to_dict())

method_timer(func) 类方法

用于计算方法时间成本的装饰器。

参数
  • func

    要装饰的方法。

返回
  • 装饰后的方法。

源代码位于 agents/processors/basic.py
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
@classmethod
def method_timer(cls, func):
    """
    Decorator to calculate the time cost of the method.
    :param func: The method to be decorated.
    :return: The decorated method.
    """

    @wraps(func)
    def wrapper(self, *args, **kwargs):
        start_time = time.time()
        result = func(self, *args, **kwargs)
        end_time = time.time()
        self._time_cost[func.__name__] = end_time - start_time
        return result

    return wrapper

parse_response() 抽象方法

解析响应。

源代码位于 agents/processors/basic.py
259
260
261
262
263
264
@abstractmethod
def parse_response(self) -> None:
    """
    Parse the response.
    """
    pass

print_step_info() 抽象方法

打印步骤信息。

源代码位于 agents/processors/basic.py
224
225
226
227
228
229
@abstractmethod
def print_step_info(self) -> None:
    """
    Print the step information.
    """
    pass

process()

处理一轮中的单个步骤。该过程包括以下步骤:1. 打印步骤信息。2. 捕获屏幕截图。3. 获取控件信息。4. 获取提示消息。5. 获取响应。6. 更新成本。7. 解析响应。8. 执行操作。9. 更新内存。10. 更新步骤和状态。11. 保存日志。

源代码位于 agents/processors/basic.py
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
def process(self) -> None:
    """
    Process a single step in a round.
    The process includes the following steps:
    1. Print the step information.
    2. Capture the screenshot.
    3. Get the control information.
    4. Get the prompt message.
    5. Get the response.
    6. Update the cost.
    7. Parse the response.
    8. Execute the action.
    9. Update the memory.
    10. Update the step and status.
    11. Save the log.
    """

    start_time = time.time()

    try:
        # Step 1: Print the step information.
        self.print_step_info()

        # Step 2: Capture the screenshot.
        self.capture_screenshot()

        # Step 3: Get the control information.
        self.get_control_info()

        # Step 4: Get the prompt message.
        self.get_prompt_message()

        # Step 5: Get the response.
        self.get_response()

        # Step 6: Update the context.
        self.update_cost()

        # Step 7: Parse the response, if there is no error.
        self.parse_response()

        if self.is_pending() or self.is_paused():
            # If the session is pending, update the step and memory, and return.
            if self.is_pending():
                self.update_status()
                self.update_memory()

            return

        # Step 8: Execute the action.
        self.execute_action()

        # Step 9: Update the memory.
        self.update_memory()

        # Step 10: Update the status.
        self.update_status()

        self._total_time_cost = time.time() - start_time

        # Step 11: Save the log.
        self.log_save()

    except StopIteration:
        # Error was handled and logged in the exception capture decorator.
        # Simply return here to stop the process early.

        return

resume()

在会话暂停后恢复操作执行过程。

源代码位于 agents/processors/basic.py
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
def resume(self) -> None:
    """
    Resume the process of action execution after the session is paused.
    """

    self._is_resumed = True

    try:
        # Step 1: Execute the action.
        self.execute_action()

        # Step 2: Update the memory.
        self.update_memory()

        # Step 3: Update the status.
        self.update_status()

    except StopIteration:
        # Error was handled and logged in the exception capture decorator.
        # Simply return here to stop the process early.
        pass

    finally:
        self._is_resumed = False

string2list(string) 静态方法

如果输入是字符串,则将字符串转换为字符串列表。

参数
  • string (Any) –

    字符串。

返回
  • List[str]

    列表。

源代码位于 agents/processors/basic.py
776
777
778
779
780
781
782
783
784
785
786
@staticmethod
def string2list(string: Any) -> List[str]:
    """
    Convert a string to a list of string if the input is a string.
    :param string: The string.
    :return: The list.
    """
    if isinstance(string, str):
        return [string]
    else:
        return string

sync_memory() 抽象方法

同步代理的内存。

源代码位于 agents/processors/basic.py
217
218
219
220
221
222
@abstractmethod
def sync_memory(self) -> None:
    """
    Sync the memory of the Agent.
    """
    pass

update_cost()

更新成本。

源代码位于 agents/processors/basic.py
318
319
320
321
322
323
324
def update_cost(self) -> None:
    """
    Update the cost.
    """

    self.round_cost += self.cost
    self.session_cost += self.cost

update_memory() 抽象方法

更新代理的内存。

源代码位于 agents/processors/basic.py
273
274
275
276
277
278
@abstractmethod
def update_memory(self) -> None:
    """
    Update the memory of the Agent.
    """
    pass

update_status()

更新会话状态。

源代码位于 agents/processors/basic.py
280
281
282
283
284
285
286
287
288
289
290
291
def update_status(self) -> None:
    """
    Update the status of the session.
    """
    self.agent.step += 1
    self.agent.status = self.status

    if self.status != self._agent_status_manager.FINISH.value:
        time.sleep(configs["SLEEP_TIME"])

    self.round_step += 1
    self.session_step += 1