应用流部署

在应用流开发完成后,您可以将其部署为EAS服务。EAS提供自动扩缩容和全面的运维监控等功能,能够确保应用灵活应对业务需求的变化和增长,提升系统的稳定性与性能,从而更好地支持生产环境的需求。

前提条件

已创建应用流,并完成调试。详情请参见应用流开发

部署应用流

进入LangStudio,选择工作空间后,在应用流页签下单击已调试完的应用流,然后在页面右上角单击部署(仅当运行时启动时才可进行部署)。关键参数说明:

image

参数

描述

资源部署

资源类型

选择公共资源组或您创建的专属资源组

实例数

配置服务实例数。在生产阶段,建议配置多个服务实例,以降低单点故障的风险。

部署资源

如果仅作为业务流调度使用,您可以根据业务流复杂程度选择合适的CPU资源。相对于GPU资源,CPU资源通常更加经济实惠。部署后会产生EAS相关的资源费用,计费详情请参见模型在线服务(EAS)计费说明

专有网络:由于部署应用流实际上是将其部署为EAS服务,为确保服务部署后客户端能正常访问EAS在线服务,您可以选择专有网络连通方案,将客户端与EAS服务间的网络连通。需要注意的是,EAS服务内部默认与公网不通,如果您有EAS服务访问公网的需求,需配置具备公网访问能力的VPC,详情请参见配置网络连通

说明

如果应用流中包含向量数据库连接(如Milvus),请确保配置的专有网络与向量数据库实例所在的专有网络一致,或确保两者网络互通。

对话历史

开启对话历史

仅适用于“对话型”应用流的配置,开启后支持存储和传递多轮对话的历史消息,需要配合服务请求头参数使用。

对话历史存储

本地存储不支持多实例部署,如果您部署的服务为生产使用,建议使用外部存储,如阿里云数据库RDS。详情请参见附录:对话历史

重要

采用本地存储方案时,不支持多实例部署,也不支持单实例扩容到多实例,否则会导致对话历史功能出现异常。

链路追踪:开启后,可在服务部署完成后查看Trace详情,以评估应用流的效果。

角色与权限:在应用流程中,如果使用了Faiss向量数据库(创建知识库时需要选择FaissMilvus向量数据库)或“阿里云IQS-标准搜索”(IQS联网搜索聊天助手模板会使用到该组件),则需要根据实际情况选择相应的角色。

更多参数配置说明,请参见控制台自定义部署参数说明

在线调试

调用服务

在线调试

部署成功后,跳转到PAI-EAS,在在线调试页签下配置并发送请求。请求Body中的Key与应用流中“开始节点”中的参数“对话输入”字段一致,本文使用默认字段question

image

