多智能体系统的上下文工程——从提示到上下文:构建语义蓝图

81 阅读47分钟

上下文工程(Context engineering) 是一门学科,它让生成式 AI 从一个“不可预测的合作者”,变成一个“完全可控的创意伙伴”。当一个 prompt(提示词) 往往只是给随机性打开了一扇门时,一个 context(上下文) 则为可预测的结果提供了一份有结构的蓝图。
这代表着一个根本性的转变:从“让 LLM 继续一段序列”,变成“为它搭建一个封闭环境,让它在其中执行一份精确的计划”。
这种演进让人与模型的交互从简单的请求,进入到“定向创作”的范畴——你不再只是告诉模型“做什么”,而是告诉它“在你划定的边界内,应该如何思考”。

长久以来,我们一直把生成式 AI 当作“神谕”:把 prompt 丢进黑箱,然后祈祷能收到一份连贯的回复。我们会为它偶尔的神来之笔鼓掌,却对它的不稳定和不一致睁一只眼闭一只眼,把这种不可预测当成体验的一部分。
但那只是“提问的艺术”,而不是“创作的艺术”。
本章要讲的不是“如何问更好的问题”,而是“如何给出更好的计划,并告诉 LLM 应该做什么”。

我们的旅程从一个实战演示开始,它会带你依次经历五个不同层级的上下文复杂度,展示每加一层上下文,如何把输出从随机猜测,变成结构化、目标驱动的响应。
接着,我们会从“线性文字序列”迈向“多维语义结构”,引入语义角色标注(Semantic Role Labeling,SRL)这一语言学技术,它能回答:谁做了什么、对谁做的、在什么时候、出于什么原因。
以 SRL 为基础,我们会编写一个 Python 程序,把这些结构可视化成
语义蓝图(semantic blueprints)

最后,我们将在一个完整的“会议分析”用例中综合运用这些技能,在那里我们会引入上下文链式(context chaining) 的概念,并展示多步工作流如何把原始会议记录转化为洞见、决策以及专业化行动。

在本章结束时,你将不再是在数字荒野中“寻找答案”的人。
你将成为这片荒野的建筑师——能设计 AI 思维所处的“地形”,并把它引导向你选择的任何目的地。

本章将涵盖以下主题:

  • 通过上下文工程的五个层级,构建语义蓝图
  • 借助 SRL,从线性文本过渡到多维语义结构
  • 使用 SRL 构建一个 Python 程序,对文本进行解析与结构化
  • 将上下文链式(context chaining)应用为一种“逐步、可控推理”的方法
  • 通过一个完整的会议分析用例,将原始会议记录转化为一封专业邮件

理解上下文工程(Understanding context engineering)

上下文工程既是一门艺术,也是一门科学,目的是控制并引导大型语言模型(LLM)已学习的信息世界
它会让你的角色从一个“提问者”,变成一个“自信的导演”。
这就像是:你不再只是递给演员一句台词,而是给 TA 一整份剧本——包括角色动机和舞台走位。你不再只是“请求一场表演”,而是在设计这场表演,并告诉 LLM 要做什么

理解上下文工程的最佳方式,就是亲身体验。我们会跳过枯燥的理论,从一个动手演示开始。这个过程是为了让你“切身感受到”AI 输出的变化,看到它从原始的统计性猜测,逐步进化为细腻、可靠、并且与你目标高度契合的回答。
接下来,我们会一起经历五个复杂度逐级提升的阶段,如图 1.1 所示。从一个简单的 prompt 出发,最终抵达一个完备设计的语义蓝图。在过程中,我们会分别用到三大主流 Copilot(Google、Microsoft 与 OpenAI):

  • Level 1:基础提示(零上下文)
    这只是一个简单指令,没有任何背景。AI 只能依赖训练数据进行猜测,往往生成通用化、模板化甚至陈词滥调的内容。
  • Level 2:更好的上下文(线性上下文)
    这是向前迈出的一小步。通过增加一条线性的叙事线或背景信息,相比零上下文,事实准确性有所提升,但模型在风格、目的性和整体方向上仍然欠缺。
  • Level 3:良好的上下文(目标导向上下文)
    这是第一个真正意义上的上下文层级。通过为模型明确设定清晰的目标,它的回答会变得更有意图、更加对齐预期。这是上下文工程中的第一个可接受里程碑
  • Level 4:高级上下文(角色驱动上下文)
    这一层比只给目标更结构化。通过为模型分配明确的角色,它能够理解冲突与动机,从而生成在叙事上更聪明、更有张力的内容。
  • Level 5:语义蓝图(semantic blueprint)
    这是上下文工程的终极形态。借助语义角色构造出的精确、无歧义的计划,把“创造力”转化为一种可靠、可复用的工程流程

image.png

你得到的回复可能会有所不同:每个 LLM Copilot 都会不断更新,而且生成式 AI 本身具有随机性,所以即便是两次完全相同的请求,结果也可能不同。然而,有方向、有设计的上下文,一定会比即兴、无方向的提示词产生更好的输出

那我们先从一个最基础的提示开始。

第 1 级:基础提示(零上下文)

基础提示就是一个简单、直接、没有任何背景信息的指令。
在这种情况下,AI 完全依赖训练数据中最常见的统计模式来作答,我们很快就能在例子中看到这一点。我们的输入是:

完成这个句子:
“The cat played with the...(这只猫玩着……)”

Gemini 2.5 的回复是:

... ball of yarn.

Here are a few other ways to complete the sentence:
... toy mouse.
... string.
... cardboard box.
... laser pointer dot.
... other kitten.

可以看到,这个输出非常“老套”。在没有上下文时,AI 会回退到最可预测、也最缺乏新意的补全。

Microsoft Copilot 的回复是:

“The cat played with the ball of yarn until it unraveled across the floor.”

...crumpled receipt it found under the couch, batting it around like it was the most precious treasure in the kingdom of dust bunnies.

这个输出在创意上还不错,但如果我们需要的是一个精确的回答,就会把它视为一种“幻觉(hallucination)”。在缺乏上下文时,AI 同样会回到它统计上最可能的补全。

OpenAI GPT-5 的回复是:

The cat played with the ball of yarn until it unraveled across the floor.

这里又是一个老套的答案。依旧是:没有上下文,AI 就会倾向于可预测但没什么灵感的补全。

实际上,这三个模型都完全可以回答成:

抱歉,在没有更多上下文的情况下,我无法正确完成这个句子。

我们可以看到,基础提示只会带来基础且不精确的回答,甚至会出现幻觉
这里我们的目标,并不是去折腾模型的超参数(比如 temperature),而是要设计更好的上下文
那么,接下来我们进入下一个层级。

第 2 级:更好的上下文(线性上下文)

在这一层,我们会添加一个简单的前置句子作为额外上下文,形成一条线性的语义“线索”。这能在一定程度上提高事实准确性,但仍然不会指导 AI 的风格或目标。我们的输入是:

完成这个句子:
“The ball fell on the floor and it rolled for a few feet. The cat then played with the...
(球掉到地上,在地上滚了几英尺。然后猫开始玩起了……)”

Gemini 2.5 的回复是:

The ball fell on the floor and it rolled for a few feet. The cat then played with the ball.

注意,这个回答事实是正确的,但缺乏创意——在没有更多上下文时,这是很正常的。

Microsoft Copilot 的回复是:

...ball, pouncing on it with swift little swats and chasing it across the room like it was the most thrilling prey in the world.

