刘亦菲大战金刚3

核心内容摘要

绝美三国,泪洒铁球——高清壁纸下的绝代美人小乔
跨越感官的艺术巅峰:深度剖析MEYD-881的剧情魅力与震撼画面

全网都在搜“掇bbbb掇bbbb掇”,这背后究竟藏着什么秘密?

作者来自 Elastic Tomás Murúa学习如何将 Discord 连接到 Elastic Agent Builder 的 Agent-to-Agent A2A 服务器以创建游戏社区支持 bot。

Agent Builder 现已正式发布。

通过 Elastic Cloud Trial 开始使用并在此查看 Agent Builder 的文档。

在这篇文章中我们将构建一个游戏社区支持机器人把 Discord 连接到 Elastic Agent Builder 的 Agent-to-AgentA2A服务器。

玩家可以提出像 “谁是最强的 Mage魔术师”或“当前的 meta 是什么”这样的问题并通过 Elasticsearch Query LanguageES|QL分析和语义搜索获得实时答案。

许多游戏公司已经在使用 Elasticsearch 来处理玩家数据和游戏分析。

在本教程中我们将通过 Discord 访问这些数据而 Discord 正是许多用户日常活跃的平台。

前置条件Elasticsearch 集群

2 或更高版本Python

9已创建的 Discord 机器人 token 和服务器我们要构建的内容我们将创建一个 Discord 机器人使用 Elastic Agent Builder 的 A2A 服务器来回答玩家问题。

这个机器人将有两类工具用于分析的ES|QL 工具排行榜、英雄统计、meta 报告。

用于知识的索引搜索 工具游戏机制、

常见问题解答 FAQ 。

架构如下所示架构概览Elastic Agent Builder 提供了一个 A2A 服务器用于与客户端连接。

该服务器暴露了一个 agent并提供可以使用 ES|QL 或 索引搜索工具来查询 Elasticsearch 的工具。

任何兼容 A2A 的客户端都可以连接到它。

A2A 客户端会实例化一个机器人 该机器人可以连接到 Discord 服务器与 Agent Builder 通信并向用户接收 / 发送消息。

为什么使用 A2A 而不是 MCP 来源 https://developers.googleblog.com/en/a2a-a-new-era-of-agent-interoperability/Agent Builder 还提供通过 Model Context ProtocolMCP服务器暴露 agent 工具的选项。

关键区别在于使用 MCP 时客户端只能访问工具及其描述而不能访问整个 agent。

此外工具选择逻辑必须在 MCP 客户端实现因为所有 agent 的工具会被一起暴露。

使用 A2A 时整个 agent包括指令和工具都可供客户端使用。

这让你可以从 Agent Builder 端获得更多控制权从而集中管理行为而不是在每个客户端分别管理。

哪种方式更合适取决于你希望控制权存在的位置。

对于这个 Discord 机器人我们希望从 Elastic 管理 agent 的行为因此 A2A 更适合。

设置示例游戏数据我们来创建 机器人 可以查询的游戏数据。

我们将设置三个索引player_stats玩家档案包括胜场、击杀数、排名。

hero_meta英雄选择率和各段位胜率。

game_knowledge

常见问题和游戏机制。

使用 semantic_text 进行基于语义而非关键词的匹配。

title和content都会复制到 semantic_field用于混合搜索 hybrid search 解决方案。

