1. 文档目的

本文描述一种面向智能体 Harness 的能力管理架构,用于解决以下问题:

  • 系统长期积累大量脚本、操作配方、API、知识说明和工具后,如何避免一次性向模型暴露过多工具。

  • 模型如何根据用户的自然语言目标,找到正确的能力。

  • 如何按需向模型披露具体工具的参数 Schema。

  • 如何在保持统一执行入口的同时,对每个具体动作实施独立的权限、风险、确认和审计控制。

  • 多种检索方式如何通过并行分发、结果汇聚、融合和重排形成最终候选。

该架构不应被简单理解为传统“知识库智能体”。更准确的定义是:

 

分层能力注册表(Capability Registry)

  • 渐进式能力披露(Progressive Capability Disclosure)

  • 并行能力检索(Parallel Capability Retrieval)

  • 受控动作执行(Governed Action Execution)

原始设想中的“领域—范围—工具”可以分别映射为能力包、子能力包和叶子动作,而 README、INDEX、DESCRIBE 等内容则承担局部操作指引、使用边界和能力摘要的职责。


2. 问题背景

在小型智能体中,可以直接向模型提供少量工具,例如:

read
edit
bash
schedule_create
weather_query

但当系统不断积累以下内容时,工具集合会快速膨胀:

  • Codex、npm、Conda 等本地环境维护命令。

  • 自建应用的业务 API。

  • 日程、出行、用户资料等服务接口。

  • 故障诊断经验和操作步骤。

  • 封装后的固定 Bash 或 Python 脚本。

  • 发布、删除、更新等高风险动作。

如果每轮请求都把所有工具 Schema 发送给模型,会产生以下问题:

  1. 上下文占用不断扩大。

  2. 相似工具之间更容易发生误选。

  3. 模型需要理解大量与当前任务无关的参数。

  4. 工具更新后,Schema 管理成本上升。

  5. 高风险能力被无差别暴露。

  6. 工具数量增长后,调用准确率可能下降。

因此需要将能力组织成层级注册表,只在需要时披露相关能力。


3. 核心概念

3.1 Capability Pack

Capability Pack 是一组相关能力的逻辑集合。

例如:

maintenance
├── codex
├── npm
├── python
└── docker

其中:

maintenance.codex

可以包含:

maintenance.codex.status
maintenance.codex.diagnose
maintenance.codex.update
maintenance.codex.path_repair
maintenance.codex.rollback

能力包主要用于:

  • 组织能力。

  • 限定搜索范围。

  • 提供局部规则。

  • 描述该领域的操作惯例。

  • 控制能力的整体启用和禁用。

3.2 Action

Action 是一个可以直接执行的叶子动作。

例如:

maintenance.codex.diagnose
maintenance.codex.update
myapp.schedule.create

每个 Action 必须拥有独立定义,包括:

action_id:
version:
title:
summary:
when_to_use:
when_not_to_use:
arguments_schema:
handler:
side_effect:
risk_level:
acl:
requires_confirmation:
timeout:
network_policy:
output_schema:

即使模型侧只看到统一的 capability::run,宿主系统内部也必须保留每个 Action 的独立 Schema、权限和执行合同。

3.3 Recipe / Skill

Recipe 或 Skill 是操作知识,而不是独立执行动作。

适合表示:

  • 故障排查步骤。

  • 命令组合建议。

  • 使用现有 Bash、Read、Edit 完成任务的方法。

  • 很少使用且不值得独立封装的操作流程。

例如:

maintenance.codex.path_conflict_guide

它可以告诉模型:

1. 执行 type -a codex。
2. 检查 npm prefix -g。
3. 对比 npm 全局包版本和实际启动版本。
4. 分别检查 Bash 与 Fish 的 PATH。

3.4 元工具

系统常驻的不是所有业务工具,而是一组少量元工具:

capability::search
capability::list
capability::describe
capability::run

其中:

  • search:根据目标搜索能力。

  • list:浏览某个能力包。

  • describe:获取某个能力的完整调用合同。

  • run:执行已注册动作。


4. 为什么统一执行工具需要能力发现系统

