chore: import upstream snapshot with attribution
tools_continuous_delivery / Private PyPI non-main branch release (push) Has been skipped
tools_continuous_delivery / Private PyPI main branch release (push) Failing after 2m42s
Publish Promptflow Doc / Build (push) Has been cancelled
Publish Promptflow Doc / Deploy (push) Has been cancelled
Flake8 Lint / flake8 (push) Has been cancelled
Spell check CI / Spell_Check (push) Has been cancelled
tools_continuous_delivery / Private PyPI non-main branch release (push) Has been skipped
tools_continuous_delivery / Private PyPI main branch release (push) Failing after 2m42s
Publish Promptflow Doc / Build (push) Has been cancelled
Publish Promptflow Doc / Deploy (push) Has been cancelled
Flake8 Lint / flake8 (push) Has been cancelled
Spell check CI / Spell_Check (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
CHAT_DEPLOYMENT_NAME=gpt-35-turbo
|
||||
AZURE_OPENAI_API_KEY=<your_AOAI_key>
|
||||
AZURE_OPENAI_ENDPOINT=<your_AOAI_endpoint>
|
||||
@@ -0,0 +1,114 @@
|
||||
---
|
||||
resources: examples/tutorials/tracing/
|
||||
cloud: local
|
||||
category: tracing
|
||||
---
|
||||
|
||||
## Tracing
|
||||
|
||||
Prompt flow provides the tracing feature to capture and visualize the internal execution details for all flows.
|
||||
|
||||
For `DAG flow`, user can track and visualize node level inputs/outputs of flow execution, it provides critical insights for developer to understand the internal details of execution.
|
||||
|
||||
For `Flex flow` developers, who might use different frameworks (langchain, semantic kernel, OpenAI, kinds of agents) to create LLM based applications, prompt flow allow user to instrument their code in a [OpenTelemetry](https://opentelemetry.io/) compatible way, and visualize using UI provided by promptflow devkit.
|
||||
|
||||
## Instrumenting user's code
|
||||
#### Enable trace for LLM calls
|
||||
Let's start with the simplest example, add single line code `start_trace()` to enable trace for LLM calls in your application.
|
||||
```python
|
||||
from openai import OpenAI
|
||||
from promptflow.tracing import start_trace
|
||||
|
||||
# start_trace() will print a url for trace detail visualization
|
||||
start_trace()
|
||||
|
||||
client = OpenAI()
|
||||
|
||||
completion = client.chat.completions.create(
|
||||
model="gpt-4",
|
||||
messages=[
|
||||
{"role": "system", "content": "You are a poetic assistant, skilled in explaining complex programming concepts with creative flair."},
|
||||
{"role": "user", "content": "Compose a poem that explains the concept of recursion in programming."}
|
||||
]
|
||||
)
|
||||
|
||||
print(completion.choices[0].message)
|
||||
```
|
||||
|
||||
With the trace url, user will see a trace list that corresponding to each LLM calls:
|
||||

|
||||
|
||||
Click on line record, the LLM detail will be displayed with chat window experience, together with other LLM call params:
|
||||

|
||||
|
||||
More examples of adding trace for [autogen](https://microsoft.github.io/autogen/) and [langchain](https://python.langchain.com/docs/get_started/introduction/):
|
||||
|
||||
1. **[Add trace for Autogen](./autogen-groupchat/)**
|
||||
|
||||

|
||||
|
||||
2. **[Add trace for Langchain](./langchain)**
|
||||
|
||||

|
||||
|
||||
#### Trace for any function
|
||||
More common scenario is the application has complicated code structure, and developer would like to add trace on critical path that they would like to debug and monitor.
|
||||
|
||||
See the **[math_to_code](./math_to_code.py)** example on how to use `@trace`.
|
||||
|
||||
```python
|
||||
from promptflow.tracing import trace
|
||||
# trace your function
|
||||
@trace
|
||||
def code_gen(client: AzureOpenAI, question: str) -> str:
|
||||
sys_prompt = (
|
||||
"I want you to act as a Math expert specializing in Algebra, Geometry, and Calculus. "
|
||||
"Given the question, develop python code to model the user's question. "
|
||||
"Make sure only reply the executable code, no other words."
|
||||
)
|
||||
completion = client.chat.completions.create(
|
||||
model=os.getenv("CHAT_DEPLOYMENT_NAME", "gpt-35-turbo"),
|
||||
messages=[
|
||||
{
|
||||
"role": "system",
|
||||
"content": sys_prompt,
|
||||
},
|
||||
{"role": "user", "content": question},
|
||||
],
|
||||
)
|
||||
raw_code = completion.choices[0].message.content
|
||||
result = code_refine(raw_code)
|
||||
return result
|
||||
```
|
||||
|
||||
Execute below command will get an URL to display the trace records and trace details of each test.
|
||||
|
||||
```bash
|
||||
python math_to_code.py
|
||||
```
|
||||
|
||||
## Trace visualization in flow test and batch run
|
||||
### Flow test
|
||||
|
||||
If your application is created with DAG flow, all flow test and batch run will be automatically enable trace function. Take the **[chat_with_pdf](../../flows/chat/chat-with-pdf/)** as example.
|
||||
|
||||
Run `pf flow test --flow .`, each flow test will generate single line in the trace UI:
|
||||

|
||||
|
||||
Click a record, the trace details will be visualized as tree view.
|
||||
|
||||

|
||||
|
||||
### Evaluate against batch data
|
||||
Keep using **[chat_with_pdf](../../flows/chat/chat-with-pdf/)** as example, to trigger a batch run, you can use below commands:
|
||||
|
||||
```shell
|
||||
pf run create -f batch_run.yaml
|
||||
```
|
||||
Or
|
||||
```shell
|
||||
pf run create --flow . --data "./data/bert-paper-qna.jsonl" --column-mapping chat_history='${data.chat_history}' pdf_url='${data.pdf_url}' question='${data.question}'
|
||||
```
|
||||
Then you will get a run related trace URL, e.g. http://127.0.0.1:52008/v1.0/ui/traces?run=chat_with_pdf_variant_0_20240226_181222_219335
|
||||
|
||||

|
||||
@@ -0,0 +1,2 @@
|
||||
OAI_CONFIG_LIST.json
|
||||
groupchat
|
||||
@@ -0,0 +1,16 @@
|
||||
[
|
||||
{
|
||||
"model": "gpt-4",
|
||||
"api_key": "<your_AOAI_key>",
|
||||
"base_url": "<your_AOAI_endpoint>",
|
||||
"api_type": "azure",
|
||||
"api_version": "2023-06-01-preview"
|
||||
},
|
||||
{
|
||||
"model": "gpt-35-turbo",
|
||||
"api_key": "<your_AOAI_key>",
|
||||
"base_url": "<your_AOAI_endpoint>",
|
||||
"api_type": "azure",
|
||||
"api_version": "2023-06-01-preview"
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,6 @@
|
||||
# Tracing existing application using promptflow: Auto Generated Agent Group Chat
|
||||
|
||||
AutoGen offers conversable agents powered by LLM, tool or human, which can be used to perform tasks collectively via automated chat. This framework allows tool use and human participation through multi-agent conversation.
|
||||
Please find documentation about this feature [here](https://microsoft.github.io/autogen/docs/Use-Cases/agent_chat).
|
||||
|
||||
Check out this [notebook](./agentchat_groupchat.ipynb) for example.
|
||||
@@ -0,0 +1,3 @@
|
||||
promptflow
|
||||
pyautogen>=0.2.9
|
||||
pydantic>=2.6.0
|
||||
@@ -0,0 +1,230 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Tracing with AutoGen"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"AutoGen offers conversable agents powered by LLM, tool or human, which can be used to perform tasks collectively via automated chat. This framework allows tool use and human participation through multi-agent conversation.\n",
|
||||
"Please find documentation about this feature [here](https://microsoft.github.io/autogen/docs/Use-Cases/agent_chat).\n",
|
||||
"\n",
|
||||
"**Learning Objectives** - Upon completing this tutorial, you should be able to:\n",
|
||||
"\n",
|
||||
"- Trace LLM (OpenAI) Calls and visualize the trace of your application.\n",
|
||||
"\n",
|
||||
"## Requirements\n",
|
||||
"\n",
|
||||
"AutoGen requires `Python>=3.8`. To run this notebook example, please install required dependencies:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%%capture --no-stderr\n",
|
||||
"%pip install -r ./requirements.txt"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Set your API endpoint\n",
|
||||
"\n",
|
||||
"You can create the config file named `OAI_CONFIG_LIST.json` from example file: `OAI_CONFIG_LIST.json.example`.\n",
|
||||
"\n",
|
||||
"Below code use the [`config_list_from_json`](https://microsoft.github.io/autogen/0.2/docs/reference/oai/openai_utils/#config_list_from_json) function loads a list of configurations from an environment variable or a json file. \n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import autogen\n",
|
||||
"\n",
|
||||
"# please ensure you have a json config file\n",
|
||||
"env_or_file = \"OAI_CONFIG_LIST.json\"\n",
|
||||
"\n",
|
||||
"# filters the configs by models (you can filter by other keys as well). Only the gpt-4 models are kept in the list based on the filter condition.\n",
|
||||
"\n",
|
||||
"# gpt4\n",
|
||||
"# config_list = autogen.config_list_from_json(\n",
|
||||
"# env_or_file,\n",
|
||||
"# filter_dict={\n",
|
||||
"# \"model\": [\"gpt-4\", \"gpt-4-0314\", \"gpt4\", \"gpt-4-32k\", \"gpt-4-32k-0314\", \"gpt-4-32k-v0314\"],\n",
|
||||
"# },\n",
|
||||
"# )\n",
|
||||
"\n",
|
||||
"# gpt35\n",
|
||||
"config_list = autogen.config_list_from_json(\n",
|
||||
" env_or_file,\n",
|
||||
" filter_dict={\n",
|
||||
" \"model\": {\n",
|
||||
" \"gpt-35-turbo\",\n",
|
||||
" \"gpt-3.5-turbo\",\n",
|
||||
" \"gpt-3.5-turbo-16k\",\n",
|
||||
" \"gpt-3.5-turbo-0301\",\n",
|
||||
" \"chatgpt-35-turbo-0301\",\n",
|
||||
" \"gpt-35-turbo-v0301\",\n",
|
||||
" },\n",
|
||||
" },\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Construct agents"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import os\n",
|
||||
"\n",
|
||||
"os.environ[\"AUTOGEN_USE_DOCKER\"] = \"False\"\n",
|
||||
"\n",
|
||||
"llm_config = {\"config_list\": config_list, \"cache_seed\": 42}\n",
|
||||
"user_proxy = autogen.UserProxyAgent(\n",
|
||||
" name=\"User_proxy\",\n",
|
||||
" system_message=\"A human admin.\",\n",
|
||||
" code_execution_config={\n",
|
||||
" \"last_n_messages\": 2,\n",
|
||||
" \"work_dir\": \"groupchat\",\n",
|
||||
" \"use_docker\": False,\n",
|
||||
" }, # Please set use_docker=True if docker is available to run the generated code. Using docker is safer than running the generated code directly.\n",
|
||||
" human_input_mode=\"TERMINATE\",\n",
|
||||
")\n",
|
||||
"coder = autogen.AssistantAgent(\n",
|
||||
" name=\"Coder\",\n",
|
||||
" llm_config=llm_config,\n",
|
||||
")\n",
|
||||
"pm = autogen.AssistantAgent(\n",
|
||||
" name=\"Product_manager\",\n",
|
||||
" system_message=\"Creative in software product ideas.\",\n",
|
||||
" llm_config=llm_config,\n",
|
||||
")\n",
|
||||
"groupchat = autogen.GroupChat(agents=[user_proxy, coder, pm], messages=[], max_round=12)\n",
|
||||
"manager = autogen.GroupChatManager(groupchat=groupchat, llm_config=llm_config)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Start chat with promptflow trace"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from promptflow.tracing import start_trace\n",
|
||||
"\n",
|
||||
"# start a trace session, and print a url for user to check trace\n",
|
||||
"# traces will be collected into below collection name\n",
|
||||
"start_trace(collection=\"autogen-groupchat\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Open the url you get in start_trace output, when running below code, you will be able to see new traces in the UI. "
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from opentelemetry import trace\n",
|
||||
"import json\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"tracer = trace.get_tracer(\"my_tracer\")\n",
|
||||
"# Create a root span\n",
|
||||
"with tracer.start_as_current_span(\"autogen\") as span:\n",
|
||||
" message = \"Find a latest paper about gpt-4 on arxiv and find its potential applications in software.\"\n",
|
||||
" user_proxy.initiate_chat(\n",
|
||||
" manager,\n",
|
||||
" message=message,\n",
|
||||
" clear_history=True,\n",
|
||||
" )\n",
|
||||
" span.set_attribute(\"custom\", \"custom attribute value\")\n",
|
||||
" # recommend to store inputs and outputs as events\n",
|
||||
" span.add_event(\n",
|
||||
" \"promptflow.function.inputs\", {\"payload\": json.dumps(dict(message=message))}\n",
|
||||
" )\n",
|
||||
" span.add_event(\n",
|
||||
" \"promptflow.function.output\", {\"payload\": json.dumps(user_proxy.last_message())}\n",
|
||||
" )\n",
|
||||
"# type exit to terminate the chat"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Next steps\n",
|
||||
"\n",
|
||||
"By now you've successfully tracing LLM calls in your app using prompt flow.\n",
|
||||
"\n",
|
||||
"You can check out more examples:\n",
|
||||
"- [Trace your flow](https://github.com/microsoft/promptflow/blob/main/examples/flex-flows/basic/flex-flow-quickstart.ipynb): using promptflow @trace to structurally tracing your app and do evaluation on it with batch run."
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"build_doc": {
|
||||
"author": [
|
||||
"zhengfeiwang@github.com",
|
||||
"wangchao1230@github.com"
|
||||
],
|
||||
"category": "local",
|
||||
"section": "Tracing",
|
||||
"weight": 20
|
||||
},
|
||||
"description": "Tracing LLM calls in autogen group chat application",
|
||||
"kernelspec": {
|
||||
"display_name": "prompt_flow",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.10.13"
|
||||
},
|
||||
"resources": ""
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 2
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
import os
|
||||
|
||||
from dotenv import load_dotenv
|
||||
from openai.version import VERSION as OPENAI_VERSION
|
||||
|
||||
from promptflow.tracing import trace
|
||||
|
||||
|
||||
def get_client():
|
||||
if OPENAI_VERSION.startswith("0."):
|
||||
raise Exception(
|
||||
"Please upgrade your OpenAI package to version >= 1.0.0 or using the command: pip install --upgrade openai."
|
||||
)
|
||||
api_key = os.environ.get("OPENAI_API_KEY", None)
|
||||
if api_key:
|
||||
from openai import OpenAI
|
||||
|
||||
return OpenAI()
|
||||
else:
|
||||
from openai import AzureOpenAI
|
||||
|
||||
return AzureOpenAI(api_version=os.environ.get("OPENAI_API_VERSION", "2023-07-01-preview"))
|
||||
|
||||
|
||||
@trace
|
||||
def my_llm_tool(prompt: str, deployment_name: str) -> str:
|
||||
if "OPENAI_API_KEY" not in os.environ and "AZURE_OPENAI_API_KEY" not in os.environ:
|
||||
# load environment variables from .env file
|
||||
load_dotenv()
|
||||
|
||||
if "OPENAI_API_KEY" not in os.environ and "AZURE_OPENAI_API_KEY" not in os.environ:
|
||||
raise Exception("Please specify environment variables: OPENAI_API_KEY or AZURE_OPENAI_API_KEY")
|
||||
messages = [
|
||||
{"role": "system", "content": "You are a helpful assistant."},
|
||||
{"role": "user", "content": prompt},
|
||||
]
|
||||
response = get_client().chat.completions.create(
|
||||
messages=messages,
|
||||
model=deployment_name,
|
||||
)
|
||||
|
||||
# get first element because prompt is single.
|
||||
return response.choices[0].message.content
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
result = my_llm_tool(
|
||||
prompt="Write a simple Hello, world! python program that displays the greeting message. Output code only.",
|
||||
deployment_name="gpt-4o",
|
||||
)
|
||||
print(result)
|
||||
@@ -0,0 +1,205 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Tracing with Custom OpenTelemetry Collector"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"In certain scenario you might want to user your own [OpenTelemetry Collector](https://opentelemetry.io/docs/collector/) and keep your dependency mimimal.\n",
|
||||
"\n",
|
||||
"In such case you can avoid the dependency of [promptflow-devkit](https://pypi.org/project/promptflow-devkit/) which provides the default collector from promptflow, and only depdent on [promptflow-tracing](https://pypi.org/project/promptflow-tracing), \n",
|
||||
"\n",
|
||||
"\n",
|
||||
"**Learning Objectives** - Upon completing this tutorial, you should be able to:\n",
|
||||
"\n",
|
||||
"- Trace LLM (OpenAI) Calls using Custom OpenTelemetry Collector.\n",
|
||||
"\n",
|
||||
"## 0. Install dependent packages"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%%capture --no-stderr\n",
|
||||
"%pip install -r ./requirements.txt"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# 1. Set up an OpenTelemetry collector\n",
|
||||
"\n",
|
||||
"Implement a simple collector that print the traces to stdout."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import threading\n",
|
||||
"from http.server import BaseHTTPRequestHandler, HTTPServer\n",
|
||||
"\n",
|
||||
"from opentelemetry.proto.collector.trace.v1.trace_service_pb2 import (\n",
|
||||
" ExportTraceServiceRequest,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class OTLPCollector(BaseHTTPRequestHandler):\n",
|
||||
" def do_POST(self):\n",
|
||||
" content_length = int(self.headers[\"Content-Length\"])\n",
|
||||
" post_data = self.rfile.read(content_length)\n",
|
||||
"\n",
|
||||
" traces_request = ExportTraceServiceRequest()\n",
|
||||
" traces_request.ParseFromString(post_data)\n",
|
||||
"\n",
|
||||
" print(\"Received a POST request with data:\")\n",
|
||||
" print(traces_request)\n",
|
||||
"\n",
|
||||
" self.send_response(200, \"Traces received\")\n",
|
||||
" self.end_headers()\n",
|
||||
" self.wfile.write(b\"Data received and printed to stdout.\\n\")\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def run_server(port: int):\n",
|
||||
" server_address = (\"\", port)\n",
|
||||
" httpd = HTTPServer(server_address, OTLPCollector)\n",
|
||||
" httpd.serve_forever()\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def start_server(port: int):\n",
|
||||
" server_thread = threading.Thread(target=run_server, args=(port,))\n",
|
||||
" server_thread.daemon = True\n",
|
||||
" server_thread.start()\n",
|
||||
" print(f\"Server started on port {port}. Access http://localhost:{port}/\")\n",
|
||||
" return server_thread"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# invoke the collector service, serving on OTLP port\n",
|
||||
"start_server(port=4318)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# 2. Trace your application with tracing\n",
|
||||
"Assume we already have a Python function that calls OpenAI API\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from llm import my_llm_tool\n",
|
||||
"\n",
|
||||
"deployment_name = \"gpt-35-turbo-16k\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Call `start_trace()`, and configure the OTLP exporter to above collector."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from promptflow.tracing import start_trace\n",
|
||||
"\n",
|
||||
"start_trace()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from opentelemetry import trace\n",
|
||||
"from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter\n",
|
||||
"from opentelemetry.sdk.trace.export import BatchSpanProcessor\n",
|
||||
"\n",
|
||||
"tracer_provider = trace.get_tracer_provider()\n",
|
||||
"otlp_span_exporter = OTLPSpanExporter()\n",
|
||||
"tracer_provider.add_span_processor(BatchSpanProcessor(otlp_span_exporter))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Visualize traces in the stdout."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"result = my_llm_tool(\n",
|
||||
" prompt=\"Write a simple Hello, world! python program that displays the greeting message. Output code only.\",\n",
|
||||
" deployment_name=deployment_name,\n",
|
||||
")\n",
|
||||
"result\n",
|
||||
"# view the traces under this cell"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"build_doc": {
|
||||
"author": [
|
||||
"zhengfeiwang@github.com",
|
||||
"wangchao1230@github.com"
|
||||
],
|
||||
"category": "local",
|
||||
"section": "Tracing",
|
||||
"weight": 40
|
||||
},
|
||||
"description": "A tutorial on how to levarage custom OTLP collector.",
|
||||
"kernelspec": {
|
||||
"display_name": "tracing-rel",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.9.17"
|
||||
},
|
||||
"resources": ""
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 2
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
promptflow-tracing
|
||||
python-dotenv
|
||||
opentelemetry-exporter-otlp-proto-http
|
||||
@@ -0,0 +1,5 @@
|
||||
promptflow
|
||||
langchain>=0.1.5
|
||||
langchain_community
|
||||
opentelemetry-instrumentation-langchain
|
||||
python-dotenv
|
||||
@@ -0,0 +1,181 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Tracing with LangChain apps"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"The tracing capability provided by Prompt flow is built on top of [OpenTelemetry](https://opentelemetry.io/) that gives you complete observability over your LLM applications. \n",
|
||||
"And there is already a rich set of OpenTelemetry [instrumentation packages](https://opentelemetry.io/ecosystem/registry/?language=python&component=instrumentation) available in OpenTelemetry Eco System. \n",
|
||||
"\n",
|
||||
"In this example we will demo how to use [opentelemetry-instrumentation-langchain](https://github.com/traceloop/openllmetry/tree/main/packages/opentelemetry-instrumentation-langchain) package provided by [Traceloop](https://www.traceloop.com/) to instrument [LangChain](https://python.langchain.com/docs/tutorials/) apps.\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"**Learning Objectives** - Upon completing this tutorial, you should be able to:\n",
|
||||
"\n",
|
||||
"- Trace `LangChain` applications and visualize the trace of your application in prompt flow.\n",
|
||||
"\n",
|
||||
"## Requirements\n",
|
||||
"\n",
|
||||
"To run this notebook example, please install required dependencies:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%%capture --no-stderr\n",
|
||||
"%pip install -r ./requirements.txt"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Start tracing LangChain using promptflow\n",
|
||||
"\n",
|
||||
"Start trace using `promptflow.start_trace`, click the printed url to view the trace ui."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from promptflow.tracing import start_trace\n",
|
||||
"\n",
|
||||
"# start a trace session, and print a url for user to check trace\n",
|
||||
"start_trace()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"By default, `opentelemetry-instrumentation-langchain` instrumentation logs prompts, completions, and embeddings to span attributes. This gives you a clear visibility into how your LLM application is working, and can make it easy to debug and evaluate the quality of the outputs."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# enable langchain instrumentation\n",
|
||||
"from opentelemetry.instrumentation.langchain import LangchainInstrumentor\n",
|
||||
"\n",
|
||||
"instrumentor = LangchainInstrumentor()\n",
|
||||
"if not instrumentor.is_instrumented_by_opentelemetry:\n",
|
||||
" instrumentor.instrument()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"attachments": {},
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Run a simple LangChain\n",
|
||||
"\n",
|
||||
"Below is an example targeting an AzureOpenAI resource. Please configure you `API_KEY` using an `.env` file, see `../.env.example`."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import os\n",
|
||||
"\n",
|
||||
"from langchain.chat_models import AzureChatOpenAI\n",
|
||||
"from langchain.prompts.chat import ChatPromptTemplate\n",
|
||||
"from langchain.chains import LLMChain\n",
|
||||
"from dotenv import load_dotenv\n",
|
||||
"\n",
|
||||
"if \"AZURE_OPENAI_API_KEY\" not in os.environ:\n",
|
||||
" # load environment variables from .env file\n",
|
||||
" load_dotenv()\n",
|
||||
"\n",
|
||||
"llm = AzureChatOpenAI(\n",
|
||||
" deployment_name=os.environ[\"CHAT_DEPLOYMENT_NAME\"],\n",
|
||||
" openai_api_key=os.environ[\"AZURE_OPENAI_API_KEY\"],\n",
|
||||
" azure_endpoint=os.environ[\"AZURE_OPENAI_ENDPOINT\"],\n",
|
||||
" openai_api_type=\"azure\",\n",
|
||||
" openai_api_version=\"2023-07-01-preview\",\n",
|
||||
" temperature=0,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"prompt = ChatPromptTemplate.from_messages(\n",
|
||||
" [\n",
|
||||
" (\"system\", \"You are world class technical documentation writer.\"),\n",
|
||||
" (\"user\", \"{input}\"),\n",
|
||||
" ]\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"chain = LLMChain(llm=llm, prompt=prompt, output_key=\"metrics\")\n",
|
||||
"chain({\"input\": \"What is ChatGPT?\"})"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"You should be able to see traces of the chain in promptflow UI now. Check the cell with `start_trace` on the trace UI url."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Next steps\n",
|
||||
"\n",
|
||||
"By now you've successfully tracing LLM calls in your app using prompt flow.\n",
|
||||
"\n",
|
||||
"You can check out more examples:\n",
|
||||
"- [Trace your flow](https://github.com/microsoft/promptflow/blob/main/examples/flex-flows/basic/flex-flow-quickstart.ipynb): using promptflow @trace to structurally tracing your app and do evaluation on it with batch run."
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"build_doc": {
|
||||
"author": [
|
||||
"zhengfeiwang@github.com",
|
||||
"wangchao1230@github.com"
|
||||
],
|
||||
"category": "local",
|
||||
"section": "Tracing",
|
||||
"weight": 30
|
||||
},
|
||||
"description": "Tracing LLM calls in langchain application",
|
||||
"kernelspec": {
|
||||
"display_name": "prompt_flow",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.9.17"
|
||||
},
|
||||
"resources": ""
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 2
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
AZURE_OPENAI_API_KEY=<your_AOAI_key>
|
||||
AZURE_OPENAI_ENDPOINT=<your_AOAI_endpoint>
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 51 KiB |
@@ -0,0 +1,3 @@
|
||||
promptflow
|
||||
openai>=1.0.0
|
||||
python-dotenv
|
||||
@@ -0,0 +1,201 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Tracing with LLM application"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Tracing is a powerful tool for understanding the behavior of your LLM application, prompt flow tracing capability supports instrumentation for such scenario.\n",
|
||||
"\n",
|
||||
"This notebook will demonstrate how to use prompt flow to instrument and understand your LLM application.\n",
|
||||
"\n",
|
||||
"**Learning Objective** - Upon completion of this notebook, you will be able to:\n",
|
||||
"\n",
|
||||
"- Trace LLM application and visualize with prompt flow."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Requirements\n",
|
||||
"\n",
|
||||
"To run this notebook example, please install required dependencies."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%%capture --no-stderr\n",
|
||||
"%pip install -r ./requirements.txt"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Please configure your API key using an `.env` file, we have provided an example `.env.example` for reference."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# load api key and endpoint from .env to environ\n",
|
||||
"from dotenv import load_dotenv\n",
|
||||
"\n",
|
||||
"load_dotenv()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Create your LLM application\n",
|
||||
"\n",
|
||||
"This notebook example will build a LLM application with Azure OpenAI service."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from openai import AzureOpenAI\n",
|
||||
"\n",
|
||||
"# in this notebook example, we will use model \"gpt-35-turbo-16k\"\n",
|
||||
"deployment_name = \"gpt-35-turbo-16k\"\n",
|
||||
"\n",
|
||||
"client = AzureOpenAI(\n",
|
||||
" azure_deployment=deployment_name,\n",
|
||||
" api_version=\"2024-02-01\",\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# prepare one classic question for LLM\n",
|
||||
"conversation = [\n",
|
||||
" {\"role\": \"system\", \"content\": \"You are a helpful assistant.\"},\n",
|
||||
" {\"role\": \"user\", \"content\": \"What is the meaning of life?\"},\n",
|
||||
"]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"response = client.chat.completions.create(\n",
|
||||
" messages=conversation,\n",
|
||||
" model=deployment_name,\n",
|
||||
")\n",
|
||||
"print(response.choices[0].message.content)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Start trace using `promptflow.tracing.start_trace` to leverage prompt flow tracing capability; this will print a link to trace UI, where you can visualize the trace."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from promptflow.tracing import start_trace\n",
|
||||
"\n",
|
||||
"# start a trace session, and print a url for user to check trace\n",
|
||||
"start_trace(collection=\"trace-llm\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Run the LLM application again, and you should be able to see new trace logged in the trace UI, and it is clickable to see more details.\n",
|
||||
"\n",
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"response = client.chat.completions.create(\n",
|
||||
" messages=conversation,\n",
|
||||
" model=deployment_name,\n",
|
||||
")\n",
|
||||
"print(response.choices[0].message.content)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Next Steps\n",
|
||||
"\n",
|
||||
"By now you have successfully tracing your LLM application with prompt flow.\n",
|
||||
"\n",
|
||||
"You can check out more examples:\n",
|
||||
"\n",
|
||||
"- [Trace LangChain](https://github.com/microsoft/promptflow/blob/main/examples/tutorials/tracing/langchain/trace-langchain.ipynb): tracing `LangChain` and visualize leveraging prompt flow.\n",
|
||||
"- [Trace AutoGen](https://github.com/microsoft/promptflow/blob/main/examples/tutorials/tracing/autogen-groupchat/trace-autogen-groupchat.ipynb): tracing `AutoGen` and visualize leveraging prompt flow.\n",
|
||||
"- [Trace your flow](https://github.com/microsoft/promptflow/blob/main/examples/flex-flows/basic/flex-flow-quickstart.ipynb): using promptflow @trace to structurally tracing your app and do evaluation on it with batch run.\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"build_doc": {
|
||||
"author": [
|
||||
"zhengfeiwang@github.com"
|
||||
],
|
||||
"category": "local",
|
||||
"section": "Tracing",
|
||||
"weight": 10
|
||||
},
|
||||
"description": "Tracing LLM application",
|
||||
"kernelspec": {
|
||||
"display_name": "pf-dev",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.11.8"
|
||||
},
|
||||
"resources": ""
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 2
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
import ast
|
||||
import os
|
||||
|
||||
from dotenv import load_dotenv
|
||||
from openai import AzureOpenAI
|
||||
|
||||
from promptflow.tracing import start_trace, trace
|
||||
|
||||
|
||||
@trace
|
||||
def infinite_loop_check(code_snippet):
|
||||
tree = ast.parse(code_snippet)
|
||||
for node in ast.walk(tree):
|
||||
if isinstance(node, ast.While):
|
||||
if not node.orelse:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
@trace
|
||||
def syntax_error_check(code_snippet):
|
||||
try:
|
||||
ast.parse(code_snippet)
|
||||
except SyntaxError:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
@trace
|
||||
def error_fix(code_snippet):
|
||||
tree = ast.parse(code_snippet)
|
||||
for node in ast.walk(tree):
|
||||
if isinstance(node, ast.While):
|
||||
if not node.orelse:
|
||||
node.orelse = [ast.Pass()]
|
||||
return ast.unparse(tree)
|
||||
|
||||
|
||||
@trace
|
||||
def code_refine(original_code: str) -> str:
|
||||
original_code = original_code.replace("python", "").replace("`", "").strip()
|
||||
fixed_code = None
|
||||
|
||||
if infinite_loop_check(original_code):
|
||||
fixed_code = error_fix(original_code)
|
||||
else:
|
||||
fixed_code = original_code
|
||||
|
||||
if syntax_error_check(fixed_code):
|
||||
fixed_code = error_fix(fixed_code)
|
||||
|
||||
return fixed_code
|
||||
|
||||
|
||||
@trace
|
||||
def code_gen(client: AzureOpenAI, question: str) -> str:
|
||||
sys_prompt = (
|
||||
"I want you to act as a math expert specializing in Algebra, Geometry, and Calculus. "
|
||||
"Given the question, develop python code to model the user's question. "
|
||||
"Make sure only reply the executable code, no other words."
|
||||
)
|
||||
completion = client.chat.completions.create(
|
||||
model=os.getenv("CHAT_DEPLOYMENT_NAME", "gpt-35-turbo"),
|
||||
messages=[
|
||||
{
|
||||
"role": "system",
|
||||
"content": sys_prompt,
|
||||
},
|
||||
{"role": "user", "content": question},
|
||||
],
|
||||
)
|
||||
raw_code = completion.choices[0].message.content
|
||||
result = code_refine(raw_code)
|
||||
return result
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
start_trace()
|
||||
|
||||
if "AZURE_OPENAI_API_KEY" not in os.environ:
|
||||
# load environment variables from .env file
|
||||
load_dotenv()
|
||||
|
||||
client = AzureOpenAI(
|
||||
api_key=os.getenv("AZURE_OPENAI_API_KEY"),
|
||||
azure_endpoint=os.getenv("AZURE_OPENAI_ENDPOINT"),
|
||||
api_version="2023-12-01-preview",
|
||||
)
|
||||
|
||||
question = "What is 37593 * 67?"
|
||||
|
||||
code = code_gen(client, question)
|
||||
print(code)
|
||||
Reference in New Issue
Block a user