k8s-agent架构思考(一)

k8s-agent架构思考(一)

背景思考

LLM 大模型横空出世之后,一切都变得不一样了。以前写程序,所有逻辑都得靠人一行行写,参数对参数,一步都马虎不得。但现在突然冒出来一个"东西",你问它什么,它就能答什么,而且回答得既准又深,简直像换了个时代。

你可以把 LLM 想象成一个黑盒子,往里输自然语言,往外吐自然语言,就像身边随时有个导师,总能告诉你该怎么做。而 Function Call 则让这个指导变得更精准------你给它一堆工具清单和说明,它会根据你的问题告诉你该调哪个工具;等工具跑完出结果,你再把结果扔回给 LLM,让它综合起来给出最终答案。

既然有这么牛的"神导师",那我们是不是可以围着它来做各种程序上的决策呢?

llm模型是监督学习的,训练的时候,输入一大段文字,输出为这大段文字的下一个文字,然后不断循环.

基础agent程序模块划分

既然我们要围绕这位"神导师"形成一个系统,那必然得有分工。

我们常说 Agent 是一段程序,那这段程序又该如何与 LLM 更好地协作呢?

一个基础的思考:

最接近大模型的模块 - provider模块

总览

模块的核心就是调大模型, 可以多种方式, 常见的是http, openai,另外有些厂商有自己的方式和客户端库,直接使用即可

如deepseek文档:

HTTP

openai库

这里要说明一下,OpenAI 的库其实是一个通用的客户端库,并不是说只能调用 OpenAI 的服务端。因为 GPT 出现得比较早,它的调用规范后来被很多其他大模型也兼容了,所以很多时候你只需要把 base_url 换成对应模型的 API 地址就行,比如这里用的是 DeepSeek 的地址。

当然,像 Gemini、Anthropic 这些也有自己的调用方式,国内厂商同样如此,你可以根据自己的需求选择接入。

流程
核心参数说明
model ,对应的模型,厂商的官网找
Messages,

实际上这个就是对话消息,

role分几类 :

  • System 系统prompt

会把一段加载到content中, 参考:

Shell 复制代码
 **# 系统角色**

你是一个智能 Agent 的任务执行模块。你需要根据 Planner 制定的步骤序列,逐步执行任务,并最终向用户输出结果。

**# 任务描述**

1. 接收 Planner 提供的子任务列表以及用户最初的诉求。
2. 按照步骤顺序,依次完成每个任务的 `task_desc`,确保产出符合 `expected_output` 的要求。
3. 在执行过程中,若需要使用外部工具(如搜索、计算器等),请按规定格式调用工具;若无需工具,则利用你的内在知识直接处理。
4. 当执行到最后一步(通常是总结步骤)时,你需要将前面步骤的产出进行综合汇总,并严格按照 ****Markdown**** 格式输出最终的完整回复给用户。

**# 执行规则**

- 保持上下文连贯性,将前置步骤的产出作为后续步骤的输入。
- 内容都用中文输出
- 只有在执行到最后一步,或需要调用外部工具时,才向外输出对应信息。非最后一步的纯思考与推演过程在内部完成即可,无需直接展示给用户。
- 最后一步的最终输出必须是结构清晰、排版良好的 Markdown 文本,直接面向最终用户。

**# 对应的markdown 格式输出规范:**

一、总体原则

    结构清晰:使用层级标题组织内容,逻辑递进,避免大段无结构文本。
    视觉分明:代码、表格、列表、引用等元素须与正文明确区分,便于阅读与复制。
    专业克制:全文不使用任何 emoji 或表情符号,语气客观、严谨。
    语义准确:Markdown 语法使用规范,不滥用加粗、斜体等强调手段。

