从今天开始开个新坑,讲一讲Agent的开发。Agent开发的本质和原理都是非常简单直接的,但市面上,尤其是中文系列教程,都写的太烂了。
我们这个系列教程的最终目的,是基于DeepSeek API,用C#写出一个类似于Claude Code或Copilot CLI的工具。选择DeepSeek API的原因比较简单:便宜,好用。而选C#的原因则有点猎奇:一方面是如今我最熟悉的编程语言就是C#,另一方面,市面上现在有了太多的基于Python或前端技术栈的Agent开发教程,搞得仿佛Agent开发就得用Python或者NodeJS一样,这是不对的。
实际上,Agent开发用什么语言都可以,而之所以市面上大多数的Agent工具都是用Python或者NodeJS实现的,原因只是Agent本身并不是性能敏感的东西,并且Python和NodeJS这玩意写起来飞快。这个随着后续你跟进这个教程你就会体会到。
好了,废话不多说,我们开始旅程吧。
首先,你先去deepseek开放平台去注册个账号,然后充点钱,我建议你先充个二三十,如果你财力雄厚,就多充点,充个百八十块的。
然后我们需要创建一个API KEY,如图,注意这个API KEY就跟密码一样,它只会在这个页面显示一次,所以注意复制保存一下:

然后把这个玩意设置成你的环境变量

现在,你在powershell中就能读到这个环境变量的值了,在本系列教程后续所有要用到API KEY的地方,我们都是去环境变量里去读这个值的:

再接下来h,去bruno的官网下载bruno安装上,这个软件只是一个用来发送http请求的小工具,和postman差不多,如果你已经安装postman并且知道postman怎么使用的话,可以不安装bruno。
现在我们打开bruno,然后创建一个请求,如下所示:

先不纠结http request/response的json格式,直观上能感受到,这个api请求调用得到的结果好像有点不对劲,deepseek api并没有查出来今天的日期,以及上证指数到底是多少。而作为对比,在网页版 deepseek上,回答就智能了很多:

而更神奇的是,如果我们改一下请求体里的问题,继续追问deepseek api的话,api仿佛失忆了一样:

