新闻详情

新闻详情

首页 / 资讯中心 / 详情

从Function Calling到技能框架:AI Agent能力设计实战

发布时间:2026/9/26 19:14:21来源:尧图网络
从Function Calling到技能框架:AI Agent能力设计实战
1. 从手搓 Function Calling 到 Agent 技能框架做 AI Agent 开发的朋友大概率都经历过这么一段路一开始你的 Agent 只会聊天顶多用个大模型自己的知识库回答点问题。然后你发现这玩意儿不实用得让它能查天气、能算数学、能调内部 API、能操作数据库。于是你开始写 function calling——在代码里定义一堆 JSON Schema塞给大模型让它“决定”什么时候调用哪个函数。这个阶段一切都还能忍。函数就十几个参数也不复杂调试起来虽然烦但可控。直到某一天你的 Agent 需要掌握的“技能”越来越多比如我要做一个招聘助手它既要能解析简历 PDF又要能查公司知识库还要能评估候选人和岗位的匹配度更要能生成面试邀约邮件并调用邮件系统发出去。十几个函数膨胀到几十个每个函数背后还挂着一堆状态和上下文。这时候你手里的代码就开始失控了。我那个阶段最头疼的事儿有三件一是技能的注册和路由逻辑全散在各个模块里想加一个新技能得改五六处代码二是技能和技能之间经常需要协作比如“查了天气再决定要不要提醒用户带伞”这套状态流转靠 function calling 天然不支持三是技能的复用性极差这个项目里写的“简历解析”换个项目想用基本等于重写。后来我接触到了 agent-skills 这种思路——把 Agent 的能力从“函数”提升为“技能”并且把技能的发现、加载、执行、编排都做成一套相对独立、可插拔的机制。这篇文章不聊某个特定的开源库而是把我实践下来的一套 Agent 技能框架的设计思路、踩坑记录和完整代码方案整理出来希望对正在从“函数式 Agent”往“技能式 Agent”过渡的朋友有帮助。这套方案适合谁如果你现在手头的 Agent 项目开始出现函数爆炸、逻辑耦合严重、或者你想把 Agent 能力模块化、让多个 Agent 共享一套技能库那这篇文章里的思路可以直接抄。如果你刚接触 Agent 开发也能从中学到一套从零搭建技能框架的完整路径。2. 整体设计三层架构与关键取舍2.1 技能的定义函数之上流程之下先说一个很容易混淆的点技能到底和函数有什么区别我的理解是函数是大模型可以直接调用的“原子操作”比如get_weather(city)它没有状态、没有前置条件、没有组合逻辑。而技能是一个“带上下文感知的完整能力单元”它内部可能封装了多个函数调用、有一套参数校验逻辑、甚至还会调用别的技能。举个例子一个“候选人面试安排”技能接收一个候选人 ID 和几个时间段它内部要先查候选人简历、再查面试官空闲时间、然后创建一个会议邀请、最后给候选人发通知邮件。这个流程如果用 function calling你得让大模型连续调用四五个函数中间任何一步出错整个流程就断了。如果把它封装成一个技能大模型只需要调用一次内部的编排和错误处理都封装好了。在设计技能框架时我参考了 Claude Code 里面 skills 的概念也参考了一些开源 Agent 框架的工具注册机制最后定下了一个核心原则技能要有独立的定义文件、独立的执行入口、明确的输入输出协议。具体来说一个技能由三部分组成技能描述告诉大模型这个技能是干什么的、什么时候应该用、什么时候不应该用。这是大模型选择技能的依据。输入 Schema定义这个技能需要哪些参数每个参数的类型、取值范围、是否必填。这决定了调用方也就是大模型该传什么数据。执行器真正的业务逻辑接收验证后的参数执行具体操作返回结构化结果。这三部分有机组合一个技能才算完整。缺了描述大模型不知道怎么选缺了 Schema大模型不知道传什么参数缺了执行器整个技能就是空壳。2.2 技能注册与发现一份 manifest 文件解决一切技能的数量一多“怎么让 Agent 发现并加载技能”就成了第一个需要解决的问题。我的方案是为每一个技能配一个SKILL.md文件内容用 YAML 写元数据用 Markdown 写描述和使用说明。这些技能文件统一放在skills/目录下框架启动时自动扫描整个目录解析每个子目录里的SKILL.md构建出技能索引。这个方案的灵感其实来自 Anthropic 的 Claude Skills 规范——它也是用SKILL.md作为技能的入口文件。这个设计的好处有几个技能与代码解耦新加一个技能只需要新建一个目录、写一个SKILL.md、放一段代码实现不需要改动框架本身的注册逻辑。人类可读SKILL.md是普通文本产品经理、运营同事也能看懂技能的作用和参数方便跨角色协作。天然支持版本管理每个技能是一个独立的目录用 Git 管理时互不冲突。下面是我实际使用的一个SKILL.md模板--- name: schedule_interview description: 根据候选人 ID 和可选时间段自动查找面试官空闲时间并创建会议邀请同时发送通知邮件给候选人。适用于招聘流程中的面试安排环节。 version: 1.0.0 author: ops tags: [recruitment, calendar, email] input_schema: candidate_id: type: string description: 候选人唯一标识 required: true preferred_slots: type: array items: type: string description: 候选人的可选时间段ISO 8601 格式 required: true interview_type: type: string enum: [onsite, remote] default: remote description: 面试类型线上或线下 required: false output_schema: meeting_url: type: string description: 会议链接 confirmation_id: type: string description: 通知邮件确认 ID --- # schedule_interview 这个技能用于自动化面试安排流程。 ## 适用场景 - 候选人确认了多个可选时间段 - 需要协调至少一名面试官的时间 - 创建会议并通知相关方 ## 不适用的场景 - 候选人还未提交简历此时应该先解析简历 - 面试官名单未确定需要先匹配面试官 ## 执行流程 1. 根据 candidate_id 获取候选人信息 2. 查询面试官日历匹配空闲时间段 3. 创建日历事件 4. 发送邮件通知 5. 返回会议链接和确认 ID你可能会问为什么不用纯 JSON 或者纯代码来定义技能元数据我的实测感受是YAML 加 Markdown 的组合可读性最强。YAML 解决结构化字段的解析问题Markdown 部分相当于给大模型写了一份详细的使用说明书。大模型在决定是否调用某个技能时会读取这段 Markdown 作为上下文描述越详细、示例越具体大模型的调用准确率就越高。2.3 执行器的实现方式类方法加装饰器技能描述和 Schema 只是“面子”真正的“里子”是执行器的实现。我的做法是用一个 Python 类来表示一个技能类名和SKILL.md里的name字段保持一致类里面的方法通过装饰器标记为执行入口或者内部工具。# skills/schedule_interview/executor.py from skill_framework import BaseSkill, skill_method class ScheduleInterviewSkill(BaseSkill): name schedule_interview version 1.0.0 skill_method def execute(self, candidate_id: str, preferred_slots: list[str], interview_type: str remote) - dict: 技能主入口编排整个面试安排流程。 # 1. 获取候选人信息 candidate self.tools.get_candidate(candidate_id) if not candidate: return {success: False, error: candidate not found} # 2. 查询面试官空闲时间 interviewers self.tools.get_team_members(candidate.team_id) free_slots self.tools.find_free_slots( interviewers, preferred_slots, duration_minutes60 ) # 3. 确定最终时间段 final_slot free_slots[0] if free_slots else None if not final_slot: return {success: False, error: no available time slot} # 4. 创建会议并发送通知 meeting self.tools.create_meeting( titlef面试: {candidate.name}, startfinal_slot[start], endfinal_slot[end], attendees[interviewer[email] for interviewer in interviewers] [candidate.email], type_interview_type, ) email_result self.tools.send_email( tocandidate.email, templateinterview_invitation, context{name: candidate.name, meeting_url: meeting[url]}, ) return { success: True, meeting_url: meeting[url], confirmation_id: email_result[id], }这里有个很关键的设计技能类不直接依赖于某个具体的日历 API 或邮件 API而是通过self.tools调用底层工具。tools是什么它是框架注入的“工具桶”把那些需要鉴权、连接外部服务的底层能力统一管理起来。这样分层的逻辑很直白schedule_interview技能关心的是“面试安排的流程编排”但它不关心日历用的是 Google Calendar 还是 Outlook也不关心邮件系统是自研的还是第三方的。底层的差异被 tools 层隔离了换一家服务商只需要改 tool 的实现技能代码完全不用动。这一点在后期的维护中价值极大我实测下来框架搭好后的三个月里底层工具换了两轮技能层代码基本零改动。3. 核心细节解析参数校验、上下文与安全边界3.1 参数校验的“双重门”机制大模型调用技能时参数不一定靠谱。实测中模型经常会出现把日期格式传错、把枚举值传成自由文本、甚至漏传必填参数的情况。所以参数校验一定要做而且要做“两道门”。第一道门在框架层基于input_schema做自动校验。我用的库是pydantic把 YAML 里的 Schema 动态转成 Pydantic 模型在调用执行器之前先做一次类型检查。from pydantic import BaseModel, Field, create_model def build_validator(schema: dict) - type[BaseModel]: fields {} for field_name, field_def in schema.items(): field_type { string: str, integer: int, number: float, boolean: bool, array: list, object: dict, }.get(field_def[type]) if field_type is None: raise ValueError(funsupported field type: {field_def[type]}) fields[field_name] ( field_type, Field( descriptionfield_def.get(description, ), default... if field_def.get(required, False) else field_def.get(default), ), ) return create_model(SkillInput, **fields)第二道门在技能内部是业务逻辑层面的校验。比如preferred_slots虽然是字符串数组但每个字符串必须能被解析成合法的时间段interview_type虽然是枚举但实际值的大小写可能不符合预期。这些业务规则框架层管不了必须在执行器里自己判断。为什么非要搞两层因为第一层校验过滤掉的是“格式错误”它能保证代码不会因为None或者类型不对而直接崩溃第二层过滤的是“语义错误”保证流程不会带着错误数据往下走。少任何一道门线上都会出幺蛾子。我踩过的坑是早期只做了第一层校验结果大模型传来的时间字符串next monday格式上没问题但业务解析器根本处理不了最后面试邀请的时间错得离谱还得靠人工发现。3.2 技能内的上下文管理从小脑到大脑Agent 运行时的上下文是技能框架里最容易被忽视、但影响最大的东西。我见过不少 Agent 项目把整个对话历史全部塞给大模型然后让大模型“理解”当前应该调用哪个技能。这个方案在早期可行一旦技能变多、对话变长问题就来了上下文变长token 成本飙升无关信息太多模型选择技能的准确率下降技能执行过程中的临时状态无处安放要么塞进全局变量并发时直接炸要么反复从对话里提取性能极差。我的方案是给框架引入一个技能上下文对象在每个技能执行时创建一个独立的上下文存储技能内部每一步产生的中间结果都写入上下文技能结束或出错时由框架决定哪些信息需要回传到大模型的对话流。class SkillContext: def __init__(self, skill_name: str, conversation_id: str): self.skill_name skill_name self.conversation_id conversation_id self.memory: dict[str, Any] {} self.events: list[dict] [] def remember(self, key: str, value: Any) - None: self.memory[key] value def recall(self, key: str, default: Any None) - Any: return self.memory.get(key, default) def log_event(self, event: str, data: Any None) - None: self.events.append({event: event, data: data, ts: datetime.utcnow().isoformat()})这个SkillContext还有一个额外作用它是技能和技能之间协作的“桥梁”。比如我做过一个“周报自动生成”技能里面需要调用“数据查询”技能获取本周工作项。按照传统的 function calling 思路两个技能之间的数据传递要靠参数传递你得把上一个函数的输出整理成下一个函数的输入模型在中间来回倒腾效率很低。有了SkillContext我可以在“数据查询”技能里执行ctx.remember(weekly_items, items)然后在“周报生成”技能里通过ctx.recall(weekly_items)直接取用。底层执行器之间的数据通道省掉了大模型的参与既快又准。但这里有个边界要注意——不要让技能之间的依赖变成隐式的。如果一个技能的运行依赖另一个技能先运行这个依赖关系必须写清楚并且在技能调度时显式声明。我用一个depends_on字段来标记技能依赖框架在运行时会自动检查依赖是否满足不满足就拒绝执行并返回明确错误而不是让技能跑一半才发现数据是空的。这个设计帮我挡住了不少诡异的线上问题。3.3 安全边界技能不是无限权力的Agent 技能的本质是“让大模型拥有执行某种操作的权限”。权限越大风险越大。尤其是当技能能调用时、能读写文件、能发邮件的时候安全设计绝对不能省。我在这套框架里做了三层安全边界第一层是技能能力声明。每个技能在SKILL.md里声明自己需要哪些权限比如requires_network: true、requires_fs: false、requires_admin: false。框架启动时会做一次权限检查如果技能声明的能力超出了运行环境赋予它的权限直接拒绝加载。第二层是运行时沙箱。技能的执行器运行在受控的 Python 环境中默认禁用文件写入、网络连接等危险操作只有显式开启对应能力的技能才允许访问。class Sandbox: def __init__(self, allowed_networks: bool False, allowed_fs_write: bool False): self.allowed_networks allowed_networks self.allowed_fs_write allowed_fs_write def open_file(self, path: str, mode: str): if w in mode and not self.allowed_fs_write: raise PermissionError(ffs write is not allowed in this skill: {path}) return open(path, mode) def http_request(self, url: str, method: str GET, **kwargs): if not self.allowed_networks: raise PermissionError(fnetwork access is not allowed in this skill: {url}) # 实际这里会用 requests / httpx 做请求 return execute_http(url, method, **kwargs)第三层是输出过滤。技能执行完返回给大模型的结果不能是原始的敏感数据。比如一个“用户资料查询”技能内部可能拿到了用户的手机号、身份证号但这些信息不应该全部塞回给大模型。执行器在返回前要通过一个输出清洗函数只保留符合需要返回的字段。这层设计听起来像是给技术宅看的但实际上它对整个系统的稳定性影响极大。一旦技能能被大模型自由调用一个不够安全的技能就是一个可以被提示注入攻击利用的入口。我之前处理过一例某个技能会把文件内容回传给大模型结果用户在对话里诱导模型读取服务器上的配置文件如果当时没有沙箱拦截服务器信息就泄露了。安全设计宁可一上来就做严也不要等到出事再补。4. 实操过程从零搭建一套可运行的技能框架4.1 项目结构规划我实际跑通的这套框架项目结构如下agent_skills_demo/ ├── app.py # Agent 主入口 ├── skill_framework/ # 框架核心 │ ├── __init__.py │ ├── loader.py # 技能发现与加载 │ ├── registry.py # 技能注册表 │ ├── validator.py # 参数校验器 │ ├── sandbox.py # 沙箱与权限控制 │ ├── context.py # 技能上下文 │ └── router.py # 大模型调用路由 ├── skills/ # 技能库目录 │ ├── schedule_interview/ │ │ ├── SKILL.md │ │ └── executor.py │ └── query_knowledge_base/ │ ├── SKILL.md │ └── executor.py ├── tools/ # 底层工具 │ ├── calendar_api.py │ ├── email_api.py │ └── knowledge_base.py └── config/ └── skills_config.yaml # 技能启停与权限配置这个结构最重要的特征是技能完全以目录的形式独立存在。新写一个技能不用改框架代码不用重启服务框架支持热加载——定时扫描技能目录发现新增技能自动注册发现修改自动重载。这个能力在开发调试阶段太香了改完技能代码刷新一下 Agent 就能测试不用反复重启整套服务。4.2 核心代码Loader、Registry、Router先看技能加载器。它的职责是扫描skills/目录解析每个子目录里的SKILL.md把元数据读出来然后动态加载对应的executor.py。# skill_framework/loader.py import os import yaml import importlib.util from pathlib import Path from typing import Optional class SkillLoader: def __init__(self, skills_dir: str): self.skills_dir Path(skills_dir) def load_all(self) - list[dict]: skills [] for skill_dir in self.skills_dir.iterdir(): if not skill_dir.is_dir(): continue manifest_path skill_dir / SKILL.md if not manifest_path.exists(): continue skill_meta self._parse_manifest(manifest_path) executor self._load_executor(skill_dir / executor.py, skill_meta[name]) skill_meta[executor] executor skills.append(skill_meta) return skills def _parse_manifest(self, manifest_path: Path) - dict: raw manifest_path.read_text(encodingutf-8) parts raw.split(---) if len(parts) 3: raise ValueError(finvalid SKILL.md format: {manifest_path}) meta yaml.safe_load(parts[1]) description_md ---.join(parts[2:]).strip() meta[description_md] description_md return meta def _load_executor(self, executor_path: Path, skill_name: str) - Optional[object]: if not executor_path.exists(): return None spec importlib.util.spec_from_file_location(fskill_{skill_name}, executor_path) module importlib.util.module_from_spec(spec) spec.loader.exec_module(module) for attr_name in dir(module): attr getattr(module, attr_name) if isinstance(attr, type) and hasattr(attr, name) and getattr(attr, name) skill_name: return attr() return None然后是注册表。它的职责是维护一份“技能名 → 技能对象”的映射并提供查找接口。加了一层缓存避免每次请求都重新解析SKILL.md。# skill_framework/registry.py class SkillRegistry: def __init__(self): self._skills: dict[str, dict] {} def register(self, skill_meta: dict) - None: name skill_meta[name] self._skills[name] skill_meta print(f[registry] skill registered: {name} v{skill_meta.get(version, ?)}) def get(self, name: str) - dict | None: return self._skills.get(name) def list_skills(self) - list[str]: return list(self._skills.keys()) def build_tool_schema(self) - list[dict]: 把技能索引转换成 OpenAI 兼容的 tools 格式方便大模型调用。 tools [] for skill in self._skills.values(): tools.append({ type: function, function: { name: skill[name], description: skill.get(description_md, )[:1024], parameters: self._convert_schema(skill.get(input_schema, {})), }, }) return tools def _convert_schema(self, schema: dict) - dict: properties {} required [] for field_name, field_def in schema.items(): properties[field_name] { type: field_def[type], description: field_def.get(description, ), } if enum in field_def: properties[field_name][enum] field_def[enum] if field_def.get(required, False): required.append(field_name) return {type: object, properties: properties, required: required}到这里你可能已经看出来了这套框架本质上做了一件事把大模型调函数的那套标准流程封装到底层让开发者写技能时只关注业务逻辑不用关心“怎么让大模型选到这个函数”这些脏活。Router 是最后一块拼图。它负责接收大模型的 tool_call 请求找到对应的技能校验参数执行返回结果。# skill_framework/router.py import json from .validator import build_validator from .context import SkillContext from .sandbox import Sandbox class SkillRouter: def __init__(self, registry, config: dict): self.registry registry self.config config def dispatch(self, skill_name: str, arguments: str | dict, ctx: SkillContext) - dict: skill self.registry.get(skill_name) if skill is None: return {success: False, error: fskill not found: {skill_name}} # 1. 参数解析 if isinstance(arguments, str): args json.loads(arguments) else: args arguments # 2. 参数校验第一道门 if input_schema in skill and skill[input_schema]: validator_cls build_validator(skill[input_schema]) try: validated validator_cls(**args) args validated.model_dump() except Exception as e: return {success: False, error: finvalid arguments: {e}} # 3. 沙箱与权限 executor skill.get(executor) if executor is None: return {success: False, error: skill executor not implemented} skill_config self.config.get(skill_name, {}) sandbox Sandbox( allowed_networksskill_config.get(allow_network, False), allowed_fs_writeskill_config.get(allow_fs_write, False), ) executor.ctx ctx executor.sandbox sandbox executor.tools self._build_tool_layer(skill_config, sandbox) # 4. 执行 try: result executor.execute(**args) except PermissionError as e: return {success: False, error: fpermission denied: {e}} except Exception as e: ctx.log_event(execution_error, {skill: skill_name, error: str(e)}) return {success: False, error: fexecution failed: {e}} return result def _build_tool_layer(self, skill_config, sandbox): # 按需注入底层工具这里做简化处理 return { get_candidate: lambda cid: {id: cid, name: Alice, email: aliceexample.com}, get_team_members: lambda tid: [{email: mgrexample.com}, {email: peerexample.com}], find_free_slots: lambda interviewers, slots, duration_minutes: slots[:1], create_meeting: lambda **kw: {url: fhttps://meet.example.com/{kw[title]}}, send_email: lambda **kw: {id: email-123}, query_knowledge: lambda q: {answer: fmock answer for: {q}}, }这套代码在真实项目中已经跑通。它的核心价值是把“技能的定义、加载、校验、执行、安全”做成了一条标准流水线。开发者写新技能时只需要关心SKILL.md的元数据写得好不好、执行器的业务逻辑对不对其他事情交给框架处理。4.3 大模型侧如何接入框架搭好了大模型侧怎么接我用的方案是标准的 OpenAI Function Calling 流程把注册表生成的 tools schema 塞给模型模型返回 tool_call 时走 Router 分发。# app.py import json from openai import OpenAI from skill_framework.loader import SkillLoader from skill_framework.registry import SkillRegistry from skill_framework.context import SkillContext client OpenAI() def build_agent(): loader SkillLoader(skills) all_skills loader.load_all() registry SkillRegistry() for skill in all_skills: registry.register(skill) return registry def chat(registry: SkillRegistry, messages: list[dict]): tools registry.build_tool_schema() response client.chat.completions.create( modelgpt-4o, messagesmessages, toolstools, tool_choiceauto, ) msg response.choices[0].message if msg.tool_calls: ctx SkillContext(skill_nameunknown, conversation_idconv-123) for tool_call in msg.tool_calls: result router.dispatch( skill_nametool_call.function.name, argumentstool_call.function.arguments, ctxctx, ) messages.append(msg) messages.append({ role: tool, tool_call_id: tool_call.id, content: json.dumps(result, ensure_asciiFalse), }) # 把工具结果回传给模型生成最终回复 second_response client.chat.completions.create( modelgpt-4o, messagesmessages, toolstools, tool_choicenone, ) return second_response.choices[0].message.content return msg.content if __name__ __main__: registry build_agent() messages [ {role: system, content: 你是一个招聘助手请使用技能完成面试安排。}, {role: user, content: 请为候选人 Alice 安排一场远程面试她周三下午有空。}, ] print(chat(registry, messages))这里有一个很实用的经验不要小看 messages 的处理顺序。大模型返回 tool_call 后一定要先把原始的 assistant message 追加到对话里再把 tool message 追加进去最后才发起第二次模型调用。顺序只要错一步模型就会对不上号导致“明明调用了工具却把工具结果当成无关信息忽略掉”。这个坑我踩了不止一次每次都是在线上环境被用户反馈“Agent 调了工具但不看结果”才发现的。5. 常见问题与排查技巧实录5.1 高频问题速查表整理了一下我维护这套框架时遇到的高频问题按出现频率排了个序问题现象根因解决方案大模型选择了技能但参数明显不对SKILL.md中的input_schema描述不够具体给字段描述加示例值字段枚举一定要列全技能执行返回报错但大模型没感知到错误信息没有正确传回 tool message确保 tool_call 的结果以 JSON 形式完整回传技能能注册但调用时提示 not foundmanifest 的name和 executor 类的name不一致统一两边命名最好加一个启动时的自检逻辑技能执行慢拖慢整个 Agent 响应技能内串行调用了多个外部 API无依赖的调用改并行超时时间要设好技能有副作用但被重复调用大模型可能重复调用同一个工具在技能内做幂等控制相同参数只执行一次两个技能互相调用导致死循环技能编排逻辑没有做深度限制在 Router 里加调用深度计数器超过 5 层直接拒绝5.2 排查技巧让 Agent 的每一步都可观测技能框架最怕的就是“黑盒”大模型调用技能后你完全不知道它内部发生了什么、哪一步出错了。所以我在框架里默认接入了日志系统技能上下文的每一次log_event都会生成一条结构化日志。实际排查时我的习惯是复现问题后先看三个东西大模型的那次 tool_call 请求模型到底选了哪个技能、传了什么参数。这一步能判断是模型选错了还是技能执行错了。技能执行日志技能内部每一步事件的时间线和结果。这一步能定位到具体是哪一行代码报错。回传给模型的 tool message执行结果有没有被正确拼接回消息流。这一步能判断模型是不是拿到了结果但没用好。有了这三个维度的日志绝大多数问题都能在十分钟之内定位到根因。否则就靠猜效率极差。5.3 技能调试的“最小复现”策略技能开发多了你会发现调试技能最大的麻烦不是代码逻辑错而是“大模型的调用行为不可控”。你可能明明写好了技能但模型就是不按预期调用它直接凭感觉回答了。这时候最好的调试方法是绕过大模型直接测试技能本身。我用了一个简单的 CLI 工具可以在命令行里手动指定技能名和参数直接跑一遍执行器看输出是否符合预期。python -m skill_framework.cli --skill schedule_interview --args {candidate_id: c001, preferred_slots: [2025-06-04T14:00:00Z]}测试通过之后再回到大模型链路里测。这样分两步走能快速区分“是技能代码的问题”还是“是大模型调用策略的问题”不用混在一起猜来猜去。6. 从技能到 Agent 生态一些延伸思考整套技能框架跑通之后我最大的感受是Agent 开发的重心正在从“怎么调大模型”转向“怎么设计能力边界”。技能化之后Agent 的能力不再取决于模型本身的大小而取决于你给它在外面挂了多少技能。这就像一个人本身很聪明但手里如果没有工具能做的事情终究有限。技能框架就是给 Agent 配工具包的机制你的工具包越丰富、工具之间的协同越顺畅Agent 能独立完成的活儿就越多。我目前在这套框架上接入的技能包括知识库检索、日历操作、邮件发送、数据库查询、代码执行沙箱、前端页面生成本地预览等。每个技能从写好到上线平均只需要半天到一天。而在我还没做技能化之前每加一个能力都要改动 Agent 主流程的代码起码花两三天。如果你正在做 Agent 项目建议早点把技能的思路引入进去。不用一开始就做成完整的框架先按照“一个技能一个目录、一份 manifest、一个执行器”的规范来组织代码。等技能数量上来了你会自然而然地发现下一步就需要引入注册表、上下文、沙箱这些机制——那时候再用这套方案也不迟。最后分享一个小技巧技能的描述里一定要写“什么时候不应该用这个技能”。大模型在选择工具时正例给得再多都不如几个负例管用。我实测下来加了负例描述之后技能的错误调用率至少下降了六成。这算是踩了一堆坑之后攒下的最实用的一条经验。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

