当前位置: 首页 > article >正文

拆解 OpenHands(8)--- CodeActAgent

在 OpenHands 智能框架的生态中CodeActAgent 占据着核心地位它是基于 CodeAct 理念构建的核心代理模块。其设计初衷极具巧思将各类复杂任务统一转化为 “代码执行” 的形式来完成同时兼顾自然语言对话的交互特性。这一设计既保障了任务执行的精准性与高效性又为人类与智能代理的协作提供了灵活空间使其成为框架中处理自动化编程、数据处理等复杂场景的核心载体。因为本系列借鉴的文章过多可能在参考文献中有遗漏的文章如果有还请大家指出。0x01 背景1.1 Agent的核心能力根据Google电子书的定义一个真正的 AI 智能体拥有四项核心能力做出动态决策 (Make dynamic decisions)它们不是遵循预定的路径而是根据所学到的东西决定下一步做什么。跨交互保持状态 (Maintain state across multiple interactions)它们能记住自己做过什么并利用这些历史来为未来的决策提供信息。自适应地使用工具 (Use tools adaptively)它们可以从可用工具中进行选择并以非预先编程的方式组合它们。根据结果修正方法 (Modify their approach based on results)当一种策略不起作用时它们可以尝试不同的方法。1.2 Agent设计原则如何设计Agent不同人有不同的理解这可能是一个哲学问题。我们使用 https://github.com/humanlayer/12-factor-agents 来切入具体如下原则一组织规划、工具调用复杂Agent的工作范式原则二工具执行器Agent“思考”和“行动”分离解耦、独立进化原则三通过工具调用来联系人类Agent中的“人机协同”原则四提示词可调试、可迭代、可回滚、面向场景设计、A/B测试原则五建设上下文评估与仲裁突破上下文有限束缚提升“生成质量”原则六将错误压缩到上下文窗口让Agent从错误中学习并尝试自我纠正原则七统一执行状态和业务状态为Agent赋予了“自主恢复”的能力原则八使用简单的API来完成启动、暂停和恢复实现“任务全生命周期”管理原则九有限状态机拥有Agent的自主控制流原则十多个小而专注的Agent共同组成“智能组织”原则十一从任何地方触发Agent构建“无处不在的智能生产力”原则十二将Agent看做是一个“无状态的归约器”论文 From Storage to Experience: A Survey on the Evolution of LLM Agent Memory Mechanisms 也给出了Agent的设计原则设计原则1Memory as Experience, Not Storage错误方向追求更大的存储容量、更快的检索速度正确方向追求更深的经验抽象、更强的模式迁移设计原则2Proactive over Reactive错误方向优化响应速度和准确度正确方向增强主动探索和自我完善能力设计原则3Cross-trajectory Learning错误方向单任务优化、垂直领域深耕正确方向跨任务抽象、通用能力泛化设计原则4Continual Learning without Catastrophic Forgetting错误方向定期重训、版本迭代正确方向增量更新、经验积累1.3 Agent in OpenHands智能体抽象将配置与执行状态分离智能体被定义为无状态、不可变的规格对象包含 LLM 设置、工具规格、安全策略与智能体核心逻辑可序列化并跨进程传输。1.3.1. 事件驱动执行智能体通过事件驱动循环逐步处理对话状态不直接返回结果而是通过回调函数 on_event (event: Event) - None 输出结构化事件如消息、动作、观察结果实现事件生成与执行控制的分离。该设计支持安全介入 —— 基于风险分析在执行前审核或拦截动作增量执行 —— 智能体分步推进任务支持暂停 / 恢复、上下文溢出恢复与长对话压缩事件流传输 —— 实时输出中间结果如观察数据、推理轨迹用于界面更新与监控。1.3.2. 基于技能与提示的智能体上下文定制AgentContext 集中管理所有影响 LLM 行为的输入包括系统 / 用户消息的前缀 / 后缀、用户定义的 Skill技能对象。技能可通过编程方式定义或从 Markdown 文件如 .openhands/skills/及 .cursorrules、agents.md 等兼容格式加载永久激活技能triggerNone持续增强系统提示条件激活技能基于用户输入的关键词匹配触发可包含 MCP 工具。该设计支持丰富的上下文与行为定制无需修改智能体核心逻辑。1.3.3. 子智能体委托机制SDK 通过委托工具实现分层智能体协作充分体现了工具抽象的可扩展性。子智能体作为独立对话存在继承父智能体的模型配置与工作空间上下文无需修改核心 SDK 即可实现结构化并行处理与隔离。当前实现提供阻塞式并行执行能力作为 openhands.tools 包中的标准工具 —— 父智能体创建并监控子智能体直至所有任务完成。这一模式证明异步委托、动态调度、容错恢复等复杂协作行为均可通过用户自定义工具实现无需修改核心框架彰显了 SDK “高级智能体编排无需改动核心” 的可扩展设计原则。1.4 CodeAct1.4.1 理念CodeAct 理念的核心突破在于将智能代理的动作空间提升至通用编程的高度 —— 通过让大语言模型LLM直接生成可执行代码打破了传统工具调用的局限。以往的智能代理往往受困于固定的工具接口只能机械地调用预设功能而 CodeAct 赋予代理一个统一的 “可编程” 动作接口就像为工匠配备了一套可灵活组合的精密工具为解决复杂任务开辟了全新路径。这一理念的本质是深度挖掘 LLM 擅长编写代码的原生能力。它让代理的 “动作” 不再局限于单一的原子 API 调用而是通过生成一段完整的 Python 代码交由 Python 解释器执行来完成复杂任务。如此一来代理能在单个动作中封装完整的逻辑流程包括调用多个函数或工具、控制执行顺序、处理中间结果并存储极大地提升了任务处理的连贯性与自主性。1.4.2 模式CodeAct Agent 是一个极简主义的智能体以 ReAct的模式根据已有的若干 Action-Observation 对的轨迹决定下一步需要采取什么 Action。在每一轮的交互循环中CodeActAgent 具备两种核心操作模式二者相辅相成共同支撑任务推进对话模式Converse以自然语言为沟通桥梁实现与人类的高效协作。例如当任务需求模糊时代理会主动请求用户澄清细节在执行关键操作前也会向用户确认以规避风险充分体现了人机协作的灵活性。代码行动模式CodeAct依托一组标准化工具展开具体操作覆盖多类任务场景调用execute_bash函数执行 Linux 系统的 bash 命令实现系统级操作通过execute_ipython_cell在 IPython 环境中运行 Python 代码处理数据计算、逻辑执行等核心任务借助browser与fetch工具与网页浏览器交互完成信息爬取、页面操作等需求利用str_replace_editor或edit_file工具编辑文件内容实现文档修改、代码编写等功能。这种 “对话 代码” 的双轨模式不仅简化了智能代理的操作体系更在实际应用中显著提升了任务处理性能。实际上 OpenDevin 中 CodeAct Agent 的实现与原始 CodeAct 并不完全一样前者在原始 CodeAct 的基础上进行改进并很大程度上借鉴了 SWE-Agent.1.4.3 特色CodeActAgent 的特色如下行动空间统一化打破传统代理多行动类型的碎片化设计将所有任务文件操作、数据处理、系统交互等统一为 “代码执行” 行动简化架构且提升执行效率。双模式交互能力支持 “自然语言对话” 与 “代码行动” 双模式既可以通过自然语言与人类协作如请求澄清也能通过代码自主完成复杂任务适配多样场景。插件化沙盒依赖通过sandbox_plugins定义沙盒环境所需插件按顺序初始化确保依赖正确性同时支持灵活扩展技能如通过AgentSkillsRequirement新增工具函数。完善的记忆与上下文管理集成ConversationMemory管理 “行动 - 观察” 历史搭配Condenser压缩长上下文平衡上下文相关性与模型输入长度限制。灵活的模型路由支持通过LLMRegistry.get_router获取路由 LLM可根据任务复杂度动态选择适配模型兼顾性能与成本。极简主义设计核心逻辑聚焦 “代码执行” 单一行动空间架构简洁易懂同时保持高扩展性便于后续功能迭代与定制化开发。0x02 定义CodeActAgent的定义如下。class CodeActAgent(Agent): CodeActAgent极简主义的智能代理基于 CodeAct 理念实现。 核心逻辑将模型的行动统一到“代码执行”这一单一行动空间通过传递“行动-观察”对列表 引导模型决策下一步操作兼顾简洁性与执行性能。 核心理念源自论文https://arxiv.org/abs/2402.01030 打破传统代理多行动类型的复杂设计用代码执行统一所有行动既简化架构又提升效率。 VERSION 2.2 # 代理版本号 # 沙盒环境所需插件依赖按初始化顺序排列 sandbox_plugins: list[PluginRequirement] [ # 注意AgentSkillsRequirement 需在 JupyterRequirement 之前初始化 # 原因AgentSkillsRequirement 提供大量 Python 工具函数 # Jupyter 环境需要依赖这些函数才能正常工作 AgentSkillsRequirement(), # 提供代理核心技能函数的插件 JupyterRequirement(), # 提供交互式 Python 执行环境的插件 ] def __init__(self, config: AgentConfig, llm_registry: LLMRegistry) - None: 初始化 CodeActAgent 实例。 参数 config (AgentConfig)当前代理的配置对象包含模型路由、记忆策略等 llm_registry (LLMRegistry)LLM 注册表实例用于获取所需 LLM 或路由 LLM # 调用父类 Agent 的初始化方法完成基础配置如 LLM 注册、提示词管理器初始化 super().__init__(config, llm_registry) self.pending_actions: deque[Action] deque() # 待执行的行动队列双端队列支持高效进出 self.reset() # 重置代理状态初始化行动历史、观察记录等 self.tools self._get_tools() # 获取代理可使用的工具集从插件或配置中提取 # 初始化对话记忆实例存储“行动-观察”对支持记忆压缩、上下文管理 self.conversation_memory ConversationMemory(self.config, self.prompt_manager) # 初始化上下文压缩器根据配置创建 Condenser 实例用于压缩长对话历史 self.condenser Condenser.from_config(self.config.condenser, llm_registry) # 覆盖父类的 LLM 实例如需模型路由优先使用路由 LLM根据代理配置动态选择模型 self.llm self.llm_registry.get_router(self.config)2.1 可配置性CodeActAgent 通过 AgentConfig可以灵活启用 / 禁用各种功能可配置的功能如下config.enable_cmd # 启用命令执行 config.enable_think # 启用思考功能 config.enable_finish # 启用完成功能 config.enable_browsing # 启用浏览器功能 config.enable_jupyter # 启用 Jupyter config.enable_editor # 启用文件编辑器2.2 插件系统CodeActAgent 通过sandbox_plugins定义沙盒环境所需插件按顺序初始化确保依赖正确性同时支持灵活扩展技能如通过AgentSkillsRequirement新增工具函数。sandbox_plugins: list[PluginRequirement] [ # NOTE: AgentSkillsRequirement need to go before JupyterRequirement, since # AgentSkillsRequirement provides a lot of Python functions, # and it needs to be initialized before Jupyter for Jupyter to use those functions. AgentSkillsRequirement(), # 提供Python函数 JupyterRequirement(), # 提供Jupyter支持 ]2.3 工具系统Tools工具是智能代理拓展能力边界的关键正是工具的存在让 LLM 从单纯的对话机器人ChatBot进化为具备实际执行能力的智能代理Agent。CodeAct 的方案却反其道而行之以极致简洁的思路重构了工具调用逻辑 —— 它将 Python 作为唯一的工具让 LLM 通过自主编写代码的方式实现各类功能调用摒弃了传统多工具集成的复杂设计。传统工具调用模式中开发者需要在系统提示词system prompt中明确告知 LLM 可用的工具接口Available APIsLLM 再通过生成工具名和参数列表的方式调用工具无论输出格式是文本还是 JSON本质上都受限于预设范围。而 CodeAct 省去了这一繁琐的预定义步骤将 Python 作为统一接口LLM 在每一轮交互中直接生成代码并交由解释器执行。这种设计让动作空间更标准化工具调用过程简洁优雅充分释放了 LLM 的原生潜力。2.3.1 工具集CodeActAgent 则有所不同。CodeActAgent是一个混合型代理它既允许模型执行任意代码也提供了一些特定工具供模型使用。具体来说允许模型执行任意代码。CodeActAgent的核心理念是让模型能够执行任意代码通过create_cmd_run_tool工具模型可以执行任何有效的Linux bash命令通过IPythonTool工具模型可以执行任何有效的Python代码这符合CodeAct论文中提出的统一代码操作空间的概念旨在简化和提高代理性能。提供特定工具集。CodeActAgent 也提供了一些预定义的工具供模型使用ThinkTool让模型记录其思考过程FinishTool结束交互CondensationRequestTool请求压缩对话历史BrowserTool与浏览器交互非 Windows 平台LLMBasedFileEditTool 或 create_str_replace_editor_tool编辑文件create_task_tracker_tool任务管理工具工具启用的灵活性通过配置可以控制哪些工具被启用CodeActAgent支持丰富的工具集如下def _get_tools(self) - list[ChatCompletionToolParam]: # For these models, we use short tool descriptions ( 1024 tokens) # to avoid hitting the OpenAI token limit for tool descriptions. SHORT_TOOL_DESCRIPTION_LLM_SUBSTRS [gpt-4, o3, o1, o4] use_short_tool_desc False if self.llm is not None: # For historical reasons, previously OpenAI enforces max function description length of 1k characters # https://community.openai.com/t/function-call-description-max-length/529902 # But it no longer seems to be an issue recently # https://community.openai.com/t/was-the-character-limit-for-schema-descriptions-upgraded/1225975 # Tested on GPT-5 and longer description still works. But we still keep the logic to be safe for older models. use_short_tool_desc any( model_substr in self.llm.config.model for model_substr in SHORT_TOOL_DESCRIPTION_LLM_SUBSTRS ) tools [] if self.config.enable_cmd: # Bash命令执行工具 tools.append(create_cmd_run_tool(use_short_descriptionuse_short_tool_desc)) if self.config.enable_think: # 思考工具记录推理过程 tools.append(ThinkTool) if self.config.enable_finish: # 完成工具结束任务 tools.append(FinishTool) if self.config.enable_condensation_request: tools.append(CondensationRequestTool) if self.config.enable_browsing: # 浏览器工具 if sys.platform win32: logger.warning(Windows runtime does not support browsing yet) else: tools.append(BrowserTool) if self.config.enable_jupyter: # IPython工具 tools.append(IPythonTool) if self.config.enable_plan_mode: # In plan mode, we use the task_tracker tool for task management tools.append(create_task_tracker_tool(use_short_tool_desc)) if self.config.enable_llm_editor: # 文件编辑工具 tools.append(LLMBasedFileEditTool) elif self.config.enable_editor: tools.append( create_str_replace_editor_tool( use_short_descriptionuse_short_tool_desc, runtime_typeself.config.runtime, ) ) return tools2.3.2 BrowserToolBrowserTool 举例如下BrowserTool ChatCompletionToolParam( typefunction, functionChatCompletionToolParamFunctionChunk( nameBROWSER_TOOL_NAME, description_BROWSER_DESCRIPTION, parameters{ type: object, properties: { code: { type: string, description: ( The Python code that interacts with the browser.\n _BROWSER_TOOL_DESCRIPTION ), }, security_risk: { type: string, description: SECURITY_RISK_DESC, enum: RISK_LEVELS, }, }, required: [code, security_risk], }, ), )_BROWSER_TOOL_DESCRIPTION 如下。_BROWSER_TOOL_DESCRIPTION The following 15 functions are available. Nothing else is supported. goto(url: str) Description: Navigate to a url. Examples: goto(http://www.example.com) go_back() Description: Navigate to the previous page in history. Examples: go_back() go_forward() Description: Navigate to the next page in history. Examples: go_forward() noop(wait_ms: float 1000) Description: Do nothing, and optionally wait for the given time (in milliseconds). You can use this to get the current page content and/or wait for the page to load. Examples: noop() noop(500) scroll(delta_x: float, delta_y: float) Description: Scroll horizontally and vertically. Amounts in pixels, positive for right or down scrolling, negative for left or up scrolling. Dispatches a wheel event. Examples: scroll(0, 200) scroll(-50.2, -100.5) fill(bid: str, value: str) Description: Fill out a form field. It focuses the element and triggers an input event with the entered text. It works for input, textarea and [contenteditable] elements. Examples: fill(237, example value) fill(45, multi-line\nexample) fill(a12, example with quotes) select_option(bid: str, options: str | list[str]) Description: Select one or multiple options in a select element. You can specify option value or label to select. Multiple options can be selected. Examples: select_option(a48, blue) select_option(c48, [red, green, blue]) click(bid: str, button: Literal[left, middle, right] left, modifiers: list[typing.Literal[Alt, Control, ControlOrMeta, Meta, Shift]] []) Description: Click an element. Examples: click(a51) click(b22, buttonright) click(48, buttonmiddle, modifiers[Shift]) dblclick(bid: str, button: Literal[left, middle, right] left, modifiers: list[typing.Literal[Alt, Control, ControlOrMeta, Meta, Shift]] []) Description: Double click an element. Examples: dblclick(12) dblclick(ca42, buttonright) dblclick(178, buttonmiddle, modifiers[Shift]) hover(bid: str) Description: Hover over an element. Examples: hover(b8) press(bid: str, key_comb: str) Description: Focus the matching element and press a combination of keys. It accepts the logical key names that are emitted in the keyboardEvent.key property of the keyboard events: Backquote, Minus, Equal, Backslash, Backspace, Tab, Delete, Escape, ArrowDown, End, Enter, Home, Insert, PageDown, PageUp, ArrowRight, ArrowUp, F1 - F12, Digit0 - Digit9, KeyA - KeyZ, etc. You can alternatively specify a single character youd like to produce such as a or #. Following modification shortcuts are also supported: Shift, Control, Alt, Meta, ShiftLeft, ControlOrMeta. ControlOrMeta resolves to Control on Windows and Linux and to Meta on macOS. Examples: press(88, Backspace) press(a26, ControlOrMetaa) press(a61, MetaShiftt) focus(bid: str) Description: Focus the matching element. Examples: focus(b455) clear(bid: str) Description: Clear the input field. Examples: clear(996) drag_and_drop(from_bid: str, to_bid: str) Description: Perform a drag drop. Hover the element that will be dragged. Press left mouse button. Move mouse to the element that will receive the drop. Release left mouse button. Examples: drag_and_drop(56, 498) upload_file(bid: str, file: str | list[str]) Description: Click an element and wait for a filechooser event, then select one or multiple input files for upload. Relative file paths are resolved relative to the current working directory. An empty list clears the selected files. Examples: upload_file(572, /home/user/my_receipt.pdf) upload_file(63, [/home/bob/Documents/image.jpg, /home/bob/Documents/file.zip]) 2.4 上下文让 AI 做决策意味着它需要对环境有深刻的理解甚至具备一定程度的“常识”在已知的模型能力下往往和高质量的prompt和上下文强相关。要让 AI 胜任这个角色必须给它提供一套明确的行动框架清晰的工具集、详尽的工具使用场景、固定的工作流甚至要细化到每个决策节点的触发时机。2.4.1 需求在以自然语言为接口、大模型为核心的 Software 3.0 时代AI Agent 作为上下文驱动的生成式应用需突破传统上下文窗口的固有局限。传统依赖上下文窗口维持对话状态与任务记忆的方式存在长度受限、组织无序、知识静态、成本高昂四大痛点 —— 既无法承载超长历史信息也难以高效检索与动态更新知识更会因长文本处理消耗大量计算资源。从本质上讲上下文Context是提供给 LLM 的、用于完成下一步推理或生成任务的全部信息集合从系统架构视角看Agentic System 可类比为新型操作系统LLM 扮演 CPU 角色上下文窗口则如同容量有限的 RAM而上下文工程就是核心的 “内存管理器”—— 其核心职责并非简单填充数据而是通过智能调度算法动态决定上下文数据的加载与换出确保系统高效运行与结果精准性。上下文工程具体如下图所示。图中所有模块可分为“上下文输入源” 和 “输出 / 工具支撑”两类分类模块作用说明上下文输入源Instructions / System Prompt模型的 “规则 / 角色定义”决定模型的行为模式如 “你是一个严谨的助手”State / HistoryShort-term Memory短期记忆当前会话的历史交互记录保证对话连贯性Long-term Memory长期记忆跨会话的用户 / 任务信息如用户偏好、历史任务结果User Prompt用户当前的查询指令是上下文的核心触发点Retrieved InformationRAG检索增强生成从外部知识库文档、数据库中调取的相关信息输出 / 工具支撑Available Tools模型可调用的外部工具如计算器、搜索引擎扩展模型能力Structured Output模型输出的结构化格式如 JSON、表格提升结果的可用性2.4.2 核心特色AgentContext是 OpenHands 框架中管理提示词扩展的核心结构负责整合所有影响系统扩展和解释用户提示的上下文信息。它将静态环境细节如代码库信息和动态用户激活的扩展如技能组件结合为大语言模型LLM交互提供完整的提示词上下文是组装、格式化和注入所有与提示相关信息的主要容器。多维度上下文整合统一管理代码库上下文、运行时环境、对话指令和知识技能等多类信息避免上下文分散。技能扩展机制支持通过技能Skill动态扩展提示词技能可被用户输入触发自动注入领域知识或指导信息。灵活的提示词后缀提供系统消息后缀和用户消息后缀可按需附加额外信息如代码库详情、运行时参数。用户技能自动加载支持从本地目录自动加载用户自定义技能且避免与显式技能重复。2.4.3 流程图2.4.4 代码class AgentContext(BaseModel): 管理提示词扩展的核心结构。 AgentContext 统一了所有影响系统扩展和解释用户提示的上下文输入 融合了静态环境细节和来自技能的动态用户激活扩展。 具体包含 - **代码库上下文/代码库技能**活跃代码库、分支信息及代码库技能提供的特定指令。 - **运行时上下文**当前执行环境主机、工作目录、密钥、日期等。 - **对话指令**约束或指导智能体在会话中行为的任务/渠道特定规则可选。 - **知识技能**可被用户输入触发的扩展组件用于注入知识或领域特定指导。 这些元素共同使 AgentContext 成为负责组装、格式化和注入所有提示相关上下文到 LLM 交互中的主要容器。 # noqa: E501 skills: list[Skill] Field( default_factorylist, descriptionList of available skills that can extend the users input., ) system_message_suffix: str | None Field( defaultNone, descriptionOptional suffix to append to the system prompt. ) user_message_suffix: str | None Field( defaultNone, descriptionOptional suffix to append to the users message. ) load_user_skills: bool Field( defaultFalse, description( Whether to automatically load user skills from ~/.openhands/skills/ and ~/.openhands/microagents/ (for backward compatibility). ), ) field_validator(skills) classmethod def _validate_skills(cls, v: list[Skill], _info): 验证技能列表确保无重复名称。 if not v: return v # 检查重复的技能名称 seen_names set() for skill in v: if skill.name in seen_names: raise ValueError(fDuplicate skill name found: {skill.name}) seen_names.add(skill.name) return v model_validator(modeafter) def _load_user_skills(self): 若启用则从用户主目录加载自定义技能。 if not self.load_user_skills: return self try: # 加载用户技能 user_skills load_user_skills() # 合并用户技能与显式技能避免重复 existing_names {skill.name for skill in self.skills} for user_skill in user_skills: if user_skill.name not in existing_names: self.skills.append(user_skill) else: logger.warning( fSkipping user skill {user_skill.name} f(already in explicit skills) ) except Exception as e: logger.warning(fFailed to load user skills: {str(e)}) return self def get_system_message_suffix(self) - str | None: 获取包含代码库技能内容和自定义后缀的系统消息。 自定义后缀通常包括 - 代码库信息仓库名称、分支名称、PR编号等 - 运行时信息如可用主机、当前日期 - 对话指令如用户偏好、任务详情 - 代码库特定指令从代码库技能收集 # 筛选无触发条件的技能始终激活的代码库技能 repo_skills [s for s in self.skills if s.trigger is None] logger.debug(fTriggered {len(repo_skills)} repository skills: {repo_skills}) # 构建工作区上下文信息 if repo_skills: # TODO(test): 添加渲染测试确保功能正常 formatted_text render_template( prompt_dirstr(PROMPT_DIR), # 模板目录 template_namesystem_message_suffix.j2, # 系统消息后缀模板 repo_skillsrepo_skills, # 代码库技能列表 system_message_suffixself.system_message_suffix or , # 自定义系统后缀 ).strip() return formatted_text # 若无可激活的代码库技能直接返回自定义系统后缀非空时 elif self.system_message_suffix and self.system_message_suffix.strip(): return self.system_message_suffix.strip() return None def get_user_message_suffix( self, user_message: Message, skip_skill_names: list[str] ) - tuple[TextContent, list[str]] | None: 通过技能召回的知识增强用户消息。 流程如下 - 提取用户消息的文本内容 - 匹配查询中的技能触发词 - 若有相关技能被触发返回格式化的知识和触发的技能名称 # noqa: E501 user_message_suffix None # 处理自定义用户消息后缀 if self.user_message_suffix and self.user_message_suffix.strip(): user_message_suffix self.user_message_suffix.strip() # 提取用户消息中的纯文本内容 query \n.join( c.text for c in user_message.content if isinstance(c, TextContent) ).strip() recalled_knowledge: list[SkillKnowledge] [] # 若查询为空仅返回自定义用户后缀如有 if not query: if user_message_suffix: return TextContent(textuser_message_suffix), [] return None # 在查询中搜索技能触发词 for skill in self.skills: if not isinstance(skill, Skill): continue # 匹配技能触发条件 trigger skill.match_trigger(query) if trigger and skill.name not in skip_skill_names: logger.info( Skill %s triggered by keyword %s, skill.name, trigger, ) # 收集触发技能的知识 recalled_knowledge.append( SkillKnowledge( nameskill.name, triggertrigger, contentskill.content, ) ) # 若有触发的技能渲染知识内容 if recalled_knowledge: formatted_skill_text render_template( prompt_dirstr(PROMPT_DIR), template_nameskill_knowledge_info.j2, # 技能知识模板 triggered_agentsrecalled_knowledge, # 触发的技能知识列表 ) # 合并自定义用户后缀 if user_message_suffix: formatted_skill_text \n user_message_suffix return TextContent(textformatted_skill_text), [ k.name for k in recalled_knowledge ] # 若无触发技能仅返回自定义用户后缀如有 if user_message_suffix: return TextContent(textuser_message_suffix), [] return None2.5 提示词promptCodeActAgent的提示词prompt是通过PromptManager从文件中加载的。具体来说提示词位置提示词文件位于openhands/agenthub/codeact_agent/prompts/目录下主提示词文件名为codeact_agent_system_prompt.hbs。加载机制通过PromptManager类管理提示词默认系统提示词文件名由AgentConfig的resolved_system_prompt_filename属性决定。2.6 迭代修改CodeActAgent 被设计为可以并且应该继续修改自己生成的代码。系统提供了多种工具和明确的指导原则来支持迭代开发过程。代理被鼓励通过多次迭代来完善其解决方案包括修改、测试和重新修改代码直到达到满意的结果。这种设计符合 CodeAct 论文的理念即将所有操作统一到代码执行空间中从而简化和提高代理性能。系统设计系统设计明确鼓励 CodeActAgent 迭代修改代码在系统提示中有明确的指导原则当探索代码库时使用高效的工具如 find、grep 和 git 命令并在适当时候使用过滤器来最小化不必要的操作提示中还强调在实现任何更改之前首先通过探索彻底理解代码库在 reproducing bugs 或 implementing fixes 时使用单个文件而不是创建具有不同版本的多个文件系统提示中的文件系统指南明确支持修改现有代码如果被要求编辑文件直接编辑文件而不是创建具有不同文件名的新文件对于全局搜索和替换操作考虑使用 sed 而不是多次打开文件编辑器永远不要为同一文件创建多个版本系统提示中定义的问题解决工作流程明确支持迭代修改探索彻底探索相关文件并理解上下文分析考虑多种方法并选择最有希望的一种测试为 bug 修复创建测试以在实施修复之前验证问题实施进行有针对性的、最小的更改以解决问题验证如果环境设置为运行测试则彻底测试实现包括边缘情况CodeActAgent 拥有多种工具来支持迭代修改代码文件编辑工具create_str_replace_editor_tool 和 LLMBasedFileEditTool允许它修改现有文件Bash 命令执行工具允许它运行测试、编译代码、安装依赖等IPython 执行工具允许它测试代码片段0x03 工作流程我们接下来看看 CodeActAgent 的工作流程。3.1 决策流程step方法是决策过程返回各种ActionCmdRunAction(command) - 要运行的bash命令IPythonRunCellAction(code) - 要运行的IPython代码AgentDelegateAction(agent, inputs) - 用于子任务的委托操作MessageAction(content) - 要运行的消息操作例如请求澄清AgentFinishAction() - 结束交互CondensationAction(...) - 通过遗忘指定事件并可选地提供摘要来压缩对话历史FileReadAction(path, ...) - 从指定路径读取文件内容FileEditAction(path, ...) - 使用基于LLM已弃用或基于ACI的编辑方式编辑文件AgentThinkAction(thought) - 记录代理的思考/推理过程CondensationRequestAction() - 请求压缩对话历史BrowseInteractiveAction(browser_actions) - 使用指定操作与浏览器交互MCPAction(name, arguments) - 与MCP服务器工具交互具体代码如下def step(self, state: State) - Action: 使用CodeAct Agent执行一步操作。 包括收集先前步骤的信息并提示模型生成要执行的命令。 参数: - state (State): 用于获取更新的信息 # 处理待处理操作如果有 if self.pending_actions: # 返回并移除队列中的第一个待处理操作 return self.pending_actions.popleft() # 如果任务已完成退出 # 获取最新的用户消息 latest_user_message state.get_last_user_message() # 若用户输入/exit则返回结束操作 if latest_user_message and latest_user_message.content.strip() /exit: return AgentFinishAction() # 压缩状态中的事件。如果获得视图将其传递给对话管理器处理 # 如果获得压缩事件则返回该事件而非操作。控制器将立即要求代理使用新视图再次执行步骤 condensed_history: list[Event] [] # 匹配压缩器返回的结果类型 match self.condenser.condensed_history(state): # 若为View类型提取事件列表作为压缩历史 case View(eventsevents): condensed_history events # 若为Condensation类型返回其包含的压缩操作 case Condensation(actioncondensation_action): return condensation_action # 打印调试日志显示处理的压缩事件数量和总事件数量 logger.debug( f从共{len(state.history)}个事件中处理{len(condensed_history)}个压缩事件 ) # 获取初始用户消息从状态历史中 initial_user_message self._get_initial_user_message(state.history) # 构建用于LLM的消息列表基于压缩历史和初始用户消息 messages self._get_messages(condensed_history, initial_user_message) # 构建LLM调用参数 params: dict { messages: messages, # 消息列表 } # 检查并添加可用工具根据LLM配置过滤 params[tools] check_tools(self.tools, self.llm.config) # 添加额外元数据从状态中提取适配LLM格式 params[extra_body] { metadata: state.to_llm_metadata( model_nameself.llm.config.model, agent_nameself.name ) } # 调用LLM获取响应 response self.llm.completion(** params) # 打印调试日志显示LLM返回的响应 logger.debug(fLLM返回的响应: {response}) # 将LLM响应转换为具体操作列表 actions self.response_to_actions(response) # 打印调试日志显示转换后的操作 logger.debug(fresponse_to_actions转换后的操作: {actions}) # 将所有操作添加到待处理队列 for action in actions: self.pending_actions.append(action) # 返回并移除队列中的第一个操作 return self.pending_actions.popleft()3.2 消息处理_get_messages方法负责处理消息。该方法执行以下步骤检查事件中是否有SystemMessageAction若缺失则添加为了向后兼容将事件操作和观察结果处理为消息包括SystemMessageAction在函数调用模式下处理工具调用及其响应管理消息角色交替用户/助手/工具为特定LLM提供商如Anthropic应用缓存在非函数调用模式下添加环境提醒def _get_messages( self, events: list[Event], initial_user_message: MessageAction ) - list[Message]: 为LLM对话构建消息历史。 该方法通过处理状态中的事件并将其格式化为LLM可理解的消息构建结构化的对话历史。 它处理常规消息流和函数调用场景。 参数: events: 要转换为消息的事件列表 返回: list[Message]: 格式化的消息列表可直接供LLM使用包括 - 带提示的系统消息来自SystemMessageAction - 操作消息来自用户和助手 - 观察消息包括工具响应 - 环境提醒在非函数调用模式下 注意: - 在函数调用模式下工具调用及其响应会被仔细跟踪以维持正确的对话流程 - 同一角色的消息会被合并以避免连续出现相同角色的消息 - 对于Anthropic模型会根据其文档对特定消息进行缓存 # 若未实例化提示管理器抛出异常 if not self.prompt_manager: raise Exception(提示管理器未实例化。) # 使用对话内存处理事件包括SystemMessageAction messages self.conversation_memory.process_events( condensed_historyevents, # 压缩后的事件历史 initial_user_actioninitial_user_message, # 初始用户消息 max_message_charsself.llm.config.max_message_chars, # 消息最大字符数限制 vision_is_activeself.llm.vision_is_active(), # 是否启用视觉功能 ) # 若LLM启用了提示缓存应用缓存机制 if self.llm.is_caching_prompt_active(): self.conversation_memory.apply_prompt_caching(messages) # 返回构建的消息列表 return messages3.3 历史压缩Condensation在step函数中会通过Condensor压缩对话历史避免上下文过长。# Condense the events from the state. If we get a view well pass those # to the conversation manager for processing, but if we get a condensation # event well just return that instead of an action. The controller will # immediately ask the agent to step again with the new view. condensed_history: list[Event] [] match self.condenser.condensed_history(state): case View(eventsevents): condensed_history events case Condensation(actioncondensation_action): return condensation_action3.4 内存管理成员变量conversation_memory会进行会话内存管理。self.conversation_memory ConversationMemory(self.config, self.prompt_manager)具体代码参见def _get_messages( self, events: list[Event], initial_user_message: MessageAction ) - list[Message]: # Use ConversationMemory to process events (including SystemMessageAction) messages self.conversation_memory.process_events( condensed_historyevents, initial_user_actioninitial_user_message, max_message_charsself.llm.config.max_message_chars, vision_is_activeself.llm.vision_is_active(), ) if self.llm.is_caching_prompt_active(): self.conversation_memory.apply_prompt_caching(messages) return messages

