ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

拆解 harness9(7):SubAgent 系统——从 Registry 到 task 的 Go Agent 配置骨架

拆解 harness9(7):SubAgent 系统——从 Registry 到 task 的 Go Agent 配置骨架 1. 先搞清楚 harness9 的 SubAgent 到底在解决什么问题如果你正在用 Go 写 Agent大概率遇到过这个场景主 Agent 读十个文件、跑五次 bash、反复试错中间过程全塞进对话历史token 预算被吃掉一大半后续推理质量还跟着下降。harness9 的 SubAgent 系统就是冲着这个痛点来的——把边界清晰的子任务整体外包出去只拿回一份简洁结论。harness9 是一款 Local-First、轻量级、生产可用的通用 Go Agent 框架。它的 SubAgent 不是新造的执行器而是运行在隔离 Session 上的普通engine.AgentEngine实例复用RunStream流水线不改 runLoop 一行代码。创建 SubAgent 只有两条路内置编程式注册general-purpose和.harness9/agents/*.md文件式定义二者统一进 Registry。委派也只有两条路主 LLM 通过task工具基于语义自主决策或用户用agent直接绕开 LLM 前台直跑。这篇聚焦落地配置以 Go Agent 为背景梳理 Registry 注册与 task 分发的关键配置项给出可复制的config.toml骨架与settings.json片段并说明如何通过统一 Key/API 通道完成接入与验证。适合已经跑通基础 Agent 循环、想进一步拆分任务边界的 Go 开发者。2. 接入前的准备统一 Key/API 通道在写配置之前先把模型通道打通。harness9 本身不绑定特定 provider它通过统一的 Key/API 通道调用模型。我试过用 TaoToken 作为统一入口好处是主 Agent 和 SubAgent 共用一套 Key不用为每个 SubAgent 单独配 provider。你需要先拿到 API Key。访问控制台创建控制台入口https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewriteAPI Keys 管理https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite拿到 Key 之后API 基地址用https://taotoken.net/api注意这个地址不加 UTM 参数直接作为 base_url 使用。模型名按你实际需要的填比如openai/gpt-4o这类格式具体以控制台模型列表为准。注意Key 只放在环境变量或本地配置文件里不要硬编码进 Go 源码提交到仓库。harness9 的配置文件支持从环境变量读取后面 config.toml 里会体现。这一步做完主 Agent 和 SubAgent 就共享同一条模型通道了。SubAgent 的Model字段留空时继承父代理模型填了则覆盖——但底层走的还是同一个 base_url 和 Key。3. 可复制的 config.toml 骨架harness9 的配置分两层全局的config.toml管模型通道和运行参数项目侧的.harness9/agents/*.md管 SubAgent 定义。先看 config.toml 骨架。# config.toml —— harness9 全局配置骨架 [provider] # 统一 Key/API 通道主 Agent 与 SubAgent 共用 base_url https://taotoken.net/api api_key ${TAOTOKEN_API_KEY} # 从环境变量读取勿硬编码 model openai/gpt-4o # 默认模型SubAgent 未指定时继承 [engine] max_turns 50 # 主 Agent 默认最大轮数 tool_timeout_sec 60 # 单个工具调用超时task 前台执行会绕开此限制 work_dir . # 工作目录SubAgent 的 promptBuilder 会写入 system prompt [subagent] enabled true agents_dir .harness9/agents # 文件式定义扫描目录不存在则静默跳过 allow_background true # 是否允许 task(backgroundtrue)几个关键点值得展开。api_key用${TAOTOKEN_API_KEY}占位启动前export TAOTOKEN_API_KEY你的Key即可。tool_timeout_sec是父工具的超时但 SubAgent 前台执行时 Runner 会派生独立的 execCtx绕开这个 60s 限制——否则一个多步骤子任务很容易被父超时掐断。agents_dir指向的目录不存在时LoadFromDir静默返回 nil零配置也能跑。对应的settings.json片段如果你的项目用 JSON 管理运行时开关{ harness9: { provider: { baseUrl: https://taotoken.net/api, apiKeyEnv: TAOTOKEN_API_KEY, defaultModel: openai/gpt-4o }, subagent: { enabled: true, agentsDir: .harness9/agents, allowBackground: true, denyRecursive: true }, hooks: { denyTaskInSubAgent: true } } }denyRecursive和denyTaskInSubAgent对应的是 ResolveTools 里硬编码移除 task 的那层防御配置里显式打开只是让意图更清楚——即使配置漏了代码层也会强制移除。4. 定义第一个 SubAgent文件式注册进 Registry配置就绪后创建一个 SubAgent 定义文件。在项目根目录建.harness9/agents/security-auditor.md--- name: security-auditor description: 安全审计专家。对涉及认证、鉴权、输入校验的代码变更后使用。 tools: read_file, bash disallowed_tools: write_file, edit_file model: openai/gpt-4o max_turns: 30 skills: security-review --- 你是一名应用安全工程师专注于识别代码中的安全漏洞。 审查时按优先级输出严重 高危 中危 低危每条附上 CWE 编号与修复建议。 不要修改文件只输出审查报告。这个文件在 harness9 启动时被Registry.LoadFromDir扫描加载。解析逻辑在parseAgentFile里是个手写解析器——按---\n定界符切出 frontmatter逐行按:切分 key/value列表字段按逗号拆分。没引入 YAML 库因为 frontmatter 字段集合固定又扁平。注册进 Registry 后task工具的subagent_type枚举会自动包含security-auditor。因为Definition()每次调用都动态生成把Registry.List()里所有 SubAgent 的 Name 塞进 enum 数组——新增一个 md 文件不用改任何 schema 代码。文件式定义还有个覆盖规则同名文件定义会覆盖编程式定义记日志不报错。所以想改内置general-purpose的行为写个.harness9/agents/general-purpose.md就行不用碰 Go 代码。5. 验证请求跑通一次 task 委派配置和定义都就位后启动 harness9在主对话里让主 LLM 发起一次委派。你可以直接输入自然语言帮我审查 internal/auth 目录下的代码重点看输入校验和鉴权逻辑。主 LLM 会自主决策调用task工具参数大致是{ subagent_type: security-auditor, description: 审查 auth 目录, prompt: 审查 internal/auth 目录下所有 .go 文件重点检查输入校验、鉴权逻辑、SQL 拼接。文件路径internal/auth/。要求按严重程度分级输出附 CWE 编号。, background: false }前台执行时TaskTool.Execute直接调用runner.Run(ctx, def, prompt, false)同步等结果把FinalText包进 XML 风格字符串返回task statecompletedtask_result...审查报告.../task_result/task父代理下一轮立即能读到这份报告。如果你想要后台异步跑把background设为trueExecute 会立即返回一个句柄task idtask-security-auditor-1 staterunning/真正的结果走 TaskTracker在下一次dispatch()前通过DrainCompleted()排空、拼进 LLM 的 prompt 前缀。想直接验证模型通道是否通可以先用模型对话页面发一条简单请求模型对话https://taotoken.net/model-chat?utm_sourcetaotoken_aicg_blog_endutm_contentmodel-chatutm_campaignrewrite确认返回正常再回到 harness9 里跑委派能排除掉通道层面的干扰。6. 本篇常见错排查报错一未知SubAgent类型 security-auditor可用: general-purpose说明文件没被加载。检查三点.harness9/agents/目录是否在work_dir下文件名是否以.md结尾frontmatter 是否以---\n开头parseAgentFile对起始分隔符敏感前面有空格或 BOM 都会失败。单文件解析失败只记 warning 不中断所以启动日志里翻一下有没有 warning。报错二SubAgent 执行到一半被超时掐断前台执行时 Runner 会派生独立 execCtx 绕开父工具的 60s 超时但如果你在 SubAgent 定义里把max_turns设得太小或者子任务本身步骤过多还是可能提前结束。把max_turns调到 30 以上同时确认tool_timeout_sec不是卡在 10s 这种激进值。报错三后台任务一直 running结果不回来后台执行审批一律 fail-closed——没有 TUI 通道可弹审批对话框时自动拒绝。如果 SubAgent 定义里包含需要审批的高危工具比如bash执行写操作后台任务会因权限不足失败。解决办法是前台跑或者把 SubAgent 的tools白名单收窄到只读工具。报错四SubAgent 说看不到上下文这是设计约束不是 bug。SubAgent 启动时对父对话一无所知prompt参数是父子之间唯一的信息通道。文件路径、背景信息、任务要求全得靠主 LLM 显式写进 prompt 字符串。如果发现子任务跑偏先检查主 LLM 生成的 prompt 是否足够完整。报错五想递归委派但被拒绝ResolveTools硬编码把task塞进 denied mapdenyTaskHook又额外拦一层。SubAgent 无法再创建 SubAgent这是双重防御。如果你确实需要多级委派得在主 Agent 层面拆成多次串行 task 调用而不是让 SubAgent 自己再派。7. 长期编码与 Agent 场景的接入建议如果你打算把 harness9 用在长期编码或 Agent 流水线里几个配置习惯值得养成。SubAgent 的tools白名单尽量收窄。ResolveTools的三步收窄算法是白名单∩全集 - 黑名单 - task输入是父代理的可用工具集所以 SubAgent 权限永远不会越过 MainAgent。但白名单留空等于继承全集专门化角色还是显式列出工具更安全。模型覆盖按需开。Model留空继承父代理模型填了则覆盖。安全审计这类需要强推理的子任务可以单独指定更强的模型而文档撰写这类轻量任务用默认模型就够。底层走的还是同一个 base_url 和 Key不用额外配通道。后台任务配合 TaskTracker 用。TaskTracker用sync.Mutex替代 channel 管后台任务状态从根上规避 send-on-closed-channel 风险。后台任务适合我不想等交给系统去跑的场景但记得审批是 fail-closed 的高危操作别指望后台自动放行。需要长期跑编码 Agent 的话Coding Plan 页面有更完整的接入说明Coding Planhttps://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite接入文档里对 Registry 注册、task 分发、ResolveTools 权限收窄都有对应章节配置卡住时可以直接对照接入文档https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewriteSubAgent 最核心的价值就是一个词——隔离。创建阶段用 Registry 划定存在哪些 SubAgent的边界委派阶段用一个普通 task 工具划定如何发起委派。ResolveTools 隔离权限MemorySession 隔离上下文。把这两层隔离配好主 Agent 的上下文窗口就能省下来干更重要的推理。
返回列表