通信优先型CRM实战解析:DeskcommCRM让销售与客服真正用起来 2026/9/26 20:56:43

通信优先型CRM实战解析:DeskcommCRM让销售与客服真正用起来

我一直跟团队强调一句话:客户管理系统好不好用,不看功能列表有多长,要看销售和客服每天是不是真的在用。过去几年我参与过不少CRM的选型、实施和日常运维,踩过最典型的坑就是:系统上了,数据也迁了&#xff…

阅读更多 →
Python代码质量之从规范到自动化检查全过程 2026/9/26 20:56:43

Python代码质量之从规范到自动化检查全过程

1. 技术分析1.1 代码质量维度维度描述工具代码风格PEP 8规范black, isort类型检查类型注解检查mypy代码规范最佳实践flake8, pylint安全检查潜在漏洞bandit, safety测试覆盖代码测试比例coverage1.2 工具对比工具功能性能学习曲线black代码格式化快低flake8代码检查快低mypy类型…

阅读更多 →
TortoiseGit汉化教程:官方语言包安装与中文切换详解 2026/9/26 20:56:36

TortoiseGit汉化教程:官方语言包安装与中文切换详解

第一次装完 TortoiseGit,满屏英文菜单确实劝退过不少人。我当初也是从搜“TortoiseGit 汉化包”开始的,后来才发现这软件根本不用改文件、不用第三方补丁,官网就专门提供了官方语言包,也就是大家常说的官方汉化包。按顺序装好语言…