创建索引from elasticsearch import Elasticsearch import os es Elasticsearch( hosts[os.getenv(ELASTICSEARCH_URL)], api_keyos.environ[ELASTIC_API_KEY] ) # Player stats index es.indices.create( indexplayer_stats, mappings{ properties: { player_id: {type: keyword}, username: {type: keyword}, hero: {type: keyword}, wins: {type: integer}, losses: {type: integer}, kills: {type: integer}, deaths: {type: integer}, rank: {type: keyword}, last_played: {type: date} } } ) # Hero meta index es.indices.create( indexhero_meta, mappings{ properties: { hero_name: {type: keyword}, pick_rate: {type: float}, win_rate: {type: float}, tier: {type: keyword}, patch_version: {type: keyword} } } ) # Game knowledge index (for semantic search) es.indices.create( indexgame_knowledge, mappings{ properties: { title: {type: text, copy_to: semantic_field}, content: {type: text, copy_to: semantic_field}, category: {type: keyword}, semantic_field: {type: semantic_text} # Semantic search queries this combined field } } )索引示例数据from datetime import datetime, timedelta from elasticsearch.helpers import bulk import random # Sample player data players [ {player_id: p001, username: DragonSlayer99, hero: Warrior, wins: 342, losses: 198, kills: 4521, deaths: 2103, rank: Diamond}, {player_id: p002, username: ShadowMage, hero: Mage, wins: 567, losses: 234, kills: 8932, deaths: 3421, rank: Master}, {player_id: p003, username: HealBot3000, hero: Healer, wins: 423, losses: 187, kills: 1234, deaths: 1876, rank: Diamond}, {player_id: p004, username: TankMaster, hero: Tank, wins: 298, losses: 302, kills: 2341, deaths: 1543, rank: Platinum}, {player_id: p005, username: AssassinX, hero: Assassin, wins: 789, losses: 156, kills: 12453, deaths: 2987, rank: Grandmaster}, ] for player in players: player[last_played] datetime.now() - timedelta(hoursrandom.randint(1,

) # Hero meta data heroes [ {hero_name: Warrior, pick_rate:

1

2, win_rate:

5

3, tier: A, patch_version:

2.

1}, {hero_name: Mage, pick_rate:

2

8, win_rate:

5

7, tier: S, patch_version:

2.

1}, {hero_name: Healer, pick_rate:

1

5, win_rate:

5

1, tier: A, patch_version:

2.

1}, {hero_name: Tank, pick_rate:

1

3, win_rate:

4

9, tier: B, patch_version:

2.

1}, {hero_name: Assassin, pick_rate:

3

2, win_rate:

4

2, tier: A, patch_version:

2.

1}, ] # Game knowledge for semantic search knowledge [ {title: How to unlock the Dragon Mount, content: Complete the Dragons Lair dungeon on Nightmare difficulty with all party members alive. The mount has a 15% drop rate., category: mounts}, {title: Best Mage build for Season 4, content: Focus on Intelligence and Critical Chance. Use the Arcane Staff with Frost Runes. Prioritize cooldown reduction for burst damage., category: builds}, {title: Understanding the ranking system, content: Ranks go from Bronze to Grandmaster. You need 100 points to advance. Wins give 25 points, losses subtract

, category: ranked}, ] # Bulk index all data actions [] for player in players: actions.append({_index: player_stats, _source: player}) for hero in heroes: actions.append({_index: hero_meta, _source: hero}) for doc in knowledge: actions.append({_index: game_knowledge, _source: doc}) success, errors bulk(es, actions) print(fIndexed {success} documents) es.indices.refresh(indexplayer_stats,hero_meta,game_knowledge)完成现在我们已有可查询的数据。

通过 API 创建 ES|QL 工具我们将不使用 UI而是通过 Agent Builder API 编程方式创建工具。

这使版本控制和部署更方便。

首先设置我们的 Kibana API 连接import requests KIBANA_URL os.environ[KIBANA_URL] # e.g., https://your-deployment.kb.us-central

gcp.cloud.es.io KIBANA_API_KEY os.environ[KIBANA_API_KEY] headers { kbn-xsrf: true, Authorization: fApiKey {KIBANA_API_KEY}, Content-Type: application/json }工具 1排行榜该工具显示按击杀数排名的顶级玩家。

我们使用 ES|QL 进行聚合leaderboard_tool { id: leaderboard, type: esql, description: Shows top players ranked by kills. Use when someone asks Who is the best? or Show me top players., configuration: { query: FROM player_stats | STATS total_kills SUM(kills), total_wins SUM(wins) BY username, hero, rank | SORT total_kills DESC | LIMIT 10, params: {} } } response requests.post( f{KIBANA_URL}/api/agent_builder/tools, headersheaders, jsonleaderboard_tool ) print(fLeaderboard tool: {response.status_code})工具 2英雄统计英雄统计工具使用动态参数返回特定英雄的性能数据hero_stats_tool { id: hero_stats, type: esql, description: Gets win rate, pick rate, and tier for a specific hero. Use when someone asks How good is Mage? or What is the win rate for Warrior?, configuration: { query: FROM hero_meta | WHERE hero_name ?hero | KEEP hero_name, win_rate, pick_rate, tier, patch_version, params: { hero: { type: keyword, description: The hero name to look up } } } } response requests.post( f{KIBANA_URL}/api/agent_builder/tools, headersheaders, jsonhero_stats_tool ) print(fHero stats tool: {response.status_code})?hero 是一个动态参数。

