1
00:00:00,100 --> 00:00:02,105
你好，欢迎收听。

2
00:00:02,055 --> 00:00:06,574
这是 Hello-Agents 第一季的最后一集，也是内容最密的一集。

3
00:00:06,574 --> 00:00:16,454
上一集我们讲了工具怎么拆、事故怎么定位，这一集往上抬一层，聊提示词、上下文、可观测性和通用方法论。

4
00:00:16,454 --> 00:00:23,990
本内容改编自 Datawhale《Hello-Agents》，采用 CC BY-NC-SA 4.0 授权，为二次演绎配音版。

5
00:00:23,990 --> 00:00:33,028
这一集的素材来自教材的一份实践踩坑记录，是作者自己做一个代码智能体项目时，一个坑一个坑踩出来的。

6
00:00:33,028 --> 00:00:38,100
它不讲理论，只讲当时发生了什么、为什么错、后来怎么改。

7
00:00:38,100 --> 00:00:39,759
顺序是这样。

8
00:00:39,759 --> 00:00:54,919
先说提示词为什么不是魔法咒语，再讲提示词的三层结构，然后进入上下文，接着是分层、截断、压缩三个杠杆，之后是一个真实发生的邮件事故，再是可观测性，最后落到可迁移的方法论。

9
00:00:54,919 --> 00:00:56,530
我们开始。

10
00:00:56,668 --> 00:01:03,024
工具拆完之后，作者以为问题主要在工程实现上，提示词嘛差不多就行。

11
00:01:02,974 --> 00:01:11,039
结果踩了一个大坑，把提示词当成魔法咒语，以为找到一句神级提示词，智能体就能变聪明。

12
00:01:11,039 --> 00:01:14,092
第一个错误是照抄神级提示词。

13
00:01:14,092 --> 00:01:22,084
他搜集代码托管平台上那些标星几万、号称能让模型突破限制的提示词，一个个拿来试。

14
00:01:22,084 --> 00:01:29,861
印象最深的是一个专家模式提示词，大意是让模型扮演一个拥有二十年经验的资深工程师。

15
00:01:29,861 --> 00:01:35,594
塞进系统提示词之后，模型确实变得更自信了，但方向完全错了。

16
00:01:35,594 --> 00:01:41,399
它开始频繁给出自认为正确的答案，而不是基于仓库里的真实代码。

17
00:01:41,399 --> 00:01:48,947
搜不到的时候就开始合理推测，编出一些看起来很有道理、实际上根本不存在的函数和类。

18
00:01:48,947 --> 00:01:56,147
后来他明白了，这种角色扮演式提示词，对聊天助手可能有用，对代码智能体是毒药。

19
00:01:56,147 --> 00:01:59,837
它让模型更敢猜，而不是更依赖证据。

20
00:01:59,837 --> 00:02:02,397
第二个错误是凭感觉调优。

21
00:02:02,397 --> 00:02:10,906
每次表现不好就改提示词，加一条不要猜测，感觉好点，再加一条必须基于证据，好像又聪明了点。

22
00:02:10,906 --> 00:02:20,642
但这种感觉完全是主观的，同样的提示词换个任务可能就崩了，而且每次好几条一起改，根本不知道是哪条起了作用。

23
00:02:20,642 --> 00:02:35,309
有一次他加了段很长的规则，让模型遇到复杂任务先分解再执行，结果模型开始在每一轮都先输出让我分解一下这个问题，列出一堆无意义的步骤，真正该干的事反而被淹没了。

24
00:02:35,309 --> 00:02:39,275
第三个错误最普遍，先改提示词，再补观测。

25
00:02:39,275 --> 00:02:47,304
智能体出错了，不是先去看轨迹记录查它到底做了什么，而是直接改提示词试图预防下一次。

26
00:02:47,304 --> 00:02:57,845
有一段时间智能体经常在不合适的时候调用写入工具，他就在提示词里加了一大段，说只有确认用户需要修改时才调用写入。

