☰
Harbor 模拟用户(Simulated User)评估:基于 ACP 协议的多轮人机交互评测方案(RFC 0002 全解析)
2026/10/12 1:27:48 网站建设 项目流程

【免费下载链接】harbor

Framework for evaluating and improving agents

项目地址:https://gitcode.com/gh_mirrors/harbor17/harbor
点击查看免费下载

导读

Harbor 的模拟用户(Simulated User)机制,是在一次运行中同时启动两个 Agent:一个扮演"用户",另一个作为"被评估的编码 Agent",双方通过 Agent Client Protocol(ACP) 协议在任务容器内进行多轮、由用户驱动的自然对话,最终由验证器对环境的最终状态打分。相比"一次喂入完整任务说明"的传统评测方式,这种方式更贴近真实用户"描述目标 → 观察 Agent 反应 → 追问澄清 → 直到满意"的真实协作过程。读完本文你将掌握:模拟用户方案的设计动机、harbor run下新增的 CLI 参数、Trial 生命周期中各阶段的时序、用户提示词模板的定制方法、ACP 桥接器(bridge)的底层实现原理,以及当前实现的边界与后续演进方向。

本文以仓库中的 RFC 0002 及其 补丁文档 为主体,并结合src/harbor中已落地的实现代码、CLI 参数定义与单元测试进行印证与扩充。


一、背景:为什么需要"模拟用户"评测

许多 Harbor 使用者希望评估 Agent 在多轮、用户驱动的交互下的表现,而不是一次性收到完整指令后自主完成任务。真实用户不会把任务规格一次性贴完就离开——他们会描述一个目标,对 Agent 的提问和进展作出反应,并在过程中不断澄清需求。

RFC 0002 提出一个极简机制来模拟这种行为:让第二个 Agent 扮演用户。一次运行的示例:

harbor run \ --agent gemini-cli --model gemini/gemini-3-pro-preview \ --user claude-code --user-model anthropic/claude-opus-4-8 \ --path ./tasks/my-multi-turn-task

两个角色都是Harbor 既有的 Agent,各自搭配自己的模型。扮演用户的 Agent 收到任务指令(外加一句"请扮演用户"的提示),然后通过 ACP 协议与被评估的 Agent 对话——这正像真实用户在 IDE 里输入提示词、让编码 Agent 去干重活。任务在模拟用户满意时结束,验证器照常对环境状态评分。

注:原 RFC 使用--user标志;补丁将其重命名为--user-agent,与--user-model对齐,并避免与既有的harbor job share --user冲突。当前仓库 CLI 采用--user-agent/--user-model命名(见 src/harbor/cli/jobs.py)。


二、核心概念:新标志与配置模型

整个特性在配置层只有两个新东西:CLI 新增的--user-agent/--user-model标志,以及TrialConfig上新增的可选字段user_agent。

2.1 标志与配置字段的映射

标志映射到的配置说明
--user-agentuser_agent.name扮演模拟用户的 Agent(原 RFC 中的--user,补丁重命名)。
--user-modeluser_agent.model_name模拟用户使用的模型。
--agentagent.name被评估的 Agent(必须支持 ACP),含义不变。
--modelagent.model_name被评估 Agent 的模型,含义不变。
字段类型状态说明
TrialConfig.user_agentAgentConfig \| None可选由--user-agent/--user-model填充。存在时,该 Agent 作为模拟用户运行,TrialConfig.agent中的 Agent 以 ACP 模式启动。None(默认)时行为与今天完全一致。

在源码中,UserAgentConfig继承自AgentConfig,并额外携带user_persona_path、user_prompt_template_path和必填的bridge字段(见 src/harbor/models/trial/config.py):

class UserAgentConfig(AgentConfig): user_persona_path: Path | None = None user_prompt_template_path: Path | None = None bridge: BridgeConfig