阅读更多 →
KAIST CS109 编程实践教程(三) 2026/9/26 20:56:30

KAIST CS109 编程实践教程(三)

setLineWidth(width: Double)设置轮廓绘制的笔宽度; drawRectangle(x: Double, y: Double, width: Double, height: Double, s: DrawStyle) 绘制矩形; drawCircle(x: Double, y: Double, radius: Double, s: DrawStyle) 在 ((x,y)) 处以半径 (r) 绘制一…

阅读更多 →
数据中心机房设计全解:从功率密度到气流组织的落地指南 2026/9/26 20:56:23

数据中心机房设计全解:从功率密度到气流组织的落地指南

简介:数据中心机房设计方案文档,面向机房建设相关的设计人员、系统集成商、项目经理及甲方技术负责人,是一份可直接参考的B级机房设计模板。方案依据《电子信息系统机房设计规范》《电子计算机场地通用规范》等标准编写,覆盖机房平…

阅读更多 →
PowerShell提供程序与PSDrive:把注册表、证书库当文件夹逛 2026/9/26 20:56:23

PowerShell提供程序与PSDrive:把注册表、证书库当文件夹逛

PowerShell 系列写到第七篇,终于要聊一聊这个系列里最“Windows 味”的概念——提供程序(Provider)和驱动器(PSDrive)。说实话,很多人用了很久 PowerShell,天天敲cd C:\、dir,却不知…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