LangChain 如何构建付费媒体智能体
How we built LangChain's Paid Media Agent
LangChain 公开其付费媒体智能体的构建方法,该智能体运行在 Slack 中,每周汇总广告平台与仓库数据并生成报告,付费媒体在六个月内从贡献 0 提升到营销管道的 20%,单条合格线索成本在 6 月至 8 月下降 30%。
LangChain 公开付费媒体智能体的完整工程细节,包括上下文分层、工具按需发现和子智能体隔离,可作为自建长时运行智能体的参考。
在前三年里,LangChain 的销售管道主要依靠开源、内容、YouTube、社区和会议等有机增长方式,由这些因素驱动。一月,我们希望启动付费广告计划,以连接那些我们无法通过有机方式触达的潜在客户,例如新地区的客户和企业决策者。
我们希望在六个月内从主要依靠有机增长的引擎扩展到五个付费渠道。这对我们的小型营销团队提出了新的挑战。我们必须跟踪跨渠道的新活动启动、不同的创意和定位实验,以及不断增长的性能数据,以了解和采取行动。
为了扩展和优化,我们有一些技术障碍需要克服。每个广告平台都有自己的数据模式,这使得跨渠道的性能难以协调。活动参数也无法直接映射到我们最终关心的结果,例如销售咨询、注册或内容下载。随着公司产品发布节奏的加快和活动数量的增加,跟踪正在运行的活动、哪些活动有效以及下一步要尝试什么变得越来越难以手动管理。
我们开始构建一个能够帮助管理这种复杂性的代理。它将跟踪新产品公告、起草活动、添加关键词、测试变体,并将建议的实验展示给团队以供批准。随着时间的推移,它将作为一个持续学习的循环运行:分析性能、做出改变、观察结果、捕获所学内容,并将这些见解应用于未来的活动。我们的目标是提高营销团队的生产力,同时不断改进活动性能。
在这篇文章中,您将了解我们的付费媒体代理如何工作,它如何支持营销团队,以及我们在构建它的过程中学到的关于代理工程的知识。
我们已经 开源了我们的付费媒体代理,您可以将其作为自己项目的起点。您还可以观看 GTM Engineering Live: 我们如何构建付费媒体代理 的录像,在那里我们展示了代理、回顾了代码和设计决策,并回答了将这些模式应用于您自己的代理的问题。
主要成果
- 在六个月内,付费媒体从驱动 0% 到 20% 的营销管道。
- 从六月到八月,每条合格线索的成本(CPL)降低了 30%,而月度支出增加了约 60%。在领英上,我们最大的社交渠道,CPL 比一月份低了 40%。
- 通过将分析和报告内部化而不是依赖代理,我们每月节省了约 5K 美元。
- 我们还通过将计算移入代码并删除不必要的模型调用来优化代理本身,使早期的报告工作流成本降低了 40 倍,速度提高了 13 倍,运行时间从 18 分钟降至 85 秒。
我们构建的内容
付费媒体代理是一个长期运行的代理,它存在于 Slack 中。每周一,它将广告平台数据与我们的仓库中的线索和管道数据结合起来。它为每个平台发布摘要和带有品牌标志的 PDF,解释发生了什么变化、为什么变化以及团队下一步应该做什么。
团队可以在一个线程中标记它,以询问关于活动、成本或管道的后续问题。它还可以根据我们的剧本和编码的判断提出新的关键词、定位更改、广告文案或新的搜索活动。

我们构建它的方法
我们围绕一个简单的原则构建这个代理:编码代理是一个知识工作者。
知识工作通常涉及读取文件、转换信息、运行分析以及记录内容。编码代理也用文件和 shell 完成这些任务。
我们将代理视为新的付费媒体分析师。我们给它提供了电脑、完成工作所需的软件、访问我们数据的方式以及关于我们业务运作的文档。