这个回答在我们构造的“小故事”中是事实正确的,同时也带有一些创意,但模型其实并不知道我们真正想让它生成什么

OpenAI GPT-5 的回复是:

The ball fell on the floor and it rolled for a few feet. The cat then played with the ball, batting it back and forth with its paws.

这个回答同样在事实和创意层面都还不错,但它依然不清楚我们的真正诉求,只是在随机延续故事

这些回复在“超出基础概率计算”方面并不算特别出色,但相对准确
对于一些简单任务,这可能已经够用了;但当我们需要模型执行更具体、更明确的任务时,这种方式就不够了。
所以,我们继续前进,开始真正地“工程化”一个上下文,并为模型设定清晰目标

第 3 级:良好的上下文(目标导向的上下文)

这一层,是上下文工程的第一个真正台阶
我们会给出一个明确的目标,并提供更丰富的描述性细节,让 LLM 能够和我们共同创作一个与目标对齐的场景。输入如下:

Goal:为一个儿童故事写一段简短而悬疑的场景。


Complete this sentence:
“The ancient grandfather clock chimed midnight, its shadow stretching like a claw.
A red ball, seemingly moving on its own, rolled out from under the dusty armchair.
The black cat, Onyx, crouched low, his eyes gleaming.
He then played with the...”

也就是:

目标:写一段适合儿童故事的、简短而悬疑的场景。

完成这个句子:
“古老的落地钟敲响了午夜,钟影像一只利爪般拖得老长。
一个红色的球仿佛自己会动似的,从满是灰尘的扶手椅底下滚了出来。
黑猫 Onyx 俯下身子,眼睛闪闪发光。
然后他开始玩起了那颗……”

Gemini 2.5 的回复是:

The ancient grandfather clock chimed midnight, its shadow stretching like a claw. A red ball, seemingly moving on its own, rolled out from under the dusty armchair. The black cat, Onyx, crouched low, his eyes gleaming. He then played with the... tiny, shimmering thread tied to the ball.

He pounced, but the thread danced away, pulling the red ball with it. The ball didn't just roll; it skittered across the floorboards as if it were alive, a little red mouse being tugged towards the heavy velvet curtains by the window. Onyx let out a low growl, a sound he never made when playing. The ball slipped silently behind the thick, dark fabric. The thread hung in the air for a second, taut and humming, before it too was yanked into the darkness. A tiny whisper, no louder than the rustle of a leaf, echoed from behind the curtain. "Mine."

可以看到,这个回答明显更有“方向性”
我们开始得到真正“符合我们要求”的东西了。
记住:LLM 和人类一样,都需要上下文才能给出更有效的回答。
对于人类和 LLM 来说,更长且设计良好的上下文窗口,通常意味着更好的输出。

Microsoft Copilot 的回复是:

...ball for only a moment before freezing. The ball had stopped—dead still—but Onyx's fur bristled. From behind the armchair came a soft creak, like a whispering floorboard. Onyx backed away, tail puffed, eyes locked on the darkness.

Then, a tiny giggle echoed through the room.
Not a human giggle.

The curtains fluttered though the windows were shut. Onyx hissed, and the ball rolled again—this time toward the hallway, leaving a faint trail of glowing red dust. The clock ticked louder now, each second like a drumbeat.

And just before the hallway swallowed the ball, a pale hand reached out from the shadows and snatched it.

Onyx bolted.

But the giggle remained.

你会注意到,这里 Microsoft Copilot 正好从我们输入结束的地方接着往下写
同时,我们也可以看到:我们正在从“一个提示词(非结构化上下文)”,过渡到“一个有导演意图的请求”。——我们是导演。

OpenAI GPT-5 的回复是:

...ball, batting it across the wooden floor. But instead of stopping, the ball bounced back toward him—as if pushed by an invisible hand. Onyx froze, his tail puffing up, while the clock ticked louder than ever, each tick echoing through the empty room.

在这个例子中,同样可以看到,模型准确地从我们指定的位置开始续写,而且质量也不错
总体来看,这一层的输出,比第 2 级明显更具创造性和目的性。但它们仍然是**“大致被引导”,而不是“精密地被控制”**。

如果我们想获得更高的精确度,就需要进一步——
把结构引入上下文本身。

第 4 级:高级上下文(基于角色的上下文)

在这一层,我们不再让 AI 自己去猜戏剧结构,而是明确规定每个参与者的角色
通过向 LLM 提供人物、物体以及它们之间的关系,我们给了它一套关于“冲突与动机”的脚手架,这会让输出在叙事上显得更聪明。
我们的输入如下:

Goal(目标) :写一句用于续写儿童故事的悬疑句子。

BACKGROUND(背景):

  • 主角(Protagonist):Onyx,一只勇敢的黑猫。
  • 反派(Antagonist):一座古老、闹鬼的落地钟。
  • 催化物(Catalyst Object):一个神秘的红球。
  • 场景(Setting):午夜,一个黑暗而布满灰尘的房间。
  • 前情动作(Preceding Action):落地钟敲响,红球滚了出来。

从这里继续故事:
“The black cat, Onyx, crouched low... he then played with the...”

Gemini 2.5 的回答是:

...mysterious red ball, batting it gently until a low groan echoed from the clock and its tall, glass door swung open into the darkness within.
……神秘的红球,他轻轻地拍打着它,直到一声低沉的呻吟从落地钟中传出,高高的玻璃门缓缓敞开,露出里面一片漆黑的深处。

这一次,我们不只是“提问”,而是非常具体地告诉 LLM 我们想要什么,结果就更可接受、更有指向性。

Microsoft Copilot 的回答是:

...ball until it pulsed with a strange glow, and the clock's hands spun wildly backward, unleashing a chilling whisper that slithered across the floor toward him.
……红球,直到它开始脉动般发出诡异的光芒,落地钟的指针疯狂地倒转,一阵阴冷的低语从钟内释放出来,贴着地板向它爬行而去。

在这个例子中,LLM 很明显在注意我们这个“导演”给出的结构化指令,故事的走向紧贴我们设定好的框架。

OpenAI GPT-5 的回答是:

The black cat, Onyx, crouched low… he then played with the red ball—only to freeze as the grandfather clock's pendulum creaked on its own, swinging faster and faster in the midnight silence.
黑猫 Onyx 伏低身子……然后他开始玩起那个红色的球——却猛地僵住了,因为落地钟的钟摆自己发出吱呀声,在午夜的寂静中越摆越快。

在这里,模型明显是按照我们提供的上下文结构来写的
到这里,我们已经从“无方向的线性提示”进化到“结构化上下文”:
我们不再只是问(ask) ,而是在指挥(tell) ——模型也以更有叙事纪律性的方式进行响应。
下一步,就是把这个过程形式化为一个语义蓝图(semantic blueprint)

第 5 级:语义蓝图(The semantic blueprint)

这一层代表了上下文架构的完整体
在这里,我们通过一种结构化的格式,为模型提供精确且无歧义的计划
创作行为因此变成一种可重复、可工程化的流程,由一组语义角色来驱动:场景目标、参与者及其描述、要完成的具体动作、动作的施事者(Agent)、以及受到影响最大的对象(Patient)。

我们的输入如下:

**TASK:**生成一句充满悬念的句子。

SEMANTIC BLUEPRINT(语义蓝图):

