Agentic体验:1,324次调用我的CLI,15.9%的错误率

我的CLI最常见的用户并不是我自己 lql 是一个用 Rust 开发的CLI工具,用于管理Linear的问题任务。我开发这个工具是因为现有的替代方案并不能满足我的实际使用需求:让一个自主的AI代理来管理问题任务。 为什么我必须开发自己的CLI Linear的MCP服务是我的第一个尝试。这个想法很优雅:搭建一个MCP服务器,从而直接向代理公开Linear的API。但是在实际使用中,它的运行速度很慢且非常不稳定,每次调用时,代理都需要从头开始构建GraphQL查询。这增加了在每次调用中引发不存在字段的机会。用了一两周后,我把这个方案卸载了。 社区版CLI(schpet 的 linear)是我的第二个尝试。这个工具主要是为人类用户设计的,带有交互式菜单、箭头选择以及确认提示。但问题是,一个代理不能操作交互式菜单。也不适合。 Linear 的“智能代理”功能。 2026年3月,Linear 发布了一个集成了 AI 的智能代理。乍一看听起来很理想,直到你发现其局限性:它仅能在Linear的Web界面内使用,没有终端调用功能,没有API,也无法与外部工具集成。它就是一个嵌在自己用户界面中的聊天机器人。如果你的工作流包括“编程的代理也需要管理问题”,Linear 的代理功能无法满足需求。 基于数据的设计:初步分析 在开发 lql 之前,我解析了Claude Code与Linear交互时165次会话中的每一个错误。结果表明,共记录了500多个错误,370次重试,并估算出每月约有700,000个token被浪费。--sort忘记使用40次;写成了--state "Todo" 而非 --state unstarted共12次;--no-interactive未添加导致CLI挂起,等待键盘输入64次。(全套数据细节见原始文章。) 基于这些数据,我设计了 lql 的用户界面。我并没有猜测一个代理需要什么,而是使用测量得到的数据。这形成了一些基础设计决策:输出格式为精简化版本TOON(每个问题约25个token,而不是繁多的JSON格式),为LLM容易混淆的选项添加别名(例如--status → --state),对值进行标准化(比如Todo 转化为 unstarted,urgent 转化为 1),并提供建议正确命令的错误提示信息,而不是简单地显示“未知选项”。 当时我并不清楚,实际上自己是在应用Postel法则。这是后来才意识到的。 第二次分析:lql在生产环境中的一个月 lql上线已经一个月。Claude Code每天会调用它30到50次,用于创建问题、更新状态、链接依赖、查询细节等。我自己从来不手动使用它,因为对我而言,手动管理问题不是兴趣所在。我有代理来解决这些事情。如果哪天我必须亲自执行lql,那说明出了严重的问题。 lql唯一的用户是一个LLM。这让整个设计变得完全不同。 所以我再次解析了Claude Code调用lql的会话日志,搜寻错误。 指标 数值 分析的会话数 200 lql 的调用次数 1,324 错误数 (is_error: true) 210 错误率 15.9% 15.9%的错误率未包括因为并行调用失败且被Claude取消的调用。这里只计算CLI实际发生的错误。 错误分类 并非所有错误都是一样的。有些表明缺乏约定,而有些则表明需要添加操作。 错误 频率 实例 未找到Label 20 --label tokamak (在该团队中不存在) --title 用作 create 的选项 8 lql create --title "Epic: ..." --team PROD 将 show/get 写成 view 6 lql show PROD-911 relate 参数顺序错误 12 lql relate PROD-834 PROD-833 blocked-by 尝试 update --team (移动问题任务) 超过15次 lql update PRIV-32 --team PROD relates 写成 related 2 lql relate PROD-912 relates PROD-910 --body 用于 comment 1 lql comment PROD-926 --body "文本" --comments 用于 view 1 lql view PROD-824 --comments 其余是Linear的API错误、1Password认证问题、或shell错误(长heredocs中的引号破裂)。 ...

2026年4月29日 · Fernando

上下文工程:区分优秀与普通AI代理的隐形技能

