Spring Ai Alibaba Graph 集成 Langfuse 观测—快速上手

原文链接:Spring Ai Alibaba Graph 集成 Langfuse 观测—快速上手

[!TIP]
Graph 观测,可对每个节点的输入、输出、执行状态、异常等进行实时追踪和流式采集,可帮助开发者快速理解复杂链路数据流转,还可为性能分析、异常定位提供帮助

本期先带来快速上手教程(代码零入侵,即可观测 Graph 相关信息),后面会出文章讲解 Graph 观测的架构设计等

实战代码可见:https://github.com/GTyingzi/spring-ai-tutorial 的 graph 目录下的 observe-langfuse 模块

pom.xml

<properties>
    <!-- Spring AI -->
    <spring-ai.version>1.0.1</spring-ai.version>
    <!-- Spring Boot -->
    <spring-boot.version>3.4.5</spring-boot.version>
    <!-- Spring AI Alibaba -->
    <spring-ai-alibaba.version>1.0.0.3</spring-ai-alibaba.version>
</properties>

<dependencyManagement>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-dependencies</artifactId>
        <version>${spring-boot.version}</version>
        <type>pom</type>
        <scope>import</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-bom</artifactId>
        <version>${spring-ai.version}</version>
        <type>pom</type>
        <scope>import</scope>
    </dependency>
    <dependency>
        <groupId>com.alibaba.cloud.ai</groupId>
        <artifactId>spring-ai-alibaba-bom</artifactId>
        <version>${spring-ai-alibaba.version}</version>
        <type>pom</type>
        <scope>import</scope>
    </dependency>
    <dependencies>
        <dependency>
            <groupId>io.opentelemetry.instrumentation</groupId>
            <artifactId>opentelemetry-instrumentation-bom</artifactId>
            <version>2.17.0</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<dependencies>

    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-autoconfigure-model-openai</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.ai</groupId>
        <artifactId>spring-ai-autoconfigure-model-chat-client</artifactId>
    </dependency>

    <dependency>
        <groupId>com.alibaba.cloud.ai</groupId>
        <artifactId>spring-ai-alibaba-graph-core</artifactId>
        <version>${spring-ai-alibaba.version}</version>
    </dependency>

    <dependency>
        <groupId>com.alibaba.cloud.ai</groupId>
        <artifactId>spring-ai-alibaba-starter-graph-observation</artifactId>
        <version>${spring-ai-alibaba.version}</version>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>io.opentelemetry.instrumentation</groupId>
        <artifactId>opentelemetry-spring-boot-starter</artifactId>
    </dependency>
    <!-- Spring Boot Actuator for observability support -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <!-- Micrometer Observation -> OpenTelemetry bridge -->
    <dependency>
        <groupId>io.micrometer</groupId>
        <artifactId>micrometer-tracing-bridge-otel</artifactId>
    </dependency>
    <!-- OpenTelemetry OTLP exporter for traces -->
    <dependency>
        <groupId>io.opentelemetry</groupId>
        <artifactId>opentelemetry-exporter-otlp</artifactId>
    </dependency>
</dependencies>

application.yml

server:
  port: 8080
spring:
  application:
    name: observe-langfuse
  profiles:
    # LangFuse可观测配置
    include: observability
  ai:
    openai:
      api-key: ${AIDASHSCOPEAPIKEY}
      base-url: https://dashscope.aliyuncs.com/compatible-mode
      chat:
        options:
          model: qwen-max

    alibaba:
      graph:
        observation:
          enabled: true
  1. 为了让配置文件更清晰,这里单独把观测配置抽离出来 spring.profiles.include = observability
  2. 开启 graph 观测 spring.ai.alibaba.graph.observation = true

application-observability.yml 文件如下,在前文中已经介绍过 langfuse 如何配的了集成 Langfuse

# OpenTelemetry Observation configuration for Langfuse integration
management:
  endpoints:
    web:
      exposure:
        include: "*"
  endpoint:
    health:
      # health status check with detailed messages
      # show-details: always
      access:
  tracing:
    sampling:
      # trace information with every request
      probability: 1.0
  observations:
    annotations:
      enabled: true