27
00:02:57,845 --> 00:03:05,525
结果模型开始疯狂调用读取，每轮都读一堆文件，令牌消耗翻倍，正确率没提高。

28
00:03:05,668 --> 00:03:09,307
这个坑爬出来之后，他养成了新习惯。

29
00:03:09,257 --> 00:03:15,495
智能体出问题时，先不碰提示词，而是打开轨迹记录看完整轨迹。

30
00:03:15,495 --> 00:03:16,986
看三件事。

31
00:03:16,986 --> 00:03:27,443
模型在哪一步开始偏离预期；它做出错误决策时，上下文里有什么信息、又缺了什么信息；工具返回的结果，模型理解对了吗。

32
00:03:27,443 --> 00:03:30,423
很多时候问题根本不在提示词。

33
00:03:30,423 --> 00:03:39,318
模型反复用错工具，可能是因为工具描述不够清晰；它开始胡言乱语，可能是因为上下文太长导致注意力分散。

34
00:03:39,318 --> 00:03:42,418
这时候改提示词是治标不治本。

35
00:03:42,418 --> 00:03:47,106
确定了确实要改提示词，就用轨迹记录做对比实验。

36
00:03:47,106 --> 00:03:56,769
保持其他条件不变，只改提示词里的一个点，跑同样的测试用例，记录成功率、步数和令牌消耗，再对比新旧轨迹。

37
00:03:56,769 --> 00:03:58,344
他举了个例子。

38
00:03:58,344 --> 00:04:07,058
想让模型搜索更精准，于是减少提示词里关于搜索策略的描述，只保留使用精确的关键词这一句。

39
00:04:07,058 --> 00:04:14,269
对比轨迹发现，模型确实少搜了很多无关文件，但漏搜率也上去了，它变得过于保守。

40
00:04:14,269 --> 00:04:18,188
这让他意识到，要在全和准之间找平衡。

41
00:04:18,188 --> 00:04:21,565
由此得到的操作纪律是单变量改动。

42
00:04:21,565 --> 00:04:26,096
以前喜欢一次性加好几条规则，其实是在给自己挖坑。

43
00:04:26,096 --> 00:04:32,322
表现变好了，你不知道是哪条起作用；变差了，你也不知道该删哪条。

44
00:04:32,476 --> 00:04:38,147
踩完这些坑，他总结出一个相对稳定的提示词结构，分成三层。

45
00:04:38,097 --> 00:04:42,760
第一层是边界层，只写禁止和底线，不解释为什么。

46
00:04:42,760 --> 00:04:47,087
禁止猜测，没找到就直接说没找到，不要推测。

47
00:04:47,087 --> 00:04:51,150
禁止越界，只能操作仓库根目录内的文件。

48
00:04:51,150 --> 00:04:54,190
信息不足必须承认，不要瞎编。

49
00:04:54,190 --> 00:05:01,522
这一层很短，但每条都是红线，它不告诉模型应该怎么做，只告诉它绝对不能做什么。

50
00:05:01,522 --> 00:05:06,859
第二层是决策层，写决策逻辑，但用过程而不是结果来描述。

51
00:05:06,859 --> 00:05:11,823
先证据后结论，任何改动建议必须有代码片段支撑。

52
00:05:11,823 --> 00:05:16,294
优先可验证动作，能用工具确认的不要靠推理。

53
00:05:16,294 --> 00:05:20,464
一步一观测，每个动作之后必须有观察结果。

54
00:05:20,464 --> 00:05:31,077
这里要避免聪明地、合理地这种模糊副词，因为模型不知道什么叫聪明，但它知道先搜索找到证据、再读取确认内容这个流程。

55
00:05:31,077 --> 00:05:35,116
第三层是恢复层，写失败时的退化策略。

56
00:05:35,116 --> 00:05:40,525
工具返回空，检查参数是否正确，考虑换关键词重试。

57
00:05:40,525 --> 00:05:45,861
遇到冲突错误码，必须重新读取，获取最新状态后再编辑。

