Spaces:
Sleeping
Sleeping
Upload 9 files
Browse files- examples/trace/asyncio_test.py +41 -0
- examples/trace/autotrace_demo.py +24 -0
- examples/trace/instrument_fastapi.py +54 -0
- examples/trace/instrument_flask.py +47 -0
- examples/trace/instrument_threading.py +29 -0
- examples/trace/opentelemetry_trace.py +69 -0
- examples/trace/sofa_tracer.py +71 -0
- examples/trace/span_cosumer.py +33 -0
- examples/trace/trace_agent.py +249 -0
examples/trace/asyncio_test.py
ADDED
@@ -0,0 +1,41 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import asyncio
|
2 |
+
import aworld.trace as trace
|
3 |
+
from aworld.logs.util import logger
|
4 |
+
trace.configure()
|
5 |
+
|
6 |
+
|
7 |
+
async def async_handler(name):
|
8 |
+
async with trace.span("async_handler") as span:
|
9 |
+
logger.info(f"async_handler start {name}")
|
10 |
+
await asyncio.sleep(1)
|
11 |
+
logger.info(f"async_handler end {name}")
|
12 |
+
|
13 |
+
|
14 |
+
async def async_handler2(name):
|
15 |
+
span = trace.get_current_span()
|
16 |
+
logger.info(f"async_handler2 span: {span.get_trace_id()}")
|
17 |
+
logger.info(f"async_handler2 start {name}")
|
18 |
+
await asyncio.sleep(1)
|
19 |
+
logger.info(f"async_handler2 end {name}")
|
20 |
+
|
21 |
+
|
22 |
+
async def test1():
|
23 |
+
logger.info(f"hello test1")
|
24 |
+
task = asyncio.create_task(async_handler('test1'))
|
25 |
+
# await task
|
26 |
+
logger.info(f"hello test1 end")
|
27 |
+
|
28 |
+
|
29 |
+
async def test2():
|
30 |
+
async with trace.span("test2") as span:
|
31 |
+
logger.info(f"hello test2")
|
32 |
+
task = asyncio.create_task(async_handler2(
|
33 |
+
'test2'))
|
34 |
+
# await task
|
35 |
+
logger.info(f"hello test2 end")
|
36 |
+
|
37 |
+
if __name__ == "__main__":
|
38 |
+
with trace.span("hello") as span:
|
39 |
+
logger.info(f"main execute")
|
40 |
+
asyncio.run(test2())
|
41 |
+
asyncio.run(test1())
|
examples/trace/autotrace_demo.py
ADDED
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import time
|
2 |
+
|
3 |
+
class TestClassA:
|
4 |
+
|
5 |
+
def classa_function_1(self):
|
6 |
+
print("classa_function_1")
|
7 |
+
|
8 |
+
def classa_function_2(self):
|
9 |
+
time.sleep(0.02)
|
10 |
+
print("classa_function_2")
|
11 |
+
|
12 |
+
def classa_function_3(self):
|
13 |
+
print("classa_function_3")
|
14 |
+
|
15 |
+
class TestClassB:
|
16 |
+
def classb_function_1(self):
|
17 |
+
time.sleep(0.02)
|
18 |
+
print("classb_function_1")
|
19 |
+
def classb_function_2(self):
|
20 |
+
a = TestClassA()
|
21 |
+
a.classa_function_1()
|
22 |
+
a.classa_function_2()
|
23 |
+
a.classa_function_3()
|
24 |
+
print("classb_function_2")
|
examples/trace/instrument_fastapi.py
ADDED
@@ -0,0 +1,54 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import time
|
3 |
+
import threading
|
4 |
+
from aworld.trace.config import ObservabilityConfig
|
5 |
+
from aworld.trace.instrumentation.fastapi import instrument_fastapi
|
6 |
+
from aworld.trace.instrumentation.requests import instrument_requests
|
7 |
+
from aworld.logs.util import logger, trace_logger
|
8 |
+
import aworld.trace as trace
|
9 |
+
from aworld.utils.import_package import import_packages
|
10 |
+
import_packages(['fastapi', 'uvicorn']) # noqa
|
11 |
+
import fastapi # noqa
|
12 |
+
import uvicorn # noqa
|
13 |
+
|
14 |
+
os.environ["MONITOR_SERVICE_NAME"] = "otlp_example"
|
15 |
+
os.environ["ANT_OTEL_ENDPOINT"] = "https://antcollector.alipay.com/namespace/aworld/task/aworld/otlp/api/v1/metrics"
|
16 |
+
|
17 |
+
trace.configure(ObservabilityConfig(
|
18 |
+
metrics_provider="otlp",
|
19 |
+
metrics_backend="antmonitor"
|
20 |
+
))
|
21 |
+
|
22 |
+
instrument_fastapi()
|
23 |
+
instrument_requests()
|
24 |
+
|
25 |
+
app = fastapi.FastAPI()
|
26 |
+
|
27 |
+
|
28 |
+
@app.get("/api/hello")
|
29 |
+
async def hello():
|
30 |
+
return {"message": "Hello World"}
|
31 |
+
|
32 |
+
|
33 |
+
def invoke_api():
|
34 |
+
import requests
|
35 |
+
response = requests.get('http://127.0.0.1:7071/api/hello')
|
36 |
+
logger.info(f"invoke_api response={response.text}")
|
37 |
+
|
38 |
+
|
39 |
+
def main():
|
40 |
+
logger.info("main running")
|
41 |
+
with trace.span("test_fastapi") as span:
|
42 |
+
trace_logger.info("start invoke_api")
|
43 |
+
invoke_api()
|
44 |
+
|
45 |
+
|
46 |
+
if __name__ == "__main__":
|
47 |
+
server_thread = threading.Thread(
|
48 |
+
target=lambda: uvicorn.run(app, host="0.0.0.0", port=7071),
|
49 |
+
daemon=True
|
50 |
+
)
|
51 |
+
server_thread.start()
|
52 |
+
time.sleep(1)
|
53 |
+
main()
|
54 |
+
server_thread.join()
|
examples/trace/instrument_flask.py
ADDED
@@ -0,0 +1,47 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import threading
|
2 |
+
import flask
|
3 |
+
from aworld.trace.instrumentation.flask import instrument_flask
|
4 |
+
from aworld.trace.instrumentation.requests import instrument_requests
|
5 |
+
from aworld.logs.util import logger, trace_logger
|
6 |
+
import aworld.trace as trace
|
7 |
+
import os
|
8 |
+
from aworld.trace.config import ObservabilityConfig
|
9 |
+
|
10 |
+
os.environ["MONITOR_SERVICE_NAME"] = "otlp_example"
|
11 |
+
os.environ["ANT_OTEL_ENDPOINT"] = "https://antcollector.alipay.com/namespace/aworld/task/aworld/otlp/api/v1/metrics"
|
12 |
+
|
13 |
+
trace.configure(ObservabilityConfig(
|
14 |
+
metrics_provider="otlp",
|
15 |
+
metrics_backend="antmonitor"
|
16 |
+
))
|
17 |
+
instrument_flask()
|
18 |
+
instrument_requests()
|
19 |
+
|
20 |
+
app = flask.Flask(__name__)
|
21 |
+
|
22 |
+
|
23 |
+
@app.route('/api/test')
|
24 |
+
def test():
|
25 |
+
return 'Hello, World!'
|
26 |
+
|
27 |
+
|
28 |
+
thread = threading.Thread(target=lambda: app.run(port=7070), daemon=True)
|
29 |
+
thread.start()
|
30 |
+
|
31 |
+
|
32 |
+
def invoke_api():
|
33 |
+
import requests
|
34 |
+
response = requests.get('http://localhost:7070/api/test')
|
35 |
+
logger.info(f"invoke_api response={response.text}")
|
36 |
+
|
37 |
+
|
38 |
+
def main():
|
39 |
+
logger.info("main running")
|
40 |
+
with trace.span("test_flask") as span:
|
41 |
+
trace_logger.info("start invoke_api")
|
42 |
+
invoke_api()
|
43 |
+
|
44 |
+
|
45 |
+
if __name__ == "__main__":
|
46 |
+
main()
|
47 |
+
thread.join()
|
examples/trace/instrument_threading.py
ADDED
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import threading
|
2 |
+
import aworld.trace as trace
|
3 |
+
import os
|
4 |
+
import time
|
5 |
+
from aworld.trace.instrumentation.threading import instrument_theading
|
6 |
+
from aworld.logs.util import logger, trace_logger
|
7 |
+
|
8 |
+
os.environ["MONITOR_SERVICE_NAME"] = "otlp_example"
|
9 |
+
trace.configure()
|
10 |
+
instrument_theading()
|
11 |
+
|
12 |
+
|
13 |
+
def child_thread_func():
|
14 |
+
logger.info("child thread running")
|
15 |
+
with trace.span("child_thread") as span:
|
16 |
+
trace_logger.info("child thread running")
|
17 |
+
time.sleep(1000)
|
18 |
+
|
19 |
+
|
20 |
+
def main():
|
21 |
+
logger.info("main running")
|
22 |
+
with trace.span("test_fastapi") as span:
|
23 |
+
trace_logger.info("start run child_thread_func")
|
24 |
+
threading.Thread(target=child_thread_func).start()
|
25 |
+
threading.Thread(target=child_thread_func).start()
|
26 |
+
|
27 |
+
|
28 |
+
if __name__ == "__main__":
|
29 |
+
main()
|
examples/trace/opentelemetry_trace.py
ADDED
@@ -0,0 +1,69 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os # noqa
|
2 |
+
# os.environ["START_TRACE_SERVER"] = "false" # noqa
|
3 |
+
os.environ["MONITOR_SERVICE_NAME"] = "otlp_example" # noqa
|
4 |
+
# os.environ["OTLP_TRACES_ENDPOINT"] = "http://localhost:4318/v1/traces"
|
5 |
+
# os.environ["METRICS_SYSTEM_ENABLED"] = "true"
|
6 |
+
# os.environ["LOGFIRE_WRITE_TOKEN"] = (
|
7 |
+
# "Your logfire write token, "
|
8 |
+
# "create guide refer to "
|
9 |
+
# "https://logfire.pydantic.dev/docs/how-to-guides/create-write-tokens/"
|
10 |
+
# )
|
11 |
+
|
12 |
+
import aworld.trace as trace # noqa
|
13 |
+
from aworld.logs.util import logger, trace_logger
|
14 |
+
from aworld.trace.server import get_trace_server
|
15 |
+
|
16 |
+
|
17 |
+
trace.configure()
|
18 |
+
|
19 |
+
|
20 |
+
@trace.func_span(span_name="test_func", attributes={"test_attr": "test_value"}, extract_args=["param1"], add_attr="add_attr_value")
|
21 |
+
def traced_func(param1: str = None, param2: int = None):
|
22 |
+
trace_logger.info("this is a traced func")
|
23 |
+
traced_func2(param1="func2_param1_value", param2=222)
|
24 |
+
traced_func3(param1="func3_param1_value", param2=333)
|
25 |
+
|
26 |
+
|
27 |
+
@trace.func_span(span_name="test_func_2", add_attr="add_attr_value")
|
28 |
+
def traced_func2(param1: str = None, param2: int = None):
|
29 |
+
name = 'func2'
|
30 |
+
trace_logger.info(f"this is a traced {name}")
|
31 |
+
raise Exception("this is a traced func2 exception")
|
32 |
+
|
33 |
+
|
34 |
+
@trace.func_span
|
35 |
+
def traced_func3(param1: str = None, param2: int = None):
|
36 |
+
trace_logger.info("this is a traced func3")
|
37 |
+
|
38 |
+
|
39 |
+
def main():
|
40 |
+
|
41 |
+
logger.info("this is a no trace log")
|
42 |
+
|
43 |
+
trace.auto_tracing("examples.trace.*", 0.01)
|
44 |
+
|
45 |
+
with trace.span("hello") as span:
|
46 |
+
span.set_attribute("parent_test_attr", "pppppp")
|
47 |
+
logger.info("hello aworld")
|
48 |
+
trace_logger.info("trace hello aworld")
|
49 |
+
with trace.span("child hello") as span2:
|
50 |
+
span2.set_attribute("child_test_attr", "cccccc")
|
51 |
+
logger.info("child hello aworld")
|
52 |
+
current_span = trace.get_current_span()
|
53 |
+
logger.info("trace_id=%s", current_span.get_trace_id())
|
54 |
+
try:
|
55 |
+
traced_func(param1="func1_param1_value", param2=111)
|
56 |
+
except Exception as e:
|
57 |
+
logger.error(f"exception: {e}")
|
58 |
+
# from examples.trace.autotrace_demo import TestClassB
|
59 |
+
# b = TestClassB()
|
60 |
+
# b.classb_function_1()
|
61 |
+
# b.classb_function_2()
|
62 |
+
# b.classb_function_1()
|
63 |
+
# b.classb_function_2()
|
64 |
+
if get_trace_server():
|
65 |
+
get_trace_server().join()
|
66 |
+
|
67 |
+
|
68 |
+
if __name__ == "__main__":
|
69 |
+
main()
|
examples/trace/sofa_tracer.py
ADDED
@@ -0,0 +1,71 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os # noqa: E402
|
2 |
+
|
3 |
+
os.environ["MONITOR_SERVICE_NAME"] = "otlp_example" # noqa
|
4 |
+
os.environ["ANT_OTEL_ENDPOINT"] = "https://antcollector.alipay.com/namespace/aworld/task/aworld/otlp/api/v1/metrics" # noqa
|
5 |
+
os.environ["OTLP_TRACES_ENDPOINT"] = "https://antcollector.alipay.com/namespace/aworld/task/aworld_trace/otlp/api/v1/traces" # noqa
|
6 |
+
|
7 |
+
from aworld.trace.config import ObservabilityConfig
|
8 |
+
from aworld.logs.util import logger
|
9 |
+
from aworld.trace.baggage import BaggageContext
|
10 |
+
from aworld.trace.base import get_tracer_provider
|
11 |
+
from aworld.trace.instrumentation.requests import instrument_requests
|
12 |
+
from aworld.trace.instrumentation.flask import instrument_flask
|
13 |
+
import flask
|
14 |
+
import threading
|
15 |
+
import aworld.trace as trace
|
16 |
+
|
17 |
+
|
18 |
+
trace.configure(ObservabilityConfig(
|
19 |
+
trace_provider="otlp",
|
20 |
+
trace_backends=["other_otlp"],
|
21 |
+
trace_base_url="https://antcollector.alipay.com/namespace/aworld/task/aworld_trace/otlp/api/v1/traces",
|
22 |
+
metrics_provider="otlp",
|
23 |
+
metrics_backend="antmonitor",
|
24 |
+
metrics_base_url="https://antcollector.alipay.com/namespace/aworld/task/aworld/otlp/api/v1/metrics"
|
25 |
+
))
|
26 |
+
instrument_flask()
|
27 |
+
instrument_requests()
|
28 |
+
|
29 |
+
app = flask.Flask(__name__)
|
30 |
+
|
31 |
+
|
32 |
+
@app.route('/api/test')
|
33 |
+
def test():
|
34 |
+
sofa_trace_id = BaggageContext.get_baggage_value("attributes.sofa.traceid")
|
35 |
+
sofa_rpc_id = BaggageContext.get_baggage_value("attributes.sofa.rpcid")
|
36 |
+
sofa_pen_attrs = BaggageContext.get_baggage_value(
|
37 |
+
"attributes.sofa.penattrs")
|
38 |
+
sofa_sys_pen_attrs = BaggageContext.get_baggage_value(
|
39 |
+
"attributes.sofa.syspenattrs")
|
40 |
+
logger.info(
|
41 |
+
f"test sofa_trace_id={sofa_trace_id}, sofa_rpc_id={sofa_rpc_id}, sofa_pen_attrs={sofa_pen_attrs}, sofa_sys_pen_attrs={sofa_sys_pen_attrs}"
|
42 |
+
)
|
43 |
+
return 'Hello, World!'
|
44 |
+
|
45 |
+
|
46 |
+
thread = threading.Thread(target=lambda: app.run(port=7070), daemon=True)
|
47 |
+
thread.start()
|
48 |
+
|
49 |
+
|
50 |
+
def invoke_api():
|
51 |
+
import requests
|
52 |
+
session = requests.session()
|
53 |
+
session.headers.update({
|
54 |
+
"SOFA-TraceId": "12345678901234567890123456789012",
|
55 |
+
"SOFA-RpcId": "0.1.1",
|
56 |
+
"sofaPenAttrs": "key1=value1&key2=value2",
|
57 |
+
"sysPenAttrs": "key1=value1&key2=value2"
|
58 |
+
})
|
59 |
+
response = session.get('http://localhost:7070/api/test')
|
60 |
+
logger.info(f"invoke_api response={response.text}")
|
61 |
+
|
62 |
+
|
63 |
+
def main():
|
64 |
+
logger.info("main running")
|
65 |
+
invoke_api()
|
66 |
+
|
67 |
+
|
68 |
+
if __name__ == "__main__":
|
69 |
+
main()
|
70 |
+
get_tracer_provider().force_flush(1000)
|
71 |
+
thread.join()
|
examples/trace/span_cosumer.py
ADDED
@@ -0,0 +1,33 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import json
|
3 |
+
from aworld.logs.util import logger, trace_logger
|
4 |
+
from typing import Sequence
|
5 |
+
import aworld.trace as trace
|
6 |
+
from aworld.trace.base import Span
|
7 |
+
from aworld.trace.span_cosumer import register_span_consumer, SpanConsumer
|
8 |
+
from aworld.logs.util import logger, trace_logger
|
9 |
+
|
10 |
+
os.environ["MONITOR_SERVICE_NAME"] = "otlp_example"
|
11 |
+
|
12 |
+
|
13 |
+
@register_span_consumer({"test_param": "MockSpanConsumer111"})
|
14 |
+
class MockSpanConsumer(SpanConsumer):
|
15 |
+
|
16 |
+
def __init__(self, test_param=None):
|
17 |
+
self._test_param = test_param
|
18 |
+
|
19 |
+
def consume(self, spans: Sequence[Span]) -> None:
|
20 |
+
for span in spans:
|
21 |
+
logger.info(
|
22 |
+
f"_test_param={self._test_param}, trace_id={span.get_trace_id()}, span_id={span.get_span_id()}, attributes={span.attributes}")
|
23 |
+
|
24 |
+
|
25 |
+
def main():
|
26 |
+
with trace.span("hello") as span:
|
27 |
+
span.set_attribute("parent_test_attr", "pppppp")
|
28 |
+
logger.info("hello aworld")
|
29 |
+
trace_logger.info("trace hello aworld")
|
30 |
+
|
31 |
+
|
32 |
+
if __name__ == "__main__":
|
33 |
+
main()
|
examples/trace/trace_agent.py
ADDED
@@ -0,0 +1,249 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import traceback
|
2 |
+
from aworld.agents.llm_agent import Agent
|
3 |
+
from aworld.config.conf import AgentConfig, ConfigDict
|
4 |
+
from aworld.core.common import Observation, ActionModel
|
5 |
+
from typing import Dict, Any, List, Union, Callable
|
6 |
+
from aworld.core.tool.base import ToolFactory
|
7 |
+
from aworld.models.llm import call_llm_model, acall_llm_model
|
8 |
+
from aworld.utils.common import sync_exec
|
9 |
+
from aworld.logs.util import logger
|
10 |
+
from examples.tools.common import Tools
|
11 |
+
from examples.tools.tool_action import GetTraceAction
|
12 |
+
from aworld.core.agent.swarm import Swarm
|
13 |
+
from aworld.runner import Runners
|
14 |
+
from aworld.trace.server import get_trace_server
|
15 |
+
from aworld.runners.state_manager import RuntimeStateManager, RunNode
|
16 |
+
import aworld.trace as trace
|
17 |
+
|
18 |
+
|
19 |
+
trace.configure()
|
20 |
+
|
21 |
+
|
22 |
+
class TraceAgent(Agent):
|
23 |
+
|
24 |
+
def __init__(self,
|
25 |
+
conf: Union[Dict[str, Any], ConfigDict, AgentConfig],
|
26 |
+
resp_parse_func: Callable[..., Any] = None,
|
27 |
+
**kwargs):
|
28 |
+
super().__init__(conf, **kwargs)
|
29 |
+
|
30 |
+
def policy(self, observation: Observation, info: Dict[str, Any] = {}, **kwargs) -> List[ActionModel]:
|
31 |
+
"""use trace tool to get trace data, and call llm to summary
|
32 |
+
|
33 |
+
Args:
|
34 |
+
observation: The state observed from tools in the environment.
|
35 |
+
info: Extended information is used to assist the agent to decide a policy.
|
36 |
+
|
37 |
+
Returns:
|
38 |
+
ActionModel sequence from agent policy
|
39 |
+
"""
|
40 |
+
|
41 |
+
self._finished = False
|
42 |
+
self.desc_transform()
|
43 |
+
|
44 |
+
tool_name = "trace"
|
45 |
+
tool = ToolFactory(tool_name, asyn=False)
|
46 |
+
tool.reset()
|
47 |
+
tool_params = {}
|
48 |
+
action = ActionModel(tool_name=tool_name,
|
49 |
+
action_name=GetTraceAction.GET_TRACE.name,
|
50 |
+
agent_name=self.id(),
|
51 |
+
params=tool_params)
|
52 |
+
message = tool.step(action)
|
53 |
+
|
54 |
+
observation, _, _, _, _ = message.payload
|
55 |
+
|
56 |
+
llm_response = None
|
57 |
+
|
58 |
+
messages = self.messages_transform(content=observation.content,
|
59 |
+
sys_prompt=self.system_prompt,
|
60 |
+
agent_prompt=self.agent_prompt)
|
61 |
+
try:
|
62 |
+
llm_response = call_llm_model(
|
63 |
+
self.llm,
|
64 |
+
messages=messages,
|
65 |
+
model=self.model_name,
|
66 |
+
temperature=self.conf.llm_config.llm_temperature
|
67 |
+
)
|
68 |
+
|
69 |
+
logger.info(f"Execute response: {llm_response.message}")
|
70 |
+
except Exception as e:
|
71 |
+
logger.warn(traceback.format_exc())
|
72 |
+
raise e
|
73 |
+
finally:
|
74 |
+
if llm_response:
|
75 |
+
if llm_response.error:
|
76 |
+
logger.info(
|
77 |
+
f"{self.id()} llm result error: {llm_response.error}")
|
78 |
+
else:
|
79 |
+
logger.error(f"{self.id()} failed to get LLM response")
|
80 |
+
raise RuntimeError(
|
81 |
+
f"{self.id()} failed to get LLM response")
|
82 |
+
|
83 |
+
agent_result = sync_exec(self.resp_parse_func, llm_response)
|
84 |
+
if not agent_result.is_call_tool:
|
85 |
+
self._finished = True
|
86 |
+
return agent_result.actions
|
87 |
+
|
88 |
+
async def async_policy(self, observation: Observation, info: Dict[str, Any] = {}, **kwargs) -> List[ActionModel]:
|
89 |
+
|
90 |
+
self._finished = False
|
91 |
+
self.desc_transform()
|
92 |
+
|
93 |
+
tool_name = "trace"
|
94 |
+
tool = ToolFactory(tool_name, asyn=False)
|
95 |
+
tool.reset()
|
96 |
+
tool_params = {}
|
97 |
+
action = ActionModel(tool_name=tool_name,
|
98 |
+
action_name=GetTraceAction.GET_TRACE.name,
|
99 |
+
agent_name=self.id(),
|
100 |
+
params=tool_params)
|
101 |
+
message = tool.step([action])
|
102 |
+
|
103 |
+
observation, _, _, _, _ = message.payload
|
104 |
+
|
105 |
+
llm_response = None
|
106 |
+
|
107 |
+
messages = self.messages_transform(content=observation.content,
|
108 |
+
sys_prompt=self.system_prompt,
|
109 |
+
agent_prompt=self.agent_prompt)
|
110 |
+
try:
|
111 |
+
llm_response = await acall_llm_model(
|
112 |
+
self.llm,
|
113 |
+
messages=messages,
|
114 |
+
model=self.model_name,
|
115 |
+
temperature=self.conf.llm_config.llm_temperature
|
116 |
+
)
|
117 |
+
|
118 |
+
logger.info(f"Execute response: {llm_response.message}")
|
119 |
+
except Exception as e:
|
120 |
+
logger.warn(traceback.format_exc())
|
121 |
+
raise e
|
122 |
+
finally:
|
123 |
+
if llm_response:
|
124 |
+
if llm_response.error:
|
125 |
+
logger.info(
|
126 |
+
f"{self.id()} llm result error: {llm_response.error}")
|
127 |
+
else:
|
128 |
+
logger.error(f"{self.id()} failed to get LLM response")
|
129 |
+
raise RuntimeError(
|
130 |
+
f"{self.id()} failed to get LLM response")
|
131 |
+
|
132 |
+
agent_result = sync_exec(self.resp_parse_func, llm_response)
|
133 |
+
if not agent_result.is_call_tool:
|
134 |
+
self._finished = True
|
135 |
+
return agent_result.actions
|
136 |
+
|
137 |
+
|
138 |
+
search_sys_prompt = "You are a helpful search agent."
|
139 |
+
search_prompt = """
|
140 |
+
Please act as a search agent, constructing appropriate keywords and searach terms, using search toolkit to collect relevant information, including urls, webpage snapshots, etc.
|
141 |
+
|
142 |
+
Here are the question: {task}
|
143 |
+
|
144 |
+
pleas only use one action complete this task, at least results 6 pages.
|
145 |
+
"""
|
146 |
+
|
147 |
+
summary_sys_prompt = "You are a helpful general summary agent."
|
148 |
+
|
149 |
+
summary_prompt = """
|
150 |
+
Summarize the following text in one clear and concise paragraph, capturing the key ideas without missing critical points.
|
151 |
+
Ensure the summary is easy to understand and avoids excessive detail.
|
152 |
+
|
153 |
+
Here are the content:
|
154 |
+
{task}
|
155 |
+
"""
|
156 |
+
|
157 |
+
trace_sys_prompt = "You are a helpful trace agent."
|
158 |
+
|
159 |
+
trace_prompt = """
|
160 |
+
Please act as a trace agent, Using the provided trace data, summarize the token usage of each agent,
|
161 |
+
whether the runotype attribute of span is an agent or a large model call:
|
162 |
+
run_type=AGNET represents the agent,
|
163 |
+
run_type=LLM represents the large model call.
|
164 |
+
The LLM call of a certain agent is represented as LLM span, which is a child span of that agent span
|
165 |
+
|
166 |
+
Here are the content: {task}
|
167 |
+
"""
|
168 |
+
|
169 |
+
|
170 |
+
def build_run_flow(nodes: List[RunNode]):
|
171 |
+
graph = {}
|
172 |
+
start_nodes = []
|
173 |
+
|
174 |
+
for node in nodes:
|
175 |
+
if hasattr(node, 'parent_node_id') and node.parent_node_id:
|
176 |
+
if node.parent_node_id not in graph:
|
177 |
+
graph[node.parent_node_id] = []
|
178 |
+
graph[node.parent_node_id].append(node.node_id)
|
179 |
+
else:
|
180 |
+
start_nodes.append(node.node_id)
|
181 |
+
|
182 |
+
for start in start_nodes:
|
183 |
+
print("-----------------------------------")
|
184 |
+
_print_tree(graph, start, "", True)
|
185 |
+
print("-----------------------------------")
|
186 |
+
|
187 |
+
|
188 |
+
def _print_tree(graph, node_id, prefix, is_last):
|
189 |
+
print(prefix + ("└── " if is_last else "├── ") + node_id)
|
190 |
+
if node_id in graph:
|
191 |
+
children = graph[node_id]
|
192 |
+
for i, child in enumerate(children):
|
193 |
+
_print_tree(graph, child, prefix +
|
194 |
+
(" " if is_last else "│ "), i == len(children)-1)
|
195 |
+
|
196 |
+
|
197 |
+
if __name__ == "__main__":
|
198 |
+
agent_config = AgentConfig(
|
199 |
+
llm_provider="openai",
|
200 |
+
llm_model_name="gpt-4o",
|
201 |
+
llm_temperature=0.3,
|
202 |
+
|
203 |
+
llm_base_url="http://localhost:34567",
|
204 |
+
llm_api_key="dummy-key",
|
205 |
+
)
|
206 |
+
|
207 |
+
search = Agent(
|
208 |
+
conf=agent_config,
|
209 |
+
name="search_agent",
|
210 |
+
system_prompt=search_sys_prompt,
|
211 |
+
agent_prompt=search_prompt,
|
212 |
+
tool_names=[Tools.SEARCH_API.value]
|
213 |
+
)
|
214 |
+
|
215 |
+
summary = Agent(
|
216 |
+
conf=agent_config,
|
217 |
+
name="summary_agent",
|
218 |
+
system_prompt=summary_sys_prompt,
|
219 |
+
agent_prompt=summary_prompt
|
220 |
+
)
|
221 |
+
|
222 |
+
trace = TraceAgent(
|
223 |
+
conf=agent_config,
|
224 |
+
name="trace_agent",
|
225 |
+
system_prompt=trace_sys_prompt,
|
226 |
+
agent_prompt=trace_prompt
|
227 |
+
)
|
228 |
+
|
229 |
+
# default is sequence swarm mode
|
230 |
+
swarm = Swarm(search, summary, trace, max_steps=1, event_driven=True)
|
231 |
+
|
232 |
+
prefix = "search baidu:"
|
233 |
+
# can special search google, wiki, duck go, or baidu. such as:
|
234 |
+
# prefix = "search wiki: "
|
235 |
+
try:
|
236 |
+
res = Runners.sync_run(
|
237 |
+
input=prefix + """What is an agent.""",
|
238 |
+
swarm=swarm,
|
239 |
+
session_id="123"
|
240 |
+
)
|
241 |
+
print(res.answer)
|
242 |
+
except Exception as e:
|
243 |
+
logger.error(traceback.format_exc())
|
244 |
+
|
245 |
+
state_manager = RuntimeStateManager.instance()
|
246 |
+
nodes = state_manager.get_nodes("123")
|
247 |
+
logger.info(f"session 123 nodes: {nodes}")
|
248 |
+
build_run_flow(nodes)
|
249 |
+
get_trace_server().join()
|