# OpenTelemetry configuration
otel:
  service:
    name: spring-ai-alibaba-deepresearch-langfuse
  resource:
    attributes:
      deployment.environment: development
  # configure exporter
  traces:
    exporter: otlp
    sampler: alwayson
  metrics:
    exporter: otlp
  # logs exportation inhibited for langfuse currently cannot support
  logs:
    exporter: none
  exporter:
    otlp:
      # OpenTelemetry exporter endpoint configuration. For details, refer to the official Langfuse documentation: https://langfuse.com/docs/opentelemetry/get-started
      endpoint: "https://us.cloud.langfuse.com/api/public/otel" # 🇺🇸 US data region
      headers:
        Authorization: "Basic ${YOURBASE64ENCODEDCREDENTIALS}" # echo -n "pk-xxx:sk-xxx" | base64
      protocol: http/protobuf

config

package com.spring.ai.tutorial.graph.observe.config;

import com.alibaba.cloud.ai.graph.GraphRepresentation;
import com.alibaba.cloud.ai.graph.KeyStrategy;
import com.alibaba.cloud.ai.graph.KeyStrategyFactory;
import com.alibaba.cloud.ai.graph.StateGraph;
import com.alibaba.cloud.ai.graph.exception.GraphStateException;
import com.alibaba.cloud.ai.graph.state.strategy.ReplaceStrategy;
import com.spring.ai.tutorial.graph.observe.node.ExpanderNode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.HashMap;

import static com.alibaba.cloud.ai.graph.action.AsyncNodeAction.nodeasync;

/**
 * @author yingzi
 * @since 2025/6/13
 */
@Configuration
public class GraphConfiguration {

    private static final Logger logger = LoggerFactory.getLogger(GraphConfiguration.class);

    @Bean
    public StateGraph simpleGraph(ChatClient.Builder chatClientBuilder) throws GraphStateException {
        KeyStrategyFactory keyStrategyFactory = () -> {
            HashMap<String, KeyStrategy> keyStrategyHashMap = new HashMap<>();

            // 用户输入
            keyStrategyHashMap.put("query", new ReplaceStrategy());
            keyStrategyHashMap.put("expandernumber", new ReplaceStrategy());
            keyStrategyHashMap.put("expandercontent", new ReplaceStrategy());
            return keyStrategyHashMap;
        };

        StateGraph stateGraph = new StateGraph(keyStrategyFactory)
                .addNode("expander", nodeasync(new ExpanderNode(chatClientBuilder)))
                .addEdge(StateGraph.START, "expander")
                .addEdge("expander", StateGraph.END);

        // 添加 PlantUML 打印
        GraphRepresentation representation = stateGraph.getGraph(GraphRepresentation.Type.PLANTUML,
                "expander flow");
        logger.info("\n=== expander UML Flow ===");
        logger.info(representation.content());
        logger.info("==================================\n");

        return stateGraph;
    }
}

node

ExpanderNode
  • PromptTemplate DEFAULTPROMPTTEMPLATE:扩展文本的提示词
  • ChatClient chatClient:调用 AI 模型的 client 端
  • Integer NUMBER:默认扩展为 3 条相似问题

最后将 AI 模型的响应内容返回给给到字段 expandercontent 中

package com.spring.ai.tutorial.graph.node;