JobConfig增加同样的可选字段并转发给每个 trial。AgentConfig本身完全不变:两个角色复用同一个配置类,模拟用户的模型同样存放在model_name字段中。user_agent为None时,本特性完全不激活,行为与今天逐字节一致——这是向后兼容性的硬约束,也由单元测试test_trial_config_round_trip等用例守护(见 tests/unit/test_simulated_user.py)。

2.2 桥接器(Bridge)配置

bridge是UserAgentConfig的必填字段,其类型定义在 src/harbor/models/bridge.py:

class BridgeKind(StrEnum): ACP = "acp" class BridgeConfig(BaseModel): kind: BridgeKind prompt_path: Path | None = None kwargs: dict[str, Any] = Field(default_factory=dict)

CLI 端对应--bridge acp、--bridge-prompt-path与可重复的--bridge-kwarg(--bk)三个选项(见 src/harbor/cli/jobs.py)。在命令行上,--user-agent必须搭配--bridge,否则 CLI 直接报错退出:"--user-agent requires --bridge."(见 src/harbor/cli/jobs.py)。


三、架构:三个小部件,全部在任务容器内

整个设计由三块小部件组成,全部运行在既有任务容器内部:

┌────────────────────────── task container ──────────────────────────┐ │ │ │ user agent (normal Harbor agent run) │ │ │ runs `chat "<message>"` via its shell tool │ │ ▼ │ │ ACP host (small Python process, started by Harbor) │ │ │ JSON-RPC over stdio (ACP): session/prompt, session/update │ │ ▼ │ │ target agent (spawned in ACP mode, e.g. `claude-code-acp`) │ │ │ └────────────────────────────────────────────────────────────────────┘
  1. 用户 Agent:走完全未改动的BaseAgent.setup()/run()生命周期,唯一区别是它的指令里追加了一段话(见第四节),告诉它扮演模拟用户并通过chat命令与另一个 Agent 对话。
  2. ACP 宿主:Harbor 上传并启动的一个 Python 脚本。它负责以 ACP 模式生成目标 Agent,执行一次initialize+session/new,并在整个 trial 期间持有 stdio 会话,通过 Unix socket 对外提供服务。它扮演的角色正是 Zed、JetBrains 等 IDE ACP 客户端中编辑器进程的角色——只不过把对话面板换成了 socket。
  3. chat命令:一个极简 CLI——通过 socket 发送一条消息并打印目标 Agent 的回复。对用户 Agent 而言,与其他 Agent 对话只是运行一条 shell 命令,完全不需要协议知识。

宿主存在的唯一机械原因是:ACP 客户端需要持有到 Agent 子进程的持久 stdio 管道,而通过一次性 shell 命令运作的 LLM Agent 无法持有管道。宿主就是那个"持管者",仅此而已。独立项目 acpx(headless ACP CLI 客户端)也独立地收敛到了完全相同的架构:一个按会话持连接的后台进程 + 一层薄薄的 Unix socket CLI 前端。

3.1 补丁后的最终架构:用 acpx 替换自研客户端

补丁将原 RFC 中"自研 ACP host +chatCLI"收窄为:直接采用 acpx 作为 ACP 客户端,用户 Agent 通过真实的acpxCLI驱动对话,而不是自研的chat包装。Harbor 将全部策略钉在项目级配置文件.acpxrc.json中,用户 Agent 只负责提供消息内容;Agent 命令、权限策略、超时与输出格式全部来自配置,且会话按(agent, cwd)作用域自动续接:

补丁这样收窄的理由来自评审共识:客户端应当是既有的 CLI 或 MCP(避免重复造轮子),而强制对话走自研chat工具可能诱导不自然的模型行为。当前仓库中该架构已完整落地于 src/harbor/bridges/acp.py 的ACPBridge实现。


四、Trial 生命周期:时序与各阶段职责

设置user_agent后,trial 各阶段的变化如下:

4.1 执行顺序(补丁版)

  1. user.setup():安装用户 Agent(Harbor 既有生命周期,不改动)。
  2. agent.setup() + acp_install():安装目标 Agent,随后运行其acp_install()钩子(原生 ACP Agent 为空操作;其余安装适配器)。
  3. 启动 ACP 客户端:Harbor 将.acpxrc.json写入工作区,在agents映射下注册目标(command+args取自agent.acp_command()),并钉住策略:defaultAgent: "target"、defaultPermissions: "approve-all"、ttl: 0(空闲不关停)、宽松的timeout、format: "quiet"(只输出助手文本,让用户 Agent 看到合并后的单条回复而非目标 Agent 的工具调用或思考过程)。随后运行acpx sessions ensure生成会话持有进程——该进程以 ACP 模式生成目标并完成一次initialize+session/new,在整个 trial 期间持有 stdio 管道。
  4. user.run(instruction + user_prompt):用户 Agent 收到提示词(任务instruction经用户提示词模板渲染进 persona/goal 与固定的 acpx 操作说明),然后正常运行,由它自己的智能体循环驱动整段对话。它唯一的"新能力"是PATH上的acpx;会话以(agent, cwd)为键自动续接,因此每次acpx prompt "msg"都延续同一段对话,无需 Agent token、会话 ID 或任何标志。Harbor 不编排轮次;该阶段在user.run()返回时结束,不需要显式终止命令,既有的 Agent 超时机制是对话失控的最后防线。
  5. 转录 + 验证:Harbor 通过acpx sessions export --output <trial-logs>(cwd 默认作用域,无需会话 ID)将会话记录恢复到 trial 的 agent 日志目录,然后验证器照常对环境状态评分。

该顺序与 src/harbor/trial/trial.py 中的_prepare一致:user→target→bridge,单元测试test_prepare_orders_agents_before_bridge明确断言了这一顺序(见 tests/unit/test_simulated_user.py)。

4.2 每轮对话循环

目标 Agent 不接收任何指令文件——它了解任务的全部途径就是模拟用户的消息。这种信息不对称正是让模拟有意义的关键。


五、用户提示词:模板、persona 与桥接指令

5.1 原 RFC 中的示例追加段落

用户 Agent 收到任务的instruction.md并附带一段追加段落(由 trial 注入,不写入任务文件,因此既有任务无需修改):

Instead of acting as an agent solving this task yourself, act as a simulated user talking to another agent that will solve the task on your behalf. Send messages to that agent by runningchat "<your message>"; the command prints the agent's reply. Do not edit files or run task commands yourself. Describe what you want, review the agent's responses, and follow up until the task is complete, like a real user would.

补丁落地后,这段机制文案由 Harbor 内置的DEFAULT_ACP_PROMPT承载,措辞如下(见 src/harbor/bridges/acp.py):

## How to talk to the coding agent A coding agent is connected to this workspace. You talk to it by running the `acpx` command-line tool in your shell: - Send it a message with: `acpx prompt "<your message>"` - `acpx prompt` is the only channel to the coding agent. Your first action must send an opening message with that command. - The command blocks until the coding agent finishes its turn; long waits are normal. - Run it again to continue the same session, sending exactly one message each time. - Do not edit files or complete the task yourself. You may inspect the workspace read-only to review the coding agent's work. - When you are satisfied, stop sending messages and end your session.

5.2 提示词的组装:persona + 桥接指令 + 任务

Harbor 用既有的 Jinja2 提示词模板机制(with_prompt_template/render_prompt_template)渲染用户 Agent 的提示词。默认模板与默认 persona 定义在 src/harbor/trial/simulated_user.py:

DEFAULT_USER_PERSONA = """\ You are playing the role of a human user who wants an agent to complete a task. Your goal is given at the end of this prompt. It is private to you; the agent cannot see it, so convey it through your messages.""" DEFAULT_USER_PROMPT_TEMPLATE = """\ {{ persona }} {{ bridge_instructions }} {{ instruction }}"""

三部分组装关系如下:

部分默认值覆盖方式
Persona(人格设定)内置默认 persona--user-persona-path
桥接指令(acpx 操作说明)内置DEFAULT_ACP_PROMPT--bridge-prompt-path
任务指令instruction.md—