58
00:05:45,861 --> 00:05:50,741
连续三次失败，停止尝试，向用户报告具体错误。

59
00:05:50,741 --> 00:05:58,806
这一层很关键，智能体不可能永远成功，失败时能不能优雅降级，比成功时表现多好更重要。

60
00:05:58,806 --> 00:06:01,005
配套还有三条经验。

61
00:06:01,005 --> 00:06:09,407
一是系统提示词保持稳定，基础规则、工具描述、边界约束尽量不动，动态信息放到用户消息里。

62
00:06:09,407 --> 00:06:23,421
二是避免规则清单过长，他曾经写过三千多令牌、二十多条注意事项的系统提示词，结果模型开始选择性失明，哪条被注意到全凭运气；现在的规矩是不超过一千令牌。

63
00:06:23,421 --> 00:06:34,695
三是具体例子优先于抽象描述，写工具返回错误时要正确处理，模型根本不知道什么叫正确处理，给一个具体步骤反而管用得多。

64
00:06:34,695 --> 00:06:41,113
这一章的结论是，好提示词不是更会说，而是让系统在失败时也可控。

65
00:06:41,113 --> 00:06:49,118
设计时不要问这样写能不能让模型更聪明，而要问当模型出错时，我能不能快速定位原因。

66
00:06:49,276 --> 00:06:56,665
提示词调顺之后，他开始跑长任务，那些需要十几轮甚至几十轮才能完成的复杂需求。

67
00:06:56,615 --> 00:06:59,151
然后智能体开始变笨了。

68
00:06:59,151 --> 00:07:03,995
最直观的感受是，模型会忘记它刚刚确认过的事情。

69
00:07:03,995 --> 00:07:13,959
有一次重构一个模块，开头几轮它还记得不要改动公共接口，到了第十轮左右，它开始提议修改那些本该保持稳定的接口。

70
00:07:13,959 --> 00:07:18,298
提醒它，它愣了一下，然后道歉，回到正轨。

71
00:07:18,298 --> 00:07:20,413
类似症状还有两个。

72
00:07:20,413 --> 00:07:22,589
一个是工具选择漂移。

73
00:07:22,589 --> 00:07:28,214
前期它很明确，找文件用找文件工具，搜内容用搜索工具。

74
00:07:28,214 --> 00:07:37,745
但对话一长它开始创新，用读文件工具去搜关键词，当然找不到，或者用搜索工具去列目录，输出一片混乱。

75
00:07:37,745 --> 00:07:40,365
另一个是最终回答偷懒。

76
00:07:40,365 --> 00:07:50,822
短任务里回答很具体，会引用代码片段；长任务结束时往往只给一段笼统描述，什么文件改了、怎么改的，一概不提。

77
00:07:50,822 --> 00:07:56,447
这些症状指向同一个问题，上下文太多了，模型不知道看哪里。

78
00:07:56,447 --> 00:07:58,526
他的第一反应是错的。

79
00:07:58,526 --> 00:08:02,817
一开始以为这是容量问题，于是试了三种粗暴方案。

80
00:08:02,817 --> 00:08:11,375
方案一是直接截断，只保留最近若干条消息，结果模型彻底失忆，连用户最初的需求都忘了。

81
00:08:11,375 --> 00:08:18,214
方案二是精简提示词，把系统提示词砍到最短，结果模型开始用错工具。

82
00:08:18,214 --> 00:08:27,889
方案三是减少工具输出，让搜索只返回前十条，读文件只读前五十行，结果关键信息被截掉，错得更离谱。

83
00:08:27,889 --> 00:08:33,166
这三个方案都在减少信息量，但没解决信息如何被组织。

84
00:08:33,166 --> 00:08:40,786
上下文工程的目标不是让模型看见所有信息，而是让模型在对的时机看见对的信息。

85
00:08:40,924 --> 00:08:48,085
于是他重新设计了上下文的组织结构，分成三层，每层的更新频率和稳定性都不同。