API调用

  1. 概览页签下获取调用服务的EndpointToken。

    image

  2. 发送API请求。

    支持以简单模式和完整模式调用,两者区别如下:

    属性

    简单模式

    完整模式

    请求路径

    <Endpoint>/

    <Endpoint>/run

    功能描述

    直接返回应用流的输出结果。

    返回一个复杂的结构,包括应用流的节点状态、流的错误信息、流的输出消息等。

    适用场景

    • 用户只需要应用流的最终输出结果,而不关心流的内部处理过程或状态。

    • 适用于简单的查询或操作,快速获取结果。

    • 用户需要详细了解应用流的执行过程,包括每个节点的状态和可能的错误信息。

    • 适用于调试、监控或分析应用流的执行情况。

    优点

    使用简单,无需解析复杂的结构。

    • 提供全面的信息,帮助用户深入理解应用流的执行过程。

    • 有助于故障排查和优化应用流的性能。

    简单模式

    cURL命令

    部署的EAS应用流服务支持使用cURL命令进行流式或非流式调用,请求/返回示例如下:

    示例类型

    流式

    非流式

    请求示例

    curl -X POST \
         -H "Authorization: Bearer <your_token>" \
         -H "Content-Type: application/json" \
         -H "Accept: text/event-stream" \
         -d '{"question": "Where is the capital of France?"}' \
         "<your_endpoint>"
    curl -X POST \
         -H "Authorization: Bearer <your_token>" \
         -H "Content-Type: application/json" \
         -d '{"question": "Where is the capital of France?"}' \
         "<your_endpoint>"

    返回示例

    event: Message
    data: {"answer": ""}
    
    event: Message
    data: {"answer": "The"}
    
    event: Message
    data: {"answer": " capital"}
    
    event: Message
    data: {"answer": " of"}
    
    event: Message
    data: {"answer": " France"}
    
    event: Message
    data: {"answer": " is"}
    
    event: Message
    data: {"answer": " Paris"}
    
    event: Message
    data: {"answer": "."}
    
    event: Message
    data: {"answer": ""}
    {"answer":"The capital of France is Paris."}

    请求参数配置说明:

    参数

    描述

    -H "Authorization: Bearer <your_token>"

    HTTP头部信息。其中<your_token>需要替换为步骤1中获取的Token。

    -H "Accept: text/event-stream"

    表示Client接受SSE请求,返回的信息为流式信息。注:仅当LLM节点作为应用流的输出节点时(结束节点的直接输入必须是LLM节点),才支持流式调用。

    -d '{"question": "Where is the capital of France?"}'

    请求的主体数据。格式为JSON对象,包含一个Key-Value对,即问题字符串。其中Key需要与应用流中“开始节点”中的参数“对话输入”字段一致,此处为默认字段question

    "<your_endpoint>"

    请求的目标URL。其中<your_endpoint>需要替换为步骤1中获取的Endpoint。

    Python脚本

    以下示例展示了如何使用 requests 库向应用流服务发送一个POST请求,支持流式或非流式调用。请确保您已安装该库,如果尚未安装,可以通过运行 pip install requests 命令来进行安装。

    示例类型

    流式

    非流式

    请求示例

    import requests
    import json
    
    url = "http://<your-endpoint-here>"
    token = "<your-token-here>"
    data = {"question": "Where is the capital of France?"}
    
    # 设置请求头,包含您的token
    headers = {
        "Authorization": f"Bearer {token}",
        "Accept": "text/event-stream",
        "Content-Type": "application/json"
    }
    
    if __name__ == '__main__':
        with requests.post(url, json=data, headers=headers, stream=True) as r:
            for line in r.iter_lines(chunk_size=1024):
                print(line)
    
    import requests
    import json
    
    url = "http://<your-endpoint-here>"
    token = "<your-token-here>"
    data = {"question": "Where is the capital of France?"}
    
    # 设置请求头,包含您的token
    headers = {
        "Authorization": f"Bearer {token}",
        "Content-Type": "application/json"
    }
    
    response = requests.post(url, json=data, headers=headers)
    
    if response.status_code == 200:
        print("请求成功,返回结果:")
        print(response.text)
    else:
        print(f"请求失败,状态码: {response.status_code}")
    

    返回示例

    event: Message
    data: {"answer": ""}
    
    event: Message
    data: {"answer": "The"}
    
    event: Message
    data: {"answer": " capital"}
    
    event: Message
    data: {"answer": " of"}
    
    event: Message
    data: {"answer": " France"}
    
    event: Message
    data: {"answer": " is"}
    
    event: Message
    data: {"answer": " Paris"}
    
    event: Message
    data: {"answer": "."}
    
    event: Message
    data: {"answer": ""}
    {"answer":"The capital of France is Paris."}

    请求参数配置说明:

    参数

    描述

    url

    请求的目标URL。其中<your-endpoint-here>需要替换为步骤1中获取的Endpoint。

    token

    HTTP头部信息。其中<your-token-here>需要替换为步骤1中获取的Token。

    data

    请求的主体数据。格式为JSON对象,包含一个Key-Value对,即问题字符串。其中Key需要与应用流中“开始节点”中的参数“对话输入”字段一致,此处为默认字段question

    "Accept": "text/event-stream"

    表示Client接受SSE请求,返回的信息为流式信息。注:仅当LLM节点作为应用流的输出节点时(结束节点的直接输入必须是LLM节点),才支持流式调用。

    完整模式

    Langstudio支持SSE(Server-Sent Events),在发送请求时可以输出应用流(Flow)执行时对应各节点的状态、错误信息、输出消息等,同时支持定制事件中node_run_infos的内容组成。本文以在线调试方式举例说明,您需要在调用地址后面追加/run,然后编辑请求Body:

    image

    请求Body参数字段说明:

    字段名

    类型

    默认值

    描述

    inputs

    Mapping[str, Any]

    Flow的输入数据字典。键(Key)应与Flow定义的输入字段名称匹配。如果Flow无输入,则忽略此字段。

    stream

    bool

    True

    控制响应格式。取值:

    • True:以SSE流式响应。响应Header中的Content-Typetext/event-stream,数据采用DataOnly的方式返回,按照事件不同,分为RunStarted、NodeUpdated、RunOutputRunTerminated,详情请参见表格下文。

    • False:以单个JSON体响应。响应Header中的Content-Typeapplication/json,可参见在线调试中的响应信息。

    response_config

    Dict[str, Any]

    -

    控制流式响应(当stream=True) 中包含的节点详细信息。

    ∟ include_node_description

    bool

    False

    (response_config内)是否在SSE事件流中包含节点描述。

    ∟ include_node_display_name

    bool

    False

    (response_config内)是否在SSE事件流中包含节点名称。

    ∟ include_node_output

    bool

    False

    (response_config内)是否在SSE事件流中包含节点输出。

    ∟ exclude_nodes

    List[str]

    []

    (response_config内)要从SSE事件流中排除的节点名称列表。

    返回数据按事件不同,分为RunStarted、NodeUpdated、RunOutputRunTerminated:

    RunStarted事件

    • 定义:RunStarted事件标志着Flow执行的开始。通常作为运行的SSE流中发送的第一个事件。

    • Payload示例:

      data: {"event": "RunStarted", "run_id": "fb745e15-3b3b-4a10-9e0d-0bea08d47411", "timestamp": "2025-06-12T08:15:07.223611Z", "flow_run_info": {"run_id": "fb745e15-3b3b-4a10-9e0d-0bea08d47411", "status": "Running", "error": null, "otel_trace_id": ""}}
    • 字段说明:

      字段名

      类型

      描述

      event

      string

      事件类型,固定为RunStarted

      run_id

      string

      当前Flow执行的唯一标识符。

      timestamp

      string

      事件发生的时间戳,遵循ISO 8601标准。

      flow_run_info

      object

      包含整个Flow运行的最终状态信息。

      ∟ run_id

      string

      (flow_run_info内)Flow执行的唯一标识符(与外层run_id相同)。

      ∟ status

      string

      (flow_run_info内)Flow执行的初始状态,固定为Running。

      ∟ error

      object or null

      (flow_run_info内)如果Flow执行失败,则包含错误信息对象;否则为 null

      ∟ otel_trace_id

      string

      (flow_run_info内)与此Flow执行关联的OpenTelemetry追踪ID(可能为空或零值)。

    NodeUpdated事件

    • 定义:NodeUpdated事件表示Flow中一个或多个节点的状态或输出发生了变化。在一个Flow的执行过程中,当节点开始运行(Running)或完成执行(Completed/Failed)时,通常会发送此事件。如果设置了response_config,此事件还可以包含节点的描述、显示名称和输出。注:如果在请求的response_config中指定了exclude_nodes,则相应节点的NodeUpdated事件将不会返回。

    • Payload示例:

      data: {"event": "NodeUpdated", "run_id": "8f92b1a6-4d69-422a-a080-50713e488b56", "timestamp": "2025-04-25T08:57:15.208601Z", "node_run_infos": [{"node_name": "custom_python", "node": "custom_python", "status": "Running", "error": null, "duration": 0.0, "description": null, "display_name": null, "output": null}]}
      data: {"event": "NodeUpdated", "run_id": "8f92b1a6-4d69-422a-a080-50713e488b56", "timestamp": "2025-04-25T08:57:15.209621Z", "node_run_infos": [{"node_name": "custom_python", "node": "custom_python", "status": "Completed", "error": null, "duration": 0.001246, "description": null, "display_name": null, "output": {"text": "echo:你好", "input_length": 2}}]}
    • 字段说明:

      字段名

      类型

      描述

      event

      string

      事件类型,固定为NodeUpdated

      run_id

      string

      当前Flow执行的唯一标识符。

      timestamp

      string

      事件发生的时间戳,遵循ISO 8601标准。

      node_run_infos

      array[object]

      包含一个或多个节点运行信息的数组。每个对象代表一个状态或输出发生变化的节点。

      ∟ node_name

      string

      (node_run_infos内)节点的名称(旧版字段,与node字段相同)。

      ∟ node

      string

      (node_run_infos内)节点的名称。

      ∟ status

      string

      (node_run_infos内)节点当前的运行状态,如Running、Completed、Failed。

      ∟ error

      object or null

      (node_run_infos内)如果节点执行失败,则包含错误信息对象;否则为null。

      ∟ duration

      float

      (node_run_infos内)节点执行所花费的时间(秒)。对于Running状态,通常为0.0。

      ∟ description

      string or null

      (node_run_infos内)节点的描述。仅当请求中response_config.include_node_descriptiontrue时包含,否则为null

      ∟ display_name

      string or null

      (node_run_infos内)节点的显示名称。仅当请求中response_config.include_node_display_nametrue时包含,否则为null

      ∟ output

      object or null

      (node_run_infos内)节点的输出数据。仅当节点状态为Completed且请求中response_config.include_node_outputtrue时包含,否则为null

    RunOutput事件

    • 定义:RunOutput事件表示Flow执行已生成其最终输出。通常在Flow运行结束时的RunTerminated事件之前发生。

    • Payload示例:

      data: {"event": "RunOutput", "run_id": "4c185c72-1bb0-4beb-a288-f7a73e37fc3b_llm_3ce063ad-bc9b-417d-9e68-08ce92c3db1b", "timestamp": "2025-04-30T11:55:24.745130Z", "outputs": {"answer": "有什么"}, "output_metadata": {"answer": {"is_stream": true, "status": "Streaming"}}}
      
      data: {"event": "RunOutput", "run_id": "4c185c72-1bb0-4beb-a288-f7a73e37fc3b_llm_3ce063ad-bc9b-417d-9e68-08ce92c3db1b", "timestamp": "2025-04-30T11:55:24.829133Z", "outputs": {"answer": "可以帮助你的吗?"}, "output_metadata": {"answer": {"is_stream": true, "status": "Streaming"}}}
      
      data: {"event": "RunOutput", "run_id": "4c185c72-1bb0-4beb-a288-f7a73e37fc3b_llm_3ce063ad-bc9b-417d-9e68-08ce92c3db1b", "timestamp": "2025-04-30T11:55:24.950055Z", "outputs": {"answer": ""}, "output_metadata": {"answer": {"is_stream": true, "status": "Streaming"}}}
      
      data: {"event": "RunOutput", "run_id": "4c185c72-1bb0-4beb-a288-f7a73e37fc3b_llm_3ce063ad-bc9b-417d-9e68-08ce92c3db1b", "timestamp": "2025-04-30T11:55:24.954983Z", "outputs": {}, "output_metadata": {"answer": {"is_stream": true, "status": "Finished"}}}
      
      data: {"event": "RunOutput", "run_id": "4c185c72-1bb0-4beb-a288-f7a73e37fc3b_python_oHG7_1c9fb0ac-0f45-4dbc-bf97-8e4175fd991c", "timestamp": "2025-04-30T11:55:24.957091Z", "outputs": {"python_output": "Hello: 你好!有什么可以帮助你的吗?"}, "output_metadata": {"python_output": {"is_stream": false, "status": "Finished"}}}
    • 字段说明:

      字段名

      类型

      描述

      event

      string

      事件类型,固定为RunOutput

      run_id

      string

      当前Flow执行的唯一标识符。

      timestamp

      string

      事件发生的时间戳,遵循ISO 8601标准。

      outputs

      object

      包含Flow最终输出结果的字典。其具体结构取决于Flow设计时定义的输出。

      output_metadata

      object

      包含Flow输出元数据的字典。键是输出名称(与outputs中的键对应),值是包含该输出元数据(例如is_streamstatus)的对象。

    RunTerminated事件

    • 定义:RunTerminated事件标志着Flow执行的结束。通常作为运行的SSE流中发送的最后一个事件。

    • Payload示例:

      data: {"event": "RunTerminated", "run_id": "8f92b1a6-4d69-422a-a080-50713e488b56", "timestamp": "2025-04-25T08:57:15.212791Z", "flow_run_info": {"run_id": "8f92b1a6-4d69-422a-a080-50713e488b56", "status": "Completed", "error": null, "otel_trace_id": "0x00000000000000000000000000000000"}}
    • 字段说明:

      字段名

      类型

      描述

      event

      string

      事件类型,固定为RunTerminate

      run_id

      string

      当前Flow执行的唯一标识符。

      timestamp

      string

      事件发生的时间戳,遵循ISO 8601标准。

      flow_run_info

      object

      包含整个Flow运行的最终状态信息。

      ∟ run_id

      string

      (flow_run_info内)Flow执行的唯一标识符(与外层run_id相同)。

      ∟ status

      string

      (flow_run_info内)Flow执行的最终状态,如Completed、Failed、Canceled。

      ∟ error

      object or null

      (flow_run_info内)如果Flow执行失败,则包含错误信息对象;否则为 null

      ∟ otel_trace_id

      string

      (flow_run_info内)与此Flow执行关联的OpenTelemetry追踪ID(可能为空或零值)。