若使用--user-prompt-template-path传入自定义 Jinja2 模板,模板必须包含{{ bridge_instructions }}与{{ instruction }}两个变量,{{ persona }}为可选项(见 src/harbor/cli/jobs.py 的 help 文本,以及 src/harbor/trial/simulated_user.py 的模板校验逻辑:缺失必需变量、引用未知变量、persona_path与无{{ persona }}槽的模板组合都会被拒绝)。

5.3 模板为什么这样设计

用户 Agent不需要认识 acpx 的全部功能——sessions、exec、set-mode、标志位、Agent 别名这些要么被钉在.acpxrc.json里,要么与模拟用户无关。教学过多只会增加误用面、把模型从角色扮演中拉走。命令对模型是"不透明的"("我与另一个 Agent 交谈的方式"),因此它不需要 ACP、会话乃至 acpx 是独立工具这些概念。

由于指令里不出现别名或标志,内部变更(重命名agents键、调整策略、甚至换掉二进制包装)都不会影响用户 Agent。模板机制把各部分分开治理:机制文案是 Harbor 提供的常量(每次 trial 完全相同);persona 与目标是作者可写部分,可通过--user-prompt-template-path按 run 定制。因为模板是独立于任务的 run 级文件,同一个用户 Agent 可以跨任务复用,也可以对同一任务批量扫过多个用户 persona。


六、Agent 的 ACP 支持:声明式钩子

CLI 永远使用 Harbor 既有 Agent 名:--agent claude-code,而不是claude-code-acp。像claude-code-acp这样的名字不是 Agent 身份,而是启动命令(本例是 Zed 维护的适配器二进制),用于以 ACP 模式启动某个 Agent。每个 Agent 用哪个命令是其 Harbor 类内部细节,通过以下成员声明:

成员类型说明
SUPPORTS_ACPbool类标志,默认False。
acp_command()list[str]在容器内以 ACP 模式启动该 Agent 的命令。
acp_install()async 钩子ACP 模式的额外安装步骤,在 Agent 正常install()之后运行,默认空操作。

实现层面,ACPAgentMixin(见 src/harbor/agents/protocols/acp.py)是桥接器要求的"目标 Agent 能力"抽象基类,定义了acp_command()、acp_env()、acp_install()、acp_teardown()四个成员。桥接器创建时会校验目标 Agent 实现了该 mixin(见 src/harbor/bridges/base.py),不支持acp桥接的 Agent 会抛出ValueError。

6.1 两种集成形态的参考实现

原生形态:gemini-cli(src/harbor/agents/installed/gemini_cli.py)。acp_command()返回["env", "GEMINI_CLI_TRUST_WORKSPACE=true", "gemini", "--acp", "--model=..."]——同一个已安装二进制加 ACP 标志即可;acp_install()只做 node 与 gemini 二进制定位与固定,不安装新东西。

适配器形态:claude-code(src/harbor/agents/installed/claude_code.py)。acp_command()通过env前缀注入模型选择与CLAUDE_CONFIG_DIR(把会话日志定向到 trial 日志目录,供后续原生转 ATIF 轨迹使用),最后以claude-code-acp收尾;acp_install()用 npm 安装钉死版本的@zed-industries/claude-code-acp@<version>,并把适配器二进制固定到/usr/local/bin(src/harbor/agents/installed/claude_code.py)。

此外codex(src/harbor/agents/installed/codex.py)与opencode(src/harbor/agents/installed/opencode.py)也已实现 ACP 钩子,单元测试test_creates_acp_bridge_for_openai_targets覆盖了这两个目标(见 tests/unit/test_simulated_user.py)。

6.2 安装是"叠加"而非"替换"

已安装 Agent 本就实现install()钩子,setup()在容器内运行;当该 Agent 作为 ACP 目标时,trial 额外运行acp_install()。对原生 Agent(gemini-cli)该钩子是空操作,因为acp_command()就是该类已安装的同一二进制加 ACP 标志;对适配器型 Agent(claude-code)则安装适配器包,把claude-code-acp放到 PATH 上、紧挨着正常的claude二进制。两种形态下认证方式都不变——适配器读取与正常 Agent 相同的ANTHROPIC_API_KEY等环境变量。