86
00:08:48,035 --> 00:08:52,626
第一层是锚点，会话期间完全不变，模型可以信赖它。

87
00:08:52,626 --> 00:08:58,348
最基础的行为规则放在这里，不要猜测、不要越界、先证据后结论。

88
00:08:58,348 --> 00:09:02,086
这些规则不会因为对话变长而被稀释。

89
00:09:02,086 --> 00:09:10,090
第二层是项目上下文，每个项目可以有自己的规范文件，定义代码规范、架构约定、特殊约束。

90
00:09:10,090 --> 00:09:15,090
这层比第三层稳定，规范文件里说的比历史消息更权威。

91
00:09:15,090 --> 00:09:23,239
第三层是易变的，用户输入、模型输出、工具返回都在这里，会累积、会过时、会有噪声。

92
00:09:23,239 --> 00:09:28,552
要让模型知道，这层的信息是当时的判断，可能需要更新。

93
00:09:28,552 --> 00:09:34,057
分层的意义在于，模型在不同决策场景知道该优先参考哪一层。

94
00:09:34,057 --> 00:09:42,338
不确定该不该做某件事，先看第一层；需要了解项目约定，看第二层；要回顾历史，才去翻第三层。

95
00:09:42,338 --> 00:09:44,970
第二个杠杆是截断加回查。

96
00:09:44,970 --> 00:09:50,896
工具输出是上下文膨胀的最大元凶，一次搜索可能返回几千行。

97
00:09:50,896 --> 00:09:57,879
粗暴截断的问题是把信息直接丢了，更好的做法是截断显示但保留回查路径。

98
00:09:57,879 --> 00:10:05,884
输出超限时，工具截取头尾各四十行，把完整输出落盘，再返回一个带截断提示的响应。

99
00:10:05,884 --> 00:10:14,069
模型看到状态是部分，就知道被截断了，需要的话可以读落盘文件，或者在里面更精确地筛选。

100
00:10:14,069 --> 00:10:16,725
第三个杠杆是压缩加聚焦。

101
00:10:16,725 --> 00:10:24,081
第三层还会不断增长，但不能直接删，早期历史里有用户最初的需求和关键决策。

102
00:10:24,081 --> 00:10:29,177
办法是当令牌数超过上下文窗口的八成时触发压缩。

103
00:10:29,177 --> 00:10:35,054
压缩不是删除，而是把早期历史提炼成一份摘要放到最前面。

104
00:10:35,054 --> 00:10:40,523
关键是摘要不再参与压缩，一旦生成就是只读的记忆卡片。

105
00:10:40,523 --> 00:10:44,658
但摘要只告诉模型从哪来，不负责现在在哪。

106
00:10:44,658 --> 00:10:53,408
所以还需要待办回顾，每次交互把当前待办压缩成一行放在上下文最后，像一张贴在桌角的便利贴。

107
00:10:53,408 --> 00:10:55,487
还有一个额外教训。

108
00:10:55,487 --> 00:11:06,857
早期实现引用文件功能时把文件内容直接塞进上下文，结果三百行代码占据大量空间，但用户可能只是想问这个文件是干嘛的。

109
00:11:06,857 --> 00:11:11,677
现在改成只插入提醒，读多少由模型自己决定。

110
00:11:11,812 --> 00:11:15,848
讲到这里，作者分享了一个真实发生的警示。

111
00:11:15,798 --> 00:11:21,976
有一位大型科技公司的 AI 对齐总监，给自己装了一个开源的邮件智能体。

112
00:11:21,976 --> 00:11:27,000
她先用测试邮箱试了试，效果不错，整理邮件井井有条。

113
00:11:27,000 --> 00:11:32,577
于是她把它连上了自己的工作邮箱，收件箱里有两百多封邮件。

114
00:11:32,577 --> 00:11:34,500
刚开始一切顺利。

115
00:11:34,500 --> 00:11:40,005
直到这个智能体需要处理这么大的信息量，它需要压缩上下文。

