ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Kimi Code CLI 工具架构规范:依赖边界与 kosong.tooling 类型体系

2026/9/15 19:41:17 拓冰建站 浏览量
Kimi Code CLI 工具架构规范:依赖边界与 kosong.tooling 类型体系 Kimi Code CLI 工具架构规范依赖边界与 kosong.tooling 类型体系【免费下载链接】kimi-cliKimi Code CLI is your next CLI agent.项目地址: https://gitcode.com/GitHub_Trending/ki/kimi-cli本指南以仓库内 src/kimi_cli/tools/AGENTS.md 为核心系统解读 Kimi Code CLI 内置工具tools模块的架构规范工具代码为什么不能直接依赖kimi_cli/wire/下的类型、何时允许例外以及应优先从kosong.tooling获取哪些核心类型。读完本文你将理解 kimi-cli 工具层与 UI/运行时桥接层的依赖关系全貌并掌握按规范编写、注册一个内置工具的完整模式。一、规范原文一页纸定下的依赖铁律src/kimi_cli/tools/AGENTS.md全文非常简短核心只有一条规则Tools should not refer to types inkimi_cli/wire/unless they are explicitly implementing a UI / runtime bridge. When importing things likeToolReturnValueorDisplayBlock, preferkosong.tooling.翻译过来即两条约束默认禁止工具代码不得引用kimi_cli/wire/中的类型唯一例外当工具明确实现 UI / 运行时桥接UI / runtime bridge时可以引用正替代方案需要ToolReturnValue、DisplayBlock这类类型时优先从kosong.tooling导入。这条规范虽然只有一句话但它定义了整个工具模块的依赖方向kimi_cli.tools做什么→kosong.tooling类型契约并严格隔离了kimi_cli.wire如何与 UI 通信。下面我们从源码层面逐层剖析它为什么存在、如何落地。二、分层背景tools、kosong.tooling 与 wire 各司其职要理解这条规范先要看清三个模块在架构中的位置。2.1 kosong.tooling与 UI 无关的工具类型契约kosong是仓库 packages/kosong 下的独立 Python 包kosong.tooling是它的子模块packages/kosong/src/kosong/tooling/init.py。它定义了一套与具体 CLI、具体 UI 完全解耦的工具抽象Tool可被模型识别的工具定义名称、描述、JSON Schema 参数ToolReturnValue可调用工具的返回类型DisplayBlock面向用户展示的内容块Toolset/SimpleToolset/EmptyToolset工具的注册与分发机制。从源码结构看kosong.tooling只依赖kosong.message、kosong.utils与 pydantic/jsonschema不依赖任何kimi_cli内部模块因此它可以被独立复用例如测试、后台任务、SDK 场景。2.2 kimi_cli.wiresoul 与 UI 之间的通信通道kimi_cli/wire是另一层职责——src/kimi_cli/wire/init.py 中的Wire类注释写得很清楚A spmc channel for communication between the soul and the UI during a soul run.它是一个单生产者多消费者SPMC通道负责在 agentsoul运行期间把消息广播给 UIsrc/kimi_cli/wire/types.py 则定义了TurnBegin、SteerInput、WireMessage等协议级类型以及QuestionRequest、PlanDisplay等面向 UI 交互的结构。2.3 依赖方向的本质把三者放在一起依赖关系非常清晰工具层kimi_cli.tools依赖kosong.tooling的类型契约来定义工具能做什么、返回什么wire层负责这些结果如何序列化、如何呈现给 UI它反而会反向引用kosong.tooling与kimi_cli.tools.display见 src/kimi_cli/wire/types.py 中从kosong.tooling导入DisplayBlock、ToolReturnValue并从kimi_cli.tools.display导入 CLI 自定义展示块。如果工具反过来依赖wire类型就会把业务能力与UI 通信协议耦合在一起工具将无法脱离 UI 环境运行比如纯后台任务、无界面测试也会让wire协议的任何改动波及所有工具实现。这正是 AGENTS.md 第一条约束要防止的。三、kosong.tooling 类型体系详解工具层应优先使用的 API规范明确preferkosong.tooling那么它到底提供了哪些核心类型逐一展开。3.1 Tool工具定义与参数 Schema 校验Tool是 pydanticBaseModelpackages/kosong/src/kosong/tooling/init.py#L18-L33name工具名description工具描述parametersJSON Schema 格式的参数定义注册时通过jsonschema.validate(..., jsonschema.Draft202012Validator.META_SCHEMA)强制校验其本身是合法 Schema。它只描述长什么样不包含执行逻辑供模型调用时读取。3.2 CallableTool / CallableTool2两类可调用工具基类CallableTool同文件 #L172-L216是抽象基类其call()方法统一处理参数分发调用前用jsonschema.validate校验参数失败返回ToolValidateError参数是 JSON 数组 → 解包为位置参数JSON 对象 → 解包为关键字参数其他 → 作为单个参数传入返回值若不是ToolReturnValue会被包装成ToolErrorInvalid return type即不信任工具实现的返回注解。CallableTool2[Params]#L232-L316是更现代、类型更友好的变体用 pydanticBaseModel子类声明参数构造时自动通过model_json_schemaderef_json_schema生成去 title 的 JSON Schema调用时用model_validate做参数校验。从仓库实际代码看kimi-cli 内置工具几乎全部采用CallableTool2风格。3.3 ToolReturnValue 与 ToolOk / ToolErrorToolReturnValue#L112-L137是工具返回的统一结构字段设计体现了面向模型与面向用户的双通道字段类型含义is_errorbool本次调用是否出错outputstr \| list[ContentPart]返回给模型的输出内容messagestr给模型的解释性消息displaylist[DisplayBlock]展示给用户的 UI 内容块extrasdict \| None调试/测试用附加数据ToolOk与ToolError是它的两个语义化子类#L140-L169ToolOk默认is_errorFalseToolError强制is_errorTrue并必须提供message与brief。工具实现只需return ToolOk(output...)或return ToolError(message..., brief...)即可错误语义由框架保证。此外 packages/kosong/src/kosong/tooling/error.py 预置了四个标准错误子类ToolNotFoundError工具不存在、ToolParseError参数不是合法 JSON、ToolValidateError参数校验失败、ToolRuntimeError执行异常分别对应工具分发生命周期中的不同失败点。3.4 DisplayBlock可扩展的用户展示块DisplayBlock#L36-L95是工具向用户界面输出内容的抽象基类与模型消息的ContentPart明确区分——注释指出ContentPart面向模型消息DisplayBlock面向工具/UI 扩展且允许用户直接继承它定义自定义展示块。它的设计有三个要点每个子类必须声明type: str字段__init_subclass__强制检查并登记到注册表基类通过自定义 pydantic 校验器按type字段分派到具体子类遇到未注册的 type 时回退为UnknownDisplayBlocktypeunknown 原始data保证向后兼容。内置的BriefDisplayBlocktypebrief是最简实现ToolReturnValue.brief属性就是从中提取纯文本摘要#L131-L137。3.5 Toolset注册与分发机制Toolset是一个runtime_checkable的 Protocol#L332-L354只要求两个成员tools属性工具定义列表与handle(tool_call)方法。其 docstring 明确了实现约束handle必须在消费聊天响应流期间被调用禁止阻塞操作除asyncio.CancelledError外不得抛异常一切错误都要以is_errorTrue的ToolReturnValue返回。标准实现有两个simple.py 的SimpleToolset支持并发handle返回asyncio.create_task包装的 Future并在注册时通过inspect.signature检查工具的返回注解必须是ToolReturnValue兼容from __future__ import annotations的字符串注解empty.py 的EmptyToolset则永远返回ToolNotFoundError用于无工具场景。四、规范允许的例外谁在合法地触碰 wireAGENTS.md 的例外条款是unless they are explicitly implementing a UI / runtime bridge。仓库中恰好有几个工具落在例外内可作为正反例对照。4.1 正例ask_user、read_media、plan在 src/kimi_cli/tools 下搜索kimi_cli.wire的导入命中恰好集中在三个桥接工具上tools/ask_user/init.py导入QuestionItem、QuestionNotSupported、QuestionOption、QuestionRequest—— 它实现的是向用户弹出提问面板这一UI 交互属于运行时桥接tools/file/read_media.py导入ImageURLPart、VideoURLPart—— 读取媒体文件后要把图片/视频直接渲染进 UI 消息流同样是桥接tools/plan/init.py 与 tools/plan/enter.py导入PlanDisplay、QuestionRequest等 —— 计划模式需要把计划展示 用户审批选项推送到 UI是典型的运行时桥接。这些工具的共同点是它们的产物本身就需要 UI 参与提问、展示媒体、审批计划不引用 wire 就无法完成职责因此符合例外条款。4.2 反例绝大多数工具只依赖 kosong.tooling对比之下其余工具file 读写、shell、web、todo、think、background 等在实现中都只从kosong.tooling导入类型。以 tools/file/read.py 为例其导入只有CallableTool2, ToolError, ToolOk, ToolReturnValue全部来自kosong.tooling。这说明规范在真实代码中是多数遵守、少数豁免的。4.3 wire 层的反向依赖印证了分层值得注意虽然工具默认不依赖 wire但 wire 层自身大量引用了kosong.tooling和kimi_cli.tools.display的类型见 src/kimi_cli/wire/types.py。这印证了依赖方向是单向的类型契约向上流动kosong → tools → wire而工具永远不该向下依赖传输协议。自定义展示块定义在 src/kimi_cli/tools/display.pyDiffDisplayBlock、TodoDisplayBlock、ShellDisplayBlock、BackgroundTaskDisplayBlock它们全部继承自kosong.tooling.DisplayBlock而不是 wire 层——这正是prefer kosong.tooling的最佳实践样本。五、按规范编写一个内置工具从声明到注册规范最终要落到怎么写一个工具。结合源码内置工具的完整套路如下。5.1 目录结构约定从 tools 目录 可以看到每个工具是独立子目录典型结构为__init__.py工具类实现CallableTool2子类description.md工具描述文档供模型读取支持 Jinja2 渲染变量复杂工具附带的辅助模块如file/下的read.py、write.py、replace.py、glob.py、grep_local.py及公共的utils.py。5.2 最小实现以 test.py 为例tools/test.py 提供了教科书式的最小工具from typing import override from kosong.tooling import CallableTool2, ToolOk, ToolReturnValue from pydantic import BaseModel class PlusParams(BaseModel): a: float b: float class Plus(CallableTool2[PlusParams]): name: str plus description: str Add two numbers params: type[PlusParams] PlusParams override async def __call__(self, params: PlusParams) - ToolReturnValue: return ToolOk(outputstr(params.a params.b))要点全部对应规范类型从kosong.tooling导入、参数用 pydantic 模型声明、返回ToolReturnValue。5.3 真实工具的模式以 ReadFile 为例真实工具会加上更严格的参数约束与错误处理。tools/file/read.py 展示了Params的写法path必填Field(description...)提供对模型的完整语义说明line_offset默认 1负数表示从文件末尾读取且经model_validator校验不能为 0、绝对值不能超过MAX_LINES1000n_lines默认MAX_LINESge1约束最小值常量边界如MAX_LINE_LENGTH 2000、MAX_BYTES 100 10100KB在文件顶部统一定义避免硬编码。工具内部还会配合 tools/utils.py 的load_desc()渲染description.mdJinja2 模板${变量}语法、未定义占位符原样保留以及truncate_line()对超长内容做截断。5.4 注册与加载机制工具类写好后由 src/kimi_cli/soul/toolset.py 的load_tools()加载注释明确说明路径格式为kimi_cli.tools.shell:Shell这样的模块:类形式。加载过程中的两个细节工具可以在加载阶段抛出 tools/display.py 定义的SkipThisTool异常主动跳过自己比如平台不支持时load_tools会记录日志继续加载其余工具外部工具如 MCP通过register_external_tool()soul/toolset.py#L615-L634以WireExternalTool形式注册名字冲突时返回明确错误——这与内置工具走的kosong.tooling体系是并行的两条轨道但都汇聚到同一个工具字典。六、规范对工具返回与展示的实践影响理解ToolReturnValue的双通道设计后就能明白规范为何强调类型来源工具返回的display列表DisplayBlock经由 wire 层序列化给 UI 渲染而output/message进入模型上下文。工具作者只需构造ToolOk/ToolError并填充展示块无需关心序列化细节——那是 wire 层的职责也是 AGENTS.md 刻意隔离的原因。若需要在 CLI 中呈现 diff、todo、shell 命令或后台任务状态直接继承kosong.tooling.DisplayBlock定义新块即可参照 tools/display.py然后由 wire 层负责分发渲染工具本身保持与 UI 协议解耦。这样既满足了prefer kosong.tooling又通过继承机制保留了 CLI 的展示扩展能力。七、小结src/kimi_cli/tools/AGENTS.md以极简篇幅确立了 kimi-cli 工具模块最核心的架构约束可以概括为一张依赖图工具层kimi_cli.tools只依赖kosong.tooling的类型契约负责业务能力类型契约层kosong.tooling与 UI 无关的可复用抽象Tool/CallableTool2/ToolReturnValue/DisplayBlock/Toolset桥接层kimi_cli.wire仅对明确实现 UI/运行时桥接的工具开放引用ask_user、read_media、plan其余工具一律禁止触碰。遵循这条规范工具可以在 UI、后台任务、测试等任意环境中复用wire 协议的演进也不会波及工具实现——这正是 kimi-cli 工具体系能够持续扩展而保持边界清晰的根本原因。若要继续深入可阅读 tools/test.py 与 packages/kosong/src/kosong/tooling 源码以及 tests/tools 下针对各工具的测试用例。【免费下载链接】kimi-cliKimi Code CLI is your next CLI agent.项目地址: https://gitcode.com/GitHub_Trending/ki/kimi-cli创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考