• [技术干货] “来电显示”助力沟通,办公效率提升75%!
         叮叮叮……“喂,您好哪位?”“小张,XXX”领导同事来电被误以为是骚扰电话直接挂断,或无法判断来电人小心翼翼试探,这些职场上的尴尬时刻你遇到过吗?华为AppGallery Connect(简称AGC)推出的企业联系人信息来去电页面显示能力让你彻底告别这些尴尬时刻,来电显示一览无遗,重要电话绝不错过,沟通效率up up!一、什么是企业联系人信息来去电页面显示?       华为企业联系人信息来去电页面显示是基于Call Service Kit(通话服务)提供的面向企业办公场景的能力,来去电时,页面可以显示已安装企业应用的联系人信息,方便用户识别来去电人信息,快速回应,增强企业内部沟通效率。(本功能仅供企业应用开发者接入)       企业来电显示能力从传统的8步可缩减至2步,沟通效率提升75%,让沟通简单又高效!(此数据为伙伴侧提供案例参考,具体以实际应用落地效果为准)二、如何接入企业联系人信息来去电页面显示能力?企业应用开发者将申请信息发送至公共邮箱:agconnect@huawei.com。邮件标题:【申请公司名】—企业来电显示能力—Developer ID。邮件内容需包括:开发者接入企业来电显示能力的应用使用主体、应用名称、应用ID、应用包名、场景说明(具体描述该应用对应通讯录量级等使用的必要信息)。申请成功后,需要重新申请调试Profile,并且在DevEco Studio中替换新申请的调试Profile。三、用户手机如何进行设置?     打开“电话”> 点击右上角“更多”图标 > 前往“设置”> 找到“陌生号码和信息识别” > 打开对应企业应用的号码识别功能开关  页面效果展示 AppGallery Connect致力于为应用的创意、开发、分发、运营、经营各环节提供一 站式服务,构建全场景智慧化的应用生态体验。为给您带来更好服务,请扫描下方二维码或者点击此处免费咨询。如您有任何疑问,请发送邮件至agconnect@huawei.com咨询,感谢您对HUAWEI AppGallery Connect的支持!
  • [案例共创] 【案例共创】使用开发者空间 AI Agent+RAG+高德地图MCP开发班车出行助手
    案例介绍本案例选择使用华为开发者空间-开发平台,通过开发平台提供的RAG和高德地图MCP的能力实现班车出行助手,从用户提供的班车时刻表知识库中获得班车的站点和时刻表信息,同时利用高德MCP查找附近的站点信息,从而实现班车时刻查询和出现建议功能。案例内容1 概述1.1 案例介绍通用大模型的训练数据覆盖广泛但侧重 “常识性知识”,且其核心能力是基于统计规律的 “生成式应答”,而非对特定领域固定信息的精准记忆和实时调用。班车表属于高度结构化、动态更新的 “专用信息”,包含具体线路、站点、发车时间、临时调整等细节,这些内容既不会被大模型完整 “记住”,也可能因数据更新滞后导致应答错误(比如模型仍输出已调整的旧时刻表)。此外,通用大模型可能为了 “流畅应答” 而对模糊信息进行 “脑补”,进一步增加错漏风险。RAG(检索增强生成)非常适合查询班车时刻表这类工作,核心在于其能高效结合 “精准检索” 与 “灵活应答” 的优势。RAG 能先从存储的时刻表数据库中快速检索出匹配用户需求(如特定线路、时间、站点)的精准信息,再通过生成模型将这些信息以自然语言的方式清晰呈现,既避免了传统数据库查询中用户需理解复杂查询逻辑的门槛,又能确保信息的准确性和时效性,完美适配班车时刻表这类对信息精准度和获取便捷性要求较高的查询场景。本案例选择使用开发者空间开发平台,通过开发平台提供的RAG和高德地图MCP的能力,实现班车出行助手,从用户提供的班车时刻表知识库中获得班车的站点和时刻表信息,同时利用高德MCP查找附近的站点信息,从而实现班车时刻查询和出现建议功能。通过实际操作,帮助开发者了解华为开发者空间开发平台的使用,并借助开发平台AI Agent工具平台,体验从知识集准备到AI应用发布开发旅程。1.2 适用对象企业个人开发者高校学生1.3 案例时间本案例总时长预计60分钟。1.4 案例流程  说明:准备班车时刻表知识集;华为开发者空间-开发平台添加高德地图MCP;华为开发者空间-开发平台创建班车出行助手Agent;发布班车出行助手Agent。1.5 资源总览本案例预计花费0元。资源名称规格单价(元)时长(分钟)华为开发者空间-开发平台 ——060 2. 班车时刻表知识集准备要使用RAG技术处理班车时刻表,最好把班车时刻表转换为半结构化的格式。下面以海淀驾校班车时刻表为例进行介绍。网上找到的班车时刻表一般是这样的:  我们可以将该数据复制后交给大语言模型,让它帮助我们转换为适合RAG处理的MARKDOWN格式,整理后的数据保存在一个文本文件中供后文使用。本案例附件中包括了一个整理好的班车时刻表(仅作为演示用,数据不全,也可能不是最新的)。3. 添加高德地图MCP3.1 添加MCP高德地图MCP Server现已覆盖12大核心接口,提供全场景覆盖的地理信息服务,包括地理编码、逆地理编码、IP定位、天气查询、骑行路径规划、步行路径规划、驾车路径规划、公交路径规划、距离测量、关键词搜索、周边搜索、详情搜索等。在开发者空间的开发者平台中找到MCP,然后从其中查找高德地图的MCP。点击“高德地图”,然后选择安装。 在安装页面中需要填入高德地图的API Key。如果没有,可以到高德地图的开发者网站免费注册并获得。  3.2 获得API Key登录 高德开放平台控制台(https://console.amap.com/),如果没有开发者账号,请注册成为开发者。   进入【应用管理】,点击页面右上角【创建新应用】,填写表单即可创建新的应用。  进入【应用管理】,在我的应用中选择需要创建 Key 的应用,点击【添加 Key】,表单中的服务平台选择【Web 服务】。  创建成功后,可获取 Key 和安全密钥。  4.  AI Agent创建并发布4.1 创建助手在华为云开发者空间开发台,进入AI Agent页面,点击Agent,点击创建Agent。   Agent配置如下:配置项内容基础信息—Agent名称班车出行助手基础信息—Agent描述专注于为用户提供精准的班车信息查询与个性化出行建议,扮演着 “高效通勤规划伙伴” 的角色。​模型选择—高级配置DeepSeek-V3-32K模型选择—思考模型DeepSeek-V3-32K角色设定角色设定你是基于 “班车时刻表”知识库运行的智能服务体,专注于为用户提供精准的班车信息查询与个性化出行建议,扮演着 “高效通勤规划伙伴” 的角色。​核心职责​精准查询服务:依托 “班车时刻表” 数据库,快速响应用户关于班车线路、发车时间、停靠站点、运行方向(去程 / 返程)、工作日 / 节假日班次差异等基础信息的查询,确保数据与数据库实时同步。​智能出行建议:结合用户查询的出发地、目的地、计划出行时间等信息,分析班车班次的时间匹配度,推荐最优乘车方案(如 “建议乘坐 7:30 去程班车,可在 8:15 抵达科技园,避开高峰拥堵”);若用户计划时间无直达班车,提供换乘建议或替代方案(如 “最近的一班直达车为 8:00,若赶时间可乘坐 7:10 班车至中途站换乘 7:40 接驳车”)。​场景化提醒:针对特殊场景主动提示,如 “明日为节假日,科技园线路仅 8:30 和 17:30 两班班车”“当前查询的 18:30 班车因道路施工可能延误 15 分钟” 等。​附近班车站点搜索:当用户提供的出发地附近没有班车站点时,自动调用高德地图插件,搜索并告知用户距离出发地最近的班车站点信息,包括具体位置、距离、步行或骑行所需时间以及前往该停靠点的路线指引。​性格特质​专业严谨:对班车时刻、线路等信息的回复准确无误,不模糊表述,若数据库中无相关信息,明确告知用户 “暂未查询到该线路信息”,而非猜测回答。​亲和贴心:采用自然、友好的交互语言,避免机械感,例如用户询问 “明天去科技园最早的车” 时,回复 “明天(6 月 10 日)去科技园的最早一班车是 7:30 哦,建议提前 10 分钟到总部停车场候车~”。​高效务实:优先直接回应核心需求,再补充辅助信息,不冗余表述,让用户快速获取关键内容。​能力边界​仅基于 “班车时刻表” 知识库及公开的通勤相关信息(如节假日安排、常规道路状况)提供服务,不涉及与班车无关的出行方式(如公交、地铁、打车等)的详细信息。​无法处理数据库未覆盖的线路、临时突发的班车取消 / 改道等未更新信息(需等数据库同步后才可响应),此类情况会提示用户 “当前信息未更新,建议联系行政部门确认”。​不具备实时定位班车位置的功能,仅能基于时刻表提供计划内的时间信息。​交互风格​语言风格:口语化、简洁化,避免专业术语,必要时使用表情符号增强亲和力(如 “😊”“🚗”),但不过度使用。​响应速度:确保 1-3 秒内给出初步回应,复杂查询(如多线路对比)不超过 5 秒。​追问机制:当用户查询信息不完整时,礼貌追问关键信息,例如用户问 “去科技园的车几点有” 时,回复 “请问你想查询的是工作日还是节假日的班次呢?另外需要去程(总部→科技园)还是返程(科技园→总部)的信息呀?”。​配置知识库,知识->知识库后的+号,点击创建知识库     知识库配置如下:配置项内容基础配置—知识库名称班车时刻表数据接入—接入方式本地上传数据接入—数据文件上传我们准备好的班车时刻表文件索引配置—向量化模型bge-large-zh-v1.5最后点击“保存并启用”完成知识库构建。回到创建Agent页面后选择刚创建的知识库。配置MCP,技能->MCP后的+号,选择我们上面添加的高德地图MCP,点击添加,点击确定。  然后我们点击保存,在Agent预览窗口进行对话测试,例如:  4.2 发布助手 助手Agent测试没问题后,可以点击右上角发布按钮进行发布。发布渠道勾选上Web Url,配置API Key。如果还没有创建发布密钥,可以点击页面中“获取API Key”超链接进行创建。然后点击发布,发布大概需要1~2分钟。  发布后,在我的Agent中的班车出行助手处点击体验按钮就可以运行发布后的版本。      至此,班车出行助手已经完成。 我正在参加【案例共创】第5期 开发者空间 AI Agent 开发  cid:link_0”
  • [技术干货] 基于华为开发者空间Astro低代码应用平台,构建Deepseek智能助手界面
    📰 案例概览🚀 背景与简介华为开发者空间是为全球开发者打造的专属云上成长空间,深度整合昇腾AI、鸿蒙、鲲鹏等华为根技术。开发者空间在HDC2025上迎来全面升级,新增AI原生应用引擎、AI Notebook、鸿蒙云手机、FunctionGraph云函数、Astro低代码等核心能力,并在算力、模型、平台、应用层实现全方位优化,助力开发者高效完成从编码到调测的全流程,打造智能AI应用开发新体验。智能助手模板是基于AI大模型定制化的智能助手解决方案,旨在为企业和开发者提供灵活、高效、智能的交互体验。通过对接先进的AI大模型,能够实现多场景、多领域的智能化应用,满足不同业务的需求,助力企业实现数字化转型和效率提升。随着AI技术的不断进步,智能助手模板将进一步扩展应用场景,为企业创造更大的价值。案例优势:智能助手模板支持无缝对接主流AI大模型,通过灵活的模型调用和优化机制,实现多场景、多领域的智能适配,满足不同业务需求。智能助手模板提供高度可定制化的前端配置能力,支持根据具体场景需求,灵活调整交互逻辑、功能模块及品牌视觉风格,打造贴合用户需求的智能化解决方案。🎯  本案例将通过华为开发者空间-低代码应用开发平台对接AI开发平台ModelArts,并以其中的DeepSeek-V3-32K服务模型为例,实现智能助手对话界面的搭建及后端功能开发。🥏 案例流程🕹️ 流程说明:领取华为开发者空间,登录华为开发者空间-低代码应用开发平台,新建低代码应用工程,进入Astro轻应用服务控制台主页,开发应用。登录ModelArts平台,领取免费服务tokens,配置DeepSeek-V3-32K服务模型。完成Deepseek智能助手低代码应用开发,发布应用。✍️ 案例实操🎉 AstroChat智能助手对话界面开发  👈👈👈  体验完整案例,点这里登录华为开发者空间-低代码应用开发平台,创建AstroChat标准应用;创建智能助手模板自定义组件:获取组件模板、上传自定义组件;登录ModelArts平台,领取免费服务tokens,获取DeepSeek模型关键参数API地址、模型名称、API Key;创建自定义连接器,设置连接器动作参数与认证信息,配置DeepSeek模型信息;创建服务编排,添加配置图元,启用服务编排;开发智能助手对话界面,设置agent-ui组件属性,测试发布智能助手应用。🌈  案例最终效果:
  • [热门活动] 校企携手共育智能时代新质人才,华为开发者名校行中南大学专场活动圆满举办
    在数字化转型纵深推进、科技创新成为产业升级核心引擎的当下,高校作为人才培育与技术创新的战略高地,与企业的深度协同已成为驱动创新的必然路径。6月26日,由华为云主办、中南大学承办的 "华为开发者名校行・中南大学专场" 活动,在中南大学麓南校区大礼堂成功举办。华为云开发者联盟与云商店部部长王希海、EDA²执行秘书长陈朗、华为云高校生态总监罗静、EDA²对外合作委员会主任郑云升带领技术专家团队走进校园,与中南大学副校长何军、电子信息学院院长邓晓衡、副院长石金晶、副书记董晶晶、计算机学院副院长夏佳志及师生代表展开深入交流。▲ 活动现场图以科技创新为抓手持续助力高校人才培养改革会议伊始,中南大学党委常委、副校长何军在开场致辞中表示,当前,全球数字经济发展方兴未艾,人工智能、云计算、大数据等新技术正在深刻改变着我们的生产生活方式。在此背景下,深化产教融合、校企合作,构建协同育人新机制,显得尤为重要。他强调道,中南大学和华为云主要聚焦在“共建人才培养新体系、共筑科技创新新高地、共享人才发展新机遇”三个维度展开合作,希望学生们勇于创新,敢于实践,努力成为具有国际视野的数字时代创新型人才,也期待教师团队能够与华为专家深入交流,将产业需求融入教学科研,共同探索信息技术领域人才培养的新模式。未来,双方将携手并进,共同为服务国家创新驱动发展战略、实现高水平科技自立自强作出新的更大贡献。▲ 中南大学党委常委、副校长 何军“高校是开发者的源头。华为云始终致力于将先进的技术与平台融入高校教学与实践,支持师生在统一开发者平台上探索创新应用。”华为云开发者联盟与云商店部部长王希海也在致辞中表示,今年6月,基于CloudMatrix384超节点的新一代昇腾AI云服务正式上线,提供强大算力以支撑复杂大模型训练与推理。同时,华为云重磅发布盘古大模型5.5,涵盖自然语言处理、多模态、科学计算等五大基础模型,全面提升知识推理与工具调用能力。中南大学作为华为在高校人才生态中的重要合作伙伴,双方已在课程共建、学生实践、智慧校园等方面开展深度合作。未来,华为云将继续携手中南大学,深化产教融合,共育支撑智能时代发展的新质生产力。▲ 华为云开发者联盟与云商店部部长 王希海华为云学生开发者计划(HCSD)作为推动高校技术人才培养与行业前沿技术接轨的重要平台,依托校园大使团队,搭建起了高校师生与华为云的深度交流桥梁,致力于为云计算领域培育储备创新型人才,助力我国数字经济高质量发展。经严格选拔,中南大学韩欣然、张海亮、高志韬、王崇尚4位同学凭借优异的学业成绩、扎实的专业素养、丰富的技术实践经验,以及对华为企业文化的高度认同,从众多候选人中脱颖而出,正式成为华为云校园大使团队成员。会上,也举行了校园大使授证仪式,中南大学党委常委、副校长何军、华为云开发者联盟与云商店部部长王希海为校园大使颁发证书。▲ 校园大使授证仪式在主题分享环节,EDA² 对外合作委员会主任郑云升带来了主题为“集成电路新生态:新挑战、新机会”的前沿分享,他表示,集成电路产业正面临着规模、复杂度和工艺的三重挑战,也迎来More Moore、More than Moore、Beyond CMOS的三维创新机遇。EDA² 通过产学研用深度合作,构建起了包含研发、创新、推广加速的三大业务板块及四大会议平台,在产品、生态、学术阵地等方面取得了0-1的突破,目标是建成可持续自演进、有竞争力的新生态。他强调道,竞争力是商业最朴素的逻辑,基于国情的创新才是最佳路径,EDA²的技术路线图有效平衡了工艺分叉下的创新路径与商业预期,并通过打造汉擎底座、标准体系及“习芯堂”教培平台,持续推动全流程全要素多元化工具链发展,也期待与相关高校院所加强合作,加速科研创新和人才培养,共建半导体产业新生态。▲ EDA² 对外合作委员会主任 郑云升深化校企合作,华为云携手伙伴绘就数字人才培养新蓝图。随着人工智能、云计算、物联网等新兴技术不断重塑产业格局,市场对具备前沿技术能力和创新思维的开发者需求愈发迫切,其培养与成长已成为推动行业进步的关键。会上,华为云DTSE开发者技术专家郭高举以“全球开发者专属空间,让每个学生拥有一台免费的云主机”为题,全面展示了华为云对开发者的支持举措,介绍华为开发者空间进行了全面升级,深度集成了鲲鹏、昇腾、鸿蒙及华为云等根生态工具与资源。此次升级以AI原生应用引擎为核心,支持一键开发AI Agent、部署MCP Server,可为开发者提供AI 时代智能应用开发体验。同时,围绕着开发者空间,华为云持续开展开发者生态运营,通过丰富的赛事与活动,让开发者相互交流和学习,持续优化开发者体验,助力开发者更高效地开发与协作。▲ 华为云DTSE开发者技术专家 郭高举低代码开发作为无需或少量编码即可快速生成应用的技术,也正成为企业数字化转型的关键工具。华为云PaaS高级工程师卢步云在主题为“低代码,高效率:解锁应用开发新技能”的演讲中分享到,华为云Astro低代码平台作为行业领先者,已汇聚10万+开发者,产出10万+应用,连续两年入选Gartner 低代码魔力象限。平台通过Astro Canvas(数据可视化大屏)、Astro Zero(零码轻应用)等模块,实现了“专业+全民”开发者融合,支持从企业核心应用到轻量化业务的全场景开发。其核心亮点包括预置360+组件、多端适配、DevOps实践及等保4级认证。华为云还提供免费试用、学习文档、视频教程等资源,助力开发者快速掌握低代码技能,已有多个大学生作品借助Astro在全国竞赛中获奖,展现了低代码技术在人才培养和产业实践中的重要价值。▲ 华为云PaaS高级工程师 卢步云值得关注的是,本次活动还特别设置了高含金量的实操环节:华为云 DTSE 开发者技术专家郭高举以云主机为底座部署DeepSeek大模型,现场指导学生完成Agent智能助手的全流程构建,从模型调优到功能封装实现手把手教学;华为云PaaS高级工程师卢步云则带领学生开展低代码实战,通过Astro平台可视化拖拽组件,助力学生快速完成从需求分析到应用部署的“全栈”AI 项目闭环。现场学生参与热情高涨,在基于昇腾算力的实时开发环境中,通过搭建智能问答系统、数据可视化看板等实操任务,掌握大模型应用开发与低代码平台的协同技术路径,切实提升了解决复杂工程问题的能力。当日下午,华为云开发者联盟与云商店部部长王希海,EDA²执行秘书长陈朗共同带领华为云高校生态团队及技术专家团队,与中南大学电子信息学院、计算机学院领导及教师代表围绕EDA人才培养、特色化示范性软件学院建设、大数据专业建设、实习实训、科研合作与教材开发等内容展开了深入交流与探讨。双方围绕如何发挥高校在教学与科研方面的优势,结合企业资源,共同推动相关专业高质量发展,达成了多项共识。▲ 教师研讨会此次活动不仅为中南大学师生搭建了与华为技术专家的深度交流平台,也促进了高校与企业在技术领域的深度融合,构建起了高校理论教学与企业技术实践的双向赋能通道。未来,华为云将以根技术生态为底座,持续开放昇腾AI云服务等核心能力,联合高校打造“课程共建-实训落地-就业衔接”的人才培养闭环,同时,华为云也将继续推动产教融合基地建设,并扮演技术赋能者与生态构建者角色,助力高校科研成果与产业需求精准对接,携手培养更多复合型人才,为我国数字经济高质量发展注入持续动能。
  • [热门活动] 【华为云学堂】云计算新手入门集证有礼,热门认证1元购
    【获奖公示】一、活动获奖公示信息如下:(1)活动期间账户积分数据见本论坛贴附件1(2)积分兑换奖品公示名单见附件2(含不符合条件用户)(3)完成云实验抽奖公示名单见附件3(含不符合条件用户)(4)邀请有礼人数公示见附件4(5)完成空间案例实操抽奖中奖公示链接:cid:link_21二、公示时间:2025年8月8日—2025年8月17日(含),若有疑问请在该时间段反馈,逾期视为放弃奖励!三、积分数据统计周期:仅统计6月30日—8月7日期间的考试数据(首次考取以上认证可参与积分),如积分数对不上请先检查是否考了重复的认证或微认证证书未生成,微认证要证书生成才核算积分。四、奖品发放:所有奖励将于活动公示期后陆续安排发放,其中本活动中的实物礼品如遇缺货等情况,将替换成类似款或其他等值礼品发放。五、积分兑换好礼(点此填写积分兑换问卷-仅可兑换1次,填写时间截止到8月12日18:00,请及时填写)六、点此填写活动满意度调查问卷 【活动时间】2025年6月30日—2025年8月7日【活动报名】立即报名【活动福利】福利1:邀请报名有礼,最高可领1000元云资源代金券;福利2:积分兑好礼,最高可兑换1000元云资源券代金券、1099元工作级开发者认证代金券福利3:完成云实验实操抽奖,抽华为手环9、定制双肩包、开发者定制冲锋衣等礼品;  福利4:完成开发者空间案例实操抽奖,抽华为智能体脂称3、定制雨伞、定制冲锋衣等礼品。【微认证1元购】序号认证名称(含购买入口)积分数价格1听歌识曲-抖音小视频背景音乐识别2282实现图片压缩及水印添加2283华为云计算服务实践2284华为云存储服务实践2285Web暴力破解漏洞挖掘2286AI智能语音识别计算器2287ModelArts实现智能花卉识别2288ModelArts实现零售商客户分群2289基于昇腾AI处理器的算子开发22810电子相册智慧整理22811微信公众号后台消息回复22812搭建Discuz论坛网站22813基于鲲鹏搭建zabbix分布式监控系统22814华为云数据库服务实践22815基于物联网平台构建智慧路灯应用22816使用低代码平台开发园区访客应用22817华为企业级JAVA编程规范22818华为云上两地三中心实践24819FunctionGraph服务入门及实战248点击前往活动页,可领取考试代金券及查看详细福利。部分奖品限量,先到先得,赶紧来参加吧!
  • [技术干货] 基于华为开发者空间 - 开发平台,构建AI会议助手
    📰 案例概览🚀 背景与简介华为开发者空间深度整合昇腾AI、鸿蒙、鲲鹏等根技术,开发者空间在HDC2025上迎来全面升级,新上线开发平台,集成了 AI原生应用引擎、AI Notebook、FunctionGraph云函数、Astro低代码四大核心能力,实现算力、模型、平台、应用层全栈优化,助力开发者高效完成编码→调测全流程,打造智能化开发体验。⚡️ AI Agent应用开发核心路径通过华为开发者空间开发平台提供的云函数(FunctionGraph)、MCP 构建、AI 原生应用引擎完成一站式 AI Agent 应用开发:创建云函数,完成 Serverless 部署——基于华为云提供的 FunctionGraph(基于 Serverless 技术)服务实现业务函数的部署构建和发布 MCP Server——基于华为开发者空间开发平台提供的模板快速构建和发布 MCP ServerAI Agent 应用开发和发布——基于 AI 原生应用引擎提供的可视化界面快速实现 AI Agent 应用的开发和发布🎯 案例选择使用华为开发者空间-开发平台,通过开发平台提供的云函数、AI Agent能力实现We码会议助手从MCP Server部署到创建AI会议Agent,再到发布使用AI 会议Agent,最后在浏览器中操作使用该AI会议Agent,实现端到端自动化会议创建等操作。🥏 案例流程🕹️ 流程说明:华为开发者空间-开发平台创建云函数,部署MCP Server代码;华为开发者空间-开发平台创建MCP;华为开发者空间-开发平台创建AI 会议Agent;发布体验AI会议Agent,成功创建WeLink会议并发送会议通知。✍️案例实操快速入门:使用MCP资产快速构建AI Agent应用 👈️👈️👈️ 原文点这里1. 华为开发者空间-开发平台安装预置的MCP;2. 构建AI Agent应用,添加安装好的MCP;3. 发布AI Agent应用并体验添加的MCP能力。通过开发平台AI原生应用引擎中提供的MCP资产和预置的的大模型,快速便捷地完成饮食推荐和12306车票助手Agent的构建和发布,轻松get华为开发者空间-开发平台中AI Agent工具的使用技巧。接下来趁热打铁,使用华为开发者空间-开发平台构建一个WeLink会议助手。实战演练:构建WeLink会议助手 👈️👈️👈️ 原文点这里1. 创建云函数部署MCP Server代码,创建触发器,生成调用URL;2. 华为开发者空间-开发平台创建MCP,以SSE的安装方式,配置云函数生成的调用URL;3. 华为开发者空间-开发平台创建AI 会议Agent,配置大模型和MCP;4. 发布体验AI会议Agent,创建WeLink会议,WeLink成功收到会议通知!!!🎉 案例最终效果
  • [案例共创] 【获奖名单已公布】【案例共创】第5期 开发者空间 AI Agent 开发
    本期获奖情况如下,代金券和礼品会发到参与活动时大家填写的这个报名问卷的账号和收货地址中,请注意查收。代金券即将发放至论坛私信(右上角我的社区-我的消息-私信中领取),礼品已在申请流程中,请耐心等待,谢谢多篇文章的本期以最高奖项的发放,不叠加。如发布3篇,2篇参与奖,1篇三等奖,按三等奖发放。主题作者帖子标题奖项胡琦【案例共创】快速搭建智搜可视化Agent二等奖黄生【案例共创】使用华为云开发者空间 AI Agent 进行昇腾C算子开发知识库构建二等奖小草飞上天【案例共创】基于华为开发者空间开发平台 MCP资产快速构建税务AI助手服务三等奖加油~加油!【案例共创】快速搭建一个智能资助小助手三等奖给无眠点压力【案例共创】 基于华为开发者空间构建「HDiet 智膳」-智能膳食 AI Agent三等奖CC07【案例共创】使用华为云开发者空间AI agent功能零基础开发一个购房助手三等奖miyalian【案例共创】基于华为开发者空间构建实时股票分析助手三等奖郑小健【案例共创】使用AI Agent进行“信息系统项目管理师”智能助手构建三等奖柠檬味拥抱【案例共创】基于华为开发者空间从0实现一个AI Agent—大学生开学指南助手三等奖yd_272483742【案例共创】基于华为开发者空间开发平台构建旅游规划助手三等奖神一样的老师【案例共创】使用开发者空间 AI Agent+RAG+高德地图MCP开发班车出行助手三等奖曹无悔开发者空间 AI Agent 开发 - 基于 Versatile AI原生应用引擎的《系统编程》智能助教参与奖熊猫钓鱼【案例共创】基于华为开发者空间快速实现一个智能家居园艺助手参与奖风亦安AI Agent应用开发 - 利用AI创建一个Slogan生成大师的小助手参与奖yd_70527782【案例共创】AI Agent应用开发 - 利用AI创建一个作业生成小助手参与奖yd_286176440基于华为开发者空间开发平台构建云端运维助手参与奖星霞云梦低代码完成政策服务助手Agent搭建参与奖 了解案例共创活动为了让更多开发者能够更轻松、更高效地理解和使用我们的文档,进而提升云产品的整体使用体验,我们致力于进一步优化和完善官方产品文档。在此过程中,我们诚挚地邀请广大开发者积极参与,通过亲身体验云产品,编写实践案例或体验评测。一旦您的案例经过专家评审团的认可与采纳,将有以下三点:优质案例将被正式收录至官方案例库,供广大开发者学习。优质案例将选送到在华为云站内外10+个技术社区推荐,给予百万级流量资源。以上案例我们都将注明原作者名字,实现与开发者共创官方文档。参与者不仅有机会获得每月活动礼品,还有可能被评为年度内容贡献官,享受更多荣誉和奖励,获得更多合作机会。我们期待着与您一起,共同打造更加优质、高效的云服务体验。参与投稿方式第1步:(已注册并实名可跳过)华为云账号实名认证,点击这里。(已设置可跳过)登录后设置社区昵称,点我设置。第2步:点击报名填写报名问卷,提供礼品发放地址等信息第3步:开启您的云端体验,分享实践案例,点我写帖子。版块选择“社区活动”分类选择“案例共创”帖子标题在前面添加【案例共创】(一定要加,方便识别参与活动的帖子)文末可添加活动名称及链接地址,如“我正在参加【案例共创】第5期 开发者空间 AI Agent 开发  cid:link_23”【如您在体验中有任何产品问题,欢迎在论坛发布问题求助帖(帖子分类选择问题求助)咨询产品专家,如发现任何体验不友好、产品Bug、文档页面错漏等情况,欢迎通过云声平台反馈给我们,还有机会领取云声专属礼品!活动相关咨询可以论坛私信“论坛小助手SUN”】本期投稿内容Ø  华为云产品介绍:华为开发者空间AI Agent:AI原生应用引擎提供企了包括数据准备、模型选择/调优、知识工程、模型编排、应用部署、应用集成等能力,降低智能应用开发门槛、提升开发效率。华为开发者空间的AI Agent集成Versatile空间,Versatile空间是通用型AI助手和领域专家Agent的智能协同工作空间,通过自主任务规划及多工具协同,实现复杂任务的智能化处理,从而提升工作效率。领取链接:cid:link_2 AI Agent页面操作文档:cid:link_1云函数页面操作文档:cid:link_0Ø  应用构建要求开发者可结合自己的工作实践,须在华为开发者空间内完成应用构建,应用构建类型和主题参考如下:AI Agent应用开发 主题场景包括但不限于以下方向(仅做参考):使用AI Agent进行专业领域知识库构建(进行组织、存储及管理知识);咨询快捷助手(推荐助手等);工作流规划规划(使用工作流规划行程等); 案例模版参考:1. AI Agent应用开发:- 1)案例地址:cid:link_3简介:使用开发者空间开发平台,通过开发平台AI原生应用引擎中提供的MCP资产和预置的的大模型,快速便捷地完成饮食推荐和12306车票助手Agent的构建和发布。- 2)案例地址:cid:link_4简介:使用华为开发者空间-开发平台,通过开发平台提供的云函数、AI Agent能力实现We码会议助手从MCP Server部署到创建AI会议Agent,再到发布使用AI 会议Agent,最后在浏览器中操作使用该AI会议Agent。注意:请大家一定要按照案例模版的格式进行编写注意:请大家一定要按照案例模版的格式进行编写注意:请大家一定要按照案例模版的格式进行编写Ø  投稿规则1)构建的应用需要完成发布,有应用在线截图。2)案例场景和方案以及用到的华为云产品或者开源框架简述。3)开发过程实际操作描述(文字描述+截图+代码)。4)案例实操需要完整体现,读者可根据案例上手并体验。  活动流程(全年征集,每月一期评选)投稿时间:2025年7月1日-7月31日联合评审:2025年8月1日-8月9日奖项公示:2025年8月10-11日奖品发放:获奖名单公布后15个工作日内寄出 评奖规则届时将有华为技术专家团参与评审,主要按照以下维度评分:标准类型分值释义分值阶梯总分值操作完整性关键节点以文字+截图的形势进行说明1:空间的实践操作,而非方案类描述2:参考官方提供模版,可读性好,有关键节点文字说明与截图3:符合2的条件下能够突出关键代码释义以及关键步骤解释说明4:应用构建后可执行,并有执行后效果介绍和展示1-4/0.5梯度4案例实用性贴近实际行业生产或者业务场景1:纯技术应用不涉及实际应用场景,比如接入模型后的问答助手2:基于实际应用场景具有一定的实用性3:基于实际场景且在开发者空间完成部署实施4:基于实际应用场景解决行业的痛点问题,可用于生产实施1-4/0.5梯度4技术多样性案例中应用更多的华为云技术或主流开源框架1:使用活动中要求的空间以及工具或者技术2:基于空间结合更多的华为云技术/服务、开源框架或技术1-2/0.5梯度2荣誉与奖励1、获奖案例将有机会作为华为云开发者空间应用的标杆案例,进行录入成册推广宣传,并发布到华为云开发者联盟公众号传播矩阵。同时,案例内容可作为后续作者申请评选HCDE的相关贡献内容。标杆案例:【华为开发者空间 · 案例共创故事(郑州轻工业大学)】(https://mp.weixin.qq.com/s/pPmPcdlWYLPalzJPqxIfew) Ø  奖项设置 文章类奖项:视频案例奖项:一等奖1个,1000元实物,华为sound joy 音箱;  二等奖3个,华为6i耳机;三等奖10个,礼品+代金券注:每期评审专家根据每篇文章评选文章分数及等级,每期文章质量不一,不排除有某个奖项轮空的情况,如第X期文章质量在A级和B级,即S和S+级轮空。代金券及周边礼物发放对象为:已完成实名认证的华为云用户。发放到填写报名问卷的账号及收货地址中,礼包类礼品均为实物礼品。 重要说明1、投稿内容一经采用,将会被纳入官方产品文档,文章作者拥有著作权,华为云拥有使用权、修改权等。2、每期评审专家根据每篇文章评选文章分数及等级,每期文章质量不一,不排除有某个奖项轮空的情况,如第X期文章质量在A级和B级,即S和S+级轮空3、投稿内容字数不少于500字(不含代码),要求思路清晰、文字顺通、图片清晰、代码规范,不得有打广告、加二维码引流和凑字数行为。4、文章要求发布在华为云开发者社区论坛,允许搬运自己发在其他平台的文章,但仅支持搬运自己的原创文章,搬运他人的文章当抄袭处理。内容必须保证内容原创性,实践过程真实、内容代码化,如发现投稿内容为转载、复制、抄袭、恶意拼接、灌水等侵权作弊行为,均视为无效并取消参与资格5、将发表过的文章删除后重新发表的文章,不计入发文数量,以文章评选时在线显示数量为准。活动期间,如有用脚本刷阅读量、注册僵尸号刷赞等严重违反社区规范的行为,直接取消所有获奖资格。6、审核通过被采纳的文章作者,将在下月初进行获奖名单公布和奖励发放,届时会有站内信通知,请及时关注并填写快递信息,过期未核对或填写视为放弃该期奖品。7、对于持续输出高质量内容的作者,每年度末还有年度贡献大礼包送上。特别声明:华为云有权根据自身运营安排,自主决定和调整
  • [热门活动] 礼品已邮寄//【体验有礼】华为开发者空间新特性体验,华为手环、云宝礼盒等你来抽
    本期华为开发者空间【体验有礼】活动获奖名单如下,请获奖用户8月29日前反馈收件信息,奖品将于9月初寄出  活动一【体验打卡】获奖清单活动二【实践互动】获奖清单__________________________________________________________________________________________________________________    在6月20日华为开发者大会上,开发者空间宣布全部升级,新功能集成了AI原生应用引擎、AI Notebook、FunctionGraph云函数、云开发环境、Astro低代码等能力,基于这些全新特性,开发者在开发者空间可以开通大模型服务、部署MCP Server、创建Agent等各位小伙伴是不是已经跃跃欲试了?小编特意准备新功能体验打卡活动,更有华为手环、云宝礼盒等你来抽,快叫上小伙伴一起来体验吧~ 【活动时间】即日起—7月31日 【活动流程】完成报名 → 选择活动方式 → 参与活动 → 获得激励 【活动方式】(以下活动均可参与,奖励可叠加)活动一【体验打卡】:体验打卡开发者空间新功能,参与开发者定制礼品抽奖参与方式:活动期间,进入开发者空间,体验空间各项新能力,比如开发平台(AI Agent、低代码应用、云开发环境、云函数)、学习成长、知识推荐、学习笔记、应用构建等,活动结束后将在参与活动报名并在活动期间登录名单中抽奖。奖项设置:开发者定制双肩包*2个,开发者定制短袖T恤*10个 活动二【实践互动】:完成开发者空间“开发平台”新功能案例体验,抽取华为手环参与方式:选择下方任意一个或多个案例进行体验,并在评论区分享案例截图(也欢迎书写你对案例实践后的体验和感受),活动结束后,将在评论区用户中抽奖。体验功能案例名称难度系数AI Agent基于华为开发者空间开发平台 MCP资产快速构建AI Agent应用★★★AI Agent、云函数基于华为开发者空间开发平台构建We码会议助手★★★★Astro低代码应用基于华为开发者空间Astro低代码应用平台,构建业务用户登录后台开发★★★★基于华为开发者空间Astro低代码应用平台,构建业务用户登录页面前台开发★★★★云开发环境开发者空间 - 云开发环境使用指导★★★本地Xshell基于华为开发者空间云开发环境完成上传下载★★★奖项设置:华为手环9(NFC款)*2个,华为云云宝礼盒款*3个,开发者定制短袖T恤*15个中奖小妙招:完成多个案例,会增加中奖概率!完成后请在回帖中注明完成了几个案例,以及案例名称。小编会对案例完成情况进行复核,请大家真实完成哦! 部分礼品示意 PS:完成案例的小伙伴可以继续参加开发者空间案例共创第五期活动,如在使用中有产品优化建议,可参与开发者空间产品体验官活动,更多礼品等你解锁~【活动规则】1、抽奖方式:活动结束后,我们将从参与活动的用户中(华为云新老用户均可参与),通过巨公平台或Excel 函数形式抽取获奖用户。获奖名单将在活动结束后的7个工作日内公布。2、活动二仅限于在“华为开发者空间”内体验相关案例项目,其他项目建议不参与此次活动,否则视为无效内容,具体参考案例中心内容。另外活动将根据有效评论数设置获奖人员数量,规则如下:有效评论数量获奖名额105201030以上213、本次活动将根据实际参与情况发放奖励,包括但不限于用户百分之百中奖或奖项轮空的情况。【活动说明】用户限制说明:1、参加本次社区活动的用户必须为华为云注册用户。同时为保证活动公平性,禁止用户以IAM账号身份参与活动,否则将视为无效。2、领取奖品的用户需为华为云实名用户,未完成实名认证的用户将不发放活动奖励。3、本次活动如一个实名认证对应多个账号,只有一个账号可领取奖励。如在同一概率活动中,同一账号重复获奖,只发放首先获奖奖品。4、本次活动一个实名认证账号只能对应一个收件人,如同一账号填写多个不同收件人,不予发放奖励。5、请开发者不要在活动期间随意修改社区昵称和华为云账号,由此产生的统计问题,如过了申诉期,小助手不再处理。(申诉期为活动结果公示3天内。)奖品发放说明:1、本活动结束之后10个工作日内公示获奖信息,获奖开发者用户需在截止时间在获奖信息收集表中填写获奖信息,获奖信息截止收集日过后10个工作日内,将统一发出奖品。华为云遵守《中华人民共和国个人信息保护法》规定,将以上个人信息仅用于礼品发放之目的,不会向任何第三方披露。若由于获奖开发者用户自身原因(包括但不限于联系方式有误、身份不符或超过截止登记日期等)造成奖品无法发送,视为获奖开发者用户放弃领奖。2、为保证活动的公平公正,华为云有权对恶意刷活动资源(“恶意”是指为获取资源而异常注册账号等破坏活动公平性的行为),利用资源从事违法违规行为的开发者用户收回抽奖及奖励资格。3、若发放奖品时,出现库存不足,则优先发放等价值的其他实物奖品;HDC限定礼包为24/25年款随机发货;活动二中华为耳机需要在有效评论>40个开启。4、所有参加本活动的开发者用户,均视为认可并同意遵守《华为云开发者用户协议》,包括以援引方式纳入《华为云开发者用户协议》、《可接受的使用政策》、《法律声明》、《隐私政策声明》、相关服务等级协议(SLA),以及华为云服务网站规定的其他协议和政策(统称为“云服务协议”)的约束。5、如果您不同意本活动规则和云服务协议的条款,请勿参加本活动。
  • [热门活动] 【中奖名单公示】///【产品体验官】华为开发者空间开发平台全新上线,提优化建议领千元开发者好礼
     【华为开发者空间开发平台】产品体验官活动获奖名单如下:一、有效建议奖:昵称建议分值奖项礼品yd_2846377506.9有效建议奖第一名1000元开发者定制礼品banjin4.4有效建议奖第二名800元开发者定制礼品胡琦2.1有效建议奖第三名500元开发者定制礼品二、优质建议奖:昵称礼品yd_284637750100-200元开发者定制礼品banjin100-200元开发者定制礼品胡琦100-200元开发者定制礼品小草飞上天100-200元开发者定制礼品神一样的老师100-200元开发者定制礼品给无眠点压力100-200元开发者定制礼品yd_70527782100-200元开发者定制礼品yd_269585276100-200元开发者定制礼品yd_238822659100-200元开发者定制礼品cxw100-200元开发者定制礼品andyleung100-200元开发者定制礼品 恭喜以上11名获奖用户,请获奖用户通过以下问卷反馈奖品收件信息(9月3日前反馈有效),感谢大家对云声平台的关注和支持~华为开发者空间全新升级,开发平台重磅上线。此次开发平台集成了AI原生应用引擎、FunctionGraph云函数、Astro低代码、云开发环境能力,在算力、模型、平台和应用层都进行了大升级。基于这些全新特性,企业开发者可以在开发者空间开通大模型服务、部署MCP Server、创建Agent、可视化实现业务需求,从而快速开发上线一个企业级 AI 智能应用,让华为云和根生态技术的能量触达到每位开发者的指尖!大家赶快来体验吧,体验完后提交开发者空间优化建议,还可以领取开发者礼包,包括但不限于华为耳机、手环、鼠标、云宝等好礼,快叫上小伙伴一起提建议吧~ 【实践项目】体验项目项目名称难度系数功能体验开发平台:AI Agent/开发平台:低代码应用/开发平台:云函数 /开发平台:云开发环境/案例体验基于华为开发者空间Astro低代码应用平台,构建业务用户登录后台开发★★★★基于华为开发者空间Astro低代码应用平台,构建业务用户登录页面前台开发★★★★基于华为开发者空间开发平台 MCP资产快速构建AI Agent应用★★★基于华为开发者空间开发平台构建We码会议助手★★★★开发者空间 - 云开发环境使用指导 ★★★本地Xshell基于华为开发者空间云开发环境完成上传下载 ★★★详细信息请见“开发平台”,案例中心。 【活动时间】2025年7月1日-7月30日 【参与方式】01 体验开发者空间开发平台   》   02 去云声平台提建议    》  03 建议评估公示  》   04 获奖公示(活动结束后两周内) ps:建议标题需要以“开发者空间体验官”开头 【奖项设置】奖项设置评选条件获奖名额激励礼品有效建议奖1、有效建议数量不少于2条,有效建议由内部技术专家评审得出2、建议内容需针对上述实践项目3、有效建议中有不低于一条是关于功能体验的3名积分榜第1名:1000元礼品/人积分榜第2名:800元礼品/人积分榜第3名:500元礼品/人优质建议奖1、有效建议不少于2条,由内部技术专家评审选出10名每人100-200元开发者定制礼品【活动说明】1、建议预审通过即为有效建议,其中1条有效功能类建议为1分,1条有效体验类建议为0.3分,1条有效Bug类建议0.5分;有效建议奖与优质建议奖可叠加2、建议提交时需要在标题中以“【开发者空间体验官】”为建议标题开头,比如【开发者空间体验官】开发者空间增加XX/优化XX/导入XX等3、建议内容仅针对以上实践项目中“开发平台功能体验+开发平台案例体验”涉及的云产品,非以上实践项目涉及产品建议内容不参与此活动4、优质建议要求建议对云产品功能及优化改进有重要作用,优先从已被采纳的建议的选择;建议内容需要表述清晰,有明确的建议方案,最好有操作截图或链接等能进一步详细描述;高价值建议数量不限,且与有效建议奖可叠加,每位用户每月最多可获得一次。5、注意事项1)若出现积分相同且排名一致的情况,结合已实现和已采纳建议情况,由内部技术专家选出价值更高的建议用户给予奖励2)同一用户在同一页面(文档)提出的同一类用户体验问题(包括但不限于错别字、语句不通顺、视觉体验等),在通过审核后仅算作一条有效建议数3)若发现代他人提交优化建议,此建议分值只取原分值30%;若发现2次及以上重复提交他人建议,或3次及以上重复提交体验类相关建议进行恶意刷量(包括但不限于错别字、语句不通顺、视觉体验等),取消本人活动参与资格;在活动截止日前进行大量刷屏提交建议,或者重复提交同类型体验建议,直接取消活动参与资格4)以上兑换礼品均为仓库现有实物礼品,有货的情况下优先满足,其中1-3名可优先选择华为自营品牌电子礼品,礼品价值不能超过商品原价,无货则不可以指定,如遇商品缺货,将随机换成其他等价值礼品发放5)此【开发者空间体验官】与云声月度例行激励活动不叠加,若标题无【开发者空间体验官】标记,则有效建议默认参与月度例行激励
  • [云实验室] 云计算新手入门集证有礼
    完成时间: 2025-07-01 10:35:00案例名称: 初识云主机:CodeArts IDE入门案例完成截图:实验心得: 实验非常有趣,让我初步了解 python 和 codearts ide 的使用,而且居然还有一个云电脑能用,实验完成之后还能继续使用,真是太棒了
  • [案例共创] 【案例共创】基于华为开发者空间从0开始完成仓颉编程语言与Python的互操作
    本文基于当前仓颉通用版 (0.53.18) 进行开发演示,该版本对Linux平台提供Python FFI支持。文中的所有操作均在华为开发者空间的云主机中进行。关于Python FFI的更多说明,请参阅仓颉官方文档使用指南 -  ://docs.cangjie-lang.cn/docs/0.53.18/user_manual/source_zh_cn/FFI/cangjie-python.htmlAPI 文档  -  ://docs.cangjie-lang.cn/docs/0.53.18/libs/std/ffi_python/ffi_python_package_overview.html需要额外说明的是,截至2025年6月,仓颉尚未发布LTS版本,鸿蒙仓颉尚未提供Python FFI支持。。因此,Python FFI功能在0.53.x后续Canary版本中的变动不在本文讨论范围内。补充更新:2025年7月1日发布的仓颉(通用版)LTS1.0移除了Python FFI。0. 初始化开发者空间的云主机进入开发者空间 (cid:link_0),系统选择Ubuntu,这样可以确保预装了Python、Cangjie、以及对应的CodeArts IDE。华为云空间提供完整的开发环境。打开云主机,初始化后进入云桌面,可以通过终端命令行指令检查系统当前的 Cangjie 和 Python 版本。问🤔:什么是云主机?答🤓:云主机是开发者空间众多功能的其中之一,而云桌面是云主机默认的登录方式,此外还有无图形界面的云终端形式。1. 创建项目虽然云主机自身提供一定程度的数据持久化功能,但为了更好管理自己的代码,我们需要一个完善的流程来管理项目代码,避免意外情况造成的数据丢失。云桌面上的CodeArts IDE非常贴心地提供了完整的GitCode服务支持,此处我们可以通过点击云桌面上的GitCode快捷方式,在云主机的Firefox浏览器中访问GitCode网站。💡tips: 考虑到云主机的计算资源有限,不建议在复杂场景下高强度使用云主机内置的浏览器,同样的需求可以在外部浏览器中得到满足。GitCode的注册非常简单,此处过程省略。打开CodeArts IDE for Cangjie,其界面应如下所示:1.3 导入工程为方便后续操作,这里选择 导入GitCode 工程 。接下来我们需要获取登录令牌,在登录GitCode之后,可以根据链接指示进行操作。下图是手动创建登录令牌的界面参考,主要需要关注的是有效期和权限设置。注:熟悉云主机功能的开发者可能有注意到一个叫作同步项目的功能。这个功能的原理和上面的手动配置操作类似,区别在于同步项目需要自己手动关联华为云账号和GitCode账号;其次它目前有一个缺点,每次同步都会创建新的项目目录,此处手动配置token正是为了避免这个问题。1.1 创建代码仓库因为本文的预设前提是从0开始,故此处选择创建一个空项目,勾选初始化README。创建时需要留意 .gitignore文件 和 LICENSE 这两个文件的选择。初始化创建新项目后,切回 CodeArts IDE,选择刚创建的项目。1.1 初始化仓颉项目新建空仓库后可通过终端命令 cjpm new 完成项目初始化,通过 cjpm run 测试初始化项目运行结果。看到hello world即说明仓颉开发环境能够正常工作,在开始Python FFI代码编写前,我们通过Git提交代码完成项目的初始化。2. 在仓颉中调用Python函数2.2 指定libpython动态库位置仓颉的Python FFI默认只提供动态链接库的位置检测支持,动态库加载策略如下图所示:由于云主机预装的Python 3.12是不满足第二种查找策略的两点要求,若直接执行以下示例代码,则会报错退出:import std.ffi.python.*import std.log.*main(): Int64 { Python.load(loglevel: LogLevel.INFO) print("${Python.getVersion()}\n") Python.unload() return 0}为了解决这个问题,我们可以通过指定 PYTHON_DYNLIB 环境变量,强制仓颉运行时使用策略1进行动态库加载:export PYTHON_DYNLIB=$(find $(python -c 'import sysconfig as s;print(s.get_path("stdlib"))') -name 'libpython*' 2>/dev/null)也可以通过仓颉的子进程调用完成这个操作:// import std.io.* // import std.os.* // import std.os.process.* func pylib_path(config!: Bool = false): String { const PYEK = "PYTHON_DYNLIB" if (let Some(ev) <- getEnv(PYEK)) { return ev } let p = Process.start("bash", "-c", ##"find $( python3 -c \ 'import sysconfig as s; print(s.get_path("stdlib"))' ) \ -name 'libpython*' 2> /dev/null "##, stdOut: ProcessRedirect.Pipe) let rv = StringReader(p.stdOut).readToEnd() if (config) { setEnv(PYEK, rv) } return rv }2.1 调整仓颉运行时栈大小由于 Python 互操作使用到大量 Python 库的 native 代码,这部分代码在仓颉侧无法对其进行相应的栈保护。仓颉栈保护默认大小为 64KB,在对 Python C API 进行调用过程中,容易造成 native 代码超出默认栈大小,发生溢出,会触发不可预期的结果。建议用户在执行 Python 互操作相关代码前,配置仓颉默认栈大小至少为 1MB:export cjStackSize=1MB 3. 在仓颉中调用Python3.1 导入模块3.2 执行代码
  • [案例共创] 【案例共创】基于仓颉 + DeepSeek + MCP 的智能膳食分析助手
    基于仓颉 + DeepSeek + MCP 的智能膳食分析助手一、项目背景及需求分析1.1 项目背景随着人们对健康饮食关注度的提升,越来越多用户希望借助 AI 助手实现个性化的饮食分析与管理。然而,目前市面上的饮食类应用普遍存在如下痛点:1️⃣. 缺乏智能分析:大多数仅记录卡路里,无法提供专业点评与优化建议;2️⃣. 知识更新不及时:难以结合最新营养研究进行推荐与判断;3️⃣. 缺乏可扩展性:难以适配特定人群(如高血压、糖尿病、健身人群等)的差异需求。本项目旨在构建一个基于大语言模型(DeepSeek)和结构化协议(MCP)的智能饮食健康助手,通过自然语言交互,帮助用户实现饮食数据结构化、健康风险识别与个性化建议生成。1.2 核心需求1️⃣ 食品实体识别能力系统应具备从自然语言中准确识别出饮食相关的食品实体与关键词的能力。例如,用户输入:“我今天吃了煎饼果子、卤牛肉、奶茶”,系统应能够自动识别出食品列表:["煎饼果子", "卤牛肉", "奶茶"] 该能力是后续营养分析与健康判断的基础,应支持中文短语、多食物组合、模糊词等多种表达方式。2️⃣ 饮食结构化分析能力(MCP 中间层处理)系统应通过 MCP 模块完成对用户输入饮食内容的语义解析与结构化处理,主要包括:应提取食品清单;应识别饮食行为时段(如早餐、晚餐、夜宵等);应对识别出的食物打上健康标签(如高糖、高油脂、高钠、低纤维等);应构造符合 LLM 输入规范的 Prompt,以支撑后续模型理解与生成。结构化分析结果应作为 DeepSeek 模型调用的核心中间数据。3️⃣ 合理饮食建议生成能力(基于 DeepSeek)系统应利用 DeepSeek 大模型,根据 MCP 构造的 Prompt 生成具有科学性、专业性与可操作性的饮食建议,具体应包括:对当前饮食存在的健康风险进行分析(如糖分摄入超标、缺乏蔬菜等);提供可替代食材建议(如炸鸡 → 烤鸡,奶茶 → 绿茶);给出搭配优化方案(如餐前饮水、搭配高纤维蔬菜等);提出个性化提示(如适合三高人群、健身人群、孕期饮食等)。模型输出应以自然语言形式呈现,逻辑清晰、结构明确,风格应贴近真实营养师表达方式。二、项目概述本项目旨在构建一套基于多模块协作的 智能膳食分析助手,通过自然语言输入,实现对个人饮食行为的结构化分析与健康建议生成,服务于日常健康管理、饮食优化与疾病预防等场景。系统采用模块化设计,主要由三大核心组成部分构成:2.1 技术选型模块技术栈职责🧑‍💻 客户交互仓颉语言提供终端或界面交互入口,接收用户自然语言输入并展示模型生成结果🔧 中间处理MCP 模块(Python + FastAPI)实现饮食语义解析、食物识别、健康标签打标、Prompt 生成与请求路由🤖 模型服务DeepSeek 大语言模型接收经过标准化构造的请求 Prompt,返回结构化营养建议、健康分析与饮食优化建议2.2 适用对象企业健康服务平台产品经理个人开发者高校学生营养师/健身爱好者病患群体2.3 案例时间环境配置:约30 分钟构建项目:约25分钟测试阶段:约10 分钟本案例总时长预计 65 分钟。2.4 项目流程整个系统的数据处理与响应流程如下所示:2.5 资源总览本案例预计花费 0 元。资源名称规格免费额度/价格开发者空间–云主机2CPU4g X86 Ubuntu 22.04 Server定制版0元CodeArts IDE for CangjieIDE 仓颉 云主机预装0元CodeArts IDE for PythonIDE Python 云主机预装0元Maas DeepSeek 模型服务试用200W Token0元2.6 架构亮点✅ 使用 MCP 解耦输入处理与模型调用,提升可扩展性与灵活性;✅ DeepSeek 专注自然语言生成任务,MCP 预处理提高 prompt 精度;✅ 仓颉终端可后续拓展为图形界面、Web 应用或移动端入口;✅ 本地配置与食物字典可按需调整,适配多种用户类型(如减脂、控糖、健身等);✅ 架构支持多模型/多来源接入,可拓展至 Claude、SparkDesk、ChatGPT 等后端模型。三、环境准备3.1 申请云主机面向广大开发者群体,华为开发者空间提供一个随时访问的“开发桌面云主机”、丰富的“预配置工具集合”和灵活使用的“场景化资源池”,开发者开箱即用,快速体验华为根技术和资源。如果还没有领取开发者空间云主机,可以参考免费领取云主机文档领取。领取云主机后可以直接进入华为开发者空间工作台界面,点击进入桌面连接云主机。3.2 免费领取DeepSeek R1满血版华为云提供了单模型200万免费Tokens,包含DeepSeek-R1&V3满血版,我们可以登录华为云ModelArts Studio(MaaS)控制台领取免费额度,这里我们选择DeepSeek-R1满血版来搭建我们的专属AI聊天机器人。在云主机桌面底部菜单栏,点击打开火狐浏览器。用火狐浏览器访问ModelArts Studio首页:cid:link_2,点击ModelArts Studio控制台跳转到登录界面,按照登录界面提示登录,即可进入ModelArts Studio控制台。签署免责声明。进入ModelArts Studio控制台首页,区域选择西南-贵阳一,在左侧菜单栏,选择在线推理 > 预置服务 > 免费服务,选择DeepSeek-R1-32K模型,点击领取额度,领取200万免费token。领取后点击调用说明,可以获取到对应的API地址、模型名称。红色方块为API 地址 红色箭头为 API KEY四、项目构建本案例采用 本地MCP 服务+ 本地仓颉AI机器人对话 (参考来自于 (https://gitcode.com/CaseDeveloper/Cangjie-Examples)4.1 MCP 服务构建4.1.1 打开 CodeArts IDE for Python4.1.2 新建项目项目名称 构建为: food_mcp 然后点击 创建4.1.3 代码实施mcp_server.py# -*- coding: utf-8 -*- # mcp_server.py """基于仓颉 + DeepSeek + MCP 的智能膳食分析助手""" from fastapi import FastAPI from pydantic import BaseModel import json from typing import List, Dict, Any from fastapi.responses import StreamingResponse from deepseek_client import stream_deepseek, async_stream_deepseek from text_match import extract_food_simple, extract_food from loguru import logger from cachetools import TTLCache import sys # 加载食物字典 with open("food_tags.json", encoding="utf-8") as f: FOOD_TAGS: Dict[str, Dict[str, Any]] = json.load(f) app = FastAPI() class Input(BaseModel): input: str # 全局缓存:prompt -> full_reply_text CACHE = TTLCache(maxsize=500, ttl=1800) # 30分钟自动过期 logger.remove() logger.add(sys.stdout, level="INFO", enqueue=False, backtrace=False) # ---- 基础角色词 ---- BASE_SYSTEM_PROMPT = ( "你是一名资深注册营养师,擅长以简洁的 Markdown 格式给出科学、可执行的饮食建议。" "所有回答需包含以下小节:\n" "1. 总体评价\n" "2. 推荐摄入(量/食材)\n" "3. 过量风险\n" "4. 不宜同食\n" "5. 行动建议\n" "回答请使用中文,并尽量在 300 字以内。" ) # ---- 场景化模板 ---- PROMPTS = { "nutrition_review": ( BASE_SYSTEM_PROMPT + "\n\n【场景】饮食点评。请先总体评价,再按上表 1~5 小节输出:{input}" ), "diet_plan": ( BASE_SYSTEM_PROMPT + "\n\n【场景】减脂期餐单。请输出 3 日食谱 (表格形式),并在每餐注明热量估计:{input}" ), "effects_inquiry": ( BASE_SYSTEM_PROMPT + "\n\n【场景】过量影响。请列出已知副作用及参考文献:{input}" ), "avoid_inquiry": ( BASE_SYSTEM_PROMPT + "\n\n【场景】相克查询。请说明不宜同食原因及替代方案:{input}" ), } def _process_input(user_input: str): """内部共用逻辑,返回分析结果和 prompt""" # === 1. 食物关键字匹配 === food_list, exact_hits, fuzzy_hits = extract_food(user_input, FOOD_TAGS.keys()) # 记录匹配详情到日志 logger.info(f"[匹配] 精确={exact_hits} 模糊={fuzzy_hits}") # === 2. 聚合静态信息 === tags = list({tag for food in food_list for tag in FOOD_TAGS[food].get("tags", [])}) effects = {food: FOOD_TAGS[food].get("effects") for food in food_list if FOOD_TAGS[food].get("effects")} avoid_with = list({aw for food in food_list for aw in FOOD_TAGS[food].get("avoid_with", [])}) diet_type = list({dt for food in food_list for dt in FOOD_TAGS[food].get("diet_type", [])}) # === 3. 根据关键词判定 mode === mode = "nutrition_review" if any(k in user_input for k in ["减肥", "减脂", "低卡", "少油", "瘦身", "个人食谱"]): mode = "diet_plan" elif any(k in user_input for k in ["吃多了", "过量", "上火", "副作用", "影响"]): mode = "effects_inquiry" elif any(k in user_input for k in ["不能一起", "相克", "不宜同食", "一起吃"]): mode = "avoid_inquiry" new_prompt_base = PROMPTS[mode].format(input=user_input) # === 4. 拼接静态附加信息 === notes = [] if effects: notes.append("【过量风险】" + ";".join(f"{food}:{desc}" for food, desc in effects.items())) if avoid_with: notes.append("【不宜同食】" + "、".join(avoid_with)) extra_info = ";".join(notes) if extra_info: new_prompt_base += ( "\n\n以下为已知静态信息(请务必先列出【过量风险】与【不宜同食】两个小节,并完整引用下列内容,否则视为回答不完整):" f"{extra_info}" ) # 要求模型以 JSON 输出,配合 response_format new_prompt = new_prompt_base + "\n请使用 markdown bullet list 输出建议。" return { "food_list": food_list, "tags": tags, "effects": effects, "avoid_with": avoid_with, "diet_type": diet_type, "mode": mode, "routed_input": new_prompt, } @app.post("/mcp") async def route_prompt(data: Input): user_input = data.input result = _process_input(user_input) return result @app.post("/mcp_stream") async def route_prompt_stream(data: Input): user_input = data.input result = _process_input(user_input) async def event_generator(): meta_json = json.dumps({k: v for k, v in result.items() if k != 'routed_input'}, ensure_ascii=False) # 发送 Meta 事件 yield f"event: meta\ndata: {meta_json}\n\n" prompt_key = result["routed_input"] # 若缓存命中,直接按20字符切片发送缓存内容 if prompt_key in CACHE: logger.info("[缓存] 命中") cached_text = CACHE[prompt_key] # SSE data 行不能包含裸换行,需逐行加前缀 payload_lines = [f"data: {line}" for line in cached_text.split("\n")] payload_block = "\n".join(payload_lines) yield f"event: token\n{payload_block}\n\n" yield "event: done\ndata: [DONE]\n\n" return logger.info("[缓存] 未命中") collected_chunks = [] async for chunk in async_stream_deepseek(prompt_key): collected_chunks.append(chunk) yield f"event: token\ndata: {chunk}\n\n" # 缓存完整内容 full_text = "".join(collected_chunks) CACHE[prompt_key] = full_text # 结束事件 yield "event: done\ndata: [DONE]\n\n" return StreamingResponse(event_generator(), media_type="text/event-stream") deepseek_client.py# deepseek_client.py # 基于 DeepSeek API 的客户端 import requests import json from typing import Generator import httpx # 从 config.json 读取配置 with open("config.json", encoding="utf-8") as f: config = json.load(f) DEEPSEEK_API_KEY = config["DEEPSEEK_API_KEY"] DEEPSEEK_URL = config["DEEPSEEK_URL"] MODEL_NAME = config["MODEL_NAME"] def call_deepseek(prompt): headers = { "Content-Type": "application/json", "Authorization": f"Bearer {DEEPSEEK_API_KEY}" } payload = { "model": MODEL_NAME, "messages": [ {"role": "user", "content": prompt} ] } response = requests.post(DEEPSEEK_URL, headers=headers, json=payload) result = response.json() return result["choices"][0]["message"]["content"] # 新增:流式推理生成器 def stream_deepseek(prompt) -> Generator[str, None, None]: """Yield generated content chunks from DeepSeek API using SSE.""" headers = { "Content-Type": "application/json", "Authorization": f"Bearer {DEEPSEEK_API_KEY}" } payload = { "model": MODEL_NAME, "messages": [ {"role": "user", "content": prompt} ], "stream": True, "max_tokens": 2048, "stream_options": {"include_usage": True}, } # 使用 stream=True 触发增量输出 response = requests.post(DEEPSEEK_URL, headers=headers, json=payload, stream=True) # iter_lines 将保持连接并逐行读取 for line in response.iter_lines(decode_unicode=True): if not line: continue # DeepSeek/SSE 行以 "data: " 开头 if line.startswith("data: "): data_str = line[6:] # 结束标志 if data_str.strip() == "[DONE]": break # 解析 JSON,获取增量内容 try: data_json = json.loads(data_str) # usage 块 choices 为空,跳过 choices = data_json.get("choices", []) if not choices: continue delta = choices[0]["delta"].get("content", "") if delta: yield delta except json.JSONDecodeError: # 忽略无法解析的片段 continue # 异步流式生成器 async def async_stream_deepseek(prompt): """异步生成器,从 DeepSeek API 生成内容(SSE)。""" headers = { "Content-Type": "application/json", "Authorization": f"Bearer {DEEPSEEK_API_KEY}" } payload = { "model": MODEL_NAME, "messages": [ {"role": "user", "content": prompt} ], "stream": True, "max_tokens": 2048, "stream_options": {"include_usage": True}, } async with httpx.AsyncClient(timeout=None) as client: async with client.stream("POST", DEEPSEEK_URL, headers=headers, json=payload) as resp: async for line in resp.aiter_lines(): if not line: continue if line.startswith("data: "): data_str = line[6:] if data_str.strip() == "[DONE]": break try: data_json = json.loads(data_str) choices = data_json.get("choices", []) if not choices: continue delta = choices[0]["delta"].get("content", "") if delta: yield delta except json.JSONDecodeError: continue test_pipeline.py# -*- coding: utf-8 -*- # test_pipeline.py import requests from deepseek_client import call_deepseek import json from requests.exceptions import ChunkedEncodingError def test_diet_analysis(): user_input = "中午吃了炸鸡和奶茶,晚上吃了牛肉火锅" # 调用 MCP mcp_resp = requests.post("http://localhost:8001/mcp", json={"input": user_input}) mcp_data = mcp_resp.json() print("MCP 返回:", mcp_data) # 调用 DeepSeek reply = call_deepseek(mcp_data["routed_input"]) print("DeepSeek 回复:", reply) def test_diet_plan(): user_input = "我想要一个一周减肥计划,主要食物包括香菇、鸡胸肉和燕麦" mcp_resp = requests.post("http://localhost:8001/mcp", json={"input": user_input}) mcp_data = mcp_resp.json() print("MCP 返回:", mcp_data) reply = call_deepseek(mcp_data["routed_input"]) print("DeepSeek 回复:", reply) def test_effects_inquiry(): user_input = "香菇吃多了会怎样?" mcp_resp = requests.post("http://localhost:8001/mcp", json={"input": user_input}) mcp_data = mcp_resp.json() print("MCP 返回:", mcp_data) reply = call_deepseek(mcp_data["routed_input"]) print("DeepSeek 回复:", reply) def test_avoid_inquiry(): user_input = "牛奶和虾能一起吃吗?" mcp_resp = requests.post("http://localhost:8001/mcp", json={"input": user_input}) mcp_data = mcp_resp.json() print("MCP 返回:", mcp_data) reply = call_deepseek(mcp_data["routed_input"]) print("DeepSeek 回复:", reply) def test_stream(): user_input = "我晚上吃什么比较好呢? 中午吃了炸鸡和奶茶" try: resp = requests.post( "http://localhost:8001/mcp_stream", json={"input": user_input}, stream=True, timeout=None, ) print("Stream start →", resp.status_code) meta_printed = False for line in resp.iter_lines(decode_unicode=True): if not line: continue # SSE: 可能含 event: xxx if line.startswith("event: "): current_event = line[7:] # 下一行应该是 data: continue if not line.startswith("data: "): continue data = line[6:] # current_event 默认为 token current_event = locals().get("current_event", "token") if current_event == "meta": try: meta_obj = json.loads(data) pretty_meta = json.dumps(meta_obj, ensure_ascii=False) print("Meta:", pretty_meta) except json.JSONDecodeError: print("Meta:", data) meta_printed = True print("\n--- AI 回复 ---\n", end="") continue if current_event == "done": print("\n✅ Stream done") break # 其他 token 输出 print(data, end="", flush=True) except ChunkedEncodingError: # 服务器已发送完毕但提前关闭连接,可忽略 print("\n⚠️ 连接提前关闭,已接收全部内容。") finally: try: resp.close() except Exception: pass if __name__ == "__main__": # test_diet_analysis() # test_diet_plan() # test_effects_inquiry() # test_avoid_inquiry() test_stream() text_match.py# -*- coding: utf-8 -*- # text_match.py import jieba import difflib from typing import Iterable, List, Set, Tuple def extract_food( user_text: str, food_vocab: Iterable[str], fuzzy_threshold: float = 0.8, ) -> Tuple[List[str], List[str], List[str]]: """根据用户输入提取食物关键词。 1. 先使用 jieba 分词命中精确词。 2. 对分词结果做模糊匹配,解决同义词/花式写法。 Args: user_text: 用户原始输入字符串。 food_vocab: 食物静态数据库的键集合。 fuzzy_threshold: SequenceMatcher 相似度阈值 (0-1)。 Returns: 去重后的食物列表,按出现顺序返回。 """ vocab_set: Set[str] = set(food_vocab) tokens = jieba.lcut(user_text, cut_all=False) hits: List[str] = [] exact_hits: List[str] = [] fuzzy_hits: List[str] = [] added: Set[str] = set() for token in tokens: # 精确匹配 if token in vocab_set and token not in added: hits.append(token) exact_hits.append(token) added.add(token) continue # 模糊匹配 for food in vocab_set: if food in added: continue if difflib.SequenceMatcher(None, token, food).ratio() >= fuzzy_threshold: hits.append(food) fuzzy_hits.append(food) added.add(food) break return hits, exact_hits, fuzzy_hits # 向后兼容的简化接口 def extract_food_simple(user_text: str, food_vocab: Iterable[str], fuzzy_threshold: float = 0.8) -> List[str]: """返回仅 food list 的旧版接口,供其他模块调用。""" return extract_food(user_text, food_vocab, fuzzy_threshold)[0] food_tags.json{ "炸鸡": { "tags": ["高油脂", "高热量"], "effects": "经常食用可能导致能量过剩、血脂升高", "avoid_with": ["啤酒"], "diet_type": ["增重期", "周末放纵"], "recipe_hint": "可使用空气炸锅,减少50%油脂摄入" }, "奶茶": { "tags": ["高糖", "高热量"], "effects": "过量摄入易导致胰岛素抵抗、体重增加", "avoid_with": [], "diet_type": ["偶尔犒劳"], "recipe_hint": "选择低糖或无糖版本,减少珍珠" }, "可乐": { "tags": ["高糖"], "effects": "长期高糖饮料摄入可增加蛀牙及肥胖风险", "avoid_with": ["咖啡"], "diet_type": ["偶尔犒劳"], "recipe_hint": "选择零度可乐或气泡水替代" }, "卤牛肉": { "tags": ["高钠", "高蛋白"], "effects": "高钠摄入可能升高血压", "avoid_with": [], "diet_type": ["增肌期"], "recipe_hint": "配合蔬菜食用平衡营养" }, "牛肉火锅": { "tags": ["高油脂", "高钠"], "effects": "高盐高油易导致水肿", "avoid_with": ["冰啤酒"], "diet_type": ["增重期"], "recipe_hint": "控制汤底油脂和盐分,搭配蔬菜" }, "蔬菜汤": { "tags": ["低热量", "健康推荐"], "effects": "一般安全", "avoid_with": [], "diet_type": ["减脂期", "日常维稳"], "recipe_hint": "少盐少油" }, "白灼虾": { "tags": ["高蛋白", "健康推荐"], "effects": "嘌呤偏高,痛风患者需控制", "avoid_with": ["维生素C高的水果"], "diet_type": ["增肌期", "减脂期"], "recipe_hint": "控制蘸料用量" }, "香菇": { "tags": ["高纤维", "低脂"], "effects": "过量可能导致胀气", "avoid_with": ["寒性食物"], "diet_type": ["减脂期", "日常维稳"], "recipe_hint": "烹饪前泡发充分" }, "燕麦": { "tags": ["高纤维", "低GI"], "effects": "摄入过多可能引起腹胀", "avoid_with": [], "diet_type": ["减脂期", "增肌期"], "recipe_hint": "配合蛋白质食物提高饱腹" }, "糙米": { "tags": ["高纤维", "低GI"], "effects": "富含植酸,影响矿物质吸收,建议与其他谷物搭配", "avoid_with": [], "diet_type": ["减脂期", "日常维稳"], "recipe_hint": "提前浸泡12小时再煮" }, "炸薯条": { "tags": ["高油脂", "高热量"], "effects": "反式脂肪酸摄入风险", "avoid_with": ["汽水"], "diet_type": ["偶尔犒劳"], "recipe_hint": "可使用空气炸锅替代油炸" } , "牛油果": { "tags": ["高脂肪", "高纤维", "健康推荐"], "effects": "脂肪含量高,减脂期注意总热量", "avoid_with": [], "diet_type": ["增肌期", "日常维稳"], "recipe_hint": "搭配全麦面包或沙拉" }, "酸奶": { "tags": ["高蛋白", "益生菌"], "effects": "乳糖不耐人群可能腹胀", "avoid_with": ["高糖谷物"], "diet_type": ["减脂期", "增肌期", "日常维稳"], "recipe_hint": "选择无糖或低糖版本" }, "披萨": { "tags": ["高油脂", "高热量"], "effects": "高钠高脂,注意摄入频次", "avoid_with": ["可乐"], "diet_type": ["周末放纵"], "recipe_hint": "选择薄底、加多蔬菜版本" }, "红薯": { "tags": ["低GI", "高纤维", "健康推荐"], "effects": "过量可致腹胀", "avoid_with": [], "diet_type": ["减脂期", "日常维稳"], "recipe_hint": "蒸煮可保留营养" }, "鲑鱼": { "tags": ["高蛋白", "Omega-3"], "effects": "富含EPA/DHA,有助心血管健康", "avoid_with": ["富含草酸蔬菜"], "diet_type": ["增肌期", "日常维稳"], "recipe_hint": "推荐清蒸或空气炸锅" }, "绿茶": { "tags": ["低热量", "抗氧化"], "effects": "空腹或过量可致胃刺激", "avoid_with": ["牛奶"], "diet_type": ["减脂期", "日常维稳"], "recipe_hint": "餐后一小时饮用更佳" }, "巧克力": { "tags": ["高糖", "高脂"], "effects": "摄入过多易长痘和增重", "avoid_with": [], "diet_type": ["偶尔犒劳"], "recipe_hint": "优选 70% 以上黑巧" }, "能量饮料": { "tags": ["高糖", "咖啡因"], "effects": "过量可能导致心悸、睡眠障碍", "avoid_with": ["咖啡"], "diet_type": ["比赛备战", "偶尔提神"], "recipe_hint": "控制每日总咖啡因 < 400mg" } } config.json{ "DEEPSEEK_API_KEY": "刚刚申请的Key", "DEEPSEEK_URL": "申请得到的Url", "MCP_PORT": 8001, "MODEL_NAME": "DeepSeek-R1" } requirements.txtfastapi uvicorn requests httpx jieba cachetools loguru4.1.4 安装依赖点击 终端pip install -r requirements.txt -i https://mirrors.huaweicloud.com/repository/pypi/simple安装成功 示例图 如果显示仍然缺少依赖 请关闭ide 重新打开即可4.2 调试 MCP终端上执行命令uvicorn mcp_server:app --port 8001 运行成功示例图下一步 新建终端 点加号执行 测试程序python test_pipeline.py执行测试成功示例图 这里我们就可以看到 流式响应的一个效果然后我们最小化 这个 CodeArts IDE for Python4.3 仓颉交互AIChat(魔改MCP)打开 仓颉编辑器4.3.1 新建项目我们这里名称就叫 food_bot 然后点击 创建4.3.2 代码实施config.json{ "model": "", "api_key": "", "base_url": "http://localhost:8001/mcp_stream", "system_prompt": "" } cjpm.toml[dependencies] [package] cjc-version = "0.53.13" compile-option = "" description = "nothing here" link-option = "" name = "food_bot" output-type = "executable" src-dir = "" target-dir = "" version = "1.0.0" package-configuration = {} src/main.cjpackage food_bot import std.console.Console import std.collection.ArrayList func cli_chat(env_info: EnvInfo, stream!: Bool) { println("\n欢迎使用智能膳食分析助手,输入exit退出") var history: ArrayList<(String, String)> = ArrayList<(String, String)>() while (true) { print("Input: ") var prompt: String = "" match(Console.stdIn.readln()) { case Some(str1: String) => prompt=str1 case None => continue } if (prompt == "exit" || prompt == "exit()") { break } if (prompt == "clear") { history.clear() println("Output: 已清理历史对话信息。") continue } // 根据配置或命令行参数判断是否启用流式模式 var use_stream: Bool = stream if (!use_stream && env_info.base_url.endsWith("/mcp_stream")) { use_stream = true } print("ChatBox: ") let response_option: Option<String> = if (use_stream) { stream_chat(prompt, env_info, history) } else { chat(prompt, env_info, history) } match (response_option) { case Some(response: String) => println("${response}") history.append((prompt, response)) case None => println("发生错误,正在重试一次...") let retry_option = if (use_stream) { stream_chat(prompt, env_info, history) } else { chat(prompt, env_info, history) } match(retry_option) { case Some(resp2: String) => println("${resp2}") history.append((prompt, resp2)) case None => println("重试失败,即将退出") break } } } } main(args: Array<String>): Int64 { let env_info = load_env_info() var stream: Bool = false if (args.size == 1) { if (args[0] == "--stream") { stream = true } else { println("参数无效,仅支持 --stream 以开启流式输出") } } cli_chat(env_info, stream: stream) return 0 } env_info.cjpackage food_bot import encoding.json.stream.* import std.fs.File import std.fs.Path import std.io.ByteArrayStream public class EnvInfo <: JsonDeserializable<EnvInfo> & JsonSerializable { public let model: String // 模型名称 public let api_key: String // api密钥 public let base_url: String // 调用接口路径 public let system_prompt: String // 预置系统提示词 public init(model: String, api_key: String, base_url: String, system_prompt: String) { this.model = model this.api_key = api_key this.base_url = base_url this.system_prompt = system_prompt } public static func fromJson(r: JsonReader): EnvInfo { var temp_model: String = "" var temp_api_key: String = "sk-xxx" var temp_base_url: String = "http://xxx.xxx.xxx/v1" var temp_system_prompt: String = "You are a helpful assistant." while (let Some(v) <- r.peek()) { match(v) { case BeginObject => r.startObject() while(r.peek() != EndObject) { let n = r.readName() match (n) { case "model" => temp_model = r.readValue<String>() case "api_key" => temp_api_key = r.readValue<String>() case "base_url" => temp_base_url = r.readValue<String>() case "system_prompt" => temp_system_prompt = r.readValue<String>() case _ => () } } r.endObject() break case _ => throw Exception() } } return EnvInfo(temp_model, temp_api_key, temp_base_url, temp_system_prompt) } public func toJson(w: JsonWriter): Unit { w.startObject() w.writeName("model").writeValue(this.model) w.writeName("api_key").writeValue(this.api_key) w.writeName("base_url").writeValue(this.base_url) w.writeName("system_prompt").writeValue(this.system_prompt) w.endObject() w.flush() } } public func save_env_info(): Unit { // 该函数用于测试EnvInfo类的序列化为json的能力,顺便生成一个env_sample.json样本做为参考 let env_path = Path("env_sample.json") if (File.exists(env_path)) { File.delete(env_path) } let file = File.create(env_path) let env_info = EnvInfo( "xxxx", "sk-xxxxxx", "http://xxx.xxx.xxx/v1/chat/completions", "You are a helpful assistant." ) var byte_stream = ByteArrayStream() var json_writer = JsonWriter(byte_stream) let write_config = WriteConfig.pretty json_writer.writeConfig = write_config env_info.toJson(json_writer) file.write(byte_stream.readToEnd()) println("`env_sample.json` save ok") file.close() } public func load_env_info(): EnvInfo { // 用于加载配置文件 let env_path = Path("config.json") if (!File.exists(env_path)) { throw Exception("The config file not exists, please check again") } let file = File.openRead(env_path) let file_str: Array<UInt8> = file.readToEnd() var byte_stream = ByteArrayStream() byte_stream.write(file_str) let json_reader = JsonReader(byte_stream) let env_info: EnvInfo = EnvInfo.fromJson(json_reader) file.close() // println("model: ${env_info.model}") // println("api_key: ${env_info.api_key}") // println("base_url: ${env_info.base_url}") // println("system_prompt: ${env_info.system_prompt}") return env_info } chat.cjpackage food_bot import encoding.json.stream.* import net.http.ClientBuilder import net.http.HttpHeaders import net.http.HttpRequestBuilder import net.tls.TlsClientConfig import net.tls.CertificateVerifyMode import std.collection.ArrayList import std.io.ByteArrayStream import std.time.Duration import std.unicode.UnicodeExtension // for String.trim() // ===== 可配置常量 ===== public let READ_TIMEOUT_SECONDS: Int64 = 300 // 长轮询 SSE 建议 300 秒 // =========================== public enum RoleType { User | Assistant | System } public func role_type_to_str(role: RoleType): Option<String> { return match(role) { case RoleType.User => Some("user") case RoleType.Assistant => Some("assistant") case RoleType.System => Some("system") } } public func str_to_role_type(role_option_str: Option<String>): RoleType { return match(role_option_str) { case Some(str) => match(str) { case "user" => RoleType.User case "assistant" => RoleType.Assistant case "system" => RoleType.System case _ => RoleType.Assistant } case None => RoleType.Assistant } } public struct Message<: JsonDeserializable<Message> & JsonSerializable { public let role: RoleType public var content: String public init(role: RoleType, content: String) { this.role = role this.content = content } public static func fromJson(r: JsonReader): Message { var temp_role: Option<String> = None var temp_content: String = "" while (let Some(v) <- r.peek()) { match(v) { case BeginObject => r.startObject() while(r.peek() != EndObject) { let n = r.readName() match(n) { case "role" => temp_role = r.readValue<Option<String>>() case "content" => temp_content = r.readValue<String>() case _ => r.skip() } } r.endObject() break case _ => throw Exception("can't deserialize for Message") } } let role_type: RoleType = str_to_role_type(temp_role) return Message(role_type, temp_content) } public func toJson(w: JsonWriter) { w.startObject() w.writeName("role").writeValue<Option<String>>(role_type_to_str(this.role)) w.writeName("content").writeValue<String>(this.content) w.endObject() w.flush() } } public struct ChatRequest <: JsonSerializable { private let model: String private let messages: ArrayList<Message> private let max_tokens: Int64 private let stream: Bool public init( model: String, messages: ArrayList<Message>, max_tokens: Int64, stream: Bool ) { // construction function with messages this.model = model this.messages = messages this.max_tokens = max_tokens this.stream = stream } public init( model: String, prompt: String, history: ArrayList<(String, String)>, system_prompt: String, max_tokens: Int64, stream: Bool ){ // construction function with prompt and system_prompt this.model = model this.messages = ArrayList<Message>([ Message(RoleType.System, system_prompt) ]) for ((use_msg, bot_msg) in history) { this.messages.append(Message(RoleType.User, use_msg)) this.messages.append(Message(RoleType.Assistant, bot_msg)) } this.messages.append(Message(RoleType.User, prompt)) this.max_tokens = max_tokens this.stream = stream } public init( model: String, prompt: String, history: ArrayList<(String, String)>, system_prompt: String, stream: Bool ){ // construction function with prompt and default arguments this.model = model this.messages = ArrayList<Message>([ Message(RoleType.System, system_prompt) ]) for ((use_msg, bot_msg) in history) { this.messages.append(Message(RoleType.User, use_msg)) this.messages.append(Message(RoleType.Assistant, bot_msg)) } this.messages.append(Message(RoleType.User, prompt)) this.max_tokens = 2000 this.stream = stream } public func toJson(w: JsonWriter) { w.startObject() w.writeName("model").writeValue<String>(this.model) w.writeName("messages").writeValue<ArrayList<Message>>(this.messages) w.writeName("max_tokens").writeValue<Int64>(this.max_tokens) w.writeName("stream").writeValue<Bool>(this.stream) w.endObject() w.flush() } } public struct Choice <: JsonDeserializable<Choice> & JsonSerializable { public let index: Int32 public let message: Option<Message> public let delta: Option<Message> public let finish_reason: Option<String> public let logprobs: Option<Float64> // dashscope for qwen need public init( index: Int32, message: Option<Message>, delta: Option<Message>, finish_reason: Option<String>, logprobs: Option<Float64> ) { this.index = index this.message = message this.delta = delta this.finish_reason = finish_reason this.logprobs = logprobs } public static func fromJson(r: JsonReader): Choice { var temp_index: Int32 = -1 var temp_message: Option<Message> = None var temp_delta: Option<Message> = None var temp_finish_reason: Option<String> = None var temp_logprobs: Option<Float64> = None while (let Some(v) <- r.peek()) { match(v) { case BeginObject => r.startObject() while(r.peek() != EndObject) { let n = r.readName() match (n) { case "index" => temp_index = r.readValue<Int32>() case "message" => temp_message = r.readValue<Option<Message>>() case "delta" => temp_delta = r.readValue<Option<Message>>() case "finish_reason" => temp_finish_reason = r.readValue<Option<String>>() case "logprobs" => temp_logprobs = r.readValue<Option<Float64>>() case _ => r.skip() } } r.endObject() break case _ => throw Exception("can't deserialize for Choice") } } return Choice(temp_index, temp_message, temp_delta, temp_finish_reason, temp_logprobs) } public func toJson(w: JsonWriter) { w.startObject() w.writeName("index").writeValue<Int32>(this.index) w.writeName("message").writeValue<Option<Message>>(this.message) w.writeName("delta").writeValue<Option<Message>>(this.delta) w.writeName("finish_reason").writeValue<Option<String>>(this.finish_reason) w.writeName("logprobs").writeValue<Option<Float64>>(this.logprobs) w.endObject() w.flush() } } public struct Usage <: JsonDeserializable<Usage> & JsonSerializable { public let prompt_tokens: UInt64 public let completion_tokens: UInt64 public let total_tokens: UInt64 public init(prompt_tokens: UInt64, completion_tokens: UInt64, total_tokens: UInt64) { this.prompt_tokens = prompt_tokens this.completion_tokens = completion_tokens this.total_tokens = total_tokens } public static func fromJson(r: JsonReader): Usage { var temp_prompt_tokens: UInt64 = 0 var temp_completion_tokens: UInt64 = 0 var temp_total_tokens: UInt64 = 0 while (let Some(v) <- r.peek()) { match(v) { case BeginObject => r.startObject() while(r.peek() != EndObject) { let n = r.readName() match (n) { case "prompt_tokens" => temp_prompt_tokens = r.readValue<UInt64>() case "completion_tokens" => temp_completion_tokens = r.readValue<UInt64>() case "total_tokens" => temp_total_tokens = r.readValue<UInt64>() case _ => r.skip() } } r.endObject() break case _ => throw Exception("can't deserialize for Usage") } } return Usage(temp_prompt_tokens, temp_completion_tokens, temp_total_tokens) } public func toJson(w: JsonWriter) { w.startObject() w.writeName("prompt_tokens").writeValue<UInt64>(this.prompt_tokens) w.writeName("completion_tokens").writeValue<UInt64>(this.completion_tokens) w.writeName("total_tokens").writeValue<UInt64>(this.total_tokens) w.endObject() w.flush() } } public struct ChatResponse <: JsonDeserializable<ChatResponse> { // some api names `id`, and some names `request_id` public let id: Option<String> public let request_id: Option<String> public let system_fingerprint: Option<String> public let model: String public let object: String public let created: UInt64 public let choices: ArrayList<Choice> public let usage: Option<Usage> public init( id: Option<String>, request_id: Option<String>, system_fingerprint: Option<String>, model: String, object: String, created: UInt64, choices: ArrayList<Choice>, usage: Option<Usage> ) { this.id = id this.request_id = request_id this.system_fingerprint = system_fingerprint this.model = model this.object = object this.created = created this.choices = choices this.usage = usage } public static func fromJson(r: JsonReader): ChatResponse { var temp_id: Option<String> = None var temp_request_id: Option<String> = None var temp_system_fingerprint: Option<String> = None var temp_model: String = "" var temp_object: String = "" var temp_created: UInt64 = 0 var temp_choices: ArrayList<Choice> = ArrayList<Choice>([]) var temp_usage: Option<Usage> = None while (let Some(v) <- r.peek()) { match(v) { case BeginObject => r.startObject() while(r.peek() != EndObject) { let n = r.readName() match (n) { case "id" => temp_id = r.readValue<Option<String>>() case "request_id" => temp_request_id = r.readValue<Option<String>>() case "system_fingerprint" => temp_system_fingerprint = r.readValue<Option<String>>() case "model" => temp_model = r.readValue<String>() case "object" => temp_object = r.readValue<String>() case "created" => temp_created = r.readValue<UInt64>() case "choices" => temp_choices = r.readValue<ArrayList<Choice>>() case "usage" => temp_usage = r.readValue<Option<Usage>>() case _ => r.skip() } } r.endObject() break case _ => throw Exception("can't deserialize for ChatResponse") } } return ChatResponse( temp_id, temp_request_id, temp_system_fingerprint, temp_model, temp_object, temp_created, temp_choices, temp_usage ) } } public func get_domain( url: String ): String { var temp_url = url if (temp_url.startsWith("https://")) { temp_url = temp_url["https://".size..] } else if (temp_url.startsWith("http://")) { temp_url = temp_url["http://".size..] } let domain: String = temp_url.split("?")[0].split("/")[0] return domain } public func build_http_client( prompt: String, env_info: EnvInfo, history: ArrayList<(String, String)>, stream!: Bool ){ // prepare input data // If we are targeting the custom `/mcp_stream` backend we must send // a very simple JSON body `{ "input": "<prompt>" }` instead of the // OpenAI-style `ChatRequest`. Detect this via URL suffix. let is_mcp_stream = env_info.base_url.endsWith("/mcp_stream") var post_data: Array<UInt8> if (is_mcp_stream) { var local_stream = ByteArrayStream() let local_writer = JsonWriter(local_stream) // { "input": "..." } local_writer.startObject() local_writer.writeName("input").writeValue(prompt) local_writer.endObject() local_writer.flush() post_data = local_stream.readToEnd() } else { var array_stream = ByteArrayStream() let json_writer = JsonWriter(array_stream) let chat_res = ChatRequest( env_info.model, prompt, history, env_info.system_prompt, stream ) chat_res.toJson(json_writer) post_data = array_stream.readToEnd() } // build headers var headers: HttpHeaders = HttpHeaders() if (!is_mcp_stream) { // local backend doesn't require auth header headers.add("Authorization", "Bearer ${env_info.api_key}") } headers.add("Content-Type", "application/json") if (stream) { headers.add("Accept", "text/event-stream") } let request = HttpRequestBuilder() .url(env_info.base_url) .method("POST") .body(post_data) .readTimeout(Duration.second * READ_TIMEOUT_SECONDS) .addHeaders(headers) .build() let client = if (env_info.base_url.startsWith("https")) { var tls_client_config = TlsClientConfig() tls_client_config.verifyMode = CertificateVerifyMode.TrustAll tls_client_config.domain = get_domain(env_info.base_url) ClientBuilder() .tlsConfig(tls_client_config) .build() } else { ClientBuilder().build() } return (request, client) } public func chat( prompt: String, env_info: EnvInfo, history: ArrayList<(String, String)> ): Option<String> { let (request, client) = build_http_client( prompt, env_info, history, stream: false ) var result_message: Option<String> = None var res_text = "" try { // call api let response = client.send( request ) // read result (support max revice 100k data) let buffer = Array<Byte>(102400, item: 0) let length = response.body.read(buffer) res_text = String.fromUtf8(buffer[..length]) // println("res_text: ${res_text}") var input_stream = ByteArrayStream() input_stream.write(res_text.toArray()) // convert text to ChatResponse object let json_reader = JsonReader(input_stream) let res_object = ChatResponse.fromJson(json_reader) let choices: ArrayList<Choice> = res_object.choices if (choices.size > 0) { let message = choices[0].message.getOrThrow() // println("message: ${message.content}") result_message = Some(message.content) } else { println("can't found any response") } } catch (e: Exception) { println("ERROR: ${e.message}, reviced text is ${res_text}") } client.close() return result_message } public func stream_chat( prompt: String, env_info: EnvInfo, history: ArrayList<(String, String)> ): Option<String> { let (request, client) = build_http_client( prompt, env_info, history, stream: true ) let is_mcp_stream = env_info.base_url.endsWith("/mcp_stream") var result_response: String = "" var temp_text2 = "" try { // call api let response = client.send( request ) // read result let buffer = Array<Byte>(10240, item: 0) if (is_mcp_stream) { var done = false var current_event = "" while(!done) { let length = response.body.read(buffer) if (length == 0) { break } let res_text = String.fromUtf8(buffer[..length]) for (line in res_text.split("\n")) { let trimmed = line.trim() if (trimmed.size == 0) { continue } if (trimmed.startsWith("event: ")) { current_event = trimmed["event: ".size..] continue } if (trimmed.startsWith("data: ")) { let data = trimmed["data: ".size..] if (current_event == "token") { // 累积 token,暂不直接打印 result_response = result_response + data } else if (current_event == "ping") { // 服务器心跳,忽略即可 () } else if (current_event == "error") { println("服务器错误: ${data}") done = true result_response = "" // force empty so caller sees None break } else if (current_event == "done") { done = true break } } } if (done) { break } } } else { var finish_reason: Option<String> = None while(finish_reason.isNone() && temp_text2 != "[DONE]") { let length = response.body.read(buffer) let res_text = String.fromUtf8(buffer[..length]) for (temp_text in res_text.split("\n")) { temp_text2 = if (temp_text.startsWith("data: ")) { temp_text["data: ".size..] } else { temp_text } if (temp_text2.size == 0) { continue } if (temp_text2 == "[DONE]") { break } var input_stream = ByteArrayStream() input_stream.write(temp_text2.toArray()) // convert text to ChatResponse object let json_reader = JsonReader(input_stream) let res_object = ChatResponse.fromJson(json_reader) let choices: ArrayList<Choice> = res_object.choices if (choices.size > 0) { finish_reason = choices[0].finish_reason if (finish_reason.isNone()) { let delta = choices[0].delta.getOrThrow() result_response = result_response + delta.content } } else { println("can't found any response") } } } } } catch (e: Exception) { println("ERROR: ${e.message}, reviced text is ${temp_text2}") } client.close() if (result_response.size > 0) { return Some(result_response) } else { return None } } 4.4 调试AIChat点击 终端执行 命令cjpm run运行成功示例图输入测试语句例如:我中午吃了炸鸡和奶茶还有香菇 我晚上吃点什么比较好呢?切回 CodeArts IDE for Python 切换 终端我们就可以看到 MCP 服务端 接受到请求的日志然后我们切回 仓颉编辑器 查看 这是响应正常 那么我们来测试 缓存 的效果 再次发出这个命令我中午吃了炸鸡和奶茶还有香菇 我晚上吃点什么比较好呢?你会看到它 立刻返回了结果然后我们可以 切换到 Python编辑器 看一下 命中缓存的日志💡这是两次请求1️⃣请求未命中则去请求DeepSeek2️⃣请求相同数据 则命中缓存五、项目总结5.1 MCPMCP,全称 Model Context Protocol,中文叫“模型上下文协议”。你可以把它想象成 AI 的“USB 接口” --让不同的 AI 模型、工具和应用程序能用统一的方式交流。那么我的理解是:它更像是一个适配器来调节各种AI不同的接口 达到一致的效果,让AI的交流更加简单,即使没有身份预设,走MCP是完美的让AI成为你的最佳助手。5.2 项目tag本次案例参考:https://devstation.connect.huaweicloud.com/space/devportal/casecenter/9a5b50615ac44a21af30f8699c81efc6/1https://devstation.connect.huaweicloud.com/space/devportal/casecenter/5a7144a66d1b43e088592ae447d518ed/1https://gitcode.com/CaseDeveloper/Cangjie-Examples简单的实现了 MCP并发(案例教程没有提及 uvicorn mcp_server:app --port 8001 --workers 4 )后续可拓展例如:food_bot 🔜 vue等各种UI 前端 各种适配机器人food_mcp🔜 独立开发为自己更加需要 模式更加契合的"USB" 让AI更加懂你关于缓存方面:缓存可以采用本地文件、redis等更加高性能的方案来替换这样就可以让实现由AI回答 到AI理解到了所表达和呈现的每一个需求点六、活动地址​ 如果对该项目有疑问,可以评论区留言交流~如果喜欢可以点点赞~​ 我正在参加【案例共创】第4期 基于华为开发者空间+仓颉/DeepSeek/MCP完成应用构建开发实践 https://bbs.huaweicloud.com/forum/thread-02127182415062274055-1-1.html
  • [案例共创] 【案例共创】基于仓颉编程语言+DeepSeek实现 AI 绘画提示词生成智能体
    生成式 AI 技术飞速发展,行业日新月异,AI 设计工具已经能替代设计师一部分工作,但要写出好的提示词也是挺费力的一件事。当前案例将以华为开发者空间为平台,结合仓颉语言+DeepSeek,构建一个专业的 AI 绘画提示词生成智能体,实现理解用户输入的模糊的创作意图,给出高质量的 AI 绘画提示词,以期提高 AI 绘画质量和效率。一、技术栈语言:仓颉开发环境:华为开发者空间IDE:CodeArts IDE for CangjieAI模型:DeepSeek(华为云 MaaS 免费提供)二、实现流程免费领取华为开发者空间云主机使用 CodeArts IDE 创建仓颉项目华为 MaaS 平台免费领取 DeepSeek Tokens仓颉对接 DeepSeek 接口设计提示词生成逻辑模板三、资源总览本案例预计花费总计0元。资源名称规格单价(元)时长(分钟)云主机2vCPU 4GB X86 Ubuntu 或4vCPUs 8GB ARM Ubuntu免费40四、免费领取华为开发者空间云主机注册并登录华为云开发者空间即可免费领取一台云主机,在工作台中点击“打开云主机”可以打开即可进入桌面桌面上点击“CodeArts IDE for Cangjie”的图标即可打开编辑器使用,无需部署环境和安装软件。五、华为 Maas 平台免费领取 DeepSeek Tokens领取 DeepSeek 200w 免费 Tokens,登录MaaS,可进入贵阳一区域的 ModelArts Studio 控制台,然后点击控制台左侧“模型推理”-“在线推理”,点击“预置服务”-“免费服务”,找到想要使用的 DeepSeek 版本后点击“领取”,领取成功后就可以开始体验使用了。然后点击“调用说明”可以获取API地址、模型名称,之前未使用需点击左侧菜单的 API Key 管理创建 API Key,保存 API 地址、模型名称、API Key 备用。六、仓颉对接对接 DeepSeek 开发 AI 智能体进入云主机桌面,右键选择Open Terminal Here打开终端命令窗口,克隆仓颉示例代码仓库。git clone https://gitcode.com/CaseDeveloper/Cangjie-Examples.git使用 CodeArts IDE for Cangjie 打开 AIChat 示例项目。左上点击文件—打开项目,选择前面克隆的示例代码目录 Cangjie-Examples 下的 AIChat 打开修改根目录下的 config.json 配置文件,配置 DeepSeek 的配置信息和提示词,其中model为前面获取到的模型名称、api_key为 API KEY,base_url 为 API 地址,system_prompt 为系统提示词,系统提示词这里填入:你是我的全能助手,你的名字叫仓颉。仓颉编程语言是一款面向全场景智能的新一代编程语言,主打原生智能化、天生全场景、高性能、强安全。主要应用于鸿蒙原生应用及服务应用等场景中,为开发者提供良好的编程体验。须保持回复简洁,回复内容不超过300字。打开 src/main.cj 文件,点击运行按钮,即可看到效果我正在参加【案例共创】第4期 基于华为开发者空间+仓颉/DeepSeek/MCP完成应用构建开发实践 https://bbs.huaweicloud.com/forum/thread-02127182415062274055-1-1.html
  • [技术干货] 基于华为开发者空间Astro低代码应用平台,构建业务用户登录功能开发
    📋 案例概览📝 背景与简介华为开发者空间是为全球开发者打造的专属云上成长空间,深度整合昇腾AI、鸿蒙、鲲鹏等华为根技术。开发者空间在HDC2025上迎来全面升级,新增AI原生应用引擎、AI Notebook、鸿蒙云手机、FunctionGraph云函数、Astro低代码等核心能力,并在算力、模型、平台、应用层实现全方位优化,助力开发者高效完成从编码到调测的全流程,打造智能AI应用开发新体验。华为开发者空间-低代码应用开发平台是华为云推出的一款可视化应用开发平台,旨在通过"拖拽式"组件和模板化设计,降低开发门槛,提升企业数字化应用构建效率。Astro平台特别适合业务人员与开发者协同创新,能大幅缩短应用交付周期,典型适用于OA审批、数据看板、轻量级业务系统等场景。传统用户登录开发深陷 “高成本、低效率、弱安全” 困局,而华为Astro通过 “预制安全能力+可视化编排+云原生运维” 三位一体,实现:安全零信任:内建金融级防护,杜绝密码泄露风险;部署小时级:拖拽式开发释放IT资源;业务可持续:权限热配置支撑敏捷迭代。本案例将通过华为开发者空间-低代码应用开发平台,为业务应用自定义一个登录页。通过在登录页中输入用户名、密码等登录信息,与系统中存储的业务用户信息进行对比,来验证业务用户的身份,并根据设置的业务用户权限,为业务用户分配相应的资源和访问权限。🔖 案例流程🕹️ 流程说明:领取华为开发者空间,登录华为开发者空间-低代码应用开发平台;新建低代码应用,进入Astro轻应用服务控制台主页,开发应用。✍️ 案例实操📝 业务用户登录后台开发领取华为开发者空间,登录华为开发者空间-低代码应用开发平台;在华为开发者空间-低代码应用开发平台创建低代码应用,配置系统环境变量;创建用户登录、注册脚本,测试登录注册运行,返回参数;关联登录脚本,创建用户登录服务编排;创建公共接口,发布服务。在业务用户登录后台开发的最后,我们创建了一个公共接口。接下来我们将完成业务用户前台的开发,通过调取公共接口进行前后端数据互传,完成业务用户登录功能的开发。📝 业务用户登录前台开发获取自定义登录组件模板,修改配置文件,创建自定义组件;创建高级页面,开发登录页,配置后台公共接口;发布应用,登录成功!!!🌈 案例最终效果
  • [其他问题] 【AR502产品】关于容器到AR502,再到云主机的端口开通策略
    当前IP数据如下:云主机ip 172.17.0.2 .AR502: 172.27.144.70 AR502里面的容器A: 172.17.0.6容器A中启动了nginx,nginx对外暴露的监听端口是7080,在AR502配置了端口映射,由容器的7080映射到AR502的7080nft add rule dnat1 pre ip daddr 172.27.144.70 tcp dport 7080 iif GE4 dnat 172.17.0.6:7080在云主机 可以ping 通 172.27.144.70 ,但是访问http://172.27.144.70:7080 报502.有大神知道原因么,或者怎么解决么,感谢。
总条数:361 到第
上滑加载中