持续打磨适合自己的AI Agent

过去一个月,我在一个 agent 配置仓库里改动了 51 个文件、约 2500 行。改的不是业务代码,而是 AI agent 自己的"运行环境":模型路由、权限矩阵、提示词缓存、上下文压缩、技能治理。这些问题很少出现在业务开发教程里,但每一个都真实地烧过 token、坑过行为。这里挑九件事记录一下,多数与具体工具无关。

一、最危险的配置 bug 是不报错的那种

一个月内先后揪出三个同族 bug,全是键名单复数写错:

  • permission.skills ------ 实际生效的键是 skill(单数)。技能隔离块(deny-all 加 allowlist)从引入那天起就是死的;
  • attachments.image ------ 实际是 attachment(单数)。图片自动缩放配置死了三天才被 schema 对照发现;
  • 一个手写的 compat 兼容块 ------ 字段路径根本不被解析器读取,整块是死代码。

共同点:配置解析器对不认识的键静默忽略。没有报错,没有警告,配置"看起来生效了",行为上只表现为"模型不太听话"------而这种症状太容易被归因到提示词写得不好。

应对方式:

  1. 用工具自带的 JSON Schema 做严格对照,或直接读配置解析源码确认键名;
  2. 把配置校验放进 CI:解析配置文件,递归比对 schema,未识别的键直接报错;
  3. 行为验证:改完配置要真实触发一次确认生效,"改完了"不等于"生效了"。

教训:对声明式系统,"没报错"和"生效了"之间隔着一条鸿沟。

二、一段正则的两条命:从丢转义到状态机

JSONC 解析前要剥离尾逗号。第一版正则写成了 /,(s*[}\]])/g------\s 丢了反斜杠,变成匹配字面字符 s

这个 bug 阴险的地方在于它是"半死"的:s* 可以匹配零次,所以 ,} 这种紧凑写法能匹配成功,而 , } 这种带空白的------恰恰是尾逗号最常见的排版------永远匹配不上。偶发的成功掩盖了失败路径,比全死的 bug 难发现得多。

第二版修正为 /,\s*(\}|\])/g。但正则方案有先天缺陷:它不认识字符串字面量。提示词模板里一旦出现 "list: a, }" 这样的内容,字符串内部的 , } 会被误删。

第三版放弃正则,重写为逐字符状态机 stripTrailingCommas():跟踪 inString 状态和反斜杠转义,只在字符串外剥离逗号。三十行,零依赖,语义正确。两处 JSONC 剥离器统一换用。

教训:正则处理不了有嵌套上下文的内容(引号、转义)。当你发现自己在为正则不断打边界补丁时,就是换状态机思维的时候。

三、权限设计:默认 ask、last-match-wins 与提权级联

bash 权限原本是 "*": "allow"------全放行。问题是破坏性命令的变体列举不完:rm -rf 换个拼写、加个空格、套一层别名,都会命中 * 直接执行。

