一、docker镜像无法下载时
如果无法访问docker官方镜像源 https://registry-1.docker.io,那么需要替换国内镜像源
root用户执行vi /etc/docker/daemon.json
添加:
“registry-mirrors” :
[
“https://docker.domys.cc”,
“https://hub.domys.cc”,
“https://docker.m.daocloud.io”,
“https://docker.xuanyuan.me”,
“https://docker.1ms.run”
]
重启Docker服务
sudo systemctl daemon-reload
sudo systemctl restart docker
二、demo
#!/usr/bin/env python # -*- coding: utf-8 -*- """ LangGraph + LangFuse 集成演示 LangFuse 基于 OpenTelemetry 架构,提供两种追踪方式: 方式1(推荐):@observe 装饰器 - 最简洁,直接修饰函数 - 自动追踪函数内的所有 LLM 调用 - 支持嵌套:被装饰的函数互相调用时,自动形成父子 span 方式2:@observe + OTEL span 属性 - 适用于需要动态传入 user_id / session_id / tags 的场景 - 通过 OpenTelemetry span 属性注入用户上下文 环境变量配置(Windows PowerShell): $env:OPENAI_API_KEY="sk-xxx" $env:OPENAI_BASE_URL="https://api.openai.com/v1" $env:LANGFUSE_PUBLIC_KEY="pk-lf-xxx" $env:LANGFUSE_SECRET_KEY="sk-lf-xxx" $env:LANGFUSE_BASE_URL="http://172.31.234.9:3000" """ import os import uuid import logging from typing import TypedDict, Optional import warnings warnings.filterwarnings("ignore") # 修复 langchain 版本兼容性 import langchain for attr in ('verbose', 'debug', 'llm_cache'): if not hasattr(langchain, attr): setattr(langchain, attr, False if attr != 'llm_cache' else None) # ========== 替换为 langchain_openai ========== from langchain_openai import ChatOpenAI from langchain_core.prompts import ChatPromptTemplate from langchain_core.output_parsers import StrOutputParser from langgraph.graph import StateGraph, END # LangFuse 导入 from langfuse import observe, get_client os.environ["LANGFUSE_PUBLIC_KEY"] = "pk-lf-xxx" os.environ["LANGFUSE_SECRET_KEY"] = "sk-lf-xxx" os.environ["LANGFUSE_BASE_URL"] = "http://ip:3000" # 抑制 OpenTelemetry 网络超时日志 logging.getLogger("opentelemetry").setLevel(logging.CRITICAL) # ==================== 全局配置 ==================== LANGFUSE_ENABLED = bool( os.getenv("LANGFUSE_PUBLIC_KEY") and os.getenv("LANGFUSE_SECRET_KEY") ) # 使用 ChatOpenAI,可兼容 OpenAI / 通义 / DeepSeek 等 OpenAI‑兼容接口 llm = ChatOpenAI( model="qwen3.8-27b", api_key="sk-xxxxx", base_url="https://dashscope.aliyuncs.com/compatible-mode/v1", temperature=0, ) # ====== 方式1:@observe 装饰器(推荐) ====== @observe(as_type="generation") def call_llm(prompt_text: str, model_name: str = "gpt-3.5-turbo") -> str: prompt = ChatPromptTemplate.from_template("{text}") chain = prompt | llm | StrOutputParser() result = chain.invoke({"text": prompt_text}) get_client().update_current_generation( model=model_name, input=prompt_text, output=result, ) return result @observe() def translate(text: str) -> str: return call_llm(f"请将以下内容翻译成英文,只返回译文:\n{text}") @observe() def summarize(text: str) -> str: return call_llm(f"请用一句话总结以下内容:\n{text}") @observe() def qa(question: str) -> str: return call_llm(f"请用一句话回答:{question}") @observe(name="multi_tool_agent") def agent_entry(user_input: str): answer = qa(user_input) summary = summarize(answer) translated = translate(summary) return {"answer": answer, "summary": summary, "translated": translated} # ====== 方式2:@observe + 动态设置 trace 属性 ====== class State(TypedDict): question: str answer: Optional[str] def chat_node(state: State) -> dict: answer = call_llm(f"请用一句话回答:{state['question']}") return {"answer": answer} def build_graph(): graph = StateGraph(State) graph.add_node("chat", chat_node) graph.set_entry_point("chat") graph.add_edge("chat", END) return graph.compile() @observe(as_type="chain") def traced_graph_invoke(question, user_id, session_id, tags=None, metadata=None): from opentelemetry import trace as otel_trace span = otel_trace.get_current_span() if span.is_recording(): span.set_attribute("langfuse.user.id", user_id) span.set_attribute("langfuse.session.id", session_id) if tags: span.set_attribute("langfuse.tags", tags) if metadata: get_client().update_current_span(metadata=metadata) app = build_graph() return app.invoke({"question": question}) # ====== 运行演示 ====== def demo_observe_decorator(): print("\n" + "=" * 60) print("方式1:@observe 装饰器") print("=" * 60) result = agent_entry("什么是大语言模型?") print(f" 回答: {result['answer']}") print(f" 摘要: {result['summary']}") print(f" 译文: {result['translated']}") def demo_observe_with_context(): print("\n" + "=" * 60) print("方式2:@observe + 动态上下文") print("=" * 60) session_id = f"session-{uuid.uuid4().hex[:8]}" questions = [ ("user_001", "什么是 Python?"), ("user_001", "它和 Java 有什么区别?"), ("user_002", "推荐一个入门编程语言"), ] for user_id, question in questions: print(f"\n [{user_id}] {question}") result = traced_graph_invoke( question=question, user_id=user_id, session_id=session_id, tags=["langgraph", "multi-turn"], metadata={"app_version": "1.0.0"}, ) print(f" 助手: {result['answer']}") if LANGFUSE_ENABLED: get_client().flush() if __name__ == "__main__": print(f"LangFuse: {'已启用' if LANGFUSE_ENABLED else '未配置(跳过追踪)'}") demo_observe_decorator() demo_observe_with_context() if LANGFUSE_ENABLED: get_client().flush() print("\n运行完毕。在 LangFuse 控制台可查看追踪数据。")参考资料
1.https://blog.csdn.net/leonhongliang806/article/details/148711169