假设模型原本直接看到:

{
  "name": "maintenance_codex_update",
  "description": "使用受控 npm 流程更新 Codex CLI",
  "parameters": {
    "type": "object",
    "properties": {
      "channel": {
        "type": "string",
        "enum": ["stable", "latest"]
      },
      "dry_run": {
        "type": "boolean"
      }
    },
    "required": ["channel"]
  }
}

模型可以直接知道:

  • 该动作存在。

  • 动作用于什么场景。

  • 参数名称和类型。

  • 参数枚举范围。

  • 哪些参数必填。

如果将所有动作统一隐藏在:

capability::run(action_id, arguments)

后面,模型初始只知道存在一个统一执行通道,却不知道:

  • 可用的 action_id 有哪些。

  • 应选择 diagnose、update 还是 rollback。

  • arguments 应包含哪些字段。

  • 哪个动作会产生写操作。

  • 哪个动作需要用户确认。

因此,万能工具减少了表面工具数量,但同时隐藏了 leaf tool 的 Schema。

必须通过 search / list / describe 恢复以下信息:

  • 可发现性。

  • 参数说明。

  • 适用与不适用条件。

  • 示例。

  • 风险级别。

  • 权限和环境要求。

否则系统只是把几十个工具名变成了几十个需要模型记忆的字符串 ID。


5. Capability Search 的职责

capability::search 的定义应当是:

 

在当前用户、当前环境、当前权限和当前任务约束下,从能力注册表中召回并排序一组可能适用的能力,供模型下一步选择。

它不负责:

  • 直接执行动作。

  • 返回所有完整 Schema。

  • 代替权限校验。

  • 直接生成最终用户答案。

它负责:

  1. 理解当前搜索目标。

  2. 选择适当的检索通道。

  3. 并行召回候选。

  4. 汇聚不同检索器的证据。

  5. 过滤不可发现或不可用能力。

  6. 融合候选排名。

  7. 根据风险、上下文和使用边界重排。

  8. 返回少量候选摘要。


6. Search 请求协议

推荐的工具定义如下:

{
  "name": "capability_search",
  "description": "根据当前目标搜索可用的能力包、动作和操作配方,不执行任何动作。",
  "parameters": {
    "type": "object",
    "properties": {
      "query": {
        "type": "string",
        "description": "当前任务目标,应尽量包含对象、问题、限制和期望结果。"
      },
      "within": {
        "type": "string",
        "description": "可选,限制搜索范围,例如 maintenance.codex。"
      },
      "types": {
        "type": "array",
        "items": {
          "type": "string",
          "enum": ["pack", "action", "recipe"]
        }
      },
      "side_effect_max": {
        "type": "string",
        "enum": ["R", "W-local", "W-shared", "I"]
      },
      "limit": {
        "type": "integer",
        "minimum": 1,
        "maximum": 10,
        "default": 5
      }
    },
    "required": ["query"],
    "additionalProperties": false
  }
}

调用示例:

{
  "query": "Codex 更新后仍然启动旧版本,先检查 npm 全局安装路径和 Shell PATH 冲突",
  "within": "maintenance.codex",
  "types": ["action", "recipe"],
  "side_effect_max": "W-local",
  "limit": 5
}

7. 能力注册表设计

搜索质量首先取决于能力元数据,而不是向量模型。

一个 Action 的推荐定义如下:

action_id: maintenance.codex.diagnose
version: 3
resource_type: action

title: 诊断 Codex 安装与路径冲突

summary: >
  检查当前实际启动的 Codex 可执行文件、版本、
  npm 全局安装目录、npm 已安装版本以及 Shell PATH 优先级。

aliases:
  - codex 更新后还是旧版本
  - codex path 冲突
  - npm 安装版本与运行版本不同

intents:
  - diagnose
  - inspect
  - verify

entities:
  - codex
  - npm
  - path
  - bash
  - fish

symptoms:
  - active_version_mismatch
  - multiple_executables
  - npm_prefix_mismatch

when_to_use:
  - 更新后实际运行版本仍然较旧
  - type -a codex 显示多个路径
  - npm 全局版本与当前执行版本不一致