相关文章:

拆解 OpenHands(8)--- CodeActAgent

在 OpenHands 智能框架的生态中,CodeActAgent 占据着核心地位,它是基于 CodeAct 理念构建的核心代理模块。其设计初衷极具巧思:将各类复杂任务统一转化为 “代码执行” 的形式来完成,同时兼顾自然语言对话的交互特性。这一设计既保…...

配置Claude Code遇到Unable to connect to Anthropic services Failed to connect to api.anthropic.cOm: ERR_B

在PowerShell里输入[Environment]::SetEnvironmentVariable("HTTP_PROXY", "http://127.0.0.1:xxxxx", "User")[Environment]::SetEnvironmentVariable("HTTPS_PROXY", "http://127.0.0.1:xxxxx", "User")[Enviro…...

GraceTheme定义“优雅大气”的WordPress主题新标准

网站不仅是信息的载体,更是品牌气质的延伸。无论是企业官网、个人博客还是作品集展示,如何在茫茫网海中脱颖而出,给用户留下深刻的第一印象?答案往往就藏在网站的“气质”之中。如果你正在寻找一款能够完美平衡美学设计与功能实用性的WordPr…...

Cursor/AI 助手用自然语言操作监控与告警

主要用途告警管理:查询活跃告警和历史告警,查看告警规则和订阅目标监控:浏览和搜索被监控的主机,分析目标状态事件响应:创建和管理告警屏蔽规则、通知规则和事件流水线团队协作:查询用户、团队和业务组快速…...

三步解锁:突破限制的浏览器插件全攻略

三步解锁:突破限制的浏览器插件全攻略 【免费下载链接】wechat-need-web 让微信网页版可用 / Allow the use of WeChat via webpage access 项目地址: https://gitcode.com/gh_mirrors/we/wechat-need-web 在当今数字化办公环境中,许多用户面临着…...

OpCore-Simplify:让黑苹果配置从3天缩短到15分钟的智能助手

OpCore-Simplify:让黑苹果配置从3天缩短到15分钟的智能助手 【免费下载链接】OpCore-Simplify A tool designed to simplify the creation of OpenCore EFI 项目地址: https://gitcode.com/GitHub_Trending/op/OpCore-Simplify 你是否曾因为复杂的黑苹果配置…...

BilibiliDown终极指南:3个专业技巧实现B站视频高效下载与无损音频提取

BilibiliDown终极指南:3个专业技巧实现B站视频高效下载与无损音频提取 【免费下载链接】BilibiliDown (GUI-多平台支持) B站 哔哩哔哩 视频下载器。支持稍后再看、收藏夹、UP主视频批量下载|Bilibili Video Downloader 😳 项目地址: https://gitcode.c…...

Zotero CitationCounts:学术引用追踪与文献影响力分析的高效工具

Zotero CitationCounts:学术引用追踪与文献影响力分析的高效工具 【免费下载链接】zotero-citationcounts Zotero plugin for auto-fetching citation counts from various sources 项目地址: https://gitcode.com/gh_mirrors/zo/zotero-citationcounts Zote…...

torchaudio报错没安装torchcodec

安装torchcodec后仍然报错,原因是torchcodec需要cuda13.x的配置解决办法:重装torchaudio,版本回退到2.4,在保存音频时无需依赖torchcodec同时需要注意匹配torch和torchvision的版本pip install torch2.4.0 torchvision0.19.0 torc…...

ClaimsPrincipal序列化为Json的正确姿势

第二步,理解三者的关系 1. Claim:声明的基本单元 职责 表示一个键值对形式的声明(如 "name" "Alice"、"role" "Admin")。不仅包含类型(Type)和值&#xff08…...

3个核心功能让视频创作者内容采集效率提升300%的实战指南

3个核心功能让视频创作者内容采集效率提升300%的实战指南 【免费下载链接】douyin-downloader A practical Douyin downloader for both single-item and profile batch downloads, with progress display, retries, SQLite deduplication, and browser fallback support. 抖音…...

深度解析Godot资源提取:构建专业级解包方案

深度解析Godot资源提取:构建专业级解包方案 【免费下载链接】godot-unpacker godot .pck unpacker 项目地址: https://gitcode.com/gh_mirrors/go/godot-unpacker 在游戏开发与逆向工程领域,Godot资源提取技术已成为开发者探索游戏内部结构的核心…...

SEGGER J-Flash V8.94添加芯片方法

1.打开J-Flash安装路径&#xff08;一般为\SEGGER\JLink_V894&#xff09; 在此路径下新建文件JLinkDevices.xml2.编辑xml文件 <DataBase><Device><ChipInfo Vendor"Renergy" /*厂家*/Name"RN8213B_SOC_V2" /*芯片型号*/WorkRAMAddr&q…...

解压缩软件分享-Banizip

解压缩软件分享-Banizip蓝奏云地址https://wwbdt.lanzoul.com/ijspk3mbduxi 密码:9y00百度网盘地址通过网盘分享的文件&#xff1a;BANDIZIP6-SETUP.EXE 链接: https://pan.baidu.com/s/1VBovOqT-M7kiv2b9YuJGIw?pwdrc87 提取码: rc87 为什么推荐这个呢&#xff0c;因为这个支…...

春秋云境CVE-2018-12613

1.阅读靶场介绍index.php中存在一处文件包含逻辑可以理解为对url做处理能想到的就是../../../../../flag2.启动靶场如上图所示看到这个界面我想到的就是select flag from flag出来但是本博主没有找到哟期待各位大神的评论3.poc这里博主是通过这个处理过的url夺旗的如下所示url在…...

从一线装维经验看,扩展式智能插座更适合多路监测与项目落地

作为一名做了12年现场电气安装与运维的一线装维人员&#xff0c;今天想聊聊智能插座。这些年接触过的智能插座不少&#xff0c;市面上的产品确实五花八门&#xff0c;外观、功能、结构都不一样。选择多了&#xff0c;对用户来说未必是好事&#xff0c;反而更容易挑花眼。尤其一…...

数据库基础知识----数据库大观

这里写目录标题绪论发展历程数据模型三层模式两层映像基本概念关系数据库简介&#xff08;基本术语&#xff09;关系模型组成数据结构数据操纵数据完整性规则关系代数五个基本操作并差笛卡尔积投影&#xff08;π&#xff09;选择四个组合操作交连接除法关系数据库语言----SQL简…...

具备百万并发用户执行能力,静态页面加载的平均响应时间低于1.1毫秒, 事务请求处理成功率100%

在Tomcat性能测试与技术选型中&#xff0c;“具备百万并发用户执行能力”“静态页面加载平均响应时间低于1.1毫秒”“事务请求处理成功率100%”是常被提及的理想指标。这些指标看似彰显系统高性能&#xff0c;实则需结合计算机底层原理、操作系统限制、工程实践场景综合研判。本…...

如何高效构建雷达系统:Python雷达模拟的完整实战指南

如何高效构建雷达系统&#xff1a;Python雷达模拟的完整实战指南 【免费下载链接】radarsimpy Radar Simulator built with Python and C 项目地址: https://gitcode.com/gh_mirrors/ra/radarsimpy RadarSimPy是一个基于Python和C构建的开源雷达模拟器&#xff0c;为雷达…...

Steam Achievement Manager终极指南:如何完全掌控你的Steam成就系统

Steam Achievement Manager终极指南&#xff1a;如何完全掌控你的Steam成就系统 【免费下载链接】SteamAchievementManager A manager for game achievements in Steam. 项目地址: https://gitcode.com/gh_mirrors/st/SteamAchievementManager Steam Achievement Manage…...

WarcraftHelper终极指南:如何让魔兽争霸3在现代电脑上焕然新生 [特殊字符]

WarcraftHelper终极指南&#xff1a;如何让魔兽争霸3在现代电脑上焕然新生 &#x1f3ae; 【免费下载链接】WarcraftHelper Warcraft III Helper , support 1.20e, 1.24e, 1.26a, 1.27a, 1.27b 项目地址: https://gitcode.com/gh_mirrors/wa/WarcraftHelper 还在为魔兽争…...

【愚公系列】《剪映+DeepSeek+即梦:短视频制作》047-转场:短视频一气呵成的秘密(转场类型)

&#x1f48e;【行业认证权威头衔】 ✔ 华为云天团核心成员&#xff1a;特约编辑/云享专家/开发者专家/产品云测专家 ✔ 开发者社区全满贯&#xff1a;CSDN博客&商业化双料专家/阿里云签约作者/腾讯云内容共创官/掘金&亚马逊&51CTO顶级博主 ✔ 技术生态共建先锋&am…...

【python】MacOS下永久配置pip镜像源

核心方法&#xff1a;修改 pip 的配置文件在 macOS 上&#xff0c;您需要创建或修改一个位于用户主目录下的配置文件 pip.conf。详细步骤第一步&#xff1a;打开终端按 Command 空格键 打开 Spotlight 搜索。输入“终端”或“Terminal”&#xff0c;然后按回车键打开。第二步&…...

Jupyter notebook打不开本地文件,有关目录存放问题

Jupyter notebook打不开本地文件&#xff0c;有关目录存放问题 基于Anaconda下载后&#xff0c;点击Jupyter notebook无法打开文件目录问题&#xff0c;或者需要更改打开的文件目录&#xff0c;主要解决方法&#xff1a;修改配置文件和路径。 第一步&#xff1a;修改配置文件 打…...

LFM2.5-1.2B-Thinking在Ollama上的真实体验:生成速度、内容质量实测

LFM2.5-1.2B-Thinking在Ollama上的真实体验&#xff1a;生成速度、内容质量实测 1. 模型初体验与部署 1.1 第一印象&#xff1a;轻量但强大 当我第一次在Ollama上看到LFM2.5-1.2B-Thinking这个模型时&#xff0c;最吸引我的是它"小身材大能量"的特点。作为一个仅有…...

小白也能轻松上手!通义千问2.5-7B+Ollama快速入门

小白也能轻松上手&#xff01;通义千问2.5-7BOllama快速入门 1. 为什么选择通义千问2.5-7B&#xff1f; 通义千问2.5-7B-Instruct是阿里云2024年9月发布的中等规模开源大模型&#xff0c;拥有70亿参数&#xff0c;专为指令跟随任务优化。这个模型特别适合想在本地运行AI但又不…...

Kandinsky-5.0-I2V-Lite-5s部署案例:中小企业用其替代高价视频外包,降本70%

Kandinsky-5.0-I2V-Lite-5s部署案例&#xff1a;中小企业用其替代高价视频外包&#xff0c;降本70% 1. 为什么中小企业需要关注这个方案 对于中小企业来说&#xff0c;视频制作一直是个头疼的问题。传统外包制作5秒短视频的平均成本在2000-5000元不等&#xff0c;而使用Kandi…...

重获数据自主权:WechatDecrypt让你掌控数字记忆

重获数据自主权&#xff1a;WechatDecrypt让你掌控数字记忆 【免费下载链接】WechatDecrypt 微信消息解密工具 项目地址: https://gitcode.com/gh_mirrors/we/WechatDecrypt 在数字时代&#xff0c;我们的聊天记录、社交关系和工作信息都存储在第三方平台上&#xff0c;…...

效率提升秘籍:用快马AI自动生成9·1免费素材的可复用组件

效率提升秘籍&#xff1a;用快马AI自动生成91免费素材的可复用组件 最近在做一个需要整合大量91免费素材的项目&#xff0c;发现每次都要手动编写重复的展示代码&#xff0c;效率实在太低。经过一番摸索&#xff0c;我找到了用快马平台快速生成可复用组件的方法&#xff0c;效…...

wechat-need-web:基于Manifest V3的微信网页版访问架构解析与实现方案

wechat-need-web&#xff1a;基于Manifest V3的微信网页版访问架构解析与实现方案 【免费下载链接】wechat-need-web 让微信网页版可用 / Allow the use of WeChat via webpage access 项目地址: https://gitcode.com/gh_mirrors/we/wechat-need-web 微信网页版访问限制…...