harbor run --user-agent ... --agent X若遇到未设置 ACP 支持的目标 Agent,会快速失败并给出清晰报错。CLI 端的 bridge 校验还会额外验证目标 Agent 名单与桥接器种类匹配(见 src/harbor/cli/jobs.py)。官方 ACP 注册表是"哪些 Agent 说 ACP、如何启动"的权威来源,但 Harbor 在运行时并不查询它;合法的--agent目标 = "Harbor 自带" ∩ "支持 ACP"——Harbor 仍然负责被评估 Agent 的安装、版本、认证与日志解析。

注意:Agent 在被以 ACP 模式生成前必须非交互认证(通过既有--ae管线注入 API Key)。


七、ACP 客户端策略:.acpxrc.json与权限处理

7.1 配置文件的生成

.acpxrc.json是 acpx 自己的项目级配置文件;acpx 从工作目录自动发现它,因此 trial 内每次acpx调用都读取同一策略。Harbor不在仓库中手写或提交它,而是在 trial setup 时动态生成(容器内、每 trial 一份、随容器销毁)。它是派生产物而非第二事实来源:人类只在 CLI 上命名一次 Agent(--agent gemini-cli),Harbor 翻译成文件:

--agent gemini-cli → GeminiCli.acp_command() → ["gemini","--acp"] → .acpxrc.json { agents.target = {command:"gemini", args:["--acp"]}, defaultAgent:"target", ... }

没有双重指定:agents.target由--agent计算而来,从不与它并列维护。策略字段带有合理默认值:defaultPermissions: "approve-all"、ttl: 0、format: "quiet"、宽松timeout。对应的 Python 实现是build_acpx_config()(src/harbor/bridges/acp.py),其默认timeout为 3600 秒(DEFAULT_ACPX_TURN_TIMEOUT_SEC),并预留agents与defaultAgent两个保留键(RESERVED_ACPX_CONFIG_KEYS),防止用户覆盖。

7.2 覆盖策略:acp_client_config与--bridge-kwarg

要覆盖默认策略,人类走 Harbor 而不是生成文件:一个透传字典acp_client_config(例如{defaultPermissions: "deny-all", timeout: 1800})在写文件时被合并到默认值之上。该字典与 acpx 的配置键一一对应,Harbor 不发明自己的词汇、无需维护翻译表。CLI 端通过可重复的--bridge-kwarg/--bk(key=value格式,见 src/harbor/cli/jobs.py)或 job 配置文件中的bridge.kwargs传入。

跨 trial 变化策略(例如做"权限拒绝"型评测)因此是 Harbor 侧的可调旋钮,而不是用户 Agent 运行时能控制的东西。桥接器加载配置时会拒绝保留键、拒绝未知 kwarg(extra="forbid"),这些约束由单元测试test_config_file_rejects_reserved_key、test_unknown_kwarg_rejected守护(见 tests/unit/test_simulated_user.py)。

7.3 权限与"两层交互"模型

acpx prompt "..."会阻塞整个回合(像任何长时 shell 命令),用户 Agent 的调用被挂起直到回合解决,随后一次性收到合并回复与退出码。这里有两层交互需要区分:

  • 单次调用内(目标 Agent ↔ acpx):思考、工具调用与权限请求。全部由 acpx 在用户 Agent 挂起期间内部处理,不会冒泡上来。
  • 跨调用(用户 Agent ↔ 目标):对话消息。一次acpx prompt恰是一条消息,用户 Agent 只在回合边界参与。

权限请求属于第一类。应答它的 ACP 客户端是acpx 而非用户 Agent——用户 Agent 位于 acpx 上游、阻塞在子进程等待中,无法在调用中途应答。acpx 依据.acpxrc.json钉住的策略解决它,只有回复内容(可能还有退出码)会变化:

user agent runs: acpx prompt "do X" ─── shell call BLOCKS ─────────────────────┐ acpx → session/prompt → target │ target → tool_call acpx logs it │ user agent target → request_permission ───────→ acpx answers per its policy │ suspended target → agent_message_chunk acpx accumulates text │ the whole time target → result {end_turn} ───────→ acpx returns consolidated text, exit 0 ─┘
  • approve-all(本补丁默认):每个请求自动放行 → 回复 + 退出码 0。
  • deny-all:每个工具自动拒绝;目标 Agent 自我调整或放弃,回合仍会完成 → 回复描述局限,退出码 0。
  • approve-reads(acpx 自身默认):读自动放行,写/执行落入nonInteractivePermissions(deny→ 拒绝、回合完成;fail→ 提示中止、非零退出)。注意:默认策略会阻止目标 Agent 编辑文件,这正是本补丁钉住approve-all的原因。

在任何情况下,用户 Agent 的体验形状都一样:阻塞 → 读取文本 + 退出码;它永远看不到权限对话框。让模拟用户当审批人(IDE"点按钮"流程)在技术上可行(ACP 会把权限请求挂起到客户端应答为止),但需要自定义交互式客户端而非 stock acpx 的无头自动解决,被推迟到未来工作。

7.4 为什么不用 acpx 的内置 Agent

acpx 自带的内置 Agent 要么假定 Agent 已在PATH(无版本控制),要么自钉到 acpx 自己的包版本范围(版本由 acpx 而非 Harbor 决定)。Harbor刻意不用它们,而是注册自己的命令为自定义agents.target条目(优先级高于任何内置)。自持安装/启动换来四个内置做不到的好处:

  • 可复现性:acp_install()钉住精确适配器版本(如@zed-industries/claude-code-acp@<version>),不继承 acpx 当时解析到的版本。
  • 一次安装、两种模式:acp_install()在 Agent 正常setup()之上叠加,acp_command()只是用 ACP 模式启动那个已装好的二进制;依赖 acpx 内置则意味着同一工具二次并行安装(Harbor 的用于普通 trial、acpx 的用于 ACP trial),版本还可能不同。
  • 认证一致性:Harbor 安装的 Agent 读取 Harbor 已通过--ae铺设的同一批密钥,ACP 运行与普通运行认证方式完全相同。
  • 覆盖面与稳定性:acpx 只有约 19 个内置,Harbor 自带更多,还有永远不会进 acpx 注册表的内部与外部(--agent-import-path)Agent。acp_command()把"说 ACP"与"是 acpx 内置"解耦,并隔离注册表变动(gemini 的 ACP 标志已从--experimental-acp迁移到--acp一次)。

对 gemini 这类原生 Agent,acp_command()恰好与 acpx 内置一致、acp_install()为空操作——这一行冗余是代价;收益是 acpx 被降级为 Harbor 可控命令的"哑执行器":生成的.acpxrc.json是 acpx 的格式,但其中每个值都追溯到 Harbor 持有的来源。

7.5 acpx 的安装与固定

桥接器的setup()依次:安装 acpx(install_acpx,src/harbor/bridges/acp.py)→ 运行目标acp_install()→ 写入.acpxrc.json→ 执行acpx sessions ensure启动会话。acpx 安装逻辑会先补齐curl/bash前置(兼容 apt-get / apk / dnf 各发行版),需要时安装 Node 22,再用npm install -g acpx@0.11.2(ACPX_NPM_VERSION常量)安装钉死版本,并把 acpx 固定到它所属的 Node 版本(pinned_bin_wrapper_command)。前置缺失时的报错行为由单元测试test_reports_missing_prerequisite_without_package_manager验证(tests/unit/test_simulated_user.py)。


八、CLI 参数速查与实战示例

8.1 v1 新增的 CLI 标志