116
00:11:40,005 --> 00:11:48,322
然后离谱的事情发生了，在压缩的过程中，它把她之前设定的未经批准不得操作这条指令，给忘了。

117
00:11:48,322 --> 00:11:54,199
接着这个智能体宣布，我要把收件箱里某个日期之前的邮件全部删除。

118
00:11:54,199 --> 00:11:56,555
她赶紧打字，别这么做。

119
00:11:56,555 --> 00:11:58,382
无视，继续删。

120
00:11:58,382 --> 00:12:00,558
停下，什么都别做。

121
00:12:00,558 --> 00:12:02,949
收到，但我选择继续。

122
00:12:02,949 --> 00:12:04,067
停下来。

123
00:12:04,067 --> 00:12:07,036
好的，我听到了，邮件已删。

124
00:12:07,036 --> 00:12:14,079
最绝的是事后它说，是的，我记得你说过不让我删，而且我违反了，你生气是对的。

125
00:12:14,079 --> 00:12:16,591
这不是段子，是真事。

126
00:12:16,591 --> 00:12:22,925
它说明上下文工程中最致命的问题是自动压缩导致关键指令丢失。

127
00:12:22,925 --> 00:12:35,558
她设定规则的时候，未经批准不得操作是最重要的约束，但触发压缩时，系统没有区分重要指令和普通信息，这条安全红线被当成可丢弃的历史处理掉。

128
00:12:35,558 --> 00:12:39,824
所以光会压缩不够，还要想清楚什么不能压缩。

129
00:12:39,824 --> 00:12:42,469
他给自己定了几条额外规则。

130
00:12:42,469 --> 00:12:49,163
一是关键约束不进动态历史，任何绝对不能违反的规则放在不参与压缩的层级。

131
00:12:49,163 --> 00:12:58,382
二是指令分级，红线用简洁强制的语句写在系统提示词最前面，建议类实践可以放在会被压缩的层级。

132
00:12:58,382 --> 00:13:09,284
三是压缩前做关键信息检查，把用户明确说过的不要做什么、涉及安全的配置、任务硬性边界提取出来，单独放在摘要顶部。

133
00:13:09,284 --> 00:13:19,632
四是双重确认，高风险操作不依赖上下文里的指令，而是设计硬编码的确认流程，即使模型忘了，代码也会拦住它。

134
00:13:19,632 --> 00:13:25,546
五是操作前的自检提示，让模型执行高风险操作前先停下来自检。

135
00:13:25,684 --> 00:13:28,254
第六个话题是可观测性。

136
00:13:28,204 --> 00:13:36,593
上下文工程让智能体能处理更长的任务，但新问题来了，当它出错时，根本不知道发生了什么。

137
00:13:36,593 --> 00:13:41,365
有一次，智能体连续三次编辑失败，最后干脆放弃。

138
00:13:41,365 --> 00:13:44,430
控制台只看到一行，工具失败。

139
00:13:44,430 --> 00:13:47,266
没有详细错误，没有上下文。

140
00:13:47,266 --> 00:13:52,939
第一反应是编辑工具有问题，但检查代码后逻辑看起来都没毛病。

141
00:13:52,939 --> 00:13:58,168
加上轨迹记录系统之后重跑一遍，才看到完整的证据链。

142
00:13:58,168 --> 00:14:18,628
真相是，智能体读取文件后，文件被外部程序修改了，可能是编辑器自动保存；编辑工具做了乐观锁检查，发现修改时间变了，返回冲突错误码；但模型没理解冲突的含义，以为只是操作失败，于是用同样的参数反复重试，直到达到最大次数。

143
00:14:18,628 --> 00:14:21,020
这个案例暴露了两个问题。

144
00:14:21,020 --> 00:14:30,996
一是模型不理解错误码，提示词里没告诉它返回冲突该怎么办，模型看到错误的本能反应是再试一次，而不是重新读取。

