- 可观测性
- AI 评测
- LLMOps
- AI 应用
- 人工智能
【免费下载链接】phoenix
AI Observability & Evaluation
本篇技术指南围绕当前仓库中的可运行示例项目 js/examples/apps/tracing-tutorial 展开,完整演示如何用 TypeScript(AI SDK + Phoenix SDK)构建一个客服支持 Agent(SupportBot),并借助 Phoenix 对每一次 LLM 调用、工具执行、RAG 检索进行追踪,通过 Annotation 与 LLM-as-Judge 评估回答质量,最终用 Sessions 把多轮对话串成完整会话。读完本文,你将掌握 Phoenix 可观测性体系的四个核心能力:接入 Tracing、阅读 Trace 执行树、运行自动化评估、跟踪并评估多轮会话。
教程概览与前置条件
该示例是一个随官方文档发布的配套工程,对应文档中的三个章节:
- 第 1 章:你的第一批 Trace:构建支持 Agent 并追踪所有内部操作
- 第 2 章:Annotation 与评估:用人工反馈与 LLM-as-Judge 评估回答质量
- 第 3 章:Sessions:将多轮对话作为会话进行跟踪与评估
运行示例需要满足以下前提:
- Node.js 18+(本仓库当前依赖的 AI SDK 版本较新,若使用最新 AI SDK 可能需要 Node.js 22+)
- 本地运行中的 Phoenix 服务:
uvx arize-phoenix serve,或pip install arize-phoenix && phoenix serve - OpenAI API Key(示例使用
gpt-4o-mini与text-embedding-ada-002)
从 package.json 可以看到该工程的依赖组成,它们正好对应追踪链路的每一环:
| 依赖包 | 在教程中的作用 |
|---|---|
@arizeai/phoenix-otel | 注册 OpenTelemetry,把 Trace 发往 Phoenix |
@arizeai/phoenix-client | 通过 Phoenix Client 获取 Span、回写 Annotation |
@arizeai/phoenix-evals | 提供createClassificationEvaluator等 LLM-as-Judge 评估器 |
@arizeai/openinference-core | 提供setSession等会话上下文传播能力 |
@arizeai/openinference-semantic-conventions | 提供 OpenInference 语义约定常量(如SESSION_ID) |
ai+@ai-sdk/openai | AI SDK 的generateText、embed、toolAPI 与 OpenAI 模型接入 |
zod | 工具输入参数的运行时校验 Schema |
工程还依赖tsx(TypeScript 直接运行器)与typescript,四个 npm scripts 对应本教程的三个章节(见 package.json):
"scripts": { "evaluate": "npx tsx evaluate-traces.ts", "evaluate:sessions": "npx tsx evaluate-traces.ts --sessions", "sessions": "npx tsx support-agent.ts --sessions", "start": "npx tsx support-agent.ts" }环境搭建:安装依赖、配置环境变量、启动 Phoenix
1. 安装依赖
在 js/examples/apps/tracing-tutorial 目录下执行:
pnpm install2. 设置环境变量
# OpenAI API key(必填) export OPENAI_API_KEY=your-openai-api-key # 可选:自定义 Phoenix 端点(默认为 http://localhost:6006) export PHOENIX_COLLECTOR_ENDPOINT=http://localhost:6006关于PHOENIX_COLLECTOR_ENDPOINT的解析逻辑,可以从 js/packages/phoenix-otel/src/register.ts 的源码注释得到印证:register()的url参数若未提供,会优先读取PHOENIX_COLLECTOR_ENDPOINT环境变量;URL 若未带/v1/traces路径会被自动规范化补全。此外,工程还支持PHOENIX_PROJECT(项目名)、PHOENIX_API_KEY(认证,自动以 Bearer Token 形式加入 Authorization 头)等环境变量。
3. 启动 Phoenix
若使用本地方式运行 Phoenix 服务:
pip install arize-phoenix phoenix serve服务启动后默认监听http://localhost:6006,这也是 Trace 收集端点的默认地址。
追踪接入:理解 instrumentation.ts 做了什么
追踪的开关在 instrumentation.ts 中,它必须在每个脚本的最顶部被导入:
import { register } from "@arizeai/phoenix-otel"; // Register with Phoenix - this handles all the OpenTelemetry boilerplate export const provider = register({ projectName: "support-bot", // Optional: set batch to false for immediate span delivery during development batch: false, });这里的register()一次性完成了 OpenTelemetry 的全部样板工作。从 register.ts 的类型定义可以了解到它支持的核心配置项:
| 配置项 | 默认值 | 说明 |
|---|---|---|
projectName | "default" | Span 在 Phoenix 中归属的项目名,用于 UI 分组与过滤;未传时读PHOENIX_PROJECT环境变量 |
url | 读PHOENIX_COLLECTOR_ENDPOINT | Phoenix 服务地址,自动补全/v1/traces路径 |
apiKey | 读PHOENIX_API_KEY | 云端/认证场景下以 Bearer Token 认证 |
batch | true | true用批量 Span 处理器(生产推荐,减少网络开销);false用简单处理器即时导出(调试方便) |
global | true | 是否把 TracerProvider 注册为全局 Provider |
instrumentations | 无 | 需要自动注册的 OpenTelemetry 插桩列表(注意 ESM 项目可能需手动注册) |
spanProcessors | 无 | 自定义 Span 处理器,提供后会覆盖由url/apiKey/batch生成的默认处理器 |
教程中把batch显式设为false,是为了让开发调试阶段的 Span 立即送达 Phoenix,不必等待批处理窗口。对应的实现位于 lazyOpenInferenceSpanProcessor.ts,它根据batch标志在批量处理器与简单处理器之间切换。
另外注意:示例代码在每次 Agent 执行完毕后会调用provider.forceFlush()(见 support-agent.ts),确保脚本退出前所有 Span 已落盘,这一点在手动跑脚本时很关键。
第 1 章:你的第一批 Trace
运行单轮演示
pnpm start这条命令运行 support-agent.ts 的默认路径,用 7 条精心设计的测试查询去"压测"Agent:
const queries = [ "What's the status of order ORD-12345?", // → 订单状态 → 工具调用(订单存在) "How can I get a refund?", // → FAQ → RAG(知识库中已有) "Where is my order ORD-67890?", // → 订单状态 → 工具调用(订单存在) "I forgot my password", // → FAQ → RAG(知识库中已有) "What's the status of order ORD-99999?", // → 订单不存在,触发失败路径 "How do I upgrade to a premium plan?", // → 知识库中没有,Agent 无法回答 "Can you help me with something random?",// → 模糊请求 ];其中前 4 条是"好查询",后 3 条刻意设计为"坏查询",用来制造真实的失败场景,供后续章节的评估环节分析。
Agent 内部结构与 Trace 形态
handleSupportQuery是整个 Agent 的核心(见 support-agent.ts),它用tracer.startActiveSpan("support-agent", ...)开启一个openinference.span.kind: AGENT的父 Span,把一次请求内的所有操作都嵌套进去。流程分为两步:
Step 1 - 查询分类:用generateText让gpt-4o-mini输出 JSON(category/confidence/reasoning),把查询路由到order_status或faq。分类结果会被写回父 Span 的属性(classification.category、classification.confidence),供 Phoenix UI 直接查看。
Step 2 - 按分类路由:
- 订单状态路径:用 AI SDK 的
tool()定义lookupOrderStatus工具(输入 Schema 由 zod 校验),maxSteps: 2允许"决定调用工具 → 拿到结果"两步;工具内部先模拟 300ms 延迟,再从内存中的orderDatabase查订单,查不到时返回{ error: "Order ... not found in our system" }。拿到结果后再用一次generateText汇总成面向客户的友好回复。 - FAQ 路径(RAG):先用
text-embedding-ada-002对查询做embed,再与 FAQ 库中预先嵌入的向量做余弦相似度排序,取 Top-2 作为上下文,最后让gpt-4o-mini"只使用给定上下文"生成答案。
由于 AI SDK 的generateText、embed、tool调用都带experimental_telemetry: { isEnabled: true },它们会被自动打点为子 Span。因此,在 Phoenix 中每条support-agentTrace 的执行树如下:
订单状态查询:
support-agent (AGENT) ├── ai.generateText (classification → "order_status") ├── ai.generateText (with tool call) │ └── tool: lookupOrderStatus └── ai.generateText (summarizes tool result)FAQ 查询:
support-agent (AGENT) ├── ai.generateText (classification → "faq") ├── ai.embed (query embedding) └── ai.generateText (RAG generation)每个 LLM Span 会记录输入消息(system/user 提示词)、输出、模型名与提供商、调用参数、Token 用量与延迟;RAG 的生成 Span 系统提示词里直接包含检索到的上下文,方便你一眼看出"检索是否找对了文档"。
交互式反馈采集
Agent 跑完所有查询后会进入交互式反馈环节(collectUserFeedback,见 support-agent.ts):对每条响应输入y(👍 有用)、n(👎 无用)或s(跳过)。关键点在于,Agent 在父 Span 创建时通过agentSpan.spanContext().spanId捕获了 Span ID(见第 L219 行),反馈随之通过logSpanAnnotations以user_feedback的名义、annotatorKind: "HUMAN"写回 Phoenix:
await logSpanAnnotations({ spanAnnotations: annotations, sync: false, // async mode - Phoenix processes in background });annotatorKind字段区分标注来源(HUMAN人工 /LLM模型评估),metadata 里记录了分类类别与来源(interactive_tutorial),方便后续按维度聚合。
第 2 章:Annotation 与 LLM-as-Judge 评估
跑完 Agent、收集完人工反馈后,运行评估脚本:
pnpm evaluate该命令对应 evaluate-traces.ts 的默认路径,核心流程是"取 Span → 分类评估 → 回写 Annotation → 输出汇总"。
流程一:从 Phoenix 拉取 Span
通过@arizeai/phoenix-client/spans的getSpans按项目名support-bot拉取最近 100 条 Span(见 evaluate-traces.ts)。如果 Phoenix 未启动或尚未生成 Trace,脚本会给出明确的排查提示。
流程二:工具结果检查(tool_result)
从 Span 列表里过滤出name === "ai.toolCall"的工具 Span,对output.value做纯代码级检查——输出中若包含error或not found则判为error,否则为success(见 evaluate-traces.ts):
const hasError = output.toLowerCase().includes("error") || output.toLowerCase().includes("not found"); const status = hasError ? "❌ ERROR" : "✅ SUCCESS"; annotations.push({ spanId, name: "tool_result", label: hasError ? "error" : "success", score: hasError ? 0 : 1, explanation: hasError ? "Tool returned an error or 'not found' response" : "Tool executed successfully", annotatorKind: "LLM" as const, // 代码级检查,仅为了与评估流程统一 metadata: { evaluator: "tool_result", type: "code" }, });这正是排查"回答为什么没用"的第一层证据:只要在 Phoenix 中看到tool_result = error的 Annotation,就知道是订单在数据库里不存在(例如 ORD-99999)。
流程三:检索相关性评估(retrieval_relevance,LLM-as-Judge)
对 RAG 生成阶段的 LLM Span(按系统提示词特征过滤,见 evaluate-traces.ts),使用@arizeai/phoenix-evals的createClassificationEvaluator创建评估器:
const retrievalRelevanceEvaluator = createClassificationEvaluator({ name: "retrieval_relevance", model: openai("gpt-4o-mini"), choices: { relevant: 1, irrelevant: 0, }, promptTemplate: `You are evaluating whether the retrieved context is relevant to answering the user's prompt. Classify the retrieval as: - RELEVANT: The context contains information that directly helps answer the question - IRRELEVANT: The context does NOT contain useful information for the question You are comparing the "Context" object and the "prompt" object. [Context and Prompt]: {{input}} `, });createClassificationEvaluator的本质是返回一个ClassificationEvaluator实例(见 js/packages/phoenix-evals/src/llm/createClassificationEvaluator.ts),它把自定义promptTemplate与choices(标签到分数的映射)绑定到指定模型上,调用evaluate({ input })即返回{ label, score, explanation }。评估器还会自动生成 explanation,解释"为什么相关/不相关",便于快速定位原因。
评估输入取自 RAG 生成 Span 的input.value(其中包含检索上下文),每评估完一条 Span 会setTimeout 500ms做限流(见第 L301 行)。
流程四:回写 Annotation 与结果汇总
两类评估结果统一通过logSpanAnnotations以异步模式(sync: false)写回 Phoenix,落在子 Span上——这正是"点开一条不理想的 Trace,立刻知道哪一步出了问题"的关键设计。脚本最后会打印两类汇总:
🔧 Tool Calls (lookupOrderStatus): Success: N | Errors: M 📚 FAQ Retrieval: Relevant: N | Irrelevant: M可复用的排障工作流
至此你拥有了一个完整的闭环(与文档 annotations-and-evaluations.mdx 的 "The Debugging Workflow" 小节一致):
- 运行 Agent(
pnpm start),对响应给出 👍/👎; - 运行评估(
pnpm evaluate),给子 Span 打 Annotation; - 在 Phoenix 中点开被标记为不理想的 Trace;
- 查看子 Span 的 Annotation 定位根因:
tool_result = error→ 订单不存在;retrieval_relevance = irrelevant→ FAQ 不在知识库中。
这正是"可扩展的调试方式":用人工反馈定位失败,用自动化评估诊断原因,用 Trace 细节理解根因,而不是逐条人工翻看。
第 3 章:Sessions 多轮会话跟踪
运行多轮会话演示
pnpm sessionspnpm sessions等价于npx tsx support-agent.ts --sessions,运行三组预置的会话场景(见 support-agent.ts):
- 订单咨询(Order Inquiry):客户问订单状态,再追问到货时间、追踪号;
- FAQ 会话(FAQ Conversation):同一会话里连续问密码重置、退款政策;
- 混合会话(Mixed Conversation):在订单与 FAQ 主题间来回切换,测试 Agent 的上下文保持能力。
每个会话通过crypto.randomUUID()生成唯一 Session ID,所有轮次共享同一个 ID。演示还会维护conversationHistory(消息历史)与sessionContext(记住客户提到过的订单号),并在每轮之后用正则/ORD-\d+/i从消息中提取订单号存入上下文(见 support-agent.ts),这样客户在后续轮次说"my order"时 Agent 能接得上。
会话如何被追踪
Sessions 的核心机制在handleSupportQuery中(见 support-agent.ts):
// If we have a session ID, propagate it to all child spans if (sessionId) { return context.with(setSession(context.active(), { sessionId }), runAgent); }关键点有三:
- 父 Span 上写入标准属性
session.id(源码中用SemanticConventions.SESSION_ID常量,见第 L213 行),同时记录conversation.turn轮次号; setSession()来自@arizeai/openinference-core,把会话 ID 注入到 OpenTelemetry 的 Context 中;context.with()确保整个 Agent 执行期间该上下文处于激活状态,从而让所有子 Span 自动继承会话 ID。
文档 sessions.mdx 中把这一机制总结得很精辟:Session ID 本质上只是 Span 属性——在父 Span 上设置它,Phoenix 就会自动把所有相关 Trace 按会话分组。
在 Phoenix 中查看会话
打开 Phoenix 的Sessions标签页,可以看到:
- 对话线程(Conversation threads):所有轮次按 Session ID 分组;
- 聊天视图(Chat view):点进某个会话看到完整的你来我往;
- 会话级 Annotation:落在最后一轮上的连贯性与解决状态评估。
你可以按conversation_coherence或resolution_status过滤会话,快速挑出有问题的对话。
会话级评估
pnpm evaluate:sessions等价于npx tsx evaluate-traces.ts --sessions,执行 evaluate-traces.ts 中的evaluateSessions()。流程如下:
1. 按会话分组:拉取最多 200 条 Span,过滤出name === "support-agent"的 Span,读取session.id属性分组(见groupSpansBySession,第 L184-L195 行)。
2. 构建会话转录(transcript):组内 Span 按conversation.turn排序,把每轮的input.value/output.value拼成Turn N:\nUser: ...\nAgent: ...格式的完整对话文本。
3. 运行两个会话级评估器,均使用gpt-5模型:
- conversation_coherence(对话连贯性):判断 Agent 是否记住了前文信息、有没有重复询问、回复是否承接上文。
coherent: 1 / incoherent: 0。 - resolution_status(问题解决状态):判断对话结束时客户的诉求是否得到满足。
resolved: 1 / unresolved: 0。
两个评估器的判定标准都写在promptTemplate里,并且自动生成 explanation——被标记为 incoherent 或 unresolved 时,点进去即可看到具体原因。
4. 写回会话级 Annotation:与 Span 级不同,这里使用@arizeai/phoenix-client/sessions的logSessionAnnotations,Annotation 落在会话而非单个 Span 上(见第 L504-L516 行),metadata 中记录model: "gpt-5"与turnCount。
5. 汇总输出:
🧠 Conversation Coherence: Coherent: N/M ✅ Issue Resolution: Resolved: N/M会话评估的价值:一个真实的上下文保持案例
文档 sessions.mdx 给出了一个很有说服力的分析案例。在"混合会话"场景中:
- 第 1 轮:用户问 ORD-67890 的状态,Agent 正确查单并回复"处理中,预计 12 月 15 日送达";
- 第 2 轮:用户完全切换话题——"怎么取消订阅?",Agent 走 RAG 给出正确指引;
- 第 3 轮(真正的考验):用户只说"回到我的订单——承运商是谁?",没有重复订单号。Agent 正确回忆起 ORD-67890 并回答(承运商 pending),全程没让用户重复。
会话级 Annotation 印证了这一点:conversation_coherence: coherent (1.0)、resolution_status: resolved (1.0),explanation 明确指出"Agent 跨轮正确引用了订单号与一致细节,同时没有丢失对订阅问题的处理"。
这就是会话级评估的意义:不用逐轮人工检查,通过连贯性与解决率即可扫描全部会话,发现异常后点进去看 explanation 就能定位问题。
在 Phoenix 中应该看什么
打开http://localhost:6006,按章节对照查看:
Traces(第 1 章)
每条support-agentTrace 展示完整请求流。订单路径能看到"分类 → 工具决策 → 工具执行 → 结果汇总"四段;FAQ 路径能看到"分类 → 嵌入 → RAG 生成"。注意分类置信度属性:如果某条查询的confidence: low,通常意味着查询超出了 Agent 的能力范围(例如"Can you help me with something random?")。
Annotations(第 2 章)
每个 Trace 的Annotations标签页会显示三类标注:
user_feedback:用户在终端交互输入的 👍/👎(HUMAN);tool_result:代码级 success/error 检查;retrieval_relevance:LLM 评估的 relevant/irrelevant。
按 Annotation 值过滤 Trace,可以快速发现失败模式(例如所有tool_result = error的 Trace 都对应不存在的订单号)。
Sessions(第 3 章)
Sessions标签页展示完整对话线程与聊天视图,会话级 Annotation 落在最后一轮。按conversation_coherence/resolution_status过滤,即可找到"忘记上下文"或"问题未解决"的会话。
项目结构速览
js/examples/apps/tracing-tutorial/ ├── package.json # 依赖与脚本(start / sessions / evaluate / evaluate:sessions) ├── tsconfig.json # TypeScript 配置(ES2022 / strict / bundler 解析) ├── instrumentation.ts # Phoenix/OpenTelemetry 接入(register + batch:false) ├── support-agent.ts # 第 1 & 3 章:支持 Agent(含会话支持与交互反馈) ├── evaluate-traces.ts # 第 2 & 3 章:LLM-as-Judge 评估(Span 级 + 会话级) └── README.md # 本教程说明各模块的底层实现可以在对应包中找到:追踪注册逻辑见 js/packages/phoenix-otel/src/register.ts,Span Annotation 写入见 js/packages/phoenix-client/src/spans/logSpanAnnotations.ts,会话 Annotation 写入见 js/packages/phoenix-client/src/sessions/logSessionAnnotations.ts,分类评估器工厂见 js/packages/phoenix-evals/src/llm/createClassificationEvaluator.ts。
总结
通过这个 TypeScript 教程工程,你掌握了一套完整的 LLM 应用可观测性方法论:
- 追踪:接入
@arizeai/phoenix-otel后,AI SDK 的每次generateText、embed、tool调用都会自动成为 Trace 中的节点;再用父 Span 把一次请求的全部操作聚合成一棵执行树; - 评估:用人工反馈(👍/👎)标注好坏,用代码级检查与 LLM-as-Judge 自动化诊断失败原因,Annotation 直接落在对应的 Span 上;
- 会话:通过
setSession+context.with让会话 ID 沿上下文传播,把孤立的单次查询串成对话线程,并用会话级评估器回答"上下文是否保持""问题是否解决"。
这套"观察一切 → 度量重点 → 用数据改进"的模式适用于任何 LLM 应用:评估器和指标会随业务变化,但追踪、标注、评估、会话的闭环方法是通用的。你也可以参照仓库中其余示例(如 js/examples/apps 目录下的其他应用)将同样的模式迁移到 LangGraph、OpenAI Agents 等不同框架之上。
- 可观测性
- AI 评测
- LLMOps
- AI 应用
- 人工智能
【免费下载链接】phoenix
AI Observability & Evaluation
相关推荐
如何永久保存微信聊天记录:开源工具完整指南与实战应用
如何永久保存微信聊天记录:开源工具完整指南与实战应用 你是否曾因手机更换而丢失珍贵的聊天记录?那些与亲友的温馨对话、工作群的重要信息、学习交流的宝贵内容,都值得
人工智能AI AgentAgent 框架后端多智能体RAG工具调用Agent 记忆Agent 工作流AI 评测MCP 服务MCP Clients语音Phoenix TypeScript 追踪接入指南:使用 @arizeai/phoenix-otel 完成 LLM 可观测性配置
Phoenix TypeScript 追踪接入指南:使用 @arizeai/phoenix otel 完成 LLM 可观测性配置 导读 本文基于 Phoenix
可观测性AI 评测LLMOpsAI 应用人工智能Ragas 可观测性实战指南:用 Phoenix 与 LangSmith 打通 RAG 评估的追踪与可视化
Ragas 可观测性实战指南:用 Phoenix 与 LangSmith 打通 RAG 评估的追踪与可视化 构建一个可用的 RAG 基线并不困难,但要让它在生产
人工智能大模型模型评测RAG
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考