AI产品工程化实战:Harness管控与Skills封装落地指南
发布时间:2026/10/2 11:33:58 锦皓数字建站

1. 从“能跑通”到“能交付”AI产品研发的工程化困局做过AI产品的人大概都有这种体会Demo阶段一切都很美好模型效果惊艳交互流畅团队信心满满。可一旦进入真实业务场景问题就像潮水一样涌来——同一个Prompt在不同用户手里输出天差地别模型版本一升级整个链路崩掉多轮对话到第五轮就开始胡言乱语更别提并发上来之后的延迟飙升和成本失控。这不是某个团队的问题而是整个行业从“AI功能”走向“AI产品”时必然撞上的墙。我所在的团队在过去一年多时间里前后经历了三个AI产品的完整研发周期从智能客服到文档理解再到多模态内容生成踩过的坑几乎可以写一本错题集。直到我们把Harness工程管控和Skills技能封装这两套方法论真正落地之后才算是找到了从“能跑通”到“能交付”的系统性解法。这篇文章不聊虚的我会把我们在工程管控体系搭建、技能封装设计、规模化落地过程中积累的实操经验完整拆开包括具体的目录结构、配置参数、排查思路和踩坑记录。如果你正在带AI产品团队或者你是负责AI产品落地的工程师、产品经理正在被“模型效果不稳定”“迭代速度跟不上”“线上问题难复现”这些问题折磨那这篇内容应该能帮你少走不少弯路。核心关键词就两个Harness负责工程管控Skills负责能力封装两者配合起来才能让AI产品从手工作坊走向流水线生产。2. Harness工程管控体系给AI研发装上“控制面板”2.1 Harness到底管什么从Prompt到上线的全链路治理很多人第一次听到Harness这个词会以为它只是个测试工具或者监控面板。实际上在我们团队的实践中Harness承担的是一整套AI研发工程管控的职责它管的是从Prompt编写、模型调用、输出校验到线上监控的完整生命周期。你可以把它理解成AI产品的“操作系统”——所有跟模型交互的行为都要经过它所有跟业务逻辑相关的配置都由它统一管理。为什么需要这么一层因为AI产品的研发和传统软件有本质区别。传统软件的行为是确定的输入A必然得到B测试用例写死了就行。但AI产品的输出是概率性的同一个输入可能得到B、C、D三种结果而且模型版本、温度参数、上下文长度任何一个变了输出分布就会漂移。没有Harness这层管控你的研发过程就是黑盒出了问题只能靠猜。我们最初的做法是把Prompt硬编码在业务代码里模型调用散落在各个Service中。结果就是改一个Prompt要重新发版换一个模型要改十几个文件线上出了badcase根本不知道当时用的哪个版本的Prompt。后来引入Harness之后我们把所有跟AI相关的配置都抽离出来形成了统一的管控层。具体来说Harness管控的核心内容包括Prompt模板的版本管理、模型路由与降级策略、输入输出的结构化校验、调用链路的全量日志、效果指标的实时监控。这五块缺一不可少了任何一块你的AI产品就还是个脆弱的Demo。2.2 目录结构设计让每个Prompt都可追溯Harness落地的第一步是设计一套合理的目录结构。我们的做法是按业务域划分每个业务域下面再按功能模块组织。这套结构看起来简单但它是整个管控体系的地基设计不好后面会非常痛苦。harness/ ├── configs/ │ ├── models.yaml # 模型路由配置 │ ├── guardrails.yaml # 安全护栏配置 │ └── metrics.yaml # 监控指标定义 ├── prompts/ │ ├── customer_service/ │ │ ├── intent_classify/ │ │ │ ├── v1.0.0.prompt │ │ │ ├── v1.1.0.prompt │ │ │ └── manifest.yaml │ │ └── response_gen/ │ │ ├── v2.0.0.prompt │ │ └── manifest.yaml │ └── document_qa/ │ └── ... ├── skills/ │ ├── registry.yaml # 技能注册表 │ └── implementations/ └── pipelines/ ├── preprocess.yaml ├── postprocess.yaml └── fallback.yaml每个Prompt文件都带语义化版本号manifest.yaml里记录了这个Prompt的元信息适用模型、温度参数、最大token数、变更说明、负责人。这样任何时候线上出了问题你都能通过日志里的版本号定位到当时用的哪个Prompt谁改的改了什么。注意Prompt版本号一定要跟Git commit关联起来我们是在CI流程里自动把commit hash写进manifest这样代码和Prompt的对应关系永远不会断。2.3 模型路由与降级别让单一模型绑架你的产品AI产品最怕什么最怕模型服务商突然涨价、限流或者模型下线。我们早期就吃过这个亏某个核心功能依赖单一模型结果对方调整了API策略整个功能瘫痪了两天。从那以后模型路由就成了Harness的标配能力。模型路由的核心逻辑是根据请求的特征比如输入长度、任务类型、用户等级动态选择最合适的模型。同时配置降级链路主模型不可用时自动切到备用模型。我们在configs/models.yaml里的配置大概长这样routes: - name: long_text_analysis condition: input_tokens 4000 primary: model-a-large fallback: [model-b-large, model-c-medium] timeout: 30s retry: 2 - name: quick_intent condition: input_tokens 500 primary: model-d-small fallback: [model-e-small] timeout: 5s retry: 1这里有个经验降级不是简单换个模型就完事不同模型的输出格式和风格可能不一样。所以我们在降级链路后面加了一层输出适配器把不同模型的输出统一成业务层期望的格式。这层适配器看起来增加了复杂度但它让上层业务完全不用关心底层用的是哪个模型切换模型对业务透明。2.4 输入输出校验把不确定性关进笼子AI产品的输出不确定性是最大的风险来源。用户问“帮我查一下订单”模型可能返回JSON也可能返回一段自然语言还可能返回一个完全无关的内容。如果业务代码直接消费模型输出那线上事故就是必然的。Harness的校验层分两道关卡。第一道是结构校验用JSON Schema或者Pydantic模型定义期望的输出结构模型返回后先过这道校验不符合结构的直接触发重试或者降级。第二道是语义校验用规则引擎或者小模型判断输出内容是否合理比如是否包含敏感信息、是否偏离了用户意图、是否出现了幻觉。from pydantic import BaseModel, validator class OrderQueryResult(BaseModel): order_id: str status: str estimated_delivery: str validator(status) def status_must_be_valid(cls, v): allowed [pending, shipped, delivered, cancelled] if v not in allowed: raise ValueError(fInvalid status: {v}) return v这道校验看起来简单但它拦截了大概30%的异常输出。没有这层校验的时候这些异常会直接透传到前端变成用户看到的“系统繁忙”或者更糟糕的错误信息。2.5 全链路日志与效果监控让每次调用都有据可查Harness的日志系统记录每一次模型调用的完整上下文请求ID、用户ID、Prompt版本、模型版本、输入token数、输出token数、延迟、是否命中缓存、是否触发降级、校验结果。这些日志不仅用于排查问题更是后续优化的数据基础。监控指标我们重点关注四个输出合格率通过校验的比例、降级触发率、P95延迟、单次调用成本。这四个指标任何一个异常波动都意味着线上可能出了问题。比如输出合格率突然从95%掉到80%大概率是某个Prompt被改坏了或者模型服务端有变更。实操心得日志里一定要记录完整的输入输出内容但要注意脱敏。我们是在日志写入前做一层PII个人身份信息过滤把手机号、身份证号、银行卡号这些敏感信息替换掉。这个过滤规则也是配置化的不同业务域可以有不同的脱敏策略。3. Skills技能封装把AI能力变成可复用的“积木”3.1 什么是Skills从“写Prompt”到“造技能”如果说Harness解决的是“怎么管”的问题那Skills解决的就是“怎么复用”的问题。在没有Skills封装之前我们每个业务场景都要从头写Prompt、调模型、做校验大量重复劳动。而且不同人写的Prompt风格不一质量参差不齐维护成本极高。Skills的思路是把AI能力封装成标准化的“技能单元”。一个Skill就是一个独立的功能模块有明确的输入输出定义、有独立的Prompt模板、有配套的校验逻辑和降级策略。比如“意图识别”是一个Skill“情感分析”是一个Skill“文档摘要”也是一个Skill。业务方需要什么能力直接调用对应的Skill就行不用关心底层用的是哪个模型、Prompt怎么写的。这就像传统软件开发里的函数封装——你把一段逻辑封装成函数别人直接调用不用关心内部实现。Skills就是AI能力的函数化封装。3.2 技能注册表设计让能力可发现、可组合Skills要能被复用首先得让人知道有哪些Skill可用。我们维护了一个技能注册表registry.yaml每个Skill的元信息都登记在里面skills: - name: intent_classification version: 2.1.0 description: 对用户输入进行意图分类支持32种预定义意图 input_schema: type: object properties: text: type: string maxLength: 2000 output_schema: type: object properties: intent: type: string confidence: type: number model_route: quick_intent fallback_skill: keyword_match owner: nlp-team sla: latency_p95: 200ms accuracy: 92%这个注册表不仅是文档它还是运行时路由的依据。业务代码调用Skill时只需要传Skill名称和输入Harness会自动根据注册表找到对应的实现、模型路由和校验规则。新增一个Skill只需要在注册表里登记然后在implementations目录下实现对应的逻辑业务方就能直接用了。3.3 技能组合与编排112的玩法单个Skill能解决单一问题但真实业务场景往往需要多个Skill组合。比如一个智能客服场景可能需要先做意图识别再做情感分析然后根据意图和情感选择不同的回复生成策略。这种组合关系我们通过Pipeline来编排。pipeline: name: customer_service_flow steps: - skill: intent_classification input: ${user_input} output: intent_result - skill: sentiment_analysis input: ${user_input} output: sentiment_result - skill: response_generation input: text: ${user_input} intent: ${intent_result.intent} sentiment: ${sentiment_result.label} output: final_response condition: ${intent_result.confidence} 0.8 - skill: fallback_response condition: ${intent_result.confidence} 0.8 output: final_responsePipeline的编排能力让Skills从单点能力变成了流程能力。而且每个步骤的输入输出都有明确的Schema定义步骤之间的数据传递是类型安全的。这比把逻辑全写在一个巨型Prompt里要可靠得多也更容易调试——哪个步骤出了问题看日志一目了然。3.4 技能版本管理与灰度发布Skills的版本管理比Prompt更复杂因为一个Skill可能包含Prompt、模型配置、校验逻辑、后处理逻辑等多个组件。我们的做法是给每个Skill打一个整体版本号版本号变更时所有组件一起升级。同时支持灰度发布新版本先切5%的流量观察指标正常后再逐步放大。灰度发布的关键是指标对比。我们会同时监控新旧版本的输出合格率、延迟、成本、以及业务侧的核心指标比如客服场景的解决率。如果新版本在某个指标上明显劣化自动回滚。这套机制让我们敢于频繁迭代Skill因为知道有安全网兜着。踩坑记录早期我们灰度发布只看了技术指标没看业务指标。结果有一次新版本的技术指标全绿但业务侧的用户满意度掉了5个点。后来我们把业务指标也接入了灰度判断技术指标和业务指标双达标才允许全量。4. 完整实操从零搭建一套AI产品研发流水线4.1 环境准备与Harness初始化假设你现在要从零开始搭建这套体系第一步是初始化Harness工程。我们内部用的是Python技术栈核心依赖包括Pydantic做Schema校验、FastAPI做服务层、Redis做缓存和限流、Prometheus做指标采集。# 创建Harness工程目录 mkdir ai-harness cd ai-harness mkdir -p configs prompts skills pipelines logs # 初始化Python环境 python -m venv venv source venv/bin/activate pip install pydantic fastapi redis prometheus-client pyyaml初始化完成后先配置configs/models.yaml把可用的模型服务都登记进去。这里要注意的是不同模型服务的API格式可能不一样所以我们在Harness里做了一层模型适配器把不同厂商的API统一成内部标准格式。这样切换模型时只需要改配置不用改代码。class ModelAdapter: def __init__(self, config): self.provider config[provider] self.endpoint config[endpoint] self.api_key config[api_key] def invoke(self, prompt, **kwargs): if self.provider openai_compatible: return self._invoke_openai(prompt, **kwargs) elif self.provider custom: return self._invoke_custom(prompt, **kwargs)4.2 第一个Skill的完整实现我们以“意图识别”这个Skill为例走一遍完整的实现流程。首先在skills/registry.yaml里登记- name: intent_classification version: 1.0.0 description: 用户意图分类 input_schema: type: object properties: text: type: string maxLength: 2000 required: [text] output_schema: type: object properties: intent: type: string enum: [query_order, cancel_order, complaint, consult, other] confidence: type: number minimum: 0 maximum: 1 required: [intent, confidence] model_route: quick_intent fallback_skill: keyword_match然后在prompts/customer_service/intent_classify/下创建Prompt模板你是一个意图分类助手。请对以下用户输入进行分类输出JSON格式结果。 可选意图query_order查询订单、cancel_order取消订单、complaint投诉、consult咨询、other其他 用户输入{{text}} 请只输出JSON不要输出其他内容。格式{intent: 意图, confidence: 0.95}Prompt里的{{text}}是变量占位符运行时会被实际输入替换。这里有个细节我们在Prompt末尾强调了“只输出JSON”但实际测试中发现模型仍然偶尔会输出多余的解释文字。所以校验层必须能处理这种情况——我们的做法是先尝试提取JSON部分提取失败再触发重试。4.3 校验层的实现细节校验层是Skills可靠性的关键。我们的校验分三步格式提取、结构校验、业务规则校验。import json import re from pydantic import BaseModel, ValidationError class IntentResult(BaseModel): intent: str confidence: float def validate_intent_output(raw_output: str) - IntentResult: # 第一步提取JSON json_match re.search(r\{.*\}, raw_output, re.DOTALL) if not json_match: raise ValueError(No JSON found in output) # 第二步解析并做结构校验 try: data json.loads(json_match.group()) result IntentResult(**data) except (json.JSONDecodeError, ValidationError) as e: raise ValueError(fInvalid output structure: {e}) # 第三步业务规则校验 valid_intents [query_order, cancel_order, complaint, consult, other] if result.intent not in valid_intents: raise ValueError(fUnknown intent: {result.intent}) if result.confidence 0.5: # 置信度过低触发降级 raise LowConfidenceError(fConfidence too low: {result.confidence}) return result这套校验逻辑看起来繁琐但它把模型输出的不确定性收敛到了可控范围内。实测下来加上校验层之后意图识别的端到端准确率从87%提升到了94%因为低置信度的case被自动路由到了降级逻辑关键词匹配而不是硬着头皮返回错误结果。4.4 Pipeline编排与线上部署单个Skill跑通之后就可以用Pipeline把多个Skill串起来。我们以智能客服为例完整的Pipeline包含意图识别、情感分析、回复生成、安全过滤四个步骤。每个步骤的输出都经过校验任何一个步骤失败都会触发对应的降级策略。部署方面Harness服务本身是无状态的可以水平扩展。Prompt和Skill配置通过配置中心下发支持热更新。模型调用层做了连接池和限流防止突发流量打垮后端。监控指标通过Prometheus采集Grafana做可视化关键指标配置了告警规则。实操心得线上部署时一定要做流量预热。我们有一次大促前扩容了实例但新实例的缓存是空的导致大量请求直接打到模型服务延迟飙升。后来我们在实例启动时加了一个预热脚本提前加载常用Prompt和Skill配置问题就解决了。5. 规模化落地中的常见问题与排查实录5.1 模型输出格式漂移最隐蔽的线上杀手这个问题我们遇到过至少三次每次表现都不一样。第一次是模型服务商悄悄升级了模型版本输出格式从纯JSON变成了带Markdown代码块的JSON。第二次是我们自己调整了Prompt不小心删掉了一个格式约束。第三次最诡异同样的Prompt和模型白天输出正常晚上开始出现格式错误——后来发现是模型服务商晚上做了负载均衡部分请求路由到了不同版本的模型上。排查这类问题的关键是日志对比。我们在Harness日志里记录了每次调用的完整输入输出出问题时把正常case和异常case的日志拉出来对比很快就能定位到差异点。如果是模型服务商的问题就通过模型路由切到备用模型如果是Prompt问题就回滚到上一个版本。问题表现可能原因排查方法解决方案输出格式突然变化模型版本升级对比调用日志中的模型版本号锁定模型版本或切换路由部分请求格式错误负载均衡到不同版本按时间维度分析错误分布联系服务商确认或加版本约束特定输入格式错误Prompt边界case用错误输入复现补充Prompt约束或加校验规则输出内容质量下降温度参数被修改检查配置变更记录回滚配置并加变更审批5.2 延迟毛刺从P99到P999的深挖AI产品的延迟问题比传统服务更复杂因为模型推理时间本身就有波动。我们监控的是P95和P99延迟但有一次用户投诉“偶尔特别慢”查P99指标却正常。后来把监控粒度细化到P999才发现有0.1%的请求延迟超过了10秒。深挖之后发现两个原因一是某些超长输入接近token上限的推理时间天然就长二是模型服务的冷启动问题当并发突增时部分请求会排队等模型实例扩容。针对第一个问题我们在Harness层加了输入长度预检超过阈值的请求走异步处理或者拆分针对第二个问题我们配置了最小实例数并优化了扩容策略。5.3 成本失控Token消耗的精细化管理AI产品的成本大头是Token消耗。我们第一个月上线时没太关注这个月底账单出来吓了一跳。后来在Harness里加了Token计量和成本监控才发现有几个地方在“漏财”一是Prompt里塞了太多示例每次调用都重复消耗二是缓存命中率低相同请求重复调用模型三是降级逻辑不完善失败重试消耗了大量Token。优化措施包括把Prompt里的静态示例抽出来做缓存、对高频请求做结果缓存、重试次数从3次降到2次并加退避策略、对超长输入做摘要预处理。这套组合拳下来Token成本降低了约40%。5.4 多团队协作规范比工具更重要Harness和Skills这套体系要发挥价值前提是团队都按规范来。我们最初只有两个人在用后来扩展到五个团队共用问题就来了有人不写manifest、有人直接改线上Prompt、有人注册了Skill但不维护。后来我们定了三条硬规矩所有Prompt变更必须走PR流程、所有Skill必须有人负责维护、线上配置变更必须经过审批。工具层面也做了配套CI流程里加了Prompt格式检查配置中心加了变更审计日志Skill注册表加了负责人字段和最后更新时间。规矩定下来之后协作效率反而提高了因为大家知道边界在哪里。6. 一些关于AI产品工程化的个人体会这套Harness加Skills的体系我们跑了大概八个月支撑了三个产品线、二十多个AI功能模块的研发和迭代。最大的感受是AI产品的工程化不是把模型调好就完事了它需要一整套配套的管控和封装机制。模型能力是上限工程能力是下限下限决定了你的产品能不能稳定交付。另一个体会是不要过度设计。我们最开始想把Harness做成一个万能平台什么功能都想往里塞结果复杂度失控团队怨声载道。后来做减法只保留最核心的管控能力把扩展性留给Skills层反而更健康。工具是给人用的好用比强大更重要。最后分享一个我们内部的小习惯每次线上出问题除了修复之外一定要在Harness里加一条对应的校验规则或者监控指标。这样同样的问题不会出第二次。八个月下来我们的线上事故率下降了70%以上靠的就是这种“每次踩坑都填上”的笨办法。
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。