通义千问 + 函数计算 FC:给商会小程序做一个能调后端的 AI 助手

简介: 该方案为商会小程序打造智能助手,用通义千问(Qwen-Max)作“调度员”,结合阿里云函数计算(FC)、百炼向量库与后端接口,实现自然语言问答:自动理解问题、按需调用工具查会员数据(如会费、等级)、RAG检索章程制度。日均处理数百次重复咨询,释放人力,成本远低于人工。

商会小程序有一个很反直觉的现象:每天登录的会员很多,但真正打开"找秘书处"入口的会员更多。这些会员问的问题高度重复——会费怎么交、章程在哪下载、本月活动在哪开、我的会员等级是不是到期了。

秘书处两三个干事,每天要花掉大半天回这些重复问题。剩下的时间才用来做真正需要人处理的事:活动对接、跨商会资源撮合、会长临时交办。

我们试过几种方案。第一种是 FAQ 知识库,会员自助查,但实际点击率不到一成,因为大家更习惯问一句"我这个情况怎么办"而不是先去翻列表。第二种是关键词机器人,问题进来后正则匹配,但凡是问题里多两个字、换个说法,就匹配不上。第三种是直接接入大模型 API,但模型不知道会员的实时状态,回答永远是模板化的官腔。

后来我们换了一个思路:让大模型当"调度员",把具体信息查询交给后端去查。这就是下面要写的整套方案。

一、整体架构

整个助手由四块组成。

第一块是通义千问 Qwen,负责理解会员的自然语言问题、判断要不要查后端、决定调哪个接口、把查回来的结果用自然语言回答给会员。这里我们用的是 Qwen-Max,因为会员问题里常带口语化表达,Max 系列的指令遵循更稳。

第二块是阿里云函数计算 FC,承担整个调用入口。FC 跑的是事件驱动的无服务器函数,会员从小程序发一次请求,FC 起一个实例、调 Qwen、必要时再起几个实例并发查后端,处理完一次请求就把实例释放掉。这种"用一次起一次"的模型,对商会这种白天高峰、夜里几乎没量的业务形态特别合适,省了一台常驻服务器的钱。

第三块是百炼 + 自建向量库,承担知识库问答。商会的章程、制度、活动通知、行业报告这些静态资料,先切片、向量化、进百炼的向量库;会员问到具体业务规则时,先走 RAG 召回相关文档片段,再让 Qwen 结合片段回答。这部分比纯靠模型"硬答"靠谱得多,因为模型不会乱编商会的制度条款。

第四块是后端业务系统的查询接口,承担所有"需要会员本人数据"的查询。比如"我这个月会费交了没",模型要把会员编号传给后端,后端去查实际的支付记录、查他今年的会费账单、查他过往的支付习惯。

二、FC 入口函数的核心代码

下面是 FC 入口函数的核心代码。这是整个助手的主流程:解析小程序请求、调 Qwen、判断要不要调工具、调完工具再回 Qwen 拿最终回答。

# fc_handler.py
import json
import dashscope
from dashscope import Generation
from http import HTTPStatus
from tool_dispatcher import dispatch

TOOLS = json.loads(open("tools.json", encoding="utf-8").read())

def handler(event, context):
    body = json.loads(event)
    question = body.get("question", "")
    member_id = body.get("member_id", "")

    # 1. 构造系统提示,把会员身份塞进去
    system_prompt = (
        "你是商会智能助手,会员编号是 " + member_id + "。"
        "回答必须基于工具查询结果,不要凭空编造。"
    )

    messages = [
        {
   "role": "system", "content": system_prompt},
        {
   "role": "user", "content": question}
    ]

    # 2. 第一次调 Qwen,让它判断要不要调工具
    msg = call_qwen(messages, TOOLS)

    # 3. 如果模型说要调工具,循环调,直到它不再要工具
    for _ in range(5):
        if not msg.get("tool_calls"):
            break
        for tc in msg["tool_calls"]:
            name = tc["function"]["name"]
            args = json.loads(tc["function"]["arguments"])
            result = dispatch(name, args, member_id)
            messages.append({
   
                "role": "tool",
                "tool_call_id": tc["id"],
                "content": json.dumps(result, ensure_ascii=False)
            })
        msg = call_qwen(messages, TOOLS)

    return {
   
        "statusCode": 200,
        "body": json.dumps({
   "answer": msg.get("content", "")}, ensure_ascii=False)
    }

