上下文工程实践 - 工具管理(上篇)

上下文工程实践 - 工具管理(上篇)

工具管理涉及的概念较多,所以我分成上下两篇来介绍:

上篇:主要讲 MCP 与 Tool 的定义和区别,以及工具的定义规范

下篇:继续展开,讨论工具的定位、错误处理方式和常见分类

1、什么是 MCP 和 Tool

  • MCP :是一份规范/协议,规定了"容器要怎么长、里面的功能要怎么描述、调用要怎么沟通"。就像 HTTP 规范本身,不是一个服务,而是大家都得遵守的语言。
  • MCP服务器 :是规范的一个实现,它作为一个容器,可以对外暴露很多能力(Tool / Resource / Event)。就像一个跑在端口上的 Web 服务器,遵循 HTTP 协议,里面可以有很多 API。
  • Tool :是容器里的功能单元,一般表现为一个"函数"或者"接口"。调用的时候就是传参执行,返回结果。

Tool 目前使用起来是比较简单的,在项目中按照规范写一个函数,将这个函数以 tool 参数的形式传递给大模型,大模型输出函数名之后,系统调用该函数

如果你需要搭建一套工具集的服务,想要提供给多个项目使用,提供给别人使用,提供给支持 MCP 的客户端使用,那么你就可以遵守 MCP 协议搭建 MCP 的服务

我觉得 MCP 和 Tool 本质是差不多的,就是给模型提供"外部能力"的作用,根据自己的情况和能力来选择使用是比较好的

2、工具定义规范

在定义工具的时候,最重要的就是工具的描述和工具调用需要的参数

  1. **工具的描述:**清晰的工具描述可以提高大模型工具调用的成功率
  2. **工具的参数:**描述参数工具的时候,要从参数名,参数类型,参数描述等尽可能多的方面讲这个参数表达的更清楚,这样在大模型输出工具参数的时候会准确和很多
  3. **工具的执行函数:**这个是一个函数,用于大模型输出合适的工具调用指令之后,系统执行该函数

2.1、工具(Tool)的类型定义:

  • description🌟:工具的描述
  • parameters🌟(ToolParameterDefinition):工具的参数定义
  • category:工具分类
  • version:工具版本
  • handler:工具的执行函数,这个不需要传递给大模型,而是作为系统内部执行的
  • agentAccessible:控制工具是否对代理可见
  • internal:标记为内部工具类
  • Purpose:描述了工具的核心目的和功能定位,它回答"这个工具为什么存在"以及"它解决啦什么问题",其是一个宏观的功能描述,例如:purpose: 'Perform semantic search over stored memory entries to retrieve relevant knowledge and reasoning traces that can inform current decision-making.'
  • UseCase:描述了工具的具体使用场景和适用条件,它回答了"在什么情况下应该使用这个工具"以及"如何正确的使用这个工具",其更多的关注应用场景和适用条件,例如:useCase: 'Use when you need to find previously stored knowledge, code patterns, or technical information that may be relevant to answering current questions or solving problems.'

descriptionparamenters**handler**是工具定义必须要的参数,其他的参数是根据情况选择的

handler 是工具的执行函数,这个不用作为工具定义信息传递给大模型

2.2、工具参数(ToolParameterDefinition)的类型定义:

  • type :定义参数数据类型,如:'string' | 'number' | 'boolean' | 'object' | 'array'
  • description:提供参数的人类可读描述,帮助 LLM 理解参数的用途
  • minimum | maximum:定义参数数值的最小值和最大值
  • minItems | maxItems:定义数组参数的最小和最大元素数量
  • minLength | maxLength:定义字符串参数的最小和最大长度
  • oneOf:定义参数必须匹配多个 Schema 中的一个
  • additionalProperties:禁止对象参数包含额外属性
  • items:定义数组元素的类型
  • enum:定义参数的可能取值
  • default:定义参数的默认值

typedescription 是必须的,这个是参数定义的基本元素,并且参数命名也可以成为参数的描述

下面是一个工具定义完整的案例:

typescript 复制代码
export const memoryOperationTool: InternalTool = {
	name: 'memory_operation',
	category: 'memory',
	internal: true,
	description:
		'Process extracted knowledge and determine memory operations (ADD, UPDATE, DELETE, NONE) using LLM-powered intelligent reasoning and similarity analysis with existing memories.',
	version: '2.0.0', // version
	parameters: {
		type: 'object',
		properties: {
			extractedFacts: {
				type: 'array',
				description:
					'Array of knowledge facts already extracted from interactions, containing technical details, code patterns, or implementation information.',
				items: {
					type: 'string',
				},
			},
			existingMemories: {
				type: 'array',
				description: 'Array of existing memory entries to compare against for similarity analysis.',
				items: {
					type: 'object',
					properties: {
						id: {
							type: 'string',
							description: 'Unique identifier of the existing memory',
						},
						text: {
							type: 'string',
							description: 'Content of the existing memory',
						},
						metadata: {
							type: 'object',
							description: 'Optional metadata for the memory',
						},
					},
					required: ['id', 'text'],
				},
			},
		},
		required: ['extractedFacts'],
	},
	handler: memoryOperationHandler
	},
};

//工具调用函数
const memoryOperationHandler = async (
	args: MemoryOperationArgs,
	context?: InternalToolContext
): Promise<MemoryOperationResult> => {
	// TODO: Implement intelligent reasoning logic to determine memory operations
	// Example placeholder return structure
	return {
		operations: [], // List of { operation: 'ADD' | 'UPDATE' | 'DELETE' | 'NONE', fact, memoryId? }
	};
};

2.3、工具执行函数定义

上面工具定义和工具参数定义这些都在作为 tool 参数传递给 LLM ,本质上就是 LLM 根据传递的工具描述和用户输入挑选出来一个合适的工具,但是大模型不负责执行工具函数,它只负责输出工具名称和工具参数

对于工具执行函数的定义,可以简单的根据工具参数去定义的,但是还是有一些常规定义方法,可以参考

工具的执行函数,会定义两个参数对象

  • arge:函数执行需要的参数对象
  • context |metadata:函数的元信息

一般来说,arge 是刚刚传入工具参数的类型,是工具执行函数的基本参数,而 context 或者 metadata 是属于辅助参数,大部分情况是用于监控和统计的,是可选的,没有这个也不影响函数的主功能执行

例如上面的定义案例中的memoryOperationHandler

typescript 复制代码
//主要参数-参数对象
export interface MemoryOperationArgs {
	extractedFacts: string[];
	existingMemories?: {
		id: string;
		text: string;
		metadata?: Record<string, any>;
	}[];
}

//辅助参数-元信息
export interface InternalToolContext {
    toolName: string;
    startTime: number;
    sessionId: string | undefined;
    userId?: string;
    metadata: Record<string, any> | undefined;
    
    // 服务依赖
    services?: {
        embeddingManager?: EmbeddingManager;
        vectorStoreManager?: VectorStoreManager;
        llmService?: ILLMService;
        knowledgeGraphManager?: KnowledgeGraphManager;
    };
}

//工具执行函数
const memoryOperationHandler = async (
	args: MemoryOperationArgs,
	context?: InternalToolContext
): Promise<MemoryOperationResult> => {
	// TODO: Implement intelligent reasoning logic to determine memory operations
	// Example placeholder return structure
	return {
		operations: [], // List of { operation: 'ADD' | 'UPDATE' | 'DELETE' | 'NONE', fact, memoryId? }
	};
};

最后

本文节选自我正在整理的 「上下文工程实践」 项目,该项目已完整发布在 GitHub 上。

如果你希望阅读更多相关的章节与案例,可以前往项目仓库查看:

👉 github.com/WakeUp-Jin/...

相关推荐
用户49055816081252 小时前
linux内核网络协议栈报文的处理过程
后端
ERP老兵_冷溪虎山2 小时前
Python/JS/Go/Java同步学习(第十三篇)四语言“字符串转码解码“对照表: 财务“小南“纸式转码术处理凭证乱码崩溃(附源码/截图/参数表/避坑指南)
java·后端·python
汤姆Tom2 小时前
JavaScript Proxy 对象详解与应用
前端·javascript
BillKu2 小时前
Vue3中app.mount(“#app“)应用挂载原理解析
javascript·vue.js·css3
努力的小郑2 小时前
MySQL索引(四):深入剖析索引失效的原因与优化方案
后端·mysql·性能优化
智商偏低2 小时前
ASP.NET Core 中的简单授权
后端·asp.net
xiaopengbc2 小时前
在 React 中如何使用 useMemo 和 useCallback 优化性能?
前端·javascript·react.js
GISer_Jing2 小时前
React 18 过渡更新:并发渲染的艺术
前端·javascript·react.js
练习时长一年2 小时前
搭建langchain4j+SpringBoot的Ai项目
java·spring boot·后端