{
  "scene_goal": "Increase tension by showing defiance",
  "participants": [
    { "name": "Onyx", "role": "Agent", "description": "black cat" },
    { "name": "Red Ball", "role": "Patient", "description": "mysterious" },
    { "name": "Grandfather Clock", "role": "Source_of_Threat", "description": "ancient, looming" }
  ],
  "action_to_complete": {
    "predicate": "play with",
    "agent": "Onyx",
    "patient": "Red Ball"
  }
}

SENTENCE TO COMPLETE(待补全句子): “He then played with the...”

Gemini 2.5 的回答是:

He then played with the red ball, batting it with deliberate slowness directly under the shadow of the looming grandfather clock as its heavy pendulum began the first inexorable swing toward midnight.
随后,他开始玩起那个红球,故意慢条斯理地拍打着它,把球推到高大落地钟的阴影正下方,而那沉重的钟摆也在此刻启动了第一下不可阻挡的午夜摆动。

这个输出完全遵循了我们的蓝图
此时我们不再即兴发挥,而是让模型在执行一份已经设计好的计划

Microsoft Copilot 的回答是:

He then played with the red ball, his shadow flickering defiantly beneath the looming tick of the grandfather clock, as if daring time itself to strike.
随后,他开始玩起那颗红球,他的影子在落地钟逼近般的滴答声下倔强地晃动,仿佛在向“时间”本身下战书:来啊,敲响啊。

故事此时带有一种非常贴合我们指令的悬疑基调

OpenAI GPT-5 的回答是:

He then played with the Red Ball, its echoing bounce defying the relentless tick of the Grandfather Clock that seemed to grow louder with every daring swipe of Onyx's paw.
随后,他开始玩起那颗红球,每一次回弹都在无声对抗落地钟无情的滴答声,而那滴答声仿佛随着 Onyx 每一次大胆的挥爪而变得愈发响亮。

这里的悬疑氛围,正好呼应了我们设定的目标。
我们提供的结构,被完整地映射进了叙事中——我们得到了我们“让 LLM 做的事”

在这个阶段,我们已经不再是表演的观众,而是整场戏的导演;LLM 则是根据我们给出的剧本进行表演的演员。
但是,第 5 级中的这种语义蓝图到底是如何工作的?
要回答这个问题,我们需要引入 SRL(Semantic Role Labeling,语义角色标注) ,它将带领我们第一次从“线性语言序列”跨入“多维语义结构”的世界。

SRL:从线性序列到语义结构

我们在上下文工程的五个层级中一路走来,最终抵达了“语义蓝图”这一方法:
它不再给 LLM 一个模糊的请求,而是提供一套结构化的计划。
但我们如何从人类语言这种线性、往往含糊的表达方式,构造出这样一份蓝图呢?

要做到这一点,我们必须停止把句子仅仅看成“单词串”,而开始把它们视为意义结构

将我们对“线性序列”的感知升级为“结构化语义”的关键,就是 SRL(语义角色标注)
这是一种强大的语言学技术,最初由 Lucien Tesnières 正式提出,之后由 Charles J. Fillmore 进一步发展。它将语言表示从线性序列提升为语义结构。你可以在本书参考文献部分找到他们工作的链接。

SRL 在这些先驱的基础上逐步发展,目标是从一条线性的句子中拆解出一个最根本的问题:

谁在什么时间、什么地点、出于什么原因,对谁做了什么?
(Who did what to whom, when, where, and why?)

它超越了传统语法分析,去识别每个成分在整体行动中所扮演的功能角色
这样一来,我们获得的不再是简单的文本线性序列,而是一张以动作或谓词为中心的语义层次结构图

对于希望了解这些基础概念——如 SRL 和语义蓝图——如何融入更大“上下文引擎(context engine)”架构的读者,附录中提供了一个简明的整体概览,展示整个系统如何把这些概念串联起来。

来看一个简单的句子:

Sarah pitched the new project to the board in the morning.
Sarah 在早晨向董事会推介了这个新项目。

一个 LLM 通常会把这串词当作一连串 token 来处理。
而一个使用 SRL 的“上下文工程师”,看到的则是更多的东西:
是一张 “语义树 / 图(stemma 或 graph)” ,将每个词映射到它的语义角色上。
这里的中心动作是 “pitched”,其他所有成分都根据这个动作被分配角色。

通过给这些角色贴标签,我们将能够做到:

  • 从原本线性的字符串中,重建出多维的语义结构
  • 定义一份 LLM 可以遵循的语义蓝图,就像我们在第 5 级示例中看到的那样

这个过程,是高阶上下文工程的基础技能

为了更加直观地理解 SRL 的过程,接下来我们会编写一个 Python 程序,把这套强大的理论真正运用到实践中。

在 Python 中构建一个 SRL 笔记本

这个 Python 脚本的目的,是把一句话中最关键的成分提取出来,并把它们转化为一张“意义的可视化图”。程序不会把结构悄悄地藏在文本里,而是画出词与语义角色之间的关系示意图。图 1.2 展示了整个流程:

image.png

图 1.2:SRL 程序的流程图

我们一步一步走过每个阶段:

  • 用户输入(User Input)
    整个过程从你调用主函数 visualize_srl() 开始。在这里,你提供句子的构建块,例如动词(谓词)、施事(执行动作的实体)、受事(接收或被动作影响的实体),以及其它用文本参数表示的语义角色。
  • 数据结构化(Data Structuring)
    主函数会把这些组件组织成一个 Python 字典。每一项都会被赋予合适的 SRL 标签,于是,一开始那串松散的词语就变成了一张有结构的“角色地图”。
  • 绘图引擎(The Plotting Engine)
    当字典准备好之后,它会被传入一个内部辅助函数 _plot_stemma。这个函数只做一件事:画图
  • 画布设置(Canvas Setup)
    绘图引擎使用 Matplotlib 创建一张空白画布,为后续的图形展示搭好舞台。
  • 动态定位(Dynamic Positioning)
    函数会计算每个语义角色节点应该放在哪个位置,这样无论包含多少成分,布局都能保持清晰与平衡。
  • 绘制语义树(绘图 / 图结构)(Drawing the Stemma / Graph)
    引擎先把核心动词作为根节点画出来,再把每个角色添加为子节点,并用带标签的箭头把它们连接起来。原本线性的一句句子,此时变成了一张“意义地图”。
  • 最终展示(Final Display)
    最后,函数添加标题并展示完整的语义蓝图。

到这里,我们已经准备好在实践中实现 SRL 了。请在 GitHub 仓库 Chapter01 目录下打开 SRL.ipynb

关于代码本身,需要说明的是:它是为了讲解和教学而写的,而不是为了生产环境。重点是尽可能直接地展示信息流的走向。因此,这个笔记本刻意避免了复杂的控制结构或错误处理逻辑,以免分散你对流程本身的关注。如果未来要构建真正的生产系统,这些完善工作可以随时再补上。
另外,如果你要在本地运行这个笔记本,需要安装 spaCy、Matplotlib 和 Graphviz,然后通过如下命令下载 spaCy 的英文模型:

python -m spacy download en_core_web_sm

接下来,我们要开始构建一个语义蓝图可视化工具,用于生成我们的 stemma ——本质上就是一个带有语义节点和边的图。我们会把脚本拆成几个代码块,逐段解释每一部分的用途。


首先,导入必要的工具

我们的可视化工具依赖 Matplotlib 来绘图:

  • matplotlib.pyplot as plt
    主绘图库接口,按惯例使用别名 plt 以方便使用。
  • from matplotlib.patches import FancyArrowPatch
    用于绘制干净、带方向的箭头,以便将动词与各个语义角色连接起来。