操作系统
我们使用 LangChain Deep Agents 作为代理的框架,这样我们就不必从头开始构建核心代理基础设施。 就像操作系统一样,Deep Agents 管理对文件、代码执行和工作内存的访问。它为模型提供规划工作的工具,将任务委派给子代理,并在任务变得更加复杂时管理上下文。这个基础是 代理框架。我们在其上叠加我们的付费媒体工具、技能和业务知识。
电脑
每次运行默认都有一个 LangSmith Sandbox。它是一个隔离的微型虚拟机,配备 32 GB 硬盘和用于运行命令的 shell。这个 沙盒 为代理提供了一个安全、隔离的环境,以便执行代码和处理文件,而不会影响其他运行或底层系统。
我们用它配备了 pandas 和 DuckDB 进行分析,openpyxl 用于电子表格,以及 WeasyPrint 和 Jinja2 用于生成报告。除了这些软件之外,还有它的工作数据和业务知识,存储在 Markdown 中,跨越六个技能和一个十九页的维基。
为了加快启动速度,我们将软件和业务维基烘焙成一个 快照,即沙盒从中启动的保存图像。这将平均启动时间缩短了 10 秒。
💡 不同的代理需要不同的电脑。 我们的内容生成代理的沙盒看起来更像一个视频编辑工作站,配备了无头浏览器、ffmpeg、媒体工具和品牌手册。一个财务代理可能需要 openpyxl 用于电子表格和 DuckDB 用于更复杂的数据处理。工作决定了你如何设计电脑。
提供正确的上下文
一旦代理有了电脑,下一个挑战就是给它提供正确的上下文。人类分析师需要理解他们的角色、他们使用的方法、他们为之工作的公司、当前正在发生的事情以及他们需要遵循的规则。
简单的方法是将所有这些信息都放在系统提示中。然而,这会导致一个过长、在每次运行中携带成本高昂且可能过时的提示。
更好地思考这个问题的方法是将上下文窗口视为瓶颈,而不是模型。许多明显的推理失败实际上是上下文失败。要么模型缺少正确的信息,要么太多不相关的信息在争夺它的注意力。
我们不将提示视为知识存在的场所,而是将其视为一张地图。知识存在于具有可预测位置的 结构化文件中,代理仅加载执行当前任务所需的上下文。

💡 你设计代理的工作空间需要与你给它的工具一样深思熟虑。 我们发现代理可以通过组合其桌面上的现有内容来回答我们从未为其构建明确工作流程的问题。它有一个剧本来指导调查,有活动数据可以处理,以及库来分析这些数据。设计这个工作空间成为设计代理本身的一部分。
我们将上下文分为五个层次,并在下方逐一描述(按每个层次变化的快慢排序):
- 系统提示:定义代理的角色和导航。我们的提示从一个句子的代理角色描述开始,然后是三个简短的章节:如何操作、数字来源以及如何展示结果。其他所有内容都是代理的指引,例如,剧本在这里,维基在那里,先阅读索引。提示告诉代理它需要什么以及在哪里找到。
- 技能:六组指令,在运行时逐步披露。代理最初只能看到每个标题和描述。
- 维基:十九页解释我们的漏斗如何工作,每个活动旨在完成什么,哪个数据源拥有哪个数字,以及团队做出的决策和原因。
- 实时工具:支出、设置和管道每天都会变化,所以代理在请求时获取它们。我们有218次这样的调用。更多关于我们如何防止上下文膨胀的信息将在下面讨论。
- 确定性代码:我们使用代码来处理任何应该一致和可重复的内容,包括计算、日期窗口、账户匹配和硬性安全措施。例如,一条规则阻止代理在坏的一周后切断顶级管道驱动器,该规则在代码中强制执行,因此模型无法覆盖它。最难画的是技能和维基之间的界限。一个技能解释如何完成工作:读取数据、运行数字、撰写报告、准备变更,并应用剧本来解释付费媒体表现。它不包含我们活动任何特定的内容。