OpenAI兼容方式调用

部署的对话应用流(ChatFlow)支持以兼容OpenAI的方式进行调用,同时也允许被其他支持OpenAI的客户端使用。

基于OpenAI API的方式

本文以cURL命令进行流式调用举例说明,请求/返回示例如下:

请求示例:

curl --location '<Endpoint>/v1/chat/completions' \
--header "Authorization: Bearer $DASHSCOPE_API_KEY" \
--header 'Content-Type: application/json' \
--data '{
    "model": "default",  
    "messages": [
        {
            "role": "system",
            "content": "You are a helpful assistant."
        },
        {
            "role": "user", 
            "content": "Who are you?"
        }
    ],
    "stream":true
}'

请求参数配置说明:

参数

描述

--location '<Endpoint>/v1/chat/completions'

请求的目标URL。其中<Endpoint>需要替换为API调用-步骤1中获取的Endpoint。

--header "Authorization: Bearer $DASHSCOPE_API_KEY"

HTTP头部信息。其中$DASHSCOPE_API_KEY需要替换为API调用-步骤1中获取的Token。

"model": "default"

模型名称,固定为default

"stream":true

返回的信息是否为流式信息。注:仅当LLM节点作为应用流的输出节点时(结束节点的直接输入必须是LLM节点),才支持流式调用。