when_not_to_use:
  - 用户已经明确要求回滚
  - 已确认问题与 PATH 无关
  - Codex 并非通过 npm 安装

supported_os:
  - linux
  - macos

required_executors:
  - shell
  - npm

side_effect: R
risk_level: low
requires_confirmation: false

produces:
  - active_binary
  - active_version
  - installed_npm_version
  - npm_prefix
  - path_conflicts

tags:
  - maintenance
  - codex
  - npm
  - cli

其中最重要的字段是:

  • aliases:用户可能如何表达。

  • intents:用户想完成什么。

  • entities:涉及什么对象。

  • symptoms:用户观察到什么现象。

  • when_to_use:正向使用边界。

  • when_not_to_use:排除条件。

  • side_effect:动作副作用。

  • required_context:环境是否满足。


8. Search 总体架构

能力搜索适合采用典型的 Fan-out / Fan-in 架构:

                         ┌─ Exact Retriever ──────┐
                         ├─ Lexical Retriever ────┤
Query → Search Planner ──┼─ Semantic Retriever ──┼→ Gather
                         ├─ Metadata Retriever ───┤
                         ├─ Hierarchy Retriever ──┤
                         └─ History Retriever ────┘

Gather
  ↓
Policy Filter
  ↓
Fusion
  ↓
Rerank
  ↓
Diversification
  ↓
Top-K Candidates

完整流程为:

请求校验
→ 查询规范化
→ 搜索计划生成
→ 并行分发 Retriever
→ 汇聚候选和证据
→ 权限与环境过滤
→ 多路排名融合
→ 策略感知重排
→ 多样性控制
→ 置信度判断
→ 返回 Top 3~5

9. Query Normalizer

Query Normalizer 将自然语言目标转换为结构化搜索意图。

输入:

刚更新了 Codex,但 codex --version 还是旧版本,先检查原因,不要直接重装。

输出:

{
  "intents": ["diagnose"],
  "entities": ["codex"],
  "symptoms": ["active_version_mismatch"],
  "constraints": ["read_first"],
  "forbidden_intents": ["reinstall", "update"],
  "desired_outcome": "定位实际运行版本与安装版本不一致的原因"
}

Normalizer 可以由以下方式组合实现:

规则识别明确实体和强约束
+
别名词典识别领域术语
+
必要时使用 LLM 做结构化解析

早期 MVP 不必每次调用 LLM。对于 Codex、npm、PATH、Fish 等明确实体,规则和词典通常足够。


10. Search Planner

Search Planner 根据查询特征决定启动哪些 Retriever。

并行并不意味着每次都执行所有检索器。

明确 Action ID

查询:

maintenance.codex.diagnose

计划:

Exact Retriever
Metadata Retriever

模糊自然语言问题

查询:

我明明升级了,为什么运行出来还是旧的?

计划:

Lexical Retriever
Semantic Retriever
Metadata Retriever
History Retriever

能力浏览请求

查询:

Codex 维护相关能力有哪些?

计划:

Hierarchy Retriever
Metadata Retriever

示例:

def build_search_plan(query: ParsedQuery) -> SearchPlan:
    if query.explicit_resource_id:
        return SearchPlan(
            retrievers=("exact", "metadata")
        )

    if query.scope and query.is_browse_request:
        return SearchPlan(
            retrievers=("hierarchy", "metadata")
        )

    retrievers = ["lexical", "metadata"]

    if query.needs_semantic_matching:
        retrievers.append("semantic")

    if query.use_history:
        retrievers.append("history")

    return SearchPlan(retrievers=tuple(retrievers))

11. Retriever 设计

11.1 Exact Retriever

负责精确匹配:

  • 完整 action_id

  • action ID 前缀。

  • 固定别名。

  • 唯一标识。

例如:

maintenance.codex.update
schedule_create
codex_diagnose

精确命中通常应获得最高权重。

11.2 Lexical Retriever

负责关键词和全文检索:

  • 标题。

  • 摘要。

  • aliases。

  • entities。

  • symptoms。

  • tags。

  • when_to_use。

