ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

如何构建真正好用的 LLM Agent?从上下文工程到 Skills 与 Compaction 的落地实践

如何构建真正好用的 LLM Agent?从上下文工程到 Skills 与 Compaction 的落地实践 1. 为什么你的 LLM Agent 跑三分钟就开始胡言乱语先说一个我踩过的坑。去年做一个代码审查 Agent单轮任务跑得好好的一旦让它连续处理十几个文件到第八个文件左右就开始出现诡异行为明明文件里没有的变量它说存在明明测试没跑它说通过了。查了半天以为是模型能力问题换了个更大的模型结果只是把崩溃点从第八个文件推迟到第十二个文件。后来才想明白这不是模型笨是上下文被垃圾信息塞满了。每一轮的工具输出、编译日志、中间思考全部堆在历史里KV 缓存线性膨胀模型注意力被大量无关内容稀释最后连当前任务是什么都抓不住。这就是 LLM Agent 从能跑到好用之间那道最真实的坎。核心循环本身简单得不能再简单——观察、思考、行动循环到任务完成。但生产环境里这个循环会撞上三堵墙上下文窗口有限、任务完成判断不可靠、多轮成本失控。这篇文章面向正在搭建多 Agent 协作系统的开发者把上下文工程、Skills 封装、Compaction 压缩这三件事拆成可复制的配置和规则。读完你应该能拿到一套能直接落地的分层上下文结构、Skills 定义模板以及 Compaction 的触发阈值和验证动作。适合谁看已经写过基础 Agent 循环、被长任务稳定性折磨过、想搞清楚为什么我的 Agent 跑着跑着就飘了的人。如果你还在纠结怎么调 API那可能得先补一下基础。先说结论上下文工程是 LLM Agent 真正的核心竞争力Skills 是按需加载的技能包Compaction 是上下文满了之后的压缩策略。三者配合才能让 Agent 在长任务里保持稳定和低成本。下面逐个拆。2. TaoToken 前置准备把模型接入层先理顺在动手改 Agent 架构之前得先把模型调用这层理顺。很多上下文工程的优化效果会被一个不稳定的接入层吃掉——比如你精心设计了分层上下文结果每次请求因为网络抖动重试三次延迟和成本全乱了。我现在的做法是把模型接入统一走一个兼容层Base URL 指向https://taotoken.net/api这样切换模型、做 A/B 对比、统计 token 消耗都在一个地方管。对于多 Agent 场景这点尤其重要主 Agent 和子 Agent 可能用不同模型统一接入层能让成本核算和限流策略集中处理。具体操作上先拿到 API Key。进入控制台创建密钥路径是 console 页面下的 api-keys 管理。创建时建议按用途命名比如agent-main、agent-sub-review方便后面按 Agent 角色统计消耗。拿到 Key 之后配置方式取决于你用什么框架。如果是直接调 OpenAI 兼容接口改环境变量就行export OPENAI_BASE_URLhttps://taotoken.net/api export OPENAI_API_KEYsk-你的密钥如果你用的是 Claude Code 这类工具配置会写在 settings 文件里。这里给一个可复制的 settings 片段路径是~/.claude/settings.json{ env: { ANTHROPIC_BASE_URL: https://taotoken.net/api, ANTHROPIC_API_KEY: sk-你的密钥, ANTHROPIC_MODEL: claude-sonnet-4-20250514 } }注意这里三件套要写全Base URL、Key、Model ID。少任何一个都会在启动时报认证或模型找不到的错。Model ID 要和你实际要用的模型对齐别照抄去模型列表里确认当前可用的 ID。如果你用的是 Codex 系的工具配置写在~/.codex/auth.json{ OPENAI_API_KEY: sk-你的密钥, OPENAI_BASE_URL: https://taotoken.net/api }对于 Cline 这类带 MCP 的编辑器插件配置在 MCP 设置里同样是 Base URL Key Model ID 三件套。Cline 的 MCP 配置通常长这样{ mcpServers: { taotoken: { command: npx, args: [-y, your-mcp-server], env: { OPENAI_BASE_URL: https://taotoken.net/api, OPENAI_API_KEY: sk-你的密钥 } } } }配好之后先别急着上多 Agent用最简单的单轮请求验证一下接入层通不通。这一步很重要因为后面所有上下文工程的调试都建立在模型调用本身没问题这个前提上。验证方法在第四节展开。关于模型选择多 Agent 场景下我的建议是主 Agent 用能力强的模型负责规划和最终判断子 Agent 用便宜快速的模型负责信息提取和摘要。这样成本能压下来一大截而质量损失很小因为子 Agent 的任务通常是读文件返回摘要这种低复杂度工作。接入层理顺之后就可以进入正题了。3. 上下文分层配置把历史存储和喂给模型的内容分开上下文工程的核心思想一句话把历史存储和实际喂给 LLM 的上下文分开。历史可以无限长但每一轮喂进去的上下文要精心准备刚好够用就行。最朴素的 Agent 循环是这样的token_history task_instruction while task not completed: generated_tokens LLM(token_history) thoughts, action parse(generated_tokens) output exec(action) token_history [thoughts, action, output]问题在于token_history只增不减几轮之后就把窗口塞满了。改造后的版本引入context_buildtoken_history task_instruction while task not completed: context context_build(token_history, external_info) generated_tokens LLM(context) thoughts, action parse(generated_tokens) output exec(action) token_history [thoughts, action, output]context_build就是上下文工程的主战场。我把它分成四层来管理这个分层结构可以直接抄层级内容生命周期是否进 KV 缓存前缀稳定前缀层系统提示、角色定义、工具列表整个任务不变是记忆层跨任务积累的经验、身份认知任务间更新是任务层当前任务指令、目标单任务不变是临时层当前轮的工具输出、环境状态单轮丢弃否稳定前缀层和记忆层放在最前面保证 KV 缓存前缀不变。任务层紧随其后。临时层追加在最后用完即丢不存入历史。这里有个关键约束KV 缓存。如果你每一轮都动态增删前缀内容缓存就会失效每轮都要重新计算成本飙升。所以稳定前缀层要尽量固定需要动态调整的东西放到临时层。临时层的写法while task not completed: context stable_prefix memory task_instruction current_log generated_tokens LLM(context) thoughts, action parse(generated_tokens) output exec(action) token_history [thoughts, action, output] # 只存结果不存 current_logcurrent_log是这一轮特有的信息比如当前文件内容、当前敌人位置、当前编译输出。下一轮它就没意义了所以不存历史。动态工具切换也是上下文工程的一部分。工具列表定义在稳定前缀里但你可以按阶段调整可用工具集。比如编程 Agent 开始用文件浏览工具中间切到编辑工具最后换成测试工具。实现方式是在context_build里根据当前阶段过滤工具列表def context_build(token_history, external_info, phase): tools TOOL_REGISTRY[phase] # 按阶段取工具子集 return build_prompt(tools, token_history, external_info)这样每一轮喂进去的工具定义都是当前阶段需要的不相关的工具不占空间也减少了模型选错工具的概率。分层配置做完之后你会发现 Agent 的稳定性有明显提升因为模型每一轮看到的都是干净、聚焦的上下文而不是一堆历史垃圾。但光有分层还不够技能怎么按需加载、上下文满了怎么压缩是接下来两件事。4. Skills 封装与 Compaction 触发规则Skills 是结构化的技能包本质是提示词 工具集 指令的组合需要时才加载进上下文。为什么不直接写成一个超长系统提示因为窗口有限Skills 的逻辑是需要什么用什么不需要的不占空间。一个 Skill 就是一个文本文件。下面是一个可复制的 Skill 定义模板以 git 提交为例# /commit —— 创建 git 提交 ## 触发条件 当用户要求提交更改时加载。 ## 执行步骤 1. 运行 git status 和 git diff 查看所有变更 2. 分析差异概括变更性质新功能、修 bug、重构、文档 3. 起一个简洁的提交信息1-2 句重点写为什么而不是做了什么 4. 暂存相关文件避免包含密钥、.env 等敏感文件 5. 创建提交 ## 可用工具 Bash(git status), Bash(git diff), Bash(git add), Bash(git commit)这个文件在 Agent 调试代码时根本不会被加载只有用户明确要求提交时才进上下文。Skills 更妙的地方在于它可以被 Agent 自己写入和更新更新 Skill 就等于更新提示词这是一种去中心化的持续学习方式。不过要警惕Skills 是最容易过拟合测试集的手段。针对特定任务定制的 Skill 能刷高评分但不代表通用能力真的提升了。我见过一个团队为了刷某个 benchmark写了二十几个高度特化的 Skill结果换个任务全废。Compaction 是上下文满了之后的压缩策略。不同场景策略不同编程 Agent 可以扔掉冗长的编译日志只保留成功/失败结果。ML 研究 Agent 只保留验证损失不保存完整训练曲线。实在没办法了用另一个 LLM 做摘要压缩。Compaction 的触发规则我建议用 token 占比而不是绝对轮数因为不同任务每轮消耗差异很大。可复制的触发配置COMPACTION_CONFIG { trigger_ratio: 0.75, # 上下文占用超过窗口 75% 触发 keep_recent_rounds: 5, # 保留最近 5 轮完整历史 summary_model: fast, # 用便宜模型做摘要 preserve_keys: [task_goal, final_result, error_signals] }触发逻辑def maybe_compact(token_history, window_size): used count_tokens(token_history) if used / window_size COMPACTION_CONFIG[trigger_ratio]: recent token_history[-COMPACTION_CONFIG[keep_recent_rounds]:] old token_history[:-COMPACTION_CONFIG[keep_recent_rounds]] summary summarize(old, COMPACTION_CONFIG[summary_model]) return [summary] recent return token_historypreserve_keys里列的东西在压缩时必须保留尤其是任务目标和错误信号。我踩过的坑是压缩时把错误信息也摘要掉了结果 Agent 重复犯同一个错。多 Agent 场景下Compaction 还要考虑子 Agent 的上下文隔离。主 Agent 不直接读大文件而是派子 Agent 去读子 Agent 返回摘要后自己的上下文直接丢弃。主 Agent 只看到简洁结论上下文保持整洁。这就是多 Agent 的本质——上下文隔离类似面向对象里的对象隔离。验证请求是否正常工作用这个最小请求curl https://taotoken.net/api/v1/chat/completions \ -H Content-Type: application/json \ -H Authorization: Bearer sk-你的密钥 \ -d { model: claude-sonnet-4-20250514, messages: [{role: user, content: 回复 OK}], max_tokens: 10 }成功的话返回 JSON 里choices[0].message.content应该是 OK 或类似内容。如果这一步就失败先别往下走去第五节排查。5. 常见报错排查401、local proxy failed 与 reading choices这一节列几个我实际遇到过的报错以及对应的排查路径。这些错误在接入层和上下文工程调试阶段出现频率最高。401 Unauthorized最常见通常是 Key 没配对或者 Base URL 写错。排查顺序先确认OPENAI_API_KEY或ANTHROPIC_API_KEY环境变量确实生效了用echo $OPENAI_API_KEY看一眼。然后确认 Base URL 结尾没有多余的斜杠https://taotoken.net/api和https://taotoken.net/api/在某些客户端里行为不同。最后确认 Key 没有过期或被禁用去 console 的 api-keys 页面核对。local proxy failed这个报错通常出现在客户端配置了本地代理但代理没起来或者代理配置和实际网络环境冲突。排查时先检查客户端设置里有没有残留的代理配置把它清掉直接用 Base URL 直连。如果用的是 Cline 或类似插件检查 MCP 配置里的 env 字段有没有多余的 proxy 相关变量。reading choices of undefined这个报错说明返回的 JSON 结构里没有choices字段通常是请求根本没成功返回的是错误对象。打印完整响应体看error字段。常见原因模型 ID 写错导致服务端返回错误、请求体格式不对、max_tokens 超限。我遇到过一次是 model ID 里多了个空格排查了半小时。OAuth 相关报错如果你用的是 Claude Code 这类带 OAuth 流程的工具报 OAuth 错误通常是认证方式冲突——既配了 API Key 又走了 OAuth。解决方法是明确用哪一种用 API Key 就把 OAuth 相关配置清掉。settings.json 里只保留ANTHROPIC_API_KEY和ANTHROPIC_BASE_URL别混着来。上下文相关报错context length exceeded这个不是接入层问题是上下文工程没做好。说明 Compaction 没触发或者触发阈值设太高。检查trigger_ratio是不是设成了 0.9 以上留的余量太小。另外确认count_tokens函数算的是实际喂进去的 context 而不是 token_history两者可能差很多。多 Agent 场景子 Agent 返回空子 Agent 返回空摘要通常是子 Agent 的上下文里没有明确的任务指令。子 Agent 上下文干净是好事但干净不等于空。派发任务时要把读哪个文件、返回什么格式的摘要写清楚。我习惯在子 Agent 的指令里加一句如果文件为空或无法读取返回字符串 EMPTY避免返回 undefined 导致主 Agent 解析失败。排查完这些接入层和上下文层基本就稳了。接下来是多 Agent 场景下的验证动作和观测指标。6. 多 Agent 验证动作与观测指标多 Agent 系统搭起来之后怎么知道它真的在工作而不是在空转烧钱需要一套验证动作和观测指标。验证动作分三层。第一层是单 Agent 冒烟测试给一个明确的小任务比如读取 config.json 并返回其中的 port 值确认单个 Agent 的循环能正常跑完。第二层是双 Agent 协作测试主 Agent 派子 Agent 读文件子 Agent 返回摘要主 Agent 基于摘要做决策。这一层重点看上下文隔离是否生效——子 Agent 的完整上下文不应该出现在主 Agent 的历史里。第三层是长任务压力测试给一个需要 20 轮以上才能完成的任务观察 Compaction 是否在预期位置触发以及触发后 Agent 是否还能保持任务目标。观测指标我盯这几个指标含义健康范围每轮上下文 token 数实际喂给模型的量稳定不随轮数线性增长Compaction 触发次数压缩发生频率长任务 2-5 次子 Agent 调用占比子 Agent 消耗 / 总消耗30%-50%虚假完成率声称完成但实际未完成的比例越低越好重点监控单任务总成本整个任务的 token 花费与任务复杂度匹配虚假完成是最需要盯的指标。在需要深度专业知识的任务上Agent 可能在时间限制内提交多次结果每次都充满信心地认为完成了但实际全错。大约 80% 的失败源于虚假完成。应对虚假完成有两个方案。重一点的是 Ralph 循环加一个外层循环让一个全新的 Agent 从干净上下文验证工作是否真的完成只有当新 Agent 什么都没改动才退出。while True: # 外层 token_history [] while True: # 内层上下文干净 ... if action done: break output, answer_not_changed exec(action) token_history [thoughts, action, output] if answer_not_changed: break轻一点的是 Terminus-KIRA 的变体正常跑的同时单独维护一份只含动作和输出、不含思考过程的历史。Agent 觉得完成时让一个只看做了什么、看不到怎么想的的验证者再确认一遍。去掉思考过程的干扰验证者判断更客观而且不用完整重启循环。token_history task_instruction token_history_wo_thoughts [] while True: ... if action done: generated_tokens LLM(token_history_wo_thoughts) thoughts, action parse(generated_tokens) if action done: break # 两个都同意才算真完成 output exec(action) token_history [thoughts, action, output] token_history_wo_thoughts [action, output] # 只记做了什么如果任务本身进度可度量比如训练损失、测试通过率虚假完成几乎不会发生因为数据说了算。这种情况下不需要 Ralph 循环让 Agent 一直跑就行。多 Agent 的观测还要注意一点给每个 Agent 角色打标签统计各自的 token 消耗和成功率。我见过主 Agent 消耗占 90% 的情况一查发现子 Agent 根本没被调用所有活都是主 Agent 干的上下文隔离形同虚设。最后说个实用技巧。上下文工程的调试不要靠猜把每一轮实际喂进去的 context 落盘成文件出问题时直接看那一轮模型到底看到了什么。这个习惯帮我定位过好几次模型为什么突然变傻的问题——十有八九是某一轮 context_build 出了 bug把不该塞的东西塞进去了。整套配置和规则跑通之后你的 Agent 应该能在长任务里保持稳定成本也可控。剩下的就是根据具体业务场景微调阈值和 Skill 内容了。
返回列表