7. 进入 harness

本章向 harness 的 IToolRegistry 注册一个模型可调用的工具,并观察工具流水线的结果。 示例不需要 API 密钥,也不会调用模型。

工具插件

using Microsoft.Extensions.AI;
using Tether.Core;

ctx.Plugin(Plugin.From(c =>
{
    var registry = c.Require<IToolRegistry>();

    var tool = AIFunctionFactory.Create(
        (string name) => $"Hello, {name}!",
        name: "greet",
        description: "Greet the named person.");

    var registration = registry.Register(tool);
    c.Effect(registration.Dispose);       // 工具注册随插件卸载而注销
}, typeof(IToolRegistry)));               // inject:注册表就绪前保持 PENDING

这里的每个模式都来自前几章:typeof(IToolRegistry) inject (第 3 章)让插件等待工具注册表就绪; Register 返回的 IDisposable 交给 ctx.Effect (第 2 章),卸载时注销工具。 AIFunctionFactory 对应 dsh 的 defineTool:从方法签名推导向模型展示的 JSON Schema, 并在执行前校验模型提供的参数——对齐 Microsoft.Extensions.AI 的既定选型。

观察插件

观察方是独立插件,通过工具流水线的监听器接口观察每次调用(对应 dsh 的 ctx.on('tools/result', ...)):

ctx.Plugin(Plugin.From(c =>
{
    var registry = c.Require<IToolRegistry>();
    var subscription = registry.RegisterPostExecuteListener(null, (execution, outcome, next) =>
    {
        Console.WriteLine($"[tool-logger] {execution.Name} -> settled");
        return next();                    // 观察型监听器必须委托(第 4 章 waterfall 纪律)
    });
    c.Effect(subscription.Dispose);
}, typeof(IToolRegistry)));

两个插件互不知道对方存在——它们由注册表服务和流水线事件连接。

greet-tool 插件 Register(AIFunction) tool-logger 插件 RegisterPostExecuteListener IToolRegistry 声明 + 执行流水线 模型 / Agent loop 按声明发起调用 结果经 post-execute waterfall 返回
提供、观察、调用三方经注册表解耦:任何一方卸载,其余两方不受影响——这正是第 2–4 章机制的组合应用。

组合并运行

真实组合里,IToolRegistry 由 Tether.Core.Tools 的 ToolRegistry 提供,连同系统提示词、 LLM 适配器等一起写进 Bundles YAML;Headless 与 CLI 都从 compositions/bundles/ 解析同一份组合 (见 Composition Root 与运行)。缺少提供方时,工具插件会像 第 6 章所述保持 PENDING。

从这里走向完整 agent

真实 agent 就是这套组合再加更多插件:LLM 适配器、agent loop、持久化和运行入口。 对照 预设与组合包,你现在已经可以读懂其中每个配置项。

后续可以阅读:

  • 工具:工具流水线、guard 与 scope 可见性。
  • 能力服务:harness 如何组织可替换能力。
  • 架构:这些插件所处的系统地图。
在 GitHub 上编辑此页