适合使用:

  • SQLite FTS5。

  • PostgreSQL 全文检索。

  • Elasticsearch BM25。

  • 本地倒排索引。

专有名词如 Codex、npm、Fish、AuraTrip 不应只依赖向量召回。

11.3 Semantic Retriever

负责语义近似表达。

例如用户说:

安装明明成功了,但真正执行的好像不是新版本。

即使未出现 PATH shadowing,也应召回:

maintenance.codex.diagnose
maintenance.codex.path_repair

用于 Embedding 的索引文本应包含正反使用边界:

动作:诊断 Codex 安装与路径冲突

用于:
- 更新后仍显示旧版本
- npm 安装版本与实际运行版本不同
- 存在多个 Codex 可执行路径

不用于:
- 单纯执行更新
- 回滚指定版本

11.4 Metadata Retriever

负责结构化字段匹配:

intent = diagnose
entity = codex
symptom = active_version_mismatch
side_effect = R

它通常比纯语义检索更稳定。

11.5 Hierarchy Retriever

负责能力树和范围检索:

within = maintenance.codex

只召回:

maintenance.codex.*

同时可以返回:

  • 父能力包。

  • 子动作。

  • 相邻能力。

  • 路径深度。

11.6 History Retriever

负责召回:

  • 当前用户过去成功使用的动作。

  • 当前项目常用能力。

  • 最近加载的能力包。

  • 相似任务中的成功路径。

历史只能作为弱信号,不能覆盖权限、当前语义和风险判断。


12. 并行 Dispatcher

Retriever 应通过统一 Dispatcher 并行执行。

from __future__ import annotations

import asyncio
from dataclasses import dataclass
from typing import Protocol


@dataclass(frozen=True)
class RetrievalHit:
    resource_id: str
    rank: int
    score: float | None
    source: str
    matched_fields: tuple[str, ...] = ()


@dataclass(frozen=True)
class RetrievalContext:
    query: str
    scope: str | None
    user_id: str
    limit_per_source: int = 20


class Retriever(Protocol):
    name: str

    async def retrieve(
        self,
        context: RetrievalContext,
    ) -> list[RetrievalHit]:
        ...


class SearchDispatcher:
    def __init__(
        self,
        retrievers: dict[str, Retriever],
        timeout_seconds: float = 1.0,
    ) -> None:
        self._retrievers = retrievers
        self._timeout_seconds = timeout_seconds

    async def dispatch(
        self,
        retriever_names: tuple[str, ...],
        context: RetrievalContext,
    ) -> dict[str, list[RetrievalHit]]:
        coroutines = [
            asyncio.wait_for(
                self._retrievers[name].retrieve(context),
                timeout=self._timeout_seconds,
            )
            for name in retriever_names
        ]

        raw_results = await asyncio.gather(
            *coroutines,
            return_exceptions=True,
        )

        results: dict[str, list[RetrievalHit]] = {}

        for name, result in zip(
            retriever_names,
            raw_results,
            strict=True,
        ):
            if isinstance(result, BaseException):
                results[name] = []
            else:
                results[name] = result

        return results

每个 Retriever 应配置独立超时,并支持部分成功。

示例:

Exact:50 ms
Metadata:100 ms
Lexical:200 ms
Semantic:500 ms
History:300 ms

不能因为 Semantic Retriever 超时而使整个能力搜索失败。


13. Gather 阶段

Gather 不是简单拼接列表。

它至少需要完成以下工作。

13.1 统一结果格式

不同检索器分数不可直接比较:

  • BM25 是全文分数。

  • 向量检索是相似度。

  • Metadata 是规则命中。

  • Hierarchy 是路径关系。

  • History 是使用频率。

因此统一保留排名和原始证据:

@dataclass(frozen=True)
class CandidateEvidence:
    source: str
    rank: int
    raw_score: float | None
    matched_fields: tuple[str, ...]


@dataclass
class GatheredCandidate:
    resource_id: str
    evidence: list[CandidateEvidence]

13.2 按 resource_id 去重

以下结果:

Lexical  → maintenance.codex.diagnose
Semantic → maintenance.codex.diagnose
Metadata → maintenance.codex.diagnose