返回示例:

data: {"choices":[{"delta":{"content":"","role":"assistant"},"index":0,"logprobs":null,"finish_reason":null}],"object":"chat.completion.chunk","usage":null,"created":1715931028,"system_fingerprint":null,"model":"qwen-plus","id":"chatcmpl-3bb05cf5cd819fbca5f0b8d67a025022"}

data: {"choices":[{"finish_reason":null,"delta":{"content":"I am"},"index":0,"logprobs":null}],"object":"chat.completion.chunk","usage":null,"created":1715931028,"system_fingerprint":null,"model":"qwen-plus","id":"chatcmpl-3bb05cf5cd819fbca5f0b8d67a025022"}

data: {"choices":[{"delta":{"content":"a large"},"finish_reason":null,"index":0,"logprobs":null}],"object":"chat.completion.chunk","usage":null,"created":1715931028,"system_fingerprint":null,"model":"qwen-plus","id":"chatcmpl-3bb05cf5cd819fbca5f0b8d67a025022"}

data: {"choices":[{"delta":{"content":"language model"},"finish_reason":null,"index":0,"logprobs":null}],"object":"chat.completion.chunk","usage":null,"created":1715931028,"system_fingerprint":null,"model":"qwen-plus","id":"chatcmpl-3bb05cf5cd819fbca5f0b8d67a025022"}