有了这些工具之后,我们就可以开始定义 SRL 的可视化函数了。

主函数:visualize_srl

我们这个程序的核心是主函数 visualize_srl()
它是整个流程的主要交互入口,对应图 1.2 中的步骤 1。
作为用户,你只需要把句子的核心成分作为参数传给它——函数会负责剩下的工作:组织数据,并把它交给负责绘图的辅助函数。

这些参数与之前定义的语义角色一一对应。为了让接口足够灵活,函数还接收 **kwargs,这样你就可以传入任意数量的可选修饰角色(例如时间、地点等),而不必让函数签名变得臃肿。

visualize_srl() 唯一的目的,就是把这些语义角色组装成一个字典 srl_roles,然后再把它连同谓词(动词)一起交给内部函数 _plot_stemma() 做可视化:

def visualize_srl(verb, agent, patient, recipient=None, **kwargs):
    """
    Creates a semantic blueprint and visualizes it as a stemma.
    This is the main, user-facing function.
    """
    srl_roles = {
        "Agent (ARG0)": agent,
        "Patient (ARG1)": patient,
    }
    if recipient:
        srl_roles["Recipient (ARG2)"] = recipient
    # Add any extra modifier roles passed in kwargs
    for key, value in kwargs.items():
        # Format the key for display, e.g., "temporal" -> "Temporal (ARGM-TMP)"
        role_name = f"{key.capitalize()} (ARGM-{key[:3].upper()})"
        srl_roles[role_name] = value
    _plot_stemma(verb, srl_roles)

这个函数刻意保持简单:
它展现的是“意义流”的组织方式,而不是一个生产级解析器的全部复杂性。
通过这种简化,我们可以把注意力集中在:语义角色是如何被组织成一份 LLM 可以使用的语义蓝图的

在开始真正绘制 stemma 之前,我们先更仔细地看一下支撑这一结构的语义角色。

定义语义角色

我们来看一下 visualize_srl 中用到的这些角色——它们是进行上下文工程的一种手段。
继续使用我们的示例句:

Sarah pitched the new project to the board in the morning.
Sarah 在早晨向董事会推介了这个新项目。

乍一看,这只是一个简单的句子。
对一个 LLM 来说,这不过是一串 token,按次序排成的单词序列。
但对一个“上下文工程师”来说,句子中的每个部分都在这次动作中扮演着特定的角色。

为了捕捉这些角色,我们使用一组标签——它们是为线性文字添加多维结构、定义“意义”的主要工具:

  • Predicate(谓词 / 动词)
    谓词是句子的核心,是中心动作或状态。其他所有角色都围绕它来定义。
    在我们的例子中,pitched 就是谓词。

  • Agent (ARG0,施事)
    施事是执行动作的实体,也就是“谁在做这件事”。
    在例子中,Sarah 是施事(Agent)。

  • Patient (ARG1,受事)
    受事是被动词直接作用或影响的实体。
    例子中,the new project(这个新项目)是受事。

  • Recipient (ARG2,受益者 / 接收方)
    接收者是接收受事,或接收动作结果的实体。
    在例子中,the board(董事会)就是接收者。

  • Argument Modifiers(ARGM-,论元修饰语)
    这些是额外的角色,用来提供上下文,但不是核心动作的一部分。它们回答的是:何时、何地、为何、如何等问题,例如:

    • Temporal (ARGM-TMP) :时间修饰,说明动作“什么时候”发生。
      在例子中,…in the morning(在早晨)就是时间修饰。
    • Location (ARGM-LOC) :地点修饰,说明动作“在哪里”发生。
      例如:…in the conference room(在会议室里)就是地点修饰。
    • Manner (ARGM-MNR) :方式修饰,说明动作“如何”被执行。
      例如:…with great confidence(非常自信地)就是方式修饰。

有了这些角色之后,句子就不再只是扁平的单词序列,而变成了一张结构化的意义地图
接下来,我们就可以开始绘制这张 stemma 了。

绘图引擎:_plot_stemma 和画布设置

我们的内部辅助函数 _plot_stemma(对应图 1.2 中的步骤 3)负责完成可视化的主要工作。
它只专注于一个职责:绘制图形

首先,我们创建一张空白画布 fig, ax,并设置图形尺寸。
我们关闭坐标轴,因为这里画的不是传统的图表,而是一张示意图:

def _plot_stemma(verb, srl_roles):
    """Internal helper function to generate the stemma visualization."""
    fig, ax = plt.subplots(figsize=(10, 6))
    ax.set_xlim(0, 10)
    ax.set_ylim(0, 10)
    ax.axis('off')

接下来,可以像图 1.2 中第 4 步那样定制样式:
我们定义节点的视觉外观。使用 Python 字典来存储动词和各角色节点的样式(边框、填充色等),这样如果将来想改视觉风格,只需改这两处配置即可:

    verb_style = dict(boxstyle="round,pad=0.5", fc="lightblue", ec="b")
    role_style = dict(boxstyle="round,pad=0.5", fc="lightgreen", ec="g")

画布准备好、样式也设定之后,我们就进入动态布局部分:根据角色数量动态摆放每个节点的位置,保证无论有多少角色,图都能保持清晰美观。

动态定位与绘制 stemma(图)

我们先从根节点(动词)开始。
因为动词是整个结构的锚点,我们把它放在画布顶部偏中间的位置。利用 ax.text() 把它画出来,并应用之前定义的 verb_style

    verb_pos = (5, 8.5)
    ax.text(verb_pos[0], verb_pos[1], verb, ha="center", va="center",
        bbox=verb_style, fontsize=12)

接下来,我们要为根节点的子节点——这些语义角色——安排位置。
为了让图在角色数量变化时仍然整洁,我们需要动态计算它们的坐标
我们先把 srl_roles 字典转成列表,计算角色数量,然后在一条水平线上均匀分布它们的 x 坐标:

    srl_items = list(srl_roles.items())
    num_roles = len(srl_items)
    x_positions = [10 * (i + 1) / (num_roles + 1)
        for i in range(num_roles)]
    y_position = 4.5

现在,我们可以往 stemma 图里添加角色节点、箭头以及箭头标签了。

我们通过循环遍历 srl_roles 字典中的每一项,在每次循环中执行三个操作:

  1. 绘制角色节点(role node)
    ax.text() 在计算出的坐标位置画出当前角色的文本框。
  2. 绘制连接箭头(connecting arrow)
    使用 FancyArrowPatch 将动词位置与角色位置连接起来,并添加到图中。
  3. 绘制箭头标签(arrow label)
    计算箭头中点的位置,在那里标注这个角色的名称(例如 “Agent (ARG0)”),以清晰展示语义关系。

代码如下:

    for i, (role, text) in enumerate(srl_items):
        child_pos = (x_positions[i], y_position)
        ax.text(child_pos[0], child_pos[1], text,
                ha="center", va="center",
                bbox=role_style, fontsize=10, wrap=True)

        arrow = FancyArrowPatch(
            verb_pos,
            child_pos,
            arrowstyle='->',
            mutation_scale=20,
            shrinkA=15,
            shrinkB=15,
            color='gray'
        )
        ax.add_patch(arrow)

        label_pos = (
            (verb_pos[0] + child_pos[0]) / 2,
            (verb_pos[1] + child_pos[1]) / 2 + 0.5
        )
        ax.text(label_pos[0], label_pos[1],
            role, ha="center", va="center",
            fontsize=9, color='black', bbox=dict(boxstyle="square,pad=0.1", fc="white", ec="none"))