应聚合为一个候选,并保留三份召回证据。

13.3 保留来源证据

{
  "resource_id": "maintenance.codex.diagnose",
  "evidence": [
    {
      "source": "lexical",
      "rank": 1,
      "matched_fields": ["aliases", "symptoms"]
    },
    {
      "source": "semantic",
      "rank": 2,
      "raw_score": 0.89
    },
    {
      "source": "metadata",
      "rank": 1,
      "matched_fields": ["intent", "entity"]
    }
  ]
}

这些证据可用于:

  • 解释命中原因。

  • 调试检索质量。

  • 离线评估。

  • 调整权重。

  • 生成可观测日志。

13.4 控制候选规模

例如:

每路 Top 20
→ 最多 100 条原始结果
→ 去重后保留 Top 30
→ 进入精排
→ 最终返回 Top 5

14. Policy Filter

权限过滤应分成两层。

14.1 召回前硬过滤

适合处理:

  • 租户隔离。

  • 禁止发现的高敏感动作。

  • disabled action。

  • 明确不支持当前操作系统。

  • 明确超出 within 范围。

14.2 Gather 后统一过滤

适合处理:

  • 当前执行权限。

  • Feature Flag。

  • 动态依赖状态。

  • 凭据是否存在。

  • 当前环境是否满足。

  • 版本是否兼容。

  • 当前预算是否允许。

安全判断最终必须由统一 Policy Service 再执行一次,不能只相信 Retriever 已正确过滤。

权限还应区分:

discover permission
describe permission
execute permission

模型可以知道某个能力存在,不代表能够查看完整参数;能够查看参数,也不代表能够执行。


15. Fusion

Fusion 回答的问题是:

 

多个 Retriever 综合认为,哪些候选最相关?

由于不同检索器的分数空间不同,第一版建议使用 Weighted Reciprocal Rank Fusion。

公式:

FusionScore(d)
=
Σ source_weight(i) / (k + rank_i(d))

示例权重:

SOURCE_WEIGHTS = {
    "exact": 2.0,
    "metadata": 1.4,
    "lexical": 1.2,
    "semantic": 1.0,
    "hierarchy": 0.8,
    "history": 0.4,
}

实现:

def weighted_rrf(
    candidate: GatheredCandidate,
    k: int = 60,
) -> float:
    return sum(
        SOURCE_WEIGHTS[evidence.source]
        / (k + evidence.rank)
        for evidence in candidate.evidence
    )

History 权重应保持较低,防止系统因过去经常使用某个动作而形成强化偏差。


16. Rerank

Rerank 回答的问题是:

 

在当前任务、环境和风险约束下,哪个候选最适合作为下一步?

Rerank 可以考虑:

intent match
entity match
symptom match
when_to_use
when_not_to_use
side effect
risk level
environment fit
permission state
current workflow stage
historical reliability

示例:

用户:先检查原因,不要直接更新。

候选:

maintenance.codex.diagnose
maintenance.codex.path_repair
maintenance.codex.update

重排规则应使:

diagnose > path_repair > update

其中 update 虽然语义相关,但命中了用户的禁止约束和自身的 when_not_to_use,因此需要明显降权。

示例评分:

FinalScore
=
FusionScore
+ IntentMatch
+ EntityMatch
+ SymptomMatch
+ ContextFit
- RiskPenalty
- NegativeUsagePenalty

Fusion 和 Rerank 的职责必须分开:

Fusion:多路检索认为它是否相关
Rerank:当前任务中它是否合适

17. 风险模型

建议统一使用以下副作用等级:

等级

含义

示例

R

只读

查询版本、列出日程

W-local

修改本地环境

安装工具、修改 PATH

W-shared

修改远端或共享数据

创建业务日程、更新团队数据

I

高影响或不可逆

删除、发布、付款、外发

当用户目标不明确时,默认排序应偏向:

R
> 可逆 W-local
> W-shared
> I

当用户明确要求写操作时,不应因风险等级完全压制正确动作。

风险控制不是万能工具级别的统一权限,而应在解析 action_id 后,针对叶子动作执行。万能的只能是执行通道,不能是权限。


