{"id":823,"date":"2026-07-06T18:01:58","date_gmt":"2026-07-06T10:01:58","guid":{"rendered":"https:\/\/blog.itsmygo.uk\/2026\/07\/06\/%e5%b9%ab-claude-agent-sdk-%e6%8e%a5%e4%b8%8a-mlflow-tracing%ef%bc%9aautolog-%e6%8e%9b%e4%b8%8d%e5%88%b0%ef%bc%8c%e5%b0%b1%e5%be%9e%e8%a8%8a%e6%81%af%e6%b5%81%e8%87%aa%e5%b7%b1%e9%87%8d%e5%bb%ba-span\/"},"modified":"2026-07-06T18:32:34","modified_gmt":"2026-07-06T10:32:34","slug":"%e5%b9%ab-claude-agent-sdk-%e6%8e%a5%e4%b8%8a-mlflow-tracing%ef%bc%9aautolog-%e6%8e%9b%e4%b8%8d%e5%88%b0%ef%bc%8c%e5%b0%b1%e5%be%9e%e8%a8%8a%e6%81%af%e6%b5%81%e8%87%aa%e5%b7%b1%e9%87%8d%e5%bb%ba-span","status":"publish","type":"post","link":"https:\/\/blog.itsmygo.uk\/wordpress\/2026\/07\/06\/%e5%b9%ab-claude-agent-sdk-%e6%8e%a5%e4%b8%8a-mlflow-tracing%ef%bc%9aautolog-%e6%8e%9b%e4%b8%8d%e5%88%b0%ef%bc%8c%e5%b0%b1%e5%be%9e%e8%a8%8a%e6%81%af%e6%b5%81%e8%87%aa%e5%b7%b1%e9%87%8d%e5%bb%ba-span\/","title":{"rendered":"\u5e6b Claude Agent SDK \u63a5\u4e0a MLflow Tracing\uff1a\u5b98\u65b9 autolog + 30 \u884c\u88dc\u4e01\u5c64\uff08cost\u3001chat id\uff09\uff0c\u8207\u5168\u624b\u52d5\u91cd\u5efa span \u6a39\u7684\u53d6\u6368"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">\u6211\u6709\u4e00\u500b\u7528 <strong>Claude Agent SDK\uff08Python\uff09+ FastAPI<\/strong> \u505a\u7684\u804a\u5929\u61c9\u7528\uff1a\u4f7f\u7528\u8005\u4e1f\u4e00\u7bc7\u6587\u7ae0\u9032\u804a\u5929\u6846\uff0c\u5f8c\u7aef\u7684 agent \u81ea\u5df1\u8dd1\u5e7e\u767e\u500b\u5de5\u5177\u547c\u53eb\uff0c\u6700\u5f8c\u5410\u51fa\u4e00\u652f\u5f71\u7247\u3002\u554f\u984c\u662f agent \u4e00\u8dd1\u5c31\u662f\u5e7e\u5206\u9418\uff0c\u4e2d\u9593\u505a\u4e86\u4ec0\u9ebc\u3001\u6bcf\u56de\u5408\u71d2\u591a\u5c11 token\u3001\u54ea\u500b\u5de5\u5177\u5361\u4f4f\uff0c\u5168\u90fd\u662f\u9ed1\u7bb1\u3002<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u9019\u7bc7\u7b46\u8a18\u8a18\u9304\u6211\u600e\u9ebc\u5e6b\u5b83\u88dd\u4e0a <strong>MLflow Tracing<\/strong>\uff08\u4e00\u500b\u804a\u5929\u56de\u5408 = \u4e00\u689d trace\uff09\uff0c\u904e\u7a0b\u4e2d\u7528\u4e86\u54ea\u4e9b Claude Code skill \u548c MCP \u5de5\u5177\uff0c\u4ee5\u53ca\u8e29\u5230\u7684\u5751\u3002<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\">**2026-07-06 \u66f4\u65b0\uff08\u5169\u6b21\uff09**\uff1a\u521d\u7248\u6211\u5beb\u300cAgent SDK spawn CLI \u5b50\u884c\u7a0b\uff0cautolog \u5b8c\u5168\u639b\u4e0d\u5230\u300d\u2014\u2014**\u9019\u53e5\u8a71\u662f\u932f\u7684**\u3002\u5b98\u65b9\u5176\u5be6\u6709 [Claude Agent SDK (Python) \u7684 tracing \u6574\u5408](https:\/\/mlflow.org\/docs\/latest\/genai\/tracing\/integrations\/listing\/claude_agent_sdk_python\/)\uff08MLflow \u2265 3.5\uff09\u3002\u88ab\u8b80\u8005\u6253\u81c9\u4e4b\u5f8c\u6211\u628a\u5b98\u65b9\u6574\u5408\u5b8c\u6574\u5be6\u6e2c\u4e86\u4e00\u8f2a\u3001\u88dc\u4e0a\u5c0d\u6bd4\uff1b\u7136\u5f8c\u60f3\u901a\u4e86\uff1a**\u5b98\u65b9\u57fa\u5e95 + 30 \u884c\u88dc\u4e01\u5c64\u88dc\u6389\u5b83\u7f3a\u7684**\uff0c\u7dad\u8b77\u9762\u6700\u5c0f\u2014\u2014\u751f\u7522\u74b0\u5883\u5df2\u7d93\u5207\u904e\u53bb\uff0c\u672c\u6587\u6700\u5f8c\u4e00\u7bc0\u5c31\u662f\u6700\u7d42\u843d\u5730\u7248\u3002\u624b\u52d5\u91cd\u5efa span \u6a39\u7684\u5b8c\u6574\u5be6\u4f5c\u4ecd\u4fdd\u7559\u5728\u6587\u4e2d\uff0c\u9700\u8981\u771f\u5be6\u6642\u9577\uff0f\u5b50\u4ee3\u7406\u5de2\u72c0\u7684\u4eba\u76f4\u63a5\u6284\u3002<\/p>\n<\/blockquote>\n\n\n\n<h2 class=\"wp-block-heading\">\u5148\u8b1b\u7d50\u8ad6<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n\n<li>MLflow \u2265 3.5 <strong>\u5b98\u65b9\u652f\u63f4 trace Claude Agent SDK<\/strong>\uff1a<code>mlflow.anthropic.autolog()<\/code>\uff0c\u5b83 patch \u7684\u4e0d\u662f <code>anthropic<\/code> SDK\uff08\u4f60\u7684\u884c\u7a0b\u88e1\u6839\u672c\u6c92\u6709\uff09\uff0c\u800c\u662f <strong><code>ClaudeSDKClient.__init__<\/code><\/strong>\u2014\u2014wrap \u6389 <code>query()<\/code> \u548c <code>receive_response()<\/code>\uff0c\u7b49\u8a0a\u606f\u6d41\u6536\u5b8c\uff0c\u518d\u4e00\u53e3\u6c23\u628a\u6574\u4e32\u8a0a\u606f\u91cd\u5efa\u6210 trace\u3002<\/li>\n\n\n<li>\u63db\u53e5\u8a71\u8aaa\uff1a<strong>\u5b98\u65b9\u7684\u505a\u6cd5\u4e5f\u662f\u300c\u5f9e\u8a0a\u606f\u6d41\u91cd\u5efa span \u6a39\u300d<\/strong>\uff0c\u8ddf\u6211\u624b\u52d5\u505a\u7684\u662f\u540c\u4e00\u689d\u8def\u2014\u2014\u5dee\u5225\u53ea\u5728\u5b98\u65b9\u662f\u300c\u6536\u5b8c\u4e8b\u5f8c\u5efa\u300d\u3001\u6211\u662f\u300c\u908a\u6536\u908a\u5efa\u300d\u3002\u9019\u500b\u5dee\u5225\u6bd4\u807d\u8d77\u4f86\u5927\uff1a\u4e8b\u5f8c\u5efa\u7684 span\uff0c<strong>\u6642\u9577\u5168\u90e8\u662f\u5047\u7684\uff08~0ms\uff09<\/strong>\uff0c\u4f60\u770b\u4e0d\u51fa\u54ea\u500b\u5de5\u5177\u8dd1\u4e86 45 \u79d2\u3002<\/li>\n\n\n<li>\u5b98\u65b9\u7248\u5be6\u6e2c\u9650\u5236\uff1a<strong>\u6c92\u6709 cost<\/strong>\u3001<strong>\u5b50\u4ee3\u7406\u4e0d\u5de2\u72c0<\/strong>\u3001session \u53ea\u80fd\u662f CLI \u5167\u90e8 id\u3001\u7570\u5e38\u4e2d\u65b7\u7684\u56de\u5408\u4e0d\u8a18 trace\u3002\u5176\u4e2d cost \u548c session \u7528 <strong>trace tag \u88dc\u4e01<\/strong>\u5c31\u80fd\u88dc\uff08\u898b\u6700\u7d42\u843d\u5730\u7bc0\uff09\uff1b\u6642\u9577\u548c\u5de2\u72c0\u88dc\u4e0d\u4e86\uff0c\u8981\u5c31\u5f97\u5168\u624b\u52d5\u3002<\/li>\n\n\n<li>\u5957\u4ef6\u9078\u64c7\u662f\u500b\u96b1\u85cf\u5751\uff1a\u5b98\u65b9\u6574\u5408\u7684 <code>mlflow.claude_code<\/code> \u6a21\u7d44<strong>\u5728 <code>mlflow-skinny<\/code> \u88e1\u6709\u3001\u5728 <code>mlflow-tracing<\/code> \u88e1\u6c92\u6709<\/strong>\uff0c\u800c\u4e14 <code>autolog()<\/code> \u786c import <code>anthropic<\/code>\u3002\u6700\u5c0f\u53ef\u7528\u7d44\u5408 = <code>mlflow-skinny + anthropic + python-dateutil<\/code>\u3002<\/li>\n\n\n<li>\u6700\u9670\u7684\u5751\uff08\u5169\u7248\u90fd\u8981\u9762\u5c0d\uff09\uff1a<code>AssistantMessage.usage<\/code> \u7684 <code>output_tokens<\/code> <strong>\u6046\u70ba 1<\/strong>\uff08streaming <code>message_start<\/code> \u7684 stub \u503c\uff09\uff0c\u6e96\u78ba\u7e3d\u91cf\u53ea\u5728 <code>ResultMessage.usage<\/code>\u3002\u5b98\u65b9\u7248\u8ddf\u6211\u7684\u89e3\u6cd5\u4e00\u81f4\uff1a\u6e96\u78ba\u503c\u653e root span\u3002<\/li>\n\n\n<li><strong>\u6211\u7684\u6700\u7d42\u9078\u64c7<\/strong>\uff1a\u5b98\u65b9 autolog \u7576\u57fa\u5e95 + <code>finalize_turn_trace()<\/code> \u88dc\u4e01\u5c64\uff08\u88dc chat_id\u3001\u6bcf\u56de\u5408\u6210\u672c\u3001\u9010\u6a21\u578b\u7528\u91cf\uff09\u3002\u7406\u7531\uff1a\u8ddf\u8457\u5b98\u65b9\u6f14\u9032\u3001\u81ea\u5df1\u53ea\u7dad\u8b77 30 \u884c\u3002<\/li>\n\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">\u9019\u6b21\u7528\u5230\u7684\u5de5\u5177\u7d44<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">1. MLflow \u5b98\u65b9 Claude Code skills<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">MLflow \u51fa\u4e86\u4e00\u7d44 Claude Code skills\uff08\u88dd\u5728 <code>~\/.claude\/skills\/<\/code>\uff09\uff0c\u9019\u6b21\u4e3b\u8981\u7528\u5169\u500b\uff1a<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n\n<li><strong><code>instrumenting-with-mlflow-tracing<\/code><\/strong>\uff1atracing \u7684\u65b9\u6cd5\u8ad6\u2014\u2014\u4ec0\u9ebc\u8a72 trace\uff08root \u64cd\u4f5c\u3001LLM \u547c\u53eb\u3001\u5de5\u5177\u547c\u53eb\uff09\u3001\u4ec0\u9ebc\u4e0d\u8a72\uff08\u7d14\u8cc7\u6599\u8f49\u63db\u3001\u5b57\u4e32\u8655\u7406\uff09\uff0c\u4e09\u7a2e\u624b\u6cd5\uff08autolog \/ decorator \/ manual span\uff09\u600e\u9ebc\u9078\uff0c\u4ee5\u53ca\u6700\u91cd\u8981\u7684\uff1a<strong>\u88dd\u5b8c\u4e00\u5b9a\u8981\u8dd1\u771f\u6d41\u91cf\u9a57\u8b49<\/strong> <code>search_traces()<\/code> \u67e5\u5f97\u5230\u3001span \u4e0d\u662f\u7a7a\u6bbc\u3002<\/li>\n\n\n<li><strong><code>agent-evaluation<\/code><\/strong>\uff08\u9019\u6b21\u9084\u6c92\u7528\u5230\uff0c\u4e0b\u4e00\u6b65\uff09\uff1a\u63a5\u5728 tracing \u4e4b\u4e0a\u505a LLM-as-judge \u54c1\u8cea\u8a55\u4f30\u3002<\/li>\n\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">\u53e6\u5916\u642d\u914d <strong><code>agent-sdk-py<\/code><\/strong> skill\uff1a\u5b83\u7684\u7b2c\u4e00\u689d\u898f\u5247\u662f\u300c\u4e0d\u8981\u6191\u8a18\u61b6\u5beb Agent SDK \u7684 API\u300d\u2014\u2014\u9019\u500b SDK \u5f9e <code>claude-code-sdk<\/code> \u6539\u540d\u6210 <code>claude-agent-sdk<\/code> \u4e4b\u5f8c API \u4e00\u76f4\u5728\u52d5\uff0cskill \u9644\u4e86\u4e00\u652f introspection \u8173\u672c\u76f4\u63a5 dump \u7576\u524d\u5b89\u88dd\u7248\u672c\u7684\u771f\u5be6 API \u8868\u9762\uff1a<\/p>\n\n\n<div class=\"cbc-code-wrapper\"><div class=\"cbc-code-bar\"><button class=\"cbc-copy-button\">Copy<\/button><\/div><pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">python scripts\/sdk_surface.py\n<span class=\"hljs-comment\"># claude-agent-sdk == 0.2.104<\/span>\n<span class=\"hljs-comment\"># ResultMessage -&gt; &#91;'subtype', 'duration_ms', 'duration_api_ms', 'is_error',<\/span>\n<span class=\"hljs-comment\">#   'num_turns', 'session_id', 'stop_reason', 'total_cost_usd', 'usage',<\/span>\n<span class=\"hljs-comment\">#   'result', 'structured_output', 'model_usage', ...]<\/span>\n<span class=\"hljs-comment\"># AssistantMessage -&gt; &#91;'content', 'model', 'parent_tool_use_id', 'error',<\/span>\n<span class=\"hljs-comment\">#   'usage', 'message_id', 'stop_reason', ...]<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">\u9019\u4e00\u6b65\u7b49\u65bc\u628a\u300c\u8a0a\u606f\u6d41\u88e1\u5230\u5e95\u6709\u4ec0\u9ebc\u6599\u53ef\u4ee5\u9032 trace\u300d\u5148\u76e4\u9ede\u6e05\u695a\u2014\u2014<code>parent_tool_use_id<\/code> \u548c <code>model_usage<\/code> \u9019\u5169\u500b\u6b04\u4f4d\u5c31\u662f\u9019\u6a23\u6316\u51fa\u4f86\u7684\uff0c\u5f8c\u9762\u90fd\u6d3e\u4e0a\u7528\u5834\u3002<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">2. MLflow MCP server<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">MLflow 3.5+ \u5167\u5efa MCP server\uff0c\u5728 Claude Code \u7684\u8a2d\u5b9a\u88e1\u8a3b\u518a\u4e00\u689d\u5c31\u80fd\u7528\uff1a<\/p>\n\n\n<div class=\"cbc-code-wrapper\"><div class=\"cbc-code-bar\"><button class=\"cbc-copy-button\">Copy<\/button><\/div><pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"JSON \/ JSON with Comments\" data-shcb-language-slug=\"json\"><span><code class=\"hljs language-json\">{\n  <span class=\"hljs-attr\">\"mlflow-mcp\"<\/span>: {\n    <span class=\"hljs-attr\">\"type\"<\/span>: <span class=\"hljs-string\">\"stdio\"<\/span>,\n    <span class=\"hljs-attr\">\"command\"<\/span>: <span class=\"hljs-string\">\"uv\"<\/span>,\n    <span class=\"hljs-attr\">\"args\"<\/span>: &#91;<span class=\"hljs-string\">\"run\"<\/span>, <span class=\"hljs-string\">\"--with\"<\/span>, <span class=\"hljs-string\">\"mlflow&#91;mcp]&gt;=3.5.1\"<\/span>, <span class=\"hljs-string\">\"mlflow\"<\/span>, <span class=\"hljs-string\">\"mcp\"<\/span>, <span class=\"hljs-string\">\"run\"<\/span>],\n    <span class=\"hljs-attr\">\"env\"<\/span>: { <span class=\"hljs-attr\">\"MLFLOW_TRACKING_URI\"<\/span>: <span class=\"hljs-string\">\"http:\/\/your-mlflow-server:5000\"<\/span> }\n  }\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JSON \/ JSON with Comments<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">json<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">\u88dd\u597d\u4e4b\u5f8c Claude \u5c31\u591a\u4e86\u4e00\u6392 <code>mcp__mlflow-mcp__*<\/code> \u5de5\u5177\uff1a<code>search_traces<\/code>\u3001<code>get_trace<\/code>\u3001<code>create_experiment<\/code>\u3001<code>log_trace_feedback<\/code>\u3001<code>register_llm_judge_scorer<\/code>\u22ef\u22ef\u3002\u5e73\u5e38\u300c\u5e6b\u6211\u770b\u6628\u5929\u6700\u6162\u7684 trace \u5728\u5e79\u561b\u300d\u9019\u7a2e\u8a71\uff0cClaude \u53ef\u4ee5\u76f4\u63a5\u67e5 server \u56de\u7b54\uff0c\u4e0d\u7528\u81ea\u5df1\u5beb\u67e5\u8a62\u8173\u672c\u3002<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u9806\u5e36\u4e00\u63d0\uff0c\u9019\u6b21\u7684 tracking URI \u5c31\u662f\u5f9e\u9019\u4efd MCP \u8a2d\u5b9a\u88e1\u7ffb\u51fa\u4f86\u7684\u2014\u2014\u672c\u6a5f <code>localhost:5000<\/code> \u6709\u4e00\u53f0 MLflow \u662f\u8dd1\u5728\u5bb9\u5668\u88e1\u7684\u3001\u5bbf\u4e3b\u6839\u672c\u9023\u4e0d\u5230\uff08\u5751 3\uff0c\u5f8c\u8ff0\uff09\u3002<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">\u5b98\u65b9 autolog\uff1a\u771f\u7684\u80fd\u7528\uff08\u66f4\u6b63\u521d\u7248\u8aaa\u6cd5\uff09<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">\u555f\u7528\u53ea\u8981\u5169\u884c\uff0c\u4f46\u5fc5\u9808\u5728<strong>\u5efa\u7acb <code>ClaudeSDKClient<\/code> \u4e4b\u524d<\/strong>\u547c\u53eb\uff1a<\/p>\n\n\n<div class=\"cbc-code-wrapper\"><div class=\"cbc-code-bar\"><button class=\"cbc-copy-button\">Copy<\/button><\/div><pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">import mlflow\nimport mlflow.anthropic\n\nmlflow.set_experiment(<span class=\"hljs-string\">\"my_claude_app\"<\/span>)\nmlflow.anthropic.autolog()   <span class=\"hljs-comment\"># \u5fc5\u9808\u5728 ClaudeSDKClient \u5efa\u7acb\u4e4b\u524d<\/span>\n\nclient = ClaudeSDKClient(options=...)  <span class=\"hljs-comment\"># \u4e4b\u5f8c\u7167\u5e38\u7528<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">\u7ffb <code>mlflow\/anthropic\/__init__.py<\/code> \u770b\u5b83\u5230\u5e95 patch \u4e86\u4ec0\u9ebc\uff1a<\/p>\n\n\n<div class=\"cbc-code-wrapper\"><div class=\"cbc-code-bar\"><button class=\"cbc-copy-button\">Copy<\/button><\/div><pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\"><span class=\"hljs-comment\"># mlflow\/anthropic\/__init__.py\uff08\u7bc0\u9304\uff09<\/span>\ndef autolog(...):\n    from anthropic.resources import AsyncMessages, Messages   <span class=\"hljs-comment\"># \u2190 \u786c\u4f9d\u8cf4 anthropic \u5957\u4ef6\uff01<\/span>\n\n    safe_patch(FLAVOR_NAME, Messages, <span class=\"hljs-string\">\"create\"<\/span>, patched_class_call)\n    safe_patch(FLAVOR_NAME, AsyncMessages, <span class=\"hljs-string\">\"create\"<\/span>, async_patched_class_call)\n\n    <span class=\"hljs-comment\"># Patch Claude Code SDK if available<\/span>\n    <span class=\"hljs-keyword\">try<\/span>:\n        from claude_agent_sdk import ClaudeSDKClient\n        safe_patch(FLAVOR_NAME, ClaudeSDKClient, <span class=\"hljs-string\">\"__init__\"<\/span>, patched_claude_sdk_init)\n    except ImportError:\n        ...\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\"><code>patched_claude_sdk_init<\/code> \u505a\u7684\u4e8b\uff1awrap <code>query()<\/code> \u6355\u6349 user prompt\u3001wrap <code>receive_response()<\/code> \u628a yield \u51fa\u4f86\u7684\u6bcf\u5247\u8a0a\u606f<strong>\u7d2f\u7a4d\u5230 list<\/strong>\uff0c\u7b49\u6574\u500b async for \u8fed\u4ee3\u7d50\u675f\uff0c\u547c\u53eb <code>mlflow.claude_code.tracing.process_sdk_messages(messages)<\/code>\u2014\u2014<strong>\u4e8b\u5f8c<\/strong>\u628a\u6574\u4e32\u8a0a\u606f\u91cd\u5efa\u6210\u4e00\u689d trace\u3002<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u62ff\u5b83\u5be6\u6e2c\u8dd1\u4e00\u8f2a\uff08Haiku + \u4e00\u500b Bash \u5de5\u5177\u547c\u53eb\uff09\uff0c\u7522\u51fa\u7684 trace \u9577\u9019\u6a23\uff1a<\/p>\n\n\n<div class=\"cbc-code-wrapper\"><div class=\"cbc-code-bar\"><button class=\"cbc-copy-button\">Copy<\/button><\/div><pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">claude_code_conversation (AGENT)   \u2190 root\uff0cusage \u5b8c\u6574\uff08\u4f86\u81ea ResultMessage\uff09\n\u251c\u2500\u2500 tool_Bash (TOOL)               duration = <span class=\"hljs-number\">0.1<\/span> ms\uff08\u5047\u7684\uff0c\u5be6\u969b\u8dd1\u4e86\u5e7e\u79d2\uff09\n\u2514\u2500\u2500 llm (LLM)                      duration = <span class=\"hljs-number\">0.1<\/span> ms\uff08name \u56fa\u5b9a\u53eb <span class=\"hljs-string\">\"llm\"<\/span>\uff09\n\n<span class=\"hljs-attr\">metadata<\/span>: mlflow.trace.session = CLI \u5167\u90e8 session id\n          mlflow.trace.user    = OS \u4f7f\u7528\u8005\u540d\n<span class=\"hljs-attr\">token_usage<\/span>: {<span class=\"hljs-string\">'input_tokens'<\/span>: <span class=\"hljs-number\">18<\/span>, <span class=\"hljs-string\">'output_tokens'<\/span>: <span class=\"hljs-number\">210<\/span>,\n              <span class=\"hljs-string\">'cache_read_input_tokens'<\/span>: <span class=\"hljs-number\">18767<\/span>, <span class=\"hljs-string\">'cache_creation_input_tokens'<\/span>: <span class=\"hljs-number\">18944<\/span>}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">\u80fd\u7528\u3001token \u6e96\u78ba\u3001prompt\/\u56de\u8986\/\u5de5\u5177\u8f38\u5165\u8f38\u51fa\u90fd\u5728\u3002<strong>\u4f46\u6ce8\u610f duration<\/strong>\u2014\u2014\u6240\u6709 child span \u90fd\u662f\u8fed\u4ee3\u7d50\u675f\u90a3\u4e00\u77ac\u9593\u300c\u88dc\u5efa\u300d\u7684\uff0c\u6642\u9577\u5168\u90e8 ~0ms\u3002\u53e6\u5916\u5b98\u65b9\u6587\u4ef6\u660e\u8b1b\uff1a<strong>\u53ea\u652f\u63f4 <code>ClaudeSDKClient<\/code>\uff0c\u76f4\u63a5\u547c\u53eb <code>query()<\/code> \u7684\u4e0d\u6703\u88ab trace<\/strong>\uff1b\u9084\u6709\u4e00\u500b\u5be6\u6e2c\u767c\u73fe\uff1a<strong>\u56de\u5408\u4e2d\u9014\u70b8\u6389\uff08\u4f8b\u5916\u628a\u8fed\u4ee3\u6253\u65b7\uff09\u7684\u8a71\uff0c\u6574\u689d trace \u90fd\u4e0d\u6703\u5efa<\/strong>\u2014\u2014\u5b98\u65b9\u53ea\u8a18\u300c\u8dd1\u5b8c\u7684\u56de\u5408\u300d\u3002<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">\u5b98\u65b9\u7248 vs \u624b\u52d5\u7248\uff1a\u5be6\u6e2c\u5c0d\u6bd4<\/h2>\n\n\n\n<figure class=\"wp-block-table\"><table>\n<thead>\n<tr>\n<th>\u9762\u5411<\/th>\n<th>\u5b98\u65b9 <code>autolog()<\/code><\/th>\n<th>\u624b\u52d5 <code>TurnTrace<\/code>\uff08\u4e0b\u6587\u5be6\u4f5c\uff09<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>\u555f\u7528\u6210\u672c<\/td>\n<td>2 \u884c<\/td>\n<td>~200 \u884c<\/td>\n<\/tr>\n<tr>\n<td>\u4f9d\u8cf4<\/td>\n<td><code>mlflow-skinny<\/code>\uff08\u6216\u5b8c\u6574\u7248\uff09+ <code>anthropic<\/code><\/td>\n<td>\u8f15\u91cf <code>mlflow-tracing<\/code> \u5373\u53ef<\/td>\n<\/tr>\n<tr>\n<td>span \u5efa\u7acb\u6642\u6a5f<\/td>\n<td>\u56de\u5408\u7d50\u675f\u5f8c\u4e00\u53e3\u6c23\u88dc\u5efa<\/td>\n<td>\u908a\u6536\u8a0a\u606f\u908a\u958b\u95dc<\/td>\n<\/tr>\n<tr>\n<td><strong>\u5de5\u5177 span \u6642\u9577<\/strong><\/td>\n<td><strong>\u5168\u90e8 ~0ms\uff08\u5047\u7684\uff09<\/strong><\/td>\n<td>\u771f\u5be6 wall-time\uff08\u770b\u5f97\u51fa\u54ea\u500b\u5de5\u5177\u5361 45 \u79d2\uff09<\/td>\n<\/tr>\n<tr>\n<td>LLM span<\/td>\n<td>\u53ea\u6709\u300c\u7d14\u6587\u5b57\u3001\u7121\u5de5\u5177\u547c\u53eb\u300d\u7684\u6b65\u9a5f\u624d\u5efa\uff0cname \u56fa\u5b9a <code>llm<\/code><\/td>\n<td>\u6bcf\u500b assistant \u6b65\u9a5f\u4e00\u500b\uff0cname = model \u540d<\/td>\n<\/tr>\n<tr>\n<td><strong>\u6210\u672c<\/strong><\/td>\n<td>\u7121 \u2192 <strong>\u53ef\u7528 tag \u88dc<\/strong>\uff08\u898b\u6700\u7d42\u843d\u5730\uff09<\/td>\n<td>root span \u5e36 <code>total_cost_usd<\/code> + \u9010\u6a21\u578b <code>model_usage<\/code><\/td>\n<\/tr>\n<tr>\n<td><strong>\u5b50\u4ee3\u7406<\/strong><\/td>\n<td><strong>\u4e0d\u5de2\u72c0<\/strong>\uff08\u539f\u59cb\u78bc\u5b8c\u5168\u6c92\u78b0 <code>parent_tool_use_id<\/code>\uff09\uff0c\u88dc\u4e0d\u4e86<\/td>\n<td>\u9760 <code>parent_tool_use_id<\/code> \u5de2\u72c0\u6210\u6a39<\/td>\n<\/tr>\n<tr>\n<td>session \u5206\u7d44<\/td>\n<td>CLI \u5167\u90e8 session id \u2192 chat id <strong>\u53ef\u7528 tag \u88dc<\/strong><\/td>\n<td>\u81ea\u8a02\uff08chat_id \u9032 <code>mlflow.trace.session<\/code>\uff09<\/td>\n<\/tr>\n<tr>\n<td>\u7570\u5e38\u4e2d\u65b7\u7684\u56de\u5408<\/td>\n<td><strong>\u4e0d\u8a18 trace<\/strong><\/td>\n<td>\u8a18\uff08status=ERROR + \u932f\u8aa4\u8a0a\u606f\uff09<\/td>\n<\/tr>\n<tr>\n<td>token \u7e3d\u91cf<\/td>\n<td>ResultMessage.usage \u653e root\uff08\u6b63\u78ba\uff09<\/td>\n<td>\u540c\uff08\u6211\u8e29\u5b8c\u5751 1 \u624d\u8ddf\u5b98\u65b9\u6b8a\u9014\u540c\u6b78\uff09<\/td>\n<\/tr>\n<tr>\n<td><code>query()<\/code> \u55ae\u767c\u6a21\u5f0f<\/td>\n<td>\u4e0d\u652f\u63f4<\/td>\n<td>\u8a0a\u606f\u8ff4\u5708\u5728\u54ea\u90fd\u80fd\u639b<\/td>\n<\/tr>\n<tr>\n<td>\u7dad\u8b77<\/td>\n<td>\u5b98\u65b9\u6f14\u9032\uff0c\u5347\u7d1a\u8ddf\u8457\u8d70<\/td>\n<td>\u81ea\u5df1\u625b\uff08SDK \u8a0a\u606f\u683c\u5f0f\u8b8a\u4e86\u8981\u8ddf\uff09<\/td>\n<\/tr>\n<\/tbody>\n<\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>\u600e\u9ebc\u9078<\/strong>\uff1a\u770b\u4f60\u7f3a\u7684\u6771\u897f\u662f\u300c\u53ef\u88dc\u7684\u300d\u9084\u662f\u300c\u88dc\u4e0d\u4e86\u7684\u300d\u3002cost\u3001\u81ea\u5df1\u7684 session id\u2014\u2014tag \u88dc\u4e01 30 \u884c\u641e\u5b9a\uff0c<strong>\u9078\u5b98\u65b9<\/strong>\uff1b\u4e00\u5b9a\u8981\u771f\u5be6\u6642\u9577\u3001\u5b50\u4ee3\u7406\u6a39\u3001\u7570\u5e38\u56de\u5408\u4e5f\u8981\u6709 trace\u2014\u2014<strong>\u53ea\u80fd\u5168\u624b\u52d5<\/strong>\u3002\u6211\u4e00\u958b\u59cb\u5beb\u4e86\u5168\u624b\u52d5\u7248\uff08\u4e0b\u6587\u5b8c\u6574\u4fdd\u7559\uff09\uff0c\u60f3\u6e05\u695a\u4e4b\u5f8c\u628a\u751f\u7522\u74b0\u5883\u5207\u5230\u300c\u5b98\u65b9 + \u88dc\u4e01\u300d\uff1aagent \u9664\u932f\u6642 90% \u7684\u554f\u984c\u770b\u6d41\u7a0b\u548c\u6210\u672c\u5c31\u5920\u4e86\uff0c\u6642\u9577\u548c\u5de2\u72c0\u662f nice-to-have\uff0c\u63db\u5b98\u65b9\u6f14\u9032 + 30 \u884c\u7dad\u8b77\u9762\uff0c\u5212\u7b97\u3002<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">\u6700\u7d42\u843d\u5730\uff1a\u5b98\u65b9 autolog + 30 \u884c\u88dc\u4e01\u5c64<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">\u4f9d\u8cf4\uff1a\u4e09\u500b\u5957\u4ef6\u7684\u5dee\u7570\u5148\u641e\u6e05\u695a<\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table>\n<thead>\n<tr>\n<th>\u5957\u4ef6<\/th>\n<th><code>mlflow.anthropic<\/code><\/th>\n<th><code>mlflow.claude_code<\/code><\/th>\n<th>\u5927\u5c0f<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>mlflow<\/code>\uff08\u5b8c\u6574\u7248\uff09<\/td>\n<td>\u2705<\/td>\n<td>\u2705<\/td>\n<td>\u6700\u91cd\uff08server\/UI \u5168\u5bb6\u6876\uff09<\/td>\n<\/tr>\n<tr>\n<td><code>mlflow-skinny<\/code><\/td>\n<td>\u2705<\/td>\n<td>\u2705\uff08<strong>\u7f3a <code>python-dateutil<\/code> \u8981\u81ea\u5df1\u88dc<\/strong>\uff09<\/td>\n<td>\u4e2d<\/td>\n<\/tr>\n<tr>\n<td><code>mlflow-tracing<\/code><\/td>\n<td>\u2705\uff08\u4f46\u6703\u70b8\uff0c\u898b\u5751 2\uff09<\/td>\n<td>\u274c<\/td>\n<td>\u6700\u8f15<\/td>\n<\/tr>\n<\/tbody>\n<\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">\u6700\u5c0f\u53ef\u7528\u7d44\u5408\uff1a<\/p>\n\n\n<div class=\"cbc-code-wrapper\"><div class=\"cbc-code-bar\"><button class=\"cbc-copy-button\">Copy<\/button><\/div><pre class=\"wp-block-code\"><span><code class=\"hljs\">uv add mlflow-skinny anthropic python-dateutil\n<\/code><\/span><\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\"><code>anthropic<\/code> \u7d14\u7cb9\u662f\u8b93 <code>autolog()<\/code> \u7b2c\u4e00\u884c\u7684 import \u4e0d\u70b8\uff08Agent SDK \u672c\u8eab\u4e0d\u9700\u8981\u5b83\uff09\uff1b<code>python-dateutil<\/code> \u662f <code>mlflow.claude_code<\/code> \u7684\u96b1\u85cf\u4f9d\u8cf4\uff0cskinny \u6c92\u5e36\u3002<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">setup\uff1a\u555f\u52d5\u6642\u958b autolog<\/h3>\n\n\n<div class=\"cbc-code-wrapper\"><div class=\"cbc-code-bar\"><button class=\"cbc-copy-button\">Copy<\/button><\/div><pre class=\"wp-block-code\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\"><span class=\"hljs-string\">\"\"<\/span><span class=\"hljs-string\">\"MLflow tracing via the official integration + a patch layer for what it misses.\"<\/span><span class=\"hljs-string\">\"\"<\/span>\n\nimport asyncio\nimport json\nimport logging\nimport os\n\nimport mlflow\nimport mlflow.anthropic\nfrom claude_agent_sdk import ResultMessage\nfrom mlflow.tracing.constant import TraceMetadataKey\n\nlogger = logging.getLogger(__name__)\n\n_enabled = <span class=\"hljs-keyword\">False<\/span>\n\ndef setup_tracing() -&gt; bool:\n    <span class=\"hljs-string\">\"\"<\/span><span class=\"hljs-string\">\"App \u555f\u52d5\u6642\uff08dotenv \u4e4b\u5f8c\u3001\u4efb\u4f55 ClaudeSDKClient \u5efa\u7acb\u4e4b\u524d\uff09\u547c\u53eb\u4e00\u6b21\u3002\"<\/span><span class=\"hljs-string\">\"\"<\/span>\n    <span class=\"hljs-keyword\">global<\/span> _enabled\n    uri = os.environ.get(<span class=\"hljs-string\">\"MLFLOW_TRACKING_URI\"<\/span>)\n    <span class=\"hljs-keyword\">if<\/span> not uri:\n        logger.info(<span class=\"hljs-string\">\"MLflow tracing disabled (MLFLOW_TRACKING_URI not set)\"<\/span>)\n        <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-keyword\">False<\/span>\n    <span class=\"hljs-keyword\">try<\/span>:\n        mlflow.set_tracking_uri(uri)\n        mlflow.set_experiment(os.environ.get(<span class=\"hljs-string\">\"MLFLOW_EXPERIMENT_NAME\"<\/span>, <span class=\"hljs-string\">\"chatapp\"<\/span>))\n        mlflow.anthropic.autolog()   <span class=\"hljs-comment\"># patch ClaudeSDKClient.__init__<\/span>\n        _enabled = <span class=\"hljs-keyword\">True<\/span>\n        logger.info(<span class=\"hljs-string\">\"MLflow tracing enabled (official autolog) -&gt; %s\"<\/span>, uri)\n    except <span class=\"hljs-keyword\">Exception<\/span> <span class=\"hljs-keyword\">as<\/span> error:\n        logger.warning(<span class=\"hljs-string\">\"MLflow tracing disabled (server unreachable?): %s\"<\/span>, error)\n        _enabled = <span class=\"hljs-keyword\">False<\/span>\n    <span class=\"hljs-keyword\">return<\/span> _enabled\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre><\/div>\n\n\n<h3 class=\"wp-block-heading\">\u88dc\u4e01\u5c64\uff1aturn \u7d50\u675f\u5f8c\u88dc tag<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">\u5b98\u65b9 trace \u7f3a cost \u548c\u81ea\u5df1\u7684 chat id\u2014\u2014\u597d\u6d88\u606f\u662f trace \u5efa\u5b8c\u4e4b\u5f8c\u53ef\u4ee5\u7528 <code>set_trace_tag<\/code> \u88dc\u3002\u4e09\u500b\u7d30\u7bc0\uff1a<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n\n<li><strong>\u6642\u6a5f<\/strong>\uff1aautolog \u7684 trace \u662f\u5728 <code>receive_response()<\/code> \u8fed\u4ee3\u300c\u5b8c\u5168\u8017\u76e1\u300d\u90a3\u4e00\u523b\u5efa\u7684\u2014\u2014\u88dc\u4e01\u5fc5\u9808\u5728 async for \u8ff4\u5708<strong>\u9000\u51fa\u4e4b\u5f8c<\/strong>\u624d\u547c\u53eb\uff08\u8ff4\u5708\u88e1\u8655\u7406 <code>ResultMessage<\/code> \u6642 trace \u9084\u4e0d\u5b58\u5728\uff0c\u5148\u628a result \u5b58\u8d77\u4f86\uff09\u3002<\/li>\n\n\n<li><strong>flush<\/strong>\uff1atrace \u8d70 async export queue\uff0c<code>set_trace_tag<\/code> \u6253\u7684\u662f server\u2014\u2014\u8981\u5148 <code>flush_trace_async_logging()<\/code> \u7b49\u5b83\u4e0a\u53bb\uff0c\u4e0d\u7136 tag \u6703\u843d\u7a7a\u3002<\/li>\n\n\n<li><strong>\u7af6\u614b<\/strong>\uff1a<code>get_last_active_trace_id()<\/code> \u62ff\u7684\u662f\u300c\u672c\u884c\u7a0b\u6700\u5f8c\u4e00\u689d trace\u300d\u2014\u2014\u591a\u500b\u804a\u5929\u4e26\u884c\u6642\u53ef\u80fd\u6436\u5230\u5225\u4eba\u7684\u3002\u5b98\u65b9 trace \u7684 metadata \u5e36 CLI session id\uff0c\u6bd4\u5c0d\u4e00\u4e0b\u518d tag\u3002<\/li>\n\n<\/ol>\n\n\n<div class=\"cbc-code-wrapper\"><div class=\"cbc-code-bar\"><button class=\"cbc-copy-button\">Copy<\/button><\/div><pre class=\"wp-block-code\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">async def finalize_turn_trace(\n    chat_id: str,\n    cli_session_id: str | None,\n    result: ResultMessage | None,\n    turn_cost: float,\n    interrupted: bool = <span class=\"hljs-keyword\">False<\/span>,\n) -&gt; None:\n    <span class=\"hljs-string\">\"\"<\/span><span class=\"hljs-string\">\"\u5e6b autolog \u525b\u5beb\u5b8c\u7684 trace \u88dc\u4e0a\u5b83\u4e0d\u8a18\u7684\u6771\u897f\u3002best-effort\u3001\u7d55\u4e0d\u62cb\u932f\u3002\"<\/span><span class=\"hljs-string\">\"\"<\/span>\n    <span class=\"hljs-keyword\">if<\/span> not _enabled <span class=\"hljs-keyword\">or<\/span> result is None:\n        <span class=\"hljs-keyword\">return<\/span>\n    <span class=\"hljs-keyword\">try<\/span>:\n        await asyncio.to_thread(   <span class=\"hljs-comment\"># \u7db2\u8def\u64cd\u4f5c\u4e1f thread\uff0c\u4e0d\u5361 event loop<\/span>\n            _finalize_sync, chat_id, cli_session_id, result, turn_cost, interrupted\n        )\n    except <span class=\"hljs-keyword\">Exception<\/span>:\n        logger.debug(<span class=\"hljs-string\">\"trace finalize failed\"<\/span>, exc_info=<span class=\"hljs-keyword\">True<\/span>)\n\ndef _finalize_sync(chat_id, cli_session_id, result, turn_cost, interrupted):\n    mlflow.flush_trace_async_logging()          <span class=\"hljs-comment\"># \u7b49 trace \u771f\u7684\u4e0a\u4e86 server<\/span>\n    trace_id = mlflow.get_last_active_trace_id()\n    <span class=\"hljs-keyword\">if<\/span> not trace_id:\n        <span class=\"hljs-keyword\">return<\/span>\n    <span class=\"hljs-comment\"># \u591a\u804a\u5929\u4e26\u884c\u9632\u6436\u932f\uff1a\u5b98\u65b9 trace \u7684 session = CLI session id<\/span>\n    metadata = mlflow.get_trace(trace_id).info.trace_metadata <span class=\"hljs-keyword\">or<\/span> {}\n    trace_session = metadata.get(TraceMetadataKey.TRACE_SESSION)\n    <span class=\"hljs-keyword\">if<\/span> cli_session_id <span class=\"hljs-keyword\">and<\/span> trace_session <span class=\"hljs-keyword\">and<\/span> trace_session != cli_session_id:\n        <span class=\"hljs-keyword\">return<\/span>                                   <span class=\"hljs-comment\"># \u4e0d\u662f\u6211\u9019\u8f2a\u7684\uff0c\u653e\u624b<\/span>\n    tags = {<span class=\"hljs-string\">\"chat_id\"<\/span>: chat_id, <span class=\"hljs-string\">\"turn_cost_usd\"<\/span>: f<span class=\"hljs-string\">\"{turn_cost:.6f}\"<\/span>}\n    <span class=\"hljs-keyword\">if<\/span> result.total_cost_usd:\n        tags&#91;<span class=\"hljs-string\">\"cli_total_cost_usd\"<\/span>] = f<span class=\"hljs-string\">\"{result.total_cost_usd:.6f}\"<\/span>\n    <span class=\"hljs-keyword\">if<\/span> result.num_turns is not None:\n        tags&#91;<span class=\"hljs-string\">\"num_turns\"<\/span>] = str(result.num_turns)\n    <span class=\"hljs-keyword\">if<\/span> result.model_usage:\n        tags&#91;<span class=\"hljs-string\">\"model_usage\"<\/span>] = json.dumps(result.model_usage, ensure_ascii=<span class=\"hljs-keyword\">False<\/span>)&#91;:<span class=\"hljs-number\">4000<\/span>]\n    <span class=\"hljs-keyword\">if<\/span> interrupted:\n        tags&#91;<span class=\"hljs-string\">\"interrupted\"<\/span>] = <span class=\"hljs-string\">\"true\"<\/span>\n    <span class=\"hljs-keyword\">for<\/span> key, value in tags.items():\n        mlflow.set_trace_tag(trace_id, key, value)\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre><\/div>\n\n\n<h3 class=\"wp-block-heading\">\u639b\u9032\u56de\u5408\u8ff4\u5708<\/h3>\n\n\n<div class=\"cbc-code-wrapper\"><div class=\"cbc-code-bar\"><button class=\"cbc-copy-button\">Copy<\/button><\/div><pre class=\"wp-block-code\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">async with <span class=\"hljs-keyword\">self<\/span>._turn_lock:\n    <span class=\"hljs-keyword\">self<\/span>._last_result = None       <span class=\"hljs-comment\"># \u8ff4\u5708\u88e1\u6536\u5230 ResultMessage \u6642\u5b58\u8d77\u4f86<\/span>\n    <span class=\"hljs-keyword\">self<\/span>._last_turn_cost = <span class=\"hljs-number\">0.0<\/span>\n    <span class=\"hljs-keyword\">try<\/span>:\n        await <span class=\"hljs-keyword\">self<\/span>.agent.client.query(prompt)\n        async <span class=\"hljs-keyword\">for<\/span> message in <span class=\"hljs-keyword\">self<\/span>.agent.client.receive_response():\n            await <span class=\"hljs-keyword\">self<\/span>._handle_sdk_message(message)   <span class=\"hljs-comment\"># \u9019\u88e1\u9762\u5b58 _last_result<\/span>\n        <span class=\"hljs-comment\"># \u2191 \u8fed\u4ee3\u7d50\u675f\u7684\u77ac\u9593 autolog \u5efa\u597d trace \u2014\u2014 \u73fe\u5728\u624d\u80fd\u88dc tag<\/span>\n        await finalize_turn_trace(\n            chat_id=<span class=\"hljs-keyword\">self<\/span>.chat_id,\n            cli_session_id=<span class=\"hljs-keyword\">self<\/span>._session_id,\n            result=<span class=\"hljs-keyword\">self<\/span>._last_result,\n            turn_cost=<span class=\"hljs-keyword\">self<\/span>._last_turn_cost,\n        )\n    except <span class=\"hljs-keyword\">Exception<\/span> <span class=\"hljs-keyword\">as<\/span> error:\n        ...   <span class=\"hljs-comment\"># \u7570\u5e38\u56de\u5408\u5b98\u65b9\u4e0d\u8a18 trace\uff0c\u4e5f\u5c31\u6c92\u6771\u897f\u53ef\u88dc<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">\u5be6\u6e2c\u8dd1\u4e00\u8f2a\uff0ctrace \u4e0a\u7684 tags\uff1a<\/p>\n\n\n<div class=\"cbc-code-wrapper\"><div class=\"cbc-code-bar\"><button class=\"cbc-copy-button\">Copy<\/button><\/div><pre class=\"wp-block-code\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">tags:\n    chat_id            = <span class=\"hljs-number\">20260618<\/span><span class=\"hljs-number\">-165650<\/span>\n    turn_cost_usd      = <span class=\"hljs-number\">0.145098<\/span>\n    cli_total_cost_usd = <span class=\"hljs-number\">0.145098<\/span>\n    num_turns          = <span class=\"hljs-number\">1<\/span>\n    model_usage        = {<span class=\"hljs-string\">\"claude-haiku-4-5-...\"<\/span>: {...}, <span class=\"hljs-string\">\"claude-opus-4-8\"<\/span>: {...}}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">\u6210\u672c\u6b78\u56e0\u56de\u4f86\u4e86\u3001<code>chat_id<\/code> \u53ef\u4ee5\u641c\u4e86\uff0c\u7dad\u8b77\u9762\u53ea\u5269\u9019 30 \u884c\u3002<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">\u66ff\u4ee3\u65b9\u6848\uff1a\u5168\u624b\u52d5 TurnTrace\uff08\u8981\u771f\u5be6\u6642\u9577\uff0f\u5b50\u4ee3\u7406\u6a39\u6642\u7528\uff09<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">\u4ee5\u4e0b\u662f\u6211\u6700\u521d\u5beb\u7684\u5168\u624b\u52d5\u7248\uff0c<strong>\u5b98\u65b9\u7248\u88dc\u4e0d\u4e86\u7684\u5b83\u90fd\u6709<\/strong>\uff1a\u5de5\u5177 span \u662f\u771f\u5be6 wall-time\u3001\u5b50\u4ee3\u7406\u5de2\u72c0\u6210\u6a39\u3001\u7570\u5e38\u56de\u5408\u4e5f\u8a18 trace\u3001session \u76f4\u63a5\u7528\u81ea\u5df1\u7684 chat_id\u3002\u7528\u8f15\u91cf <code>mlflow-tracing<\/code> \u5c31\u80fd\u8dd1\u3002\u53d6\u6368\u662f ~200 \u884c\u81ea\u5df1\u7dad\u8b77\u3002<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">\u8a0a\u606f\u6d41 \u2192 span \u6a39\u7684\u6620\u5c04<\/h3>\n\n\n\n<figure class=\"wp-block-table\"><table>\n<thead>\n<tr>\n<th>SDK \u8a0a\u606f \/ \u5340\u584a<\/th>\n<th>MLflow span<\/th>\n<th>\u8aaa\u660e<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>\u6574\u500b\u56de\u5408<\/td>\n<td><code>chat_turn<\/code>\uff08AGENT, root\uff09<\/td>\n<td>inputs = \u4f7f\u7528\u8005 prompt\uff0coutputs = \u56de\u8986 + \u6210\u672c<\/td>\n<\/tr>\n<tr>\n<td><code>AssistantMessage<\/code><\/td>\n<td>LLM span<\/td>\n<td>\u8a0a\u606f\u5230\u9054\u6642\u5df2\u5b8c\u6574\uff0cspan \u5373\u958b\u5373\u95dc\uff1b\u639b model \u540d\u8207 usage<\/td>\n<\/tr>\n<tr>\n<td><code>ToolUseBlock<\/code>\uff08\u5728 AssistantMessage \u88e1\uff09<\/td>\n<td>TOOL span <strong>\u958b<\/strong><\/td>\n<td>inputs = \u5de5\u5177\u53c3\u6578<\/td>\n<\/tr>\n<tr>\n<td><code>ToolResultBlock<\/code>\uff08\u5728 UserMessage \u88e1\uff09<\/td>\n<td>TOOL span <strong>\u95dc<\/strong><\/td>\n<td>\u7528 <code>tool_use_id<\/code> \u914d\u5c0d\uff1b<code>is_error<\/code> \u6c7a\u5b9a\u7d05\u7da0<\/td>\n<\/tr>\n<tr>\n<td>\u5e36 <code>parent_tool_use_id<\/code> \u7684\u8a0a\u606f<\/td>\n<td>\u5de2\u72c0<\/td>\n<td>\u5b50\u4ee3\u7406\uff08Agent \u5de5\u5177\uff09\u5167\u7684\u4e00\u5207\u639b\u5728\u8a72 Agent TOOL span \u5e95\u4e0b<\/td>\n<\/tr>\n<tr>\n<td><code>ResultMessage<\/code><\/td>\n<td>\u95dc root span<\/td>\n<td><code>total_cost_usd<\/code>\u3001<code>num_turns<\/code>\u3001\u6e96\u78ba token \u7e3d\u91cf<\/td>\n<\/tr>\n<\/tbody>\n<\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\"><code>parent_tool_use_id<\/code> \u662f\u6574\u500b\u8a2d\u8a08\u6700\u6f02\u4eae\u7684\u4e00\u584a\uff1a\u4e3b\u7dda agent \u958b\u4e00\u500b <code>Agent<\/code> \u5de5\u5177\u53bb\u8dd1\u5b50\u4ee3\u7406\u6642\uff0c\u5b50\u4ee3\u7406\u7684\u6240\u6709\u8a0a\u606f\u90fd\u5e36\u8457\u90a3\u500b tool_use_id\u3002\u800c Agent \u5de5\u5177\u7684 TOOL span \u8981\u7b49\u5b50\u4ee3\u7406\u8dd1\u5b8c\u3001tool_result \u56de\u4f86\u624d\u6703\u95dc\u2014\u2014\u671f\u9593\u5b50\u4ee3\u7406\u7684 LLM\/TOOL span \u5168\u90e8\u81ea\u7136\u5de2\u72c0\u5728\u5b83\u5e95\u4e0b\uff0cUI \u4e0a\u5c31\u662f\u4e00\u68f5\u6f02\u4eae\u7684\u6a39\uff08\u5b98\u65b9\u7248\u6c92\u505a\u9019\u4ef6\u4e8b\uff0c\u5b50\u4ee3\u7406\u7684\u6771\u897f\u662f\u5e73\u7684\uff09\uff1a<\/p>\n\n\n<div class=\"cbc-code-wrapper\"><div class=\"cbc-code-bar\"><button class=\"cbc-copy-button\">Copy<\/button><\/div><pre class=\"wp-block-code\"><span><code class=\"hljs\">chat_turn (AGENT)\n\u251c\u2500\u2500 claude-opus-4-8 (LLM)\n\u251c\u2500\u2500 Read (TOOL)\n\u251c\u2500\u2500 Agent (TOOL)                \u2190 \u5b50\u4ee3\u7406\n\u2502   \u251c\u2500\u2500 claude-opus-4-8 (LLM)\n\u2502   \u2514\u2500\u2500 Bash (TOOL)\n\u2514\u2500\u2500 claude-opus-4-8 (LLM)\n<\/code><\/span><\/pre><\/div>\n\n\n<h3 class=\"wp-block-heading\">\u5b8c\u6574\u7a0b\u5f0f\u78bc<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">\u8a2d\u8a08\u539f\u5247\u53ea\u6709\u4e00\u689d\uff1a<strong>fail-open<\/strong>\u2014\u2014\u6c92\u8a2d <code>MLFLOW_TRACKING_URI<\/code> \u5c31\u6574\u500b\u95dc\u9589\u3001server \u639b\u4e86\u5c31\u555f\u52d5\u6642\u964d\u7d1a\u3001observe\/close \u5168\u90e8\u541e\u4f8b\u5916\u3002\u76e3\u63a7\u6c38\u9060\u4e0d\u51c6\u5f04\u58de\u804a\u5929\u672c\u9ad4\u3002<\/p>\n\n\n<div class=\"cbc-code-wrapper\"><div class=\"cbc-code-bar\"><button class=\"cbc-copy-button\">Copy<\/button><\/div><pre class=\"wp-block-code\"><span><code class=\"hljs\">\"\"\"MLflow tracing: one chat turn = one trace, built from the SDK message stream.\"\"\"\n\nimport logging\nimport os\nfrom typing import Any\n\nimport mlflow\nfrom claude_agent_sdk import (\n    AssistantMessage,\n    ResultMessage,\n    TextBlock,\n    ThinkingBlock,\n    ToolResultBlock,\n    ToolUseBlock,\n    UserMessage,\n)\nfrom mlflow.entities import SpanType\nfrom mlflow.tracing.constant import SpanAttributeKey, TraceMetadataKey\n\nlogger = logging.getLogger(__name__)\n\n_TRUNCATE_CHARS = 4000  # \u5de5\u5177\u8f38\u51fa\u53ef\u80fd\u662f\u6574\u5305\u6a94\u6848\uff0c\u780d\u6389\u514d\u5f97\u704c\u7206 trace store\n_enabled = False\n\ndef setup_tracing() -&gt; bool:\n    \"\"\"\u6307\u5411 tracking server\u3002App \u555f\u52d5\u6642\uff08dotenv \u4e4b\u5f8c\uff09\u547c\u53eb\u4e00\u6b21\u3002\"\"\"\n    global _enabled\n    uri = os.environ.get(\"MLFLOW_TRACKING_URI\")\n    if not uri:\n        logger.info(\"MLflow tracing disabled (MLFLOW_TRACKING_URI not set)\")\n        return False\n    try:\n        mlflow.set_tracking_uri(uri)\n        mlflow.set_experiment(os.environ.get(\"MLFLOW_EXPERIMENT_NAME\", \"chatapp\"))\n        # 3.14 \u8d77 trace \u4e0a\u50b3\u9810\u8a2d\u5c31\u662f async\uff0c\u4e0d\u6703\u62d6\u6162\u56de\u5408\n        _enabled = True\n        logger.info(\"MLflow tracing enabled -&gt; %s\", uri)\n    except Exception as error:\n        logger.warning(\"MLflow tracing disabled (server unreachable?): %s\", error)\n        _enabled = False\n    return _enabled\n\ndef _truncate(value: Any) -&gt; Any:\n    text = value if isinstance(value, str) else repr(value)\n    if len(text) &gt; _TRUNCATE_CHARS:\n        return text&#91;:_TRUNCATE_CHARS] + f\"\u2026 &#91;+{len(text) - _TRUNCATE_CHARS} chars]\"\n    return value\n\ndef _usage_dict(usage: Any) -&gt; dict | None:\n    \"\"\"\u628a SDK \u7684 Anthropic \u98a8\u683c usage \u6620\u5c04\u5230 MLflow \u7684 token-usage \u683c\u5f0f\u3002\"\"\"\n    if not isinstance(usage, dict):\n        return None\n    keys = (\n        \"input_tokens\",\n        \"output_tokens\",\n        \"cache_read_input_tokens\",\n        \"cache_creation_input_tokens\",\n    )\n    out = {k: usage&#91;k] for k in keys if isinstance(usage.get(k), int)}\n    if not out:\n        return None\n    out&#91;\"total_tokens\"] = sum(out.values())\n    return out\n\nclass TurnTrace:\n    \"\"\"\u6bcf\u5247 SDK \u8a0a\u606f\u9935\u7d66 observe()\uff1b\u56de\u5408\u7d50\u675f\u547c\u53eb close()\u3002\"\"\"\n\n    def __init__(self, chat_id: str, prompt: str) -&gt; None:\n        self._root = None\n        self._tools: dict&#91;str, Any] = {}  # tool_use_id -&gt; \u958b\u8457\u7684 TOOL span\n        self._texts: list&#91;str] = &#91;]\n        self._result: ResultMessage | None = None\n        if not _enabled:\n            return\n        try:\n            self._root = mlflow.start_span_no_context(\n                name=\"chat_turn\",\n                span_type=SpanType.AGENT,\n                inputs={\"prompt\": prompt},\n                # \u6a19\u6e96 session \u6b04\u4f4d\uff1a\u540c\u4e00\u804a\u5929\u7684\u56de\u5408\u5728 UI \u6703\u88ab\u6b78\u6210\u4e00\u7d44\n                metadata={TraceMetadataKey.TRACE_SESSION: chat_id},\n                tags={\"chat_id\": chat_id},\n            )\n        except Exception as error:\n            logger.warning(\"MLflow trace not started: %s\", error)\n            self._root = None\n\n    def observe(self, message: Any) -&gt; None:\n        if self._root is None:\n            return\n        try:\n            if isinstance(message, AssistantMessage):\n                self._on_assistant(message)\n            elif isinstance(message, UserMessage):\n                self._on_tool_results(message)\n            elif isinstance(message, ResultMessage):\n                self._result = message\n        except Exception:\n            logger.debug(\"trace observe failed\", exc_info=True)\n\n    def _parent_for(self, parent_tool_use_id: str | None) -&gt; Any:\n        # \u5b50\u4ee3\u7406\u7684\u8a0a\u606f\u5e36\u8457 spawn \u5b83\u7684 Agent \u5de5\u5177 id\uff0c\n        # \u639b\u5230\u90a3\u500b\uff08\u9084\u958b\u8457\u7684\uff09TOOL span \u5e95\u4e0b \u2192 \u81ea\u7136\u5de2\u72c0\n        return self._tools.get(parent_tool_use_id) or self._root\n\n    def _on_assistant(self, message: AssistantMessage) -&gt; None:\n        parent = self._parent_for(message.parent_tool_use_id)\n        texts: list&#91;str] = &#91;]\n        thinking_chars = 0\n        tool_uses: list&#91;ToolUseBlock] = &#91;]\n        for block in message.content:\n            if isinstance(block, TextBlock):\n                texts.append(block.text)\n            elif isinstance(block, ThinkingBlock):\n                thinking_chars += len(block.thinking)\n            elif isinstance(block, ToolUseBlock):\n                tool_uses.append(block)\n        if message.parent_tool_use_id is None:\n            self._texts.extend(texts)  # \u53ea\u5f59\u6574\u4e3b\u7dda\u56de\u8986\uff0c\u5b50\u4ee3\u7406\u7684\u4e0d\u7b97\n\n        # \u8a0a\u606f\u5230\u9054\u6642\u5df2\u5b8c\u6574\uff0cLLM span \u5728\u9019\u88e1\u958b\u4e86\u99ac\u4e0a\u95dc\n        attributes: dict&#91;str, Any] = {}\n        if message.model:\n            attributes&#91;SpanAttributeKey.MODEL] = message.model\n        usage = _usage_dict(message.usage)\n        if usage:\n            # \u6ce8\u610f\uff1a\u653e\u666e\u901a\u5c6c\u6027\uff0c\u300c\u4e0d\u8981\u300d\u653e\u6a19\u6e96 token-usage \u9375\uff01\n            # per-message usage \u4f86\u81ea stream \u7684 message_start\uff0c\n            # output_tokens \u662f stub \u2014\u2014 \u6e96\u78ba\u7e3d\u91cf\u5728 close() \u653e root\uff08\u5751 1\uff09\n            attributes&#91;\"usage\"] = usage\n        span = mlflow.start_span_no_context(\n            name=message.model or \"assistant\",\n            span_type=SpanType.LLM,\n            parent_span=parent,\n        )\n        outputs: dict&#91;str, Any] = {}\n        if texts:\n            outputs&#91;\"text\"] = _truncate(\"\\n\".join(texts))\n        if thinking_chars:\n            outputs&#91;\"thinking_chars\"] = thinking_chars\n        if tool_uses:\n            outputs&#91;\"tool_calls\"] = &#91;{\"name\": b.name, \"id\": b.id} for b in tool_uses]\n        span.end(outputs=outputs or None, attributes=attributes)\n\n        # \u6bcf\u500b\u5de5\u5177\u547c\u53eb\u958b\u4e00\u500b TOOL span\uff0c\u7b49\u914d\u5c0d\u7684\u7d50\u679c\u56de\u4f86\u518d\u95dc\n        for block in tool_uses:\n            self._tools&#91;block.id] = mlflow.start_span_no_context(\n                name=block.name,\n                span_type=SpanType.TOOL,\n                parent_span=parent,\n                inputs=block.input,\n            )\n\n    def _on_tool_results(self, message: UserMessage) -&gt; None:\n        content = message.content\n        if not isinstance(content, list):\n            return\n        for block in content:\n            if isinstance(block, ToolResultBlock):\n                span = self._tools.pop(block.tool_use_id, None)\n                if span is not None:\n                    span.end(\n                        outputs=_truncate(block.content),\n                        status=\"ERROR\" if block.is_error else \"OK\",\n                    )\n\n    def close(self, error: BaseException | None = None) -&gt; None:\n        if self._root is None:\n            return\n        root, self._root = self._root, None  # \u51aa\u7b49\n        try:\n            # \u56de\u5408\u4e2d\u65b7\/\u5931\u6557\u53ef\u80fd\u7559\u4e0b\u6c92\u95dc\u7684\u5de5\u5177 span\n            for span in self._tools.values():\n                span.end(status=\"ERROR\" if error else \"OK\")\n            self._tools.clear()\n\n            result = self._result\n            attributes: dict&#91;str, Any] = {}\n            outputs: dict&#91;str, Any] = {}\n            if self._texts:\n                outputs&#91;\"reply\"] = _truncate(\"\\n\".join(self._texts))\n            if result is not None:\n                outputs&#91;\"subtype\"] = result.subtype\n                for key in (\"total_cost_usd\", \"num_turns\", \"duration_ms\", \"duration_api_ms\"):\n                    value = getattr(result, key, None)\n                    if value is not None:\n                        attributes&#91;key] = value\n                if result.model_usage:\n                    attributes&#91;\"model_usage\"] = result.model_usage\n                # \u672c\u56de\u5408\u6b0a\u5a01 token \u7e3d\u91cf\uff1a\u6574\u689d trace\u300c\u552f\u4e00\u300d\u7684\u6a19\u6e96\n                # token-usage \u5c6c\u6027\uff0c\u6240\u4ee5 trace \u5c64\u805a\u5408 = \u5b83\uff08\u5751 1 \u7684\u89e3\u6cd5\uff09\n                usage = _usage_dict(result.usage)\n                if usage:\n                    attributes&#91;SpanAttributeKey.CHAT_USAGE] = usage\n            if error is not None:\n                outputs&#91;\"error\"] = str(error)\n            failed = error is not None or (result is not None and result.is_error)\n            root.end(\n                outputs=outputs or None,\n                attributes=attributes or None,\n                status=\"ERROR\" if failed else \"OK\",\n            )\n        except Exception:\n            logger.debug(\"trace close failed\", exc_info=True)\n<\/code><\/span><\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">\u639b\u9032\u56de\u5408\u8ff4\u5708\u53ea\u78b0\u56db\u500b\u5730\u65b9\uff1a<\/p>\n\n\n<div class=\"cbc-code-wrapper\"><div class=\"cbc-code-bar\"><button class=\"cbc-copy-button\">Copy<\/button><\/div><pre class=\"wp-block-code\" aria-describedby=\"shcb-language-10\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">from .tracing import TurnTrace\n\nasync with <span class=\"hljs-keyword\">self<\/span>._turn_lock:\n    trace = TurnTrace(<span class=\"hljs-keyword\">self<\/span>.chat_id, display)          <span class=\"hljs-comment\"># 1. \u958b trace<\/span>\n    <span class=\"hljs-keyword\">try<\/span>:\n        await <span class=\"hljs-keyword\">self<\/span>.agent.client.query(prompt)\n        async <span class=\"hljs-keyword\">for<\/span> message in <span class=\"hljs-keyword\">self<\/span>.agent.client.receive_response():\n            trace.observe(message)                     <span class=\"hljs-comment\"># 2. \u6bcf\u5247\u8a0a\u606f\u9935\u9032\u53bb<\/span>\n            await <span class=\"hljs-keyword\">self<\/span>._handle_sdk_message(message)\n        trace.close()                                  <span class=\"hljs-comment\"># 3. \u6b63\u5e38\u6536\u5c3e<\/span>\n    except <span class=\"hljs-keyword\">Exception<\/span> <span class=\"hljs-keyword\">as<\/span> error:\n        trace.close(error)                             <span class=\"hljs-comment\"># 4. \u932f\u8aa4\u4e5f\u6536\u5c3e<\/span>\n        ...\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre><\/div>\n\n\n<h2 class=\"wp-block-heading\">\u8e29\u5230\u7684\u5751<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">\u5751 1\uff1aAssistantMessage.usage \u7684 output_tokens \u6046\u70ba 1<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">\u88dd\u5b8c\u7b2c\u4e00\u8f2a\u5be6\u6e2c\uff0ctrace \u770b\u8d77\u4f86\u4e00\u5207\u6b63\u5e38\u2014\u2014\u76f4\u5230\u770b token \u7d71\u8a08\uff1a<\/p>\n\n\n<div class=\"cbc-code-wrapper\"><div class=\"cbc-code-bar\"><button class=\"cbc-copy-button\">Copy<\/button><\/div><pre class=\"wp-block-code\" aria-describedby=\"shcb-language-11\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">trace tokens: {<span class=\"hljs-string\">'input_tokens'<\/span>: <span class=\"hljs-number\">7164<\/span>, <span class=\"hljs-string\">'output_tokens'<\/span>: <span class=\"hljs-number\">1<\/span>, ...}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-11\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">agent \u660e\u660e\u56de\u4e86\u4e00\u6574\u53e5\u8a71\uff0coutput \u537b\u662f 1\u3002\u539f\u56e0\uff1aCLI \u8f49\u767c\u7684 assistant \u4e8b\u4ef6\uff0c<code>usage<\/code> \u662f Anthropic streaming <code>message_start<\/code> \u7684\u521d\u59cb\u503c\u2014\u2014input\/cache tokens \u90a3\u6642\u5df2\u77e5\uff0c<strong>output_tokens \u662f\u4f54\u4f4d\u7684 1<\/strong>\uff0c\u771f\u5be6\u503c\u8981\u5230 <code>message_delta<\/code> \u624d\u6709\uff0c\u4f46 SDK \u7684 <code>AssistantMessage.usage<\/code> \u62ff\u5230\u7684\u5c31\u662f\u521d\u59cb\u7248\u3002<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u66f4\u9ebb\u7169\u7684\u662f MLflow \u7684\u805a\u5408\u898f\u5247\uff1atrace \u5c64\u7684 token \u7d71\u8a08 = <strong>\u6240\u6709\u5e36\u6a19\u6e96\u9375 <code>mlflow.chat.tokenUsage<\/code> \u7684 span \u52a0\u7e3d<\/strong>\u3002\u5982\u679c\u6bcf\u500b LLM span \u90fd\u639b\u6a19\u6e96\u9375\uff0coutput \u5168\u90e8\u4f4e\u4f30\u3001\u8de8 step \u7684 input \u9084\u6703\u91cd\u8907\u7d2f\u8a08\u3002<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>\u89e3\u6cd5<\/strong>\uff1a<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n\n<li>LLM span \u7684 per-message usage \u653e<strong>\u666e\u901a\u5c6c\u6027<\/strong>\uff08<code>usage<\/code>\uff09\uff0c\u4fdd\u7559\u89c0\u5bdf\u50f9\u503c\u3001\u4e0d\u9032\u805a\u5408\uff1b<\/li>\n\n\n<li><code>ResultMessage.usage<\/code>\uff08\u56de\u5408\u6b0a\u5a01\u7e3d\u91cf\uff09\u653e root span\uff0c\u800c\u4e14\u662f\u6574\u689d trace \u552f\u4e00\u7684 <code>mlflow.chat.tokenUsage<\/code>\u2014\u2014\u805a\u5408\u51fa\u4f86\u7684\u6578\u5b57\u5c31\u7b49\u65bc\u5b83\u3002<\/li>\n\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">\u4fee\u5b8c\u518d\u8dd1\u4e00\u8f2a\uff1a<code>output_tokens: 17<\/code>\uff0c\u5408\u7406\u4e86\u3002\u4e8b\u5f8c\u7ffb\u5b98\u65b9 <code>process_sdk_messages<\/code> \u7684\u539f\u59cb\u78bc\uff0c\u767c\u73fe<strong>\u5b98\u65b9\u4e5f\u662f\u9019\u500b\u7b56\u7565<\/strong>\uff08usage \u53ea\u653e root\u3001\u5f9e ResultMessage \u62ff\uff09\u2014\u2014\u6b8a\u9014\u540c\u6b78\uff0c\u7b49\u65bc\u5e6b\u6211\u9a57\u8b49\u4e86\u9019\u500b\u5751\u662f\u771f\u7684\u3002<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">\u5751 2\uff1a\u5b98\u65b9 autolog \u5728\u8f15\u91cf\u5305\u74b0\u5883\u6709\u300c\u5169\u6bb5\u6b7b\u6cd5\u300d<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">\u70ba\u4e86\u4e0d\u628a\u6574\u5305 MLflow\uff08server\u3001UI\u3001sklearn \u5168\u5bb6\u6876\uff09\u88dd\u9032 app\uff0c\u6211\u4e00\u958b\u59cb\u7528\u4e86 <code>mlflow-tracing<\/code> \u8f15\u91cf\u5305\u3002\u5982\u679c\u4f60\u4e5f\u662f\uff0c<strong>\u5b98\u65b9 autolog \u76f4\u63a5\u8207\u4f60\u7121\u7de3<\/strong>\uff0c\u800c\u4e14\u6b7b\u6cd5\u6709\u5169\u6bb5\uff1a<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>\u7b2c\u4e00\u6bb5\uff1a<code>ModuleNotFoundError: No module named 'anthropic'<\/code><\/strong>\u3002<code>autolog()<\/code> \u51fd\u5f0f\u7b2c\u4e00\u884c\u5c31\u662f <code>from anthropic.resources import AsyncMessages, Messages<\/code>\u2014\u2014\u5c31\u7b97\u4f60\u53ea\u60f3 trace Agent SDK\uff08\u5b83\u5b8c\u5168\u4e0d\u4f9d\u8cf4 anthropic \u5957\u4ef6\uff09\uff0c\u4e5f\u5f97\u5148 <code>pip install anthropic<\/code> \u966a\u846c\u3002<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>\u7b2c\u4e8c\u6bb5\uff08\u66f4\u9670\uff0c\u975c\u9ed8\u5931\u6557\uff09<\/strong>\uff1a\u88dd\u4e86 anthropic \u4e4b\u5f8c patch \u6703\u6210\u529f\uff0c\u4f46\u6536\u5b8c\u8a0a\u606f\u8981\u5efa trace \u6642\uff0c\u5b83\u547c\u53eb\u7684 <code>mlflow.claude_code.tracing.process_sdk_messages<\/code> <strong>\u4e0d\u5b58\u5728\u65bc <code>mlflow-tracing<\/code> \u8f15\u91cf\u5305<\/strong>\u2014\u2014\u800c\u9019\u500b ImportError \u88ab <code>except Exception: logger.debug(...)<\/code> \u541e\u6389\u3002\u7d50\u679c\uff1a<strong>\u4e0d\u5831\u932f\u3001\u4e5f\u6c38\u9060\u6c92\u6709 trace<\/strong>\u3002\u4f60\u4ee5\u70ba\u88dd\u597d\u4e86\uff0c\u5176\u5be6\u4ec0\u9ebc\u90fd\u6c92\u8a18\u3002<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u51fa\u8def\u662f <code>mlflow-skinny<\/code>\uff1a\u5b83<strong>\u6709<\/strong> <code>mlflow.claude_code<\/code>\uff08\u6bd4 <code>mlflow-tracing<\/code> \u591a\u9019\u584a\u3001\u6bd4\u5b8c\u6574\u7248\u5c11 server\/UI\uff09\uff0c\u53ea\u8981\u518d\u88dc\u4e00\u500b\u5b83\u6c92\u5e36\u7684\u96b1\u85cf\u4f9d\u8cf4 <code>python-dateutil<\/code> \u5c31\u80fd\u8dd1\uff08\u898b\u6700\u7d42\u843d\u5730\u7bc0\u7684\u5957\u4ef6\u5c0d\u7167\u8868\uff09\u3002<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u5176\u4ed6\u8f15\u91cf\u5305\u7f3a\u4ef6\uff08\u624b\u52d5\u7248\u8def\u4e0a\u649e\u5230\u7684\uff09\uff1a<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n\n<li><code>mlflow.config.enable_async_logging(True)<\/code> \u2192 <strong>\u6c92\u6709 <code>mlflow.config<\/code><\/strong>\u3002\u67e5\u74b0\u5883\u8b8a\u6578\u8868\u624d\u767c\u73fe <code>MLFLOW_ENABLE_ASYNC_TRACE_LOGGING<\/code> \u9810\u8a2d\u5c31\u662f <code>True<\/code>\uff0c\u9019\u884c\u6839\u672c\u4e0d\u7528\u5beb\u3002<\/li>\n\n\n<li><code>MlflowClient<\/code>\u3001<code>get_experiment_by_name<\/code> \u2192 <strong>\u90fd\u4e0d\u5728<\/strong>\u3002\u8981\u522a\u6e2c\u8a66\u7528\u7684 experiment\uff0c\u6700\u5f8c\u76f4\u63a5\u8d70 REST API\uff1a<\/li>\n\n<\/ul>\n\n\n<div class=\"cbc-code-wrapper\"><div class=\"cbc-code-bar\"><button class=\"cbc-copy-button\">Copy<\/button><\/div><pre class=\"wp-block-code\" aria-describedby=\"shcb-language-12\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">curl -X POST <span class=\"hljs-string\">\"$MLFLOW_TRACKING_URI\/api\/2.0\/mlflow\/experiments\/delete\"<\/span> \\\n  -H <span class=\"hljs-string\">\"Content-Type: application\/json\"<\/span> -d <span class=\"hljs-string\">'{\"experiment_id\": \"2\"}'<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-12\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">\u539f\u5247\uff1a\u7528\u8f15\u91cf\u5305\u6642\uff0c<strong>\u6bcf\u500b API \u90fd\u5148 <code>dir(mlflow)<\/code> \u78ba\u8a8d\u5b58\u5728\u518d\u5beb<\/strong>\uff0c\u5b98\u65b9\u6587\u4ef6\u5beb\u7684\u662f\u5b8c\u6574\u5305\u7684 API \u8868\u9762\u3002<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">\u5751 3\uff1atracking server \u5728\u5bb9\u5668\u88e1\uff0clocalhost \u9023\u4e0d\u5230<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">\u6a5f\u5668\u4e0a <code>ps<\/code> \u770b\u5f97\u5230\u4e00\u53f0 MLflow server \u5728 5000 port\uff0c<code>curl localhost:5000\/health<\/code> \u537b\u662f\u9023\u7dda\u5931\u6557\u2014\u2014\u90a3\u53f0\u8dd1\u5728\u5bb9\u5668\u88e1\uff0cport \u6c92\u6620\u5c04\u51fa\u4f86\u3002\u771f\u6b63\u53ef\u7528\u7684 server \u662f\u53e6\u4e00\u53f0\uff0c\u4f4d\u5740\u662f\u5f9e <code>mlflow-mcp<\/code> \u7684 MCP \u8a2d\u5b9a\u88e1\u7ffb\u51fa\u4f86\u7684\u3002<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u9023\u5e36\u4e00\u500b\u76f8\u95dc\u9677\u9631\uff08skill \u6587\u4ef6\u7279\u5225\u9ede\u540d\uff09\uff1a<code>MLFLOW_TRACKING_URI<\/code> \u6c92\u8a2d\u6216\u8a2d\u932f\u6642\uff0c<strong>trace \u4e0d\u6703\u5831\u932f\uff0c\u800c\u662f\u5b89\u975c\u5730\u5beb\u9032\u672c\u5730 <code>.\/mlruns<\/code> \u76ee\u9304<\/strong>\u2014\u2014\u4f60\u4ee5\u70ba\u5728\u76e3\u63a7\uff0c\u5176\u5be6\u8cc7\u6599\u5168\u843d\u5728 app \u7684\u5de5\u4f5c\u76ee\u9304\u88e1\u3002\u6240\u4ee5 <code>setup_tracing()<\/code> \u624d\u8a2d\u8a08\u6210\uff1a\u6c92 URI \u5c31\u660e\u78ba\u505c\u7528\u4e26\u7559 log\uff0c\u8d77\u4e0d\u4f86\u5c31\u964d\u7d1a\uff0c\u7d55\u4e0d\u9ed8\u9ed8 fallback\u3002<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">\u5751 4\uff1aCLI session resume \u4e4b\u5f8c\uff0c\u91cd\u653e\u7684\u6b77\u53f2\u8a0a\u606f\u6703\u8b8a\u6210\u5047 trace<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">\u9019\u500b\u5751\u662f\u4e0a\u7dda\u5f8c\u5f9e trace \u8cc7\u6599\u88e1\u767c\u73fe\u7684\u3002\u6211\u7684 app \u6703\u628a CLI \u7684 session id \u5b58\u8d77\u4f86\uff0cbackend \u91cd\u555f\u6216 client \u91cd\u5efa\u5f8c\u5e36 <code>resume=&lt;session_id&gt;<\/code> \u63a5\u56de\u539f\u5c0d\u8a71\u3002\u7d50\u679c MLflow \u4e0a\u51fa\u73fe\u9019\u7a2e\u8a6d\u7570 trace\uff1a<\/p>\n\n\n<div class=\"cbc-code-wrapper\"><div class=\"cbc-code-bar\"><button class=\"cbc-copy-button\">Copy<\/button><\/div><pre class=\"wp-block-code\"><span><code class=\"hljs\">14:42 spans=15  duration=18ms    \u2190 15 \u500b span \u64e0\u5728 18ms\uff1f\n13:40 spans=48  duration=44ms    \u2190 48 \u500b span \u64e0\u5728 44ms\uff1f\uff1f\n12:54 spans=363 duration=22 \u5206\u9418  \u2190 \u9019\u689d\u624d\u662f\u6b63\u5e38\u7684\n<\/code><\/span><\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">\u62bd\u958b 44ms \u90a3\u689d\u4e00\u770b\uff0c\u88e1\u9762\u7684 LLM\/TOOL span \u5167\u5bb9\u5168\u662f<strong>\u4e0a\u4e00\u8f2a\u5df2\u7d93\u505a\u5b8c\u7684\u5de5\u4f5c<\/strong>\u2014\u2014resume \u4e4b\u5f8c\uff0c<code>receive_response()<\/code> \u6703\u628a\u6062\u5fa9\u7684\u6b77\u53f2\u8a0a\u606f<strong>\u91cd\u653e<\/strong>\u4e00\u904d\uff0c\u6211\u7684 TurnTrace \u628a\u5b83\u5011\u7576\u6210\u672c\u8f2a\u7684\u5373\u6642\u4e8b\u4ef6\uff0c\u5168\u6578\u91cd\u5efa\u4e86\u4e00\u6b21\u3002\u6642\u9577\u5047\u3001\u5167\u5bb9\u932f\u7f6e\u3002<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u9019\u4e0d\u662f\u624b\u52d5\u7248\u7368\u6709\u7684\u554f\u984c\uff1a\u5b98\u65b9 autolog \u4e00\u6a23\u662f\u6536 <code>receive_response()<\/code> \u7684\u8a0a\u606f\u6d41\uff0c\u540c\u6a23\u7684\u91cd\u653e\u540c\u6a23\u6703\u9032 trace\u3002SDK \u76ee\u524d\u6c92\u6709\u5728\u8a0a\u606f\u7269\u4ef6\u4e0a\u6a19\u8a18\u300c\u9019\u662f replay\u300d\uff08\u53ea\u6709\u4e00\u500b <code>extra_args={\"replay-user-messages\": None}<\/code> \u9078\u9805\u63a7\u5236\u8981\u4e0d\u8981\u91cd\u653e user \u8a0a\u606f\uff09\uff0c\u6240\u4ee5\u53ea\u80fd\u81ea\u5df1\u9632\u2014\u2014\u6bd4\u5c0d\u8a0a\u606f uuid\u3001\u6216 resume \u5f8c\u7684\u7b2c\u4e00\u8f2a\u4e1f\u68c4\u300cquery() \u767c\u51fa\u4e4b\u524d\u5c31\u6e67\u5165\u300d\u7684\u8a0a\u606f\u3002\u9019\u689d\u7684\u4fee\u6cd5\u6211\u9084\u5728\u6536\u6582\uff0c\u5148\u628a\u5751\u7acb\u724c\u3002<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">\u9644\u8d08\u5c0f\u5751\uff1apkill \u81ea\u6bba<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">\u9a57\u8b49\u6642\u8981\u91cd\u555f dev server\uff0c\u96a8\u624b\u4e00\u53e5\uff1a<\/p>\n\n\n<div class=\"cbc-code-wrapper\"><div class=\"cbc-code-bar\"><button class=\"cbc-copy-button\">Copy<\/button><\/div><pre class=\"wp-block-code\" aria-describedby=\"shcb-language-13\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">pkill -f <span class=\"hljs-string\">\"npm run dev\"<\/span>; sleep <span class=\"hljs-number\">2<\/span>; nohup npm run dev &amp;\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-13\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">\u7d50\u679c\u6574\u689d\u547d\u4ee4\u81ea\u5df1 exit 144\u3002\u56e0\u70ba <code>pkill -f<\/code> \u6bd4\u5c0d\u7684\u662f\u5b8c\u6574\u547d\u4ee4\u5217\uff0c\u800c<strong>\u9019\u689d\u8907\u5408\u547d\u4ee4\u672c\u8eab\u5c31\u542b\u6709 &#8220;npm run dev&#8221; \u5b57\u4e32<\/strong>\u2014\u2014pkill \u628a\u627f\u8f09\u5b83\u7684 shell \u4e00\u8d77\u6bba\u4e86\u3002\u89e3\u6cd5\uff1apattern \u7528 <code>\"[n]pm run dev\"<\/code> \u9019\u7a2e regex \u5beb\u6cd5\u907f\u958b\u81ea\u5339\u914d\uff0c\u6216 kill \u548c\u5f8c\u7e8c\u52d5\u4f5c\u5206\u5169\u6b21\u4e0b\u3002<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">\u9a57\u8b49\uff1a\u4e0d\u8981\u88dd\u5b8c\u5c31\u7576\u4f5c\u6709\u7528<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">\u7167 <code>instrumenting-with-mlflow-tracing<\/code> skill \u7684\u8981\u6c42\u505a\u5169\u5c64\u9a57\u8b49\uff0c\u5169\u500b\u65b9\u6848\u90fd\u8dd1\u904e\uff1a<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>\u7b2c\u4e00\u5c64\uff1a\u5408\u6210\u8a0a\u606f\u6d41<\/strong>\uff08\u624b\u52d5\u7248\uff09\u3002\u624b\u5de5\u7d44\u4e00\u4e32 <code>AssistantMessage<\/code> \/ <code>UserMessage<\/code> \/ <code>ResultMessage<\/code>\uff08\u542b\u5b50\u4ee3\u7406\u3001\u542b\u8d85\u9577\u5de5\u5177\u8f38\u51fa\u3001\u542b\u932f\u8aa4\u7d50\u679c\uff09\u9935\u7d66 <code>TurnTrace<\/code>\uff0c\u6253\u771f server\uff0c\u7136\u5f8c <code>search_traces()<\/code> + <code>get_trace()<\/code> \u65b7\u8a00\u6574\u68f5\u6a39\uff1aroot \u662f AGENT\u3001\u5de5\u5177\u914d\u5c0d\u6b63\u78ba\u3001\u5b50\u4ee3\u7406\u5de2\u72c0\u5c0d\u3001\u622a\u65b7\u751f\u6548\u3001\u805a\u5408 token = ResultMessage.usage\u300215 \u689d\u65b7\u8a00\u5168\u904e\u624d\u7b97\u6578\u3002<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>\u7b2c\u4e8c\u5c64\uff1a\u771f\u6d41\u91cf<\/strong>\uff08\u6700\u7d42\u65b9\u6848\uff09\u3002\u8d77 app\u3001\u771f\u7684\u8dd1\u4e00\u500b\u56de\u5408\uff0c\u53bb MLflow UI \u770b\u5b98\u65b9 trace + \u88dc\u4e01 tags \u90fd\u5728\uff1a<\/p>\n\n\n<div class=\"cbc-code-wrapper\"><div class=\"cbc-code-bar\"><button class=\"cbc-copy-button\">Copy<\/button><\/div><pre class=\"wp-block-code\" aria-describedby=\"shcb-language-14\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">trace: tr<span class=\"hljs-number\">-0<\/span>bc949373eef29a8... | state: OK\n<span class=\"hljs-attr\">spans<\/span>: claude_code_conversation (AGENT) \u2514\u2500 llm (LLM)\n<span class=\"hljs-attr\">token_usage<\/span>: {<span class=\"hljs-string\">'input_tokens'<\/span>: <span class=\"hljs-number\">7411<\/span>, <span class=\"hljs-string\">'output_tokens'<\/span>: <span class=\"hljs-number\">8<\/span>,\n              <span class=\"hljs-string\">'cache_read_input_tokens'<\/span>: <span class=\"hljs-number\">17192<\/span>, <span class=\"hljs-string\">'cache_creation_input_tokens'<\/span>: <span class=\"hljs-number\">9857<\/span>}\n<span class=\"hljs-attr\">tags<\/span>: chat_id=<span class=\"hljs-number\">20260618<\/span><span class=\"hljs-number\">-165650<\/span>  turn_cost_usd=<span class=\"hljs-number\">0.145098<\/span>\n      num_turns=<span class=\"hljs-number\">1<\/span>  model_usage={...per-model...}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-14\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">cost\u3001chat \u6b78\u5c6c\u3001cache \u547d\u4e2d\u4e00\u76ee\u4e86\u7136\u2014\u2014prompt cache \u6709\u6c92\u6709\u751f\u6548\uff0ctrace \u4e0a\u770b\u5f97\u6e05\u6e05\u695a\u695a\u3002<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">\u9806\u5e36\u4e00\u63d0\uff1a\u5751 4\uff08resume \u91cd\u653e\u5047 trace\uff09\u5c31\u662f\u9019\u7a2e\u300c\u4e0a\u7dda\u5f8c\u6301\u7e8c\u770b\u8cc7\u6599\u300d\u6293\u51fa\u4f86\u7684\u2014\u2014\u9a57\u8b49\u4e0d\u662f\u88dd\u5b8c\u90a3\u5929\u7684\u4e8b\u3002<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">\u4e0b\u4e00\u6b65<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Tracing \u53ea\u662f\u5730\u57fa\u3002\u63a5\u4e0b\u4f86\u53ef\u4ee5\u7528 <code>agent-evaluation<\/code> skill \u5728\u9019\u4e9b trace \u4e0a\u8dd1 LLM-as-judge\uff1a\u81ea\u52d5\u8a55\u6bcf\u56de\u5408\u7684\u56de\u7b54\u54c1\u8cea\u3001\u5de5\u5177\u9078\u64c7\u5c0d\u4e0d\u5c0d\uff0c\u518d\u7528 <code>mlflow-mcp<\/code> \u7684 <code>register_llm_judge_scorer<\/code> \u639b\u5e38\u99d0\u8a55\u5206\u5668\u3002\u7b49 trace \u7d2f\u7a4d\u5920\u591a\uff0c\u300cagent \u6700\u5e38\u5728\u54ea\u7a2e\u4efb\u52d9\u4e0a\u7ffb\u8eca\u300d\u5c31\u4e0d\u518d\u662f\u6191\u611f\u89ba\u56de\u7b54\u7684\u554f\u984c\u4e86\u3002<\/p>\n","protected":false},"excerpt":{"rendered":"<p>MLflow 3.5+ \u5b98\u65b9\u652f\u63f4 trace Claude Agent SDK\uff1amlflow.anthropic.autolog() \u6703 patch ClaudeSDKClient\u3001\u5f9e\u8a0a\u606f\u6d41\u4e8b\u5f8c\u91cd\u5efa trace\u3002\u5be6\u6e2c\u5b83\u7f3a cost\u3001\u5b50\u4ee3\u7406\u4e0d\u5de2\u72c0\u3001span \u6642\u9577\u5168\u5047\u2014\u2014\u5176\u4e2d cost \u548c\u81ea\u5df1\u7684 chat id \u7528 30 \u884c set_trace_tag \u88dc\u4e01\u5c31\u80fd\u88dc\u56de\uff0c\u9019\u662f\u6211\u6700\u7d42\u843d\u5730\u7684\u65b9\u6848\uff08mlflow-skinny + anthropic + python-dateutil \u6700\u5c0f\u7d44\u5408\uff09\u3002\u8981\u771f\u5be6\u6642\u9577\uff0f\u5b50\u4ee3\u7406\u6a39\u5247\u9644\u5168\u624b\u52d5 TurnTrace \u5be6\u4f5c\u3002\u5916\u52a0\u56db\u500b\u5751\uff1atoken stub\u3001\u8f15\u91cf\u5305\u5169\u6bb5\u6b7b\u6cd5\u3001\u5bb9\u5668\u88e1\u7684 tracking server\u3001resume \u91cd\u653e\u5047 trace\u3002<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"rolpb_likes":0,"footnotes":""},"categories":[837],"tags":[838,840,291,440,392,839,240,394],"class_list":["post-823","post","type-post","status-publish","format-standard","hentry","category-claude-agent-sdk","tag-claude-agent-sdk-2","tag-claude-code-2","tag-fastapi","tag-mcp","tag-mlflow","tag-observability","tag-python","tag-tracing"],"blocksy_meta":{"styles_descriptor":{"styles":{"desktop":"","tablet":"","mobile":""},"google_fonts":[],"version":7}},"_links":{"self":[{"href":"https:\/\/blog.itsmygo.uk\/wordpress\/wp-json\/wp\/v2\/posts\/823","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.itsmygo.uk\/wordpress\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.itsmygo.uk\/wordpress\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.itsmygo.uk\/wordpress\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.itsmygo.uk\/wordpress\/wp-json\/wp\/v2\/comments?post=823"}],"version-history":[{"count":2,"href":"https:\/\/blog.itsmygo.uk\/wordpress\/wp-json\/wp\/v2\/posts\/823\/revisions"}],"predecessor-version":[{"id":825,"href":"https:\/\/blog.itsmygo.uk\/wordpress\/wp-json\/wp\/v2\/posts\/823\/revisions\/825"}],"wp:attachment":[{"href":"https:\/\/blog.itsmygo.uk\/wordpress\/wp-json\/wp\/v2\/media?parent=823"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.itsmygo.uk\/wordpress\/wp-json\/wp\/v2\/categories?post=823"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.itsmygo.uk\/wordpress\/wp-json\/wp\/v2\/tags?post=823"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}