
1. 为什么你的 LangChain Agent 需要一个“行车记录仪”2025 年做 Agent 开发最让人抓狂的不是 Prompt 写不好而是你根本不知道它到底在干什么。一个基于 LangChain 的 RAG 助手用户问一句“帮我查下上季度的报销政策”表面上看是 3 秒返回实际上内部可能跑了 Embedding、向量检索、Rerank、LLM 决策、工具调用、再 LLM 总结整整六个环节。哪个环节慢了、哪个环节 Token 爆了、哪个工具被反复调用了全靠猜。SkyWalking 在这里扮演的角色就是给 Agent 装一个“行车记录仪”。它原本是 Apache 旗下的 APM 链路追踪工具在微服务领域用来追踪 HTTP、RPC、数据库调用现在通过 Python Agent 的runnable装饰器和自定义 Span可以把 LLM 调用、向量检索、工具执行这些 AI 特有的节点全部串成一条 Trace。你打开 SkyWalking UI看到的不再是黑盒而是一条带耗时、带 Tag、带层级关系的瀑布流。这篇文章适合两类人一是已经在用 LangChain 搭 Agent、但被延迟和 Token 成本折磨的开发者二是想把传统微服务可观测性经验迁移到 LLMOps 的运维同学。我会给出可复制的 SkyWalking 接入配置骨架、Agent 侧埋点代码、上报参数以及验证请求是否成功的具体动作。目标很明确把“黑盒推理”变成“可追踪的调用链”。2. 前置准备TaoToken 与 SkyWalking 环境怎么搭在讲埋点之前先把两个基础环境说清楚。一个是模型调用入口一个是链路追踪底座。模型调用这块我目前用的是 TaoToken 的 API 作为统一入口。它的好处是兼容 OpenAI 的接口格式LangChain 里ChatOpenAI只要改base_url和api_key就能直接切过去不用改业务代码。你可以在官网 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 注册后到控制台 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewrite 创建一个 API Key然后在 API Keys 页面 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 复制出来备用。接口地址是 https://taotoken.net/api 注意这个不带 UTM 参数直接填在base_url里即可。SkyWalking 这边你需要三样东西OAP Server负责接收和聚合数据、UI负责可视化、Python Agent负责在 Agent 应用里埋点上报。最省事的做法是用 Docker Compose 起一个单机版OAP 的 gRPC 端口默认 11800HTTP 端口 12800UI 默认 8080。Python Agent 通过pip install apache-skywalking安装然后在应用启动最前面初始化。这里有个容易踩的坑SkyWalking Python Agent 的初始化必须放在所有业务 import 之前否则部分自动埋点会失效。我试过把config.init写在 LangChain import 后面结果 HTTP 调用能追踪到但自定义的runnableSpan 死活不上报。后来把初始化挪到文件第一行才正常。3. 可复制配置SkyWalking 接入骨架与 Agent 埋点下面这套配置是我实际跑通的骨架你可以直接抄。先看环境变量和初始化部分。# skywalking_init.py # 必须在所有业务代码 import 之前执行 from skywalking import agent, config config.init( collector_address127.0.0.1:11800, # OAP gRPC 地址 service_namelangchain-agent-demo, # 服务名UI 上按这个筛选 service_instance_nameagent-node-01, # 实例名多副本时区分 agent_nameskywalking-python-agent, protocolgrpc, logging_levelINFO, trace_ignore_path/health,/metrics, # 忽略健康检查 sw_agent_collector_backend_services127.0.0.1:11800, ) agent.start()初始化完成后在 LangChain 的关键节点上加runnable装饰器。注意Layer的选择会影响 UI 上的图标和分类LLM 调用用Layer.Http向量库用Layer.Database工具执行用Layer.Function。# agent_trace.py from skywalking import Layer from skywalking.decorators import runnable from skywalking.trace.context import get_context from langchain_openai import ChatOpenAI from langchain_core.prompts import ChatPromptTemplate llm ChatOpenAI( modelgpt-4o-mini, base_urlhttps://taotoken.net/api, api_key你的_TaoToken_API_Key, temperature0.2, ) runnable(opVectorDB/Search, layerLayer.Database) def search_knowledge_base(query: str): span get_context().active_span() span.tag(db.system, milvus) span.tag(db.operation, similarity_search) span.tag(query.length, str(len(query))) # 这里替换成你真实的向量检索逻辑 docs [报销政策文档片段A, 报销政策文档片段B] span.tag(result.count, str(len(docs))) return docs runnable(opLLM/ChatCompletion, layerLayer.Http) def call_llm(prompt: str): span get_context().active_span() span.tag(llm.provider, taotoken) span.tag(llm.model, gpt-4o-mini) span.tag(llm.prompt_chars, str(len(prompt))) response llm.invoke(prompt) span.tag(llm.completion_chars, str(len(response.content))) return response.content runnable(opTool/Execute, layerLayer.Function) def execute_tool(tool_name: str, tool_input: str): span get_context().active_span() span.tag(tool.name, tool_name) span.tag(tool.input.length, str(len(tool_input))) # 模拟工具执行 return f{tool_name} 执行结果 def agent_flow(user_input: str): docs search_knowledge_base(user_input) context \n.join(docs) prompt f基于以下资料回答问题\n{context}\n\n问题{user_input} answer call_llm(prompt) return answer几个关键参数说明。collector_address填 OAP 的 gRPC 地址不是 UI 地址很多人第一次会填错。service_name在 UI 上会作为一级筛选条件建议按业务命名比如rag-assistant-prod。trace_ignore_path用来过滤掉健康检查这类无意义请求避免 Trace 列表被刷屏。如果你用的是 LangChain 的 AgentExecutor可以在AgentExecutor的callbacks里挂一个自定义 CallbackHandler在on_llm_start、on_tool_start、on_tool_end这些钩子里手动创建 Span。这样即使不用装饰器也能覆盖到 Agent 内部的决策循环。4. 验证请求怎么确认 Trace 真的上报成功了配置写完别急着优化先确认数据有没有上来。验证分三步。第一步本地跑一次agent_flow(报销流程是什么)观察控制台有没有 SkyWalking Agent 的启动日志和上报日志。正常情况你会看到类似SkyWalking Python Agent started和Reported trace segment的输出。如果只有启动日志没有上报日志说明 Span 没被创建检查runnable是否加在了被调用的函数上。第二步打开 SkyWalking UI默认地址http://localhost:8080。在顶部服务列表里找到langchain-agent-demo进入 Trace 页面。你应该能看到刚才那次请求的 Trace点进去是一条瀑布流最外层是agent_flow下面挂着VectorDB/Search、LLM/ChatCompletion两个子 Span每个 Span 右侧显示耗时。第三步点开LLM/ChatCompletion这个 Span在 Tags 区域确认llm.providertaotoken、llm.modelgpt-4o-mini、llm.prompt_chars这些自定义 Tag 是否都在。如果 Tag 缺失说明get_context().active_span()拿到的不是当前 Span可能是装饰器嵌套层级不对。验证通过后你可以做一个简单的延迟对比实验。在search_knowledge_base里加一个time.sleep(2)模拟慢查询重新跑一次然后在 UI 上看VectorDB/Search的耗时是不是变成了 2 秒以上。这一步能帮你确认耗时归因是准确的后面做优化时才有可信依据。如果你在验证模型调用是否正常返回可以先用模型对话页面 https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentchatutm_campaignrewrite 单独测一下 Key 和模型名是否匹配排除掉鉴权问题再回到链路追踪。5. 本篇常见错排查Trace 不上报、Span 断链、Tag 丢失接入过程中最容易遇到三类问题我按排查顺序列一下。问题一UI 上完全看不到服务。先确认 OAP 的 11800 端口是否可达用telnet 127.0.0.1 11800测一下。如果 OAP 在容器里注意collector_address不能填localhost要填宿主机的局域网 IP 或者容器网络里的服务名。另外检查service_name是否和 UI 筛选条件一致有时候服务其实上报了只是被过滤条件挡住了。问题二Trace 有但 Span 是断开的LLM 调用没挂在 Agent 主链路上。这通常是上下文传递问题。SkyWalking Python Agent 依赖线程上下文来串联 Span如果你在 LangChain 里用了异步或者多线程runnable装饰的 Span 可能变成独立 Trace。解决办法是在异步函数里手动用with get_context().new_span(...)创建子 Span或者改用 SkyWalking 的ContextCarrier做跨线程传递。问题三自定义 Tag 在 UI 上不显示。检查两点一是span.tag()的 key 不要用中文或特殊字符建议用llm.prompt_chars这种点分命名二是 Tag 的 value 必须是字符串传 int 或 float 会被静默忽略。我踩过一次坑span.tag(token.count, 1500)死活不显示改成str(1500)就出来了。还有一个隐蔽问题如果你同时装了多个 APM 探针比如 SkyWalking 和 OpenTelemetry可能会出现 Span 冲突导致数据错乱。建议一个应用只保留一个探针或者在初始化时显式关闭自动埋点只保留手动埋点。6. 从 Trace 到优化让 Agent 的每一步都有据可查链路追踪的价值不在于“看到”而在于“看到之后能改”。有了 SkyWalking 的 Trace 数据你可以做三件很实际的事。第一件是延迟归因。把VectorDB/Search、LLM/ChatCompletion、Tool/Execute的 P99 耗时拉出来对比一眼就能看出瓶颈在检索还是在生成。我之前的项目里一直以为 LLM 慢结果 Trace 显示向量检索占了 60% 的时间把 Embedding 服务从 CPU 迁到 GPU 后整体延迟降了四成。第二件是 Token 成本追踪。通过llm.prompt_chars和llm.completion_chars这两个 Tag你可以在 SkyWalking 的聚合查询里按服务、按时间段统计字符消耗量再结合模型单价估算成本。如果发现某个工具的 System Prompt 特别长就可以针对性做 Prompt 压缩。第三件是异常告警。SkyWalking 支持基于 Trace 指标的告警规则比如“单条 Trace 内LLM/ChatCompletion调用次数超过 5 次”就触发告警。这能帮你抓住 Agent 死循环——它在“思考-行动”里反复横跳却不产出结果时Token 正在被无限消耗。如果你打算把 Agent 长期跑在生产环境建议把 Coding Plan 也配上地址是 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 它更适合需要持续调用、长期编码和 Agent 场景的用量模式。接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 里面有 LangChain、LlamaIndex 这些框架的对接示例配合 SkyWalking 的埋点一起用基本能把 Agent 的可观测性闭环搭起来。最后说一个我自己的习惯每次上线新版本的 Agent先跑一轮固定测试用例然后在 SkyWalking 里对比新旧版本的 Trace 耗时分布和 Token 消耗。数据不会骗人哪次改动引入了性能回退链路图上一目了然。