def call_qwen(messages, tools):
    response = Generation.call(
        model="qwen-max",
        messages=messages,
        tools=tools,
        result_format="message"
    )
    if response.status_code == HTTPStatus.OK:
        return response.output.choices[0].message
    raise RuntimeError("qwen call failed: " + str(response.code))

三、工具定义怎么写

工具定义决定了模型"能调什么"。我们把商会业务里最高频的几类查询抽象成函数,让模型按需调用。

// tools.json
[
  {
   
    "type": "function",
    "function": {
   
      "name": "get_member_fee",
      "description": "查询指定会员的会费账单,传入会员编号和年份,返回应缴、已缴、欠缴金额",
      "parameters": {
   
        "type": "object",
        "properties": {
   
          "member_id": {
   "type": "string"},
          "year": {
   "type": "integer", "description": "查询年份,缺省为当前年"}
        },
        "required": ["member_id"]
      }
    }
  },
  {
   
    "type": "function",
    "function": {
   
      "name": "get_upcoming_activities",
      "description": "查询指定商会近期的活动安排",
      "parameters": {
   
        "type": "object",
        "properties": {
   
          "chamber_id": {
   "type": "string"},
          "limit": {
   "type": "integer", "description": "返回条数,缺省 5"}
        }
      }
    }
  },
  {
   
    "type": "function",
    "function": {
   
      "name": "get_member_level",
      "description": "查询会员的等级、有效期、累计缴费记录",
      "parameters": {
   
        "type": "object",
        "properties": {
   
          "member_id": {
   "type": "string"}
        },
        "required": ["member_id"]
      }
    }
  }
]

工具描述里写清楚"什么时候调"很重要。模型读 description 来决定要不要触发这个工具,description 写错了,模型会乱调或者不调。

四、知识库怎么搭

商会里真正稳定的"长知识"——章程、制度、历史通知——都放在百炼的向量库里。具体做法是每周把商会后台新发的通知、章程更新、新增的行业报告,自动切片、向量化、入库。

会员问"理事会有几票表决权"这种问题,模型先去向量库召回相关章程片段,再结合片段回答。RAG 召回加 Qwen 重写回答,准确率比纯模型答高很多,模型也很少再出现"自己编"的情况。

五、踩过几个坑

第一个坑是上下文管理。模型是有上下文窗口的,会员连续追问几次后 messages 会越来越长,请求会越来越慢。我们的做法是超过 8 轮对话就触发压缩,把早期 messages 总结成一段短文本塞回去,效果很稳。

第二个坑是函数冷启动。FC 长时间不调用会有冷启动,第一次调起来慢。后来我们在 FC 里加了预置并发(Provisioned Concurrency),冷启动基本感受不到了。

第三个坑是限流。Qwen API 本身有限流,商会做活动期间并发问问题,瞬时 QPS 一高就会触发限流。我们的做法是在 FC 入口加一层简单的令牌桶,把瞬时并发压住,平峰再放过去。

六、效果

上线之后,会员的重复问题秘书处基本不需要再接了,平均每天几百次问询绝大多数都让 AI 助手自己处理掉了。成本上看,Qwen API 单次几厘到几分钱,FC 单次几厘,整个助手每天跑下来的成本远低于一个兼职秘书一个月的工资。更关键的是,秘书处的干事终于从"回消息"里解放出来,去做真正需要人际沟通的事。

我们这边落地的商会管理系统叫未来漫城·商会互联平台,上面这套 AI 助手现在已经嵌在小程序的"找秘书"入口,会员随口问一句就能直接拿到自己账单和活动安排,不再需要等干事回消息。

如果你们也在做类似的"垂直行业 AI 助手",这套"通义千问 + FC + 工具调用 + RAG"的组合是一个比较稳的起点,可以直接拿来用再根据自己业务调。