18. Diversification

搜索结果不能全部是同一类动作。

例如以下五个结果价值较低:

codex.update.stable
codex.update.latest
codex.update.specific
codex.update.force
codex.update.reinstall

建议加入以下多样性规则:

  • 同一父能力包最多返回 3 个。

  • 同一主要意图最多返回 2 个。

  • 模糊查询至少保留一个只读动作。

  • 高风险动作不能占满候选。

  • 当多个 leaf action 得分接近时,可返回父 Pack。

示例:

def diversify(
    ranked: list[RankedCandidate],
    limit: int,
) -> list[RankedCandidate]:
    selected = []
    parent_count: dict[str, int] = {}
    intent_count: dict[str, int] = {}

    for item in ranked:
        if parent_count.get(item.parent_id, 0) >= 3:
            continue

        if intent_count.get(item.primary_intent, 0) >= 2:
            continue

        selected.append(item)

        parent_count[item.parent_id] = (
            parent_count.get(item.parent_id, 0) + 1
        )
        intent_count[item.primary_intent] = (
            intent_count.get(item.primary_intent, 0) + 1
        )

        if len(selected) >= limit:
            break

    return selected

19. 置信度与模糊处理

搜索系统不能在低置信度情况下硬选一个动作。

查询:

帮我处理一下开发环境。

可能同时匹配:

maintenance.codex
maintenance.python
maintenance.npm
maintenance.docker

此时应返回 Pack 级候选或标记为模糊:

{
  "resolution": "ambiguous",
  "matches": [
    {
      "resource_type": "pack",
      "resource_id": "maintenance.codex"
    },
    {
      "resource_type": "pack",
      "resource_id": "maintenance.python"
    }
  ]
}

可区分:

confident
ambiguous
no_confident_match

阈值必须通过真实日志和离线评估校准,而不是长期写死。


20. Search 返回协议

Search 只返回候选摘要,不返回完整参数 Schema。

{
  "query": "Codex 更新后仍启动旧版本,先检查 PATH 冲突",
  "scope": "maintenance.codex",
  "resolution": "confident",
  "matches": [
    {
      "rank": 1,
      "resource_type": "action",
      "resource_id": "maintenance.codex.diagnose",
      "title": "诊断 Codex 安装与路径冲突",
      "summary": "检查活动二进制、版本、npm prefix 和 Shell PATH。",
      "matched_entities": ["codex", "npm", "path"],
      "matched_intents": ["diagnose"],
      "matched_symptoms": ["active_version_mismatch"],
      "side_effect": "R",
      "risk_level": "low",
      "requires_confirmation": false,
      "availability": "available",
      "score": 0.94,
      "next_step": {
        "tool": "capability_describe",
        "arguments": {
          "resource_id": "maintenance.codex.diagnose"
        }
      }
    }
  ],
  "search_meta": {
    "planned_retrievers": [
      "lexical",
      "semantic",
      "metadata"
    ],
    "completed_retrievers": [
      "lexical",
      "semantic",
      "metadata"
    ],
    "candidate_count": 17,
    "returned_count": 3,
    "partial": false
  }
}

21. Describe 与动态 Schema 披露

模型选中候选后调用:

{
  "action_id": "maintenance.codex.diagnose"
}

describe 返回:

{
  "action_id": "maintenance.codex.diagnose",
  "version": 3,
  "summary": "检查 Codex 安装、版本和路径冲突。",
  "when_to_use": [
    "更新后仍显示旧版本",
    "存在多个可执行路径"
  ],
  "when_not_to_use": [
    "已明确要求回滚"
  ],
  "arguments_schema": {
    "type": "object",
    "properties": {
      "include_shell_resolution": {
        "type": "boolean",
        "default": true
      },
      "include_registry_check": {
        "type": "boolean",
        "default": true
      }
    },
    "additionalProperties": false
  },
  "side_effect": "R",
  "requires_confirmation": false
}

随后可以选择两种执行方式。

方式一:统一 Run

{
  "action_id": "maintenance.codex.diagnose",
  "action_version": 3,
  "arguments": {
    "include_shell_resolution": true,
    "include_registry_check": true
  }
}

