带工具调用的多轮交互:Agent 的核心循环

真正的 Agent 场景远比单轮问答复杂。当用户问 "What's the current time and weather in Vancouver?" 时,模型无法凭自身知识回答(它不知道"现在"是什么时候),需要调用外部工具。下面完整展示这个过程中 Agent 框架与模型之间的每一步交互。

两轮工具调用的完整交互序列

**第一次 API 调用------Agent 框架发送初始请求:**

```javascript

// ═══ Request constructed by the Agent framework (1st call) ═══

{

"model": "Qwen3-0.6B",

"messages": [

{

"role": "system", // ← Written by developer

"content": "You are a helpful assistant. Use the provided tools to get real-time information when needed."

},

{

"role": "user", // ← User input

"content": "What's the current time and weather in Vancouver?"

}

],

"tools": [ // ← Tools defined by developer

{

"type": "function",

"function": {

"name": "get_current_time",

"description": "Get the current date and time in a specific timezone",

"parameters": {

"type": "object",

"properties": {

"timezone": { "type": "string", "description": "Timezone name, e.g. America/Vancouver" }

}

}

}

},

{

"type": "function",

"function": {

"name": "get_weather",

"description": "Get the current weather for a specific city",

"parameters": {

"type": "object",

"properties": {

"city": { "type": "string", "description": "City name" },

"unit": { "type": "string", "enum": "celsius", "fahrenheit" }

}

}

}

}

]

}

```

**模型返回工具调用请求(不是最终回复):**

```javascript

// ═══ Response returned by the API (model decides to call tools) ═══

{

"choices": [{

"message": {

"role": "assistant", // ← Generated by model

"content": null, // No text response

"tool_calls": [ // Model requests two tool calls

{

"id": "call_abc123",

"type": "function",

"function": {

"name": "get_current_time",

"arguments": "{\"timezone\": \"America/Vancouver\"}"

}

},

{

"id": "call_def456",

"type": "function",

"function": {

"name": "get_weather",

"arguments": "{\"city\": \"Vancouver\", \"unit\": \"celsius\"}"

}

}

]

}

}]

}

```

注意,模型并没有直接回答用户的问题,而是返回了两个**工具调用请求**------它判断"当前时间"和"天气"需要通过工具获取,而且两者之间没有依赖关系,可以并行调用。**模型只是发出了调用请求,真正执行工具的是 Agent 框架**。这是理解 Agent 架构的关键:模型负责决策(调用什么工具、传什么参数),Agent 框架负责执行(实际调用 API、运行代码)。

**Agent 框架执行工具,然后发起第二次 API 调用:**

Agent 框架拿到模型的工具调用请求后,实际执行这两个工具(比如调用时间 API 和天气 API),然后将**完整的对话历史加上工具执行结果**一起发送给模型:

```javascript

// ═══ Request constructed by the Agent framework (2nd call) ═══

{

"model": "Qwen3-0.6B",

"messages": [

{

"role": "system", // ← Same as 1st call

"content": "You are a helpful assistant. Use the provided tools to get real-time information when needed."

},

{

"role": "user", // ← Same as 1st call

"content": "What's the current time and weather in Vancouver?"

},

{

"role": "assistant", // ← Model output from 1st call, included verbatim

"content": null,

"tool_calls": [

{ "id": "call_abc123", "function": { "name": "get_current_time", "arguments": "{\"timezone\": \"America/Vancouver\"}" } },

{ "id": "call_def456", "function": { "name": "get_weather", "arguments": "{\"city\": \"Vancouver\", \"unit\": \"celsius\"}" } }

]

},

{

"role": "tool", // ← Generated by Agent framework (tool execution result)

"tool_call_id": "call_abc123",

"content": "{\"timezone\": \"America/Vancouver\", \"datetime\": \"2025-09-13T05:18:47\", \"day_of_week\": \"Saturday\"}"

},

{

"role": "tool", // ← Generated by Agent framework (tool execution result)

"tool_call_id": "call_def456",

"content": "{\"city\": \"Vancouver\", \"temperature\": 13.2, \"unit\": \"celsius\", \"conditions\": \"clear\", \"humidity\": 93}"

}

],

"tools": ... // ← Same tool definitions as above, omitted

}

```

这里有三个关键细节:

  1. **第二次请求包含了第一次的全部对话历史**------system 消息、user 消息、第一次的 assistant 回复(包含工具调用),以及新增的 tool 结果。这就是前面所说的"每次调用都是无状态的":模型不会"记住"上一次的对话,Agent 框架必须每次都把完整历史送回去。

  2. **第一次的 assistant 消息被原样放回消息列表**------这让模型能"看到"自己之前做了什么决策。

  3. **tool 消息通过 `tool_call_id` 与对应的工具调用关联**------模型据此知道哪个结果对应哪个调用。

**模型根据工具结果生成最终回复:**

```javascript

// ═══ Response returned by the API (final reply) ═══

{

"choices": [{

"message": {

"role": "assistant", // ← Generated by model

"content": "It's currently 5:18 AM on Saturday, September 13, 2025 in Vancouver.\n\nWeather: 13.2°C with clear skies and 93% humidity. It's quite cool this morning - you might want to grab a jacket."

}

}]

}

```

这一次模型没有返回 tool_calls,而是直接给出了文本回复------它判断已经有了足够的信息来回答用户的问题。如果模型认为还需要更多信息(比如用户追问"那东京呢?"),它会再次返回 tool_calls,Agent 框架再执行、再送回结果,如此循环。**这个"请求→工具调用→执行→送回结果→再请求"的循环,就是第一章介绍的 ReAct 循环在 API 层面的具体实现。**