维基是LangChain所有特定的内容:哪个活动用于提高认知,哪个应该推动演示请求,我们七月的决定,以及原因。
💡 技能应该在另一家公司‘工作’,而维基不应该。换句话说,技能捕获可重用的工作方式,而维基包含技能运行所需的特定公司上下文。
这遵循了Karpathy的LLM维基笔记和我们自己的维基记忆的模式。
统一代理架构
我们最初构建了两个代理图,因为用户体验看起来不同:
- 每周报告代理是计划性和工件密集型的。它使用深度代理、沙盒、大型模型和PDF生成。
- Slack需要在几秒钟内提供答案,因此它使用一个较轻的循环和一个较便宜的模型,使用Google Ads和仓库工具,没有沙盒,并且只有只读访问权限。
这种分裂只持续了五周。每个新功能都必须实现两次。功能在Slack和报告中到达的时间不同。Slack无法处理附件,因为它没有沙盒,并且它无法在周一报告中回答后续问题,因为那些PDF来自另一个图。
错误在于将它们视为两个产品。它们是进入同一分析的同一入口,由相同的维基、技能、工具和源规则支持。我们改为为每个请求隔离状态和能力。每个线程都有自己的沙盒和检查点,每个运行都只看到它需要的工具。
现在只有一个图,为每个请求都实例化一个新的:
- Slack提及和周一的计划任务以不同的运行模式进入。
- 计划运行看到一个单一的工具,task(),它委托给每个平台的一个子代理。
- Slack得到一套更广泛的读取、仓库和活动操作工具。

它是一个具有不同能力配置的相同运行时,托管在 LangSmith 部署 上,该部署负责托管、扩展和计划运行。并且由于 Slack 现在共享相同的沙盒架构,代理也可以打开报告 PDF 并在产生它的线程中回答后续问题。
💡 要点:为每个入口点使用一个具有能力配置的运行时。同一个工厂可以给不同用户不同的技能和权限。

关键技术教训
让代理投入工作教会了我们关于如何正确获取数字、回答我们没有预料到的问题,以及将分析转化为行动的五个教训。
1. 使用模型进行判断,而不是计算
我们每周分析的第一个版本要求模型做所有事情。我们将每个活动行、关键词、管道记录和着陆页检查加载到上下文中,然后要求它计算支出、周同比变化、分类活动性能并撰写报告。
它有效,但效率低下。在我们的冻结测试集中,单个报告处理了大约 390 万个输入标记,因为模型必须读取所有这些原始数据并反复自行进行计算。这使得每次运行更慢更昂贵,耗时 1,112 秒,成本超过 3 美元。它还使结果更难信任,因为模型负责每次重新计算底层数字。
我们发现代码更适合确定性工作。现在 Python 获取数据、对齐日期窗口、计算总计和比较、应用固定规则,并将一组紧凑的结果写入沙盒。然后模型专注于需要判断的工作:连接证据、解释可能的原因、评估活动与其目标,并建议下一步该做什么。
2. 为每个指标定义一个真实来源
我们有六个具有不同 ID、转化定义、归因窗口和活动层级的平台。试图将所有内容规范化为一个完美的模式会增加复杂性,但不一定能使数据更可信。
相反,我们定义了每个类型指标应该信任哪个系统。广告平台是媒体活动(如支出、展示次数和点击次数)的真实来源。一旦有人转化,我们依赖我们的仓库来获取下游结果,如潜在客户、机会和管道。
当一些 Google 视频活动无法干净地映射到我们的仓库时,我们了解了这一点的重要性。我们的仓库使用关键词来连接活动数据,但视频活动并不总是有关键词。结果,尽管 Google 本身有正确的支出数据,但我们仓库中约有 10% 的 Google 支出丢失了。Meta 有相反的限制:它告诉我们广告产生了转化,但我们的仓库更擅长告诉我们转化实际上是什么,例如“联系销售”请求与“注册”。这些例子加强了我们应该不期望一个系统对每个指标都有最佳答案的认识。
我们将这些真实来源规则编码到代理中。它们存在于维基中,我们移除会让代理查询给定指标的错误系统的工具。有了真实来源边界、转化映射和活动层级定义,代理可以在不同平台之间工作,而无需一个完全规范化的模式。
当数据无法可靠地连接时,代理不会尝试填补空白。它保留了这些限制,并在其答案中包含相关的来源、日期窗口和归因模型,以便团队能够了解每个数字是如何得出的。
💡 要点:在代理能够在系统中工作时,您不需要一个完美的数据模型。更重要的是定义每个指标哪个来源是权威的,明确这些规则,并在底层数据无法干净地协调时保留不确定性。
3. 让代理发现工具,而不是一开始就加载所有工具
回答像“我们为广告支出获得了哪个管道?”这样的问题需要访问两个系统。广告平台提供支出和点击,而我们的 BigQuery 仓库将活动、网站转化与合格线索、Salesforce 机会和管道连接起来。
我们希望代理能够在两个系统之间工作,而无需加载数百个工具定义或为每个问题编写一个新工具。
Pipeboard 的 MCP 暴露了 200 多个广告平台工具。在 6 月,即使是我们较小的只读目录也需要 38,000 个标记,才能在代理读取用户的问题之前加载可用工具的名称、描述和参数。其中大部分上下文对任何单个请求都不相关。
我们的仓库有一个相关的问题。我们为像按活动管道或按广告组转化这样的常见问题构建了固定查询。但是,每种新的数据分组方式,例如按单个销售机会的管道,都需要另一个专用工具。
我们通过给代理一个用于查找所需内容的简单界面来解决这两个问题。
Pipeboard 的目录位于三个工具后面:
- 搜索:根据问题查找最多八个工具。
- 读取:仅加载选定工具的完整架构。
- 运行:通过我们的服务器执行该工具。活动写入使用单独的审批路径。

