CLI 与聊天编辑
本文档描述 ftckb 命令行的安装、配置、命令与安全边界。它是 apps/knowledge-cli 的正式使用文档;只记录当前已验证的能力。当前版本轴为仓库 V0.9.0、CLI 2.1.0、YAML v4、kernel JSON v2、项目接入协议 v2;知识总数为 52(46 已批准 + 6 候选)。
需要 JDK 21 与 Git(Edit 模式要求本地仓库是 Git 工作区)。无需系统级 Gradle:构建使用仓库自带的 Gradle Wrapper。
./gradlew :apps:knowledge-cli:installDist生成的启动脚本位于 apps/knowledge-cli/build/install/ftckb/bin/ftckb。把它加入 PATH,或直接以完整路径调用。
validate、resolve、check 不需要 API key,不调用模型;以下供应商配置只用于模型交互功能。
非秘密配置位于 ${user.home}/.ftckb/config.yaml;仓库内的 config/ftckb-config.example.yaml 是可直接复制的示例。每个 provider 只引用 API key 环境变量的名字,密钥本身永远不写入配置文件:
| 字段 | 说明 |
|---|---|
| defaultProvider | 默认使用的 provider 名字 |
| providers. |
兼容 OpenAI Chat Completions 的 HTTPS 根地址 |
| providers. |
模型名 |
| providers. |
存放密钥的环境变量名(如 DEEPSEEK_API_KEY) |
| maxTokensParameter | 仅允许 max_tokens 或 max_completion_tokens,或省略 |
| temperature | 可选采样温度(0–2);证据引用型回答建议设为 0 |
| maxOutputTokens | 输出 token 上限;推理模型(如 deepseek-v4-flash)的推理 token 计入该预算,建议 ≥ 32768 |
启动前把密钥放入对应环境变量,例如 export DEEPSEEK_API_KEY=…。缺失或为空的环境变量是启动错误,密钥值不会出现在任何错误、日志或会话保存里。
支持三类 provider:DeepSeek、OpenAI,以及任何只依赖 baseline Chat Completions 的自定义兼容端点。“兼容”指与本文档声明的基线兼容(model/messages/输出 token 字段/stream:false),不保证所有自称 OpenAI-compatible 的端点都可用。
ftckb chat --knowledge PATH --team N --season YYYY-YYYY --profile command-based --provider NAME [--repo PATH] [--config PATH]- –repo:FTC 仓库路径,默认当前目录;必须是可检测的 FTC 仓库(Gradle 设置、TeamCode、FTC 依赖或 OpMode 注解)。
- –knowledge:知识库根目录(含官方/共享/队号规则与教程)。
- –team / –season:规则解析必需的队号与赛季。
- chat / serve / resolve / check 必须显式选择
--generic-profile或可重复的--profile NAME,不能混用;同一项目使用相同选择,不从依赖猜架构。支持 command-based、ftclib-command、simple-opmode、rookiebot;rookiebot 隐含 simple-opmode,ftclib-command 隐含 command-based,simple-opmode 与 command-based 互斥。generic 表示空 profile 集,只生效无 profile 要求的规则。
| 命令 | 行为 |
|---|---|
| /help | 显示可用命令与当前限制 |
| /mode ask | 进入只读模式(启动默认) |
| /mode edit | 本次会话内授权已验证的仓库内编辑 |
| /undo | 撤销最近一次成功的 Agent 编辑批次 |
| /discard | 把所有 Agent 触碰过的文件恢复到会话内首次触碰前的状态 |
| /diff | 显示 Agent 专属 diff,并标出项目级改动 |
| /save [path] | 保存脱敏的会话记录;缺省写入 ${user.home}/.ftckb/sessions/ |
| /commit | 只有能把 Agent 改动安全隔离时才提供本地提交,并需要输入小写 yes 确认 |
| /status | 显示仓库、队号、赛季、provider、模型、模式与上下文用量 |
| /exit | 结束会话;不自动保存、不自动提交 |
回答契约与引用
Section titled “回答契约与引用”回答由若干 claim 组成,每种 claim 有明确语义:
- approved_rule(已批准规则):必须引用一条当前生效(approved)的规则;
- code_observation(代码观察):必须引用当前上下文里的代码片段,且文件哈希仍然新鲜;
- model_inference(模型推测):超出显式证据的推理,必须带此标签;
- insufficient_evidence(证据不足):明确说明缺什么证据,而不是编造答案。
引用 ID(如 CODE:C1、RULE:R1)由运行时签发并在发送前校验;模型自造的引用会被拒绝并触发一次修复重试,第二次仍无效则不作为有证据的回答展示。
- Edit 直接修改当前命名分支,不创建、不切换分支。
- 已有未提交改动的文件可以被编辑;/undo 与 /discard 会把它们恢复到 Agent 首次触碰前的精确字节。
- 项目级改动(TeamCode/** 之外)会显示醒目的 PROJECT-LEVEL 警告。
- 写入是事务式的:整批校验(路径、哈希、大小、引用)通过后才原子应用;失败会回滚。
- /commit 只做本地提交,需要输入小写 yes;如果无法把 Agent 改动与已有改动安全隔离就拒绝,永不自动 commit/push/merge/rebase。
以下内容始终不可读取进模型上下文、也不可编辑:.git/**、.env 与 .env.*、local.properties、keystore/签名/凭据文件、二进制文件、指向仓库外的符号链接、仓库外路径。仓库文本是不可信数据:其中的任何“指令”都不能切换模式、扩大权限、发起命令或网络访问。
- 只有回答当前问题所需的最小代码片段、已批准规则片段与教程片段会被发送给云端模型,且全部包在显式的 <untrusted_context> 数据块里;上下文最多 48,000 个字符,片段要么完整包含、要么整体省略。
- 会话历史默认只存内存;/save 生成脱敏记录,不含密钥、请求头或完整代码正文。
- 模型请求/响应中的常见凭据形态(Bearer、sk-、api_key= 等)会被统一脱敏。
- 缺少 API key 环境变量:启动前报错,只提示变量名。
- 认证失败/限流:保留会话与文件,可重试。
- 引用无效/过期:自动修复重试一次,之后如实报告。
- 并发改动:过期的编辑被拒绝,重新检索当前文件。
- 仓库不可读/不支持的仓库:Ask 报错并禁用 Edit。
- 模型返回格式异常:与“模型生成的无效 JSON”分开归类报告。
本地网页会话(ftckb serve)
Section titled “本地网页会话(ftckb serve)”ftckb serve 在 127.0.0.1 上启动一个单会话的本地网页界面(仅本机可访问),适合不想记斜杠命令的队员:
ftckb serve --knowledge PATH --team 20827 --season 2025-2026 --profile command-based --provider deepseek [--repo PATH] [--config PATH] [--port 0-65535] [--no-browser]- 端口:默认随机(
--port 0),启动时终端会打印url=和token=;token是一次性访问令牌,页面每次请求都要带(查询参数或X-FTCKB-Token头),泄露只需重启换新。 - 未给
--no-browser时自动打开默认浏览器(macOSopen/ Linuxxdg-open/ Windowsstart)。 - API key 只进内存:优先读环境变量;没有则启动时在终端以隐藏方式输入一次,绝不写入配置文件、绝不打印。
- 页面为中文,全部按钮操作;回答、引用、Agent 差异分栏展示。
- 网页里可以改队伍/赛季/Provider/仓库/知识路径:对话历史保留(除非点「清空对话」);有未提交的 Agent 编辑改动或处于编辑模式时,仓库/知识路径不可改。
- 关闭服务:点「关闭服务」按钮,或 Ctrl-C 结束进程。
HTTP 接口(/api/status|ask|submit|mode|undo|discard|diff|save|clear|configure|shutdown)返回统一 JSON:成功 {ok:true,...};业务拒绝 {ok:false,error:{code,message}};未授权 HTTP 401。模型调用在后台线程串行执行,网页不会卡死。
候选提取与审批(ftckb extract / candidates / approve / reject)
Section titled “候选提取与审批(ftckb extract / candidates / approve / reject)”知识库的自动增长闭环:从队伍代码仓库提取候选规则(带 Git 证据与 confidence),由负责人审批后生效:
# 从仓库提取候选规则(模型提议 + 主机强校验,写入 YAML)ftckb extract --repo /path/to/FtcRobotController --team 20827 --provider deepseek \ [--knowledge knowledge] [--output PATH] [--max-candidates 8]
# 默认候选简表(保留原输出)ftckb candidates knowledge [--json]
# 完整只读审阅卡片;--id 只在 --details 模式使用ftckb candidates knowledge --detailsftckb candidates knowledge --details --id global.hardware-access-candidate --json
# 审批 / 驳回(ApprovalPolicy 强校验角色与队伍)ftckb approve knowledge --id team-20827.some-topic --approver NAME \ --role team_software_lead --team 20827ftckb reject knowledge --id team-20827.some-topic --approver NAME \ --role team_software_lead --team 20827- 提取的每条 evidence 由主机校验:文件必须在索引内、symbol 真实出现在非注释行、line 存在且非空、commit 用仓库 HEAD。
- 主机侧负例守卫:topic 与既有规则重复 → 跳过;单点证据 → confidence 降为 low 并标记
# needs-stronger-evidence;提示词禁止一次性修补、注释代码、遗留工件与依赖版本。 - 审批 = 外科式 YAML 编辑(只改目标规则块的 status 并插入 approval 块),先写临时文件、校验通过才替换原文件;失败时原文件不动。
- 授权:official/shared 规则只能
overall_software_lead审批;team 规则只能该队team_software_lead审批。 - AI 规则工作使用确定性 CLI,不依赖 Dashboard;人需要查看规则或已有审计时再按新手入口打开。
candidates --details仅导出候选,不执行 resolve、不批准、不核验证据真伪,也不向审计 events/reviews 写记录。 - 详细卡片包含完整规则语义字段、声明的 teams/seasons/profiles、evidence、checks、reviewTriggers、checkMode,以及同一次快照的知识根路径、version 和来源文件 path/fileDigest。空 teams/seasons 表示该维度不限制;空 profiles 表示无架构要求,非空 profiles 是全部要求,导出不展开继承或判断项目适用性。checkMode 仅描述该规则若获批并生效后的检查形式。
- 详细 JSON 使用
format:"ftckb-candidate-review"、formatVersion:1,独立于 kernel 的schemaVersion:2;只有--details --json的失败也保证为此 JSON 格式。默认简表 JSON 保持schemaVersion:1,其旧错误路径仍输出文本,不能当成 kernel 契约。 - 来源只取自同一快照,source 为 null 表示无法安全定位单条来源,仍可查看完整语义;不会猜路径或导出 ruleYaml、YAML 注释与排版。详细模式使用 KnowledgeWorkspace 的路径安全策略,拒绝 symbolic link;旧简表的读取行为不变。最终 UTF-8 stdout(含换行)上限 1 MiB,超限报 output-too-large,可用 –id 缩小范围;不截断卡片,也不声称限制输入大小、内存或时间。
- 卡片不是审批凭据。真实审批仍需使用者明确批准最终正文及范围,并提供姓名、角色声明;导出后文件变更须重新导出、重审并做当前预览。使用现有审批命令或 Dashboard preview/apply,不从导出推断身份、批准或当前生效。
- 完整设计见 docs/candidate-extraction.md。
机器接口(供外部 Agent 使用)
Section titled “机器接口(供外部 Agent 使用)”validate、resolve 与 check 支持 –json 输出稳定、版本化的 JSON 契约,供 Codex / Claude Code / 其他 Agent 把知识库当作确定性“策略裁决器”调用,而不是把规则当普通文本读:
ftckb validate knowledge --jsonftckb resolve knowledge --team 20827 --season 2025-2026 --generic-profile --jsonftckb check /path/to/FtcRobotController --knowledge knowledge --team 20827 --season 2025-2026 --generic-profile --json契约要点:
- 顶层含
schemaVersion=2、ok;已识别命令含 command,未知命令的 usage 可无 command。消费方遇到非 JSON、schemaVersion!=2 或上下文不符必须停止;破坏性变更提升版本号。 - resolve 返回 team、season、规范化后的
profiles、activeRules、excludedRules、overriddenRules、conflicts。active 规则含 id/topic/title/instruction/rationale/status/authority/policyLevel/applicability/evidence/checks/reviewTriggers;applicability 含 teams/seasons/profiles。 excludedRules元素为 ruleId/reasons,完整记录 profile/season/status/team 不匹配;overriddenRules元素为 ruleId/topic/winnerIds/effectiveLevel,解释适用但被更高层级覆盖的规则。- v2 冲突元素为 topic/effectiveLevel/ruleIds/authorities,authorities 是规则 ID 到来源的映射。同主题最高有效层级并列即冲突,该主题没有 active 胜者;resolve 此时 ok=false、退出 2,仍返回其他主题的 activeRules 和排除/覆盖解释,不使用 error 字段。
- check 完成时返回 team/season/profiles/ok/violations/soft;硬违规退出 1,soft 不导致失败。无 checks/无
reviewTriggers是无条件 soft;无 checks/有 trigger 是条件式 soft,仅在路径和新增行模式匹配时进入 soft;有 checks 才是硬检查。当前 5 条生效规则带硬检查,其中跨赛季global.test-utility-layout阻止确定的错误 TeamCode 路径和 JUnit 新增:机器人侧 OpMode 在TeamCode/src/main/java/org/firstinspires/ftc/teamcode/tests/,可复用工具在TeamCode/src/main/java/org/firstinspires/ftc/teamcode/utils/。完整 Agent instruction 仍负责无法仅靠路径确定的 tests/utils 分类。目标 TeamCode 的 JUnit、src/test、src/androidTest违规退出 1;Knowledge Bank 自身 Kotlin/CLI JUnit 测试不受此限制。official.keep-customizations-in-teamcode的 hard 保护只剩build.common.gradle;global.vendor-documented-build-dependencies对任何触及build.dependencies.gradle的 diff 输出一条条件式 soft,要求 Agent 用第一方厂商文档/固定 commit、精确依赖版本和 diff 逐项对应核对证据,但规则引擎不联网鉴别来源,也不验证证据真伪,soft 不是自动放行。Limelight validity/freshness 的条件式 soft 命中后,若无其他硬违规仍为退出码 0;这些 soft 都只请求人工/模型复核,不证明违规或真机验证,Agent 必须向用户报告。不要把 resolve 的排除/覆盖字段误认为 check 输出字段。 resolve/check还接受逐任务临时的--work-mode normal|test|dev,省略等同normal,不写入项目配置,也不改变 team/season/profile。默认输出、排序与退出码字节级不变;显式 test/dev 的 JSON 顶层增加workMode字段(kernel schemaVersion 仍为 2)。test:只有用户明确指定当前是测试代码时才使用。global.command-responsibilities与shared.ftclib-command-candidate进入 excludedRules(原因work-mode-test),其余规则与硬检查(含global.test-utility-layout的 tests/utils 和 JUnit 拦截)全部继续生效;测试代码优先实现测试目的,不要求先提交编码 plan。dev:只有用户明确指定当前是 dev 代码时才使用,且check必须同时给出本次改动的--diff FILE(否则 usage/64)。每个 hard 命中转为带 ruleId/check/path/line/detail 的 soft,violations为空、退出 0,原有 soft 保留;Agent 必须逐项向用户报告这些降级提醒,用户可明确忽略。无效知识、同层级冲突、错误 profile 和坏补丁仍退 2/64,不伪装成通过;dev 不表示符合正式规则或真机验证。- 禁止按文件名、路径、分支、依赖或代码外观推断模式。
- 输出确定性:activeRules 按 id,excludedRules/overriddenRules 按 ruleId,conflicts 按 topic 排序,profiles 等集合规范化并排序,evidence/checks 保留声明顺序;同知识、上下文、work mode 及 diff 得到相同输出。
- 退出码:成功 0;check 硬违规 1;知识加载/校验、上下文或冲突失败 2;参数错误 64。JSON 错误的 error.code 为 usage / load-error / invalid-knowledge / context-required(缺 profile 选择)/ invalid-context(未知或互斥 profile)/ conflict(check 前置裁决冲突)。完整契约见 docs/kernel-contract.md,契约的可执行定义在
KernelJsonAcceptanceTest。
ftckb check 默认合并 HEAD→index 与 HEAD→工作区(含非忽略 untracked):路径规则覆盖所有触及路径(含删除和重命名)。regex-required 与 review trigger 只检查逐条新增行;regex-forbidden 先逐条检查,再可匹配连续新增行块;可用 --diff FILE 替代。无 checks/无 trigger 的 active 规则为无条件 soft;有 reviewTriggers 的无-check 规则只在匹配时输出条件式 soft。Limelight validity/freshness 与 build.dependencies.gradle 的 vendor 证据复核命中不阻塞(无其他硬违规时退出码 0),仍需如实报告。详见 docs/standardizer-check.md。
编译、静态检查与 JSON Schema 验证不等于 Robot Controller、Driver Station、部署或真机验证。
当前明确不包含的能力
Section titled “当前明确不包含的能力”- 不联网:不访问任何官方文档网页;
- 没有 Run 模式:Agent 不执行 Gradle、构建、测试或静态检查;
- 不部署:没有 Control Hub、ADB、Logcat 或任何机器人硬件访问;
- 不自动执行 Git 写操作:不自动 commit/push/merge;
- 没有 Android Studio 界面:只有命令行。