Agent日志编译成Skill:从手工艺到工程化的提示词优化
1. 从一份日志到一版Skill这个思路到底在解决什么问题做过Agent开发的人都有一个共同的痛你精心调教了一个Agent给它写了一大段系统提示词定义了一堆工具调用规则跑了一段时间发现它在某些场景下表现不好。于是你改提示词加规则调参数重新部署再跑再发现问题再改。这个循环可以持续几十轮每一轮你都在手动分析日志、手动归纳问题、手动改写提示词。问题在于这个过程极度依赖人的经验和耐心。一个Agent跑一天可能产生几千条交互日志你不可能逐条看完。你只能抽样凭直觉判断哪里出了问题。更麻烦的是当你发现某个问题并修复之后你很难确认这个修复是否引入了新的回归问题——因为你的测试集可能根本没覆盖到那些边缘场景。微软这篇论文的核心思路用一句话概括就是把Agent的历史执行日志当作“源代码”把提示词优化当作“编译过程”自动产出一版新的Skill。这个“编译”的类比非常精准。传统编译器做的事情是读取源代码日志经过词法分析、语法分析、语义分析、优化、代码生成等阶段输出目标代码新版Skill。论文提出的方法本质上是在做类似的事情——从日志中提取模式词法/语法分析识别失败原因和成功策略语义分析归纳出可复用的规则优化最终生成结构化的提示词或Skill定义代码生成。这个思路解决的核心问题是Agent的提示词优化从“手工艺”变成了“工程化流程”。你不再需要逐条看日志、凭感觉改提示词而是建立一套自动化的管道让日志自己“告诉”你该怎么改。适合谁来参考这个思路我认为三类人最需要关注第一类是正在做Agent产品化的团队你们的Agent已经上线但效果不稳定需要系统化的优化方法第二类是Agent框架的开发者你们需要为上层用户提供更好的调试和优化工具第三类是对提示工程有深入兴趣的独立开发者你们想理解Agent行为优化的底层逻辑而不只是停留在“换个说法试试”的层面。2. 核心机制拆解日志怎么变成Skill2.1 日志的结构化预处理原始日志是一堆非结构化的文本直接拿来做分析效率极低。论文的第一步是把日志结构化。具体来说每条日志记录需要被拆解成几个关键字段输入上下文用户说了什么系统给了什么前置信息Agent的推理过程如果Agent有显式的思考链这部分要完整保留工具调用序列调用了哪些工具传了什么参数返回了什么结果最终输出Agent给用户的回复执行结果标记成功、失败、部分成功、超时等这个预处理步骤看起来简单但实际操作中有很多坑。比如很多Agent框架的日志格式不统一有的把思考链和工具调用混在一起有的不记录中间状态。我的建议是如果你打算用这个思路来优化自己的Agent第一件事就是统一日志格式。可以参考OpenTelemetry的Span结构来设计每个Span代表一次完整的Agent执行子Span代表工具调用或推理步骤。结构化之后还需要做一轮日志清洗。哪些日志该保留哪些该丢弃论文中的做法是保留所有“有信号”的日志——包括成功的和失败的。成功的日志用来提取有效策略失败的日志用来识别问题模式。但要注意如果某类失败是因为外部服务不可用导致的比如API超时这类日志应该被标记为“环境噪声”并排除否则会误导后续的分析。2.2 从日志中提取“编译单元”编译器处理源代码时最小的处理单元是“语句”或“表达式”。对应到Agent日志最小的“编译单元”是什么论文给出的答案是**“决策点”**。一个决策点指的是Agent在执行过程中面临选择的时刻选择调用哪个工具、选择用什么参数、选择继续推理还是直接回答、选择如何处理工具返回的异常结果。每个决策点都包含上下文信息、Agent的选择、以及这个选择导致的结果。把日志拆解成决策点序列之后就可以做模式分析了。比如你可能会发现当用户的问题涉及日期计算时Agent有80%的概率会先调用搜索工具而不是直接计算而搜索工具返回的结果往往不准确导致最终答案错误。这就是一个可操作的优化点——你可以在Skill中明确告诉Agent“遇到日期计算类问题优先使用代码执行工具进行精确计算不要依赖搜索。”这个提取过程论文中用了聚类的方法。把相似的决策点聚在一起统计每个簇的成功率和失败率失败率高的簇就是需要优化的重点区域。聚类的特征包括用户意图类型、可用工具集合、上下文长度、历史交互轮次等。2.3 “编译优化”阶段的核心策略有了决策点的聚类分析结果接下来就是真正的“编译优化”。论文中提到了几种核心策略我结合自己的理解展开说一下。第一种是规则注入。这是最直接的方式。如果发现某类决策点的失败率很高就在Skill中增加一条明确的规则。比如“当用户要求生成代码时必须先确认目标编程语言和运行环境再开始生成。”这条规则来自对失败日志的归纳——很多失败案例是因为Agent假设了错误的语言或环境。第二种是示例替换。很多Skill中包含了Few-shot示例。如果日志分析显示某些示例被频繁误用或者示例覆盖的场景与实际使用场景偏差很大就需要替换示例。论文中的做法是从成功日志中挑选最具代表性的案例替换掉原有的示例。选择标准包括覆盖的意图类型、工具调用复杂度、输出质量评分。第三种是约束收紧或放宽。有时候Agent失败是因为约束太松比如允许它自由选择工具结果选错了有时候是因为约束太紧比如强制它必须调用某个工具但那个工具在某些场景下不适用。日志分析可以帮你找到这个平衡点。具体做法是对比约束条件下和自由条件下的成功率如果约束条件下的成功率显著更高就保留或加强约束如果反而更低就放宽约束。第四种是推理链重构。这是最复杂的一种优化。如果日志显示Agent的推理过程经常在某些步骤上“跑偏”可能需要重新设计推理链的结构。比如把“先分析问题类型再选择工具再执行”改成“先列出可能的解决路径再评估每条路径的可行性再选择最优路径执行”。这种重构需要大量日志支撑但效果通常最显著。2.4 Skill的生成与验证优化策略确定之后需要把它们“编译”成新的Skill。这里的Skill可以是一段新的系统提示词也可以是一个结构化的配置文件甚至是一组带条件的规则集合。论文中建议用结构化的格式来组织Skill比如skill_name: date_calculation_handler version: 2.1 triggers: - intent: date_calculation - keywords: [计算日期, 几天后, 倒计时] rules: - priority: high condition: 用户问题涉及日期计算 action: 使用代码执行工具进行精确计算 reason: 搜索工具在日期计算场景下准确率仅62% examples: - input: 从2024年3月1日算起100天后是几号 expected_tool: code_executor expected_output: 2024-06-09生成之后必须经过验证才能上线。验证的方法是用一批留出日志没有参与优化过程的历史日志来测试新版Skill对比新旧版本的成功率、工具调用准确率、平均执行轮次等指标。如果新版在关键指标上有显著提升且没有引入新的失败模式就可以上线。3. 实操落地从零搭建一套日志编译管道3.1 环境准备与数据收集假设你现在有一个正在运行的Agent用的是常见的框架比如LangChain、AutoGen或自研框架第一步是确保日志被完整记录。我建议在Agent的每个关键节点埋点Agent入口记录用户输入和系统提示词版本每次LLM调用记录输入token数、输出token数、耗时、模型名称每次工具调用记录工具名称、参数、返回结果、耗时、是否成功Agent出口记录最终输出、总轮次、总耗时这些数据可以写到本地文件JSONL格式也可以写到数据库。如果数据量不大每天几千条JSONL足够了。如果每天几十万条建议用ClickHouse或DuckDB查询分析会快很多。注意日志中可能包含用户隐私信息收集前务必做好脱敏处理。论文中也强调了这一点建议在埋点层就对敏感字段进行哈希或替换。3.2 日志解析与决策点提取的实现这一步需要写一些代码。核心逻辑是遍历每条日志识别出所有的决策点。以下是一个简化的Python示例import json from dataclasses import dataclass from typing import List, Optional dataclass class DecisionPoint: context: str available_tools: List[str] chosen_action: str action_params: dict result: str success: bool intent_type: str def extract_decision_points(log_entry: dict) - List[DecisionPoint]: points [] steps log_entry.get(steps, []) for i, step in enumerate(steps): if step[type] tool_call: context build_context(steps[:i]) point DecisionPoint( contextcontext, available_toolsstep.get(available_tools, []), chosen_actionstep[tool_name], action_paramsstep.get(params, {}), resultstep.get(result, ), successstep.get(success, False), intent_typeclassify_intent(log_entry[user_input]) ) points.append(point) return pointsclassify_intent可以用一个简单的分类模型也可以用LLM来做零样本分类。如果日志量不大用LLM分类更准确如果量大建议训练一个小模型或者用关键词规则先做粗分类。提取出决策点之后需要做聚类。聚类的特征工程很关键。我试过几种特征组合效果比较好的是意图类型 可用工具集合的哈希 上下文长度的分桶 历史轮次的分桶。用DBSCAN或HDBSCAN做聚类不需要预先指定簇的数量。3.3 失败模式识别与优化策略生成聚类完成后对每个簇计算成功率。成功率低于某个阈值比如70%的簇标记为“问题簇”。对每个问题簇进一步分析失败的具体原因。这里可以用LLM来辅助分析——把问题簇中的失败案例喂给LLM让它归纳失败模式。比如LLM可能会输出“这些失败案例的共同点是Agent在用户没有明确指定编程语言时默认选择了Python但用户实际期望的是JavaScript。建议在Skill中增加一条规则当用户要求生成代码但未指定语言时必须先询问用户偏好。”这条归纳结果就是一条优化策略。把所有的优化策略收集起来去重、合并、按优先级排序就得到了新版Skill的规则集。3.4 新版Skill的生成与A/B测试规则集确定后生成新版Skill。如果是提示词形式的Skill就是把新规则自然地融入到原有提示词中。注意不要简单堆砌规则要保持提示词的可读性和逻辑性。我的经验是规则数量控制在15条以内超过这个数量LLM的遵循率会明显下降。生成之后用留出日志做A/B测试。具体做法是把留出日志中的用户输入重新喂给新旧两个版本的Agent对比输出质量。输出质量的评估可以用LLM-as-Judge也可以用人工评估如果量不大。关键指标包括指标说明目标任务成功率最终输出是否满足用户需求提升10%以上工具调用准确率是否调用了正确的工具提升15%以上平均执行轮次完成任务的对话轮数降低20%以上回归失败率原本成功的案例是否变失败低于5%如果新版在成功率上有显著提升且回归失败率可控就可以上线。上线后继续收集日志进入下一轮编译循环。4. 踩坑记录与常见问题排查4.1 日志质量问题的排查问题日志中缺少关键字段无法提取决策点。这是最常见的问题。很多Agent框架默认不记录工具调用的参数和返回结果只记录工具名称。解决办法是在工具调用的包装层手动埋点。如果你用的是LangChain可以通过Callback机制来捕获如果是自研框架在工具调用的入口和出口加装饰器。问题日志量太大分析跑不动。每天几十万条日志用Pandas处理会很慢。建议用DuckDB做预处理和聚合只把聚合后的结果喂给LLM分析。另外不需要分析所有日志可以按时间窗口采样比如每天随机抽取5000条。问题日志中的意图分类不准确。意图分类是后续所有分析的基础如果分类错了聚类结果就没有意义。我的建议是先用规则做粗分类再用LLM做细分类最后人工抽检100条确认准确率。如果准确率低于85%需要调整分类体系或换模型。4.2 优化策略生成的常见陷阱陷阱一过度拟合历史日志。如果优化策略完全基于历史日志生成可能会过度拟合那些日志中的特定模式导致在新场景下表现反而变差。解决办法是保留一部分日志不参与优化专门用于验证。另外策略生成时要让LLM做“泛化”处理不要把具体的用户输入写进规则里而是提取通用的模式。陷阱二规则冲突。当规则数量增多时可能会出现规则冲突。比如一条规则说“遇到日期计算用代码工具”另一条规则说“遇到数学问题用搜索工具”而日期计算也是数学问题。解决办法是给规则加优先级并在生成阶段就让LLM检查冲突。陷阱三忽略工具本身的限制。有时候Agent失败不是因为决策错误而是因为工具本身的能力边界。比如你让Agent用搜索工具查实时股价但搜索工具返回的是延迟数据。这种情况下优化Skill没用需要换工具或增加数据源。日志分析要能区分“决策问题”和“工具问题”。4.3 上线后的监控与回滚新版Skill上线后必须持续监控关键指标。建议设置告警阈值如果任务成功率下降超过5%或者回归失败率超过10%自动回滚到上一版。同时继续收集新日志为下一轮编译做准备。常见问题排查思路解决方案决策点提取不全检查日志埋点是否覆盖所有工具调用在工具包装层补充埋点聚类结果无意义检查特征工程是否合理调整特征组合增加意图类型权重优化策略无法落地检查策略是否过于抽象让LLM生成具体的条件-动作对新版Skill效果下降检查是否有规则冲突增加冲突检测调整优先级A/B测试结果不显著检查留出日志是否足够增加留出日志量延长测试周期5. 这套方法还能怎么扩展这套“日志编译成Skill”的思路本质上是一种数据驱动的Agent行为优化框架。它的应用范围远不止提示词优化。我目前看到几个很有潜力的扩展方向。第一个方向是多Agent协作场景。当多个Agent需要协同完成任务时日志分析可以帮助识别协作中的瓶颈——比如哪个Agent的响应延迟最高、哪个Agent的输出经常被其他Agent忽略。优化策略可以针对性地调整协作协议。第二个方向是Skill的版本管理与灰度发布。就像代码有Git一样Skill也应该有版本管理。每次编译生成的新版Skill都应该被记录、对比、可回滚。灰度发布可以让新版Skill只对部分流量生效进一步降低风险。第三个方向是跨Agent的Skill迁移。如果你有多个Agent处理相似的任务一个Agent的优化经验可以通过日志编译的方式迁移到另一个Agent。这可以大幅减少重复调优的工作量。第四个方向是实时编译。目前的流程是离线分析日志、生成新版Skill、上线。未来可以做到实时Agent在执行过程中如果检测到连续失败自动触发局部优化动态调整当前会话的策略。这对框架的要求更高但技术上完全可行。我在实际项目中的体会是这套方法最大的价值不是自动化本身而是它把Agent优化从“玄学”变成了“可度量的工程”。你不再需要争论“这个提示词改得好不好”而是用数据说话成功率提升了多少回归失败率是多少平均轮次降低了多少。这种可度量性才是Agent产品化的关键。