ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

基于 Spring AI + Skill 工程 + MCP 技术方案研究:用 TaoToken 统一 Key 打通通义千问法律知识库

基于 Spring AI + Skill 工程 + MCP 技术方案研究:用 TaoToken 统一 Key 打通通义千问法律知识库 1. 法律知识库问答为什么需要 Spring AI Skill MCP 三层配合法律知识库问答和普通文档问答最大的区别在于答案必须可追溯、条款必须准确、工具调用必须可控。我见过不少团队直接用一段 Prompt 把法条塞进上下文结果模型把《民法典》第 584 条和第 577 条混着说用户一问细节就露馅。真正能上生产的方案需要把「模型能力」「领域技能」「外部工具」拆成三层来管。Spring AI 负责的是模型抽象层。它把 ChatModel、EmbeddingModel、VectorStore 这些接口统一起来你换模型时不用改业务代码。Skill 工程负责的是领域能力层把「合同条款提取」「法条检索」「风险评估」这些动作封装成可被模型按需加载的技能而不是一股脑塞进系统提示。MCP 负责的是工具调用层让模型通过标准协议去调用 OCR、向量检索、图数据库查询这些外部能力。这三层配合起来法律知识库问答才能做到模型知道什么时候该查法条、查哪个库、查到之后怎么组织答案。而 TaoToken 在这里的角色是统一 Key 和 API 通道——你不需要为通义千问、Embedding 模型、OCR 工具分别维护不同的鉴权配置一个 Key 走同一个通道配置和排障都简单很多。这篇会给出 application.yml 的可复制配置骨架、MCP Server 注册与 Skill 编排示例以及一次法律条文检索问答的完整验证动作。目标是你照着跑一遍端到端链路能通。2. TaoToken 前置统一 Key 与 API 通道准备在写 Spring AI 配置之前先把 Key 和通道准备好。TaoToken 的定位是统一 API 通道你可以在控制台创建 Key然后所有模型调用都走同一个 base-url。这样做的好处是Spring AI 里只需要配一份 api-key不用为每个模型单独管理凭证。具体操作路径访问官网 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 注册后进入控制台在 API Keys 页面创建一个新 Key。创建时建议按项目命名比如legal-kb-dev方便后续区分环境。拿到 Key 之后API 通道地址是 https://taotoken.net/api注意这个地址不加 UTM 参数直接作为 base-url 使用。Spring AI 的 OpenAI 兼容模式可以直接对接这个地址因为 TaoToken 提供的是 OpenAI 兼容接口。如果你需要确认模型名称和可用列表可以打开模型对话页面实际发一条消息测试。对于法律知识库场景通义千问系列的中文理解能力比较适合Embedding 模型用于向量检索。Coding Plan 更适合长期编码和 Agent 场景如果你后续要把这套链路做成常驻服务可以考虑。注意Key 不要硬编码在代码里用环境变量或配置中心注入。下面 application.yml 里我用${TAOTOKEN_API_KEY}占位。3. 可复制配置application.yml 与 Spring AI 接入骨架先给出完整的 application.yml 配置骨架。这份配置的核心是把 TaoToken 作为统一通道同时配置 Chat 模型和 Embedding 模型。spring: ai: openai: api-key: ${TAOTOKEN_API_KEY} base-url: https://taotoken.net/api chat: options: model: qwen-plus temperature: 0.3 max-tokens: 2048 embedding: options: model: text-embedding-v3 vectorstore: type: simple simple: initialize-schema: true mcp: server: name: legal-kb-mcp version: 1.0.0 transport: sse endpoint: /mcp/sse legal: kb: top-k: 5 similarity-threshold: 0.72 max-context-chars: 6000这里有几个参数需要解释。temperature设成 0.3 是因为法律问答需要稳定输出不能太发散。top-k: 5表示每次检索召回 5 条法条或案例similarity-threshold: 0.72是相似度阈值低于这个值的召回结果会被过滤掉避免无关法条污染上下文。max-context-chars: 6000控制注入模型的法律上下文长度防止超出模型窗口。接下来是 Spring AI 的 ChatClient 配置类。这里我把 Skill 的提示增强和 MCP 工具注册都挂上去。Configuration public class LegalAiConfig { Bean public ChatClient chatClient(ChatModel chatModel, SkillRegistry skillRegistry, McpToolCallbackProvider mcpTools) { return ChatClient.builder(chatModel) .defaultSystem( 你是法律知识库问答助手。回答必须基于检索到的法条和案例 引用时标注法条编号。如果检索结果不足以回答明确说明。 ) .defaultAdvisors( SkillPromptAugmentAdvisor.builder() .skillRegistry(skillRegistry) .build() ) .defaultTools(mcpTools) .build(); } }SkillPromptAugmentAdvisor的作用是把 Skill 的元数据注入系统提示模型在需要时通过read_skill加载完整技能文档。McpToolCallbackProvider负责把 MCP Server 暴露的工具注册成 Spring AI 可调用的 ToolCallback。Skill 的定义我放在classpath:skills目录下每个 Skill 一个 Markdown 文件。比如法条检索技能--- name: legal_provision_search description: 根据关键词或语义检索法律法规条文 tools: - mcp__legal_kb__search_provisions --- ## 使用场景 当用户询问具体法律条文、合规依据时调用此技能。 ## 执行步骤 1. 提取用户问题中的法律概念关键词 2. 调用 search_provisions 工具传入关键词和 top_k 3. 对返回结果按相似度排序过滤低于阈值的条目 4. 将法条原文和编号组织成回答MCP Server 的注册配置如下。这里用 SSE 传输方式Spring AI 的 MCP 客户端会自动发现工具列表。spring: ai: mcp: client: sse: connections: legal-kb: url: http://localhost:8081/mcp/sse sse-endpoint: /mcp/sseMCP Server 端我用一个简化的 Controller 暴露法条检索工具RestController public class LegalKbMcpController { private final LegalKnowledgeBase knowledgeBase; public LegalKbMcpController(LegalKnowledgeBase knowledgeBase) { this.knowledgeBase knowledgeBase; } Tool(name search_provisions, description 根据关键词检索法律法规条文返回法条编号、内容和相似度) public ListProvisionResult searchProvisions( ToolParam(keyword) String keyword, ToolParam(topK) int topK) { return knowledgeBase.semanticSearch(keyword, topK); } Tool(name search_cases, description 检索与问题相关的司法案例) public ListCaseResult searchCases( ToolParam(caseType) String caseType, ToolParam(facts) String facts) { return knowledgeBase.searchSimilarCases(caseType, facts); } }4. 验证请求一次法律条文检索问答的完整动作配置写完之后最关键的是验证端到端链路能不能通。我设计了一个最小验证场景用户问「服务合同违约金过高可以调整吗」系统应该检索到《民法典》第 585 条并给出可追溯的回答。先写一个测试 ControllerRestController RequestMapping(/api/legal) public class LegalQaController { private final ChatClient chatClient; public LegalQaController(ChatClient chatClient) { this.chatClient chatClient; } PostMapping(/ask) public QaResponse ask(RequestBody QaRequest request) { String answer chatClient.prompt() .user(request.question()) .call() .content(); return new QaResponse(answer); } }启动应用后用 curl 发一条请求curl -X POST http://localhost:8080/api/legal/ask \ -H Content-Type: application/json \ -d {question:服务合同约定的违约金过高可以请求调整吗}预期返回应该包含几个关键要素引用《民法典》第 585 条关于违约金调整的规定说明「约定的违约金过分高于造成的损失的人民法院或者仲裁机构可以根据当事人的请求予以适当减少」并且标注法条编号。实际跑下来模型会先调用legal_provision_search技能通过 MCP 工具检索到相关法条然后组织回答。如果你在日志里看到 MCP 工具调用记录和法条召回结果说明链路是通的。验证成功的标志有三个第一回答里出现了具体的法条编号而不是泛泛而谈第二日志里有 MCP 工具调用记录第三检索到的法条相似度分数在阈值以上。如果这三点都满足端到端链路就跑通了。5. 本篇常见错排查5.1 401 鉴权失败或 base-url 配错最常见的问题是 api-key 没注入成功或者 base-url 写成了带路径的地址。检查两点环境变量TAOTOKEN_API_KEY是否在启动时生效base-url 是否严格是https://taotoken.net/api。如果用了 IDE 启动确认 Run Configuration 里加了环境变量。5.2 MCP 工具注册不上模型不调用如果模型回答时完全不调用工具先检查 MCP Server 是否正常启动SSE 端点是否可访问。可以在浏览器直接打开http://localhost:8081/mcp/sse看是否有事件流返回。另外确认McpToolCallbackProvider是否被正确注入到 ChatClient工具名称是否和 Skill 文档里声明的一致。5.3 检索结果不相关或法条召回为空这通常是 Embedding 模型配置问题或相似度阈值设太高。先把similarity-threshold降到 0.6 测试如果还是召回为空检查向量库是否已经写入了法条数据。另外确认 Embedding 模型名称和 TaoToken 通道支持的模型一致模型名写错会导致向量维度不匹配。5.4 回答超出上下文长度被截断法律问答容易召回大量法条如果max-context-chars设太大会挤占模型输出空间。建议控制在 6000 字符以内同时对召回结果做去重和排序只保留最相关的 top-k 条。如果单条法条太长可以在 Skill 里做摘要预处理。5.5 Skill 加载失败或提示注入无效检查classpath:skills目录下的 Markdown 文件格式front matter 的name和description必须存在。如果 Skill 没被加载模型就不知道有这个技能可用。可以在启动日志里搜索 SkillRegistry 的加载记录确认技能数量符合预期。6. 继续接入与长期运行的建议如果你要把这套链路做成长期运行的服务建议把 Coding Plan 用起来它更适合常驻 Agent 和编码场景Key 管理和额度控制也更清晰。接入文档在 https://taotoken.net/api-keys 和 https://taotoken.net/doc 可以查到完整的参数说明和错误码对照。模型对话页面适合快速验证模型可用性和回答质量在正式接入前先用它测几条法律问题确认通义千问在你这个领域的表现符合预期。控制台的 API Keys 页面可以创建多个 Key 做环境隔离开发、测试、生产各用一个排障时不会互相干扰。实测下来法律知识库问答的难点不在模型本身而在检索质量和工具调用的可控性。Skill 工程把领域逻辑从 Prompt 里抽出来MCP 把外部工具标准化Spring AI 把模型调用统一起来这三层各司其职链路才稳定。你可以先从一条法条检索跑通再逐步加案例检索和风险评估技能不要一上来就铺大摊子。
返回列表