相关实践学习
【玩转ComfyUI】基于函数计算一键部署AI生图平台ComfyUI
本次实验将带大家通过使用阿里云产品函数计算FC,快速使用ComfyUI实现更高质量的图像生成。
从 0 入门函数计算
在函数计算的架构中,开发者只需要编写业务代码,并监控业务运行情况就可以了。这将开发者从繁重的运维工作中解放出来,将精力投入到更有意义的开发任务上。
相关文章
|
21天前
|
算法 自动驾驶 安全
AgentLoop 数据飞轮实践(一):总览 —— 让 Agent 持续调优的闭环
Agent 上线的那一刻,真正的考试才开始:上线只是起点,持续调优才是关键。本文用一小时实操带你看 AgentLoop 如何把接入、评估、实验、经验库串成数据飞轮,以专家驱动与全自动经验挖掘,让 Agent 越转越聪明。
330 12
|
17天前
|
算法 数据挖掘 Shell
经验自进化:自动挖掘经验资产,消融实验验证真实收益丨AgentLoop 数据飞轮实践(五)
本文介绍AgentLoop经验自进化实践:从运行轨迹自动挖掘成功与失败模式,经Skill召回并注入上下文。文章详解接入验证流程,并通过消融实验优化召回策略,降低耗时、成本、Token消耗和工具调用,让Agent持续迭代。
|
21天前
|
消息中间件 人工智能 Apache
Apache RocketMQ 面向 AI 演进:LiteTopic 支撑百万级多 Agent 会话协作
本文整理自 Apache 2026 技术分享《面向 AI 的 Apache RocketMQ:多 Agent 系统的可靠协作机制》。
159 11
|
17天前
|
SQL 人工智能 运维
玩家说“充值没到账”,AI 如何从日志里找到真相?——SLS 业务模型与 DataAgent 实战
玩家说“充值没到账”,日志里却只有 deliver_status = failed 和 error_code = BAG_FULL。本文以游戏客服为例,介绍如何通过 SLS 语义层沉淀业务口径,再由 DataAgent 解析问题、查询日志、串联证据,辅助定位原因并生成客服答复草稿。
178 1
|
21天前
|
人工智能 监控 安全
零代码改造:让 AI Agent Sandbox 不再是黑盒
OBI 基于 eBPF 在内核与库函数层零代码拦截通信,自动生成调用链与指标,内置 OpenAI、Anthropic、Gemini、Qwen 及自定义 LLM 网关的 GenAI 语义追踪,覆盖 LLM、工具、MCP 与 RAG 全链路,从性能、成本、安全三个维度透视沙箱执行。
|
7天前
|
监控 安全 数据可视化
上云之后,终端安全怎么守?从 4 个实战能力说起
云时代边界消融,安全主战场下沉至终端。本文剖析终端安全四大核心能力:资产与风险可视化、勒索软件主动防御、EDR异常行为响应、外设与数据防泄漏,并给出分阶段落地建议——先看见、再预警、后处置,兼顾安全与业务 continuity。
|
21天前
|
NoSQL 关系型数据库 MySQL
买了云服务器,不等于上了云
朋友小美说「我们那不就是几台机器吗,跟云计算有什么关系」。这句话比她自己以为的准。买了云上的机器和用上了云,中间隔着三层,多数团队停在第一层。她那几台常年低利用率的 8 核 32G,答案就在第三层。
|
17天前
|
存储 SQL 消息中间件
Agent 做了这么多轮重构,企业到底该留下什么?
本文整理自第 10 届 AI + 研发数字峰会(AiDD)北京站 TOP10 最佳演讲议题之一《Agent 开发范式演进:简化多源实时上下文构建》。
|
16天前
|
监控 NoSQL Unix
【Azure Redis】Redis 指标 ClockSkewSeconds 解读:含义、读数与时钟偏差的影响
《ClockSkewSeconds 解析》:详解 Redis 监控中时钟偏差指标的含义——反映节点与参考时钟的时间差(秒级),非请求耗时;阐明其对 Key 过期、日志关联及分布式一致性的影响,强调稳定时间比瞬时偏差更关键。
|
17天前
|
NoSQL JavaScript 前端开发
【Azure Function】NodeJS Function大批量写入到Redis遇见丢失数据情况的分析
Azure Functions 中批量写 Redis 时,看到 Invocation 已完成,不代表每个 Redis SET 都完成了。如果代码用 callback 调用 client.set(),随后立即执行 client.quit() 或直接返回,Function Runtime 可能认为本次执行已经结束,但 Redis 写入还在事件循环里排队。我的建议很明确:所有外部依赖调用都必须 await,批量写入要么顺序等待,要么用受控并发等待全部 Promise 完成。
110 1

热门文章

最新文章