方式二:动态注册 Leaf Tool

Harness 在下一次模型请求中加入真实工具:

maintenance__codex_diagnose

方式二的参数 Schema 更清晰,更适合 API 和高风险动作;方式一更适合稳定脚本和中低风险注册动作。


22. 完整执行 Loop

用户请求:

Codex 更新后还是旧版本,帮我检查并修好。

Round 1:Search

{
  "query": "Codex 更新后仍启动旧版本,检查 npm prefix 和 PATH 冲突",
  "within": "maintenance.codex"
}

返回:

1. maintenance.codex.diagnose
2. maintenance.codex.path_repair
3. maintenance.codex.update

Round 2:Describe Diagnose

模型获得诊断动作的详细 Schema。

Round 3:Run Diagnose

返回:

{
  "active_binary": "/home/user/.local/bin/codex",
  "active_version": "0.141.0",
  "installed_binary": "/home/user/.npm-global/bin/codex",
  "installed_version": "0.144.6",
  "issue": "PATH shadowing",
  "recommended_actions": [
    "maintenance.codex.path_repair"
  ]
}

Round 4:Describe Path Repair

获取修改范围、参数和风险。

Round 5:Confirmation

Harness 返回:

{
  "status": "confirmation_required",
  "summary": "将调整 Bash 和 Fish 的 PATH 优先级。",
  "affected_resources": [
    "~/.bashrc",
    "~/.config/fish/config.fish"
  ],
  "confirmation_token": "confirm-abc123"
}

Round 6:Run Path Repair

完成修复并验证:

type -a codex
codex --version
npm list -g @openai/codex --depth=0

完整链路为:

Search
→ Describe
→ Run
→ Observe
→ Search/Describe next action
→ Confirm
→ Run
→ Verify

23. 推荐代码模块

capabilities/
├── models.py
├── registry.py
├── indexer.py
├── query_normalizer.py
├── search_planner.py
├── search_dispatcher.py
├── gatherer.py
├── policy_filter.py
├── fusion.py
├── reranker.py
├── diversifier.py
├── search_service.py
├── describe_service.py
├── action_executor.py
└── retrievers/
    ├── exact.py
    ├── lexical.py
    ├── semantic.py
    ├── metadata.py
    ├── hierarchy.py
    └── history.py

Search Service 主流程:

class CapabilitySearchService:
    async def search(
        self,
        request: CapabilitySearchRequest,
        runtime_context: RuntimeContext,
    ) -> CapabilitySearchResult:
        parsed_query = self.query_normalizer.normalize(
            request.query,
            runtime_context,
        )

        plan = self.search_planner.plan(
            request=request,
            parsed_query=parsed_query,
            runtime_context=runtime_context,
        )

        retrieval_results = await self.dispatcher.dispatch(
            retriever_names=plan.retrievers,
            context=RetrievalContext(
                query=request.query,
                scope=request.within,
                user_id=runtime_context.user_id,
            ),
        )

        gathered = self.gatherer.gather(
            retrieval_results
        )

        allowed = self.policy_filter.filter(
            gathered,
            runtime_context=runtime_context,
        )

        fused = self.fusion.fuse(allowed)

        reranked = self.reranker.rerank(
            candidates=fused,
            parsed_query=parsed_query,
            runtime_context=runtime_context,
        )

        selected = self.diversifier.select(
            reranked,
            limit=request.limit,
        )

        return self.result_builder.build(
            request=request,
            plan=plan,
            retrieval_results=retrieval_results,
            candidates=selected,
        )

24. MVP 实施建议

第一阶段不必立即引入向量数据库。

推荐 MVP:

YAML / JSON Capability Registry
+
Exact Retriever
+
SQLite FTS5 Lexical Retriever
+
Metadata Retriever
+
Hierarchy Retriever
+
asyncio.gather
+
Weighted RRF
+
规则 Rerank

第一阶段实现:

capability_search
capability_describe
capability_run

第二阶段再增加:

Semantic Retriever
History Retriever
动态 Leaf Tool 注册
学习排序
搜索质量评估

