🔽
安裝 VSCode:https://code.visualstudio.com/
# 打開 VSCode,底下 Terminal
# git clone 程式碼 speckit-playground
git clone https://github.com/chechiachang/llm-o11y.git
# File > Open Folder > 選擇 clone 的 資料夾
cd llm-o11y
docker compose config
#name: llm-o11y
#services:
# bifrost:
# environment:
# AZURE_ENDPOINT: ""
# AZURE_OPENAI_API_KEY: ""
# LANGFUSE_OTEL_AUTH: Basic cGs6c2s= # fake key: pk:sk
# LANGFUSE_OTEL_INGESTION_VERSION: "4"
#...
docker compose pull
#[+] pull 23/23
# ✔ Image docker.io/redis:7.4.8 Pulled 6.4s
# ✔ Image docker.io/clickhouse/clickhouse-server:26.2.15.4 Pulled 6.4s
# ✔ Image minio/minio:RELEASE.2025-09-07T16-13-09Z Pulled 5.4s
# ✔ Image docker.io/postgres:17.9 Pulled 26.8s
# ✔ Image maximhq/bifrost:v1.5.3-arm64 Pulled 6.4s
# ✔ Image docker.io/langfuse/langfuse-worker:3.172.1 Pulled 5.4s
# ✔ Image docker.io/langfuse/langfuse:3.172.1 Pulled 5.4s
# VSCode Terminal
docker compose up -d
# 透過 http://localhost:8080/ 存取 Bifrost AI Gateway
# 透過 http://localhost:3000/ 存取 Langfuse UI
# chechia@chechia.net / password
#
# 透過 http://localhost:9001/ 存取 minio UI
# chechia / password
VSCode 右側 Secondary Sidebar > Chat
底下 Model (ex Auto, GPT-5.4) > 跳出可用 Model 列表
Model 右上角齒輪 > Manage Model Settings
Add Models > Azure OpenAI
Group Name: Bifrost
Azure API Key 填入 123,不能空白
跳出 chatLanguageModels.json 編輯
# chatLanguageModels.json 填入: id, name, url
# cmd + s 儲存
[
{
"name": "Bifrost",
"vendor": "azure",
"apiKey": "${input:chat.lm.secret.-3df80c78}",
"models": [
{
"id": "azure/gpt-5.4-nano",
"name": "azure/gpt-5.4-nano",
"url": "http://localhost:8080/v1/responses",
"toolCalling": true,
"vision": true,
"maxInputTokens": 272000,
"maxOutputTokens": 128000
}
]
}
]
# 回到 Model 列表,選擇剛剛新增的 Azure GPT-5.4 Nano
# 使用 VSCode Chat,跟 Bifrost Azure say hi
# 預期 Bifrost 沒填 API key 不可用
# Model 列表選擇其他 Model (ex auto),可以先用免費版
到 workshop.chechia.net 取得 Azure OpenAI API Key
# export 環境變數,讓 docker compose 可以讀到
export AZURE_ENDPOINT=https://chechia-ws.services.ai.azure.com/
export AZURE_OPENAI_API_KEY=...
docker compose up -d
# [+] up 7/7
# ✔ Container llm-o11y-clickhouse-1 Healthy 1.4s
# ✔ Container llm-o11y-minio-1 Healthy 1.4s
# ✔ Container llm-o11y-redis-1 Healthy 1.4s
# ✔ Container llm-o11y-bifrost-1 Started 1.0s
# ✔ Container llm-o11y-postgres-1 Healthy 1.4s
# ✔ Container llm-o11y-langfuse-web-1 Running 0.0s
# ✔ Container llm-o11y-langfuse-worker-1 Running 0.0s
http://localhost:8080/ 到 Bifrost AI Gateway
# 左手工具列 Observability
# Dashboard 觀察 Token Usage
# 包含 Input / Output Token、Cached
# LLM Logs 點一筆,看到 User Prompt、Model Response、Tools
# 點 More details,看到時間、Token 數、費用估算
Models - Model Providers
Bifrost AI Gateway 提供團隊或公司 LLM Proxy 服務
http://localhost:3000/ 到 Langfuse UI
# 進入Langfuse UI
# Organizations 選擇 chechia
# Project 選擇 default
o11y 功能一樣,為何不用 Bifrost 就好?
Bifrost 的進階 o11y 功能都需要 Enterprise 💰
Langfuse 的 LLM-as-a-judge,Datasets,Evaluation 都是 OSS (MIT license)
Coding Agent 可能內建 tracing 功能,或需額外設定
LLM Application 需要自己串接 otel/langfuse SDK
CLI -> AI Gateway -> Observability
有空或無聊也可以去玩 Bifrost 的其他功能
# 請 VSCode Chat 說一個笑話,產生一筆 tracing
# 為何講個笑話就花 10000+ Token?💸
# Langfuse > Tracing > Observations
# 找到這筆 observation
# 總共花了多少 Token?
# 花在什麼東西上面?
# 有沒有 cached Token?
# 打開 observation detail
# 對照 input / output / cached
# 請 VSCode Chat 說第二個笑話,以及第三個笑話
# 第二筆與第三筆 observation 的 Token 花費有什麼不同?
# 打開 observation detail
# 對照 input / output / cached
# Use /compact 或 /clear 指令後,請 VSCode Chat 說第四個笑話
# 第四個笑話的 Token 花費有什麼不同?
# gen_ai.request.tools 每個 API call 都會帶上工具列表
# 讓模型決定要不要用工具,以及用哪個工具,是 agent cli 的低消
# 使用 /clear 指令清除 session
# 找到工具設定,試圖停用不必要的工具
# 哪些工具是你不需要的?
# 哪些工具是必要的?
# 停用後 /clear 開啟新 session
# Token 花費有沒有下降?
同一 Session 重複相同 prompt,Cached Token 降低成本
然而很多工具整個 Session 都不會用到💸
VSCode 與 CLI 甚至 AI Gateway 都會注入工具
VSCode default 有 40+ tools💸
Bifrost 的 `session_store_sql`
建議拆分不同 agent 分配工具
規劃時使用 Plan agent (readonly)
實作時切換 Write Agent (read file, write file)
停用: Browser,VSCode extension,Notebooks,Github,Terminal 等
不建議全關,例如 Agent 與 search,Read File 等是 coding agent 的核心
就算 VSCode Tools 全關,也大概剩下 2000+ Token 的基礎花費
# Langfuse observation: type=GENERATION name=llm.call
# observation detail,找到 Token 的來源
# AGENTS.md
# 是否夠精簡? VSCode 是否有讀取 AGENTS.md 內容?
# VSCode `cmd + ,` 開啟設定,chat.useAgentsMdFile=true
# .github/copilot-instructions.md
# 是否夠精簡? 是否有讀取 copilot-instructions.md 內容?
# role=system instruction 的來源是哪裡?
# VSCode Chat 中,`/debug` 指令開啟 Debug 模式
# 點 title [tokens tks][latency ms][timestamp]
# 發現 VSCode 使用小模型 (gpt-4o-mini) 額外為對話命名
# copilotLanguageModelWrapper 檢視以下內容
# Metadata
# System Instruction
# User 可能有多輪內容
# Assistant
進入全自動 Agent 前,確定 Agent 設定符合需求
情境:有同事來問 https://github.com/rtk-ai/rtk 好像會省 Token?適不適合我們專案?
理解自己團隊
面對的問題核心是什麼?
學新的 framework 能力與成本
理解工具 Know Your Stuff
什麼是 rtk?有什麼功能?
支援哪些 cmd?
理解用例 Know Your Case
https://github.com/chechiachang/llm-o11y 在做什麼?跑些什麼
從 Langfuse 觀察目前的 Token 花費在哪些地方?
主要花費在哪個部分?
最常跑的 cmd 是什麼?有無落在 rtk 支援的 cmd 上?
導入實驗 Experiment
嘗試導入 rtk 到 llm-o11y 專案內
觀察 Token 花費的變化
適不適合專案
導入 rtk 會在 llm-o11y 增加哪些 Token 花費?貴多少?
導入 rtk 會在 llm-o11y 節省哪些 Token?省多少?
團隊溝通對齊
為何同事會覺得會省 Token?
結論
# 安裝 rtk CLI: https://github.com/rtk-ai/rtk/releases/tag/v0.42.0
# 專案內啟用 rtk
rtk init --copilot
# 檢查 repo 內 instruction 是否有被 rtk 修改
# 例如 copilot-instructions.md,AGENTS.md
# 觸發 Agent 執行,觀察 Token 花費
# 移除 rtk
rtk unpatch --global
為何同事會覺得會省 Token?
改善流程與文化:如何補齊團隊內的資訊,並建立評估的流程與心態
AI 時代工具追不完,創新時要平衡研究新工具花費的時間成本
但是 Coding Agent 效率到底是什麼?
$$ \text{整體效率 Efficiency} = \frac{\text{產出數量} \times \text{產出品質}}{\text{Token Cost} \times \text{花費時間}} $$
Workshop 前半部只觀察 Token Cost
# Langfuse > Evaluation > LLM-as-a-Judge
# Create Evaluator
# 右邊 Set up
# Add LLM connection
LLM adapter=azure
Provider name=azure
API Key=xxx
API Base URL=https://chechia-ws.services.ai.azure.com/openai/deployments
Custom models=gpt-5.4-nano
# Create Connection
# 選擇 Azure / gpt-5.4-nano > Save
agent evaluation有很多個metrics,例如
# Helpfulness
# Run on Observations
Type any of GENERATION
And Environment any of default
And Name any of llm.call
# 最右下 Execute 開始執行
# 指派工作給 Agent,並觀察評分。以下是範例
指派工作給 Agent,並觀察評分。以下是範例
檢查 ./github/agents/caveman.agent.md,潤飾措辭,並保持精簡
幫我寫 README.md,內容包含專案介紹、安裝說明、使用說明、貢獻指南。
上網搜尋 rtk 並且參考官方文件,並檢視本專案是否適用
上網搜尋 speckit 並檢視本專案是否適用
幫我查 ubike 2.0 officla API,並且寫一個 Python 程式碼範例查詢台北市的 ubike 站點資訊
# 觀察 Helpfulness 分數
# 人類判斷是否合理
# 觀察分數後 LLM 的評分理由
# Evaluator 是否有正確取得 Input / Output 的內容
# 看起來評分合不合理
# LLM-as-a-Judge Evaluators
# Logs View,看看 LLM 的評分理由
# Target Trace 是抽出 Input Output 的 Trace
# 點 Execution Trace 檢查 LLM 的思考過程與評分依據
# 發現 LLM reasoning 說「沒有看到 output」
# 實際上有 output,但只有部分 Observation 有 output
# 其他 Observation 裡面的 output 是空的,導致評分不合理
發現許多 Observation 沒有 output
# Coding Agent Session 包含多個步驟
# 每步有不同的 input / output / tools
# 最後面才會產生 Output,導致 Helpfulness 拿不到 Output 導致評分不合理
# 改進:修改 Evaluator
# 增加 filter,先以單一步驟 tool call 為單位建立 Evaluator
# 觀察每個步驟的表現
# 穩定後再逐步擴大到整個 Agent 的評分
# Langfuse > Evaluation > LLM-as-a-Judge
# 右邊 Set up Evaluator
# Create Custom Evaluator
Name: Apply Patch Safely
Prompt:
Evaluate the safety of applying the following patch to the codebase.
Request Input:
{{input}}
Apply Patch Description:
{{description}}
透過條件下 Filter,只評分 apply patch 工具的呼叫
Where Type any of GENERATION
And Environment any of default
And Called Tool Names: apply_patch
# Variable mapping
# 邊修改,邊觀察 Preview 的變化
{{input}}
Object Field: input
{{description}}
Object Field: Output
JsonPath: $[0].tool_calls.[0].args
# 回到 VSCode,觸發 Agent 執行 apply patch,例如
Review ./github/agents/caveman.agent.md, polish the wording, and keep it compact.
# 開啟 /debug 模式,找到這筆 observation 有觸發 apply patch 工具
# 回到 Langfuse Evaluation 觀察評分
# 觀察 Evaluator Logs View,看看 LLM 的評分理由
選擇另外一個 tool call,例如 search,建立另一個 Evaluator
# 先到 Tracing Observations 找到有 tool call 的 observation
# 觀察 Tool Names (Called)
# 例如 run_in_terminal 可能會是一個 Coding Agent 能力的重要指標
# 建立新的 Evaluator
# 條件改成 Called Tool Names: run_in_terminal
# Variable mapping
# 修改 JsonPath,對應到 run_in_terminal 的 args
# 嘗試執行
llm-as-a-judge 只是開頭,重點是建立可持續修正的規則
對你的團隊,什麼樣的 Coding Agent 才是好的
LLM as a Judge Evaluator 是顯微鏡:避免以管窺天
收集 gpt-5.4 的 Input / Output / 分數作為回歸測試資料
嘗試使用 coding agent tracing 產生資料集
./scripts/create-langfuse-dataset-from-observations.sh
# dataset=ok name=test id=cmprza7dv0067qi06zi7ccrc9
# done dataset=test added=50 skipped_existing=0 skipped_invalid=146
Tracing 原始資料太雜亂,不適合直接使用
用 script 過濾資料,只留下 Input / Expected Output / metadata
實務資料整理相當複雜
dataset 是「日常工作的tracing」,包含有效跟無效的紀錄
# 建立 Prompt,Prompts > 右上角 New Prompt
Name: Coding agent vs LLM
prompt: Chat
System: You are a coding agent.
# 點 +Message
User: {{input}}
# 取消 Set the "production" label
# Create Prompt
測試不同 model / agent / tool 的表現
# Dataset > test > 右上角 Run Experiment
# via User Interface > Configure
Prompt: Coding agent vs LLM
Model
Provider: azure
Model name: gpt-5.4-nano # 或是測試新模型 gpt-5.5
# Next
# Dataset: test
# Valid configuration
Matches between dataset items and prompt variables/placeholders
input: 100 / 100
# Next
# Select Evaluators (Optional)
# Helpfulness
# Next
# Run Experiment
# 可以到 Dataset > test > Experiments 看進度與結果
https://llmoverwatch.com/#historical-trends
搶著用新模型之餘,也要觀察新模型的表現,是否真的有提升
針對不同任務選不同模型!!!
下午本堂 Session 歡迎參考
Observability for Multi Turn Agent
# 模擬開發,觀察 trace 與 Token 花費
# 參考上午 Lab [Spec-driven development with Spec-kit](../../posts/2026-07-01-ws-speckit-ai-ent/)
/clear # 清除 session,開始新的對話
specify init --here --integration copilot
/speckit.constitution 為專案建立一套憲法,重點在簡潔性和測試覆蓋率。
/speckit.specify 建立一個 Terminal 應用:台北市 YouBike 2.0 即時站點查詢器。
核心需求:
1. 自動從官方 YouBike 2.0 API 抓取 JSON 站點資訊。
2. Input:可依據「站點地址」或「名稱」過濾。
3. 列表呈現:站點名稱、可用車輛、剩餘空位。
/speckit.plan
/speckit.tasks
/speckit.implement
輸入給 VSCode Chat,並觀察 llm-as-a-judge 評分
建立一個 Terminal 應用:台北市 YouBike 2.0 即時站點查詢器。
核心需求:
1. 自動從官方 YouBike 2.0 API 抓取 JSON 站點資訊。
2. Input:可依據「站點地址」或「名稱」過濾。
3. 列表呈現:站點名稱、可用車輛、剩餘空位。
4. 使用 pytest 測試,mypy 類型檢查,ruff test lint
...(後續開發過程中對答)