最后,我们为这张可视化图添加标题,并通过 plt.show() 展示最终的 stemma:

    fig.suptitle("The Semantic Blueprint (Stemma Visualization)",
        fontsize=16)
    plt.show()

到这里,我们的主函数就完整了。
现在你可以运行一些示例,看看这个 stemma 可视化工具在实际中的表现。

运行 SRL 示例(Running SRL examples)

通过用不同的参数调用我们的 visualize_srl 函数,我们可以瞬间将线性的句子,转换成结构化的语义蓝图
下面这些示例会加深你对核心语义角色的理解,也能展示我们构建的这个工具有多灵活。

示例 1:商务提案(Business pitch)

我们继续使用前面一直在拆解的那句话:

Sarah pitched the new project to the board in the morning.
Sarah 在早晨向董事会推介了这个新项目。

对应的 SRL 定义如下:

print("Example 1: A complete action with multiple roles.")
visualize_srl(
    verb="pitch",
    agent="Sarah",
    patient="the new project",
    recipient="to the board",
    temporal="in the morning"
)

在这个示例中,我们为所有核心角色以及一个修饰语提供了取值:

  • Predicate(谓词) :中心动作是 pitch(推介)。
  • Agent (ARG0,施事) :执行推介的人是 Sarah
  • Patient (ARG1,受事) :被推介的对象是 the new project(这个新项目)。
  • Recipient (ARG2,接收者) :接收这次推介的是 to the board(董事会)。
  • Temporal (ARGM-TMP,时间修饰语) :动作发生在 in the morning(早晨)。

运行这段代码会生成图 1.3 所示的语义树(stemma):
pitch 作为根节点,下面连着四个子节点,分别代表这些语义角色。

image.png

图 1.3:一个根节点和四个子节点的语义结构

接下来我们看另一个示例。

示例 2:技术更新(Technical update)

现在我们来建模另一种类型的句子,这次加入一个地点信息。考虑这句话:

The backend team resolved the critical bug in the payment gateway.
后端团队修复了支付网关中的关键缺陷。

对应的 SRL 定义如下:

print("\nExample 2: An action with a location")
visualize_srl(
    verb="resolved",
    agent="The backend team",
    patient="the critical bug",
    location="in the payment gateway"
)

各个成分与语义角色的映射是:

  • Predicate(谓词) :动作是 resolved(修复了)。
  • Agent (ARG0,施事) :执行修复的是 The backend team(后端团队)。
  • Patient (ARG1,受事) :被修复的是 the critical bug(关键缺陷)。
  • Location (ARGM-LOC,地点修饰语) :修复行为发生的上下文是 in the payment gateway(在支付网关中)。

可视化工具会生成图 1.4 所示的语义树:
resolved 位于顶部,连接到三个关键参与者节点。这让这条技术更新的语义结构变得一目了然。

image.png

图 1.4:包含动作与地点的语义结构树

接下来,我们看看如何可视化“事情是如何完成的”。

示例 3:项目里程碑(Project milestone)

最后,我们可视化一句描述**“某事是如何完成的”句子,这里会用到方式修饰语(manner modifier)**。句子如下:

Maria's team deployed the new dashboard ahead of schedule.
Maria 的团队提前上线了新的仪表盘。

对应的 SRL 定义是:

print("\nExample 3: Describing how an action was performed")
visualize_srl(
    verb="deployed",
    agent="Maria's team",
    patient="the new dashboard",
    manner="ahead of schedule"
)

这些角色映射如下:

  • Predicate(谓词) :动作是 deployed(上线 / 部署)。
  • Agent (ARG0,施事) :执行动作的是 Maria's team
  • Patient (ARG1,受事) :被操作的对象是 the new dashboard(新的仪表盘)。
  • Manner (ARGM-MNR,方式修饰语) :描述部署是如何完成的 —— ahead of schedule(提前完成)。

运行这段代码会生成图 1.5 所示的语义树,展示了方式修饰语如何为核心的“施事–受事”关系增加一层上下文信息。

image.png

图 1.5:说明一个动作“如何完成”的语义结构树

这三个示例说明了:
一句话——原本只是一个简单的单词序列——可以通过 SRL 被拆解成它的语义组成部分

线性的文本因此变成了一份结构化的语义蓝图
有了这层结构,你就能更好地控制自己提供给 LLM 的信息

在掌握这个 SRL 工具之后,我们已经准备好将这套框架应用到一个实际用例中。

构建一个“会议分析”用例(Engineering a meeting analysis use case)

这个会议分析用例展示了一种很有威力的技巧,叫做 上下文链式(context chaining)
我们通过多步分析来引导 LLM,而不是扔给它一个巨大而复杂的单条提示。

与其使用一个庞大、复杂的 prompt,我们改用一系列更小、更聚焦的 prompt——前一步的输出会作为后一步的输入,这样就形成了一条高度可控、逻辑清晰的工作流。

之所以要使用上下文链式,是因为 LLM 尽管很强大,却没有真正的记忆或长期专注力
给一个 LLM 一条超长、包含多步任务的指令,就好像你给一个“聪明但健忘的助手”快速口头念了一堆复杂指示,然后还指望结果完美——现实往往是:

  • 模型会忘记主要目标
  • 会被无关细节拖住
  • 输出变得混乱、缺乏重点

上下文链式解决的就是这个问题:
它把复杂任务拆解成受控的、一步一步的对话流程。每一步都有单一而明确的目标,而它的输出会作为下一步“干净且聚焦”的输入。

这种方法给“上下文工程师”(也就是你)带来三大关键优势:

  1. 精确与可控(Precision and control)
    你可以在每个阶段引导 AI 的思路,确保分析始终不偏题。
  2. 清晰与可调试(Clarity and debugging)
    如果某一步结果不好,你可以准确知道要修改哪一个 prompt,而不是面对一条巨无霸指令无从下手。
  3. 在洞见之上不断构建(Building on insight)
    整个流程形成一条“叙事链条”,让 AI 能在前一步精炼过的洞见基础上继续深入,最终得到更加复杂而连贯的结果。

流程回顾:程序流程图(Figure 1.6)

图 1.6 展示了这个程序的流程图:

image.png

图 1.6:上下文链式分析流程图

这个分支结构是这项技术威力的关键。它把工作流从“单一路径”变成“并行的多任务分析”:
一边识别新的进展,一边分析隐含的动态,再一边生成全新的解决方案。

这种流程的复杂性也解释了为什么后续章节我们会构建一个 Context Engine(上下文引擎) ,来自动管理这些关系。

下面是整体流程的节点说明:


1. 输入原始会议记录(Input raw transcript,meeting_transcript
  • Purpose(目的) :提供唯一的原始数据源
  • Predecessor(前驱) :无(这是起点)
  • Successor(后继) :g2(“提取关键信息”)

2. 提取关键信息(Isolate key content,g2)
  • Purpose:清洗数据,把“信号”和“噪音”分开

  • Predecessor:transcript(原始会议记录)

  • Successors:这是主要的分叉点。它的输出 substantive_content 会作为三个并行步骤的直接前驱:

    • g3(识别新的进展:Identify New Developments)
    • g4(分析隐含动态:Analyze Implicit Dynamics)
    • g5(生成新的解决方案:Generate Novel Solution)

3. 识别新的进展(Identify new developments,g3)
  • Purpose:相对于“上一次会议总结”,找出新的信息

  • Predecessors

    • substantive_content(由 g2 输出)
    • prev_summary(上次会议总结)
  • Successor:g6(生成结构化摘要)


4. 分析隐含动态(Analyze implicit dynamics,g4)
  • Purpose:分析情绪、立场以及社交潜台词
  • Predecessorsubstantive_content(步骤 g2 的输出)
  • Successor:无(直接产出最终结果 implicit_threads

5. 生成新的解决方案(Generate novel solution,g5)
  • Purpose:把事实综合成一个新的、富有创意的方案
  • Predecessorsubstantive_content(来自步骤 g2)
  • Successor:无(直接产出最终结果 novel_solution

6. 生成结构化摘要(Create structured summary,g6)
  • Purpose:把“新增进展”整理成表格化的结构化摘要
  • Predecessor:g3(识别新的进展)
  • Successor:g7(撰写跟进行动)

7. 起草跟进行动(Draft follow-up action,g7)
  • Purpose:把结构化摘要转化成“可执行的行动项”,例如一封跟进邮件
  • Predecessor:g6(结构化摘要)
  • Successor:无(输出最终结果 follow_up_email

接下来,我们把这个流程图转化为真正的代码,并一步步运行。

环境准备与会议记录加载

在章节目录下打开 Use_Case.ipynb
首先安装所需的 OpenAI 库:

# Cell 1: Installation
!pip install openai

这个工作流使用 Google Colab Secrets 来存储 OpenAI 的 API Key。
加载密钥、设置环境变量,并初始化客户端:

# Cell 2: Imports and API Key Setup
# We will use the OpenAI library to interact with the LLM and Google Colab's
# secret manager to securely access your API key.

import os
from openai import OpenAI
from google.colab import userdata

# Load the API key from Colab secrets, set the env var, then init the client
try:
    api_key = userdata.get("API_KEY")
    if not api_key:
        raise userdata.SecretNotFoundError("API_KEY not found.")

    # Set environment variable for downstream tools/libraries
    os.environ["OPENAI_API_KEY"] = api_key

    # Create client (will read from OPENAI_API_KEY)
    client = OpenAI()
    print("OpenAI API key loaded and environment variable set successfully.")

except userdata.SecretNotFoundError:
    print('Secret "API_KEY" not found.')
    print('Please add your OpenAI API key to the Colab Secrets Manager.')
except Exception as e:
    print(f"An error occurred while loading the API key: {e}")

接着,把会议记录作为一个多行字符串加入代码,这就是后续链式步骤的输入:

# Cell 3: The Full Meeting Transcript
meeting_transcript = """
        Tom: Morning all. Coffee is still kicking in.
        Sarah: Morning, Tom. Right, let's jump in. Project Phoenix timeline. Tom, you said the backend components are on track?
        Tom: Mostly. We hit a small snag with the payment gateway integration. It's... more complex than the docs suggested. We might need another three days.
        Maria: Three days? Tom, that's going to push the final testing phase right up against the launch deadline. We don't have that buffer.
        Sarah: I agree with Maria. What's the alternative, Tom?
        Tom: I suppose I could work over the weekend to catch up. I'd rather not, but I can see the bind we're in.
        Sarah: Appreciate that, Tom. Let's tentatively agree on that. Maria, what about the front-end?
        Maria: We're good. In fact, we're a bit ahead. We have some extra bandwidth.
        Sarah: Excellent. Okay, one last thing. The marketing team wants to do a big social media push on launch day. Thoughts?
        Tom: Seems standard.
        Maria: I think that's a mistake. A big push on day one will swamp our servers if there are any initial bugs. We should do a soft launch, invite-only for the first week, and then do the big push. More controlled.
        Sarah: That's a very good point, Maria. A much safer strategy. Let's go with that. Okay, great meeting. I'll send out a summary.
        Tom: Sounds good. Now, more coffee.
        """

现在,你已经准备好开始做 上下文链式分析了。
第一步会在 meeting_transcript 中分离“信号”和“噪音”:
决策、更新、问题、建议提取出来,把寒暄与闲聊剔除掉。

层级 1:定义分析范围(“what”)

我们先定义本次分析的范围。
如前所述,每一步的输出都会变成下一步的输入,构成一个上下文链。

要非常明确地告诉模型:
需要提取什么、忽略什么
目标就是把“实质内容”(决策、更新、问题、方案)从“对话噪音”(问候、闲聊等)中分离出来。

# Cell 4: g2 - Isolating Content from Noise
prompt_g2 = f"""
        Analyze the following meeting transcript. Your task is to isolate the substantive content from the conversational noise.
        - Substantive content includes: decisions made, project updates, problems raised, and strategic suggestions.
        - Noise includes: greetings, pleasantries, and off-topic remarks (like coffee).
        Return ONLY the substantive content.

        Transcript:
        ---
        {meeting_transcript}
        ---
        """

现在,我们调用 OpenAI 来提取“实质内容”:

from openai import OpenAI
try:
    client = OpenAI()

    response_g2 = client.chat.completions.create(
        model="gpt-5",
        messages=[
            {"role": "user", "content": prompt_g2}
        ]
    )

    substantive_content = response_g2.choices[0].message.content
    print("--- SUBSTANTIVE CONTENT ---")
    print(substantive_content)

except Exception as e:
    print(f"An error occurred: {e}")

示例输出(实质内容)如下:

--- SUBSTANTIVE CONTENT ---
- Project Phoenix timeline: Backend mostly on track, but payment gateway integration is more complex than expected; needs an additional three days.
- Impact: Extra three days would push final testing up against the launch deadline, reducing buffer.
- Mitigation decision: Tom will work over the weekend to catch up (tentatively agreed).
- Front-end status: Ahead of schedule with extra bandwidth.
- Marketing/launch strategy: Initial plan for a big social media push on launch day flagged as risky (potential server load with early bugs). Decision: Use a soft launch (invite-only) for the first week, then execute the big push.

接着,我们模拟一次 RAG(检索增强生成) 场景:
把这次会议与“上一次的会议总结”做对比,只关注“有哪些是新的内容”。
这能很好地说明历史上下文的重要性:

# Cell 5: g3 - Identifying NEW Information (Simulated RAG)
previous_summary = "In our last meeting, we finalized the goals for Project Phoenix and assigned backend work to Tom and front-end to Maria."

prompt_g3 = f"""
Context: The summary of our last meeting was: "{previous_summary}"

Task: Analyze the following substantive content from our new meeting. Identify and summarize ONLY the new developments, problems, or decisions that have occurred since the last meeting.

New Meeting Content:
---
{substantive_content}
---
"""

再次调用 OpenAI,执行类似 RAG 的任务:

from openai import OpenAI
from google.colab import userdata

# Your chat completion request
try:
    response_g3 = client.chat.completions.create(
        model="gpt-5",
        messages=[{"role": "user", "content": prompt_g3}]
    )
    new_developments = response_g3.choices[0].message.content
    print("--- NEW DEVELOPMENTS SINCE LAST MEETING ---")
    print(new_developments)
except Exception as e:
    print(f"An error occurred: {e}")

示例输出会把“新内容”和“核心信息”提炼出来:

--- NEW DEVELOPMENTS SINCE LAST MEETING ---
- Backend issue: Payment gateway integration is more complex than expected; needs an additional three days.
- Schedule impact: The extra three days compress final testing, pushing it up against the launch deadline and reducing buffer.
- Mitigation decision: Tentative agreement that Tom will work over the weekend to catch up.
- Front-end status: Ahead of schedule with extra bandwidth.
- Launch/marketing decision: Shift from a big day-one social push to a one-week invite-only soft launch, followed by the major push.

到这里,我们已经梳理清楚了范围——也就是这次会议记录中的 “what”
下一步,我们将深入挖掘: “how” ——事情是如何被表达、感受和推进的。

第 2 层:开展调查(“how”——事情是怎么发生的)

现在,我们从识别事实,进入到生成洞见——这就是语义上下文理解之旅的核心部分。
在这一层,提示词开始要求 AI “读懂字里行间”

除了那些明面上的事实,每一次会议里其实都藏着潜台词:犹豫、紧张、情绪和氛围。
这一阶段,就是让 AI 去分析这些底层的互动动态

# Cell 6: g4 - Uncovering Implicit Threads
prompt_g4 = f"""
Task: Analyze the following meeting content for implicit social dynamics and unstated feelings. Go beyond the literal words.
- Did anyone seem hesitant or reluctant despite agreeing to something?
- Were there any underlying disagreements or tensions?
- What was the overall mood?

Meeting Content:
---
{substantive_content}
---
"""

现在我们运行这个提示,让模型去挖掘会议中 超越字面内容的隐含动态:

try:
    response_g4 = client.chat.completions.create(
        model="gpt-5",
        messages=[{"role": "user", "content": prompt_g4}]
    )
    implicit_threads = response_g4.choices[0].message.content
    print("--- IMPLICIT THREADS AND DYNAMICS ---")
    print(implicit_threads)
except Exception as e:
    print(f"An error occurred: {e}")

在这个阶段的输出中,有一个新的重点:
LLM 不只是简单地复述事实总结事件,它还会把潜台词挖掘出来:

--- IMPLICIT THREADS AND DYNAMICS ---
Here's what seems to be happening beneath the surface:

Hesitation/reluctance despite agreement
- Tom's "tentative" agreement to work over the weekend reads as reluctant. It suggests he felt pressure to volunteer rather than genuine willingness.
- Marketing likely agreed to the soft launch with some reluctance; shifting from a big day-one push to invite-only implies a concession to engineering risk.

Underlying disagreements or tensions
- Pace vs quality: Engineering wants stability and buffer; marketing originally aimed for impact. The soft launch is a compromise, but the differing risk appetites remain.
- Workload equity: Backend is behind while frontend has "extra bandwidth." The decision to have Tom work the weekend (vs redistributing tasks) hints at siloing or a norm of individual heroics, which can breed quiet resentment.
- Testing squeeze: Pushing testing against the deadline implies QA will be under pressure, potentially creating friction if bugs slip through or late changes occur.
- Estimation confidence: The payment gateway being "more complex than expected" may subtly challenge earlier estimates, inviting unspoken doubt about planning or vendor integration assumptions.

Overall mood
- Sober, pragmatic, and slightly tense. The group is solution-oriented and collaborative, but there's a sense of urgency and strain, with relief at having a plan tempered by concerns about workload, risk, and reduced buffer.

也就是说,在这里,上下文链式方法已经从记录“发生了什么” ,升级成了解释“这为什么重要”
输出不再像一份“原始会议记录”,而更像一份分析师的评论,让我们看见团队动态中那些平时不会被说出口的部分。

接下来,我们会让 AI 发挥创造力,通过综合会议中的不同信息来提出一个解决方案,展示它的“思考能力”:

# Cell 7: g5 - Generating a Novel Solution
prompt_g5 = f"""
Context: In the meeting, Maria suggested a 'soft launch' to avoid server strain, and also mentioned her team has 'extra bandwidth'.
Tom is facing a 3-day delay on the backend.

Task: Propose a novel, actionable idea that uses Maria's team's extra bandwidth to help mitigate Tom's 3-day delay. Combine these two separate pieces of information into a single solution.
"""
try:
    response_g5 = client.chat.completions.create(
        model="gpt-5",
        messages=[{"role": "user", "content": prompt_g5}]
    )
    novel_solution = response_g5.choices[0].message.content
    print("--- NOVEL SOLUTION PROPOSED BY AI ---")
    print(novel_solution)
except Exception as e:
    print(f"An error occurred: {e}")

这个提示有意挑战 AI:
把会议中的两条线索——Maria 团队有多余前端带宽Tom 的后端进度要多 3 天——编织成一个全新的解决方案

这就是上下文链式真正的力量所在:
我们不再只是让模型做“回忆”或被动解读,而是让它创造出会议中本来并不存在的新方案

--- NOVEL SOLUTION PROPOSED BY AI ---
Idea: Soft launch behind a temporary "Edge Bridge" that Maria's team builds to buffer reads/writes until Tom's backend is ready.

What Maria's team does (uses their extra bandwidth)
- Stand up a thin serverless/API facade that matches the real API contracts (e.g., API Gateway/Lambda + SQS/DynamoDB or Cloudflare Workers + Durable Objects).
- Reads: Serve from a prewarmed cache or static snapshots (stale-while-revalidate). Update snapshots hourly via a lightweight data export from staging or existing endpoints.
- Writes: Capture requests into a durable queue with idempotency keys; return immediate "queued" success to the client and show "syncing" UI. When Tom's backend is live, a replay worker drains the queue and applies changes.
- Add feature flags/traffic gating (e.g., LaunchDarkly) to limit the soft launch cohort and throttle requests to avoid server strain.

How this mitigates the 3-day delay
- The product can soft-launch to a small cohort without waiting for the backend; users get read access and buffered writes.
- When Tom's backend is ready, flip routing to the real backend and drain the queue to reconcile data.

Action plan and timeline
- Day 0 (today): Identify minimal critical endpoints for the soft launch. Classify by read vs write. Define API contracts and idempotency rules. Set success/error thresholds and a kill switch.
- Day 1: Maria's team builds the Edge Bridge, cache, and write queue; implement basic observability and encryption-at-rest for any PII in the queue. Front-end adds "syncing" UI states and feature flags.
- Day 2: QA with mocked data, then with a tiny internal cohort. Prewarm caches. Set traffic cap (e.g., 510% of target users).
- Day 3: Soft launch goes live on the Edge Bridge. When Tom's backend unlocks, switch routing gradually, start replay worker, monitor for conflicts, then retire the bridge.

Risk controls
- Data consistency: Use idempotency keys and a simple conflict policy (latest-write-wins or version checks).
- Rollback: Feature flag to disable writes or pause replay if error rate exceeds threshold.
- Privacy: Encrypt queued payloads; limit PII scope.

Owners
- Maria's team: Edge Bridge, caching, queue/replay, monitoring.
- Tom's team: Final backend endpoints, schema, and replay acceptance hooks.
- Front-end: Feature-flag routing and "queued/syncing" UX.

This combines Maria's extra bandwidth with a controlled soft launch to keep momentum while absorbing Tom's 3-day backend delay.

这个输出向我们展示了:
一个 LLM 完全可以充当富有创造力的合作伙伴,提出一个在技术上可行的折中方案:
把系统设计、风险控制、职责分工揉合在一起。

这样的结果,已经不再像是“碰运气的回答”,而更像是一位资深工程师在设计评审会上画出来的方案草图。

第 3 层:确定行动(“what next”——下一步做什么)

最后,我们要把前面的分析变成具体的、面向未来的产出物
到目前为止,我们生成的都是“原始洞见”:新的事实、隐含的动态、以及有创意的解决方案。
但只有当这些洞见能够被清晰地传达出来时,它们才真正有价值。
下一步,就是把所有内容汇总成一个结构化的最终摘要

这样做有两个目的:

  • 逼迫信息变得清晰:因为每一项内容都必须被压缩成「主题、结论/结果、负责人」三个部分。
  • 让信息具备可复用性:无论是放进邮件、报告,还是仪表盘,这份摘要都足够干净、直接可用、能立刻转化为行动。
# Cell 8: g6 - Creating the Final, Structured Summary
prompt_g6 = f"""
Task: Create a final, concise summary of the meeting in a markdown table.
Use the following information to construct the table.

- New Developments: {new_developments}

The table should have three columns: "Topic", "Decision/Outcome", and "Owner".
"""
try:
    response_g6 = client.chat.completions.create(
        model="gpt-5",
        messages=[{"role": "user", "content": prompt_g6}]
    )
    final_summary_table = response_g6.choices[0].message.content
    print("--- FINAL MEETING SUMMARY TABLE ---")
    print(final_summary_table)
except Exception as e:
    print(f"An error occurred: {e}")

我们得到的输出,代表了整个会议的“精华”:
所有噪音、潜台词和博弈,都被蒸馏成了一份干净的参考点

--- FINAL MEETING SUMMARY TABLE ---
| Topic | Decision/Outcome | Owner |
|---|---|---|
| Backend payment gateway integration | More complex than expected; requires an additional three days | Backend Team |
| Schedule impact | Extra three days compress final testing, reducing buffer before launch | Project Manager |
| Mitigation | Tentative plan: Tom will work over the weekend to catch up | Tom |
| Front-end status | Ahead of schedule with extra bandwidth available | Front-end Team |
| Launch/marketing plan | Shift to a one-week invite-only soft launch, then major day-one push | Marketing + Product |

在上下文链式流程中,最后一步就是把洞见闭环为行动
也就是把这份结构化分析变成一封专业的跟进邮件。

# Cell 9: g7 - Drafting the Follow-Up Action
prompt_g7 = f"""
Task: Based on the following summary table, draft a polite and professional follow-up email to the team (Sarah, Tom, Maria).
The email should clearly state the decisions made and the action items for each person.

Summary Table:
---
{final_summary_table}
---
"""

接下来,LLM 再次上场,完成这封跟进邮件的撰写:

try:
    response_g7 = client.chat.completions.create(
        model="gpt-5",
        messages=[{"role": "user", "content": prompt_g7}]
    )
    follow_up_email = response_g7.choices[0].message.content
    print("--- DRAFT FOLLOW-UP EMAIL ---")
    print(follow_up_email)
except Exception as e:
    print(f"An error occurred: {e}")

最终产出,是一封基于深度会议分析的跟进邮件:

--- DRAFT FOLLOW-UP EMAIL ---
Subject: Follow-up: Decisions and next steps from today's sync

Hi Sarah, Tom, and Maria,

Thanks for the productive discussion earlier. Here's a quick recap of decisions and the action items for each of us.

Decisions
- Backend payment gateway integration is more complex than expected and will require an additional three days.
- This pushes the schedule by three days and compresses the final testing window, reducing our pre-launch buffer.
- Mitigation: Tom will work over the weekend to help us catch up.
- Front-end is ahead of schedule and has extra bandwidth to support.
- Launch/marketing plan will shift to a one-week invite-only soft launch, followed by the larger day-one push.

Action items
- Tom:
  - Confirm weekend availability and share a brief plan (key milestones, dependencies, and any risks).
  - Proceed with the gateway integration and coordinate early integration testing with Front-end and QA.
  - Provide short daily progress updates and flag blockers immediately.

- Sarah:
  - Update the project timeline to reflect the three-day shift and the compressed QA window.
  - Coordinate with QA on a risk-based test plan that fits the shortened testing period.
  - Align with Marketing/Product on the invite-only soft launch scope, success metrics, and comms; circulate the plan to the team.

- Maria:
  - Reallocate Front-end bandwidth to support the backend integration (payment UI hooks, error handling, instrumentation).
  - Partner with Tom on mocks/stubs as needed to unblock early integration and QA.
  - Ensure front-end readiness for the soft launch (feature flags/toggles, tracking) and share any gaps.

Please reply to confirm your action items and note any constraints or support you need. I'm happy to set up a brief daily check-in while we work through this; propose a time if you have a preference.

Thanks all, and appreciate the quick coordination.

Best,
[Your Name]

这个最终产出很好地展示了上下文链式的全部威力:
这封邮件读起来,就像是一个认真负责的项目经理写出来的。
工作流并没有停在“抽象洞见”或者“零散要点列表”上,而是产出了真正可用于沟通的专业文稿

AI 在这里不仅总结了会议内容,还把它转化成一种具备以下特点的格式:

  • 清晰记录决策:确保对“到底达成了哪些共识”没有歧义
  • 明确责任归属:每项任务都绑定到具体负责人
  • 设定预期:包括时间、后续步骤以及责任机制
  • 降低后续沟通成本:这封草稿已经足够专业,人类只需略作修改甚至可以直接发送

在这个节点上,LLM 不再只是一个“记录员(note-taker)”,而是变成了一个创意合作者(creative partner) ——这正是我们在本章开头所强调的。
在这个用例中,我们获得的不只是一份总结,而是亲眼见证了如何与 AI 一起“思考”
人类始终处于流程的中心位置,并可以为会议、邮件处理、报表、乃至任何你能想到的场景,设计出一整套可复用的上下文链式模板。
用得好时,上下文链式可以显著提升团队、公司和客户的运转方式。

总结(Summary)

本章介绍了“上下文工程(context engineering) ”这一新兴技能——它的目标是把 LLM 打造成可靠的、以目标为导向的系统
我们不再依赖无结构的 prompt,而是通过工程化信息环境来获得控制力,最终以“语义蓝图(semantic blueprint) ”这种最精确的指令形式收束。

我们通过一个五层演进过程来追踪这种变化:

  • 从完全无上下文的提示(零上下文),只得到模板化输出;
  • 到线性上下文;
  • 再到目标导向的上下文;
  • 然后是基于角色的上下文;
  • 最终到达可精确控制的语义蓝图。

每一层都证明了一点:更结构化的输入,会带来更好的结果

为了把这种方法形式化,我们引入了 SRL(语义角色标注)
它把句子拆分为谓词(predicate)、施事(agent)、受事(patient)和各种修饰语。
我们还通过一个 Python 可视化工具,把这些角色呈现为一张语义树(stemma)图。

最后,我们在一个会议分析用例中应用了这些技能:
通过上下文链式,把一份原始的会议记录,转化为可执行的结果(actionable outcomes)
整个过程一步步:

  • 剔除噪音
  • 找出新的进展
  • 挖掘隐含动态
  • 生成结构化摘要
  • 再到明确的跟进行动(邮件)

SRL 和上下文链式结合在一起,分别提供了:

  • 理论层面的框架(如何理解语义结构),
  • 与实践层面的工作流(如何在真实任务中运用这些结构),

共同帮助我们迈出“超越单纯 prompt”这一步

在这一切的基础上,我们已经准备好在下一章中继续前进:
开始为多智能体系统设计“具备自主能力的上下文(agentic contexts)