data: {"choices":[{"delta":{"content":"created by Alibaba Cloud"},"finish_reason":null,"index":0,"logprobs":null}],"object":"chat.completion.chunk","usage":null,"created":1715931028,"system_fingerprint":null,"model":"qwen-plus","id":"chatcmpl-3bb05cf5cd819fbca5f0b8d67a025022"}

data: {"choices":[{"delta":{"content":". I am called Qwen."},"finish_reason":null,"index":0,"logprobs":null}],"object":"chat.completion.chunk","usage":null,"created":1715931028,"system_fingerprint":null,"model":"qwen-plus","id":"chatcmpl-3bb05cf5cd819fbca5f0b8d67a025022"}

data: {"choices":[{"delta":{"content":""},"finish_reason":"stop","index":0,"logprobs":null}],"object":"chat.completion.chunk","usage":null,"created":1715931028,"system_fingerprint":null,"model":"qwen-plus","id":"chatcmpl-3bb05cf5cd819fbca5f0b8d67a025022"}

data: [DONE]

被其他客户端应用集成

本文以Windows平台上的ChatBox v1.13.4应用举例说明。其他客户端应用(如Cherry Studio、AnythingLLM等)请参见本地App集成RAG服务

  1. 下载并安装Chatbox

  2. 打开ChatBox,按照以下方式配置模型提供方名称,如LangStudio。

    image

  3. 选择已配置的模型提供方,配置服务请求参数。

    image

    关键参数说明:

    参数

    描述

    API 模式

    固定为OpenAI API兼容

    API 密钥

    配置已部署LangStudio服务的Token,获取方式见API调用-步骤1

    API 主机

    配置已部署LangStudio服务的调用地址(获取方式见API调用-步骤1),并在末尾添加/v1后缀。本文以公网调用地址为例,则API主机需配置为http://langstudio-20250319153409-xdcp.115770327099****.cn-hangzhou.pai-eas.aliyuncs.com/v1

    API 路径

    固定为/chat/completions

    模型

    单击新建,输入自定义模型ID,如qwen3-8b。

  4. Chat对话框中调用已部署的LangStudio服务。

    image