当 agent 调用该工具时它会从用户的问题中填入英雄名称将自然语言问题如“Is Mage strong?”转换为结构化查询例如 | WHERE hero_name “Mage”。

工具 3Meta 报告该工具显示当前版本中哪些英雄处于主导地位meta_report_tool { id: meta_report, type: esql, description: Shows all heroes sorted by tier and win rate. Use when someone asks What is the current meta? or Which heroes are S-tier?, configuration: { query: FROM hero_meta | SORT tier ASC, win_rate DESC | KEEP hero_name, tier, win_rate, pick_rate, params: {} } } response requests.post( f{KIBANA_URL}/api/agent_builder/tools, headersheaders, jsonmeta_report_tool ) print(fMeta report tool: {response.status_code})添加索引搜索工具对于非结构化内容如

常见问题和游戏机制我们使用索引搜索工具。

pattern 参数指定要搜索的 Elasticsearch 索引game_knowledge_tool { id: game_knowledge, type: index_search, description: Searches game guides, FAQs, and mechanics. Use when someone asks How do I...? or What is...? questions about game content., configuration: { pattern: game_knowledge } } response requests.post( f{KIBANA_URL}/api/agent_builder/tools, headersheaders, jsongame_knowledge_tool ) print(fGame knowledge tool: {response.status_code})请记住ES|QL 工具用于结构化分析“谁的击杀最多”而索引搜索工具用于非结构化知识“如何解锁龙坐骑”。

创建 agent现在我们来创建一个使用这些工具的 agentagent { id: gaming_support_bot, name: Gaming Support Bot, description: A gaming community support bot that answers player questions about stats, heroes, and game mechanics., configuration: { tools: [{tool_ids: [leaderboard, hero_stats, meta_report, game_knowledge]}], instructions: You are a helpful gaming community bot. Answer player questions about: - Player stats and leaderboards (use leaderboard tool) - Hero performance and meta (use hero_stats and meta_report tools) - Game mechanics and guides (use game_knowledge tool) Be concise and friendly. Format leaderboards clearly with rankings. } } response requests.post( f{KIBANA_URL}/api/agent_builder/agents, headersheaders, jsonagent ) print(fAgent created: {response.status_code})该 agent 现在可以访问我们所有的工具并根据用户的问题选择合适的工具。

你可以通过访问 Kibana 的 Agent Chat GUI 或发送 API 调用来测试连接性。

默认情况下Agent Builder 使用 Elastic 托管的 LLM因此无需配置连接器test_message Show me all heroes sorted by tier response requests.post( f{KIBANA_URL}/api/agent_builder/converse, headersheaders, json{ agent_id: gaming_support_bot, input: test_message }, timeout60 ) print(fStatus: {response.status_code}) if response.status_code 200: result response.json() print(f\nAgent used tools: {[step.get(tool_id) for step in result.get(steps, []) if step.get(type) tool_call]}) print(f\nResponse:\n{result.get(response, {}).get(message, No message)}) else: print(fError: {response.text})设置 Discord 机器人如果你还没有 Discord 机器人需要按照以下步骤创建访问 Discord 开发者门户Discord Developer Portal。

点击 “New Application”并为应用命名。

进入 Bot 部分点击 “Add Bot”。

复制 机器人的 token。

稍后会用到在Privileged Gateway Intents下启用Message Content Intent。

转到OAuth2 URL Generator选择bot和application.commands范围并勾选Send Messages和Read Message History权限。

使用生成的 URL 将 机器人 邀请到你的服务器。

安全

注意事项在 Discord 端只请求最小权限Send MessagesSend Messages in ThreadsRead Message HistoryCreate Polls这样即使 机器人 被入侵其可执行的操作也有限。

在Elastic端创建一个权限受限的 API key。