标志说明
--user-agent <agent>扮演模拟用户的 Agent。本补丁将 RFC 0002 的--user重命名而来。
--user-model <model>模拟用户的模型。
--user-persona-path <path>persona 文本文件,注入{{ persona }}。默认:内置 persona。
--user-prompt-template-path <path>用户 Agent 提示词的 Jinja2 模板,织入 persona/goal、固定 acpx 机制({{ bridge_instructions }})与任务({{ instruction }})。默认:内置模板。
--bridge <kind>连接模拟用户与目标的协议桥接器,当前仅acp。--user-agent必需。
--bridge-prompt-path <path>教授用户 Agent 如何使用桥接器的纯文本指令。默认:内置 ACP 指令。
--bridge-kwarg/--bk(可重复)覆盖一个 acpx 客户端策略键(如defaultPermissions=deny-all、timeout=1800),合并进生成的.acpxrc.json(即acp_client_config)。
--user-agent-kwarg/--uk(可重复)附加的模拟用户 Agent kwarg(key=value)。

CLI 组装逻辑在 src/harbor/cli/jobs.py:--user-agent需要--bridge;未指定时会保留 job 配置中既有的user_agent与 bridge 字段;对已存在的user_agent,--user-model等只做单键更新。配置校验中user_agent的名字与import_path互斥(src/harbor/cli/trials.py),并会被纳入 preflight 校验。

推迟到后续迭代的能力包括:--uk/--ue形式的 per-user-agent kwargs/env 完整镜像(配合外部 user/target Agent 导入路径)、让用户/ACP 会话存活到验证器阶段(以便 SWE 任务中用户 Agent 根据 Agent 实现来调整验证器测试)、以及随功能成熟的其他参数。

8.2 实战示例(来自仓库文档)

Hello World(源自 docs-mintlify/jobs/simulate-a-user.mdx):

harbor run \ -t hello-world/hello-world \ --agent claude-code --model anthropic/claude-sonnet-5 \ --user-agent claude-code --user-model anthropic/claude-sonnet-5 \ --bridge acp

带自定义 persona 的 SWE-Interact 任务示例:

harbor run \ -p examples/tasks/deepswe_tomlkit-toml-table-converters \ --agent claude-code --model anthropic/claude-sonnet-5 \ --user-agent claude-code --user-model anthropic/claude-sonnet-5 \ --user-persona-path examples/tasks/deepswe_tomlkit-toml-table-converters/persona.md \ --bridge acp

⚠️ 模拟用户 trial 可能运行很长时间(上述示例约需 50 分钟)。

job 配置文件中的等价形式(user_agent+bridge字段,来自 tests/unit/test_simulated_user.py 的test_job_forwards_nested_config):

user_agent: name: claude-code user_prompt_template_path: /path/to/user.j2 bridge: kind: acp

8.3 运行期约束

  • 桥接器目标名单:当前 ACP 桥接器支持claude-code、gemini-cli、codex、opencode作为目标 Agent;其余 ACP 注册表 Agent 尚未接入 Harbor。用户 Agent 可以是任意 Harbor Agent(docs-mintlify/jobs/simulate-a-user.mdx)。
  • 同 Agent 版本冲突:两个角色共享一个容器(一条 PATH/安装前缀),同一 Agent 的两个版本无法共存——后装的会静默胜出。validate_user_agent_version_pin(src/harbor/trial/simulated_user.py)会拒绝"用户 Agent 钉了与目标不同的同 Agent 版本";未钉版本的用户 Agent 则没问题,它运行目标安装的版本。测试见 tests/unit/test_simulated_user.py。
  • 与 load_trajectory 互斥:agent.load_trajectory不能与user_agent组合(src/harbor/models/trial/config.py)。