对于仓库,我们添加了两个灵活的工具:
- 描述可用的表和字段。
- 运行分析查询。
代理可以检查架构并组合出问题所需的查询,而不是依赖于每个可能的分组都有一个预构建的工具。
目录将第一个成本降低到大约 12,000 个标记。在我们的比较中,它比加载每个架构同时保持相同的判断质量便宜 4 倍。从那时起,目录几乎增加了两倍,而其上下文成本大致保持一致。
我们测试了固定仓库工具、查询界面以及两者结合的 60 次实时运行。固定工具适用于常规问题,但正确报告了更深层次的问题为不支持。两个带有查询界面的版本回答了所有分析性问题。
我们保留了两种方法。固定工具为常见问题提供了快速路径,而查询界面处理了我们未预料到的问题。
💡 要点:给代理一种按需查找和查询功能的方法,而不是一开始就将每个工具放入上下文。
4. 明确设计隔离
一旦我们转向共享运行时,我们又面临另一个挑战:代理如何分析五个平台,而无需将每个平台的数据都放入一个上下文窗口?
我们在实时数据上测试了三种架构:
- 每个平台一个隔离运行。
- 一个代理处理每个平台。
- 一个父代理委托给每个平台一个子代理。
独立运行是最简单的架构,但在实际工作流程中表现最差。每个运行只涉及一个平台,因此系统产生了多个 Slack 消息,并难以跨渠道整合性能。
两种整合方法都产生了单一输出,并实现了跨平台整合。我们最终选择了父节点加子代理的架构,因为它在保持父节点上下文较小的情况下,为每个平台提供了自己的上下文窗口,用于平台特定数据和注意事项。
但独立的上下文窗口并没有自动给我们提供完全隔离。我们仍然需要设计它。
例如:
- 一个平台可能会意外抑制另一个平台。两个子代理向同一位置编写报告,并共享相同的“完成”标志。一旦第一个完成,第二个可能会将该状态误认为是自己的,并在不生成报告的情况下停止。我们通过为每个平台提供自己的报告位置和完成状态来解决这个问题。
- 一个子代理可能会试图验证自己的工作而卡住。当子代理无法确定其 PDF 是否渲染时,它会不断检查文件,消耗大量令牌,并最终尝试从头开始构建 PDF。现在子代理只有三个工具:读取上下文、计算和渲染。如果渲染成功,工作就完成了。
一个子代理为你提供了一个独立的上下文窗口。隔离模型的其余部分则取决于你。你仍然需要定义它可以使用哪些工具、可以访问哪些文件和状态、必须返回什么内容以及如何处理失败。
5. 给代理提供从分析到行动的路径
一个只分析性能的代理最终是一个更好的仪表板。我们希望代理能帮助团队根据其发现采取行动。
它可以直接在 Slack 中提出更改,例如添加关键词、更新地理定位或创建新的搜索活动。
给代理采取行动的能力引入了新的要求:权限。
付费媒体以外的团队可以使用代理询问活动性能和管道的问题,但只有指定的团队成员才能编辑或批准活动更改。服务器在接受任何操作之前会检查 Slack 用户 ID。来自其他任何人的请求都会被阻止,提议将保持待处理状态。
每个提议的更改都会出现在使用 Block Kit 构建的 Slack 审批卡片中。授权审阅者可以比较当前值和提议值、进行编辑并批准最终计划。然后代码应用批准的更改并检查广告平台以确认其成功。

