Python 应用可观测重磅上线:解决 LLM 应用落地的“最后一公里”问题

news/2024/10/22 18:24:26

作者:彦鸿

背景

随着 LLM(大语言模型)技术的不断成熟和应用场景的不断拓展,越来越多的企业开始将 LLM 技术纳入自己的产品和服务中。LLM 在自然语言处理方面表现出令人印象深刻的能力。然而,其内部机制仍然不明确,这种缺乏透明度的做法给下游应用带来了不必要的风险,这也导致了 LLM 应用落地难等问题。因此,理解和解释这些模型对于阐明其行为、局限性和社会影响至关重要。LLM 可观测性能够为模型可解释性提供必要的数据支撑,对于研究人员和开发人员来说,LLM 应用可观测,可以识别意外的偏见、风险和性能改进。

作为 AI 时代的编程语言,Python 在近年来得到了广泛的应用。目前热门的 LLM 项目,如 Langchain、Llama-index、Dify、PromptFlow、OpenAI、Dashscope 等均使用 Python 语言进行开发。为增强对 Python 应用,特别是 Python LLM 应用的可观测性,阿里云推出了 Python 探针,旨在解决 LLM 应用落地难、难落地等问题。助力企业落地 LLM。

本文将从阿里云 Python 探针的接入步骤、产品能力、兼容性等方面展开介绍。并提供一个简单的 LLM 应用例子,方便测试。

应用示例

为方便大家理解和感受 Python 探针的功能,本文构建了一个 LLM 应用的示例:

某公司升级了其产品,新增了智能问答功能。其基本架构图如下:

基本业务流程为用户向 server 端发起一个问答请求,server 去调用 chatbot 获取回复结果,chatbot 收到请求后进行 RAG 后回复。

为观测此 LLM 应用,该公司接入了阿里云 Python 探针。下文将介绍如何接入阿里云 Python 探针。

Python 应用接入应用监控

以下为在 ACK 环境下 Python 探针的接入方式,其他接入方式见:https://help.aliyun.com/zh/arms/application-monitoring/user-guide/start-monitoring-python-applications/

前提条件

  • 创建 Kubernetes 集群。您可按需选择创建 ACK 专有集群、创建 ACK 托管集群或创建 ACK Serverless 集群。
  • 创建命名空间,具体操作,请参见管理命名空间与配额。本文示例中的命名空间名称为 arms-demo。
  • 检查您的 Python 版本和框架版本。具体要求,请参见 Python 探针兼容性要求。

步骤一:安装 ARMS 应用监控组件

  1. 登录容器服务管理控制台 [ 1]

  2. 在左侧导航栏单击集群,然后在集群列表页面单击目标集群名称。

  3. 在左侧导航栏选择运维管理 > 组件管理,然后在右上角通过关键字搜索 ack-onepilot。 (重要:请确保 ack-onepilot 的版本在 3.2.4 及以上。)

  4. 在 ack-onepilot 卡片上单击安装。 (说明:ack-onepilot 组件默认支持 1000 个 pod 规模,集群 pod 每超过 1000 个,ack-onepilot 资源对应的 CPU 请增加 0.5 核、内存请增加 512M。)

  5. 在弹出的页面中可以配置相关的参数,建议使用默认值,单击确定。 (说明:安装完成后,您可以在组件管理页面升级、配置或卸载 ack-onepilot 组件。)

步骤二:修改 Dockerfile

  1. 首先从 pypi 仓库下载探针安装器
pip3 install aliyun-bootstrap
  1. 使用 aliyun-bootstrap 安装探针
aliyun-bootstrap -a install
  1. 使用阿里云 python 探针启动
aliyun-instrument python app.py
  1. 构建镜像,具体的 Dockerfile 示例如下:

Dockerfile 示例:

更改前的 Dockerfile:

# 使用Python 3.10基础镜像
FROM docker.m.daocloud.io/python:3.10# 设置工作目录
WORKDIR /app# 复制requirements.txt文件到工作目录
COPY requirements.txt .# 使用pip安装依赖
RUN pip install --no-cache-dir -r requirements.txtCOPY ./app.py /app/app.py
# 暴露容器的8000端口
EXPOSE 8000
CMD ["python","app.py"]

更改后的 Dockerfile:

# 使用官方的Python 3.10基础镜像
FROM docker.m.daocloud.io/python:3.10# 设置工作目录
WORKDIR /app# 复制requirements.txt文件到工作目录
COPY requirements.txt .# 使用pip安装依赖
RUN pip install --no-cache-dir -r requirements.txt
#########################安装aliyun python 探针###############################
RUN pip3 install  aliyun-bootstrap  && aliyun-bootstrap -a install
##########################################################COPY ./app.py /app/app.py# 暴露容器的8000端口
EXPOSE 8000
#########################################################
CMD ["aliyun-instrument","python","app.py"]

注意事项(必看)

  1. 有使用 unicorn 启动的应用推荐使用以下命令做替换:

例如:

unicorn -w 4 -b 0.0.0.0:8000 app:app

更改为:

gunicorn -w 4 -k uvicorn.workers.UvicornWorker -b 0.0.0.0:8000 app:app
  1. 有使用 gevent 协程的需要配置参数

程序中有使用

from gevent import monkey

monkey.patch_all()

需要设置环境变量 GEVENT_ENABLE=true

GEVENT_ENABLE=true

步骤三:授予 ARMS 资源的访问权限

  • 如果需监控 ASK(容器服务 Serverless 版)或对接了 ECI 的集群应用,请在云资源访问授权 [ 2] 页面完成授权,然后重启 ack-onepilot 组件下的所有 Pod。
  • 如果需监控 ACK 集群应用,但 ACK 集群中不存在 ARMS Addon Token,请执行以下操作手动为集群授予 ARMS 资源的访问权限。如果已经存在 ARMS Addon Token,请跳转至步骤四。

查看集群是否存在 ARMS Addon Token:

a. 登录容器服务管理控制台,在集群列表页面,单击目标集群名称进入集群详情页。
b. 在左侧导航栏选择配置管理 > 保密字典,然后在顶部选择命名空间为kube-system,查看addon.arms.token是否存在。

