首页 / 资讯中心 / 文章详情

营销技能库:用Function Calling让AI Agent按流程落地自动化

营销技能库:用Function Calling让AI Agent按流程落地自动化 ★ FEATURED ARTICLE
做营销自动化的朋友大概都有这种感觉市面上的 Agent 框架越来越多但真正拿到业务里跑起来总差那么一口气。差在哪不是模型不够聪明而是你没法让 Agent 按照营销的套路去干活——写文案不知道品牌调性做投放排期搞不清渠道规则分析竞品又抓不住重点。这些问题其实指向同一个需求我们需要给 AI 代理预置一套结构化的营销技能库把“该做什么、按什么顺序做、每一步用什么工具”全部固化下来。我最近重构的一版 Marketingskills 项目就是专门解决这个问题的。这套技能库本质上是一组可复用的工具、流程模板和校验规则配合主流 Agent 框架使用让模型在营销场景里不是自由发挥而是被“扶着走”。它适合三类人一是做营销自动化平台的技术同学想快速给系统加 Agent 能力二是懂业务又想折腾自动化的运营负责人需要一套能落地的方案三是对 Function Calling 和工具编排感兴趣的研究者。下面我把项目的设计思路、核心模块和实操过程完整拆开讲包括踩过的坑和排查经验希望能帮你少走几周弯路。1. 项目定位与整体设计思路1.1 为什么通用 Agent 框架不够用先聊一个很现实的问题很多人一开始直接用现成的 Agent 框架搭个对话机器人接上几个 API觉得万事大吉。但真到营销场景就露馅了。营销任务的特点是流程长、工具杂、约束多。你让 Agent 去写一篇新品推文模型可能写得不错但它知道要先去查产品资料库吗知道写完要按平台规范检查敏感词吗知道如果要配图得先去素材库搜版权可用的图片吗通用框架不会替你考虑这些它只会等用户一条条指令喂进来。我做 Marketingskills 的出发点就是把营销任务拆成“技能颗粒”每个技能解决一个明确动作再把这些技能按业务流程串成剧本。这样做的好处有三个第一模型不需要每次从零推理整个流程减少错误率第二技能可以单独测试、单独替换出问题能快速定位第三非技术人员也能通过配置文件理解和调整流程不用改代码。1.2 技能库的三种用户视角在设计技能库结构时我明确了三类使用角色这决定了数据模型的分层业务配置者通常是运营或市场人员他们关心“这个技能触发条件是什么参数怎么填”所以技能注册表要写得像一份产品说明书。系统集成者也就是开发同学他们关心“技能内部怎么实现、第三方 API 怎么封装”对应的是工具执行层。Agent 本身模型需要的是精炼的技能描述和参数 Schema它不关心内部实现只关心什么情况下调用什么技能、传什么参数。这三类视角对应到代码里就成了三层结构技能目录层、执行层、编排层。目录层定义技能的元信息和参数约束执行层是真正跑动作的代码编排层负责让 Agent 按需组合技能。这个分层思路是项目早期最大的设计决策后面所有模块都围绕它展开。1.3 技术栈选型经验关于技术栈我用了 Python Pydantic FastAPIAgent 运行时接了 OpenAI Function Calling 生态同时也兼容本地方案。选 Python 没什么悬念生态齐、团队熟、AI 相关库最全。Pydantic 是必须的因为技能参数的 Schema 定义直接关系到模型能否正确生成调用参数Pydantic 的强校验能在入口就拦住脏数据。FastAPI 用来暴露技能执行接口方便前后端分离也方便后续以微服务形态单独部署某个重技能。这里想强调一点不要一上来就追求自研 Agent 内核。我一开始也动过手写推理循环的念头后来发现那是浪费时间。现在的框架在“对话管理、多轮记忆、上下文裁剪”这些方面已经做得很好了我们的核心竞争力应该在营销技能本身。所以项目只保留了一个薄薄的调度层核心资产全部沉淀在技能定义和工具实现里。2. 技能库的核心模块拆解2.1 技能注册表一切从声明开始技能注册表是整个库的“户口本”每个技能必须在这里登记才可能被 Agent 发现。我参考了 OpenAPI 和 JSON Schema 的思路但做了简化因为 Agent 消费的是描述性文本和 JSON 参数约束不需要完整的接口规格。一个典型技能条目是这样的{ skill_id: social_post_generator, name: 社交媒体文案生成, version: 1.2.0, description: 根据产品信息和平台特点生成社交媒体发布文案支持多平台风格适配必选技能之一, tags: [content, social, copywriting], inputs: { product_id: { type: string, description: 产品ID用于获取产品详情, required: true }, platform: { type: string, enum: [wechat, xiaohongshu, weibo], description: 目标平台, required: true }, tone: { type: string, enum: [professional, playful, luxury], default: professional } }, outputs: { content: { type: string, description: 最终文案内容 }, suggested_hashtags: { type: array, items: { type: string } } }, execution: { type: local_function, function: execute_social_post_generator }, metrics: { latency_target_ms: 3000 } }有几个设计细节值得展开Description 不是给开发者看的是给模型看的。所以我刻意写成了“必选技能之一”这种带决策引导的话。为什么因为 Function Calling 时模型会根据描述判断该不该调用这个函数。描述太干巴巴比如“生成文案”模型就可能在高并发多技能场景下犹豫甚至选错。把触发条件、场景、输出结果都写清楚选召准确率会明显提升。Inputs 里的 enum 也很关键。营销场景里平台差异很大如果你不限定平台模型生成的文案可能充满“亲”“宝宝们”这种混搭风格。我试过放开自由输入的效果翻车率很高。限制枚举等于帮模型降低了选择维度输出质量可控得多。2.2 技能执行层工具函数与外部服务隔离技能注册表描述的只是“能力声明”真正跑活儿的是执行层。我把执行层分成两个子模块无状态工具函数和有状态服务客户端。无状态工具函数是纯函数输入参数返回结果比如“文本去敏感词”“关键词提取”“字数统计”。这些函数不依赖业务上下文好测试好复用是整个技能库的地基。有状态服务客户端则是对接外部系统的比如品牌素材库、订单系统、CRM。这些调用往往需要鉴权、限流、重试所以我单独封装了一个 ServiceClient 基类class ServiceClient: def __init__(self, config: ServiceConfig): self.timeout config.timeout self.retry_policy config.retry_policy self.session httpx.AsyncClient(timeoutconfig.timeout) async def call(self, endpoint: str, payload: dict): for attempt in range(self.retry_policy.max_retries 1): try: async with self.session.post(endpoint, jsonpayload) as resp: resp.raise_for_status() return await resp.json() except httpx.TimeoutException: if attempt self.retry_policy.max_retries: raise await asyncio.sleep(self.retry_policy.backoff * (2 ** attempt))为什么要隔离因为营销技能里很多操作有副作用比如“发送营销邮件”“创建广告活动”。这类动作不能像纯函数一样随意重试必须通过状态机和幂等键来保障。我踩过一次真实教训某个活动创建接口超时重试后产生了双倍邮件。后来所有带副作用的技能都强制要求传入幂等键并登记到 Redis 里做去重。2.3 编排层让 Agent 不迷路执行层有了技能但 Agent 怎么知道先用哪个后用哪个这就是编排层的职责。我采用了两种编排策略组合任务模板引导和运行时动态决策。任务模板引导类似于业务流程剧本适合那些流程固定的场景比如“新品上市营销活动”第一步查产品资料第二步生成多平台文案第三步做内容排期第四步创建投放任务。每一步引用哪个技能、参数从哪来、产出交给谁都在模板里定制。模型按引导走不用做太多判断。运行时动态决策则是给模型更多自由度适合写周报、做竞品亮点总结这类发散性任务。此时我不会指定固定技能路径而是提供一个技能子集让模型自己组合。实测下来动态决策的准确性受上下文长度影响很大所以我会在任务开始前把上下文里无关的历史内容裁剪掉只保留和本次任务相关的段落。这跟人做事一个道理信息越聚焦决策越稳。3. 关键实操流程复盘3.1 从零初始化技能库初始化技能库我建议按“最小闭环”原则来先跑通一个端到端核心链路再横向添加技能。我首先实现了内容生成链路因为它最直观、见效最快。步骤大概是建立技能目录注册 5 个核心技能产品信息查询、文案草稿生成、敏感词检测、平台风格适配、格式排版。每个技能先实现一个简陋版本保证链路能通不考虑性能优化。接入 OpenAI Function Calling构造一个测试助手模拟运营人员发指令逐项验证调用是否正常。把链路封装成 FastAPI 接口供前端页面调用。这个过程花了两三天瓶颈不在代码而在确定技能之间的数据流。比如文案草稿生成后敏感词检测返回的“命中词列表”怎么传给风格适配步骤我用一个统一的 Context 对象在步骤之间传递而不是用函数参数硬编码。好处是新增技能时不需要改既有函数签名扩展性大大提升。3.2 Function Calling 的具体接入方式这是整个项目最核心的技术环节我直接贴一段关键代码。接入时我给模型提供了两个技能函数query_product_info 和 generate_social_post模型需要根据用户消息选择合适的函数并生成参数。import json from openai import AsyncOpenAI client AsyncOpenAI(api_keyyour_api_key) SKILL_FUNCTIONS [ { type: function, function: { name: query_product_info, description: 根据产品ID查询产品详细信息包括规格、卖点、价格, parameters: { type: object, properties: { product_id: {type: string, description: 产品唯一标识} }, required: [product_id], additionalProperties: False } } }, { type: function, function: { name: generate_social_post, description: 基于产品信息和目标平台生成社媒文案, parameters: { type: object, properties: { product_name: {type: string, description: 产品名称}, selling_points: { type: array, items: {type: string}, description: 产品核心卖点列表 }, platform: {type: string, enum: [wechat, xiaohongshu, weibo]}, tone: {type: string, enum: [professional, playful], default: professional} }, required: [product_name, selling_points, platform], additionalProperties: False } } } ] async def handle_user_message(user_input: str): resp await client.responses.create( modelgpt-4.1-mini, inputuser_input, toolsSKILL_FUNCTIONS ) return resp注意几个容易踩的细节参数里一定开 additionalProperties: false不然模型偶尔会传一些别出心裁的字段后面 Pydantic 校验直接崩溃enum 里给到 3 个平台就够了给太多模型反而容易纠结description 要写“根据产品信息生成文案”而不是“生成文案”看起来差别不大实测对调用准确率影响明显。拿到模型返回的 tool_calls 后先查技能注册表确认技能存在再进入执行层运行from skills.registry import SKILL_REGISTRY from skills.executor import execute_skill if resp.output: for item in resp.output: if item.type function_call: skill_name item.name arguments json.loads(item.arguments) skill_def SKILL_REGISTRY.get(skill_name) if not skill_def: raise ValueError(funknown skill: {skill_name}) result await execute_skill(skill_name, arguments, contextcontext) # 将执行结果回传给模型进入下一轮推理这个循环就是 Agent 的基本骨架。实际项目里我在 execute_skill 内部加了日志记录、耗时统计和异常包装方便后面做复盘分析。3.3 技能执行与反馈采集链路技能跑通了但如果你不记录执行数据相当于闭着眼睛开车。这一版项目里我在执行层统一封装了一个带埋点的装饰器记录技能名、参数摘要、耗时、返回码、模型 token 消耗。这些数据有两个用途实时监控哪些技能调用失败率高哪些技能响应慢通过 Grafana 看板直接暴露。离线优化定期导出日志用 prompt 评估器给每一次调用打质量分并筛选出那些模型误调用的场景补充到技能描述的负面提示里。反馈链路非常重要因为营销技能库不是一次性建完就完事的它需要随着业务变化持续迭代。没有数据你根本不知道哪个技能该改、哪个技能该删。4. 典型场景的实战记录4.1 社媒内容自动生成场景这是我最先跑通的完整场景也最有代表性。业务诉求是运营人员输入一个产品 ID系统自动生成适配不同社交平台的发布文案并附带话题标签。执行链路分为五步调用 query_product_info 拿到产品名称、卖点、规格参数。调用 generate_social_post 根据产品信息和平台生成初稿。调用 sensitive_word_check 进行合规检查平台规则不同检查词库也不同。调用 style_adapter 根据平台特性调整表达风格比如某平台更喜欢强互动语气另一个平台更偏正式。调用 hashtag_suggester 提取关键词并生成标签列表。实测效果好于预期。原来人工写一条朋友圈文案加改稿平均要 20 分钟现在端到端大概 45 秒而且生成质量稳定在可发布水平。更重要的是业务人员可以在后台配置各平台偏好的风格模板不用改代码就能调优产出。不过也有一个坑当产品卖点很多时模型容易把全部卖点堆进文案读起来像说明书。后来我在 generate_social_post 的 description 里加了“选取 2 到 3 个核心卖点不要罗列所有参数”问题明显改善。这说明技能描述里写负面指令很有效。4.2 竞品信息收集与摘要场景这个场景很有意思它属于“半结构化信息获取”任务。我给 Agent 配了几个专用技能搜索竞品官网、抓取公开产品页、提取差异化描述、生成对比表。执行时模型先在搜索引擎列表页拿到一批链接再逐个调用 fetch_page 技能获取页面文本然后调用 extract_features 抽取结构化信息最后生成对比摘要。中间有个难点是网页内容很杂导航栏、广告、推荐模块会干扰信息抽取。我用 Readability 风格的正文提取算法做了一次预处理把页面噪音去掉再传给模型。这一步对摘要质量提升非常明显纯净文本投喂比直接塞整个 HTML 给模型要省 token也准确得多。这类场景我强烈建议把并发数控制在 3 到 5 之间别太快。抓取动作太频繁容易被目标站点限流而且一限流整批任务都崩完全得不偿失。4.3 投放计划配置与校验场景投放计划配置是比较敏感的场景因为它牵涉预算和外部投放平台的真实操作。这里我采用了“沙箱先行”策略所有投放任务先进入 pending 状态参数校验通过后再由运营人工确认执行。技能库提供了一套规则引擎检查日预算上限、定向人群规模合理性、文案素材是否齐备等约束。校验规则可以通过配置文件动态下发运营同学自己就能调整不用发版。比如预算上限默认是 5000 元活动期间可以在后台调高。这套设计避免了每次改动都要走开发流程也是技能库可维护性的核心体现。5. 常见问题与排查实录5.1 模型总是调用错技能这个现象在技能数量超过 15 个以后会越来越明显。排查思路是这样的先看执行日志确认模型实际调用的是哪个函数再把技能列表打印出来看 description 是不是存在语义相近的表述。比如“查询产品信息”和“获取产品详情”模型区分不开很正常。解决办法有两个方向一是把相似技能合并只保留一个带 mode 参数的高级技能二是在 description 里显著区分差异比如加“返回结构化 JSON 字段适合程序消费”和“生成人类可读的自然语言总结适合报告场景”。我两种方向都试过最终倾向合并技能因为技能数量少模型选择面小准确率自然高。5.2 参数生成不规则导致崩溃模型生成参数不规范的典型问题包括枚举值大小写不一致、日期格式混乱、字符串里混入多余字符。单靠 Pydantic 报错然后重试并不能根治因为整体重试要消耗 token响应还慢。我采用了一套修复管道对 enum 字段做标准化映射例如大小写归一化、“小red书”这类别名转成正式枚举值。对时间字段用 dateutil 做宽松解析解析不了就返回“无法排期”错误。对字符串字段做正则清理去掉控制字符和多余空格。这套修复管道不是让模型重算而是程序化纠正已知问题效率高。管道逻辑写在技能参数组装阶段对上层透明。5.3 外部 API 响应慢导致整个链路阻塞某个第三方素材接口偶尔响应超过 10 秒而 Agent 全链路等待导致用户体验很差。我的解决方案是给这类耗时技能设置独立超时并注册一个 mock 响应先返回给模型生成文案异步再去拉取真实素材等真实素材就绪后再触发二次质检。这种“先回复后校验”的机制很适合营销内容生成场景因为首屏响应直接影响编辑使用意愿。5.4 常见问题速查表问题现象可能原因快速解法模型反复调用同一技能技能 description 引导不足在描述中增加使用场景与负面指令参数 enum 经常非法枚举值过少或描述不明确增加 enum 标准化映射修复管道兜底链路响应超过 30 秒外部 API 慢且无超时隔离独立超时 异步任务 先返回 mock上下文里旧指令干扰新任务上下文未裁剪新任务开始时重置上下文仅保留必要段落技能执行成功但模型说没结果返回 payload 结构不清晰返回结果里附上简要人类可读摘要5.5 独家避坑技巧这里分享几个不太会被写在文档里的经验技能描述里可以写“不要做什么”这比只写“做什么”更管用。比如“生成文案时不要使用夸张促销词汇例如‘全网最低’”。模型对负面指令的理解比想象中好这能显著降低输出风险。Function Calling 的 temperature 建议调低我一般用 0.2 到 0.4。温度太高会让模型输出参数偏移太低又有些死板。这个范围是我在多个营销场景里测出来的平衡点。不要相信单次调用的输出。营销内容最终要经过第二道校验比如人工随机抽检或规则引擎的合规校验。技能库不是替代审核机制而是降低审核成本。6. 运营维护与后续扩展方向6.1 技能库的版本管理方法技能库和代码库一样需要版本管理。我用 semantic versioning主版本号变更代表技能接口不兼容次版本号是新增技能或参数补丁版本是描述文案调整或 bug 修复。上线技能前先在 staging 环境跑一遍烟雾测试确保技能注册、参数校验、执行链路全通。同时我会把技能目录的 JSON Schema 纳入 CI 校验任何新增技能必须通过格式检查才能合入主线。这样多人协作时不会出现字段拼错、参数类型不匹配的低级问题。6.2 权限与安全边界控制营销技能库会接触品牌素材、客户信息、投放预算安全设计不能省。我在执行层做了资源级 ACL每个技能声明需要的权限范围运行时校验请求者的角色。比如普通运营可以调用内容生成技能但创建广告活动、发送全员邮件这类高风险技能需要管理员审批。还有一点是防止提示注入。外部输入如果直接拼进系统指令攻击者可能诱导 Agent 执行非法操作。我的做法是外部输入统一通过 Sanitizer 处理系统指令和用户输入分属不同上下文块模型在系统层不会看到完整的外部原始文本只看到经过结构化抽取的字段。6.3 可以继续扩展的方向这套架构有明显的可扩展性。一是跨语言支持目前技能描述都是中文未来加英文和日语场景只需要改描述模板。二是技能市场机制把部分高频技能做成可配置模板不同业务团队复用。三是增强学习因子利用执行日志里的人工修正操作自动学习更优的技能编排路径。四是离线评估体系在数据集上批量回放历史对话量化每个技能对最终结果质量的贡献值而不是只看调用率。我在实际构建这套技能库的过程中最大的体会是AI Agent 能不能在营销场景落地不在于模型选多强也不在于框架多新而在于你是否把业务动作拆得足够细并且给模型画好了清晰的行为边界。技能库的本质不是代码仓库而是一份团队集体智慧的显性化表达。只要技能定义得好、数据回流得勤这套系统就会越用越顺手。上面这些经验是我踩了不少坑换来的希望对你有实际帮助。
阅读完成 · 觉得有帮助?
咨询建站