import com.alibaba.cloud.ai.graph.NodeOutput;
import com.alibaba.cloud.ai.graph.OverAllState;
import com.alibaba.cloud.ai.graph.action.NodeAction;
import com.alibaba.cloud.ai.graph.streaming.StreamingChatGenerator;
import org.bsc.async.AsyncGenerator;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.PromptTemplate;
import reactor.core.publisher.Flux;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ExpanderNode implements NodeAction {

    private static final PromptTemplate DEFAULTPROMPTTEMPLATE = new PromptTemplate("You are an expert at information retrieval and search optimization.\nYour task is to generate {number} different versions of the given query.\n\nEach variant must cover different perspectives or aspects of the topic,\nwhile maintaining the core intent of the original query. The goal is to\nexpand the search space and improve the chances of finding relevant information.\n\nDo not explain your choices or add any other text.\nProvide the query variants separated by newlines.\n\nOriginal query: {query}\n\nQuery variants:\n");

    private final ChatClient chatClient;

    private final Integer NUMBER = 3;

    public ExpanderNode(ChatClient.Builder chatClientBuilder) {
        this.chatClient = chatClientBuilder.build();
    }

    @Override
    public Map<String, Object> apply(OverAllState state) throws Exception {
        String query = state.value("query", "");
        Integer expanderNumber = state.value("expandernumber", this.NUMBER);


        Flux<String> streamResult = this.chatClient.prompt().user((user) -> user.text(DEFAULTPROMPTTEMPLATE.getTemplate()).param("number", expanderNumber).param("query", query)).stream().content();
        String result = streamResult.reduce("", (acc, item) -> acc + item).block();
        List<String> queryVariants = Arrays.asList(result.split("\n"));

        HashMap<String, Object> resultMap = new HashMap<>();
        resultMap.put("expandercontent", queryVariants);
        return resultMap;
    }
}

controller

package com.spring.ai.tutorial.graph.observe.controller;

import com.alibaba.cloud.ai.graph.CompileConfig;
import com.alibaba.cloud.ai.graph.CompiledGraph;
import com.alibaba.cloud.ai.graph.OverAllState;
import com.alibaba.cloud.ai.graph.RunnableConfig;
import com.alibaba.cloud.ai.graph.StateGraph;
import com.alibaba.cloud.ai.graph.exception.GraphRunnerException;
import com.alibaba.cloud.ai.graph.exception.GraphStateException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

/**
 * @author yingzi
 * @since 2025/6/13
 */
@RestController
@RequestMapping("/graph")
public class SimpleGraphController {

    private static final Logger logger = LoggerFactory.getLogger(SimpleGraphController.class);

    private final CompiledGraph compiledGraph;

    public SimpleGraphController(@Qualifier("simpleGraph") StateGraph stateGraph, CompileConfig observationCompileConfig) throws GraphStateException {
        this.compiledGraph = stateGraph.compile(observationCompileConfig);
    }

    @GetMapping(value = "/expand")
    public Map<String, Object> expand(@RequestParam(value = "query", defaultValue = "你好,我的外号是影子,请记住呀!", required = false) String query,
                                                @RequestParam(value = "expandernumber", defaultValue = "3", required = false) Integer  expanderNumber,
                                                @RequestParam(value = "threadid", defaultValue = "yingzi", required = false) String threadId) throws GraphRunnerException {
        RunnableConfig runnableConfig = RunnableConfig.builder().threadId(threadId).build();
        Map<String, Object> objectMap = new HashMap<>();
        objectMap.put("query", query);
        objectMap.put("expandernumber", expanderNumber);
        Optional<OverAllState> invoke = this.compiledGraph.invoke(objectMap, runnableConfig);
        return invoke.map(OverAllState::data).orElse(new HashMap<>());
    }}

这里 CompileConfig observationCompileConfig 带了观测信息,可以定位到 GraphObservationAutoConfiguration 自动注入类

效果

往期资料

Spring AI + Spring Ai Aliabba系统化学习资料

本教程将采用2025年5月20日正式的GA版,给出如下内容

  1. 核心功能模块的快速上手教程
  2. 核心功能模块的源码级解读
  3. Spring ai alibaba增强的快速上手教程 + 源码级解读

版本:

  • JDK21
  • SpringBoot3.4.5
  • SpringAI 1.0.1
  • SpringAI Alibaba 1.0.3+

免费渠道:

  1. 为Spring Ai Alibaba开源社区解决解决有效的issue or 提供有价值的PR,可免费获取上述教程
  2. 往届微信推文