改成默认 "*": "ask",外加高频安全命令的显式 allowlist(git status/diff/lognode scripts/*npm run/testrg 等)。关键机制:权限列表按 last-match-wins 解析,通配符必须放在列表最后------放前面它会先命中,后面所有精细规则全部变死。顺带把 git push --force-with-leasegit clean -fdgit checkout . 这些"半破坏"命令也归入 ask。

另一个容易忽视的是提权级联 :写者 agent 全部加了 task: "*": "deny"。如果主 agent 的写权限受限,却允许它派生子任务,那它可以委派一个不受限的子 agent 干活------限制形同虚设。权限矩阵必须在委派维度上闭合。

权限还能表达"分工"而不只是"防御":/simplify 流程设计成两段式------只读的贵模型做分析,便宜模型执行机械编辑。执行者的权限矩阵里只给分析者开 allow,其余委派全 deny。流程结构直接编码进权限矩阵,不依赖提示词自觉。

四、思考强度是请求参数,不是模型

reasoning_effort(配置里叫 reasoningEffort,请求体里是 snake_case)是请求级 的思考强度控制(low/high/max),不是独立的模型 id。有的框架会自动生成 -high/-low 模型变体,有的不会------不会的就只能靠 per-agent 的 options 深度合并注入,绝不能动模型层配置,否则模型矩阵会爆炸。

由此得到三层路由:

层级 典型角色 配置
trivial 搜索、查资料、纯问答 便宜模型 + thinking disabled(provider 级关闭,官方省钱开关)
mid 规划、常规多文件实现 便宜模型 + thinking enabled + reasoningEffort: low
deep 根因分析、评审、重实现 贵模型 + 默认 high

原则:模型选择解决"能不能做",思考强度解决"想多认真",两个维度正交。别用贵模型解决强度问题,也别指望便宜模型靠拉高强度追上深度推理。

附带一个冷知识:thinking 开启时 temperature/top_p 被静默忽略。所以便宜模型(thinking off)设温度 0 有意义,贵模型(thinking on)设了也是白设。

五、token 经济学:六个计数细节

给两个模型建了成本表(USD/1M tokens):便宜档 input 0.22 / output 0.66 / cache read 0.007;贵档 input 0.66 / output 1.98 / cache read 0.022。围绕这张表有一串反直觉的发现:

1. cache write 没有独立价格。 提供商不单独公布缓存写入价------缓存写按 cache-miss 的输入价计费,所以成本表里 cache_write 直接映射自 input。建模时若拿"平均价"糊弄,会系统性低估首轮成本。

2. cache read 比 input 便宜 30 倍。 这直接决定了提示词纪律:字节稳定前缀。所有易变内容(时间戳、随机 ID、动态文件列表)必须追加到 payload 尾部------前缀里一个字符的变动就会击穿整段缓存,重新支付全价输入。规则文件、agent 提示词的顺序都不能随意重排,哪怕语义等价。

3. 贵模型早压缩。 上下文压缩器(DCP 插件)的阈值改成按模型区分:贵模型 55K/26K,全局默认 77K/38K。贵模型输入价是便宜模型的 3 倍,同样 token 数烧的钱不同,压缩阈值理应不同。压缩阈值是经济参数,不是技术参数。

4. 百分比阈值在大窗口下失效。 模型窗口 1M 时,"到 60% 再压缩"意味着 600K------普通会话(20K--200K)永远触发不了。改成绝对 token 阈值才符合实际会话分布。

5. 负成本。 成本估算脚本一度算出负数:cache-read 的 token 计数可能超过 raw input 计数(两边口径不一致)。修复是一行 Math.max(0, input - cacheRead)。所有派生指标都需要物理约束兜底------成本不可能为负,上下文不可能为负。

6. 输出裁剪有最优区间。 工具输出裁剪设 800 行 / 20KB,比官方默认 2000 行保守。但试过更激进的 200 行 / 8KB 后回退了:正常文件读取被截断,agent 只好反复重读,端到端 token 反而更贵。省 token 的目标是总成本,不是单条消息的体积。

六、同步脚本的删除对账:用 git 历史定义"受管集合"

配置仓要同步到全局目录(独立副本,不是 symlink)。复制好写,难的是删除:仓库里删掉的技能会残留在全局目录里继续生效------幽灵配置。

又不能简单做"镜像删除",因为全局目录里可能有用户自建、从未进过 git 的文件,误删不可恢复。解法是用 git 历史计算受管集合:

powershell 复制代码
$managed = (git ls-files) `
         + (git log --all --diff-filter=D --name-only)

即"当前跟踪的文件 ∪ 历史上任何时刻删除过的文件",剥掉仓库前缀得到相对路径。同步时只对账 skills/agents/commands 三个受管子目录,删除条件严格限定为:在 $managed 中、且源里已不存在。用户本地自建文件因为从未被 git 跟踪,永远不会进受管集合,天然安全。配合 -WhatIf 预览和 -Destination 测试覆盖。

还有一个 Windows 特色坑:8.3 短路径 。调用方可能传 C:\Users\ADMINI~1\...,而 Get-ChildItem 返回解析后的长路径,直接拿字符串做 Substring 算相对路径会错位。先 (Get-Item -LiteralPath $dst).FullName 归一化再计算。

教训:任何"删除远端多余文件"的同步逻辑,先回答"多余"的定义权归谁。让版本历史来定义,比让脚本现场猜测可靠得多。

七、绕开视觉模型的硬约束:一张图不够,就切九张

多模态通道有两个硬约束:拒收 PDF(只认 JPEG/PNG/GIF/WebP);每张图内部降采样到约 800×800 的像素预算。后者的后果是------大截图、文档照片里的小字,降采样后不可读,无论你上传多高的分辨率

对策全部放在客户端预处理,把问题搬进自己能控制的域:

  • PDF → 栅格化:按页子集转换,zoom 2.0(约 144dpi)平衡清晰度与体积;
  • 大图 → 切 N×N 瓦片,带 10% 重叠------重叠区防止文字正好被切断在瓦片边界;
  • 每张瓦片单独发送,各享自己的 800×800 预算,等效分辨率翻倍甚至更多,结果在文本层合并;
  • 经验规则:长边超过 1600px 或存在密集小字就切;300-DPI 密档直接 3×3。

上传端配套约束:auto_resize、长边上限 1600px、base64 上限 2MB。既然模型端必然降采样,超大上传只是浪费编码字节,还会撑大缓存前缀。

教训:面对模型硬约束,重试和祈祷没有意义;把约束读清楚,然后在上游把输入变换到约束的舒适区里。

八、agent 行为契约:结构性不可能、显式豁免与拒绝权

一个"单模型内联执行器"agent 的设计沉淀了三条提示词工程经验:

承诺要结构化,不要靠自觉。 "零委派"不是只在提示词里写"你不许委派",而是权限矩阵直接 task: "*": "deny",连后台助手工具一起 deny(它们跑在内置小模型上,会破坏单模型保证)。委派在结构上不可能发生。文字约束在长上下文里会衰减,权限约束不会。

局部与全局规则冲突要显式豁免。 全局规则写着"2+ 步骤先规划""能委派就委派",而这个 agent 的存在意义恰恰是全程内联。不处理这个冲突,agent 会真的去尝试遵守全局规则------调用一个不存在的子任务工具,然后失败。解法是在提示词里写一条"Intentional scope exemption":明确列出哪些全局规则在此被豁免、为什么。规则不会自动让位,冲突必须人工裁决并写明。

拒绝契约。 明确规定什么时候返回"干净的拒绝"而不是"降级的部分尝试":收到多模态输入(纯文本模型应告知换视觉通道,绝不猜测图片内容)、无法诚实完成任务时直说。半吊子交付比拒绝更贵------它占用验证时间,还掩盖了失败信号。

九、可达性治理:存在 ≠ 可用

技能库切到 default-deny 的 allowlist 模式后,出现了一种新型死代码:孤儿技能------文件存在,但没有任何 agent 的 allowlist 引用它,运行时永不可达。一次清点出 7 个孤儿,逐一接线到合适的 agent。

讽刺的是:接线时用的权限键本身就拼错了(见第一节),所以这次"接线"也是死的,几天后才真正修好。两层 bug 会互相抵消出一种假象------修可达性问题之前,先验证可达性机制本身是活的。

治理动作还包括收敛:技能总数 24 → 20;语义重叠的合并(词汇表类并入领域建模类,明确唯一 owner);两个评审命令合并为一个,内嵌范围门(有效 diff 超过 500 行时先输出分级计划而不是硬审);互斥场景的技能之间加交叉引用,防止 agent 选错工具。

所有"可插件化"的系统都会这样腐烂:添加没有成本,删除有阻力。需要定期做可达性审计------枚举所有资源,检查每一个是否存在活的引用路径。

结语

这一个月改动的主线可以压缩成一句话:声明式系统(配置、提示词、权限矩阵)的正确性不能靠"看起来对",只能靠可验证的机制------schema 校验、行为验证、结构性约束、可达性审计、git 历史对账。

另一条主线是:经济参数必须进入设计决策。缓存价格决定提示词排版,模型价差决定压缩阈值,裁剪尺寸决定端到端成本。一个系统可以技术上全对、账单上全错------而在 agent 基础设施里,账单就是行为的一部分。

项目地址:https://github.com/znlgis/my-opencode-deepseek-config

相关推荐
编程的一拳超人16 小时前
DeepSeek Harness Linux/macOS/Windows 本地下载、启动与模型配置指南
linux·windows·macos·deepseek
AC赳赳老秦20 小时前
文旅市场公开数据分析:基于 OpenClaw 采集景区客流与门票公示数据,生成区域文旅热度监测报告
java·c语言·python·php·symfony·deepseek·openclaw
liulilittle21 小时前
为什么需要回程闲置保护?
ai·llm·prompt·agent·tools·subagent·opencode
AC赳赳老秦1 天前
环保监测公开数据应用:OpenClaw 抓取空气与水质公开监测数据,开展区域环境质量趋势分析
大数据·数据库·人工智能·python·php·deepseek·openclaw
大模型真好玩1 天前
大模型训练全流程实战指南实战篇(十五)——预训练数据治理
人工智能·agent·deepseek
阿里云云原生2 天前
构建 RLHF 的数据飞轮:DSH 如何将护栏决策自动转化为偏好学习信号?
deepseek
AC赳赳老秦2 天前
农产品公开数据应用:OpenClaw 抓取农产品价格、产销公开数据,实现农产品行情动态监测
java·c语言·javascript·python·php·deepseek·openclaw
梦想的颜色2 天前
【AI速览】GPT‑6 Astra 硬核深度解析:不是噱头 AGI,而是面向端到端 Agent 工作流的前沿旗舰
gpt·大模型·openai·agent·deepseek·gpt6‑astra·大模型横评