三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

阿里千问开放平台实战:从零开发AI服务Skill(快递查询为例)

阿里千问开放平台实战:从零开发AI服务Skill(快递查询为例)

最近,很多开发者都在讨论一个现象:大模型的能力越来越强,但真正能把它用起来、解决实际生活问题的门槛,似乎依然很高。写个代码助手、做个聊天机器人相对容易,但要让AI去完成一次真实的“服务”——比如帮你租到合适的房子、叫个快递、或者订辆车——你会发现,这背后需要的远不止一个聪明的模型,而是一整套连接现实世界的“管道”。

就在这个节点上,阿里千问开放平台正式上线了。它带来的核心变化,不是又一个API接口,而是一个服务型AI的“应用商店”。开发者可以像调用一个函数一样,通过对话,让千问大模型去调用第三方服务,完成租房、租车、寄快递等具体任务。这听起来像是科幻电影里的场景,但它背后,是AI从“聊天”走向“办事”的关键一步。

这篇文章,我们就来深入拆解这个“千问开放平台”。我会从一个开发者的视角,告诉你:

  1. 它解决的到底是什么问题?(不只是“多了一个API”)
  2. 它的核心架构和原理是什么?(Skill、Agent、工作流如何协同)
  3. 作为一个开发者,如何从零开始,把一个真实服务(比如查快递)接入到这个平台?
  4. 在开发、调试、上线过程中,有哪些必须注意的“坑”和最佳实践?

如果你正在关注AI应用落地,或者想了解如何将大模型能力与现有业务系统结合,这篇文章会提供一个非常具体的实操路径。

1. 千问开放平台:它到底解决了什么核心问题?

在深入代码之前,我们必须先理解这个平台出现的背景和它要啃下的“硬骨头”。

过去一年,我们见证了无数基于大模型的聊天应用。它们能写诗、能编程、能回答问题,但在处理“需要与外部世界交互”的任务时,往往力不从心。比如,用户说“帮我查一下昨天寄往上海的快递到哪了”。一个纯聊天模型只能回答:“你需要提供快递单号,然后去快递公司官网或APP查询。”——它知道流程,但无法执行。

千问开放平台要解决的,正是这个“最后一公里”的问题:让AI不仅能“知道”,还能“做到”。

它的核心价值体现在三个层面:

对用户而言:体验从“信息获取”升级为“任务完成”。用户不再需要记住各个APP、网站,或者在一堆菜单里翻找。他们可以用最自然的语言描述需求,由AI代理(Agent)去协调背后的多个服务(Skill),完成复杂操作。例如,“下周一上午从公司去机场,帮我租辆车,要经济型,带保险”,这一句话背后,可能涉及查询租车服务、比价、选择车型、填写个人信息、确认保险条款、完成支付等多个步骤。

对服务提供商(企业/开发者)而言:获得了一个全新的、低成本的用户触达和转化渠道。传统的服务接入需要开发独立的APP、小程序或H5页面,并投入大量资源进行推广。现在,通过将服务封装成“Skill”接入千问平台,就相当于把自己的服务“上架”到了一个拥有海量潜在用户的AI应用商店。用户通过对话即可发现和使用服务,转化路径被极大缩短。

对开发者/技术团队而言:平台提供了将大模型能力“工程化”、“服务化”的标准范式。它抽象出了一套完整的框架,包括技能(Skill)的定义、注册、描述,智能体(Agent)的编排、决策,以及用户意图理解、工具调用、结果返回的完整工作流。开发者无需从零开始构建复杂的Agent系统,可以专注于自己核心的服务逻辑。

简单来说,千问开放平台正在尝试定义下一代的人机交互界面标准:对话即服务(Conversation as a Service, CaaS)。它不是一个聊天工具,而是一个服务调度中枢

2. 核心概念与架构:Skill、Agent与工作流

要理解和使用这个平台,必须搞清楚三个核心概念:Skill(技能)Agent(智能体)工作流。它们的关系,可以用一个简单的比喻来理解:

  • Skill(技能):就像手机里的一个个独立APP,每个都有明确、单一的功能。比如“申通快递查询”、“神州租车下单”、“链家房源搜索”。它是一个个可被调用的、封装好的服务接口。
  • Agent(智能体):就像你手机上的智能语音助手(如Siri)。它本身不提供具体服务,但它听得懂你的话(意图识别),并且知道该打开哪个或哪几个APP来帮你完成任务(技能调度与编排)。
  • 工作流:当你下达一个复杂指令时,Agent内部执行的一系列有序步骤。例如,处理“租车”任务时,工作流可能是:1. 理解用户需求(时间、地点、车型);2. 调用“租车比价”Skill获取选项;3. 调用“用户身份验证”Skill确认权限;4. 调用“具体租车公司下单”Skill完成预订;5. 将结果整合后返回给用户。