收费服务:收费69.9元

  1. 飞书在线云文档
  2. Spring AI会员群教程代码答疑
  3. 若Spring AI、Spring AI Alibaba教程内容无法满足业务诉求,可定制提供解决方案,带价私聊

学习交流圈

你好,我是影子,曾先后在🐻、新能源、老铁就职,兼任Spring AI Alibaba开源社区的Committer。目前新建了一个交流群,一个人走得快,一群人走得远,另外,本人长期维护一套飞书云文档笔记,涵盖后端、大数据系统化的面试资料,可私信免费获取

Spring AI Alibaba 主要聚焦于简化 Java 开发者在人工智能应用开发中的复杂度,提供高层次的 AI API 抽象和与云原生基础设施的深度集成方案。尽管其核心功能主要围绕自然语言处理、图像生成、语音合成等 AI 服务展开[^3],但其设计哲学和架构模式也为集成更广泛的 AI 技术(如图计算)提供了可能性。 图计算是一种处理图结构数据的计算范式,广泛应用于社交网络分析、推荐系统、知识图谱等领域。虽然目前提供的引用中并未明确提及 Spring AI Alibaba 对图计算技术的直接支持[^1],但可以从以下几个方面推测其潜在的应用或集成方式: ### 图计算技术的潜在集成路径 1. **基于统一 API 的抽象集成** Spring AI Alibaba 提供了统一的 API 接口,使得开发者能够以一致的方式调用不同类型的 AI 服务[^3]。这种设计思想可以扩展到图计算领域,例如通过定义图计算服务的抽象接口(如 `GraphComputationService`),并实现对不同图计算引擎(如 Apache Giraph、GraphX、阿里云图计算服务)的适配。这样,开发者可以通过简单的配置切换底层图计算引擎。 2. **与 Spring Cloud Alibaba 生态的融合** Spring AI AlibabaSpring Cloud Alibaba 的深度集成使得其能够借助后者的服务发现、配置管理、负载均衡等能力[^4]。在图计算场景中,这种能力可以用于构建分布式的图计算服务,支持图数据的分片处理、任务调度与结果聚合。 3. **本地部署与开源生态支持** Spring AI Alibaba 支持本地部署及与主流 AI 框架的集成[^3]。对于图计算来说,这意味着可以与如 Neo4j、JanusGraph 等图数据库进行集成,或者与 Apache TinkerPop 等图计算框架结合,构建完整的图数据处理与分析流水线。 4. **AI 与图计算的联合应用** 在推荐系统、社交网络分析等场景中,AI 与图计算常常需要联合使用。例如,使用图计算挖掘用户之间的关系网络,再结合 AI 模型进行用户兴趣预测。Spring AI Alibaba 可以通过其 AI 服务与图计算服务的协同调用,提供端到端的解决方案。 ### 示例:图计算服务的抽象接口定义 ```java public interface GraphComputationService { /** * 执行图计算任务 * @param graphData 图数据(如邻接表或边列表) * @param algorithm 计算算法(如 PageRank、最短路径等) * @return 计算结果 */ Map<String, Object> computeGraph(String graphData, String algorithm); } ``` ### 示例:基于阿里云图计算服务的实现 ```java @Service public class AliyunGraphComputationServiceImpl implements GraphComputationService { private final GraphComputeClient graphComputeClient; public AliyunGraphComputationServiceImpl(GraphComputeClient graphComputeClient) { this.graphComputeClient = graphComputeClient; } @Override public Map<String, Object> computeGraph(String graphData, String algorithm) { // 调用阿里云图计算服务 return graphComputeClient.invoke(graphData, algorithm); } } ``` ### 示例:通过配置切换图计算引擎 ```yaml graph: computation: provider: aliyun # 可选值:aliyun, neo4j, giraph 等 ``` ### 展望与建议 尽管目前 Spring AI Alibaba 的核心功能集中在通义系列大模型的集成,但其模块化设计和高度抽象的 API 为图计算技术的集成提供了良好的基础。开发者可以基于现有框架进行扩展,或期待未来官方对图计算领域的进一步支持。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值