OpenHuman Researcher Agent 系统提示词解析:文档与网页爬虫的搜索—抓取研究循环
【免费下载链接】openhumanOpenHuman is an open source personal AI for Mac, Windows and Linux — local-first memory, agent orchestration, and deep research.项目地址: https://gitcode.com/GitHub_Trending/op/openhuman
导读
本文围绕 OpenHuman 内置Researcher(researcher)子代理的系统提示词展开,逐条拆解其 Capabilities、Rules、Research Loop Contract、Output Contract 与 Long-horizon Artifacts 五段式设计,并结合 agent.toml、graph.rs、prompt.rs 与底层web_search_tool/web_fetch工具实现,说明该代理如何被设计成一个"纯函数式"的搜索—抓取专用研究单元。读完本文,你将理解该提示词每一段的工程动机、与源码配置的对应关系,以及它如何控制幻觉、压缩上下文与长程任务的手交接力。
Researcher 在 OpenHuman 中的定位是:任何需要查阅外部知识(真实文档、API 签名、最新资料)的任务,由编排器(orchestrator)委托给该代理完成。它的座右铭是"读真实文档,不要猜"——正是这条原则决定了它的工具白名单、输出契约与上下文省略策略。
一、Researcher 的身份与能力声明
提示词开篇两行即为代理定义身份:
You are theResearcheragent. You find accurate, up-to-date information.
随后用一段Capabilities明确其全部能力边界——只有两个工具:
web_search_tool:网络搜索,用于定位最新信息源;web_fetch:HTTP 请求抓取文档页面正文。
这份能力声明与 agent.toml 的[tools]白名单一一对应:
[tools] named = [ # Keep the default researcher narrow: search to locate sources, fetch to read # selected pages. Deep Parallel, market, filesystem, and general HTTP/curl # tools belong to more specific agents so simple research tasks don't expand # into open-ended search loops. "web_search_tool", "web_fetch", ]配置注释解释了这种"窄化"的工程动机:Deep Parallel、市场数据、文件系统以及通用 HTTP/curl 类工具被刻意排除在外,归属到更专门的代理(如code_executor、planner、presentation_agent等)名下,从而避免一次简单的研究任务膨胀成无休止的搜索循环(open-ended search loop)。工具白名单本身即是提示词约束的硬件级背书——模型即使被诱导也不会拿到白名单外的工具。
值得注意的还有 prompt_tests.rs 中的回归测试:
assert!( !body.contains("file_read") && !body.contains("file_write"), "researcher must not advertise workspace tools outside its search+fetch allowlist" );该测试直接断言 Researcher 的系统提示词中绝不出现工作区文件读写工具的广告词,从测试层面锁死"搜索+抓取专用"的边界。
二、五条行为规则:反幻觉的硬约束
提示词的Rules部分是该代理的核心行为准则:
- Read real docs— 不猜测 API 签名或库的用法,必须查证;
- No hallucination— 找不到答案就明说,绝不编造 URL 或 API;
- Compress output— 将长文档蒸馏为密集、事实性的 Markdown 摘要;
- Cite sources— 引用信息时必须附上 URL 或文件路径;
- Stay focused— 只回答被问到的具体问题,不扩散到边缘话题。
这五条规则共同构成了防幻觉(anti-hallucination)的三道防线:查证(Read real docs)、如实报告(No hallucination)、可追溯(Cite sources)。其中"Stay focused"与前文工具白名单的窄化意图一脉相承——既限制工具面,也限制话题面,确保子代理不喧宾夺主。
从实现角度看,这些规则并非空泛口号:web_fetch工具本身带有安全与限额实现(见下文"工具纵深"),其响应前缀包含状态码与最终 URL(final URL),模型可以据此验证"我真的读到了目标页面,而不是被重定向到别处",从而支撑 "Cite sources" 规则的可信度。
三、Research Loop Contract:搜索—抓取循环的收敛契约
Research Loop Contract定义了 Researcher 的核心工作流——搜索与抓取如何编排、何时停止:
- 流程:没有具体 URL 时先用
web_search_tool定位候选来源,再用web_fetch只读取回答问题所需的页面; - 最小成本原则:简单事实性问题,一次聚焦搜索 + 一两个抓取源即可,除非结果为空或互相矛盾;
- 收敛约束:一旦获得有源依据的证据,不得继续扩大范围、重复搜索或追逐支线;
- 权威优先:优先抓取权威/一手来源,而非大量二手摘要;
- 失败处理:搜索或抓取失败时,在
Failed tool calls下如实返回发生了什么,不得静默地用无关查询反复重试。
这一契约实际上定义了一个带终止条件的迭代循环:收敛条件 = "有 source-backed evidence";终止条件 = "证据已足 或 明确的失败"。它把 LLM 常见的过度搜索(over-search)行为通过显式指令约束掉,使 Researcher 在max_iterations = 10的预算内高效收尾。
底层实现中,这个循环由两个内置工具支撑。web_search_tool在 src/openhuman/search/tools/web_search.rs 中实现,它基于服务端 Parallel 集成代理(server-side Parallel integration proxy)执行搜索,并将结果属性归因到具体搜索引擎提供商(managed provider),默认标签为 Exa(MANAGED_DEFAULT_PROVIDER)。工具内置max_results与timeout_secs上限,并且在每次调用前会校验会话 JWT 是否新鲜(避免用过期令牌发请求、触发竞态式会话注销,参见resolve_client对 #5873 的处理注释)——这正是"失败处理"契约在实现层的具体体现:宁可调用前刷新令牌,也不让一次搜索因 401 意外撕毁整个会话。
web_fetch在 src/openhuman/tools/impl/network/web_fetch.rs 中实现,代码注释明确其定位:
web_fetchis the single-purpose "GET and read" primitive the agent reaches for when researching: returns the response body as text, capped, with a tiny preamble (status + final URL).
它与http_request(完整的 method/header 表面)和curl(写入磁盘)刻意区分,是研究场景专用的"获取即读"原语:返回正文纯文本、有大小上限、附带状态码与最终 URL 的前缀信息。抓取限额默认值取自HttpRequestConfig::default()(max_bytes与timeout_secs),并且对Some(0)这类陈旧/非法配置做了运行时钳制(clamp)并记录告警日志,保证任何情况下抓取都不会瞬时失败或截断为 0 字节。
四、Output Contract:编排器可消费的紧凑综合
Output Contract解决的是子代理与编排器之间的接口问题——Researcher 永远不能只留下工具调用或内部笔记就结束回合:
- 无论答案是否完整,必须向编排器返回输出;
- 能回答时:答案优先,随后列出用到的 URL 列表;
- 不能回答时:精确说明缺什么、试过什么;
- 绝不以纯工具调用或内部笔记收尾,编排器需要一份可以继续传递或直接评估的紧凑综合(compact synthesis)。
这个契约将 Researcher 明确定位为无状态的信息查询函数:输入一个聚焦问题,输出一个带来源引用的浓缩答案。答案前置(lead with the answer)的设计便于编排器直接透传或提炼,而"列出用到的 URL"与 Rules 中的 "Cite sources" 互相呼应,形成端到端的可追溯链条。
从 prompt.rs 的实现看,build()按固定顺序组装最终系统提示词:先写入prompt.md原文(ARCHETYPE,通过include_str!编译期嵌入),再追加用户文件渲染(render_user_files)与工具渲染(render_tools)——输出即模型实际看到的完整提示词,运行期零后处理。这意味着上述所有契约都是提示词的有机组成部分,而非运行器附加的硬编码行为。
五、Long-horizon Artifacts:长程任务的手交接力策略
Long-horizon Artifacts是提示词中针对"长程(多轮)任务"的专门设计。Researcher 被明确为search-and-fetch only代理——它自己从不写文件,但它要管理交接体积(keep the handoff small):
- 答案+来源优先:把冗长档案(long dossier)直接粘贴进回复,会在长程任务的后续每一步都消耗编排器的上下文窗口;
- 大综合外置:若综合结果确实很大,harness 会把它持久化到 action 目录下的
outputs/文件夹,交给编排器的只是一个路径 + 摘要(abstract),而非全文。回复的开头几行必须能独立充当该摘要; - 委托工件回引:如果委托任务给了你一个工件路径,将该路径视为记录源(source of record),在回答中引用路径而非重新粘贴其内容。
这条契约体现了 OpenHuman 对token 预算的工程化思考:子代理的输出在长程任务中是上游上下文的输入,输出越膨胀、后续每一步的推理成本越高。把大输出"落盘 + 路径化"而非"直塞上下文",是典型的上下文压缩策略——与仓库中 docs/plans/2026-08-31-prompt-token-budget.md 所讨论的提示词 token 预算控制方向一致。
六、自定义图拓扑:三段式研究执行流
提示词定义的搜索—抓取循环在运行期由一段自定义图拓扑驱动。graph.rs 实现了 OpenHuman 中第一个AgentGraph::Custom拓扑,其注释写道:
This graph owns the first per-agent
AgentGraph::Customtopology: route the research task, execute the shared turn leaf, then finalize the result.
图拓扑由三个阶段组成(RESEARCHER_GRAPH_PHASES):
route_research → run_research_turn → finalizeroute_research:路由研究任务(入口节点);run_research_turn:执行共享的子代理回合叶节点——调用subagent_runner::run_agent_turn_request_via_default_graph跑模型/工具循环;finalize:收尾(结束节点)。
关键设计在于:模型/工具循环本身复用了默认运行器的共享回合叶节点(run_agent_turn_request_via_default_graph),因此 transcript 持久化、进度事件、handoff 中间件与 usage 汇总(usage rollup)与默认运行器完全一致;自定义的只是外层拓扑。run_researcher_graph还会挂载GraphTracingSink生成agent:researcher:{task_id}标签的追踪信息,并在完成后记录visited阶段序列的 debug 日志。AgentGraph::custom的注册入口定义在 src/openhuman/agent/harness/agent_graph.rs。
七、agent.toml 关键参数逐项解读
agent.toml 是 Researcher 的注册清单,各参数与提示词契约的对应关系如下:
| 参数 | 值 | 工程含义 |
|---|---|---|
id/display_name | researcher/Researcher | 注册 ID 与展示名 |
delegate_name | research | 编排器委托子代理时使用的短名 |
when_to_use | Web & docs crawler… | 编排器的路由提示词:任何需要查外部知识的任务 |
temperature | 0.4 | 偏低的采样温度,抑制发散、倾向事实性输出 |
max_iterations | 10 | 模型/工具循环的最大迭代次数,配合收敛契约 |
iteration_policy | extended | 扩展迭代策略(IterationPolicy::Extended,见 definition_part_01.rs) |
max_turn_output_tokens | 4096 | 单回合输出 token 上限,与"压缩输出"规则呼应 |
max_result_chars | 8000 | 结果字符上限 |
sandbox_mode | none | 不启用沙箱(只读、无文件写入的纯函数代理) |
omit_identity/omit_memory_context/omit_safety_preamble | 均true | 省略身份、记忆上下文与安全前导 |
[model] hint | burst | 模型选择提示:短时爆发型算力偏好 |
配置注释特别解释了omit_memory_context = true的设计动机:Researcher 是纯函数式的网页/文档专家,研究任务由编排器直接传入,不需要记忆树预取(no eager memory pre-fetch)——它不需要从长期记忆中取回任何东西,这使它的上下文干净、成本低、延迟低,也从根本上避免了记忆内容对"事实性查询"的干扰。
八、在编排器中的使用方式
在 OpenHuman 的子代理体系中,Researcher 不是用户直接对话的对象,而是编排器按需委托的研究后端。编排器在收到需要外部知识的问题时,根据when_to_use描述与delegate_name = "research"生成委托,把聚焦的研究任务传给 Researcher,并接收其按 Output Contract 返回的紧凑综合。
这一点与提示词中的两条设计互为印证:一是omit_memory_context = true(任务由编排器喂入,Researcher 自己不需要记忆);二是 "Stay focused" 规则(只回答被问到的具体问题)——两者共同保证 Researcher 对每次委托保持"无状态、纯查询"的语义,使同一代理实例可以被安全地反复委托给不同任务。
其他内置代理的注册清单可在 src/openhuman/agent/registry/agents/ 下查看(如planner、code_executor、context_scout、presentation_agent等),Researcher 的窄工具面与它们形成互补:需要真实文档、实时信息时委托research;需要执行代码、规划或展示时委托对应代理。
九、总结:一份把"反幻觉"落到工程细节的提示词
把 Researcher 的提示词与其实现合在一起看,可以提炼出 OpenHuman 设计专用研究子代理的完整方法论:
- 能力面收敛:只有搜索+抓取两个工具,防止研究任务膨胀为开放循环;
- 行为规则显式化:查证、不编造、压缩、引用、聚焦,五条规则互为补充;
- 循环契约化:搜索→抓取→收敛,明确终止条件与失败上报方式;
- 输出接口化:答案优先+来源列表,无答案时精确报缺,保证编排器永远拿得到可消费的综合;
- 上下文节俭:
omit_memory_context、低 temperature、4096 token 输出上限、"大输出落盘+路径化"多管齐下控制长程任务成本; - 实现深度绑定:工具白名单、迭代预算、图拓扑(
route_research → run_research_turn → finalize)与提示词文本共同构成完整行为约束,且由 prompt_tests.rs 的回归测试守护。
这套模式对任何需要在多代理系统中加入"事实查询型"子代理的项目都具有直接借鉴价值——提示词不只是文字,它是与配置、工具、图执行和测试共同作用的完整行为契约。
关键源码索引
- 系统提示词原文
- 代理注册配置 agent.toml
- 自定义图拓扑 graph.rs
- 提示词组装器 prompt.rs
- 提示词回归测试 prompt_tests.rs
- web_search 工具实现
- web_fetch 工具实现
- AgentGraph::custom 注册入口
【免费下载链接】openhumanOpenHuman is an open source personal AI for Mac, Windows and Linux — local-first memory, agent orchestration, and deep research.项目地址: https://gitcode.com/GitHub_Trending/op/openhuman
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考