1. 广告传媒行业为什么需要专属AI Agent
广告传媒这个行当,表面上看是创意驱动,实际上真正干过的人都知道,日常工作中至少有六成时间花在了素材整理、方案拼装、客户需求对齐这些重复性劳动上。一个中等规模的广告公司,每周可能要处理上百个素材文件——图片、视频、文案、数据报表、竞品截图,散落在各个同事的硬盘、聊天记录和邮件附件里。等到要出方案的时候,设计师和策划就开始翻箱倒柜找素材,这种场景我相信每个从业者都经历过。
我所在的团队从去年开始尝试用AI Agent来解决这个问题。最初的想法很简单:能不能让机器帮我们把素材自动归类、打标签,然后在写方案的时候自动推荐相关案例和素材?试过一些现成的SaaS工具,要么功能太泛不贴合广告行业,要么数据要上传到第三方平台,客户素材的保密性没法保证。最后还是决定自己搭一套。
这篇文章就是把这套AI Agent从零搭建的过程完整拆解出来。核心目标有两个:第一,素材整理自动化,把杂乱的文件变成结构化、可检索的素材库;第二,方案辅助生成,根据客户需求和历史案例,自动生成方案框架和素材推荐。适合有一定开发基础的广告公司技术人员、独立开发者,或者想了解AI Agent在垂直行业怎么落地的朋友。我会把架构选型、核心代码、踩过的坑都讲清楚,你照着做基本能跑通。
2. 整体架构设计与技术选型思路
2.1 为什么选择Rust作为Agent的核心语言
现在市面上讲AI Agent开发,大部分教程都是用Python,生态成熟、库多、上手快。我一开始也是用Python写的原型,但跑到实际业务场景就遇到问题了。广告公司的素材整理任务往往是批量处理——一次导入几千个文件,涉及图片压缩、视频抽帧、文本提取、向量化存储,Python的GIL限制导致多线程跑不满CPU,处理速度上不去。而且部署到客户内网环境时,Python的依赖管理简直是一场灾难,不同版本的库冲突能把人逼疯。
后来我调研了基于Rust语言的AI Agent方案,发现几个明显优势。第一,Rust的异步运行时Tokio在处理大量IO密集型任务时性能非常稳,素材扫描和文件操作可以真正做到高并发。第二,Rust编译出来是单一二进制文件,部署到客户内网只需要拷贝一个可执行文件,不需要装运行时环境,这对广告公司这种IT运维能力普遍偏弱的场景太重要了。第三,Rust的类型系统在构建复杂Agent工作流时能提前发现很多逻辑错误,减少线上事故。
当然Rust也有代价,开发效率确实比Python低,生态库没那么丰富。我的做法是混合架构:核心调度层和文件处理层用Rust写,AI模型调用和向量检索用Python微服务,两者通过gRPC通信。这样既保证了性能,又利用了Python在AI领域的生态优势。
2.2 Agent的主流架构模式与我们的选择
当前AI Agent的主流架构大致分三类。第一类是ReAct模式,推理加行动循环,适合需要多步推理的任务。第二类是Plan-and-Execute模式,先制定计划再逐步执行,适合流程明确的长任务。第三类是Multi-Agent协作模式,多个Agent各司其职,适合复杂系统。
我们的素材整理与方案辅助场景,任务边界相对清晰:素材进来先分类,然后提取元数据,再向量化入库,最后根据查询返回结果。这更像是一条流水线,而不是需要反复推理的开放任务。所以最终选择了Plan-and-Execute模式作为主干,但在方案辅助环节嵌入了ReAct循环,让Agent能根据客户反馈动态调整推荐策略。
具体来说,整个系统分为四个核心模块:素材接入层负责监听文件夹变化和批量导入;处理管道层负责文件类型识别、内容提取、标签生成;存储检索层负责向量数据库和元数据库的管理;方案辅助层负责根据需求生成方案框架和素材推荐。每个模块都是一个独立的Agent,通过消息队列串联。
2.3 技术栈全景与依赖说明
把用到的技术栈列一下,方便你对照准备环境。核心语言是Rust 1.75以上版本,异步运行时用Tokio,Web框架用Axum,gRPC用Tonic。Python侧用FastAPI做微服务,向量化模型用Sentence-Transformers,向量数据库用Qdrant,元数据库用PostgreSQL。文件处理方面,图片用image-rs,视频抽帧用ffmpeg的Rust绑定,PDF解析用lopdf,Office文档用calamine和docx-rs。
这里重点说一下向量数据库的选择。试过Milvus、Weaviate和Qdrant,最后选Qdrant的原因是它单机部署简单,Rust原生支持好,过滤查询性能强。广告素材检索经常需要组合条件,比如“找所有汽车品牌的竖版视频,时长15秒以内”,Qdrant的payload过滤能直接搞定,不用在应用层做二次筛选。
注意:如果你团队没有Rust经验,不要硬上。可以先用Python把业务逻辑跑通,等性能瓶颈出现了再逐步替换核心模块。技术选型要为业务服务,不是为了炫技。
3. 素材整理Agent的核心实现细节
3.1 素材接入与文件类型识别
素材接入层是整个系统的入口,设计目标是“无感接入”。广告公司的同事不需要改变工作习惯,只要把文件丢进指定的共享文件夹,Agent会自动扫描并处理。我们用notify库监听文件系统事件,同时每隔十分钟做一次全量扫描兜底,防止事件丢失。
文件类型识别不能只看扩展名,很多设计师导出的文件扩展名是乱的。我们的策略是三级识别:先看扩展名,再用magic number检测文件头,最后尝试用对应的解析库打开。比如一个文件扩展名是.jpg但实际是PNG,magic number能识别出来;如果扩展名和文件头都不可靠,就尝试用图片解码库打开,能打开就按图片处理。
// 文件类型识别的核心逻辑示意 fn detect_file_type(path: &Path) -> FileType { // 第一级:扩展名 if let Some(ext) = path.extension() { match ext.to_str().unwrap_or("").to_lowercase().as_str() { "jpg" | "jpeg" | "png" | "gif" | "webp" => return FileType::Image, "mp4" | "mov" | "avi" | "mkv" => return FileType::Video, "pdf" => return FileType::Pdf, "doc" | "docx" => return FileType::Word, "xls" | "xlsx" => return FileType::Excel, "ppt" | "pptx" => return FileType::Ppt, _ => {} } } // 第二级:magic number if let Ok(kind) = infer::get_from_path(path) { return map_mime_to_type(kind.mime_type()); } // 第三级:尝试打开 if image::open(path).is_ok() { return FileType::Image; } FileType::Unknown }这个逻辑看起来简单,但实际跑起来会发现很多边界情况。比如设计师发来的PSD文件,magic number识别为图片但实际包含多个图层;再比如客户给的PPT里嵌了视频,需要递归提取。这些都是在实际使用中逐步补上的。
3.2 内容提取与元数据生成
文件识别完之后,进入内容提取阶段。不同类型的素材提取策略完全不同。图片提取EXIF信息、主色调、尺寸、是否含文字;视频提取时长、分辨率、关键帧、音频转文字;文档提取正文、标题、作者、修改时间。这些信息构成了素材的基础元数据。
主色调提取有个小技巧。直接用K-means聚类计算量大,而且对渐变图片效果不好。我们改用颜色直方图加峰值检测,先把图片缩放到100x100,统计HSV空间的直方图,取前三个峰值作为主色调。实测下来速度快了十倍,效果对广告素材来说完全够用。
视频关键帧提取用ffmpeg的select滤镜,按场景变化自动抽帧。这里有个参数很关键:场景变化阈值。设太低会抽出大量相似帧,设太高会漏掉重要画面。我们试了多个值,最后定在0.3,对广告视频来说比较平衡。抽出来的关键帧再走图片处理流程,生成缩略图和特征向量。
文本提取方面,PDF用lopdf,Word用docx-rs,Excel用calamine。这里踩过一个坑:很多客户给的PDF是扫描件,直接提取文本是空的。后来加了一个判断,如果提取出的文本长度小于50个字符,就调用OCR接口重新识别。OCR我们用的是PaddleOCR的Python服务,通过gRPC调用。
3.3 自动打标签与分类体系设计
元数据生成之后,下一步是打标签。标签体系的设计直接决定了后续检索的准确性。我们参考了广告行业的常用分类维度,设计了三级标签体系。一级标签是素材类型,比如图片、视频、文案、数据。二级标签是应用场景,比如品牌宣传、产品展示、活动推广、用户见证。三级标签是具体属性,比如色调、风格、行业、情绪。
自动打标签用了两种方法结合。一种是基于规则的,比如检测到图片中有大量蓝色且构图对称,就打上“科技感”“商务”标签。另一种是基于模型的,用CLIP模型计算图片和预设标签文本的相似度,取Top3作为自动标签。两种方法的结果合并去重,再让运营同事在管理后台做最终确认。
这里要强调一点:全自动打标签在广告场景下不够可靠。广告素材的语义非常微妙,同一个画面在不同客户语境下含义可能完全相反。所以我们的设计是“AI预标注+人工确认”,AI负责把80%的明显标签打上,人工只需要处理剩下的20%和纠错。这样效率提升明显,又不会因为误标导致方案推荐出错。
3.4 向量化存储与检索优化
所有素材处理完之后,需要向量化入库。文本用Sentence-Transformers生成768维向量,图片用CLIP生成512维向量,视频用关键帧向量的平均值。Qdrant支持多向量存储,我们把文本向量和图片向量存在同一个point的不同vector字段里,检索时可以指定用哪个向量。
检索优化方面,有几个参数需要调。HNSW的m参数控制图的连接数,设太大会增加内存占用,设太小会影响召回率。我们实测m=16在百万级素材库下表现最好。ef_construct控制建索引时的搜索深度,设成200能在建索引速度和索引质量之间取得平衡。查询时的ef参数可以动态调整,对精度要求高的场景设大一些,对速度要求高的场景设小一些。
// Qdrant检索的核心参数配置 let search_result = client .search_points(&SearchPoints { collection_name: "ad_materials".to_string(), vector: query_vector, limit: 20, with_payload: Some(true.into()), params: Some(SearchParams { hnsw_ef: Some(128), exact: false, ..Default::default() }), filter: Some(Filter { must: vec![ Condition::matches("type", "video".to_string()), Condition::range("duration", Some(0.0), Some(15.0)), ], ..Default::default() }), ..Default::default() }) .await?;过滤条件用Qdrant的原生payload过滤,比在应用层筛选快很多。特别是组合条件查询,比如“汽车行业+竖版+15秒以内+暖色调”,Qdrant能在毫秒级返回结果。
4. 方案辅助Agent的工作流拆解
4.1 需求理解与方案框架生成
方案辅助Agent的输入是客户需求,可能是一段文字描述,也可能是一份招标文档。第一步是需求理解,把非结构化的需求转成结构化的任务清单。我们用了一个微调过的LLM来做这件事,提示词里定义了广告方案的标准要素:目标受众、核心信息、传播渠道、预算范围、时间节点、创意方向。
需求理解完之后,Agent会生成一个方案框架。这个框架不是凭空生成的,而是从历史方案库中检索相似案例,提取它们的结构作为模板。比如客户要做一个新车上市的整合营销方案,Agent会找到过去三年汽车行业上市方案的共同结构:市场分析、竞品分析、目标人群、核心创意、媒介策略、执行排期、预算分配、效果预估。然后根据当前需求填充具体内容。
这里有个关键设计:方案框架生成不是一步到位的,而是分步骤让用户确认。第一步确认需求理解是否正确,第二步确认框架结构是否合理,第三步才生成详细内容。这样避免了Agent跑偏之后用户要全部重来的尴尬。
4.2 素材智能推荐与匹配逻辑
方案框架确定之后,Agent会根据每个章节的内容自动推荐素材。推荐逻辑是混合检索:先用关键词做全文检索,再用向量做语义检索,最后用规则做业务过滤。三路结果加权融合,权重分别是0.3、0.5、0.2。
举个例子,方案里写到“目标人群是25-35岁女性,注重生活品质”,Agent会提取关键词“女性”“生活品质”“25-35岁”,在素材库中检索。向量检索会找到画面温馨、色调柔和、有女性形象的素材;关键词检索会找到标签里带“女性”“生活”的素材;规则过滤会排除掉分辨率太低、有水印、版权不明的素材。最后按综合得分排序,推荐前20个给策划同事。
推荐结果不是直接插入方案,而是以侧边栏的形式展示,策划可以拖拽使用。这个交互设计很重要,AI推荐只是辅助,最终决策权在人手里。我们统计过,用了推荐功能之后,策划找素材的时间从平均40分钟降到了8分钟左右。
4.3 方案文本生成与人工编辑协同
方案文本生成用的是模板加LLM填充的方式。模板定义了每个章节的写作框架和语气风格,LLM负责根据素材和需求填充具体内容。这里有个细节:不同客户的方案风格差异很大,有的喜欢数据驱动,有的喜欢故事叙述。我们在模板里加了风格参数,根据客户历史方案自动判断风格倾向。
生成出来的文本会进入一个协同编辑界面,策划可以直接修改。修改的内容会被记录下来,作为后续模型优化的反馈数据。比如策划把“提升品牌知名度”改成了“强化品牌在年轻群体中的心智占位”,这个修改会被标注为“更专业的表达”,下次生成时优先使用类似表述。
实操心得:方案生成的质量很大程度上取决于提示词的设计。我们的提示词里包含了角色定义、输出格式、语气要求、禁忌词汇四个部分。禁忌词汇特别重要,比如不能出现“最好”“第一”“绝对”这类广告法敏感词,Agent生成时会自动规避。
4.4 多轮对话与方案迭代机制
实际工作中,方案很少一次成型。客户会提修改意见,内部评审会有调整,所以Agent需要支持多轮迭代。我们的设计是每次修改都生成一个新版本,版本之间可以对比差异。Agent会记录每次修改的原因和内容,形成方案的演进历史。
多轮对话的实现用了ReAct模式。用户提出修改意见后,Agent先推理这个意见涉及哪些章节和素材,然后执行修改动作,最后检查修改后的方案是否连贯。如果发现修改导致前后矛盾,会主动提醒用户。比如用户要求把目标人群从“年轻女性”改成“商务男性”,Agent会检查方案中所有涉及人群描述的段落,提示哪些地方需要同步修改。
这个机制在实际使用中帮了大忙。有一次策划只改了目标人群,忘了改媒介策略里的“小红书投放”,Agent自动检测到并提醒,避免了方案内部不一致的尴尬。
5. 部署上线与性能调优实录
5.1 内网部署方案与依赖打包
广告公司的IT环境通常比较封闭,很多客户要求系统部署在内网,不能访问外网。这对依赖在线API的方案是致命的。我们的应对策略是全部本地化:LLM用开源模型本地部署,向量化模型用Sentence-Transformers本地推理,OCR用PaddleOCR本地服务。整个系统打包成一个Docker Compose文件,客户内网只需要装Docker就能一键启动。
Rust编译的二进制文件在这里体现了优势。核心Agent服务编译出来只有20MB左右,拷贝到内网服务器直接运行,不需要装Rust环境。Python微服务打包成Docker镜像,依赖全部固化在镜像里。数据库用PostgreSQL和Qdrant的官方镜像,数据卷挂载到本地目录。
部署脚本我写了一个install.sh,自动检测环境、拉取镜像、初始化数据库、导入预置标签体系。客户的技术人员只需要执行一个命令,等十分钟就能看到系统跑起来。这个体验对非技术背景的广告公司来说非常重要,部署门槛直接决定了系统能不能推下去。
5.2 并发处理与资源占用优化
素材批量导入是最吃资源的场景。一次导入5000个文件,如果串行处理可能要几个小时。我们的优化策略是分级并发:文件扫描用Tokio的异步IO,并发数设成CPU核数的两倍;内容提取用Rayon的并行迭代,CPU密集型任务跑满所有核心;向量化用批处理,每批32个样本,平衡内存占用和推理速度。
内存占用方面,最大的坑是图片处理。高分辨率图片解码后占用内存很大,如果同时处理太多会导致OOM。我们加了一个信号量控制并发解码数量,根据可用内存动态调整。实测在16GB内存的服务器上,同时处理8张4K图片比较稳。
GPU资源是可选的。如果服务器有GPU,向量化和LLM推理会快很多;没有GPU也能跑,只是速度慢一些。我们做了一个自动检测,有GPU就用GPU,没有就回退到CPU。这个设计让系统能适应不同客户的硬件条件。
5.3 日志监控与故障恢复
生产环境跑起来之后,监控比开发更重要。我们用了tracing库做结构化日志,每个请求都有trace_id,方便追踪完整链路。关键指标包括:素材处理成功率、平均处理耗时、向量检索延迟、LLM调用次数和token消耗。
故障恢复方面,素材处理管道设计成幂等的。每个文件处理前先检查是否已经处理过,处理过的直接跳过。如果处理中途失败,会记录失败原因并加入重试队列,最多重试三次。三次都失败的文件会进入死信队列,由人工介入处理。
注意:token消耗是容易被忽视的成本。LLM调用按token计费,方案生成场景下一次可能消耗几千token。我们加了一个token预算控制,每个方案生成任务有上限,超过就降级到模板填充模式,避免成本失控。
6. 常见问题排查与避坑指南
6.1 素材处理失败的典型原因
实际运行中,素材处理失败的原因五花八门。我整理了一个速查表,覆盖了90%以上的情况。
| 问题现象 | 可能原因 | 排查方法 | 解决方案 |
|---|---|---|---|
| 图片无法解码 | 文件损坏或格式特殊 | 用file命令查看文件头 | 跳过并记录,通知上传者 |
| 视频抽帧为空 | ffmpeg缺少编解码器 | 手动执行ffmpeg命令测试 | 安装完整版ffmpeg |
| PDF文本提取为空 | 扫描件无文本层 | 检查提取字符数 | 触发OCR流程 |
| 向量化超时 | 模型加载失败或GPU显存不足 | 查看服务日志 | 重启服务或降级到CPU |
| 检索结果不相关 | 标签体系不匹配 | 检查素材标签 | 调整标签体系或重新标注 |
| 方案生成中断 | LLM服务不可用 | 检查LLM服务健康状态 | 切换到备用模型或模板模式 |
这个表是我们运维半年积累下来的,基本上新同事遇到问题查这个表就能解决。其中最常见的是PDF扫描件问题,广告公司经常收到客户发来的扫描版合同或简报,一开始没做OCR导致这些文件在系统里是“空”的,后来加上OCR流程才解决。
6.2 向量检索精度不够的调优方法
向量检索精度不够是另一个高频问题。用户搜“温馨的家庭场景”,返回的却是“办公室会议”,这种语义偏差很让人头疼。排查思路分三步:先看向量化模型是否适合当前领域,再看检索参数是否合理,最后看素材标签是否准确。
向量化模型方面,通用的Sentence-Transformers在广告领域表现一般。我们后来用广告文案和素材描述数据做了微调,精度提升了大概15%。微调数据不需要太多,几千条标注数据就能有明显效果。
检索参数方面,HNSW的ef参数对精度影响最大。默认值128在大多数场景够用,但如果发现漏召回,可以调到256甚至512。代价是查询延迟增加,需要根据实际负载权衡。
标签准确性方面,如果素材标签本身是错的,向量检索再准也没用。我们定期做标签质量抽查,随机抽100个素材人工检查,发现错误率超过5%就触发重新标注流程。
6.3 方案生成内容不合规的预防
广告行业对内容合规要求极高,方案里出现违禁词可能导致客户被处罚。我们在Agent里加了三层防护。第一层是生成时的提示词约束,明确列出禁用词汇。第二层是生成后的正则检查,扫描所有输出文本。第三层是人工审核提醒,对高风险内容标黄提示。
违禁词库是动态更新的,我们维护了一个JSON文件,运营同事可以随时添加新发现的敏感词。Agent每次生成前会加载最新词库。这个机制运行以来,成功拦截了多次潜在违规,比如“最先进”“国家级”“独家”这类广告法禁止的表述。
实操心得:不要完全依赖AI做合规判断。我们的做法是AI初筛加人工复核,AI负责把明显有问题的标出来,人工负责判断边界情况。这样既提高了效率,又降低了风险。
6.4 系统扩展性与后续迭代方向
系统上线半年,素材库从最初的几千个增长到了十几万个,检索性能依然稳定。这得益于早期的架构设计:向量数据库和元数据库分离,检索走向量库,复杂查询走元数据库,两者通过ID关联。后续如果要扩展到百万级素材,只需要给Qdrant加节点做分片。
后续迭代方向有几个。一是多模态检索,支持用图片搜图片、用视频搜视频。二是自动方案评估,用模型对生成的方案打分,预测客户满意度。三是跨语言支持,广告公司经常服务国际客户,需要中英文素材统一检索。这些都在规划中,但优先级要看实际业务需求。
我个人在实际操作中的体会是,AI Agent在垂直行业的落地,技术只占三成,七成是对业务的理解。广告传媒这个行业,素材的语义、方案的风格、客户的偏好,这些隐性知识很难从公开数据中学到,必须深入业务一线去积累。我们团队的做法是每个开发人员每季度都要跟着策划同事做一次完整提案,从需求沟通到方案汇报全程参与。只有这样,才能让Agent真正理解广告行业的语言和逻辑。