平台的技术架构大致如下:

用户对话 ↓ 千问大模型 (意图理解与决策) ↓ Agent 调度引擎 ↓ Skill 路由与执行 ↓ 第三方服务 API ↓ 结果处理与格式化 ↓ 返回用户

在这个架构中,开发者主要参与的是“Skill 开发”“Agent 配置”两个环节。平台负责提供意图识别、对话管理、安全管控、计费结算等底层能力。

3. 环境准备与开发者入驻

在开始编码之前,你需要先完成平台侧的准备工作。

第一步:访问与注册

  1. 访问阿里云官网,找到“千问开放平台”或“通义千问开放平台”的相关入口(通常位于人工智能或云产品板块)。
  2. 使用你的阿里云账号登录。如果没有,需要先注册。
  3. 完成开发者实名认证。这是调用开放API和上线Skill的必要条件。

第二步:创建应用与获取凭证

  1. 在控制台,创建一个新的“应用”(Application)。这个应用代表了你将要开发的Skill或Agent。
  2. 创建成功后,平台会为你分配一组重要的凭证:
    • App Key:应用唯一标识。
    • App Secret:应用密钥,用于签名认证,务必保密
    • Access Token:访问令牌,通常有有效期,需要通过App Key和Secret换取。

这些凭证将在后续的API调用中用于身份验证。

第三步:本地开发环境准备假设我们使用Python作为开发语言,你需要准备:

  • Python 3.8+:建议使用最新稳定版。
  • 包管理工具pip
  • HTTP客户端库requests用于调用平台API和你的服务接口。
  • 签名工具:平台API调用通常需要签名,阿里云会提供SDK或签名算法文档。
  • 一个可公网访问的Endpoint:你的Skill服务需要提供一个HTTPS接口供平台回调。开发阶段可以使用内网穿透工具(如ngrok、frp)将本地服务暴露到公网,但生产环境必须使用正式的、有SSL证书的域名

4. 实战:开发一个“快递查询”Skill

现在,我们以一个最简单的“快递查询”Skill为例,走通从开发到调试的完整流程。这个Skill的功能是:接收一个快递单号,返回该单号的物流轨迹。

4.1 定义Skill元信息

在平台上创建Skill时,你需要填写一份详细的“说明书”,告诉平台你的Skill能做什么、需要什么参数、返回什么结果。这通常通过一个JSON Schema或类似格式来定义。

核心字段包括:

  • skill_name: 技能名称,如express_query
  • description: 技能描述,用于模型理解。例如:“根据快递单号查询最新的物流状态信息”。
  • parameters: 定义输入参数。例如,需要一个express_number(字符串类型)。
  • output_schema: 定义返回数据的结构。

以下是一个简化的定义示例(具体格式请以平台文档为准):

{ "skill_name": "express_query", "version": "1.0.0", "description": "查询快递物流信息。支持主流快递公司单号。", "endpoint": "https://your-server.com/api/express/query", "http_method": "POST", "parameters": [ { "name": "express_number", "type": "string", "description": "快递单号", "required": true }, { "name": "company_code", "type": "string", "description": "快递公司编码(如‘sto’代表申通),可空,系统尝试自动识别", "required": false } ], "output_schema": { "type": "object", "properties": { "status": { "type": "string", "description": "当前状态,如‘运输中’、‘已签收’" }, "latest_trace": { "type": "string", "description": "最新一条物流信息" }, "traces": { "type": "array", "items": { "type": "object", "properties": { "time": {"type": "string"}, "description": {"type": "string"} } } }, "estimated_delivery_time": { "type": "string", "description": "预计送达时间" } } } }

关键点description字段至关重要!千问大模型会依赖这个描述来判断在什么场景下调用你的Skill。描述要准确、简洁,包含关键触发词。

4.2 实现Skill服务端接口

你的服务器需要实现一个符合平台调用规范的HTTP接口。平台会以POST方式,将用户参数和上下文信息发送到你在endpoint中配置的URL。