对于这个 机器人只需对游戏索引拥有读取权限POST /_security/api_key { name: gaming-bot-key, role_descriptors: { gaming_bot_role: { cluster: [monitor], indices: [ { names: [player_stats, hero_meta, game_knowledge], privileges: [read] } ] } } }配置 Discord A2A 客户端下一步是将 Discord 连接到 Agent Builder。

我们将使用经过修改的kagent-a2a-discord。

克隆并进行设置git clone https://github.com/llermaly/agentbuilder-a2a-discord cd agentbuilder-a2a-discord环境变量在项目根目录下创建一个.env文件DISCORD_BOT_TOKENyour_bot_token AGENT_BUILDER_URLhttps://kibana_url/api/agent_builder/a2a/gaming_support_bot A2A_API_KEYyour_api_key使用 Python 运行# Create virtual environment uv venv # Install dependencies uv sync # Run the bot uv run main.py该机器人应该在几秒内上线你的 Discord 服务器。

测试机器人我们来测试不同类型的查询。

分析查询ES|QL用户“谁是最强的 Mage 玩家”机器人根据排行榜数据ShadowMage 目前是游戏中最强的 Mage 玩家。

他已达到大师段位拥有 8,932 次击杀和 567 胜场……用户“当前的 meta 是什么”机器人当前版本的 meta 由 Mage 主导Mage 在 S 级独占胜率达

5

7%选择率为

2

8%版本为

2.

1。

语义查询索引搜索用户“如何解锁龙坐骑”机器人要解锁龙坐骑你需要在噩梦难度完成龙之巢副本。

保持所有队员在整个副本过程中存活。

祝你好运——坐骑掉落率为 15%……该 机器人 会根据问题自动选择正确的工具。

双向互动赋予 agent 操作能力除了回答问题外我们还可以让 Agent Builder 触发 Discord 操作。

通过对 Discord 客户端进行小幅修改我们可以解析 agent 回复中的特殊标签并执行相应的 Discord 命令。

例如我们增加了对 polll 标签的支持pollShould Mage be nerfed?|Yes, too strong|No, its balanced|Need more data/poll当 agent 在回复中包含该标签时 机器人 会创建一个原生的 Discord 投票。

agent 只需知道何时使用该标签即可。

运行以下命令将其添加到指令中agent { id: gaming_support_bot, name: Gaming Support Bot, description: A gaming community support bot that answers player questions about stats, heroes, and game mechanics., configuration: { tools: [{tool_ids: [leaderboard, hero_stats, meta_report, game_knowledge]}], instructions: You are a helpful gaming community bot. Answer player questions about: - Player stats and leaderboards (use leaderboard tool) - Hero performance and meta (use hero_stats and meta_report tools) - Game mechanics and guides (use game_knowledge tool) When discussing balance topics, create a poll for community input. Use: pollQuestion|Option1|Option2|Option3/poll Be concise and friendly. Format leaderboards clearly with rankings. } } response requests.put( f{KIBANA_URL}/api/agent_builder/agents, headersheaders, jsonagent ) print(fAgent created: {response.status_code})现在当用户询问 “Is Mage overpowered?” 时agent 可以分享统计数据并创建投票将数据洞察转化为社区互动。

同样的模式也适用于其他 Discord 功能如表情反应、角色提及或定时公告。

agent 的回复就成为了控制 Discord 操作的通道。

结论在本文中我们成功使用 Elastic Agent Builder 的 A2A 服务器构建了一个 Discord 机器人。

过程包括通过 API 创建 ES|QL 工具用于分析如排行榜、英雄统计和 meta 报告以及开发索引搜索工具用于知识库的语义搜索。

此外我们演示了使用动态参数如 ?hero 进行灵活查询、建立 Discord 与 A2A 客户端的连接并测试了分析查询和语义查询类型。

Agent Builder 提供了 A2A 服务器因此你只需专注于创建工具和连接客户端而 ES|QL 处理结构化分析索引搜索处理非结构化知识。

资源尝试示例 notebookAgent Builder API 文档Discord 客户端原文https://www.elastic.co/search-labs/blog/discord-elastic-agent-builder-a2a

无风险9 1免费版观看完整版-无风险9 1免费版观看完整版应用

百度百家号客服电话人工服务

123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123 123