El agente de Python es un componente desarrollado por Alibaba Cloud para recopilar datos de observability en aplicaciones Python. Basado en el estándar OpenTelemetry, ofrece instrumentación automática y admite el rastreo de aplicaciones LLM.
Contexto
Una aplicación LLM (modelo de lenguaje grande) es cualquier aplicación construida con este tipo de modelo. Gracias a su entrenamiento con conjuntos masivos de datos y parámetros, los LLM pueden responder preguntas en lenguaje natural de forma similar a un ser humano. Se utilizan ampliamente en procesamiento de lenguaje natural, generación de texto y sistemas de diálogo inteligente. A medida que estas aplicaciones se vuelven más comunes, ofrecer servicios de inference eficientes representa un desafío importante. Los frameworks de servicio tradicionales suelen presentar cuellos de botella en el rendimiento y una gestión ineficiente de la memoria al manejar solicitudes concurrentes. Los frameworks de inference para LLM, como vLLM, están diseñados específicamente para resolver estos problemas críticos.
Los resultados de un LLM suelen ser difíciles de predecir con precisión. Además, factores como las discrepancias entre los resultados de entrenamiento y producción, la deriva en la distribución de datos que degrada el rendimiento, la calidad obsoleta de los datos y la falta de fiabilidad de dependencias externas pueden afectar negativamente el desempeño general de la aplicación LLM y del servicio de inference. Por lo tanto, es fundamental detectar cualquier disminución en la calidad de los resultados del modelo tan pronto como ocurra.
ARMS permite la instrumentación automática de aplicaciones LLM mediante el agente de Python. Tras integrar su aplicación LLM con ARMS, podrá consultar la visualización de sus trazas y analizar de manera intuitiva los detalles de entrada y salida, así como el consumo de tokens en los distintos tipos de operación. Para obtener más información, consulte LLM trace analysis.
Para ver la lista de frameworks de inference y aplicaciones LLM compatibles con ARMS, consulte Python components and frameworks supported by ARMS Application Monitoring.
Instalar el agente de Python
Elija un método de instalación según el entorno de despliegue de su aplicación LLM:
Iniciar su aplicación con el agente de Python
aliyun-instrument python llm_app.py
Reemplace llm_app.py por el archivo real de su aplicación. Si aún no cuenta con una aplicación LLM para integrar, puede utilizar la aplicación de demostración proporcionada en Appendix.
-
El agente de Python de ARMS detecta automáticamente el tipo de aplicación según las dependencias instaladas:
-
Si instala alguna de las siguientes dependencias, su aplicación se identifica como una aplicación LLM:
openai
dashscope
llama_index
langchain
-
Si instala alguna de las siguientes dependencias, su aplicación se identifica como un servicio LLM:
vllm
sglang
-
Para forzar un tipo específico de aplicación, establezca la variable de entorno APSARA_APM_APP_TYPE. Los valores válidos son:
microservice: aplicación de microservicio estándar
app: aplicación LLM
model: servicio LLM
-
Resultado de la ejecución
Aproximadamente un minuto después del inicio, si su aplicación de Python aparece en la consola de ARMS bajo y reporta datos, la integración se completó correctamente.
Configuración
Recopilación de contenido de entrada y salida
Valor predeterminado: True (habilitado por defecto).
Cuando se deshabilita: Al enviar consultas, solo se recopila el tamaño de campos como la entrada y salida de modelos, herramientas y bases de conocimiento, pero no su contenido real.
Plugins donde aplica actualmente: Solo Dify y LangChain admiten esta configuración.
Para configurar: Establezca la variable de entorno OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT=False.
Dividir aplicaciones LLM
Valor predeterminado: False (la división de aplicaciones está deshabilitada por defecto).
Cuando se habilita: Los datos reportados se dividen en subaplicaciones LLM. Cada aplicación LLM, como un flujo de trabajo de Dify, un agente o una aplicación de chat, aparece como una aplicación independiente en ARMS.
Plugins donde aplica actualmente: Solo Dify admite esta configuración.
Para configurar: Establezca la variable de entorno PROFILER_GENAI_SPLITAPP_ENABLE=True.
Regiones compatibles: Heyuan, Singapore.
Límite de longitud del contenido del mensaje
Valor predeterminado: 8K caracteres.
Cuando se habilita: Limita la longitud de cada campo de contenido del mensaje (como los mensajes de entrada y salida). El contenido que exceda el límite de caracteres especificado se trunca.
Plugins donde aplica actualmente: Esta configuración aplica a todos los plugins compatibles con OpenTelemetry (como LangChain, DashScope, Dify, etc.).
Para configurar: Si la versión de su agente es >= 1.8.3, establezca la variable de entorno OTEL_INSTRUMENTATION_GENAI_MESSAGE_CONTENT_MAX_LENGTH=<integer_value>, y reemplace <integer_value> con el límite de caracteres deseado como un valor entero.
Límite de longitud del valor de atributo de Span
Valor predeterminado: No establecido (sin límite por defecto).
Cuando se habilita: Limita la longitud de los valores de atributo de Span reportados (como gen_ai.agent.description). Los valores que excedan el límite de caracteres especificado se truncan.
Plugins donde aplica actualmente: Esta configuración aplica a todos los plugins compatibles con OpenTelemetry (como LangChain, DashScope, Dify, etc.).
Para configurar: Establezca la variable de entorno OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT=<integer_value>, y reemplace <integer_value> con el límite de caracteres deseado como un valor entero.
Comprimir Spans
Valor predeterminado: No establecido (la compresión está deshabilitada por defecto).
Cuando se habilita: Varios Spans idénticos generados en el mismo nivel se comprimen en uno solo, conservando únicamente la información clave.
Plugins donde aplica actualmente: Esta configuración aplica a todos los plugins compatibles con OpenTelemetry (como LangChain, DashScope, Dify, etc.).
Configure esto estableciendo la variable de entorno APSARA_APM_INSTRUMENTER_SPAN_COMPRESS_ENABLED
=true.
Apéndice
Demostración de OpenAI
llm_app.py
import openai
from fastapi import FastAPI
import uvicorn
app = FastAPI()
@app.get("/")
def call_openai():
client = openai.OpenAI(api_key="sk-xxx")
response = client.chat.completions.create(
model="gpt-4",
messages=[{"role": "user", "content": "Write a haiku."}],
max_tokens=20,
)
return {"data": f"{response}"}
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=8000)
requirements.txt
fastapi
uvicorn
openai >= 1.0.0
Demostración de DashScope
llm_app.py
from http import HTTPStatus
import dashscope
from dashscope import Generation
from fastapi import FastAPI
import uvicorn
app = FastAPI()
@app.get("/")
def call_dashscope():
dashscope.api_key = 'YOUR-DASHSCOPE-API-KEY'
responses = Generation.call(model=Generation.Models.qwen_turbo,
prompt='How is the weather today?')
resp = ""
if responses.status_code == HTTPStatus.OK:
resp = f"Result is: {responses.output}"
else:
resp = f"Failed request_id: {responses.request_id}, status_code: {responses.status_code}, code: {responses.code}, message: {responses.message}"
return {"data": f"{resp}"}
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=8000)
requirements.txt
fastapi
uvicorn
dashscope >= 1.0.0
Demostración de LlamaIndex
Coloque los documentos de la base de conocimiento (en formato PDF, TXT, DOC u otros formatos de texto) en la carpeta data.
llm_app.py
import time
from fastapi import FastAPI
import uvicorn
import aiohttp
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader
from llama_index.vector_stores.chroma import ChromaVectorStore
from llama_index.core import StorageContext
from llama_index.embeddings.dashscope import DashScopeEmbedding
import chromadb
import dashscope
import os
from dotenv import load_dotenv
from llama_index.core.llms import ChatMessage
from llama_index.core import VectorStoreIndex, get_response_synthesizer
from llama_index.core.retrievers import VectorIndexRetriever
from llama_index.core.query_engine import RetrieverQueryEngine
from llama_index.llms.dashscope import DashScope, DashScopeGenerationModels
import random
load_dotenv()
os.environ["DASHSCOPE_API_KEY"] = 'sk-xxxxxx'
dashscope.api_key = 'sk-xxxxxxx'
api_key = 'sk-xxxxxxxx'
llm = DashScope(model_name=DashScopeGenerationModels.QWEN_MAX,api_key=api_key)
# create client and a new collection
chroma_client = chromadb.EphemeralClient()
chroma_collection = chroma_client.create_collection("chapters")
# define embedding function
embed_model = DashScopeEmbedding(model_name="text-embedding-v1", api_key=api_key)
# load documents
filename_fn = lambda filename: {"file_name": filename}
# automatically sets the metadata of each document according to filename_fn
documents = SimpleDirectoryReader(
"./data/", file_metadata=filename_fn
).load_data()
# set up ChromaVectorStore and load in data
vector_store = ChromaVectorStore(chroma_collection=chroma_collection)
storage_context = StorageContext.from_defaults(vector_store=vector_store)
index = VectorStoreIndex.from_documents(
documents, storage_context=storage_context, embed_model=embed_model
)
retriever = VectorIndexRetriever(
index=index,
similarity_top_k=4,
verbose=True
)
# configure response synthesizer
response_synthesizer = get_response_synthesizer(llm=llm, response_mode="refine")
# assemble query engine
query_engine = RetrieverQueryEngine(
retriever=retriever,
response_synthesizer=response_synthesizer,
)
SYSTEM_PROMPT = """
You are a general-knowledge chatbot for children. Your task is to answer user questions by combining the most relevant content found in the knowledge base. Do not answer subjective questions.
"""
# Initialize the conversation with a system message
messages = [ChatMessage(role="system", content=SYSTEM_PROMPT)]
app = FastAPI()
async def fetch(question):
url = "https://www.aliyun.com"
call_url = os.environ.get("LLM_INFRA_URL")
if call_url is None or call_url == "":
call_url = url
else:
call_url = f"{call_url}?question={question}"
print(call_url)
async with aiohttp.ClientSession() as session:
async with session.get(call_url) as response:
print(f"GET Status: {response.status}")
data = await response.text()
print(f"GET Response JSON: {data}")
return data
@app.get("/heatbeat")
def heatbeat():
return {"msg", "ok"}
cnt = 0
@app.get("/query")
async def call(question: str = None):
global cnt
cnt += 1
if cnt == 20:
cnt = 0
raise BaseException("query is over limit,20 ", 401)
# Add user message to the conversation history
message = ChatMessage(role="user", content=question)
# Convert messages into a string
message_string = f"{message.role}:{message.content}"
search = await fetch(question)
print(f"search:{search}")
resp = query_engine.query(message_string)
print(resp)
return {"data": f"{resp}".encode('utf-8').decode('utf-8')}
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=8000)
requirements.txt
fastapi
uvicorn
numpy==1.23.5
llama-index==0.10.62
llama-index-core==0.10.28
llama-index-embeddings-dashscope==0.1.3
llama-index-llms-dashscope==0.1.2
llama-index-vector-stores-chroma==0.1.6
aiohttp
Demostración de LangChain
llm_app.py
from fastapi import FastAPI
from langchain.llms.fake import FakeListLLM
import uvicorn
from langchain.chains import LLMChain
from langchain.prompts import PromptTemplate
app = 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)
requirements.txt
fastapi
uvicorn
langchain
langchain_community
Demostración de Dify
Puede crear rápidamente una aplicación Dify siguiendo las instrucciones en Build a customized web-based AI Q&A assistant using Dify.