初始检索流程:

1. 校验请求。
2. 解析 scope、实体、意图、症状和约束。
3. Search Planner 选择 Retriever。
4. 并行执行 Exact、Lexical、Metadata、Hierarchy。
5. 按 resource_id 汇聚并去重。
6. 执行权限和环境过滤。
7. 使用 Weighted RRF 融合。
8. 根据 when_to_use、when_not_to_use、风险和上下文重排。
9. 执行多样性控制。
10. 返回 3~5 个候选。
11. 模型选中候选后调用 describe。

25. 评估指标

能力搜索应建立独立测试集。

每条测试样本至少包含:

query:
runtime_context:
expected_top_actions:
forbidden_actions:
expected_resolution:

建议关注:

检索指标

  • Recall@K。

  • MRR。

  • NDCG@K。

  • Top-1 Accuracy。

  • 正确 Pack 命中率。

安全指标

  • 无权限能力泄露率。

  • 高风险动作误排 Top-1 的比例。

  • when_not_to_use 违反率。

  • 未确认写操作执行率。

系统指标

  • P50/P95 搜索延迟。

  • 各 Retriever 超时率。

  • 部分降级成功率。

  • 平均候选数量。

  • 平均披露 Schema 大小。

业务指标

  • Search 后正确 Describe 的比例。

  • Describe 后正确 Run 的比例。

  • 用户澄清次数。

  • 动作执行成功率。

  • 错误动作撤销率。


26. 常见错误

错误一:把 Search 做成普通文档 RAG

能力搜索不仅是语义相似度,还必须考虑:

  • 权限。

  • 环境。

  • 副作用。

  • 使用边界。

  • 当前流程阶段。

错误二:只依赖 Embedding

专有名词、Action ID、枚举值和明确症状通常更适合关键词和结构化检索。

错误三:Search 直接返回完整 Schema

Search 应返回候选摘要,Describe 才返回单个候选的完整 Schema,否则候选一多,上下文仍会膨胀。

错误四:统一 Run 使用统一权限

权限必须在解析 action_id 后按叶子动作判断。

正确顺序:

解析 action_id
→ 读取 ActionDefinition
→ 校验版本
→ 校验参数
→ ACL
→ 风险判断
→ 确认
→ 执行

错误五:并行等于无条件调用所有 Retriever

应由 Search Planner 根据任务选择检索通道。

错误六:Gather 只是数组合并

Gather 必须去重、保留来源证据、限制候选数量,并为 Fusion 提供统一结构。

错误七:历史使用频率权重过高

历史是弱信号,不能让系统不断推荐过去使用过但当前不适用的动作。


27. 设计结论

这套系统的核心不是减少注册表中的能力数量,而是减少每轮向模型暴露的能力数量。

推荐总体模式:

少量常驻核心工具
    ↓
Search Planner
    ↓
并行 Retriever Fan-out
    ↓
Gather / Policy / Fusion / Rerank
    ↓
少量候选摘要
    ↓
Describe 单个能力
    ↓
统一 Run 或动态 Leaf Tool
    ↓
叶子级权限、确认和审计

各组件职责可以概括为:

Registry:定义系统拥有什么能力
Retriever:负责找得到
Gatherer:负责聚合证据
Fusion:负责合得起来
Reranker:负责选得正确
Policy:负责能不能发现和使用
Describe:负责披露准确合同
Executor:负责安全执行

最终形成的不是传统知识库,而是一个:

 

可搜索、可解释、可校验、可授权、可审计,并支持渐进式披露的个人能力插件系统。

对于操作经验、包装脚本和业务 API 混合存在的场景,建议采用:

Recipe / Skill
+
注册动作执行器
+
动态 Typed Leaf Tool
+
受控 Raw Bash

其中:

  • 普通经验放入 Recipe。

  • 稳定包装脚本放入注册动作执行器。

  • API 和高风险操作使用独立 Typed Tool。

  • Raw Bash 仅作为强沙箱和确认机制下的兜底能力。

这种混合方案既保留了 Harness 的通用性,又避免将所有异构动作伪装成无约束字符串参数。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