高代码智能体支持企业开发者通过veFaaS控制台进行在线开发与部署。本文为您介绍使用代码部署方式进行veFaas部署时的操作指南。(注:目前主要支持基于自定义镜像代码开发和部署)
产品名称 | 产品概述 | 是否为计费项目 | 是否需要申请开白 | 备注 |
---|---|---|---|---|
函数服务(Volcano Engine Function as a Service,veFaaS)是事件驱动的无服务器函数托管计算平台,支持快速创建和部署函数,连接云上中间件和数据库产品,帮助企业低成本构建复杂应用。 | 否 | 必选 | ||
Native 运行时支持用户基于原生的 HTTP 框架进行代码开发。使用 Native 运行时开发函数,需要遵循火山引擎的函数服务 Native 运行时规范。本文介绍 Native 运行时函数(下文简称 “Native 函数”)的运行环境、开发方法、日志采集及部署方法。 | 否 | 必选 | ||
异步任务是函数服务全新推出的函数运行机制,通过异步模式响应调用请求,在完成事件调度后立即返回 RequestId 结束调用操作,无需阻塞调用端资源。同时,异步任务支持追踪并保存任务各阶段的状态,提供丰富的任务控制和可观测能力。 | 否 | 可选 | ||
对原生 HTTP 框架应用进行托管。无需修改业务代码,在仅修改服务监听端口及服务启动脚本的情况下,便可平滑迁移至函数服务。 | 否 | 必选 | ||
火山引擎镜像仓库(Container Registry,CR)提供安全高可用的容器镜像、Helm Chart 等符合 OCI 标准的云原生制品托管服务,方便企业用户管理容器镜像和 Helm Chart 的全生命周期。 | 否 | 必选 | ||
私有网络(VPC,Virtual Private Cloud)为云上资源构建隔离的、自主配置和管理的虚拟网络环境。不同私有网络之间网络相互隔离,您可在自己的私有网络中创建和管理云服务器、负载均衡等云资源。 | 否 | 必选 | ||
火山引擎日志服务 TLS(Tinder Log Service)是日志和 Trace 类数据的一站式服务平台,提供数据采集、存储、检索分析、加工、消费、投递、监控告警、可视化等功能,适用于业务运维监控、数据统计分析等场景。 | 否 | 必选 | ||
API 网关(API Gateway,APIG)是基于云原生的、高扩展、高可用的云上网关托管服务。在传统流量网关的基础上,集成丰富的服务发现和服务治理能力,打通微服务架构的内外部网络,快速实现各服务之间、服务与客户端之间的安全通信。 | 否 | 必选 | ||
云监控服务是云上一站式监控告警解决方案。 云监控可以收集并可视化展示各类云产品的资源状态,帮助您全面了解其健康状况,及时识别异常状态并发送告警通知,确保业务平稳运行、提升运维效率。 | 否 | 必选 |
若使用子用户进行产品服务开通,则需为其配置权限:iam:CreateServiceLinkedRole
,步骤如下:
步骤一: 通过主账号,进入火山引擎访问控制台
步骤二: 增加最小权限可在决策管理处新建自定义策略CreateServiceLinkedRole
步骤三: 授权子账号用户产品开通权限
产品开通完成后,为子用户添加vsFass部署相关产品使用权限的方法如下,如需了解火山引擎IAM用户创建与授权可详见产品文档。
步骤一:进入访问控制台,点击导航栏的“身份管理-用户”处,对所需授权的子账号用户进行【管理】操作。
步骤二: 进入“用户详情”页面后点击【权限→ 添加权限→选择策略】, 搜索并选择以下策略:
VeFaaSFullAccess
CRFullAccess
VPCFullAccess
TLSFullAccess
APIGFullAccess
CloudMonitorReadOnlyAccess
选择后点击【确定】,则该步骤授权完成。
以下内容介绍用户在创建函数页面中如何操作配置:
为满足不同场景下的用户需求,函数服务提供多种类型的函数,详细选择说明见函数创建方式选型。
Web 应用帮助用户托管原生 Web 框架应用,支持基于各语言的流行框架(Golang Gin 等)或自定义容器镜像编写 Web 程序,以及迁移已有的 Web 应用。
微服务应用可托管任意语言和框架的容器应用,提供代码包和容器镜像部署两种部署方式,支持自动弹性,按量计费,主要应用于微服务应用,MQ 消费服务等领域。
任务帮助用户对一次性执行的脚本任务进行托管,通过任务模式响应异步调用请求,并追踪和保存任务各个阶段的状态,提供丰富的任务控制和可观测能力。
日志功能启用与配置步骤如下:
步骤一: 勾选启用日志功能
步骤二: 创建相应日志项目(如已创建,可忽略此步骤)
步骤三: 配置对应日志项目
步骤一: 进入“日志服务”点击导航栏的“trace服务”后点击【创建trace实例】(可选择与日志配置在同一项目下)
步骤二: 如图,获取tls私网访问地址和trace日志主题ID
步骤三: 进行trace索引配置,用户可选择在Attributes下配置二级索引: request_id, input, output
类型 | 键 / Key | 值 / Value |
---|---|---|
鉴权 | VOLC_ACCESSKEY | 火山ak |
VOLC_SECRETKEY | 火山sk | |
Trace依赖 | REGION(tls地域) | e.g. cn-beijing |
TRACE_ENDPOINT(tls私网访问地址:4317) | e.g. https://tls-cn-beijing.ivolces.com:4317 | |
TRACE_TOPIC(trace日志主题id) | e.g. a8adc928-69e1-4839-a4a0-929f4f188888 | |
自定义信息 | ACCOUNT_ID | e.g. 2100xxxxxx |
RESOURCE_TYPE | e.g. bot | |
RESOURCE_ID | e.g. browsing-pipeline |
以下介绍镜像相关配置步骤,更多可详见产品文档(注:用户若已创建镜像仓库,以下步骤可跳过)
步骤一: 在部署方式中选择:【容器镜像→镜像仓库】,部署前需通过火山的镜像仓库上传镜像。如不存在则需点击【创建镜像】,跳转至镜像仓库页面后点击【创建实例】
步骤二: 点击【创建命名空间】,并输入信息进行创建
步骤三: 创建完成后,请进入实例【设置仓库实例密码】
步骤四: 点击导航栏中的“访问控制”,开启公网访问(注:配置0.0.0.0/0放行所有IP访问,如需安全控制可自行配置IP段)
下面为您介绍创建VPC与子网步骤,更多可详见产品文档(注:如用户账号下已经有VPC,可跳过以下步骤)
步骤一: 进入私有网络控制台,点击【创建私有网络】
步骤二: 配置可用区A、可用区B两个子网
下面为您介绍创建API网关步骤,更多可详见产品文档(注:如用户账号下已经有api网关,可跳过以下步骤)
步骤一: 进入API网关控制台,点击【创建实例】。按需创建apig实例(网关类型:标准网关和serverless网关均可),需要配置双可用区
步骤二: 进入对应实例,点击【创建服务】
步骤三: 在对应服务下开启JWT认证以支持鉴权
步骤一: 完成上述前置工作后,在函数创建控制台发布函数
步骤二: 选择已建立的api网关
智能体:配置智能体api路由路径(e.g. /api/v2/bots/chat)
知识库(可选):配置 knowledge api 路由路径 (e.g. /api/v2/kb)
步骤三: 建立完成后可通过公网/私网地址访问api,以访问智能体chat接口及知识库文档上传接口
以下为您介绍基于自定义镜像代码与基于Python函数代码的两种代码部署方式(注:使用知识库场景下建议使用Python函数代码开发和部署并在2.3提供简单示例)
├── Dockerfile ├── code │ ├── __init__.py │ └── main.py └── run.sh
#!/bin/bash set -ex # shellcheck disable=SC2046 cd `dirname $0` exec python3 code/main.py
import os from typing import AsyncIterable from ark.core.task import task from ark.core.idl.maas_protocol import MaasChatRequest, MaasChatResponse from ark.core.launcher.local.serve import launch_serve @task(distributed=False) async def main(request: MaasChatRequest) -> AsyncIterable[MaasChatResponse]: # code here yield response if __name__ == "__main__": port = os.getenv('_FAAS_RUNTIME_PORT') launch_serve( package_path="main", endpoint_path="/api/v2/bots/chat", port=int(port) if port else 8080, health_check_path="/v1/ping")
@task()
即可使用tls的trace功能查看函数的调用时长、开始时间、结束时间、输入输出、request id等信息FROM python:3.9.5 ARG SDK_WHEEL="ark-0.1.4-py3-none-any.whl" ARG SDK_URL COPY code /opt/application/code COPY run.sh /opt/application/run.sh RUN wget ${SDK_URL} -O ${SDK_WHEEL} RUN pip install ${SDK_WHEEL} WORKDIR /opt/application USER root RUN chmod a+x /opt/application/run.sh CMD /opt/application/run.sh
打包发布可选择使用命令行工具发布或逐步操作两种方式:
步骤一: 安装SDK依赖
步骤二: 创建工程项目,具体指令可参考命令行工具- ark create
步骤三: 一键推送发布镜像,具体指令可参考命令行工具- ark push
步骤一: 启动docker daemon
mac环境:启动docker desktop即可
linux环境:执行sudo systemctl start docker
步骤二: 登录镜像仓库控制台,进入实例,点击【命名空间】
docker login --username={userName}@{userId} {CRHost}
步骤三: 编译镜像
CRHost: 镜像仓库实例访问域名
CRNamespace: 镜像仓库实例命名空间
ImageName: 镜像名
ImageTag: 镜像版本(可通过填写latest/1.0/2.0来区分不同版本代码,如没有版本管理需求可直接填写latest)
DOCKER_DEFAULT_PLATFORM="linux/x86_64" docker build . -f ./Dockerfile -t {CRHost}/{CRNamespace}/{ImageName}:{ImageTag}
步骤四: 上传镜像
docker push {CRHost}/{CRNamespace}/{ImageName}:{ImageTag}
步骤五: 同步与发布新版本代码
更多可参见依赖安装文档
conda create --name python3.8 python==3.8.17
conda activate python3.8
from ark.core.launcher.vefaas import faas_handler @task() def main(request: MaasChatRequest) -> Iterable[MaasChatResponse]: # wite your code here yield response def handler(event, context): return faas_handler(event=event, context=context, runnable_func=main)
zip -r ./deployment.zip .
使用知识库场景下建议使用Python函数代码开发和部署,可参照2.2,本节提供简单示例。
该步骤同2.2
def handler(event, context): # Log incoming request. # # NOTE: the log here is only for debug purpose. It's recommended to delete those debug/info # logs and only print log where error occurs after your business logic is verified and ready to # go production, nor the log amount may be too huge. LOGGER.info("received new request, event content: %s", event) body = event["body"] action = event["path"] LOGGER.info("body: %s action: %s", body, action) params = json.loads(body) ret_code, msg = asyncio.run(main(params)) if ret_code == 0: result = { 'statusCode': 200, 'headers': { 'Content-Type': 'application/json' }, 'body': msg } else: result = { 'statusCode': 500, 'headers': { 'Content-Type': 'application/json' }, 'body': msg } return result @task() async def main(params: Dict[str, Any]): """ main func """ ak = os.getenv("VOLC_ACCESSKEY") sk = os.getenv("VOLC_SECRETKEY")
该步骤同2.2
Version: 2021-03-03
参数名称 | 类型 | 是否必选 | 示例值 | 描述 |
---|---|---|---|---|
Action | String | 是 | GetJwtToken | 公共参数,本接口值:GetJwtToken |
ServiceId | String | 选填 | 服务Id(即将下线这个字段,之前是通过ServiceId来获取toke,兼容考虑) | |
GatewayId | String | 选填 | 网关Id,Token是全网关生效 |
ServiceId、GatewayId获取方法:进入API网关控制台,点击导航栏中的“路由管理-服务列表”,点击对应服务获取
POST /?Action=GetJwtToken&Version= Content-Type:application/json { "ServiceId": "xxxxxxxx", "GatewayId": "xxxxxxxx" }
参数名称 | 类型 | 示例值 | 描述 |
---|---|---|---|
JwtToken | String |
HTTP/1.1 200 OK Content-Type:application/json { "ResponseMetadata": { "RequestId": "202211302208xxxx", "Action": "GetJwtToken", "Version": "", "Service": "", "Region": "cn-beijing" }, "Result": { "JwtToken": "xxxxxxxx" } }
错误码
500:内部错误
400:参数错误
429:限流
403:无权限
调用**GetJwtToken
** 方法
注:调用api前需构造签名填充header,签名构造demo源码
Java: https://github.com/volcengine/volc-openapi-demos/blob/main/signature/java/Sign.java
Golang: https://github.com/volcengine/volc-openapi-demos/tree/main/signature/golang
Python: https://github.com/volcengine/volc-openapi-demos/blob/main/signature/python/sign.py
c#: https://github.com/volcengine/volc-openapi-demos/blob/main/signature/csharp/Program.cs
Endpoint: open.volcengineapi.com
Path: /
Version: 2021-03-03
Action: GetJwtToken
Service: apig
Service id: API网关的服务ID(路径:【API网关控制台→ 路由管理→ 服务列表】,进入对应服务获取)
curl --location 'https://open.volcengineapi.com?Version=2021-03-03&Action=GetJwtToken' \ --header 'Region: cn-beijing' \ --header 'ServiceName: apig' \ --header 'Content-Type: application/json' \ --data '{ "ServiceId": {{service id}} }'
For Java 开发场景,也可使用下面的Sample Code来实现JwtToken的自动获取和缓存:
<dependency> <groupId>com.volcengine</groupId> <artifactId>volc-sdk-java</artifactId> <!-- 使用最新版本 --> <version>1.0.155</version> </dependency>
package com.volce.demo; import com.alibaba.fastjson.JSONObject; import com.volcengine.error.SdkError; import com.volcengine.model.ApiInfo; import com.volcengine.model.Credentials; import com.volcengine.model.ServiceInfo; import com.volcengine.model.response.RawResponse; import com.volcengine.service.BaseServiceImpl; import org.apache.http.Header; import org.apache.http.NameValuePair; import org.apache.http.message.BasicHeader; import org.apache.http.message.BasicNameValuePair; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; public class ApiGatewayAuthService extends BaseServiceImpl { private static final int CONNECT_TIMEOUT = 5000; private static final int SOCKET_TIMEOUT = 5000; private static final long TOKEN_EXPIRE_TIME = 604800 * 1000; // key: gatewayId#serviceId private Map<String, Long> _expireTimes = new HashMap<>(); private Map<String, String> _cache = new HashMap<>(); public ApiGatewayAuthService(String host, String region) { super(buildServiceInfo(host, region), buildApiInfo()); } public ApiGatewayAuthService(String host, String region, String ak, String sk) { super(buildServiceInfo(host, region), buildApiInfo()); this.credentials.setAccessKeyID(ak); this.credentials.setSecretAccessKey(sk); } public String getGatewayJwtTokenWithAutoRefresh(String gatewayId, String serviceId) { String cacheKey = String.format("%s#%s", gatewayId, serviceId); Long expireTime = _expireTimes.get(cacheKey); long now = System.currentTimeMillis(); if (expireTime == null || expireTime <= now) { String token = getGatewayJwtToken(gatewayId, serviceId); _cache.put(cacheKey, token); expireTime = now + TOKEN_EXPIRE_TIME; _expireTimes.put(cacheKey, expireTime); return token; } else { return _cache.get(cacheKey); } } public String getGatewayJwtToken(String gatewayId, String serviceId) throws RuntimeException { JSONObject reqJson = new JSONObject(); reqJson.put("GatewayId", gatewayId); reqJson.put("ServiceId", serviceId); RawResponse response = this.json("get_jwttoken", null, reqJson.toJSONString()); if (response.getCode() != SdkError.SUCCESS.getNumber()) { throw new RuntimeException("fail to get jwt token, got response = " + response); } else { JSONObject rspJson = JSONObject.parseObject(new String(response.getData())); JSONObject resultJson = rspJson.getJSONObject("Result"); if (resultJson != null) { return resultJson.getString("JwtToken"); } } return null; } private static ServiceInfo buildServiceInfo(String host, String region) { Map<String, Object> serviceInfoMap = new HashMap<>(); serviceInfoMap.put("ConnectionTimeout", CONNECT_TIMEOUT); serviceInfoMap.put("SocketTimeout", SOCKET_TIMEOUT); serviceInfoMap.put("Host", host); serviceInfoMap.put("Header", new ArrayList<Header>() { { this.add(new BasicHeader("Accept", "application/json")); } }); serviceInfoMap.put("Credentials", new Credentials(region, "apig")); return new ServiceInfo(serviceInfoMap); } private static Map<String, ApiInfo> buildApiInfo() { Map<String, ApiInfo> apiInfoMap = new HashMap<>(); Map<String, Object> getJwtTokenParam = new HashMap<>(); getJwtTokenParam.put("Method", "POST"); getJwtTokenParam.put("Path", "/"); getJwtTokenParam.put("Query", new ArrayList<NameValuePair>() { { this.add(new BasicNameValuePair("Action", "GetJwtToken")); this.add(new BasicNameValuePair("Version", "2021-03-03")); } }); getJwtTokenParam.put("Form", new ArrayList<>()); getJwtTokenParam.put("Header", new ArrayList<>()); ApiInfo getJwtTokenApi = new ApiInfo(getJwtTokenParam); apiInfoMap.put("get_jwttoken", getJwtTokenApi); return apiInfoMap; } }
import com.volce.demo.ApiGatewayAuthService; public class Test { public static void main(String[] args) { ApiGatewayAuthService auth = new ApiGatewayAuthService("open.volcengineapi.com", "cn-beijing", "{yourAK}", "{yourSK}"); // 直接获取JwtToken(无缓存,每次都调用) auth.getGatewayJwtToken("{gatewayId}", "{serviceId}"); // 自动缓存获取JwtToken(默认七天轮转一次) auth.getGatewayJwtTokenWithAutoRefresh("{gatewayId}", "{serviceId}"); } }
请求智能体 api时带上JWT Token即可完成请求
APIHost:api触发器的公网域名(如果走私网访问可以配置私网域名)
curl --location '{APIHost}/api/v2/bots/chat' \ --header 'Authorization: Bearer {JWTToken}' \ --header 'Content-Type: application/json' \ --data '{ "messages": [ {"role": "user", "content": "查今天的新闻"} ] }'
字段 | 含义 |
---|---|
Name | 函数名 |
SpanID | 所调用函数ID |
ParentSpanID | 父函数ID |
StatusCode | 函数运行返回状态 |
StatusDescription | 运行失败状态描述 |
Attributes.input | 函数输入 |
Attributes.output | 函数输出 |
Attributes.request_id | x-tt-logid |
StartTime | 函数执行起始时间 |
EndTime | 函数执行终止时间 |
Duration | 函数执行时长(ms) |