查看Trace

在调用服务后,系统会自动生成一条Trace记录。您可以在链路追踪页签下单击指定链路操作列的查看链路,通过查看Trace详情进行应用流效果的评估。

image

Trace数据支持您查看应用流中各个节点的输入和输出信息,如向量数据库召回的结果,或LLM节点的输入和输出信息等。

附录:对话历史

对于“对话型”应用流,LangStudio提供了多轮对话的历史消息存储功能。您可以选择使用本地存储或外部存储来保存对话历史。

存储类型

  • 本地存储:服务将利用本地磁盘,在部署应用流的EAS实例上自动创建一个名为chat_history.dbSQLite数据库来保存对话历史记录,默认存储路径为/langstudio/flow/需要注意,本地存储方案不支持多实例部署。请定期检查本地磁盘的使用情况,您也可以通过下文提供的API接口进行对话历史数据的查询和删除操作。当EAS实例被移除时,相关的对话历史数据也将一并被清除。

  • 外部存储:目前支持使用RDS MySQL进行存储。您需要在部署服务时,为对话历史存储配置一个RDS MySQL连接,具体配置方法请参见服务连接配置-数据库。服务将在您配置的RDS MySQL数据库中自动创建以服务名称为后缀的表,例如langstudio_chat_session_<服务名称>langstudio_chat_history_<服务名称>,分别用于存储对话Session及对话历史消息。

Session/User支持

每一次对应用流服务的对话请求都是无状态的,当您希望多次请求被当作是同一个对话时,需要通过手动配置请求头的方式完成。服务请求方式详情请参见API调用

请求头名称

数据类型

说明

备注

Chat-Session-Id

String

会话ID,每一次对服务的请求,系统会自动向本次会话分配唯一标识符,用以区分不同会话,并通过Response HeaderChat-Session-Id字段返回。

支持使用自定义会话ID,为了保证唯一性,会话ID规范为长度为32-255个字符,支持大小写字母、数字、下划线(_)、中划线(-)、英文冒号(:)。

Chat-User-Id

String

用户ID,标识对话所属用户。系统不会自动分配,支持用户自定义。

-

对话历史API

应用流服务还提供了对话历史数据管理API,您可以方便地通过API来查看和删除这些数据。只需通过GET请求访问 {Endpoint}/openapi.json,即可获取完整的API Schema。该Schema基于Swagger标准构建,为了更直观地理解和探索这些API,建议您使用Swagger UI进行可视化操作,使操作更加简单明了。