用代码实现 Agent 的核心循环

理解了 JSON 结构之后,让我们用 Python 代码把上面的交互过程串起来。以下是一个最简的 Agent 实现------核心就是一个 while 循环:

```python

from openai import OpenAI

client = OpenAI()

── Tool definitions ──

tools = [

{

"type": "function",

"function": {

"name": "get_current_time",

"description": "Get the current date and time in a specific timezone",

"parameters": {

"type": "object",

"properties": {

"timezone": {"type": "string", "description": "Timezone name, e.g. America/Vancouver"}

},

},

},

},

{

"type": "function",

"function": {

"name": "get_weather",

"description": "Get the current weather for a specific city",

"parameters": {

"type": "object",

"properties": {

"city": {"type": "string", "description": "City name"},

"unit": {"type": "string", "enum": "celsius", "fahrenheit"},

},

},

},

},

]

── Tool execution function (stub with canned results; a real implementation

must parse the JSON `arguments` and call actual APIs) ──

def execute_tool(name, arguments):

if name == "get_current_time":

return '{"datetime": "2025-09-13T05:18:47", "day_of_week": "Saturday"}'

elif name == "get_weather":

return '{"temperature": 13.2, "unit": "celsius", "conditions": "clear", "humidity": 93}'

── Initial message list ──

messages = [

{"role": "system", "content": "You are a helpful assistant. Use tools to get real-time information when needed."},

{"role": "user", "content": "What's the current time and weather in Vancouver?"},

]

── Agent core loop ──

Production code needs a max_iterations cap here: as discussed later in

this chapter, Agents can get stuck repeating the same tool calls forever

while True:

response = client.chat.completions.create(

model="Qwen3-0.6B", messages=messages, tools=tools

)

assistant_message = response.choices0.message

Append model's response to message list (whether text or tool calls)

messages.append(assistant_message)

If no tool calls requested, the model has produced its final response

if not assistant_message.tool_calls:

print(assistant_message.content)

break

Execute each tool requested by the model, append results to message list

for tool_call in assistant_message.tool_calls:

result = execute_tool(tool_call.function.name, tool_call.function.arguments)

messages.append({

"role": "tool",

"tool_call_id": tool_call.id,

"content": result,

})

Return to top of loop, call model again with updated message list

```

这段代码的核心逻辑只有一个 while 循环和一个判断:**模型返回了 tool_calls 就执行工具并继续循环,没有就输出结果并退出**。整个过程中,`messages` 列表不断增长------每一轮都会追加模型的回复和工具的执行结果。

让我们跟踪 `messages` 列表在每一轮的变化:

**初始状态(第 1 次调用前):**

```

messages = [

{ role: "system", content: "You are a helpful assistant..." }, # 开发者写的

{ role: "user", content: "What's the current time and weather in Vancouver?" }, # 用户输入

]

```

**第 1 次调用后(模型返回工具调用):**

```

messages = [

{ role: "system", content: "..." },

{ role: "user", content: "What's the current time..." },

{ role: "assistant", tool_calls: get_current_time, get_weather }, # + Generated by model

{ role: "tool", tool_call_id: "call_abc", content: "{time...}" }, # + Executed by framework

{ role: "tool", tool_call_id: "call_def", content: "{weather...}" }, # + Executed by framework

]

```

**第 2 次调用后(模型返回最终回复,循环结束):**

```

messages = [

{ role: "system", content: "..." },

{ role: "user", content: "What's the current time..." },

{ role: "assistant", tool_calls: get_current_time, get_weather },

{ role: "tool", tool_call_id: "call_abc", content: "{time...}" },

{ role: "tool", tool_call_id: "call_def", content: "{weather...}" },

{ role: "assistant", content: "It's currently Saturday, Sep 13, 2025 in Vancouver..." }, # + Final reply

]

```

从这个过程可以清楚地看到:**Agent 框架的核心工作就是管理这个 messages 列表**------在合适的时机往里追加消息,然后把整个列表送给模型。本章后续所有的上下文工程技术,本质上都是在优化这个列表的内容和结构。

相关推荐
Dawson Zhu1 小时前
【CUDA编程入门②】CUDA性能优化基础:内存访问、Warp Shuffle与Occupancy调优
人工智能·语言模型·架构·aigc·agi
DFT计算杂谈1 小时前
基于大语言模型的用户画像提取与修正操作
人工智能·语言模型·自然语言处理
明志数科1 小时前
具身智能训练数据的质量口径问题:从规模扩张到评测基准
大数据·人工智能
寰宇视讯1 小时前
焙烤颜值经济持续升温,膳印科技以食品喷花打印技术树立行业标杆
大数据·人工智能·科技
Cosolar1 小时前
上下文工程的第一公里:LangChain 讲透 Agent 检索的三大坑与六套解法
人工智能·llm·agent
东宇科技1 小时前
AI短剧生成
人工智能
jiangliushi61 小时前
GPT-6.1 Sol 免费用:Windows 装完 Codex 提示“不是内部或外部命令”?三步加好 PATH
windows·gpt
samforce1 小时前
为什么微服务会退化成“分布式单体”?——软件架构里的嵌套率传导定律
人工智能·分布式·微服务·架构·软件架构·结构认知
嵌入式@hxydj1 小时前
AI小白如何使用并创建自己的skill
人工智能