二、标题层级

    使用 # 至 #### 四级标题,严禁使用五级及以下标题。
    一级标题(#)仅用于文档总标题,每篇输出最多出现一次。
    二级标题(##)用于主要章节划分,三级(###)用于小节,四级(####)用于具体条目。
    标题前后须空一行,与正文保持呼吸感。

三、段落与正文

    每段文字控制在 3--5 行以内,超过时按逻辑拆分。
    段与段之间空一行,严禁连续多行无内容空行。
    关键术语首次出现时可用 **加粗** 标注,同一文档内重复出现时不再加粗。
    长句避免堆砌,适当使用分号、编号列表拆分复杂信息。

四、代码块

    所有代码、命令、配置、JSON、伪代码等须放入 fenced code block(```)。
    必须标注语言标识符,如 ```python、```bash、```json。
    代码块前后各空一行,与正文隔离。
    行内代码(`code`)仅用于极短变量名、函数名或参数值,禁止包裹整句。

五、表格

    数据对比、参数说明、步骤映射等场景优先使用表格。
    表格须包含表头,表头与内容行使用 |---|---| 明确分隔。
    表格前后各空一行,表格内文字左对齐,数字右对齐。
    复杂表格可在表头后加一行简短说明,置于表格上方,格式为:*表 X:XXX*。

六、列表

    同级并列项使用无序列表(-),层级缩进 2 个空格。
    有序步骤使用有序列表(1.、2.),步骤间若有补充说明可嵌套无序列表。
    列表项内容较长时,项内可分段,但保持缩进一致。

七、引用与分隔

    重要提示、注意事项、免责声明使用引用块(> ),单行或多行均可。
    章节之间如需强分隔,可使用水平线(---),但全篇不超过 2 处。

八、禁止事项

    全文禁用 emoji、颜文字、ASCII 艺术及其他非功能性符号。
    禁用 HTML 标签(如 <br>、<center>)实现排版。
    禁用无意义的加粗或斜体堆砌,避免视觉噪音。

九、最终检查清单
输出前逐项确认:

    [ ] 标题层级未超过四级
    [ ] 代码块均带语言标识
    [ ] 表格有表头且对齐规范
    [ ] 无 emoji 及表情符号
    [ ] 段落间有空行,无连续空行
    [ ] 专业术语首次出现已加粗

**# 示例**

假设你收到的步骤为:
...
  • User 用户问题

例子:

JSON 复制代码
{"role": "user", "content": "广州明天天气怎样", "reason": null, "attachments": null, "tool_calls": null, "tool_call_id": null, "tool_name": null, "timestamp": "2026-07-16T16:57:53.986416", "metadata": {}}
  • Assistant llm返回

当前llm返回一般是直接content返回,如果要求agent去调用工具,则会返回 tool调用

留意下面的 tool_calls:\[\] 这是返回列表,让agent具体调哪个方法,参数是什么

JSON 复制代码
{"role": "assistant", "content": " ", "reason": "用户想知道广州明天的天气情况。我需要先获取当前日期和时间,然后再搜索广州明天的天气预报。\n\n让我先获取当前时间。", "attachments": null, "tool_calls": [{"id": "call_00_ecjW6uksa5tqRcEG6UOj7111", "name": "time-server__get_current_time", "arguments": {"timezone": "Asia/Shanghai", "format": "iso"}}], "tool_call_id": null, "tool_name": null, "timestamp": "2026-07-16T16:58:04.802830", "metadata": {"node_name": "executor"}}

上面的返回是代码里封装了下,实际上openai客户库是返回了delta对象

  • Tool 工具返回内容

agent调用了工具,然后把内容贴上来

如下实际上也是以文本的形式贴到了content中,后续llm看到这段文本就知道内容了

SQL 复制代码
{"role": "tool", "content": "{\n  \"time\": \"2026-07-15T04:40:08.000Z\",\n  \"timezone\": \"Asia/Shanghai\",\n  \"format\": \"iso\"\n}", "reason": null, "attachments": null, "tool_calls": null, "tool_call_id": "call_00_66Vs1z6zBL3vtVrMABvl3165", "tool_name": "time-server__get_current_time", "timestamp": "2026-07-15T12:40:08.153858", "metadata": {}}

一段会话如下:

这里没有存system_prompt, 一般不存,方便自己的会话消息可以给其它的agent直接使用

为什么token会消耗多,因为每一轮调用llm都会把大段地历史也结合告诉llm.

Tools

上面messages有说到llm有时会返回让agent去调用工具, 所以同时要让llm知道有哪些工具可用

传入llm的tools是个数组, 如下,cos-mcp 是腾讯云cos 的mcp服务

SQL 复制代码
[
{
        'type': 'function',
        'function': {
                'name': 'list_all_tools',
                'description': '列出当前所有可用的工具的名称列表(不包含自身)',
                'parameters': {
                        'properties': {},
                        'title': 'ListToolsParams',
                        'type': 'object'
                }
        }
}, {
        'type': 'function',
        'function': {
                'name': 'cos-mcp__getCosConfig',
                'description': '获取COS配置, 腾讯云配置',
                'parameters': {
                        'properties': {},
                        'title': 'MCPTool_Cos_mcp_Getcosconfig_Params',
                        'type': 'object'
                }
        }
}, {
        'type': 'function',
        'function': {
                'name': 'cos-mcp__putObject',
                'description': '上传本地文件到存储桶',
                'parameters': {
                        'properties': {
                                'filePath': {
                                        'description': '文件路径 (包含文件名)',
                                        'title': 'Filepath',
                                        'type': 'string'
                                },
                                'fileName': {
                                        'default': None,
                                        'description': '文件名 (存在存储桶里的名称)',
                                        'title': 'Filename',
                                        'type': 'string'
                                },
                                'targetDir': {
                                        'default': None,
                                        'description': '目标目录 (存在存储桶的哪个目录)',
                                        'title': 'Targetdir',
                                        'type': 'string'
                                }
                        },
                        'required': ['filePath'],
                        'title': 'MCPTool_Cos_mcp_Putobject_Params',
                        'type': 'object'
                }
        }
}, {
        'type': 'function',
        'function': {
                'name': 'cos-mcp__putString',
                'description': '上传字符串内容到存储桶',
                'parameters': {
                        'properties': {
                                'content': {
                                        'description': '要上传的字符串内容',
                                        'title': 'Content',
                                        'type': 'string'
                                },
                                'fileName': {
                                        'description': '文件名 (存在存储桶里的名称)',
                                        'title': 'Filename',
                                        'type': 'string'
                                },
                                'targetDir': {
                                        'default': None,
                                        'description': '目标目录 (存在存储桶的哪个目录)',
                                        'title': 'Targetdir',
                                        'type': 'string'
                                },
                                'contentType': {
                                        'default': None,
                                        'description': '内容类型,如 text/plain, application/json 等,默认为 text/plain',
                                        'title': 'Contenttype',
                                        'type': 'string'
                                }
                        },
                        'required': ['content', 'fileName'],
                        'title': 'MCPTool_Cos_mcp_Putstring_Params',
                        'type': 'object'
                }
        }
}
.....
问题

现在能调 llm了, 有了大脑, 那就需要 四肢了,于是就有了tool模块

agent自己的能力 - tool模块

流程

上面的 3,4,5,6 可能会不断循环, 这种思考, 行动,观察, Agent = LLM + 工具(Tools) 可以做为一个整体, react方式

所以简化一下

其它

mcp是什么? mcp实际上就是工具组,如 高德amap 有这些工具可用,

比如下面这个是调用 tavily-search 这个mcp的 search 工具, 留意 tool_calls中的 name, arguments

JSON 复制代码
{"role": "assistant", "content": " ", "reason": "The user is asking about the weather in Meizhou (梅州) for tomorrow (7/17) and the day after tomorrow (7/18). Let me search for this information.", "attachments": null, "tool_calls": [{"id": "call_00_wBELeSxD3v6fothJgijM5324", "name": "tavily-search__tavily_search", "arguments": {"query": "梅州 2026年7月17日 7月18日 天气预报", "search_depth": "advanced", "max_results": 5}}], "tool_call_id": null, "tool_name": null, "timestamp": "2026-07-16T16:58:53.645023", "metadata": {"node_name": "executor"}}
问题:

Agent 有了 tools 确实能干不少事,但问题是 tool 本身太原子化了。比如我想让 Agent 帮我规划某天去某个景点,它得先查天气、查交通、介绍景点、提醒注意事项、推荐酒店......这一套下来太综合了,总不能每次都重新拆一遍吧?

那能不能把这些步骤存起来,下次直接用这个流程?当然可以。所以就有了 Skill 这个概念。

经验组合- skills模块

流程

流程上我们还是上面的react 方式, 只不过会加一个tool, 加载skill, 然后通过这个skill文本来指导react的流程

所以虽然上加了个模块,但结构是没变的!!!

例子:

Markdown 复制代码
---
name: scenic-spot-guide
version: 1.0.0
description: 当用户查询某个旅游景区(古镇、古城、自然景区等)时,自动搜集该景区的全面信息,并按结构化模板生成一份图文并茂的 Markdown 旅游攻略,涵盖景点概览、交通指南、门票信息、核心景点详解(含历史特色)、美食推荐、行程建议、住宿推荐、最佳旅游季节、特产伴手礼等完整内容。
author: Agent
tags:
  - 旅游
dependencies:
  - 工具
input:
  - scenic_name: 景区名称
---

**# 景区查询攻略生成器 (Scenic Spot Guide)**

**## 核心功能**

1. ****景区基本信息获取****:搜集景区的地理位置、历史沿革、荣誉称号(如世界遗产、5A级景区等)
2. ****核心景点详解****:列出景区内所有主要景点/子景点,逐一说明其历史年代、建筑特色、文化价值、传奇故事等
3. ****实用信息整理****:门票价格、优惠政策、开放时间、交通路线(飞机/高铁/火车/汽车)
4. ****游玩攻略生成****:推荐行程路线(1日/2日/3日)、最佳游览顺序
5. ****周边配套信息****:美食推荐、住宿建议、特产伴手礼、最佳旅游季节
6. ****名人/文化轶事****:到访过的名人、相关的历史故事或民间传说

**## 输入参数**

| 参数名           | 类型          | 必填 | 说明                                                                           |
| ---------------- | ------------- | ---- | ------------------------------------------------------------------------------ |
| `scenic_name`    | string        | 是   | 景区名称,如"平遥古城"、"丽江古城"、"故宫"等                                   |
| `user_questions` | array[string] | 否   | 用户额外关心的问题列表,如["有哪些名人去过", "门票多少钱"],将作为补充搜索方向 |

**## 输出结果**

返回一份结构完整的 Markdown 旅游攻略,包含以下模块(按顺序):

1. ****概览**** - 景区名称、地理位置、历史年限、荣誉称号、世界遗产/5A等评级
2. ****交通指南**** - 飞机、高铁、火车、汽车等到达方式及注意事项
3. ****门票信息**** - 价格、优惠政策(免票/半票人群)、开放时间
4. ****核心景点详解**** - 每个景点的名称、年代、历史特色、建筑风格、文化价值、趣味故事等
5. ****城外/周边景点****(若有)
6. ****必看演出/体验****(若有)
7. ****美食推荐****
8. ****推荐行程路线****(按天数排列)
9. ****住宿建议****
10. ****最佳旅游季节****(含气候数据)
11. ****特产伴手礼****
12. ****名人到访/文化轶事****(若用户关注)

**## 依赖环境**

- 网络搜索工具(用于搜集景区最新信息,如 Tavily Search)
- 时间工具(用于获取当前时间,判断季节等)
- 文件系统(用于读取已有数据或保存输出)

**## 使用示例**

```markdown
用户输入:查一下平遥古镇

触发技能:scenic-spot-guide
参数:{ "scenic_name": "平遥古城" }

输出:# 🏛️ 平遥古城 · 完整旅游攻略 ## 📍 概览
... ## 🚗 交通指南
... ## 🎫 门票信息
...
(完整的 Markdown 攻略)

用户输入:有哪些名人去过平遥古城

触发技能:scenic-spot-guide
参数:{
"scenic_name": "平遥古城",
"user_questions": ["有哪些名人去过"]
}

输出:在攻略中补充「名人到访」章节,详列到访过的国家领导人、外国政要、文化名人、本地出身名人等。

**## 执行流程**

**### Step 1:搜索景区基本信息**

- 使用搜索工具搜索景区名称 + "旅游攻略 景点介绍"
- 获取景区的地理位置、历史沿革、荣誉称号

**### Step 2:搜索核心景点详细信息**

- 搜索景区内具体景点列表 + "详细列表 历史特色 介绍"
- 对主要景点逐一获取年代、历史背景、建筑特色

**### Step 3:搜索实用信息**

- 门票价格、优惠政策、开放时间、交通路线

**### Step 4:搜索附加信息(按用户需求)**

- 若用户问了特定问题(如名人、美食、天气),单独搜索补充
- 搜索"景区 名人 去过 参观 明星 领导"等

**### Step 5:整合输出**

- 将所有信息按输出模板整合为结构化 Markdown 文档
- 确保排版清晰、图文并茂、信息准确

**## 注意事项**

1. 门票价格等时效性信息以最新搜索结果为准,注意标注信息来源时间
2. 若景区含通票(多个子景点联票),需详细列出通票包含的景点清单
3. 每个核心景点应包含:名称、年代、历史地位/特色、值得看的点、趣味故事(如有)
4. 对于有世界遗产称号的景区,需说明登录年份和联合国评价
5. 若用户查询的是"古镇/古城"类景区,需特别关注其保存状况、建筑风格、文化底蕴
6. 行程推荐应根据景点数量和分布给出合理的1~3日方案
7. 所有信息需核实准确性,避免过时或错误信息
8. 最终输出为纯 Markdown 格式,不附加额外解释文字

**## 引用资源**

无外部引用资源。

**## 代码文件清单**

- `SKILL.md` - 技能定义文件(本文件)
问题:

这三个要素------Provider、tools、skills------确实是使用LLM的基础骨架。但在实际场景中,尤其是面对复杂任务时,光有这些还不够。我们需要一套灵活的编排机制来管理多轮交互、工具调用和分支决策。

以客服系统为例,用户的请求可以分为三类:

  1. 打招呼(如"Hi"):直接返回问候,无需任何工具介入。

  2. 简单任务(如查询订单状态):可能需要调用一次或两次工具(查数据库、整理结果),然后判断是否还需更多工具,最终给出答案。

  3. 复杂任务(如处理退换货流程):需要拆解成多个子步骤,每个步骤可能依赖前一步的结果,并且可能在不同节点上调用不同工具,甚至需要条件判断和循环。

针对这类多步骤、带状态的编排需求,节点编排是一种非常自然的解决方案。

编排- Graph 模块

这边我们习惯使用 LangGraph 这个开源工具来做编排,它能让流程搭建更直观灵活。

流程

整体上 ReAct 模式保持不变,但我们可以在此基础上加入编排逻辑:先分析用户意图,再决定后续路径。举个例子,如果你希望在最终输出前对文本做一轮润色或格式化,可以额外加一个"文本输出节点",把 ReAct 的完整输出作为输入交给这个节点处理。像这样的节点都可以根据实际业务需求自由组合,按需编排就好。

实际编排中要考虑多个内容, 每个节点负责一件事:

  • 入口节点:接收用户输入。

  • 判断节点:让 LLM 根据用户意图做分类(比如"打招呼""简单任务""复杂任务")。

  • 工具调用节点:执行具体的 tool(查天气、查交通等)。

  • LLM 推理节点:让模型根据上下文生成下一步指令或最终回复。

  • 循环/条件跳转:比如简单任务调完工具后,再次判断是否需要更多工具;复杂任务则按 Skill 定义的步骤依次执行,每步都可能回到判断节点。

  • 结束节点:输出最终答案

问题:

这样就能回答一些复杂问题了,如果想用户使用更好一点,也可以考虑加上memory等.

用户的记忆-memory,session模块

似skills 把用户的memory加载到messages中

memory是在会话中压缩的内容, 这个需要额外处理.

总结

基础的 Agent 搭建起来后,核心结构就是 Provider 和 Tool,其他部分都属于扩展。可以把 LLM 看作大脑,Tool 看作爪子,这样一个"八爪鱼式"的 Agent 就诞生了。

如果是在本地使用,安全性基本可控。可以在本地添加各种 MCP、Tools 等组件------像 Claude Code 这类工具就是这样做的。虽然它们的权限较大,但只要做好权限控制并谨慎操作,风险是可以接受的。

但如果 Agent 部署在服务器上,安全问题就会变得比较突出。因为用户可能会安装各种各样的工具,有些甚至能通过 exec 直接执行本地命令(例如 Python),进而查看环境变量(其中可能包含密钥)。这样一来,用户的问题就可能演变成类似 SQL 注入的安全风险。

相关推荐
AI情绪识别开源2 小时前
检信ALLEMOTION VibrationAI 2.4.0 12维度情绪识别开源源代码
开发语言·python
极创信息2 小时前
国产化信创适配认证高频术语:信创适配、软件自主可控、国产化率、代码溯源率、代码自主率、代码开源率是什么?
java·python·struts·eclipse·开源·php·hibernate
AC赳赳老秦3 小时前
语义采集进阶实战:利用 OpenClaw AI 语义识别自动提取网页核心信息,无需手动编写选择器
java·运维·服务器·python·信息可视化·deepseek·openclaw
Logintern093 小时前
什么时候应该用多进程什么时候用多线程呢?
开发语言·python
无凭3 小时前
字节跳动 DeerFlow:Agent Harness 怎么让大模型主动向用户提问?
人工智能·python
蜀道山老天师3 小时前
Python + Playwright 实现问卷星自动化填写
python
Zane19944 小时前
多开几个线程,为什么算数字反而没变快?一文讲透 CPython 的 GIL
后端·python
W_326004 小时前
Python-OpenCV边缘检测与阈值分割:Sobel、Scharr、Laplacian、Canny、全局与自适应阈值
开发语言·图像处理·python·opencv·机器学习
青 春 记 忆4 小时前
LeetCode 121. 买卖股票的最佳时机|Python 解法详解
python·算法·leetcode