这为我们提供了一种有用的职责分离。代理可以分析性能并建议一个行动,但人类控制该行动是否实际被采取。
💡 要点:闭环需要不仅仅是写入权限。给代理一个清晰的行动路径,内置权限、审批和验证。
6. 使界面与工作相匹配
Slack 作为第一个界面效果很好,因为审批卡片可以与导致它的分析和讨论保存在同一个线程中。跨团队的成员可以提问并发表意见,而活动所有者仍然控制实际应用的更改。
这种方法最适合相对集中的决策。随着代理开始处理更复杂的工作,例如具有许多广告组和创意的活动、批量编辑或需要多轮修订的计划,Slack 作为主要工作空间变得更加难以使用。
我们将那些更复杂的流程迁移到一个以代理为中心的专用界面中,同时保留 Slack 作为提出问题、查看建议和批准更改的轻量级场所。更多内容将在未来的帖子中介绍。
我们将在下一个版本中引入的内容
我们希望有一个能够处理我们未曾预料到的问题、生成我们可以验证的数字并对其采取行动的代理。这些是我们将带到另一个代理的设计原则:
- 像雇佣一样为代理配备工具。 给它一个沙盒、有用的库、访问正确的数据和清晰的文档。一个设计良好的工作区让代理能够调查新问题,而无需为每个问题创建一个专用的工作流。
- 将可重用的指令与公司知识分开。 技能解释如何完成工作,维基解释业务,实时工具提供当前信息。保持这些层分离使得每一层更容易更新,而不会使系统提示词增长。
- 使用代码来处理应该可重复的工作。 计算、比较和硬规则应该放在代码中。然后模型可以专注于解释结果并决定它们的意义。
- 明确设计边界。 子代理仍然需要关于它们可以访问哪些工具、文件和状态的清晰规则,它们应该返回什么,以及如何处理失败。单独的上下文窗口只是隔离的一部分。
- 针对代理是否能够完成工作进行优化。 减少令牌、成本和延迟很重要,但如果这使得代理的能力降低,那就没有意义。我们发现,与完成率和答案质量一起评估这些指标更有用。
- 让实际使用情况向您展示集成需要改进的地方。 代理反复难以回答的问题揭示了需要更干净的连接、更好的定义或专用工具的地方。
接下来
今天,代理主要响应计划运行和团队的请求。我们希望它通过持续监控活动性能、突出显示值得关注的更改,并为团队审查提出新的实验和优化而变得更加主动。
更大的机遇是将这些学习成果连接到 GTM。活动参与可以告知销售如何跟进,而管道进展、销售对话和交易结果可以改进我们对理想客户的理解,并影响下一个活动。
随着时间的推移,我们希望我们的 GTM 代理为同一个共享知识和剧本做出贡献,以便一个组织部分学到的知识可以改进整个漏斗中的目标定位、信息传递和实验。
基于我们的学习成果
观看 GTM 工程直播:我们如何构建我们的付费媒体代理 的录像,在那里我们展示了代理,回顾了代码和设计决策,并回答了将这些模式应用到您自己的代理上的问题。
您也可以将这个付费媒体代理带到您自己的团队。我们已经 开源 了它,包括广告平台工具、付费媒体技能、示例维基、报告和批准工作流。连接您的帐户,给它您公司的上下文,并使用 管理深度代理 通过一条命令将其部署到 Slack。
来源: LangChain Blog · langchain.com