下面是一个使用Python Flask框架实现的简单示例:

# 文件:app.py from flask import Flask, request, jsonify import hashlib import hmac import time import requests app = Flask(__name__) # 假设你有一个第三方快递查询API THIRD_PARTY_EXPRESS_API = "https://api.third-party-express.com/query" THIRD_PARTY_API_KEY = "your_third_party_api_key" def verify_signature(app_secret, request_body, received_signature): """验证来自千问平台的请求签名(示例逻辑,具体以官方文档为准)""" # 实际签名算法请严格参照开放平台文档 calculated_sign = hmac.new(app_secret.encode(), request_body, hashlib.sha256).hexdigest() return hmac.compare_digest(calculated_sign, received_signature) @app.route('/api/express/query', methods=['POST']) def query_express(): """ 处理千问平台发起的快递查询请求。 请求体格式示例: { "skill_id": "xxx", "request_id": "xxx", "parameters": { "express_number": "YT1234567890" }, "user_context": {...} } """ # 1. 获取请求数据和签名(假设签名在Header中) data = request.get_json() signature = request.headers.get('X-Qianwen-Signature') app_secret = "YOUR_APP_SECRET" # 从安全配置读取 # 2. 签名验证(生产环境必须开启) # if not verify_signature(app_secret, request.get_data(), signature): # return jsonify({"error": "Invalid signature"}), 403 # 3. 提取参数 express_number = data.get('parameters', {}).get('express_number') if not express_number: return jsonify({"error": "Missing express_number"}), 400 # 4. 调用真实的第三方快递查询服务 try: # 这里简化处理,实际需要处理鉴权、错误、重试等 resp = requests.post( THIRD_PARTY_EXPRESS_API, json={'number': express_number}, headers={'Authorization': f'Bearer {THIRD_PARTY_API_KEY}'}, timeout=5 ) resp.raise_for_status() third_party_data = resp.json() # 5. 将第三方数据格式化为平台约定的输出格式 formatted_result = { "status": third_party_data.get('status', '查询中'), "latest_trace": third_party_data.get('latest', {}).get('desc', ''), "traces": [ {"time": t['time'], "description": t['desc']} for t in third_party_data.get('traces', []) ], "estimated_delivery_time": third_party_data.get('estimate_time', '') } # 6. 返回标准响应 return jsonify({ "request_id": data.get('request_id'), "skill_id": data.get('skill_id'), "output": formatted_result }) except requests.exceptions.RequestException as e: # 处理网络或API错误 app.logger.error(f"Third-party API call failed: {e}") return jsonify({ "request_id": data.get('request_id'), "error": { "code": "SERVICE_UNAVAILABLE", "message": "快递查询服务暂时不可用,请稍后重试。" } }), 503 except Exception as e: app.logger.error(f"Internal server error: {e}") return jsonify({ "request_id": data.get('request_id'), "error": { "code": "INTERNAL_ERROR", "message": "服务内部错误。" } }), 500 if __name__ == '__main__': # 开发环境运行,生产环境应使用Gunicorn等WSGI服务器 app.run(host='0.0.0.0', port=5000, debug=True)

代码关键点解析:

  1. 签名验证:生产环境下,必须验证请求是否来自可信的千问平台,防止恶意调用。这是安全底线。
  2. 参数提取:从parameters字段中获取用户输入。
  3. 调用第三方服务:这里是你的业务核心。注意处理超时、重试和降级。
  4. 数据格式化:将第三方API返回的数据,转换为你在Skill元信息output_schema中定义的格式。这是保证Agent能正确理解和呈现结果的关键。
  5. 错误处理:返回结构化的错误信息,方便平台和用户理解问题所在。

