Kimi CLI Agent Flow:用 Mermaid / D2 流程图定义多轮 Agent 工作流
Kimi CLI Agent Flow用 Mermaid / D2 流程图定义多轮 Agent 工作流【免费下载链接】kimi-cliKimi Code CLI is your next CLI agent.项目地址: https://gitcode.com/GitHub_Trending/ki/kimi-cli导读Agent Flow 是 Kimi CLI 在 Agent Skill 之上推出的一项扩展能力你不再需要把对话拆成一条条孤立的 prompt而是可以直接用Mermaid 或 D2 流程图描述整条工作流让流程中的每个节点对应一次对话轮次分支节点根据大模型的choice输出自动决定下一步走向直到抵达END。本文基于 klip-10-agent-flow.md 设计提案结合仓库源码与测试用例系统讲解流程图的最小语法子集、图结构校验、SKILL.md声明方式、/flow:name触发机制与FlowRunner执行原理读完你可以独立编写并运行自己的 agent flow。背景与动机从单次对话到流程图驱动在 Agent Flow 出现之前Kimi CLI 的对话只能通过两种方式驱动交互式 REPL 输入--command单次输入。这两种方式都是一次一问的平铺交互无法表达先执行 A再根据结果决定走 B 还是 C如果条件不满足就回到 A 重试这类带有分支和循环的复杂流程。KLIP-10 的解决方案是引入agent flow让用户用流程图描述整个执行过程每个节点对应一次对话轮次分支节点的出边 label 表示分支值。流程图作为Agent Skill 的扩展通过SKILL.md中的元数据声明类型type: flow并从流程图代码块解析得到见 klip-10-agent-flow.md 的背景与目标小节。设计上明确了几个边界非目标不追求完整 Mermaid/D2 语法仅支持各自的最小子集不引入新的 UI依旧使用 shell UI 输出不处理子图、样式、链接、点击事件等 Mermaid 特性。核心设计SKILL.md 元数据与两段式加载Agent Flow 复用了 Agent Skill 的整套 discovery 逻辑唯一的变化在SKILL.md的 frontmatter 中多了一个type字段--- name: my-flow description: 一个示例 agent flow type: flow ---type: standard | flow默认standardflow类型 skill 会在SKILL.md中查找第一个mermaid或d2fenced codeblock解析为Flow存入Skill.flow未找到有效流程图或解析失败时记录日志并降级为普通 skill 处理。这一点在源码 src/kimi_cli/skill/init.py 中可以直接验证SkillType Literal[standard, flow]Skill模型带有type: SkillType standard和flow: Flow | None None字段parse_skill_text中读取 frontmatter 的type后若为flow则调用_parse_flow_from_skill遍历 fenced codeblock按语言分派到 Mermaid 或 D2 解析器任何ValueError内部是FlowError都会导致skill_type回退为standard并记录 error 日志if skill_type flow: try: flow _parse_flow_from_skill(content) except ValueError as exc: logger.error(Failed to parse flow skill {name}: {error}, namename, errorexc) skill_type standard flow None流程图语法Mermaid 最小子集Agent Flow 的 Mermaid 解析器位于 src/kimi_cli/skill/flow/mermaid.py仅支持以下语法语法元素支持形式Headerflowchart TD/flowchart LR/graph TD其余方向忽略注释%% ...节点ID[文本]、ID([文本])、ID{文本}形状仅携带 label语义上忽略引号 labelID[含特殊字符的文本]引号内可包含]、}、\|等边A -- B、A --\|label\| B、A -- label -- B内联节点定义A([BEGIN]) -- B[...]其他样式与布局语法classDef/style/linkStyle/subgraph/click/direction等会被直接跳过不报错——这一点由_is_style_line与_strip_style_tokens两个辅助函数保证见 mermaid.py。一个完整的 Mermaid flow 示例节点 label 用文本BEGIN/END标记起止注意节点C{Enough?}有两条出边解析器会在校验后把这种出边多于一条的 task 节点自动推断为decision节点_infer_decision_nodes即分支由出边数量决定而不是由节点形状决定。测试用例 tests/core/test_agent_flow.py 中的test_parse_flowchart_basic精确验证了该示例的解析结果A是 begin、D是 end、C被推断为 decision出边 label 为yes/no。流程图语法D2 最小子集D2 解析器位于 src/kimi_cli/skill/flow/d2.py支持以下语法语法元素支持形式注释# ...节点ID: labellabel 省略时使用 ID边A - B、A - B: label链式边A - B - Clabel 仅作用于最后一段节点 ID字母数字或_开头允许./-属性路径如foo.bar与{ ... }块会被忽略。此外 D2 解析器还支持: |mdmarkdown 块作为多行富文本 label测试test_parse_d2_flowchart_markdown_block_label展示了其解析结果。一个典型的 D2 flow 示例a: append a random line to file test.txt b: does test.txt contain more than 3 lines? BEGIN - a - b b - a: no b - END: yes当边语句中出现-时走_parse_edge_statement否则走_parse_node_statement见 d2.py实现上需要跨行/跨块地正确识别引号、转义与注释代码中_split_on_token、_split_unquoted_once、_iter_top_level_statements等函数负责这些词法层面的处理。图结构与校验Flow 数据模型与三条核心规则解析后的流程统一表示为位于 src/kimi_cli/skill/flow/init.py 的数据结构FlowNodeKind Literal[begin, end, task, decision] dataclass(frozenTrue, slotsTrue) class FlowNode: id: str label: str | list[ContentPart] # 支持富文本内容 kind: FlowNodeKind dataclass(frozenTrue, slotsTrue) class FlowEdge: src: str dst: str label: str | None dataclass(slotsTrue) class Flow: nodes: dict[str, FlowNode] outgoing: dict[str, list[FlowEdge]] begin_id: str end_id: strFlowNode.label支持str | list[ContentPart]两种形式后者用于 Ralph 模式等内部场景详见下文。异常层次结构同样定义在此模块class FlowError(ValueError): Base error for flow parsing/validation. class FlowParseError(FlowError): Raised when flowchart parsing fails. class FlowValidationError(FlowError): Raised when a flowchart fails validation.validate_flow函数src/kimi_cli/skill/flow/init.py实现了三条核心校验规则BEGIN / END 通过节点文本label匹配大小写不敏感解析时label.strip().lower()后与begin/end比较且必须且只能各有一个BEGIN 必须能连通到 END从 begin 出发做 BFS 可达性遍历若 end 不可达则抛出FlowValidationError多出边节点必须给每条边标注非空且不重复的 label单出边节点允许 label 缺失或为空label 会被忽略。另外未显式声明的节点允许隐式创建label 默认使用节点 ID——这保证了BEGIN -- TASK -- END这种省略节点定义的常见写法可用测试test_parse_flowchart_implicit_nodes验证。Agent Flow 的发现与加载与 Agent Skill 共用同一套逻辑Flow skill 与普通 skill 完全共用 discovery 逻辑目录来源保持不变见 src/kimi_cli/skill/init.py 中resolve_skills_roots与discover_skills作用域目录内置技能src/kimi_cli/skills/打包后为 PyInstaller_MEIPASS内路径用户技能~/.config/agents/skills、~/.agents/skills以及品牌目录~/.kimi/skills~/.claude/skills~/.codex/skills项目技能work_dir/.agents/skills以及品牌目录work_dir/.kimi/skills等额外目录extra_skill_dirs配置或--skills-dir覆盖scope 为extra发现逻辑同时支持两种布局子目录形式skills_dir/name/SKILL.md规范布局与扁平形式skills_dir/name.md。同名冲突时优先级从高到低为Project User Extra(配置) Extra(插件) Built-in先到先得discover_skills_from_roots中skills_by_name.setdefault保证首个匹配生效。对于 flow skillparse_skill_text会调用_parse_flow_from_skill找到 SKILL.md 中第一个mermaid或d2fenced codeblock 并解析_iter_fenced_codeblocks逐行扫描围栏支持与~两种围栏字符。FlowRunner 与 KimiSoul/flow: 的执行引擎实例级 slash command 注册KimiSoul在初始化时构造实例级 slash commands不再全局注册见 src/kimi_cli/soul/kimisoul.py 中_build_slash_commandsstandard类型 skill 注册为/skill:nameflow类型且skill.flow非空的 skill注册为/flow:namefunc 绑定FlowRunner(skill.flow, nameskill.name).run静态命令来自soul_slash_registry与两类 skill 命令统一去重后构成_slash_commands并通过_slash_command_map建立 name/alias 索引run方法通过_find_slash_command查找支持动态命令。命令前缀常量定义在同文件顶部SKILL_COMMAND_PREFIX skill:、FLOW_COMMAND_PREFIX flow:。FlowRunner 执行循环FlowRunnerkimisoul.py的核心是一个while True遍历循环run方法按以下规则推进当前节点kind end记录日志并返回流程结束当前节点kind begin直接沿第一条出边跳到下一节点BEGIN节点本身不消耗对话轮次其余节点调用_execute_flow_node执行一次对话轮次moves计数 1若moves max_moves抛出MaxStepsReached——DEFAULT_MAX_FLOW_MOVES 1000是防死循环的硬上限同文件第 111 行循环图如C --|no| B也会受此限制。_execute_flow_node对每个节点的处理用_build_flow_prompt(node, edges)组装 prompt 后执行一次_flow_turn内部走soul._turn并包裹TurnBegin/TurnEndwire 事件非 decision 节点直接返回唯一出边的dstdecision 节点从本次轮次新增的最后一条 assistant message 文本中抽取 choice匹配出边。分支选择的 prompt 组装与 choice 解析对于分支decision节点prompt 会追加可选分支值列表示意如下_build_flow_prompt的实现{node.label} Available branches: - 是 - 否 Reply with a choice using choice.../choice.choice 解析逻辑parse_choice位于 src/kimi_cli/skill/flow/init.py使用正则rchoice([^]*)/choice抽取最后一个choice 标签的值并 trim不强制 choice 出现在回复末尾因为 LLM 可能在 choice 之后追加解释文字用[^]*而非.*?是为了避免跨标签匹配得到 choice 后与出边 label精确匹配_match_flow_edge命中即返回目标节点若缺失或匹配失败自动重试在 base prompt 后追加你的上一条回复没有包含有效 choice请用choice.../choice回复其中一个选项的提示最多受max_moves硬上限约束。测试test_parse_choice_last_match验证了取最后一个标签的行为parse_choice(Answer choicea/choice choiceb/choice) b无标签时返回None。Ralph 模式内置的自动迭代循环Ralph 模式是 Agent Flow 引擎的一个特殊应用——一种自动迭代循环通过 CLI 参数--max-ralph-iterations启用定义于 src/kimi_cli/cli/init.pymin-1-1表示无限迭代。FlowRunner.ralph_loop静态方法把用户输入包装成一个带 CONTINUE/STOP 分支的循环流程BEGIN → R1(执行用户 prompt) → R2(决策节点) → CONTINUE(回到 R2) / STOP → ENDR2节点的 label 会明确告诉模型当前处于自动循环中并要求任务完全完成才选 STOP否则选 CONTINUE见 kimisoul.py。max_moves被设置为max_ralph_iterations 1负值时近似无限。在KimiSoul.run中若启用了 Ralph 模式则自动创建并运行该循环流程if self._loop_control.max_ralph_iterations ! 0: runner FlowRunner.ralph_loop( user_message, self._loop_control.max_ralph_iterations, ) await runner.run(self, ) returnCLI 集成与错误处理Agent Flow不新增任何 CLI 参数完全通过 skill discovery 自动加载只要SKILL.md中声明type: flow并包含流程图代码块即可通过/flow:name使用klip-10-agent-flow.md 第 7 节。错误处理与用户反馈策略场景行为Mermaid/D2 语法问题抛出FlowParseError错误消息包含行号如Line 12: Unclosed quoted label图结构问题抛出FlowValidationError指出具体违规节点与原因如Node B has an unlabeled edgeflow skill 无有效流程图记录 error 日志降级为普通 skillchoice 无效自动重试追加必须按格式输出的提示日志记录当前节点与可用分支超过max_moves抛出MaxStepsReached节点无出边记录 error 日志并停止全程通过logger.info/logger.warning记录节点推进与选择结果便于调试。此外run方法会忽略传给/flow:name的多余参数并给出 warning且 flow 启动时会通过track(flow_invoked, flow_name...)记录遥测事件。兼容性与边界仅支持 flowchart且只解析上文所述最小子集BEGIN/END只通过节点 label 识别大小写不敏感若想用其它词作为起止节点需要显式把 label 写成BEGIN/END允许循环图如回到上一节点的边但受max_moves默认 1000限制flow 名称与 skill 名称一致/flow:skill.name分支 label 建议短且稳定避免多行或包含特殊字符FlowNode.label支持str | list[ContentPart]可用于 Ralph 模式等内部富文本场景。小结Agent Flow 用最小的语法成本把 Kimi CLI 从单轮对话扩展为可分支、可循环、可持续推进的多轮工作流解析层mermaid.py / d2.py负责把流程图变成Flow数据模型加载层skill/init.py通过type: flow元数据把流程图绑定到 skill执行层kimisoul.py 中的FlowRunner在同一个 session/context 中逐节点推进直到抵达END。无论是想复现示例中的循环搜索直到满意流程还是把 Ralph 自动迭代模式应用到自己的任务上都可以从本仓库的源码与 tests/core/test_agent_flow.py 测试用例中找到可直接对照的完整实现。【免费下载链接】kimi-cliKimi Code CLI is your next CLI agent.项目地址: https://gitcode.com/GitHub_Trending/ki/kimi-cli创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考