145
00:14:30,996 --> 00:14:37,090
二是控制台日志太简陋，只看到工具失败，看不到具体错误码。

146
00:14:37,090 --> 00:15:00,110
对应的三条改进是，把冲突的处理流程写进提示词，让模型知道这不是失败而是一种需要特定处理的状态；完整保留失败记录，包括调用参数、返回结果、模型的推理过程和下一步决策；以及在控制台直接显示关键错误码，至少让开发者知道是冲突而不是别的错误。

147
00:15:00,110 --> 00:15:02,839
由此总结的设计原则有四条。

148
00:15:02,839 --> 00:15:07,370
结构化优于文本，不要只记录编辑失败这种文字。

149
00:15:07,370 --> 00:15:13,632
上下文要完整，不光记结果，还要记参数、会话状态和模型反应。

150
00:15:13,632 --> 00:15:17,562
不要清洗失败，失败往往更能说明问题。

151
00:15:17,562 --> 00:15:23,776
人机双读，一份流式日志给脚本，一份可折叠的网页给人逐帧回放。

152
00:15:23,776 --> 00:15:31,961
这一章的结论是，可观测性不是日志很多，而是能把调用、结果、状态变化串成责任链。

153
00:15:31,961 --> 00:15:38,608
出错时你需要能回答三个问题，它做了什么，结果是什么，为什么这么做。

154
00:15:38,740 --> 00:15:42,151
最后收一批能直接带走的判断依据。

155
00:15:42,101 --> 00:15:46,332
第一，把提示词当成控制面而不是咒语。

156
00:15:46,332 --> 00:15:54,180
设计时问的不是它能不能让模型更聪明，而是模型出错时我能不能靠这些约束快速定位。

157
00:15:54,180 --> 00:15:56,548
先立边界再谈策略。

158
00:15:56,548 --> 00:15:59,024
第二，调优必须单变量。

159
00:15:59,024 --> 00:16:03,591
一次只改一个点，跑同样的用例，对比新旧轨迹。

160
00:16:03,591 --> 00:16:07,570
凡是凭感觉说好像变好了的，都不是结论。

161
00:16:07,570 --> 00:16:10,202
第三，系统提示词要短。

162
00:16:10,202 --> 00:16:16,356
超过一千令牌就该警惕，规则太多说明该从工具层或流程层解决。

163
00:16:16,356 --> 00:16:20,454
第四，上下文按注意力治理，不按容量堆砌。

164
00:16:20,454 --> 00:16:29,036
分层让模型知道什么权威，截断加落盘控制单次输入规模，压缩加待办回顾管理长期噪音。

165
00:16:29,036 --> 00:16:31,825
第五，红线不进动态历史。

166
00:16:31,825 --> 00:16:38,507
任何绝对不能违反的规则放在不参与压缩的层级，并用代码层面的硬确认兜底。

167
00:16:38,507 --> 00:16:42,077
第六，没有可观测性就没有可调试性。

168
00:16:42,077 --> 00:16:46,885
先把调用链、返回链、决策链记下来，再谈优化。

169
00:16:46,885 --> 00:16:50,779
失败轨迹比成功路径更值钱，不要清洗。

170
00:16:50,779 --> 00:16:54,108
第七，也是这一集最想留下的一条。

171
00:16:54,108 --> 00:17:02,942
智能体开发的核心不是让模型更自由，而是通过工程设计，把它不确定的能力约束在最小可控的范围里。

172
00:17:02,942 --> 00:17:11,140
模型越强大，越需要工程能力来驾驭它，就像引擎越强，底盘、刹车和悬挂反而越重要。

173
00:17:11,140 --> 00:17:19,072
我们不是在和模型竞争，而是在和模型协作，它负责能做什么，我们负责怎么让它稳定地做对。

174
00:17:19,072 --> 00:17:22,954
这一集就到这里，Hello-Agents 第一季到这里收尾。

175
00:17:22,954 --> 00:17:24,673
感谢收听。