想象一下,你聘请了一位才华横溢的咨询师。他拥有两个博士学位,会说七种语言,并能解决你甚至不知道存在的问题。你把他安排到一个会议室,然后告诉他:“我需要你重新设计项目的认证系统。” 咨询师看着你,点了点头,问道:“哪个项目?” 你没有提供代码访问权限,也没有解释其架构。他不知道你在使用JWT令牌还是会话cookie,也不了解你使用的编程语言或微服务数量,更不知道为什么你上一次迁移会失败。 这个咨询师,就像你的LLM(大型语言模型)。而你刚刚犯了90%的AI代理使用者都犯的错误:关注大脑本身,而不是关注大脑所看到的信息。 Prompt工程已经过时——上下文工程长盛不衰 过去几个月,我在每个论坛、每条推特讨论线程、每场团队会议中都看到同样的对话:“GPT-5还是Claude Opus?”“哪个模型对代码更好?”“哪个模型推理能力更强?” 我的回答,每次推算下来,都是一样的:这不重要。当然,不是完全不重要。但一个顶尖模型与另一个顶尖模型之间的差异,与提供优秀上下文和垃圾上下文之间的差异相比,简直微不足道。 一个表现平庸的模型但配备完美上下文,永远优于一个顶尖模型却给它垃圾上下文。总是如此,没有例外。 这就有了一个名词:上下文工程。而且,它与Prompt工程完全不同。 Prompt工程是编写一个好的提示。它是选择正确的词语、结构请求、加入示例。这很重要,但只是一个部分。 上下文工程则是设计模型看到的所有信息:哪些输入信息、顺序如何、空间有限时需要舍弃什么、压缩什么、哪些是必须保留的。这是为LLM做信息架构。 简单来说:Prompt工程是提出一个好的问题。而上下文工程则是在考试开始前决定学生桌上有什么书籍。 四阶段记忆:你看不到的生命周期 OpenAI最近发布了两个Cookbook文章,详细解构了具有长期记忆的代理如何进行上下文管理。这不是RAG,也不是矢量数据库,而是一种基于状态的系统,像一本具有严格规则的田野笔记本。 其模式是“本地优先”和“基于状态”的:一个结构化的状态对象与代理一起更新,贯穿每个阶段。 flowchart TD A["1. 注入阶段\n(会话开始)"] --> B["2. 提纯阶段\n(对话期间)"] B --> C["3. 合并阶段\n(会话结束后)"] C --> D["4. 修剪阶段\n(持久性保存)"] D -->|"新的会话"| A A1["将状态渲染为YAML\n+全局记忆(最多6个)\n+优先规则"] -.-> A B1["save_memory_note()\n验证持久性\n确保可操作性\n拒绝PII和推测"] -.-> B C1["异步任务\n合并会话→全局\nLLM辅助去重\n过滤临时记忆"] -.-> C D1["修剪会话: 最近N次\n注入修剪记忆入\nsystem prompt"] -.-> D style A fill:#2d3748,stroke:#4a9eed,color:#fff style B fill:#2d3748,stroke:#ed9a4a,color:#fff style C fill:#2d3748,stroke:#9a4eed,color:#fff style D fill:#2d3748,stroke:#4aed5c,color:#fff 阶段1:注入——考试桌上的资料 当会话启动时,代理会创建其初始上下文。这不是随机的,而是一个具体结构: YAML前置数据,包含用户状态(如偏好、配置)。 全局记忆列表:最多6个,按最近使用排序。为什么是6个?因为超过6个会相互竞争,导致信息模糊。少即是多。 <memory_policy>块,带有明确的优先规则。 优先规则至关重要:当前输入 > 会话记忆 > 全局记忆 > 同范围内的最新信息。如果用户说“我现在用Vim”,而你的全局记忆却显示“使用VS Code”,则以用户最新输入为准。虽然看起来显而易见,但没有明确规则的情况下,模型有时会选择其“记住”的内容而非用户给出的新信息。 ...

2026年3月11日 · Fernando

你的AI编程助手不过是个有妄想症的while循环

第一次使用Claude Code重构整个模块时,我几乎产生了宗教般的震撼体验。描述需求后喝了杯咖啡回来,就看见14个文件变更的PR,测试用例全更新,提交信息也像模像样。“这简直是魔法”,我当时这样想。 但根本不是魔法。就是个while循环。 OpenAI的Michael Bolin最近发文拆解了Codex CLI的内部机制。原来这些AI编程助手背后的秘密既不是革命性算法,也不是神秘神经网络,而是一个循环调用LLM、执行工具直到任务完成的简单流程。 让我们来庖丁解牛。 状态机:5阶段循环结构 所有编程助手——Codex、Claude Code、Cursor等都遵循相同的基础模式。Michael Bolin将其描述为5阶段循环: flowchart TD A["1. 提示词组装"] --> B["2. 模型推理"] B --> C{需要工具调用?} C -->|是| D["3. 工具执行"] D --> E["4. 工具结果反馈"] E --> B C -->|否| F["5. 生成最终响应"] F -->|新输入| A 用开发者能懂的话说: 提示词组装:构建包含系统指令、可用工具、读取文件、对话历史等完整上下文的提示词 模型推理:将提示词token化后传给模型,获取思维链/工具调用/文本响应 工具调用:若模型请求工具(读文件/执行命令等),则运行对应操作 工具反馈循环:将工具执行结果作为新增上下文再次传给模型,重复2-4阶段 结果生成:当模型判定任务完成时输出最终响应 就这么简单。没有知识图谱,没有符号规划器,没有复杂架构。本质上就是个封装了LLM的while循环。 优秀助手与平庸助手的差异不在循环结构——它们完全一致——而在于每个阶段的实现细节。 阶段1:提示词工程的艺术 第一阶段是核心所在。在LLM看到任何代码前,助手需要构建包含以下要素的提示词: flowchart LR subgraph 提示词组件["提示词组装"] 方向 TB SP["系统指令\n(角色设定/规则)"] Tools["可用工具\n(读/写/Bash等)"] Ctx["已读取文件/图像"] Inst["CLAUDE.md/AGENTS.md\n(项目规范)"] Env["环境信息\n(OS/git状态等)"] Hist["完整对话历史"] User["用户最新消息"] end SP --> 最终提示 Tools --> 最终提示 Ctx --> 最终提示 Inst --> 最终提示 Env --> 最终提示 Hist --> 最终提示 User --> 最终提示 这里有个关键设计决策:组件顺序至关重要。提示词按稳定性降序排列:系统指令最前(永不变动),工具定义次之(很少变动),最后是动态增长的文件内容和对话历史。 ...

2026年3月11日 · Fernando