九、轨迹、指标与日志

  • 轨迹转录:v1 通过acpx sessions export记录原始 ACP 会话(JSONL)。桥接器在export_trajectory中先acpx sessions close再导出到 trial 日志目录;非挂载环境会download_file回宿主(src/harbor/bridges/acp.py),默认文件名bridge-trajectory.json(src/harbor/bridges/base.py)。
  • 目标 Agent 用量:extract_target_usage深度遍历会话导出,找回最后一个 token 用量映射,写入AgentContext.metadata["acp_target_usage"](src/harbor/bridges/acp.py 与enrich_context),由测试test_context_enrichment验证(tests/unit/test_simulated_user.py)。
  • 环境变量合并优先级:目标 Agent 的凭据在用户 Agent 与 bridge 环境之后最后应用,确保两角色共享同一密钥时目标总是看到自己解析后的凭据(src/harbor/trial/trial.py)。
  • 生命周期守护:桥接器关闭保证"先导出、后 teardown、只做一次",且 teardown 超时是尽力而为(test_close_exports_then_tears_down_once、test_teardown_timeout_is_best_effort等用例,tests/unit/test_simulated_user.py)。

十、限制与未来工作

  • 隔离:两个 Agent 共享容器,行为不当的用户 Agent 理论上可能触碰工作区,尽管指令禁止。v1 接受这一点;隔离用户 Agent(独立容器、经转发 socket 走 ACP)是未来工作。
  • 指标归属:用户 Agent 的 token/成本走既有AgentContext;目标 Agent 的用量从 ACPusage_update通知尽力恢复(当前实现为从会话导出中提取)。一流的双 Agent 指标是未来工作。
  • 轨迹标准化:v1 记录原始 ACP JSONL 转录;将其映射到 RFC 0001 的 ATIF 格式(该格式已建模多轮 user/agent 交互)是自然的后续步骤。值得一提:claude-code 等 Agent 的既有会话目录(<agent_dir>/sessions/.../*.jsonl)已支持原生转 ATIF 轨迹(见 src/harbor/agents/installed/claude_code.py 的convert_trajectory)。
  • 适配器对齐:ACP 适配器(claude-code、codex)在功能上可能滞后于其原生 CLI。

十一、相关工作与定位

  • Harbor #1316 / #1462:提供对/solution有 oracle 访问权、由 Harbor 编排轮次的一等User抽象。本 RFC 用更小的机制解决同一需求:用户是未修改的既有 Agent,对话由其自身智能体循环经 ACP 驱动,而非编排好的轮次。
  • Harbor Cookbook 的 simulated-user recipe:在任务层面把用户模拟成暴露ask_user工具(由 persona 文件支撑)的 MCP 服务器。今天无需修改即可配合 Harbor 使用,但用户是反应式的(只在 Agent 询问时回答),且每个任务都得捆绑该服务器;本 RFC 让用户成为驱动对话的一等 Agent。
  • acpx:无头 ACP CLI 客户端,架构与本方案一致(按会话持管的后台进程 + Unix socket 上的薄 CLI)。
  • BenchFlow:同样使用 ACP 驱动带模拟用户的 Agent 评测。
  • τ-bench:基准文献中成熟的 LLM 模拟用户多轮评测方案;本 RFC 的贡献是提供一种极简、协议标准的方式,在 Harbor 的 trial 生命周期内对任意 Agent 运行这类评测。

附:元信息与延伸阅读

字段值
StatusDraft
MaintainerKobe Chen
DateJune 2026
Changelogv0.1(原 RFC)/ v1(补丁,将 ACP 客户端收窄为 acpx)

关联的仓库路径:RFC 原文 rfcs/0002-simulated-users.md,补丁 rfcs/0002-simulated-users-patch.md,官方文档 docs-mintlify/jobs/simulate-a-user.mdx,核心实现 src/harbor/bridges/acp.py、src/harbor/trial/simulated_user.py、src/harbor/trial/trial.py,配置模型 src/harbor/models/trial/config.py、src/harbor/models/bridge.py,CLI 参数 src/harbor/cli/jobs.py,Agent ACP 钩子 src/harbor/agents/protocols/acp.py 及各 installed Agent,测试 tests/unit/test_simulated_user.py。

【免费下载链接】harbor

Framework for evaluating and improving agents

项目地址:https://gitcode.com/gh_mirrors/harbor17/harbor
点击查看免费下载

相关推荐

上一篇:WinXP:Web版Windows XP桌面模拟器完整指南
下一篇:突破物理模拟瓶颈:MuJoCo物体碰撞外力精准获取指南

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询