OpenHuman Context Scout 深度解析:只读预检代理如何用 `[context_bundle]` 为编排器压缩上下文
导读
本文围绕 OpenHuman 内置代理 Context Scout(context_scout)展开,它是一类"只读预检"(read-only pre-flight)代理:在被编排器(orchestrator)执行首轮任务之前,先以极低成本完成记忆、用户画像、已连接集成与联网信息的收集,并返回一个紧凑的 [context_bundle] 数据包。读完本文,你将掌握该代理的三段式工作流、六大只读信息源、输出契约的每个字段语义,以及它在 agent.toml 与 prompt.rs 中的实现细节与安全设计。
一、设计定位:为什么需要"预检代理"
在 OpenHuman 的多代理架构里,编排器承担"思考并行动"的职责,但它每轮可用的上下文窗口是有限的。如果每收到一个用户请求,编排器都自行去翻记忆、查技能、扫集成列表,既浪费 token,也容易把上下文撑爆。Context Scout 的定位正是把"收集上下文"这一步从编排器中剥离出来、前置到一个廉价只读代理上。
从 agent_prepare_context.rs 的模块注释可以看到两种触发方式:
- agent harness 首轮前自动触发:在编排器第一个 turn 之前,harness 先跑一次 Context Scout 完成预检;
- 父代理显式请求:父代理通过调用
agent_prepare_context工具("plan mode as a subagent"),同步地、阻塞式地跑一遍 Context Scout,获得一次临时(ad hoc)上下文收集。
无论哪种方式,Scout 的输出都受 max_result_chars(约 1000 tokens)上限约束,因此父代理的上下文只会以有界的方式增长——这正是该设计的核心收益:用一次廉价预检,换取编排器后续每一轮都站在"信息充分"的起点上。
二、工作流程:收集 → 汇总 → 推荐,然后立即停止
Scout 的角色提示词 prompt.md 明确给出了三段式工作流:
- 读取请求:读取传入的请求,以及调用方可能附加的
[Focus]指令,明确本次预检的靶心。 - 只读收集:仅收集"采取行动真正需要"的信息,而不是漫无目的地罗列。
- 及时停止:一旦信息足够就立即产出结果——绝不尝试回答请求或执行任务,那是编排器的职责。Scout 拥有的每个工具都是只读的,它从不写、不发送、不安装、不执行任何动作。
这一点在 agent.toml 中有硬约束兜底:sandbox_mode = "read_only",并且工具白名单全部是只读工具(详见第五节)。从源码结构看,Scout 被声明为 agent_tier = "worker" 的叶子 worker:它只收集并停止,从不向下委托(没有 [subagents] 块,加载器会在 worker 层拒绝任何子代理)。
三、六大只读信息源
Scout 的收集面覆盖六个来源,每一条都映射到具体的只读工具:
| 信息源 | 工具/载体 | 用途与注意点 |
|---|---|---|
| 记忆(Memory) | memory_recall(按 namespace + query 检索);memory_flavour(读取用户风格/偏好画像的一个 facet) |
只读,绝不能写记忆。memory_flavour 的 facet 包括 communication、coding_style、stack、workflow、environment、directives、anti_preferences,当请求依赖"用户喜欢怎么工作"而非某个具体事实时优先使用它 |
| 历史对话(Past conversations) | 经由 memory_recall 间接访问 |
thread_* 系列与 transcript_search 工具已被移除,因此"用户之前说过什么"只能通过记忆检索触达,而不是线程索引 |
| 目标/画像(Goals / profile) | 注入在 prompt 中的 PROFILE.md 与 MEMORY.md |
这两份用户文件会随系统提示词一起注入(omit_profile = false、omit_memory_md = false),Scout 直接从中挖掘用户声明的目标与偏好 |
| 技能(Skills) | list_workflows(列出已安装技能);skill_registry_search / skill_registry_browse(检索技能注册表) |
若技能明显契合请求,则在 recommended_skills 中上报,交由编排器运行或安装 |
| 已连接集成(Connected integrations) | 系统提示词中的 Connected Integrations 区块 | 直接告诉 Scout 哪些平台(gmail、notion、slack 等)真实接线可用,用于判断请求是否可由某个已连接应用处理 |
| 网络(The web) | web_search_tool / web_fetch |
仅当请求真正依赖新外部事实时才使用;记忆/画像已覆盖时跳过——Scout 被要求"保持廉价"(cheap) |
其中记忆检索的底层实现与编排器的记忆工具同源:Scout 的 memory_recall 走的是 memory/api/provider/retrieval.rs 提供的检索能力(该模块同时承载 FastRetrieveQuery 快路径,命中数上限为 MEMORY_FAST_PATH_LIMIT = 8),但 Scout 侧只暴露只读接口。
四、输出契约:严格单一 [context_bundle] 数据块
Scout 的产出被约束为唯一一个 [context_bundle] … [/context_bundle] 数据块,块外不允许有任何前言或收尾散文。其完整模板如下:
[context_bundle]
has_enough_context: true|false
proposed_goal: <ONE single line — the durable objective this thread should
pursue (what "done" looks like), or `none` for a trivial/one-shot request that
needs no goal. Keep it on this one line; the harness only reads the text on the
same line as `proposed_goal:`.>
summary: <≤ ~700 tokens of distilled, source-attributed context. Lead with what
matters. Attribute facts: (memory), (transcript: <thread>), (profile),
(web: <url>), (integrations).>
recommended_tool_calls:
- tool: <exact orchestrator tool name from the "Orchestrator tools" list>
args: <concrete arg values or a tight sketch>
why: <one line>
recommended_skills:
- skill: <runnable id — for installed skills the `dir_name` slug from
list_workflows (NOT the display name), since run_workflow resolves by that
id; for registry hits the installable entry id from skill_registry_search>
installed: true|false
why: <one line — why this skill fits the request>
[/context_bundle]
各字段语义如下:
has_enough_context:true表示编排器此刻即可行动、无需再收集;false表示关键事实仍缺失(须在 summary 中说明缺什么)。proposed_goal:线程的持久目标("完成"的样貌),而非步骤清单。harness 仅在线程尚未设置目标时才将其记录为线程目标——编排器仍保有权威并可后续细化。对闲聊或一次性琐碎请求,填写none即可,不值得记录目标。注意该字段的解析约定:harness 只读取proposed_goal:同一行上的文本,因此目标必须压缩在单行内。summary:不超过约 700 tokens 的蒸馏摘要,要求先讲重点,并为每条事实标注来源:(memory)、(transcript: <thread>)、(profile)、(web: <url>)、(integrations)。recommended_tool_calls:按编排器应执行的顺序排列的推荐调用。每个tool必须是下方注入的 "Orchestrator tools" 列表中的精确名称——这些是编排器能调的工具,而不是 Scout 自己用过的工具。若已信息充分且答案属知识型、无需更多调用,则返回空列表并置has_enough_context: true。recommended_skills:明确契合请求的技能(工作流)清单。已安装技能使用可运行 id——即list_workflows返回的dir_nameslug(而非显示名),因为run_workflow按该 id 解析(installed: true);注册表命中的技能使用skill_registry_search返回的可安装条目 id(installed: false)。仅当技能真正匹配时才包含,否则整节省略或留空,绝不虚构技能 id。
整个 bundle 有预算上限,应把预算花在 summary、plan 与真正匹配的技能上,而不是含糊其辞的修饰语上。
五、agent.toml 配置逐项剖析
agent.toml 是 Scout 的完整定义文件,关键配置项如下:
id = "context_scout"
display_name = "Context Scout"
when_to_use = "Pre-flight context collector. Reads memory, the user's goals/profile,
connected integrations, and the web, then returns a tight context bundle plus a
recommended plan of next tool calls. Read-only; produces a structured bundle, not actions."
temperature = 0.3
max_iterations = 8
iteration_policy = "extended"
max_result_chars = 5000
sandbox_mode = "read_only"
agent_tier = "worker"
omit_identity = true
omit_memory_context = true
omit_safety_preamble = true
omit_profile = false
omit_memory_md = false
[model]
hint = "burst"
[tools]
named = [ ... ]
temperature = 0.3:低随机性,保证预检输出稳定、可复现。max_iterations = 8、iteration_policy = "extended":注释说明从 6 提升到 8——Scout 如今拥有更宽的只读收集面(transcripts、threads、skills),需要多几步完成"recall → check skills → assess"再产出 bundle 的循环。max_result_chars = 5000:返回 bundle 的字符上限(char-safe)。runner 在交还给父代理前会把最终输出截断到这个长度,从而保证编排器上下文只增长有界量。该值从 4000 提升,为recommended_skills块与 summary、recommended_tool_calls留出空间。sandbox_mode = "read_only":沙箱只读,配合工具白名单构成双重防护。agent_tier = "worker":叶子 worker 层级,禁止向下再委托子代理。- 四个
omit_*开关:omit_identity = true、omit_memory_context = true、omit_safety_preamble = true去掉身份、通用记忆上下文与安全前言;但omit_profile = false、omit_memory_md = false保留PROFILE.md(用户声明的目标)与MEMORY.md(档案员策展的长期记忆)注入——因为 Scout 的整个职责就是让编排器扎根于"用户是谁、想要什么"。 [model] hint = "burst":多步收集循环(recall → 可能 fetch → assess)走高通量的burst层(托管后端解析为burst-v1)。设计意图是:Scout 是廉价、延迟容忍、非推理的预检,高速模型上的原始吞吐优于更贵的 agentic/reasoning 层。
工具白名单的取舍艺术
[tools].named 是精心策展的只读收集面,没有写工具、没有 shell、没有委托。特别值得注意的是 memory_tree 被故意排除:该工具在一个 ReadOnly 声明的包装器下捆绑了写模式(ingest_document → MemoryTreeIngestDocumentTool),若 Scout 自动运行在可注入的输入上,一旦拿到该工具,就可能"边运行只读、边改写记忆(remember this document)"——这等于给提示注入留下立足点。因此用纯检索的 memory_recall 覆盖需求。同理,skill_registry_install / skill_registry_uninstall 被刻意挡在白名单外,只保留三个只读技能工具。
六、系统提示词构建:prompt.rs 的组装流程
prompt.rs 负责在运行时把角色 Markdown 与动态注入块拼装成最终系统提示词。其 build() 流程为:
- 以
include_str!("prompt.md")加载角色提示词(即本文解析的这份文档本体); - 调用
render_user_files注入PROFILE.md与MEMORY.md(由include_profile/include_memory_md门控,runner 依据定义的omit_profile = false/omit_memory_md = false设置); - 调用
render_tools渲染 Scout 自己的只读工具目录; - 调用
render_connected_integrations渲染## Connected Integrations区块——只列出connected == true的平台,空连接时整块省略(见prompt_tests.rs的render_connected_integrations_lists_only_connected测试); - 调用
render_workspace追加工作区块。
而"编排器的工具目录"(Scout 推荐回去的那份)不在这里注入——它由 AgentPrepareContextTool 在 spawn 时注入,prompt.rs 只描述 Scout 自身的收集面。二者职责分离非常清晰。
七、与编排器协作的两个实现细节
1. 跳过通用子代理结果契约
通用子代理会被追加一个 "Result Contract" 后缀(Answer / Evidence used / Actions taken / Open uncertainties / Failed tool calls / Recommended next step)。但在 subagent_runner/ops/prompt.rs 的 append_subagent_role_contract 中,对 context_scout 做了特判跳过:因为 Scout 定义了自己的严格输出契约(只发一个 [context_bundle]),通用契约会与之冲突,导致 Scout 输出通用标题而非 bundle,使编排器拿不到 has_enough_context / recommended_tool_calls。
2. 有界上下文注入
agent_prepare_context.rs 明确记载:Scout 的输出被 max_result_chars 约束到约 1000 tokens,父代理上下文只增长有界量。结合 runner 中的截断逻辑,这是整个"预检"设计能够规模化运作的保障。
八、测试验证与质量保障
prompt_tests.rs 锁定了以下行为:
build_returns_nonempty_body:构建的提示词非空;body_describes_the_context_bundle_contract:提示词必须包含[context_bundle]、has_enough_context、recommended_tool_calls契约关键词;body_instructs_transcript_and_skill_gathering:提示词必须指引通过memory_recall检索历史对话(因thread_*/transcript_search已移除)、必须定义recommended_skills输出块、必须指向list_workflows技能发现;render_connected_integrations_*:集成区块只列已连接平台,全空时返回空字符串。
这些测试与 loader.rs 中对 context_scout 的定义加载校验、以及 agent_prepare_context_tests.rs 对显式调用路径的测试共同构成质量网,防止后续改动悄悄破坏预检契约。
九、延伸阅读
- 代理定义与注册:loader.rs、agents/mod.rs
- 提示词构建基础设施:
src/openhuman/agent/context/prompt.rs(render_tools、render_user_files、render_workspace、ConnectedIntegration等均在此) - 显式调用工具:agent_prepare_context.rs 及其测试
- 子代理运行器:subagent_runner/ops/runner.rs(层级门控
tier_gate_decision与迭代预算)、subagent_runner/ops/prompt.rs(契约跳过逻辑) - 记忆检索后端:
src/openhuman/memory/api/provider/retrieval.rs
小结
Context Scout 是 OpenHuman 多代理体系中"以廉价预检换有界上下文"的关键实践:一条严格的角色提示词 + 一份精心配置的 agent.toml + 一个模板化构建器,共同保证了它只收集、不行动、产出唯一 [context_bundle],并把"下一步该调用编排器的哪些工具"以结构化形式交还父代理。理解它,也就理解了 OpenHuman 如何在多代理协作中控制上下文成本与注入面。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust4.21 K637- DDeepSeek-V4.1-FlashDeepSeek-V4.1-Flash 是一个多模态混合专家(MoE)模型,拥有 5520 亿骨干参数,并支持最多一百万 token 的上下文长度。该模型原生支持图像和文本输入,并以自回归方式生成文本Python320
cherry-studio🍒 Cherry Studio 是一款支持多个 LLM 提供商的桌面客户端TypeScript2 K146
hello-agents📚 《从零开始构建智能体》——从零开始的智能体原理与实践教程Python46567
new-apiAI模型聚合管理中转分发系统,一个应用管理您的所有AI模型,支持将多种大模型转为统一格式调用,支持OpenAI、Claude、Gemini等格式,可供个人或者企业内部管理与分发渠道使用。🍥 A Unified AI Model Management & Distribution System. Aggregate all your LLMs into one app and access them via an OpenAI-compatible API, with native support for Claude (Messages) and Gemini formats.Go20043
JeecgBoot🔥企业级低代码平台集成了AI应用平台,帮助企业快速实现低代码开发和构建AI应用!前后端分离架构 SpringBoot,SpringCloud、Mybatis,Ant Design4、 Vue3.0、TS+vite!强大的代码生成器让前后端代码一键生成,无需写任何代码! 引领AI低代码开发模式: AI生成->OnlineCoding-> 代码生成-> 手工MERGE,显著的提高效率,又不失灵活~Java33951