4.3 在平台注册并配置Skill

  1. 在千问开放平台控制台,找到“技能管理”或“我的技能”页面。
  2. 点击“创建技能”,将前面定义的Skill元信息(JSON)填入或通过表单配置。
  3. 最关键的一步:填写“服务端点”,即你的服务器公网可访问的URL(如https://your-domain.com/api/express/query)。
  4. 配置安全设置,如IP白名单(如果平台支持)、签名密钥等。
  5. 提交后,平台通常会有一个“测试”环节。你可以在这里输入测试参数,触发平台向你的端点发送请求,验证整个链路是否通畅。

5. 创建与调试你的第一个Agent

Skill是“零件”,Agent是“组装好的机器”。现在,我们来创建一个能使用“快递查询”Skill的智能体。

在平台创建Agent:

  1. 进入“智能体管理”或“Agent工作室”。
  2. 创建新Agent,给它起个名字,例如“生活小助手”。
  3. 核心配置:技能绑定。在Agent的配置页面,将你刚刚创建并审核通过的“快递查询”Skill添加到该Agent可用的技能列表中。
  4. 配置Agent属性
    • 系统指令:定义Agent的角色和基础行为准则。例如:“你是一个生活助手,专注于帮助用户查询快递、租房等信息。当用户需要查询快递时,主动询问或确认快递单号。”
    • 开场白:用户第一次进入对话时的问候语。
    • 知识库:可以上传一些补充文档,帮助Agent更好地回答领域内问题(可选)。

调试与测试:

  1. 平台会提供一个Web版的对话测试窗口。
  2. 尝试输入:“帮我查一下快递YT1234567890”。
  3. 观察后台日志(你的Skill服务端),看是否收到请求,参数是否正确。
  4. 观察测试窗口,看Agent是否正确地调用了Skill并返回了格式化的物流信息。

这里有一个至关重要的调试技巧:关注意图识别。如果Agent没有触发你的Skill,可能不是因为Skill没注册,而是因为大模型没有从用户对话中识别出明确的“查询快递”意图,或者你的Skill描述不够精准。这时需要:

  • 优化你的Skill描述 (description)。
  • 在Agent的“系统指令”中加强引导。
  • 提供更多样化的测试用例。

6. 运行效果与完整对话示例

假设一切配置正确,一个完整的用户交互流程如下:

用户:“我的快递到哪了?单号是YT1234567890。”Agent:“好的,正在为您查询单号YT1234567890的物流信息...”(后台:Agent识别出“查询快递”意图和参数“YT1234567890”,调用‘express_query’ Skill。你的服务端收到请求,调用第三方API,返回格式化数据。)Agent:“查询到了!您的快递最新状态是【已签收】。最新轨迹:今天下午3点20分,已由门卫代收。完整的物流轨迹如下:... 预计送达时间已过。请问还有其他需要帮助的吗?”

这个过程中,用户感知到的只是一个流畅的对话,完全无需跳转到快递公司的APP或网站。

7. 常见问题与排查思路

在开发和集成过程中,你一定会遇到各种问题。下表列出了最常见的问题及其排查方向:

问题现象可能原因排查步骤解决方案
Skill调用失败,提示“技能不可用”1. 服务端点(Endpoint)无法访问。
2. 服务端响应超时(默认可能有5-10秒限制)。
3. 服务端返回非2xx状态码。
1. 用curl或 Postman 直接测试你的Endpoint。
2. 检查服务器日志,看是否收到请求。
3. 检查服务端处理逻辑耗时,优化性能。
1. 确保Endpoint公网可达,防火墙/安全组放行。
2. 优化代码,增加缓存,第三方调用设置合理超时。
3. 确保返回正确的HTTP状态码和JSON格式。
Agent不触发我的Skill1. Skill描述(description)不准确,模型无法匹配。
2. 用户表达模糊,意图识别失败。
3. Agent的系统指令未引导使用该Skill。
1. 在平台测试窗输入多种同义句,看是否触发。
2. 检查平台是否提供意图识别测试工具。
3. 查看Agent的对话日志,看模型对用户输入的理解。
1. 重写Skill描述,包含更全面的关键词和场景。
2. 在Agent开场白或知识库中提示可用功能。
3. 考虑是否需要为用户设计更明确的对话引导。
签名验证失败1. App Secret配置错误。
2. 签名算法实现与平台不一致。
3. 请求体在传输中被修改。
1. 核对控制台的App Secret。
2. 仔细阅读官方签名算法文档,逐行比对代码。
3. 本地使用平台提供的示例请求进行签名验签。
1. 重置App Secret。
2. 使用官方提供的SDK(如果有)进行签名验证。
3. 确保服务端接收的是原始请求体。
返回结果Agent无法理解1. 返回的JSON格式不符合output_schema定义。
2. 字段类型不匹配(如应该是数组却返回了字符串)。
3. 包含了未定义的字段。
1. 将你的服务端返回的JSON,与Skill定义中的output_schema逐字段对比。
2. 使用JSON Schema验证工具进行校验。
1. 严格按照output_schema构建返回数据。
2. 移除所有多余的字段。
3. 对于可能为空的字段,返回null或空数组[],而不是不返回该字段。
第三方服务不稳定导致Skill失败第三方API超时、宕机或返回错误。1. 监控第三方服务的健康状态。
2. 在服务端日志中记录详细的第三方调用错误。
1. 实现重试机制(如最多3次,指数退避)。
2. 设置合理的超时时间(如3秒)。
3. 实现降级策略,返回友好的错误提示或缓存的上次结果。

8. 最佳实践与进阶建议

当你跑通第一个Skill后,接下来要考虑如何把它做得更健壮、更可用。

1. 安全性是重中之重

  • HTTPS:服务端点必须使用HTTPS。
  • 签名验证:必须实现并开启请求签名验证,这是防止伪造请求的第一道防线。
  • 参数校验:在服务端对输入参数进行严格的校验和过滤,防止注入攻击。
  • 权限控制:如果你的Skill涉及用户敏感操作(如支付、修改信息),必须通过平台传递的用户标识进行二次鉴权。

2. 性能与可靠性

  • 超时设置:你的服务端调用第三方API时,必须设置超时(建议2-5秒),避免长时间阻塞。
  • 重试机制:对于可重试的临时性错误(如网络抖动),实现有策略的重试。
  • 熔断与降级:当第三方服务持续不可用时,应快速失败(熔断),并返回预设的降级内容(如“服务繁忙,请稍后再试”),而不是让用户长时间等待或看到技术性报错。
  • 异步处理:对于耗时较长的任务(如生成报告),不要同步等待。应该先返回“已受理”的响应,然后通过平台的消息推送或轮询机制告知用户最终结果。

3. Skill设计原则

  • 单一职责:一个Skill只做一件事,并把它做好。不要设计“万能”Skill。
  • 描述清晰descriptionparameters的描述要使用自然语言,清晰无歧义,帮助大模型准确理解调用时机和方式。
  • 错误信息友好:返回的错误信息要对最终用户友好。使用error.message字段提供通俗的解释,而不是内部错误码。

4. 面向生产环境

  • 日志与监控:记录所有Skill的调用请求、响应时间、成功/失败状态。接入APM工具监控性能。
  • 版本管理:当你更新Skill接口时,先在平台创建一个新版本进行测试,稳定后再切换流量,避免影响线上用户。
  • 容量规划:预估你的Skill可能承受的QPS,确保服务器资源充足。

9. 总结:从“接单”到“造轮子”的思维转变

千问开放平台的上线,标志着大模型应用进入了一个新阶段:从“玩具”和“助手”走向“生产力工具”和“服务入口”。对于开发者而言,这不仅仅是多了一个API可以调用。

它要求我们的开发思维发生转变:

  • 从“提供功能”到“定义服务”:我们不再仅仅是开发一个功能模块,而是在定义一个可以被AI智能体理解和调用的“服务”。服务的接口、语义、可靠性变得前所未有的重要。
  • 从“面向用户界面”到“面向对话流”:设计时需要考虑用户如何用自然语言触发,以及结果如何被自然地组织到对话中。
  • 从“独立应用”到“生态组件”:你的服务将成为AI智能体工具箱中的一个“零件”,它可能在各种你未曾预料的场景和组合中被调用。

作为起步,我强烈建议你按照本文的流程,亲手将一项你熟悉的服务(哪怕是查询天气、计算汇率这样的简单服务)封装成一个Skill并接入。这个过程会让你深刻理解意图识别、数据格式转换、错误处理等关键环节。

下一步,你可以探索更复杂的场景:

  • 多Skill协作:设计一个“出差规划”Agent,它需要依次调用“查询航班”、“预订酒店”、“租车”等多个Skill。
  • 状态管理:处理需要多轮对话才能完成的任务,例如租房,需要先确认预算、地点,再筛选房源,最后预约看房。
  • 与自有系统深度集成:将Skill作为桥梁,让千问这样的超级入口,能够安全、可控地操作你公司内部的核心业务系统。

机会存在于变化之中。千问开放平台这类基础设施的成熟,正在大幅降低“对话式服务”的构建门槛。现在,是时候思考如何将你的专业能力,封装成下一个可能被百万人使用的AI Skill了。

← 返回列表