docs/adr/0014-opik-observability.mdXem bản gốc Bản dịch đầy đủ theo đúng cấu trúc tài liệu; code, liên kết và định danh kỹ thuật được giữ nguyên.
0014. Khả năng quan sát của Opik - dấu vết cho mỗi lượt, lượt chạy và subagent
Trạng thái: Đã chấp nhận Ngày: 2026-07-05
Bối cảnh
decode có vòng lặp agent (REPL) và headless decode run con đường, cả hai đều điều khiển agent pydantic-ai,
cộng với phân xuất subagent M9, ghi lại bộ nhớ và nén — tất cả đều thực hiện cuộc gọi LLM. Cho đến bây giờ
không có cách nào để biết một lượt thực sự đã làm gì: lệnh gọi mô hình nào đã xảy ra, với cái gì
đầu vào/đầu ra, số lượng token, độ trễ bao nhiêu và chi phí. ADR-0013 §9 được trì hoãn rõ ràng
"Chi tiêu token con là vô hình cho đến khi Opik hạ cánh (M10)". Cột mốc 10 đã chứng minh được điều đó: giám sát
(truy tìm), không đánh giá - evals là M13.
Những hạn chế hình thành nên thiết kế:
- Mọi địa điểm gọi LLM ở
src/đã là agent pydantic-ai — vòng lặp chính (agent/factory.build_agent), ghi lại bộ nhớ (memory/extract.py), sự nén chặt (context/compaction.py) và các subagent (nhập lại CÙNG agent thông quatools/agent.py). Vì vậy, một lệnh gọi thiết bị toàn cầu có thể bao quát mọi bề mặt cùng một lúc mà không cần mã trang web cho mỗi cuộc gọi. - Quy tắc nội bộ: cơ sở hạ tầng nhập khẩu, không trừu tượng; điều đơn giản nhất mà có hiệu quả. Ưu tiên tích hợp bị xử phạt trên các nhịp cán bằng tay; một mô-đun nhỏ, không có đường nối đầu cơ.
- Quy tắc chung: không bao giờ đọc/thay đổi
os.environđi sâu vào các trang web cuộc gọi; cấu hình sống trongsettings.py. Công thức mặc định của tài liệu Opik định cấu hình xuất qua toàn cầuOTEL_EXPORTER_OTLP_*env vars - nhưng kitaru→zenml cũng cung cấp SDK OpenTelemetry và việc gây ô nhiễm môi trường OTEL toàn cầu có thể chuyển hướng của nó đo từ xa nữa. Việc xuất phải được định cấu hình theo chương trình từ cài đặt, chỉ được đính kèm với logfire's nhà cung cấp công cụ theo dõi. - Hỗ trợ dựa trên hiện diện, giống hệt byte khi tắt. Giống như mọi bề mặt tùy chọn trước đó (hộp cát, runtime), việc chạy không có phím phải không thể phân biệt được với ngày nay.
filterwarnings=["error"]— cảnh báo của người phụ trách mới và mọi định dạng công cụ đo lường không được dùng nữa sẽ thất bại bộ phần mềm.
Sự thật đã được xác minh dựa trên các gói đã cài đặt + tài liệu chính thức trước khi quyết định:
- Công thức chính thức (comet.com/docs/opik/integrations/pydantic-ai):
logfire.configure(send_to_logfire=False)logfire.instrument_pydantic_ai(); nhóm chủ đề thông quawith logfire.span("chat_turn", thread_id=…); lập trìnhadditional_span_processors=[…]đường dẫn là mẫu riêng của tài liệu (OpikSpanProcessor ví dụ).
- Nhập OTLP (comet.com/docs/opik/integrations/opentelemetry): Điểm cuối của Opik đọc tiêu chuẩn
gen_ai.usage.input_tokens|output_tokens|total_tokens+gen_ai.request/response.model+gen_ai.system; nền tảng đám mâyhttps://www.comet.com/opik/api/v1/private/otel, tự chủhttp://localhost:5173/api/v1/private/otel, tiêu đềAuthorization+Comet-Workspace+projectName; nhà xuất khẩu dấu vết http làopentelemetry.exporter.otlp.proto.http.trace_exporter.OTLPSpanExporter. - Chi phí (comet.com/docs/opik/tracing/advanced/cost_tracking): Opik ước tính chi phí phía máy chủ từ
(nhà cung cấp, mô hình, cách sử dụng) và "tổng hợp chi phí từ tất cả các nhịp trong một dấu vết"; chi phí là
Nonecho các mô hình không được hỗ trợ. Gemini có giá (Google AI); Các mô hình mở OpenRouter/Modal có thể không được định giá. - pydantic-ai
InstrumentationSettingsmặc định (pydantic.dev/docs/ai):include_content=True,include_binary_content=True,version=5(2–4 phát raPydanticAIDeprecationWarning),use_aggregated_usage_attribute_names=True(tổng số do agent điều hành theo tùy chỉnhgen_ai.aggregated_usage.*không gian tên để các phần phụ trợ tổng hợp — Opik — không tính hai lần; lá Các nhịp LLM giữ tiêu chuẩngen_ai.usage.*). Các giá trị mặc định hoàn toàn chính xác — chúng tôi không chuyển bất kỳ cài đặt nào. logfiremang lại tạm thờiopentelemetry-exporter-otlp-proto-http+opentelemetry-sdk+protobuf(đã được xác minh trên PyPI), do đó, nhà xuất khẩu sẽ đến với MỘT cấp cao nhất mới.logfire.testingtàuTestExporter/capfire/CaptureLogfire/exported_spans_as_dict- con đường khẳng định khoảng cách kín.
kitaru.current_execution_id()là bản xuất cấp cao nhất (đã cài đặt kitaru 0.18) trả về id thực thi đang hoạt động bên trong phạm vi luồng - không có đầuthread_idnguồn.- Tuân theo vòng đời (
harness/runner.py):Runner._run_turnđiều khiển một trình tạo không đồng bộ mỗi lượt và cuộc gọiagen.aclose()một cách dứt khoát trongfinally, vậy mộtAgentTurnHandler.__call__== một lượt == một nhịp gốc.
Thuật ngữ - pydantic-ai, logfire, OpenTelemetry và Opik phù hợp như thế nào
Bốn tên trong ADR này là bốn lớp của một đường ống, không phải bốn tên thay thế — được ghi ở đây bởi vì "tại sao lại là OTLP mà không phải Opik SDK?" là lần đọc sai đầu tiên một cách tự nhiên (họ không phản đối):
| Lớp | Nó là gì | Đang decode |
|---|---|---|
| pydantic-ai | khuôn khổ LLM có agent thực hiện cuộc gọi - điều đang được quan sát | vòng lặp chính, ghi lại bộ nhớ, nén, subagent |
| đốt cháy | SDK thiết bị của Pydantic — một lớp bao bọc mỏng xung quanh OpenTelemetry | instrument_pydantic_ai(), configure(), span() trong tracing.py |
| OpenTelemetry (OTel) | tiêu chuẩn + SDK trung lập với nhà cung cấp dành cho dấu vết/số liệu/nhật ký; định dạng dây là OTLP | OTLPSpanExporter, BatchSpanProcessor, cái gen_ai.* thuộc tính nhịp |
| Opik | phần phụ trợ tiếp nhận các nhịp và định giá chúng | điểm cuối OTLP mà nhà xuất khẩu POST tới |
- OpenTelemetry là ngôn ngữ phổ biến. span là một đơn vị công việc (LLM hoặc lệnh gọi công cụ) với
tên, thời gian và khóa-giá trị thuộc tính; kéo dài tổ thành một dấu vết (một lượt REPL) thông qua
lan truyền bối cảnh không đồng bộ; OTLP là giao thức vận chuyển chúng. Tên thuộc tính được tiêu chuẩn hóa
(
gen_ai.usage.*,gen_ai.request.model,gen_ai.system— Quy ước ngữ nghĩa GenAI của Otel chính xác là những gì Opik đọc để hiển thị token + chi phí không có mã keo. Bởi vì OtelTracerProviderlà process-global, cả hai thư viện đều định cấu hình nó xung đột - đây là nguyên nhân cốt lõi của xung đột kitaru→zenml buộc cài đặt theo hướng (không phải toàn cầu-OTEL_*-env) xuất khẩu (quyết định phụ 2). - logfire là Otel bên dưới (
logfire.span→ một khoảng OTel;configure()→ nhà cung cấp Otel). Chúng tôi sử dụng thư viện, không phải nền tảng lưu trữ của Pydantic —send_to_logfire=Falsechỉ mượn nó thôi thiết bị đo đạc và chuyển hướng kéo dài đến Opik. Nó giành được vị trí của mình theo hai cách: (a)instrument_pydantic_ai()là sự tích hợp một cuộc gọi toàn cầu (Pydantic tạo ra cả hai thư viện), so với. việc viết tay trải dài ở mọi địa điểm gọi bằng Otel thô; (b) cài đặtlogfiremang lại sự chuyển tiếp Nhà xuất khẩu OTLP + SDK OTel, vì vậy toàn bộ quy trình sẽ có một phụ tùng cấp cao nhất. - "OTLP" là tài liệu vận chuyển riêng của Opik cho công thức logfire/pydantic-ai
(comet.com/docs/opik/integrations/pydantic-ai) — không bỏ qua SDK Opik. Sự lựa chọn hạn hẹp
chúng tôi thực sự đã làm là
OTLPSpanExportertrên SDK opikOpikSpanProcessor: cả hai đều là Opik đường đi, nhưng nhà xuất khẩu vận chuyển miễn phí bằng logfire trong khiOpikSpanProcessorcần toàn bộopikgói dưới dạng gói phụ thứ 2 để không tăng phạm vi bao phủ (được giữ làm lối thoát một dòng trong quyết định phụ 8).
Quyết định
Cơ chế = tích hợp logfire chính thức, được trang bị trên toàn cầu, được xuất theo chương trình sang Đánh giá về OTLP. So sánh với các lựa chọn thay thế:
| Cơ chế | Nó là gì | Bảo hiểm | Deps mới | Chi phí / token | Bản án |
|---|---|---|---|---|---|
| SDK OTel đơn giản (các khoảng thời gian thủ công) | thiết bị cầm tay mỗi lệnh gọi LLM/công cụ với dữ liệu thô opentelemetry-sdk kéo dài + gen_ai.* thuộc tính | mọi thứ, nhưng bạn viết nó ở mọi trang web cuộc gọi | nhà xuất khẩu otlp | bạn đặt gen_ai.usage.* chính bạn từ run.usage() | bị từ chối - phát minh lại những gì instrument_pydantic_ai() cho miễn phí; chạm vào mọi bề mặt; giòn |
| logfire-chính thức (CHOSEN) | logfire.configure(send_to_logfire=False) + toàn cầu instrument_pydantic_ai() + nhà xuất khẩu OTLP theo hướng cài đặt → Opik | TẤT CẢ agent pydantic-ai (chính, bộ nhớ, nén, subagent) trong một lệnh gọi; không có mã cho mỗi cuộc gọi | logfire chỉ (mang đến nhà xuất khẩu OTLP) | gen_ai.usage.* trên nhịp LLM → giá Opik; aggregated_usage tránh tính hai lần | được chọn — con đường được phê duyệt; một cuộc gọi toàn cầu; khớp với phạm vi bị khóa |
trang trí SDK opik (@opik.track / OpikSpanProcessor) | bọc các điểm vào trong @opik.track và/hoặc đăng ký OpikSpanProcessor để hợp nhất các phạm vi logfire vào @track dấu vết | chỉ lối vào được trang trí; hợp nhất cần bộ xử lý | +opik (và vẫn còn cháy rừng) | giá đường dẫn SDK opik đáng tin cậy | hoãn lại — trang trí thứ 2 + cho mỗi điểm vào; chỉ kiếm được nếu chi phí OTLP không được chứng minh (cửa thoát bên dưới) |
| Tái thiết sau thời gian | xây dựng lại dấu vết ngoại tuyến từ nhật ký phiên JSONL/điểm kiểm tra Kitaru | một phần, mất mát | không | không có độ trễ/token/chi phí trực tiếp | bị từ chối — mất dữ liệu, không có tín hiệu trực tiếp, trùng lặp OTel |
Các quyết định phụ (tất cả đều được ghi lại để không bị khởi kiện lại):
-
Kích hoạt = sự hiện diện của
OPIK_API_KEY. Đặt → dò theo đám mây Comet;OPIK_URL_OVERRIDEchuyển cơ sở OTLP sang Opik tự lưu trữ; không →init_tracing()là một im lặng no-op và decode là byte giống hệt nhau. Toàn bộ nội dung tin nhắn/công cụ được ghi lại (pydantic-aiinclude_content=Truemặc định). Một dòng INFO khi hoạt động (dòng bảng điều khiển REPL + dòng nhật ký). -
Xuất theo hướng cài đặt, không theo hướng env.
init_tracing()xây dựngOTLPSpanExporter(endpoint="<base>/v1/traces", headers={Authorization, Comet-Workspace, projectName})từsettingsvà đính kèm nó thông qualogfire.configure(send_to_logfire=False, bổ sung_span_processors=[BatchSpanProcessor(exporter)]). No globalOTEL_*env var được đặt, vì vậy SDK OTel của kitaru/zenml không bị ảnh hưởng. -
Thiết bị đo có tính chung và được cấu hình mặc định.
logfire.instrument_pydantic_ai()không cóInstrumentationSettings— các giá trị mặc định cung cấp đầy đủ nội dung, định dạng v5 (không có cảnh báo không dùng nữa) vàuse_aggregated_usage_attribute_names=Truevì vậy Opik định giá LLM lá kéo dài mà không tính hai lần khoảng runtime agent tổng hợp. Một cuộc gọi bao gồm vòng lặp chính, ghi lại bộ nhớ, nén và agent phụ. -
Hình dạng dấu vết.
- REPL: một dấu vết mỗi lượt — một nhịp gốc (
chat_turn,thread_id= id phiên) kết thúc toàn bộAgentTurnHandler.__call__phần thân, vì vậy chân phê duyệt/tiếp tục của công cụ kiểm soát vẫn giữ nguyên độ trễ theo dõi và quay vòng một cách trung thực bao gồm cả thời gian chờ cổng. Các bối cảnh cùng nhiệm vụ lồng vào mô hình/công cụ trải dài dưới nó. (Cẩn thận:withnhịp vượt quayields; tính quyết định của người chạyaclose()giải phóng nó khi kết thúc bình thường, có lỗi và hủy bỏ - một cuộc kiểm tra sẽ bảo vệ điều này.) - headless: một dấu vết mỗi lần chạy — một nhịp gốc (
decode_run/decode_run_hitl,thread_id = current_execution_id()) kết thúc tốt đẹprun_sync, được mở bên trong luồng SAU_config_from_secret_store()vậy là một cửa hàng bí mậtOPIK_API_KEYđược vinh danh. - Free-rider: quá trình ghi lại và nén bộ nhớ diễn ra như những dấu vết nhỏ của riêng chúng (hoặc tổ, khi ở trong một ngã rẽ) thông qua cùng một thiết bị đo tổng thể — không cần nối dây.
- Các subagent lồng bên trong dấu vết của lượt cha (cùng một nhiệm vụ/bối cảnh), đóng ADR-0013 §9's "chi tiêu token con vô hình cho đến khi Opik hạ cánh (M10)".
- Đầu vào/đầu ra của khoảng gốc được đặt rõ ràng (bản sửa lỗi sau 091, đã được xác minh trực tiếp). riêng của pydantic-ai
nhịp (
agent run/chat …/running tool) nhận I/O miễn phí từ toàn cầu thiết bị đo đạc, nhưng được mở thủ công của chúng tôichat_turn/decode_run[_hitl]rễ bắt đầu trống - và Opik lấy đầu vào/đầu ra của dấu vết từ khoảng ROOT của nó, không bao giờ từ con cháu. Vì vậy rễ mang theo lượt/chạy đầu vào (lời nhắc / nhiệm vụ) như mộtinputthuộc tính và, ở cuối lượt/chạy, văn bản trợ lý cuối cùng dưới dạngoutputthuộc tính thông quaobservability.record_output(span, …). của Opik OTLP nhập các nhóm này bằng khớp tiền tố trên khóa thuộc tính (input*→ ĐẦU VÀO,output*→ ĐẦU RA — đã được xác minh trong opik'sGeneralMappingRules). Đây là khả năng chịu tải cho Threads: Thread Chế độ xem được xây dựng từ đầu vào/đầu ra cấp dấu vết (first_message.input/last_message.output), vậy không có nó, toàn bộ cuộc trò chuyện sẽ trở nên trống rỗng-các hàng ngay cả khi các khoảng LLM lồng nhau có I/O.
- REPL: một dấu vết mỗi lượt — một nhịp gốc (
-
Đường may ban đầu =
observability.init_tracing(), bình thường (quy trình toàn cầulogfire.configure), được gọi là từrun_app(REPL) và bên trong mỗi@flowcơ thể (headless). Một mô-đun nhỏ (observability/tracing.py) giữinit_tracing/is_tracing_active/root_span/record_output/reset_tracing. -
Deps =
logfirechỉ. Nó mang lạiopentelemetry-exporter-otlp-proto-http; khônglogfire[httpx], khôngopik. Lưu ý: Các chân OTel/protobuf của logfire phải đồng phân giải với kitaru→zenml + modal tại thời điểm khóa. -
Kiểm tra cách ly. Tự động sử dụng
_no_opik_tracingkhoảng trống cố địnhopik_api_keynhững bài kiểm tra thông thường không bao giờ định cấu hình xuất thực (mirror_no_real_provider_key); các bài kiểm tra xác nhận nhịp chọn tham gia bằng chìa khóa giả +logfire.testingnhà xuất khẩu trong bộ nhớ;reset_tracing()xóa cờ mô-đun. -
Đường dẫn chi phí — decode tem chi phí; cái
opikKHÔNG cần đến cửa thoát SDK. Kết quả chỉ dành cho token mà phần này cho phép là "chấp nhận được" hóa ra lại là kết quả dành cho cả ba nhà cung cấp, vì vậy nó hiện đã được sửa trongobservability/cost.py+CostAnnotatingExporter(tracing.py). Những gì đã được xác minh:- Quá trình nhập OTLP của Opik đọc chính xác một khóa chi phí —
gen_ai.usage.cost- và một cách rõ ràng giá trị đoản mạch phía máy chủ của nó(provider, model)tra cứu giá, vì vậy nó hoạt động ngay cả đối với một model mà Opik chưa từng nghe tới. Được tìm thấy trong các quy tắc ánh xạ phụ trợ của opik và không có trong nó tài liệu công khai — một hợp đồng có thật nhưng không có giấy tờ, vì vậy nó đã được xác nhận dựa trên Opik trực tiếp thay vì được tin cậy: một lượt OpenRouter được theo dõi (deepseek/deepseek-chat) đã trở lại vớitotal_estimated_cost = 0.00467553trênllmspan, khớp giá genai với chữ số cuối cùng. Opik có không hàng giá bộ định tuyến mở, vì vậy số đó chỉ có thể là thuộc tính đang được đọc. các cùng một hoạt động cho thấyagent runtạicost=None, xác nhận tính năng bảo vệ đếm kép trên dữ liệu trực tiếp. Nếu bản phát hành Opik trong tương lai đổi tên khóa, chi phí sẽ biến mất một cách lặng lẽ; triệu chứng cần theo dõi có token, giá trống. - pydantic-ai đã định giá mọi thứ mà danh mục genai-price biết, nhưng xuất bản nó dưới dạng
operation.cost— một phím Opik không đọc được. Đó không phải là một mức giá còn thiếu, đó là khoảng trống Gemini. - Bảng giá của Opik có **không
openrouterhoàn toàn không có hàng ** và điểm cuối Modal tự lưu trữ (Qwen/Qwen3.6-35B-A3B-FP8) không bao giờ có thể có được.
Vì vậy, nhà xuất khẩu chuyển tiếp giá danh mục của pydantic-ai theo khóa mà Opik đọc và quay trở lại
LLM_COST_{INPUT,OUTPUT}_USD_PER_MTOKkhi danh mục không có hàng. Cả hai tỷ lệ không được đặt (0,0) có nghĩa là Thuộc tính chi phí "không xác định" và no được viết — chi phí trống đánh bại chi phí bịa đặt. Mỗi nhà cung cấp, điều này thực sự mua được gì:- Song Tử — đã sửa hoàn toàn; danh mục định giá nó và cây cầu cung cấp nó.
- OpenRouter — đã sửa lỗi cho các phần mềm phổ biến mà danh mục biết (
anthropic/…,google/…,openai/…,deepseek/…,meta-llama/…). Thiếu danh mục (ví dụ:qwen/qwen3-235b-a22b) nhu cầu tỷ lệ thủ công. Mặc địnhopenrouter/freebộ định tuyến thực sự là $0, vì vậy giá trống là sửa ở đó chứ không phải thiếu. OpenRouter không trả lại chi phí đã tính chính xác thông qua việc sử dụng kế toán, nhưng pydantic-ai bỏ lĩnh vực đó - nắm bắt nó là một công việc sửa ống nước thực sự, không phải là một cái núm, và cố tình không được thực hiện ở đây. - Modal — luôn miễn phí THEO MỤC ĐÍCH. Điểm cuối tự lưu trữ tính phí GPU-giây, vì vậy không cần
con số trên mỗi token mô tả số tiền thực sự được thanh toán; tỷ giá không được sử dụng để sản xuất
một. Dấu vết phương thức mang token và độ trễ, đồng thời chi tiêu tồn tại trong thanh toán của chính Modal.
Hai hậu quả đáng được đặt tên: đó là trình bao bọc nhà xuất khẩu, không phải bộ xử lý nhịp, bởi vì
on_endđưa ra một ảnh chụp nhanh nhịp bất biến; và chỉ những nhịp mang theogen_ai.request.modelđược định giá, bởi vì pydantic-ai lặp lại cách sử dụng tổng hợp của lần chạy trên cấp độ gốcagent runspan và Opik SUMS span chi phí - cả hai mức giá sẽ báo cáo mỗi lần chạy ở mức gấp đôi chi tiêu thực tế của nó. Cửa thoát hiểm (vẫn mở, vẫn chưa sử dụng): nếu hợp đồng thuộc tính bị phá vỡ, hãy đổi sangopikSDK (additional_span_processors=[…, OpikSpanProcessor()]) vẫn là một thay đổi một dòng.
- Quá trình nhập OTLP của Opik đọc chính xác một khóa chi phí —
-
M13 (sau này) thêm đánh giá / thử nghiệm / tính điểm trực tuyến lên trên các dấu vết này — không phải bây giờ.
Sơ đồ
Span flow — REPL quay và chạy headless cung cấp dữ liệu cho một thiết bị đo toàn cầu, được xuất từ cài đặt sang Opik.
flowchart TD
subgraph repl["REPL turn (single asyncio task)"]
rt["AgentTurnHandler.__call__<br/>root span 'chat_turn' · thread_id = session_id"]:::root
rlegs["legs: model-request + tool + gated approve/resume<br/>(pydantic-ai spans nest via shared task context)"]:::leg
rt --> rlegs
end
subgraph headless["decode run (Kitaru @flow)"]
ht["@flow body<br/>root span 'decode_run' · thread_id = current_execution_id()"]:::root
hlegs["KitaruAgent.run_sync → model/tool spans<br/>(per-call worker loops: nesting best-effort)"]:::leg
ht --> hlegs
end
subgraph sub["Subagent (agent tool, same task)"]
cspans["child agent.run() model/tool spans<br/>nest INSIDE the parent turn (closes ADR-0013 §9)"]:::child
end
rlegs -.-> cspans
instr["logfire.instrument_pydantic_ai() — GLOBAL<br/>main + memory write-back + compaction + subagents"]:::instr
rlegs --> instr
hlegs --> instr
cspans --> instr
instr --> lf["logfire tracer provider<br/>configure(send_to_logfire=False)"]:::lf
lf --> exp["BatchSpanProcessor → OTLPSpanExporter<br/>endpoint + headers from settings (NO global OTEL env)"]:::exp
exp --> opik[("Opik / Comet<br/>OTLP ingest → gen_ai.usage.* → tokens + cost<br/>thread_id → conversation thread")]:::opik
off["OPIK_API_KEY unset → init_tracing() no-op<br/>zero spans · decode byte-identical"]:::off
off -.-> instr
classDef root fill:#1e293b,stroke:#0ea5e9,color:#e2e8f0
classDef leg fill:#334155,stroke:#a855f7,color:#e9d5ff
classDef child fill:#14532d,stroke:#22c55e,color:#dcfce7
classDef instr fill:#713f12,stroke:#eab308,color:#fef9c3
classDef lf fill:#334155,stroke:#38bdf8,color:#bae6fd
classDef exp fill:#3b0764,stroke:#c084fc,color:#f3e8ff
classDef opik fill:#052e16,stroke:#4ade80,color:#dcfce7
classDef off fill:#0f172a,stroke:#64748b,color:#cbd5e1
hậu quả
- Một cuộc gọi toàn cầu bao trùm mọi bề mặt. Việc thêm trang web cuộc gọi LLM pydantic-ai trong tương lai sẽ được theo dõi cho miễn phí - không có công việc trên mỗi trang web.
- decode giống hệt byte mà không có
OPIK_API_KEY. Toàn bộ tính năng sẽ không hoạt động cho đến khi một khóa được đặt; REPL không in dòng nào, thiết bị xuất chuẩn của lệnh chạy headless không thay đổi, các nhịp bằng 0 được phát ra. - Cấu hình vẫn còn
settings.py. Không có toàn cầuOTEL_*env var bị đột biến, do đó OTel của kitaru/zenml SDK không bị ảnh hưởng. - Chi phí được nỗ lực tối đa theo mô hình. Token luôn; chi phí cho các mẫu có giá (Gemini vâng; các mẫu mở qua
OpenRouter/Modal có thể chỉ có token). các
opik-SDK Escape Hatch là hoán đổi một dòng nếu cần. - Lồng nhau ở cấp độ chạy headless là nỗ lực tốt nhất trong
checkpoint_strategy="calls". Nhân viên theo cuộc gọi các vòng lặp có thể phá vỡ việc truyền bá bối cảnh OTel, vì vậy một số nhịp mô hình có thể xuất dưới dạng dấu vết anh chị em thay vì hơn được lồng dưới gốc chạy; mọi nhịp vẫn mang token. Một trần nhà được ghi lại, giống như ADR runtime. - ADR-0013 §9 đã bị đóng. Phần con phụ kéo dài lồng trong dấu vết của lượt cha mẹ với phần con hiển thị việc sử dụng token.
- Rủi ro cần xác nhận trong quá trình triển khai: (a)
uv add logfiređồng giải quyết các chân OTel/protobuf của nó với kitaru→zenml + modal (một trình chặn cứng nếu nó bị lỗi); (b) vượt qua nhịp của trình tạo không đồng bộyieldnó sẽ kết thúc đúng một lần khi hủy bỏ (được bảo vệ bởi người chạyaclose()+ bài kiểm tra); (c) liệu Chi phí Gemini hiện thực hóa thông qua OTLP thuần túy (được kiểm tra bằng khói trực tiếp; cửa thoát hiểm đã sẵn sàng); (d)logfire.configurenhà cung cấp dịch vụ theo dõi toàn cầu quy trình của cùng tồn tại với bất kỳ bộ kitaru/zenml của nhà cung cấp nào trong con đường headless. - Kỷ luật (không thay đổi):
filterwarnings=["error"], ngày giờ nhận biết UTC, chú thích đầy đủ, thư viện nhật ký mã (không bao giờprint()),tests/gươngsrc/1:1, TDD-first, không có mạng trong CI (FunctionModellogfire.testing; một làn khói sốngskipif-được bảo vệ).