说明:集群存在 ARMS Addon Token 时,ARMS 会进行免密授权。Kubernetes 托管版集群默认存在 ARMS Addon Token,但对于部分早期创建的 Kubernetes 托管版集群,可能会存在没有 ARMS Addon Token 的情况,因此,对于 Kubernetes 托管版集群,建议首先检查 ARMS Addon Token 是否存在。若不存在,需进行手动授权。

  1. 登录容器服务管理控制台。

  2. 在左侧导航栏选择集群,然后单击目标集群名称。

  3. 在目标集群的集群信息页面单击集群资源页签,然后单击 Worker RAM 角色右侧的链接。

  4. 在角色页面的权限管理页签上,单击新增授权。

  5. 选择权限为 AliyunARMSFullAccess,然后单击确定。 (如果需要监控专有版集群和注册集群应用,请确认对应的阿里云账号已包含 AliyunARMSFullAccess 和 AliyunSTSAssumeRoleAccess 权限。添加权限的操作,请参见为 RAM 用户授权 [ 3]

安装 ack-onepilot 组件后,还需要在 ack-onepilot 中填写有 ARMS 权限的阿里云账号 AK/SK。

  1. 在左侧导航栏选择应用 > Helm 页面,单击 ack-onepilot 组件右侧的更新。

  2. 将 accessKey 和 accessKeySecret 替换为当前账号的 AccessKey,然后单击确定。 (说明:获取 AccessKey 的操作,请参见创建 AccessKey [ 4] 。)

  3. 重启应用 Deployment。

步骤四:为 Python 应用开启 ARMS 应用监控

  1. 在容器服务管理控制台左侧导航栏单击集群,在集群列表页面上的目标集群右侧操作列单击应用管理。

  2. 在无状态页面的目标应用右侧选择更多 > 查看 YAML。 (如需创建一个新应用,单击右上角的使用 YAML 创建资源。)

  3. 在 YAML 文件中将以下 labels 添加到 spec.template.metadata 层级下。

labels:aliyun.com/app-language: python # Python应用必填,标明此应用是Python应用。armsPilotAutoEnable: 'on'armsPilotCreateAppName: "<your-deployment-name>"    #应用在ARMS中的展示名称。

创建一个无状态(Deployment)应用并开启 ARMS 应用监控的完整 YAML 示例模板如下:

apiVersion: apps/v1
kind: Deployment
metadata:labels:app: arms-python-clientname: arms-python-clientnamespace: arms-demo
spec:progressDeadlineSeconds: 600replicas: 1revisionHistoryLimit: 10selector:matchLabels:app: arms-python-clientstrategy:rollingUpdate:maxSurge: 25%maxUnavailable: 25%type: RollingUpdatetemplate:metadata:labels:app: arms-python-clientaliyun.com/app-language: python # Python应用必填,标明此应用是Python应用。armsPilotAutoEnable: 'on'armsPilotCreateAppName: "arms-python-client"    #应用在ARMS中的展示名称。spec:containers:- image: registry.cn-hangzhou.aliyuncs.com/arms-default/python-agent:arms-python-clientimagePullPolicy: Alwaysname: clientresources:requests:cpu: 250mmemory: 300MiterminationMessagePath: /dev/termination-logterminationMessagePolicy: FilednsPolicy: ClusterFirstrestartPolicy: AlwaysschedulerName: default-schedulersecurityContext: {}terminationGracePeriodSeconds: 30---apiVersion: apps/v1
kind: Deployment
metadata:labels:app: arms-python-servername: arms-python-servernamespace: arms-demo
spec:progressDeadlineSeconds: 600replicas: 1revisionHistoryLimit: 10selector:matchLabels:app: arms-python-serverstrategy:rollingUpdate:maxSurge: 25%maxUnavailable: 25%type: RollingUpdatetemplate:metadata:labels:app: arms-python-serveraliyun.com/app-language: python # Python应用必填,标明此应用是Python应用。armsPilotAutoEnable: 'on'armsPilotCreateAppName: "arms-python-server"    #应用在ARMS中的展示名称。spec:containers:- env:- name: CLIENT_URLvalue: 'http://arms-python-client-svc:8000'- image: registry.cn-hangzhou.aliyuncs.com/arms-default/python-agent:arms-python-serverimagePullPolicy: Alwaysname: serverresources:requests:cpu: 250mmemory: 300MiterminationMessagePath: /dev/termination-logterminationMessagePolicy: FilednsPolicy: ClusterFirstrestartPolicy: AlwaysschedulerName: default-schedulersecurityContext: {}terminationGracePeriodSeconds: 30---apiVersion: v1
kind: Service
metadata:labels:app: arms-python-servername: arms-python-server-svcnamespace: arms-demo
spec:internalTrafficPolicy: ClusteripFamilies:- IPv4ipFamilyPolicy: SingleStackports:- name: httpport: 8000protocol: TCPtargetPort: 8000selector:app: arms-python-serversessionAffinity: Nonetype: ClusterIPapiVersion: v1
kind: Service
metadata:name: arms-python-client-svcnamespace: arms-demouid: 91f94804-594e-495b-9f57-9def1fdc7c1d
spec:internalTrafficPolicy: ClusteripFamilies:- IPv4ipFamilyPolicy: SingleStackports:- name: httpport: 8000protocol: TCPtargetPort: 8000selector:app: arms-python-clientsessionAffinity: Nonetype: ClusterIP

执行结果

待容器完成自动重新部署后,等待 1~2 分钟,在 ARMS 控制台的应用监控 > 应用列表页面单击应用名称,查看应用的监控指标。更多信息,请参见查看监控详情(新版)。

产品能力

应用接入成功后,就可以通过:https://arms.console.aliyun.com/#/tracing/list/cn-hangzhou 来查看 Python 应用的信息了。以下是一些内容的展示:

调用链分析

微服务场景

调用链分析功能可以通过自由组合筛选条件与聚合维度进行实时分析,并支持通过错/慢 Trace 分析功能,定位系统或应用产生错、慢调用的原因。

调用链详情:

大模型场景

针对大模型场景,您可以查看 LLM 领域的新版 TraceView,更直观地分析不同操作类型的输入输出、Token 消耗等信息。

首先切换为大模型视图:

具体的大模型调用信息:

监控指标

应用概览

应用拓扑

配置告警

通过配置告警,您可以制定针对特定应用的告警规则。当告警规则被触发时,系统会以您指定的通知方式向告警联系人或钉群发送告警信息,以提醒您采取必要的解决措施。具体操作,请参见应用监控告警规则 [ 5]

兼容性

Python 版本>=3.8

附件

arms-python-server:

import uvicorn
from fastapi import FastAPI, HTTPException
from logging import getLogger
from concurrent import futures
from opentelemetry import trace
tracer = trace.get_tracer(__name__)
_logger = getLogger(__name__)
import requests
import osdef call_requests():url = 'https://www.aliyun.com'  # 替换为你的实际地址call_url = os.environ.get("CALL_URL")if call_url is None or call_url == "":call_url = url# try:response = requests.get(call_url)response.raise_for_status()  # 如果请求返回了错误码则抛出异常print(f"response code: {response.status_code} - {response.text}")app = FastAPI()def call_client():_logger.warning("calling client")url = 'https://www.aliyun.com'  # 替换为你的实际地址call_url = os.environ.get("CLIENT_URL")if call_url is None or call_url == "":call_url = urlresponse = requests.get(call_url)# print(f"response code: {response.status_code} - {response.text}")return response.text@app.get("/")
async def call():with tracer.start_as_current_span("parent") as rootSpan:rootSpan.set_attribute("parent.value", "parent")with futures.ThreadPoolExecutor(max_workers=2) as executor:with tracer.start_as_current_span("ThreadPoolExecutorTest") as span:span.set_attribute("future.value", "ThreadPoolExecutorTest")future = executor.submit(call_client)future.result()
# call_client()return {"data": f"call"}if __name__ == "__main__":uvicorn.run(app, host="0.0.0.0", port=8000)

arms-python-client:

from fastapi import FastAPI
from langchain.llms.fake import FakeListLLM
import uvicorn
from langchain.chains import LLMChain
from langchain.prompts import PromptTemplateapp = FastAPI()
llm = FakeListLLM(responses=["I'll callback later.", "You 'console' them!"])template = """Question: {question}Answer: Let's think step by step."""prompt = PromptTemplate(template=template, input_variables=["question"])llm_chain = LLMChain(prompt=prompt, llm=llm)question = "What NFL team won the Super Bowl in the year Justin Beiber was born?"@app.get("/")
def call_langchain():res = llm_chain.run(question)return {"data": res}if __name__ == "__main__":uvicorn.run(app, host="0.0.0.0", port=8000)

相关链接:

[1] 容器服务管理控制台

https://account.aliyun.com/login/login.htm?oauth_callback=https%3A%2F%2Fcs.console.aliyun.com%2F

[2] 云资源访问授权

https://account.aliyun.com/login/login.htm?oauth_callback=https%3A%2F%2Fram.console.aliyun.com%2Frole%2Fauthorization%3Frequest%3D%257B%2522Services%2522%253A%255B%257B%2522Service%2522%253A%2522ECS%2522%252C%2522Roles%2522%253A%255B%257B%2522RoleName%2522%253A%2522AliyunMSEForECIRole%2522%252C%2522TemplateId%2522%253A%2522AliyunMSEForECIRole%2522%257D%255D%257D%255D%252C%2522ReturnUrl%2522%253A%2522https%253A%252F%252Farms.console.aliyun.com%2522%257D&clearRedirectCookie=1&lang=zh

[3] RAM 用户授权

https://help.aliyun.com/zh/ram/user-guide/grant-permissions-to-the-ram-user

[4] 创建 AccessKeyhttps://help.aliyun.com/zh/ram/user-guide/create-an-accesskey-pair

[5] 应用监控告警规则

https://help.aliyun.com/zh/arms/application-monitoring/user-guide/create-and-manage-alert-rules-in-application-monitoring-new/

参考链接:

https://help.aliyun.com/zh/arms/application-monitoring/user-guide/start-monitoring-python-applications/

https://help.aliyun.com/zh/arms/application-monitoring/developer-reference/python-probe-compatibility-requirements

点击此处立即开通 ARMS - 应用监控,享受每月 50GB 免费额度!加入钉钉群(群号:35568145)获得在线技术支持。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.ryyt.cn/news/74738.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

相关文章

计算机视觉领域的实际应用有什么

计算机视觉在多个行业和应用场景中有着广泛的实际应用,主要包括医疗图像分析、自动驾驶、物体检测、人脸识别、增强现实(AR)和虚拟现实(VR)、工业自动化、农业监测等。医疗图像分析用于诊断疾病和制定治疗方案,提高医疗服务的质量和效率。其中,自动驾驶是一个相对成熟的…

【八叉树】从上千万个物体中【**瞬间**】就近选取坐标

众里寻他千百度,蓦然回首,那人却在灯火阑珊处前情提要 在某些情况下,我们在场景中创建了数百万个物体,这些物体没有直接的网格或碰撞体(例如,通过GPU绘制的物体),因此无法通过常规的射线检测与碰撞体进行交互。我们仅掌握这些物体的坐标或顶点位置。在这种情况下,我们…

Python 数据分析与可视化有什么区别

在当今的数据驱动时代,Python已成为数据分析和数据可视化的重要工具。尽管这两个领域经常在数据科学项目中相互交织,但它们在功能和目的上存在本质区别。本文旨在详细探讨Python在数据分析和数据可视化方面的差异,包括它们的定义、使用的主要库、应用场景以及在实际项目中的…

python第六章课后习题

点击查看代码print("学号:2023310143028")点击查看代码def prim(graph, start): num_nodes = len(graph) visited = [False] * num_nodes min_heap = [(0, start, -1)] mst_cost = 0 mst_edges = [] while min_heap: weight, u, parent = heapq.heappop(min…

go1.18版本下 beego/bee安装无法生成exe问题已解决

转自: https://www.cnblogs.com/leijiangsheng/p/17392795.html 我原来的项目是教育学习APP使用gin框架,很多东西都是自己原来实现的。最近开发小程序,需要重新独立后台,又重新找了下go框架研究了下,beego确实是个好框架,至少项目能用到的都考虑进去了。 然后发现我本地装…

哈希碰撞

问:两个字符串hashcode相同equals一定相同吗?equals相同hashcode一定相同吗? 答:equals相同hashcode一定相同,hashcode因为哈希碰撞所以equals不一定相同。 Hash如何存数据hash表的本质其实就是数组,hash表中通常存放的是键值对Entry。 如下图:这里的学号是个key,哈希表…

实景三维助力智慧水利建设

随着信息技术的快速发展,智慧水利作为智慧城市的重要组成部分,正受到越来越多的关注。实景三维技术,以其独特的优势,为智慧水利建设提供了强有力的支撑。本文将探讨实景三维技术如何助力智慧水利建设。一、智慧水利建设的背景智慧水利是指运用现代信息技术,对水利设施进行…

python第四章课后习题

点击查看代码 import numpy as np import cvxpy as cpx=cp.Variable(6,pos=True) obj=cp.Minimize(x[5]) a1=np.array([0.025, 0.015, 0.055, 0.026]) a2=np.array([0.05, 0.27, 0.19, 0.185, 0.185]) a3=np.array([1, 1.01, 1.02, 1.045, 1.065]) k=0.05; kk=[]; qq=[] while …