而网页版的deepseek显然是能多轮对话的,并且有一定的记忆力。
这就奇了怪了,怎么花钱的网页版看起来比花钱的api请求好用呢?付费玩家怎么还获得更差的体验了呢?
要理解为什么API调用效果那么差,就必须纠正一下你脑海中对于AI、大语言模型、chatgpt、openai、deekseek的错误认识。
接下来我用极不严谨,甚至可能包含错误的解释,给你讲一讲这里面的门道,注意,虽然里面可能包含一些错误,但至少能帮你建立起“稍微正确”一点的一些sense。我们来讲个故事:
几年前,有一帮聪明人,通过力大砖飞的原理,“炼”出了一个牛逼的程序。这个程序,以及同类的后来的相似的程序,就是我们今天所的“大语言模型”,英文名叫large language model,简称LLM,也有说法叫这类程序为“模型”,Model。
之所以说这个程序,这些程序,是“炼”出来的,而不是“写”出来的,是因为LLM的制造过程,跟传统程序不一样:传统程序是程序员哼哧哼哧996加班写代码,然后编译生成的。
这玩意可不是,这玩意是一帮特殊的程序员先哼哧哼哧写一堆特殊代码,生成一个特殊的程序,这个特殊程序甚至不是跑在CPU上的,而是跑在显卡上的。然后再拿海量的文本数据灌进这个程序里,等个七七四十九天,显卡上跑这个程序把海量的文本处理完了,最终生成的一个怪胎。这就是LLM。
LLM这玩意牛逼在哪呢?你可以把它想象成一个一问一答的对话程序,它让人毛骨悚然的是,跟它对话,仿佛是在跟一个有思维的“人”对话。
但LLM本身有几个缺点:
但LLM确实有以下几个让人毛骨悚然的优点:
好了,我们就暂时理解到这里就行了,现在假想我就是第一批炼出LLM的那帮邪修程序员之一,你怎么解决如下三个问题?
第二个问题怎么解决我们刚才已经提过了,但第一个和第三个问题怎么解决呢?
解决方法也非常朴素,就是把它想象成你那个屁都不懂只会指挥的老板,然后思考你老板是怎么做事的:
对于问题3:老板只动嘴皮子,但会指挥员工去做事。
但前提是:老板得知道哪些员工会做哪些事,这样他才能正确的指挥。
对于问题1:老板知识面广,但新鲜事物是完全不懂,所以你跟老板汇报的时候,你得告诉老板:“王总,虽然你不懂怎么做饭,但我知道有个B站up主叫王刚,他是个专业厨子,你看这个视频就知道怎么炒肉不沾锅了”
但前提是,你还得给老板再配个“会看视频,然后总结视频内容,最后把炒肉如何不沾锅的技巧总结出来总结成文本”的员工。
简单来说,你想让你老板给你做个辣椒炒肉,这事得这么办:
“老板,我想吃辣椒炒肉,你给我炒一盘”
“我知道你只会动嘴,所以我这里给你配备了个炒菜员工”
“我还给你配备了一个买菜员工,他会你的要求去菜市场买菜”
“根据我的知识,辣椒炒肉需要的食材包括辣椒、肉、葱姜蒜、油盐酱醋”
“我得先解决食材问题,刚好有个员工能去买菜,我得先让他去买上面提到的这些食材”
第一轮我说:
“老板,我想吃辣椒炒肉,你给我炒一盘”
“我知道你只会动嘴,所以我这里给你配备了个炒菜员工”
“我还给你配备了一个买菜员工,他会你的要求去菜市场买菜”
第一轮你回:
“根据我的知识,辣椒炒肉需要的食材包括辣椒、肉、葱姜蒜、油盐酱醋”
“我得先解决食材问题,刚好有个员工能去买菜,我得先让他去买上面提到的这些食材”
第二轮我说:
“小王已经按你的要求买齐了所有食材”
“小李,开始炒菜”
第一轮我说:
“老板,我想吃辣椒炒肉,你给我炒一盘”
“我知道你只会动嘴,所以我这里给你配备了个炒菜员工”
“我还给你配备了一个买菜员工,他会你的要求去菜市场买菜”
第一轮你回:
“根据我的知识,辣椒炒肉需要的食材包括辣椒、肉、葱姜蒜、油盐酱醋”
“我得先解决食材问题,刚好有个员工能去买菜,我得先让他去买上面提到的这些食材”
第二轮我说:
“小王已经按你的要求买齐了所有食材”
第二轮你回:
“小李,开始炒菜”
第三轮我说:
“小李炒菜过程中发现沾锅沾的要死”
“不过恰好我知道B站有个up主叫王刚,他分享了很多做菜视频,我们做菜失败的话可以去他的视频里找找原因,小张可以去看视频分析原因”
“小张,去分析一下炒肉为什么沾锅”
第一轮我说:
“老板,我想吃辣椒炒肉,你给我炒一盘”
“我知道你只会动嘴,所以我这里给你配备了个炒菜员工”
“我还给你配备了一个买菜员工,他会你的要求去菜市场买菜”
第一轮你回:
“根据我的知识,辣椒炒肉需要的食材包括辣椒、肉、葱姜蒜、油盐酱醋”
“我得先解决食材问题,刚好有个员工能去买菜,我得先让他去买上面提到的这些食材”
第二轮我说:
“小王已经按你的要求买齐了所有食材”
第二轮你回:
“小李,开始炒菜”
第三轮我说:
“小李炒菜过程中发现沾锅沾的要死”
“不过恰好我知道B站有个up主叫王刚,他分享了很多做菜视频,我们做菜失败的话可以去他的视频里找找原因,小张可以去看视频分析原因”
第三轮你回:
“小张,去分析一下炒肉为什么沾锅”
第四轮我说:
“解决沾锅的要点在于热锅凉油,并且肉下锅后保持不翻动,等定型后再翻炒”
“小李,重新炒菜,注意这次要热锅凉油,并且你那个逼手不要那么贱,肉刚下锅不要急着翻炒”
第一轮我说:
“老板,我想吃辣椒炒肉,你给我炒一盘”
“我知道你只会动嘴,所以我这里给你配备了个炒菜员工”
“我还给你配备了一个买菜员工,他会你的要求去菜市场买菜”
第一轮你回:
“根据我的知识,辣椒炒肉需要的食材包括辣椒、肉、葱姜蒜、油盐酱醋”
“我得先解决食材问题,刚好有个员工能去买菜,我得先让他去买上面提到的这些食材”
第二轮我说:
“小王已经按你的要求买齐了所有食材”
第二轮你回:
“小李,开始炒菜”
第三轮我说:
“小李炒菜过程中发现沾锅沾的要死”
“不过恰好我知道B站有个up主叫王刚,他分享了很多做菜视频,我们做菜失败的话可以去他的视频里找找原因,小张可以去看视频分析原因”
第三轮你回:
“小张,去分析一下炒肉为什么沾锅”
第四轮我说:
“解决沾锅的要点在于热锅凉油,并且肉下锅后保持不翻动,等定型后再翻炒”
第四轮你回:
“小李,重新炒菜,注意这次要热锅凉油,并且你那个逼手不要那么贱,肉刚下锅不要急着翻炒”
第五轮我说:
“小李炒成功了,我吃上辣椒炒肉了!”
“肉炒成功了,也吃上了,这个项目完成了,结束 ”
这个例子很啰嗦,但基本逻辑是对的,在看明白这个例子后,我们再来介绍以下概念:
所以,至此,想必你也理解了,为什么Deepseek API和网页产品区别那么大。
下面,则是我们对上面那个例子的生动复刻,唯一跟我们的例子对不太上的是,deepseek api并不需要小张去分析为什么炒肉会粘锅,deepseek api自己知道:
首先,我们发送如下请求。虽然请求体比较啰嗦,数据格式稍显复杂,但比较直观,你一眼就能看明白。里面有个小点,就是tool/function的名字只能由英文及数字和下划线组成,所以我们用了xiao_wang代表小王,xiao_li代表小李。
{
"model": "deepseek-flash",
"messages": [
{
"role": "user",
"content": "我想吃辣椒炒肉"
}
],
"tools": [
{
"type": "function",
"function": {
"name": "xiao_wang",
"description": "小王可以去菜市场购买东西,包括肉蛋奶葱姜蒜油盐酱醋等常见食材与调料,以及各种烹饪工具与锅碗瓢盆",
"parameters": {
"type": "object",
"properties": {
"物品": {
"type": "string",
"description": "要购买的物品名称"
}
},
"required": ["物品"]
}
}
},
{
"type": "function",
"function": {
"name": "xiao_li",
"description": "小李是个厨子,会炒菜,但炒辣椒炒肉时需要额外技巧才能不沾锅,否则辣椒炒肉会制作失败",
"parameters": {
"type": "object",
"properties": {
"菜名": {
"type": "string",
"description": "要炒的菜的名称"
},
"额外技巧": {
"type": "string",
"description": "做菜时的额外技巧"
}
},
"required": ["菜名"]
}
}
}
]
}
我们收到如下回应,看来deepseek还是非常严谨,它一方面成功的理解了我们的需求,另一方面很严谨的分析出了,我们需要先购买辣椒、猪肉、大蒜、生姜、食用油、盐、生抽、淀粉等物品。到这一步,站在LLM的角度来看,它是在指挥小王去买菜。
{
"id": "2516d9eb-4630-4f60-a11e-3dbdea93605a",
"object": "chat.completion",
"created": 1792227518,
"model": "deepseek-flash",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "我这就准备食材:辣椒、猪肉和常用配料,再用防粘技巧来炒。",
"reasoning_content": "We need respond in Chinese. Need accomplish: buy ingredients via xiao_wang, then ask xiao_li cook with extra technique to avoid sticking. Need know \"额外技巧\" required. The description says 小李 needs extra technique otherwise dish fails. We need probably buy ingredients including 辣椒, 猪肉, etc, then call cook with technique. Could do parallel? Buying and cooking dependent—need ingredients first. But can buy all at once. Tool only one item per call. We can parallel multiple xiao_wang calls for ingredients, then xiao_li call after. Need infer common ingredients: 猪肉、辣椒、葱姜蒜、油盐酱醋 maybe. Could buy \"辣椒炒肉的食材\" but item name maybe accepted? Better buy pork and peppers, plus seasonings. They asked \"想吃辣椒炒肉\". We can buy 猪肉, 辣椒, 蒜, 姜, 葱, 生抽, 老抽? 淀粉? 油盐酱醋. Overkill. Need perhaps ingredient list: 五花肉/前腿肉、青椒、蒜、姜、豆豉? The task expects use xiao_wang to purchase ingredients and xiao_li cook. Since \"额外技巧\" important: 热锅凉油? For 辣椒炒肉 not sticking: \"先把锅烧热,用油滑锅,再下肉\" or \"热锅凉油、先煸辣椒再炒肉\". Need include. Let's call buy items in parallel. Then cook. Need maybe no need ask preference. Let's do.",
"tool_calls": [
{
"index": 0,
"id": "call_00_sADDPPgg1gbpzlZwRr2F4493",
"type": "function",
"function": {
"name": "xiao_wang",
"arguments": "{\"物品\": \"辣椒\"}"
}
},
{
"index": 1,
"id": "call_01_OzvTW8ZbE8OqRfhhLdtd0846",
"type": "function",
"function": {
"name": "xiao_wang",
"arguments": "{\"物品\": \"猪肉\"}"
}
},
{
"index": 2,
"id": "call_02_b1ph42v7UaaYrS7viALZ9156",
"type": "function",
"function": {
"name": "xiao_wang",
"arguments": "{\"物品\": \"大蒜\"}"
}
},
{
"index": 3,
"id": "call_03_2g9c5erWv8Xb4i2iSAID4181",
"type": "function",
"function": {
"name": "xiao_wang",
"arguments": "{\"物品\": \"生姜\"}"
}
},
{
"index": 4,
"id": "call_04_G7Jgu5iwBnXHKWPGdSrl1583",
"type": "function",
"function": {
"name": "xiao_wang",
"arguments": "{\"物品\": \"食用油\"}"
}
},
{
"index": 5,
"id": "call_05_E44OPjxzRtp5Qajc2hMx5147",
"type": "function",
"function": {
"name": "xiao_wang",
"arguments": "{\"物品\": \"盐\"}"
}
},
{
"index": 6,
"id": "call_06_fYqugLEKRCb2rVeJub0J6012",
"type": "function",
"function": {
"name": "xiao_wang",
"arguments": "{\"物品\": \"生抽\"}"
}
},
{
"index": 7,
"id": "call_07_BPtz1T3SR5ocmjqewLab0511",
"type": "function",
"function": {
"name": "xiao_wang",
"arguments": "{\"物品\": \"淀粉\"}"
}
}
]
},
"logprobs": null,
"finish_reason": "tool_calls"
}
],
"usage": {
"prompt_tokens": 435,
"completion_tokens": 593,
"total_tokens": 1028,
"prompt_tokens_details": {
"cached_tokens": 0
},
"completion_tokens_details": {
"reasoning_tokens": 325
},
"prompt_cache_hit_tokens": 0,
"prompt_cache_miss_tokens": 435
},
"system_fingerprint": "e72d3c7f663d3e1383b00b3884cb4501"
}
然后,我们假装在现实世界里,小王把菜买齐了,所以我们会在上次请求的基础上,构造出如下请求:
{
"model": "deepseek-flash",
"messages": [
{
"role": "user",
"content": "我想吃辣椒炒肉"
},
+ {
+ "role": "assistant",
+ "content": "我这就准备食材:辣椒、猪肉和常用配料,再用防粘技巧来炒。",
+ "reasoning_content": "We need respond in Chinese. Need accomplish: buy ingredients via xiao_wang, then ask xiao_li cook with extra technique to avoid sticking. Need know \"额外技巧\" required. The description says 小李 needs extra technique otherwise dish fails. We need probably buy ingredients including 辣椒, 猪肉, etc, then call cook with technique. Could do parallel? Buying and cooking dependent—need ingredients first. But can buy all at once. Tool only one item per call. We can parallel multiple xiao_wang calls for ingredients, then xiao_li call after. Need infer common ingredients: 猪肉、辣椒、葱姜蒜、油盐酱醋 maybe. Could buy \"辣椒炒肉的食材\" but item name maybe accepted? Better buy pork and peppers, plus seasonings. They asked \"想吃辣椒炒肉\". We can buy 猪肉, 辣椒, 蒜, 姜, 葱, 生抽, 老抽? 淀粉? 油盐酱醋. Overkill. Need perhaps ingredient list: 五花肉/前腿肉、青椒、蒜、姜、豆豉? The task expects use xiao_wang to purchase ingredients and xiao_li cook. Since \"额外技巧\" important: 热锅凉油? For 辣椒炒肉 not sticking: \"先把锅烧热,用油滑锅,再下肉\" or \"热锅凉油、先煸辣椒再炒肉\". Need include. Let's call buy items in parallel. Then cook. Need maybe no need ask preference. Let's do.",
+ "tool_calls": [
+ {
+ "index": 0,
+ "id": "call_00_sADDPPgg1gbpzlZwRr2F4493",
+ "type": "function",
+ "function": {
+ "name": "xiao_wang",
+ "arguments": "{\"物品\": \"辣椒\"}"
+ }
+ },
+ {
+ "index": 1,
+ "id": "call_01_OzvTW8ZbE8OqRfhhLdtd0846",
+ "type": "function",
+ "function": {
+ "name": "xiao_wang",
+ "arguments": "{\"物品\": \"猪肉\"}"
+ }
+ },
+ {
+ "index": 2,
+ "id": "call_02_b1ph42v7UaaYrS7viALZ9156",
+ "type": "function",
+ "function": {
+ "name": "xiao_wang",
+ "arguments": "{\"物品\": \"大蒜\"}"
+ }
+ },
+ {
+ "index": 3,
+ "id": "call_03_2g9c5erWv8Xb4i2iSAID4181",
+ "type": "function",
+ "function": {
+ "name": "xiao_wang",
+ "arguments": "{\"物品\": \"生姜\"}"
+ }
+ },
+ {
+ "index": 4,
+ "id": "call_04_G7Jgu5iwBnXHKWPGdSrl1583",
+ "type": "function",
+ "function": {
+ "name": "xiao_wang",
+ "arguments": "{\"物品\": \"食用油\"}"
+ }
+ },
+ {
+ "index": 5,
+ "id": "call_05_E44OPjxzRtp5Qajc2hMx5147",
+ "type": "function",
+ "function": {
+ "name": "xiao_wang",
+ "arguments": "{\"物品\": \"盐\"}"
+ }
+ },
+ {
+ "index": 6,
+ "id": "call_06_fYqugLEKRCb2rVeJub0J6012",
+ "type": "function",
+ "function": {
+ "name": "xiao_wang",
+ "arguments": "{\"物品\": \"生抽\"}"
+ }
+ },
+ {
+ "index": 7,
+ "id": "call_07_BPtz1T3SR5ocmjqewLab0511",
+ "type": "function",
+ "function": {
+ "name": "xiao_wang",
+ "arguments": "{\"物品\": \"淀粉\"}"
+ }
+ }
+ ]
+ },
+ {
+ "role": "tool",
+ "content": "辣椒已经购买成功",
+ "tool_call_id": "call_00_sADDPPgg1gbpzlZwRr2F4493"
+ },
+ {
+ "role": "tool",
+ "content": "猪肉已经购买成功",
+ "tool_call_id": "call_01_OzvTW8ZbE8OqRfhhLdtd0846"
+ },
+ {
+ "role": "tool",
+ "content": "大蒜已经购买成功",
+ "tool_call_id": "call_02_b1ph42v7UaaYrS7viALZ9156"
+ },
+ {
+ "role": "tool",
+ "content": "生姜已经购买成功",
+ "tool_call_id": "call_03_2g9c5erWv8Xb4i2iSAID4181"
+ },
+ {
+ "role": "tool",
+ "content": "食用油已经购买成功",
+ "tool_call_id": "call_04_G7Jgu5iwBnXHKWPGdSrl1583"
+ },
+ {
+ "role": "tool",
+ "content": "盐已经购买成功",
+ "tool_call_id": "call_05_E44OPjxzRtp5Qajc2hMx5147"
+ },
+ {
+ "role": "tool",
+ "content": "生抽已经购买成功",
+ "tool_call_id": "call_06_fYqugLEKRCb2rVeJub0J6012"
+ },
+ {
+ "role": "tool",
+ "content": "淀粉已经购买成功",
+ "tool_call_id": "call_07_BPtz1T3SR5ocmjqewLab0511"
+ }
],
"tools": [
{
"type": "function",
"function": {
"name": "xiao_wang",
"description": "小王可以去菜市场购买东西,包括肉蛋奶葱姜蒜油盐酱醋等常见食材与调料,以及各种烹饪工具与锅碗瓢盆",
"parameters": {
"type": "object",
"properties": {
"物品": {
"type": "string",
"description": "要购买的物品名称"
}
},
"required": ["物品"]
}
}
},
{
"type": "function",
"function": {
"name": "xiao_li",
"description": "小李是个厨子,会炒菜,但炒辣椒炒肉时需要额外技巧才能不沾锅,否则辣椒炒肉会制作失败",
"parameters": {
"type": "object",
"properties": {
"菜名": {
"type": "string",
"description": "要炒的菜的名称"
},
"额外技巧": {
"type": "string",
"description": "做菜时的额外技巧"
}
},
"required": ["菜名"]
}
}
}
]
}
发送这个请求,我们得到如下回应:
{
"id": "6e4f760e-7e77-4721-8b0c-ee0c31be4aac",
"object": "chat.completion",
"created": 1792229143,
"model": "deepseek-flash",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "食材已经买齐。现在让小李师傅做,并提醒他用“热锅凉油、润锅后下肉”的防粘技巧。",
"reasoning_content": "Now call xiao_li with 菜名 and 额外技巧. Need specify. \"热锅凉油,先用油润锅并烧至微冒烟后倒出热油,再加凉油下肉;肉片提前用少许淀粉和生抽抓匀,下锅后先定型再翻动,可防粘锅。\" That's extra technique. Call.",
"tool_calls": [
{
"index": 0,
"id": "call_00_SE6RNMv7KcwxLeFry1WV8631",
"type": "function",
"function": {
"name": "xiao_li",
"arguments": "{\"菜名\": \"辣椒炒肉\", \"额外技巧\": \"先把锅烧热,用食用油充分润锅至微微冒烟,倒出热油后再加凉油;肉片提前用少许淀粉和生抽抓匀,下锅后先摊开定型再翻动,避免粘锅。\"}"
}
}
]
},
"logprobs": null,
"finish_reason": "tool_calls"
}
],
"usage": {
"prompt_tokens": 1128,
"completion_tokens": 216,
"total_tokens": 1344,
"prompt_tokens_details": {
"cached_tokens": 896
},
"completion_tokens_details": {
"reasoning_tokens": 78
},
"prompt_cache_hit_tokens": 896,
"prompt_cache_miss_tokens": 232
},
"system_fingerprint": "e72d3c7f663d3e1383b00b3884cb4501"
}
现在,我们再在上次请求的基础上,再添加上上次回应的信息,并假装小李已经炒完了菜,就可以构造出如下请求:
{
"model": "deepseek-flash",
"messages": [
{
"role": "user",
"content": "我想吃辣椒炒肉"
},
{
"role": "assistant",
"content": "我这就准备食材:辣椒、猪肉和常用配料,再用防粘技巧来炒。",
"reasoning_content": "We need respond in Chinese. Need accomplish: buy ingredients via xiao_wang, then ask xiao_li cook with extra technique to avoid sticking. Need know \"额外技巧\" required. The description says 小李 needs extra technique otherwise dish fails. We need probably buy ingredients including 辣椒, 猪肉, etc, then call cook with technique. Could do parallel? Buying and cooking dependent—need ingredients first. But can buy all at once. Tool only one item per call. We can parallel multiple xiao_wang calls for ingredients, then xiao_li call after. Need infer common ingredients: 猪肉、辣椒、葱姜蒜、油盐酱醋 maybe. Could buy \"辣椒炒肉的食材\" but item name maybe accepted? Better buy pork and peppers, plus seasonings. They asked \"想吃辣椒炒肉\". We can buy 猪肉, 辣椒, 蒜, 姜, 葱, 生抽, 老抽? 淀粉? 油盐酱醋. Overkill. Need perhaps ingredient list: 五花肉/前腿肉、青椒、蒜、姜、豆豉? The task expects use xiao_wang to purchase ingredients and xiao_li cook. Since \"额外技巧\" important: 热锅凉油? For 辣椒炒肉 not sticking: \"先把锅烧热,用油滑锅,再下肉\" or \"热锅凉油、先煸辣椒再炒肉\". Need include. Let's call buy items in parallel. Then cook. Need maybe no need ask preference. Let's do.",
"tool_calls": [
{
"index": 0,
"id": "call_00_sADDPPgg1gbpzlZwRr2F4493",
"type": "function",
"function": {
"name": "xiao_wang",
"arguments": "{\"物品\": \"辣椒\"}"
}
},
{
"index": 1,
"id": "call_01_OzvTW8ZbE8OqRfhhLdtd0846",
"type": "function",
"function": {
"name": "xiao_wang",
"arguments": "{\"物品\": \"猪肉\"}"
}
},
{
"index": 2,
"id": "call_02_b1ph42v7UaaYrS7viALZ9156",
"type": "function",
"function": {
"name": "xiao_wang",
"arguments": "{\"物品\": \"大蒜\"}"
}
},
{
"index": 3,
"id": "call_03_2g9c5erWv8Xb4i2iSAID4181",
"type": "function",
"function": {
"name": "xiao_wang",
"arguments": "{\"物品\": \"生姜\"}"
}
},
{
"index": 4,
"id": "call_04_G7Jgu5iwBnXHKWPGdSrl1583",
"type": "function",
"function": {
"name": "xiao_wang",
"arguments": "{\"物品\": \"食用油\"}"
}
},
{
"index": 5,
"id": "call_05_E44OPjxzRtp5Qajc2hMx5147",
"type": "function",
"function": {
"name": "xiao_wang",
"arguments": "{\"物品\": \"盐\"}"
}
},
{
"index": 6,
"id": "call_06_fYqugLEKRCb2rVeJub0J6012",
"type": "function",
"function": {
"name": "xiao_wang",
"arguments": "{\"物品\": \"生抽\"}"
}
},
{
"index": 7,
"id": "call_07_BPtz1T3SR5ocmjqewLab0511",
"type": "function",
"function": {
"name": "xiao_wang",
"arguments": "{\"物品\": \"淀粉\"}"
}
}
]
},
{
"role": "tool",
"content": "辣椒已经购买成功",
"tool_call_id": "call_00_sADDPPgg1gbpzlZwRr2F4493"
},
{
"role": "tool",
"content": "猪肉已经购买成功",
"tool_call_id": "call_01_OzvTW8ZbE8OqRfhhLdtd0846"
},
{
"role": "tool",
"content": "大蒜已经购买成功",
"tool_call_id": "call_02_b1ph42v7UaaYrS7viALZ9156"
},
{
"role": "tool",
"content": "生姜已经购买成功",
"tool_call_id": "call_03_2g9c5erWv8Xb4i2iSAID4181"
},
{
"role": "tool",
"content": "食用油已经购买成功",
"tool_call_id": "call_04_G7Jgu5iwBnXHKWPGdSrl1583"
},
{
"role": "tool",
"content": "盐已经购买成功",
"tool_call_id": "call_05_E44OPjxzRtp5Qajc2hMx5147"
},
{
"role": "tool",
"content": "生抽已经购买成功",
"tool_call_id": "call_06_fYqugLEKRCb2rVeJub0J6012"
},
{
"role": "tool",
"content": "淀粉已经购买成功",
"tool_call_id": "call_07_BPtz1T3SR5ocmjqewLab0511"
},
+ {
+ "role": "assistant",
+ "content": "食材已经买齐。现在让小李师傅做,并提醒他用“热锅凉油、润锅后下肉”的防粘技巧。",
+ "reasoning_content": "Now call xiao_li with 菜名 and 额外技巧. Need specify. \"热锅凉油,先用油润锅并烧至微冒烟后倒出热油,再加凉油下肉;肉片提前用少许淀粉和生抽抓匀,下锅后先定型再翻动,可防粘锅。\" That's extra technique. Call.",
+ "tool_calls": [
+ {
+ "index": 0,
+ "id": "call_00_SE6RNMv7KcwxLeFry1WV8631",
+ "type": "function",
+ "function": {
+ "name": "xiao_li",
+ "arguments": "{\"菜名\": \"辣椒炒肉\", \"额外技巧\": \"先把锅烧热,用食用油充分润锅至微微冒烟,倒出热油后再加凉油;肉片提前用少许淀粉和生抽抓匀,下锅后先摊开定型再翻动,避免粘锅。\"}"
+ }
+ }
+ ]
+ },
+ {
+ "role": "tool",
+ "content": "辣椒炒肉已经制作成功,没有粘锅,非常完美",
+ "tool_call_id": "call_00_SE6RNMv7KcwxLeFry1WV8631"
+ }
],
"tools": [
{
"type": "function",
"function": {
"name": "xiao_wang",
"description": "小王可以去菜市场购买东西,包括肉蛋奶葱姜蒜油盐酱醋等常见食材与调料,以及各种烹饪工具与锅碗瓢盆",
"parameters": {
"type": "object",
"properties": {
"物品": {
"type": "string",
"description": "要购买的物品名称"
}
},
"required": ["物品"]
}
}
},
{
"type": "function",
"function": {
"name": "xiao_li",
"description": "小李是个厨子,会炒菜,但炒辣椒炒肉时需要额外技巧才能不沾锅,否则辣椒炒肉会制作失败",
"parameters": {
"type": "object",
"properties": {
"菜名": {
"type": "string",
"description": "要炒的菜的名称"
},
"额外技巧": {
"type": "string",
"description": "做菜时的额外技巧"
}
},
"required": ["菜名"]
}
}
}
]
}
最后一次,API给我们如下返回。并且这一次回应的消息中,finish_reason的值为stop,也说明,LLM知道,这个“项目”完工了。
{
"id": "9b85c879-6dd5-43b9-8964-8016fd5298d9",
"object": "chat.completion",
"created": 1792229477,
"model": "deepseek-flash",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "辣椒炒肉已经做好啦,而且用了防粘技巧,没有粘锅,很成功!\n\n这道菜用了辣椒、猪肉、姜蒜,还有生抽和盐调味,肉片嫩滑、辣椒香辣,正好可以开吃。",
"reasoning_content": "Need final Chinese, maybe describe done."
},
"logprobs": null,
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 1369,
"completion_tokens": 59,
"total_tokens": 1428,
"prompt_tokens_details": {
"cached_tokens": 1152
},
"completion_tokens_details": {
"reasoning_tokens": 8
},
"prompt_cache_hit_tokens": 1152,
"prompt_cache_miss_tokens": 217
},
"system_fingerprint": "e72d3c7f663d3e1383b00b3884cb4501"
}
通过这个冗长的例子,你现在应该理解了LLM API的工作模式了,并且心里大致也隐隐对“Agent开发是做什么”有了一点点sense。我希望你此时最好自己把这个例子复刻一下,然后仔细思考下面的几个开放式问题:
想一想这三个浅显又深邃的问题,想明白了,相信你对"Agent"到底是什么东西,会有非常深刻的理解。并且对“Agent”能做哪些事情,也有了自己的理解。